diff --git a/.cmake.conf b/.cmake.conf new file mode 100644 index 0000000000..d3da691f06 --- /dev/null +++ b/.cmake.conf @@ -0,0 +1 @@ +set(QT_REPO_MODULE_VERSION "6.1.3") diff --git a/.gitignore b/.gitignore index 2fd837c975..d0d79c51df 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,6 @@ bin/lrelease* bin/lupdate* bin/lconvert* bin/moc* -bin/makeqpf* bin/pixeltool* bin/qmake* bin/qdoc3* @@ -113,10 +112,6 @@ translations/*.qm translations/*_untranslated.ts qrc_*.cpp -src/assistant/lib/fulltextsearch/qtcluceneversion.h -src/assistant/lib/qthelpversion.h -src/designer/src/lib/qtdesignerversion.h - # Test generated files QObject.log tst_* diff --git a/.prev_configure.cmake b/.prev_configure.cmake new file mode 100644 index 0000000000..9827b4badf --- /dev/null +++ b/.prev_configure.cmake @@ -0,0 +1,118 @@ + + +#### Inputs + + + +#### Libraries + + + +#### Tests + +# libclang +qt_find_package(WrapLibClang PROVIDED_TARGETS WrapLibClang::WrapLibClang) + +if(TARGET WrapLibClang::WrapLibClang) + set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE) +endif() + + + +#### Features + +qt_feature("assistant" PRIVATE + LABEL "Qt Assistant" + PURPOSE "Qt Assistant is a tool for viewing on-line documentation in Qt help file format." +) +qt_feature("clang" PRIVATE + LABEL "QDoc" + CONDITION TEST_libclang +) +qt_feature("clangcpp" PRIVATE + LABEL "Clang-based lupdate parser" + CONDITION QT_FEATURE_clang AND TEST_libclang +) +qt_feature("designer" PRIVATE + LABEL "Qt Designer" + PURPOSE "Qt Designer is the Qt tool for designing and building graphical user interfaces (GUIs) with Qt Widgets. You can compose and customize your windows or dialogs in a what-you-see-is-what-you-get (WYSIWYG) manner, and test them using different styles and resolutions." +) +qt_feature("distancefieldgenerator" PRIVATE + LABEL "Qt Distance Field Generator" + PURPOSE "The Qt Distance Field Generator tool can be used to pregenerate the font cache in order to optimize startup performance." +) +qt_feature("kmap2qmap" PRIVATE + LABEL "kmap2qmap" + PURPOSE "kmap2qmap is a tool to generate keymaps for use on Embedded Linux. The source files have to be in standard Linux kmap format that is e.g. understood by the kernel's loadkeys command." +) +qt_feature("linguist" PRIVATE + LABEL "Qt Linguist" + PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications." +) +qt_feature("macdeployqt" PRIVATE + LABEL "Mac Deployment Tool" + PURPOSE "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks." + CONDITION APPLE +) +qt_feature("pixeltool" PRIVATE + LABEL "pixeltool" + PURPOSE "The Qt Pixel Zooming Tool is a graphical application that magnifies the screen around the mouse pointer so you can look more closely at individual pixels." +) +qt_feature("qdbus" PRIVATE + LABEL "qdbus" + PURPOSE "qdbus is a communication interface for Qt-based applications." +) +qt_feature("qev" PRIVATE + LABEL "qev" + PURPOSE "qev allows introspection of incoming events for a QWidget, similar to the X11 xev tool." +) +qt_feature("qtattributionsscanner" PRIVATE + LABEL "Qt Attributions Scanner" + PURPOSE "Qt Attributions Scanner generates attribution documents for third-party code in Qt." +) +qt_feature("qtdiag" PRIVATE + LABEL "qtdiag" + PURPOSE "qtdiag outputs information about the Qt installation it was built with." +) +qt_feature("qtpaths" PRIVATE + LABEL "qtpaths" + PURPOSE "qtpaths is a command line client to QStandardPaths." +) +qt_feature("qtplugininfo" PRIVATE + LABEL "qtplugininfo" + PURPOSE "qtplugininfo dumps metadata about Qt plugins in JSON format." +) +qt_feature("windeployqt" PRIVATE + LABEL "Windows deployment tool" + PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package." + CONDITION WIN32 +) +qt_configure_add_summary_section(NAME "Qt Tools") +qt_configure_add_summary_entry(ARGS "assistant") +qt_configure_add_summary_entry(ARGS "clang") +qt_configure_add_summary_entry(ARGS "clangcpp") +qt_configure_add_summary_entry(ARGS "designer") +qt_configure_add_summary_entry(ARGS "distancefieldgenerator") +qt_configure_add_summary_entry(ARGS "kmap2qmap") +qt_configure_add_summary_entry(ARGS "linguist") +qt_configure_add_summary_entry(ARGS "macdeployqt") +qt_configure_add_summary_entry(ARGS "pixeltool") +qt_configure_add_summary_entry(ARGS "qdbus") +qt_configure_add_summary_entry(ARGS "qev") +qt_configure_add_summary_entry(ARGS "qtattributionsscanner") +qt_configure_add_summary_entry(ARGS "qtdiag") +qt_configure_add_summary_entry(ARGS "qtpaths") +qt_configure_add_summary_entry(ARGS "qtplugininfo") +qt_configure_add_summary_entry(ARGS "windeployqt") +qt_configure_end_summary_section() # end of "Qt Tools" section +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation. + Either set CMAKE_PREFIX_PATH or LLVM_INSTALL_DIR to the location of your llvm installation. On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution. On macOS, you can use Homebrew's llvm package." + CONDITION NOT QT_FEATURE_clang +) +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "Clang-based lupdate parser will not be available. LLVM and Clang C++ libraries have not been found." + CONDITION NOT QT_FEATURE_clangcpp +) diff --git a/.qmake.conf b/.qmake.conf index db2e0b653c..6bdb1fcb92 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,3 +1,5 @@ load(qt_build_config) -MODULE_VERSION = 5.14.0 +DEFINES += QT_NO_JAVA_STYLE_ITERATORS + +MODULE_VERSION = 6.1.3 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..f5057100a8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,41 @@ +# Generated from qttools.pro. + +cmake_minimum_required(VERSION 3.15.0) + +include(.cmake.conf) +project(QtTools # special case + VERSION "${QT_REPO_MODULE_VERSION}" + DESCRIPTION "Qt Tools" # special case + HOMEPAGE_URL "https://qt.io/" + LANGUAGES CXX C +) + +# special case begin +set(QT_REPO_NOT_WARNINGS_CLEAN TRUE) + +# Make sure we only use latest private CMake API, aka no compatibility wrappers. +set(QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS TRUE) + +# Make sure we use the fixed BASE argument of qt_add_resource. +set(QT_USE_FIXED_QT_ADD_RESOURCE_BASE TRUE) + +# add platform specific compontents +set(optional_components "") +if(WIN32) + list(APPEND optional_components AxContainer) +endif() + +find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core Network) +find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS + DBus Xml Widgets Quick QuickWidgets QmlDevToolsPrivate + Sql PrintSupport OpenGL OpenGLWidgets ${optional_components}) +# special case end + +qt_build_repo() + +# special case begin + +# Add tool dependencies that were deferred by qt_internal_add_docs. +qt_internal_add_deferred_dependencies() + +# special case end diff --git a/README.md b/README.md new file mode 100644 index 0000000000..ffe762e4d5 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# qttools: Assistant/WebEngine + +This is a fork of the official qttools repository for the sole purpose of compiling Qt Assistant against a stock binary distribution of Qt, without needing to build Qt itself. Assistant is patched to work with Qt WebEngine to give it full HTML browsing capability. The changes in this repository are additive in nature, but due to changes upstream it may be difficult to maintain in the future. + +## Compilation using Qt Creator + +
    +
  1. Switch to the 6.1.3_compile_against_6.2.4_assistant_webengine branch. +
  2. Using a stock distribution of the Qt SDK with WebEngine support (6.2.4 is known to work) open the file CMakeLists.txt in Qt Creator. +
  3. In Projects, select the appropriate Qt Kit if you have multiple installed. +
  4. In Build Settings, for Debug and Release individually, Build Steps, add this Custom Process Step (shown for Windows):

    + +Field | Content +------------------ | ------------- +Command: | windeployqt +Arguments: | assistant.exe +Working directory: | %{buildDir}\bin + +This will copy the necessary shared libraries so that Assistant will run from the bin subdirectory inside the build directory. +
+ +## Compilation using cmake +
    +
  1. Switch to the 6.1.3_compile_against_6.2.4_assistant_webengine branch. +
  2. Ensure you have appropriate cmake version (3.15+). +
  3. Ensure you have the correct version of Qt configured, or pass in on cmake command line. +
  4. Set up to use appropriate compiler (e.g. scl enable, or vcvars64.bat). +
  5. Create build directory and change to it. (E.g. as a subdirectory of qttools) +
  6. For Windows: +
      +
    1. Run cmake: cmake .. -DCMAKE_PREFIX_PATH=p:\qt\qt-opensource-6.2.4\win64_vc142 -DCMAKE_GENERATOR=Ninja -DCMAKE_BUILD_TYPE=Release +
    2. ninja.exe assistant +
    +
  7. For Linux: +
      +
    1. Run cmake: cmake .. +
    2. make assistant +
    + +
\ No newline at end of file diff --git a/cmake/FindWrapLibClang.cmake b/cmake/FindWrapLibClang.cmake new file mode 100644 index 0000000000..78a22cd04e --- /dev/null +++ b/cmake/FindWrapLibClang.cmake @@ -0,0 +1,81 @@ +if(TARGET WrapLibClang::WrapLibClang) + set(WrapLibClang_FOUND TRUE) + return() +endif() + +if(DEFINED ENV{LLVM_INSTALL_DIR}) + set(__qt_wrap_clang_backup_prefix "${CMAKE_PREFIX_PATH}") + list(PREPEND CMAKE_PREFIX_PATH "$ENV{LLVM_INSTALL_DIR}") +elseif(DEFINED CACHE{LLVM_INSTALL_DIR}) + set(__qt_wrap_clang_backup_prefix "${CMAKE_PREFIX_PATH}") + list(PREPEND CMAKE_PREFIX_PATH "${LLVM_INSTALL_DIR}") +endif() + +find_package(Clang CONFIG) + +if(__qt_wrap_clang_backup_prefix) + set(CMAKE_PREFIX_PATH "${__qt_wrap_clang_backup_prefix}") + unset(__qt_wrap_clang_backup_prefix) +endif() + +set(WrapLibClang_FOUND FALSE) +set(__wrap_lib_clang_requested_version_found FALSE) + +# Need to explicitly handle the version check, because the Clang package doesn't. +if(WrapLibClang_FIND_VERSION AND LLVM_PACKAGE_VERSION + AND LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL "${WrapLibClang_FIND_VERSION}") + set(__wrap_lib_clang_requested_version_found TRUE) +endif() + +if(TARGET libclang AND ((TARGET clang-cpp AND TARGET LLVM) OR TARGET clangHandleCXX) AND __wrap_lib_clang_requested_version_found) + set(WrapLibClang_FOUND TRUE) + + get_target_property(type libclang TYPE) + if (MSVC AND type STREQUAL "STATIC_LIBRARY") + get_property(__wrap_lib_clang_multi_config + GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(__wrap_lib_clang_multi_config) + set(__wrap_lib_clang_configs ${CMAKE_CONFIGURATION_TYPES}) + else() + set(__wrap_lib_clang_configs ${CMAKE_BUILD_TYPE}) + endif() + set(__wrap_lib_clang_non_release_configs ${configs}) + list(REMOVE_ITEM __wrap_lib_clang_non_release_configs + Release MinSizeRel RelWithDebInfo) + if(__wrap_lib_clang_non_release_configs STREQUAL __wrap_lib_clang_configs) + message(STATUS "Static linkage against libclang with MSVC was requested, but the build is not a release build, therefore libclang cannot be used.") + set(WrapLibClang_FOUND FALSE) + endif() + endif() + + if(WrapLibClang_FOUND) + add_library(WrapLibClang::WrapLibClang IMPORTED INTERFACE) + + target_include_directories(WrapLibClang::WrapLibClang INTERFACE ${CLANG_INCLUDE_DIRS}) + if (NOT TARGET Threads::Threads) + find_package(Threads) + endif() + qt_internal_disable_find_package_global_promotion(Threads::Threads) + # lupdate must also link to LLVM when using clang-cpp + set(__qt_clang_genex_condition "$,$>") + set(__qt_clang_genex "$") + target_link_libraries(WrapLibClang::WrapLibClang + INTERFACE libclang + ${__qt_clang_genex} + Threads::Threads + ) + + foreach(version MAJOR MINOR PATCH) + set(QT_LIB_CLANG_VERSION_${version} ${LLVM_VERSION_${version}} CACHE STRING "" FORCE) + endforeach() + set(QT_LIB_CLANG_VERSION ${LLVM_PACKAGE_VERSION} CACHE STRING "" FORCE) + set(QT_LIB_CLANG_LIBDIR "${LLVM_LIBRARY_DIRS}" CACHE STRING "" FORCE) + set(QT_LIBCLANG_RESOURCE_DIR + "\"${QT_LIB_CLANG_LIBDIR}/clang/${QT_LIB_CLANG_VERSION}/include\"" CACHE STRING "" FORCE) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(WrapLibClang + REQUIRED_VARS WrapLibClang_FOUND + VERSION_VAR LLVM_PACKAGE_VERSION) diff --git a/coin/module_config.yaml b/coin/module_config.yaml new file mode 100644 index 0000000000..5069e9d7a0 --- /dev/null +++ b/coin/module_config.yaml @@ -0,0 +1,38 @@ +version: 2 +accept_configuration: + condition: property + property: features + not_contains_value: Disable + +instructions: + Build: + - !include "{{qt/qtbase}}/coin_module_build_template_v2.yaml" + + Test: + - !include "{{qt/qtbase}}/coin_module_test_template_v3.yaml" + - type: Group + instructions: + - !include "{{qt/qtbase}}/prepare_building_env.yaml" + - type: EnvironmentVariable + variableName: QDOC_NOLINKERRORS + variableValue: 1 + - type: EnvironmentVariable + variableName: QDOC_ENABLE_WARNINGLIMIT + variableValue: 1 + - type: SetBuildDirectory + directory: "{{.SourceDir}}" + - type: ChangeDirectory + directory: "{{.BuildDir}}" + - type: EnvironmentVariable + variableName: COIN_CMAKE_ARGS + variableValue: "-DBUILD_TESTING=OFF {{.SourceDir}}" + - !include "{{qt/qtbase}}/call_cmake.yaml" + - type: ExecuteCommand + command: "cmake --build . --target generate_docs" + maxTimeInSeconds: 1800 + maxTimeBetweenOutput: 900 + userMessageOnFailure: "Documentation check failed, see the log for details." + enable_if: + condition: property + property: features + contains_value: "TestDocs" diff --git a/configure.cmake b/configure.cmake new file mode 100644 index 0000000000..b4a02e893d --- /dev/null +++ b/configure.cmake @@ -0,0 +1,128 @@ + + +#### Inputs + + + +#### Libraries + + + +#### Tests + +# libclang +# special case begin +# Even though Qt builds with qmake and libclang 6.0, it fails with CMake. +# Presumably because 6.0 ClangConfig.cmake files are not good enough? +# In any case explicitly request a minimum version of 8.x for now, otherwise +# building with CMake will fail at compilation time. +qt_find_package(WrapLibClang 8 PROVIDED_TARGETS WrapLibClang::WrapLibClang) +# special case end + +if(TARGET WrapLibClang::WrapLibClang) + set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE) +endif() + + + +#### Features + +qt_feature("assistant" PRIVATE + LABEL "Qt Assistant" + PURPOSE "Qt Assistant is a tool for viewing on-line documentation in Qt help file format." +) +qt_feature("clang" PRIVATE + LABEL "QDoc" + CONDITION TEST_libclang +) +qt_feature("clangcpp" PRIVATE + LABEL "Clang-based lupdate parser" + CONDITION QT_FEATURE_clang AND TEST_libclang +) +qt_feature("designer" PRIVATE + LABEL "Qt Designer" + PURPOSE "Qt Designer is the Qt tool for designing and building graphical user interfaces (GUIs) with Qt Widgets. You can compose and customize your windows or dialogs in a what-you-see-is-what-you-get (WYSIWYG) manner, and test them using different styles and resolutions." +) +qt_feature("distancefieldgenerator" PRIVATE + LABEL "Qt Distance Field Generator" + PURPOSE "The Qt Distance Field Generator tool can be used to pregenerate the font cache in order to optimize startup performance." +) +qt_feature("kmap2qmap" PRIVATE + LABEL "kmap2qmap" + PURPOSE "kmap2qmap is a tool to generate keymaps for use on Embedded Linux. The source files have to be in standard Linux kmap format that is e.g. understood by the kernel's loadkeys command." +) +qt_feature("linguist" PRIVATE + LABEL "Qt Linguist" + PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications." +) +qt_feature("macdeployqt" PRIVATE + LABEL "Mac Deployment Tool" + PURPOSE "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks." + CONDITION APPLE +) +qt_feature("pixeltool" PRIVATE + LABEL "pixeltool" + PURPOSE "The Qt Pixel Zooming Tool is a graphical application that magnifies the screen around the mouse pointer so you can look more closely at individual pixels." +) +qt_feature("qdbus" PRIVATE + LABEL "qdbus" + PURPOSE "qdbus is a communication interface for Qt-based applications." +) +qt_feature("qev" PRIVATE + LABEL "qev" + PURPOSE "qev allows introspection of incoming events for a QWidget, similar to the X11 xev tool." +) +qt_feature("qtattributionsscanner" PRIVATE + LABEL "Qt Attributions Scanner" + PURPOSE "Qt Attributions Scanner generates attribution documents for third-party code in Qt." +) +qt_feature("qtdiag" PRIVATE + LABEL "qtdiag" + PURPOSE "qtdiag outputs information about the Qt installation it was built with." +) +qt_feature("qtpaths" PRIVATE + LABEL "qtpaths" + PURPOSE "qtpaths is a command line client to QStandardPaths." +) +qt_feature("qtplugininfo" PRIVATE + LABEL "qtplugininfo" + PURPOSE "qtplugininfo dumps metadata about Qt plugins in JSON format." +) +qt_feature("windeployqt" PRIVATE + LABEL "Windows deployment tool" + PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package." + CONDITION WIN32 +) +qt_configure_add_summary_section(NAME "Qt Tools") +qt_configure_add_summary_entry(ARGS "assistant") +qt_configure_add_summary_entry(ARGS "clang") +qt_configure_add_summary_entry(ARGS "clangcpp") +qt_configure_add_summary_entry(ARGS "designer") +qt_configure_add_summary_entry(ARGS "distancefieldgenerator") +qt_configure_add_summary_entry(ARGS "kmap2qmap") +qt_configure_add_summary_entry(ARGS "linguist") +qt_configure_add_summary_entry(ARGS "macdeployqt") +qt_configure_add_summary_entry(ARGS "pixeltool") +qt_configure_add_summary_entry(ARGS "qdbus") +qt_configure_add_summary_entry(ARGS "qev") +qt_configure_add_summary_entry(ARGS "qtattributionsscanner") +qt_configure_add_summary_entry(ARGS "qtdiag") +qt_configure_add_summary_entry(ARGS "qtpaths") +qt_configure_add_summary_entry(ARGS "qtplugininfo") +qt_configure_add_summary_entry(ARGS "windeployqt") +qt_configure_end_summary_section() # end of "Qt Tools" section +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation. +Either set CMAKE_PREFIX_PATH or LLVM_INSTALL_DIR to the location of your llvm installation. +On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution. +On macOS, you can use Homebrew's llvm package. +You will also need to set the FEATURE_clang CMake variable to ON to re-evaluate this check." + CONDITION NOT QT_FEATURE_clang +) +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "Clang-based lupdate parser will not be available. LLVM and Clang C++ libraries have not been found. +You will need to set the FEATURE_clangcpp CMake variable to ON to re-evaluate this check." + CONDITION NOT QT_FEATURE_clangcpp +) diff --git a/configure.json b/configure.json index cd111df837..4b8e64e798 100644 --- a/configure.json +++ b/configure.json @@ -1,5 +1,151 @@ { - "subconfigs": [ - "src/qdoc" + "files": { + "publicHeader": "src/global/qttools-config.h", + "privateHeader": "src/global/qttools-config_p.h", + "publicPro": "src/global/qttools-config.pri", + "privatePro": "src/global/qttools-config.pri" + }, + "module": "tools", + "tests": { + "libclang": { + "label": "libclang", + "test": "libclang", + "type": "libclang" + } + }, + "features": { + "assistant": { + "label": "Qt Assistant", + "purpose": "Qt Assistant is a tool for viewing on-line documentation in Qt help file format.", + "output": [ "privateFeature" ] + }, + "clang": { + "label": "QDoc", + "condition": "tests.libclang", + "output": [ + "privateFeature", + { "type": "varAssign", "name": "CLANG_LIBS", "value": "tests.libclang.libs" }, + { "type": "varAssign", "name": "CLANG_INCLUDEPATH", "value": "tests.libclang.includepath" }, + { "type": "varAssign", "name": "CLANG_LIBDIR", "value": "tests.libclang.libdir" }, + { "type": "varAssign", "name": "CLANG_DEFINES", "value": "tests.libclang.defines" }, + { "type": "varAssign", "name": "CLANG_VERSION", "value": "tests.libclang.version" }, + { "type": "varAssign", "name": "CLANG_MAJOR_VERSION", "value": "tests.libclang.major_version" }, + { "type": "varAssign", "name": "CLANG_MINOR_VERSION", "value": "tests.libclang.minor_version" }, + { "type": "varAssign", "name": "CLANG_PATCH_VERSION", "value": "tests.libclang.patch_version" } + ] + }, + "clangcpp": { + "label": "Clang-based lupdate parser", + "condition": "features.clang && tests.libclang.has_clangcpp", + "output": [ + "privateFeature", + { "type": "varAssign", "name": "CLANGCPP_LIBS", "value": "tests.libclang.clangcpp_libs" } + ] + }, + "designer": { + "label": "Qt Designer", + "purpose": "Qt Designer is the Qt tool for designing and building graphical user interfaces (GUIs) with Qt Widgets. You can compose and customize your windows or dialogs in a what-you-see-is-what-you-get (WYSIWYG) manner, and test them using different styles and resolutions.", + "output": [ "privateFeature" ] + }, + "distancefieldgenerator": { + "label": "Qt Distance Field Generator", + "purpose": "The Qt Distance Field Generator tool can be used to pregenerate the font cache in order to optimize startup performance.", + "output": [ "privateFeature" ] + }, + "kmap2qmap": { + "label": "kmap2qmap", + "purpose": "kmap2qmap is a tool to generate keymaps for use on Embedded Linux. The source files have to be in standard Linux kmap format that is e.g. understood by the kernel's loadkeys command.", + "output": [ "privateFeature" ] + }, + "linguist": { + "label": "Qt Linguist", + "purpose": "Qt Linguist can be used by translator to translate text in Qt applications.", + "output": [ "privateFeature" ] + }, + "macdeployqt": { + "label": "Mac Deployment Tool", + "purpose": "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks.", + "condition": "config.darwin", + "output": [ "privateFeature" ] + }, + "pixeltool": { + "label": "pixeltool", + "purpose": "The Qt Pixel Zooming Tool is a graphical application that magnifies the screen around the mouse pointer so you can look more closely at individual pixels.", + "output": [ "privateFeature" ] + }, + "qdbus": { + "label": "qdbus", + "purpose": "qdbus is a communication interface for Qt-based applications.", + "output": [ "privateFeature" ] + }, + "qev": { + "label": "qev", + "purpose": "qev allows introspection of incoming events for a QWidget, similar to the X11 xev tool.", + "output": [ "privateFeature" ] + }, + "qtattributionsscanner": { + "label": "Qt Attributions Scanner", + "purpose": "Qt Attributions Scanner generates attribution documents for third-party code in Qt.", + "output": [ "privateFeature" ] + }, + "qtdiag": { + "label": "qtdiag", + "purpose": "qtdiag outputs information about the Qt installation it was built with.", + "output": [ "privateFeature" ] + }, + "qtpaths": { + "label": "qtpaths", + "purpose": "qtpaths is a command line client to QStandardPaths.", + "output": [ "privateFeature" ] + }, + "qtplugininfo": { + "label": "qtplugininfo", + "purpose": "qtplugininfo dumps metadata about Qt plugins in JSON format.", + "output": [ "privateFeature" ] + }, + "windeployqt": { + "label": "Windows deployment tool", + "purpose": "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package.", + "condition": "config.win32", + "output": [ "privateFeature" ] + } + }, + "report": [ + { + "type": "warning", + "condition": "!features.clang", + "message": "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation.\n +Either set CMAKE_PREFIX_PATH or LLVM_INSTALL_DIR to the location of your llvm installation. +On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution. +On macOS, you can use Homebrew's llvm package." + }, + { + "type": "warning", + "condition": "!features.clangcpp", + "message": "Clang-based lupdate parser will not be available. LLVM and Clang C++ libraries have not been found." + } + ], + "summary": [ + { + "section": "Qt Tools", + "entries": [ + "assistant", + "clang", + "clangcpp", + "designer", + "distancefieldgenerator", + "kmap2qmap", + "linguist", + "macdeployqt", + "pixeltool", + "qdbus", + "qev", + "qtattributionsscanner", + "qtdiag", + "qtpaths", + "qtplugininfo", + "windeployqt" + ] + } ] } diff --git a/configure.pri b/configure.pri new file mode 100644 index 0000000000..98c52d2697 --- /dev/null +++ b/configure.pri @@ -0,0 +1,434 @@ +defineReplace(extractVersion) { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)(svn|git)?$, \\1)) } +defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+(svn|git)?$, \\1)) } +defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+(svn|git)?$, \\1)) } +defineReplace(extractPatchVersion) { return($$replace(1, ^\\d+\\.\\d+\\.(\\d+)(svn|git)?$, \\1)) } + +defineTest(versionIsAtLeast) { + actual_major_version = $$extractMajorVersion($$1) + actual_minor_version = $$extractMinorVersion($$1) + actual_patch_version = $$extractPatchVersion($$1) + required_min_major_version = $$extractMajorVersion($$2) + required_min_minor_version = $$extractMinorVersion($$2) + required_min_patch_version = $$extractPatchVersion($$2) + + isEqual(actual_major_version, $$required_min_major_version) { + isEqual(actual_minor_version, $$required_min_minor_version) { + isEqual(actual_patch_version, $$required_min_patch_version): return(true) + greaterThan(actual_patch_version, $$required_min_patch_version): return(true) + } + greaterThan(actual_minor_version, $$required_min_minor_version): return(true) + } + greaterThan(actual_major_version, $$required_min_major_version): return(true) + + return(false) +} + +defineReplace(findLLVMVersionFromLibDir) { + libdir = $$1 + version_dirs = $$files($$libdir/clang/*) + for (version_dir, version_dirs) { + fileName = $$basename(version_dir) + version = $$find(fileName, ^(\\d+\\.\\d+\\.\\d+)$) + !isEmpty(version) { + isEmpty(candidateVersion): candidateVersion = $$version + else: versionIsAtLeast($$version, $$candidateVersion): candidateVersion = $$version + } + } + return($$candidateVersion) +} + +defineReplace(FindCleanLLVMInstallDir) { + # Assume libclang is installed on the target system + equals(QMAKE_HOST.os, Windows) { + # on Windows we have only two host compilers, MSVC or mingw. The former we never + # use for cross-compilation where it isn't also the target compiler. The latter + # is not detectable as this .prf file is evaluated against the target configuration + # and therefore checking for "mingw" won't work when the target compiler is clang (Android) + # or qcc (QNX). + msvc { + isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MSVC) + } else { + isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MINGW) + } + } + isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR) + isEmpty(LLVM_INSTALL_DIR) { + llvmConfigCandidates = \ + llvm-config-10 \ + llvm-config-9 \ + llvm-config-8 \ + llvm-config-7 \ + llvm-config-6.0 \ + llvm-config-5.0 \ + llvm-config-4.0 \ + llvm-config-3.9 \ + llvm-config + + for (candidate, llvmConfigCandidates) { + LLVM_INSTALL_DIR = $$system("$$candidate --prefix 2>$$QMAKE_SYSTEM_NULL_DEVICE") + !isEmpty(LLVM_INSTALL_DIR) { + CLANG_INCLUDEPATH = $$system("$$candidate --includedir 2>/dev/null") + LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h + !exists($$LIBCLANG_MAIN_HEADER) { + !isEmpty(LLVM_INSTALL_DIR): \ + qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") + continue + } else { + qtLog("QDoc:" \ + "Using Clang installation found in $${LLVM_INSTALL_DIR}." \ + "Set the LLVM_INSTALL_DIR environment variable to override.") + break() + } + } + } + } + LLVM_INSTALL_DIR = $$clean_path($$LLVM_INSTALL_DIR) + return($$LLVM_INSTALL_DIR) +} + +defineReplace(FindClangInstallDir) { + llvm_install_dir=$$1 + contains(QMAKE_HOST.arch, x86_64): \ + clangInstallDir = $$replace(llvm_install_dir, _ARCH_, 64) + else: \ + clangInstallDir = $$replace(llvm_install_dir, _ARCH_, 32) + isEmpty(llvm_install_dir) { + macos { + # Default to homebrew llvm on macOS. The CLANG_VERSION test below will complain if missing. + clangInstallDir = $$system("brew --prefix llvm") + } else { + clangInstallDir = /usr + } + } + return($$clangInstallDir) +} + +defineReplace(CheckClangCppLibForLupdateParser) { + clangLibDir = $$1 + libToTest = clangTooling \ + clangFrontendTool \ + clangFrontend \ + clangDriver \ + clangSerialization \ + clangCodeGen \ + clangParse \ + clangSema \ + clangStaticAnalyzerFrontend \ + clangStaticAnalyzerCheckers \ + clangStaticAnalyzerCore \ + clangAnalysis \ + clangARCMigrate \ + clangASTMatchers \ + clangAST \ + clangRewrite \ + clangRewriteFrontend \ + clangEdit \ + clangLex \ + clangIndex \ + clangBasic + + versionIsAtLeast($$CLANG_VERSION, "9.0.0"){ + libToTest += clangToolingRefactoring + } else { + libToTest += clangToolingRefactor + } + + + CLANG_CPP_LIBS = + for (lib, libToTest) { + libFullPath = + msvc { + libFullPath += $$clangLibDir/$${lib}.lib + } else { + equals(QMAKE_HOST.os, Windows): \ + libFullPath += $$clangLibDir/$${lib}.lib + else: \ + libFullPath += $$clangLibDir/lib$${lib}.a + } + + CLANG_CPP_LIBS += -l$$lib + !exists($$libFullPath): { + CLANG_CPP_LIBS = + qtLog("Cannot locate $$libFullPath.") + return($$CLANG_CPP_LIBS) + } + } + return($$CLANG_CPP_LIBS) +} + +defineReplace(CheckClangLlvmLibForLupdateParser) { + clangLibDir = $$1 + libToTest += LLVMOption \ + LLVMProfileData \ + LLVMMCParser \ + LLVMMC \ + LLVMBitReader \ + LLVMCore \ + LLVMBinaryFormat \ + LLVMSupport \ + LLVMDemangle + + versionIsAtLeast($$CLANG_VERSION, "9.0.0") { + libToTest += LLVMBitstreamReader\ + LLVMRemarks + } + + CLANG_LLVM_LIBS = + for (lib, libToTest) { + libFullPath = + msvc { + libFullPath += $$clangLibDir/$${lib}.lib + } else { + equals(QMAKE_HOST.os, Windows): \ + libFullPath += $$clangLibDir/$${lib}.lib + else: \ + libFullPath += $$clangLibDir/lib$${lib}.a + } + + CLANG_LLVM_LIBS += -l$$lib + !exists($$libFullPath): { + CLANG_LLVM_LIBS = + return($$CLANG_LLVM_LIBS) + } + } + !equals(QMAKE_HOST.os, Windows): { + equals(QMAKE_HOST.os, Darwin): CLANG_LLVM_LIBS += -lz -lcurses + else: CLANG_LLVM_LIBS += -lz -ltinfo + } + return($$CLANG_LLVM_LIBS) +} + +defineTest(qtConfTest_libclang) { + isEmpty(QDOC_USE_STATIC_LIBCLANG): QDOC_USE_STATIC_LIBCLANG = $$(QDOC_USE_STATIC_LIBCLANG) + + LLVM_INSTALL_DIR = $$FindCleanLLVMInstallDir() + isEmpty(LLVM_INSTALL_DIR) { + equals(QMAKE_HOST.os, Windows) { + return(false) + } + } + clangInstallDir = $$FindClangInstallDir($$LLVM_INSTALL_DIR) + + # note: llvm_config only exits on unix + llvm_config = $$clangInstallDir/bin/llvm-config + exists($$llvm_config) { + CLANG_LIBDIR = $$system("$$llvm_config --libdir 2>/dev/null") + CLANG_INCLUDEPATH = $$system("$$llvm_config --includedir 2>/dev/null") + output = $$system("$$llvm_config --version 2>/dev/null") + CLANG_VERSION = $$extractVersion($$output) + } else { + CLANG_LIBDIR = $$clangInstallDir/lib + CLANG_INCLUDEPATH = $$clangInstallDir/include + CLANG_VERSION = $$findLLVMVersionFromLibDir($$CLANG_LIBDIR) + } + isEmpty(CLANG_VERSION) { + !isEmpty(LLVM_INSTALL_DIR): \ + qtLog("Cannot determine version of clang installation in $${clangInstallDir}.") + return(false) + } else { + CLANG_MAJOR_VERSION = $$extractMajorVersion($$CLANG_VERSION) + CLANG_MINOR_VERSION = $$extractMinorVersion($$CLANG_VERSION) + CLANG_PATCH_VERSION = $$extractPatchVersion($$CLANG_VERSION) + } + + LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h + !exists($$LIBCLANG_MAIN_HEADER) { + !isEmpty(LLVM_INSTALL_DIR): \ + qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") + return(false) + } + + !contains(QMAKE_DEFAULT_LIBDIRS, $$CLANG_LIBDIR): CLANG_LIBS = -L$${CLANG_LIBDIR} + + CLANG_DEFINES = + HAS_CLANGCPP = false + CLANGCPP_LIB = + + isEmpty(QDOC_USE_STATIC_LIBCLANG) { + # entering here in case of user (as opposed to CI) + + #--------------- QDoc needs -------------------------------- + equals(QMAKE_HOST.os, Windows): \ + CLANG_LIBS += -llibclang -ladvapi32 -lshell32 -lversion + else: \ + CLANG_LIBS += -lclang + + #--------------- Lupdate clang-based parser needs Clang C++ and llvm libraries + CLANGCPP_DY_LIB = $$CLANG_LIBDIR/libclang_shared.so + # Checking clang cpp libraries + # check for shared libraries (not available for Windows at the moment) + exists($$CLANGCPP_DY_LIB): { + CLANGCPP_LIBS += -lclang_shared + } else { + # check for static libraries + CLANGCPP_LIBS += $$CheckClangCppLibForLupdateParser($$CLANG_LIBDIR) + } + # Checking for LLVM libraries needed for Lupdate clang-based parser + # At this point, if CLANGCPP_LIBS is empty, no need to go further + !isEmpty(CLANGCPP_LIBS): { + LLVM_DY_LIB = $$CLANG_LIBDIR/libLLVM.so + # check for shared libraries (not available for Windows at the moment) + exists($$LLVM_DY_LIB): { + CLANGCPP_LIBS += -lLLVM + HAS_CLANGCPP = true # Clang cpp and llvm libraries have been found + } else: { + # check for static libraries + CLANGLLVM_LIBS = $$CheckClangLlvmLibForLupdateParser($$CLANG_LIBDIR) + !isEmpty(CLANGLLVM_LIBS): { + CLANGCPP_LIBS += $$CLANGLLVM_LIBS + HAS_CLANGCPP = true # Clang cpp and llvm libraries have been found + } + } + #---------------------------------------------------------------------- + } + } else { + # CI + HAS_CLANGCPP = true #just assuming for now + equals(QMAKE_HOST.os, Windows) { + versionIsAtLeast($$CLANG_VERSION, "10.0.0") { + CLANG_DEFINES += CINDEX_NO_EXPORTS + } else { + CLANG_DEFINES += CINDEX_LINKAGE= + } + } + !equals(QMAKE_HOST.os, Darwin):!msvc: CLANG_LIBS+=-Wl,--start-group + CLANG_LIBS += -lclangAnalysis \ + -lclangARCMigrate \ + -lclangAST \ + -lclangASTMatchers \ + -lclangBasic \ + -lclangCodeGen \ + -lclangCrossTU \ + -lclangDriver \ + -lclangDynamicASTMatchers \ + -lclangEdit \ + -lclangFormat \ + -lclangFrontend \ + -lclangFrontendTool \ + -lclangHandleCXX \ + -lclangIndex \ + -lclangLex \ + -lclangParse \ + -lclangRewrite \ + -lclangRewriteFrontend \ + -lclangSema \ + -lclangSerialization \ + -lclangStaticAnalyzerCheckers \ + -lclangStaticAnalyzerCore \ + -lclangStaticAnalyzerFrontend \ + -lclangTooling \ + -lclangToolingASTDiff \ + -lclangToolingCore + + versionIsAtLeast($$CLANG_VERSION, "10.0.0") { + equals(QMAKE_HOST.os, Windows): \ + CLANG_LIBS += -llibclang + else: \ + CLANG_LIBS += -lclang + + CLANG_LIBS += -lclangToolingInclusions + } else { + equals(QMAKE_HOST.os, Windows): \ + CLANG_LIBS += -llibclang_static + else: \ + CLANG_LIBS += -lclang_static + + CLANG_LIBS += \ + -lclangApplyReplacements \ + -lclangChangeNamespace \ + -lclangDaemon \ + -lclangIncludeFixer \ + -lclangIncludeFixerPlugin \ + -lclangMove \ + -lclangQuery \ + -lclangReorderFields \ + -lclangTidy \ + -lclangTidyAndroidModule \ + -lclangTidyBoostModule \ + -lclangTidyBugproneModule \ + -lclangTidyCERTModule \ + -lclangTidyCppCoreGuidelinesModule \ + -lclangTidyFuchsiaModule \ + -lclangTidyGoogleModule \ + -lclangTidyHICPPModule \ + -lclangTidyLLVMModule \ + -lclangTidyMiscModule \ + -lclangTidyModernizeModule \ + -lclangTidyMPIModule \ + -lclangTidyObjCModule \ + -lclangTidyPerformanceModule \ + -lclangTidyPlugin \ + -lclangTidyReadabilityModule \ + -lclangTidyUtils \ + -lclangToolingRefactor \ + -lfindAllSymbols + } + + msvc { + LLVM_LIBS_STRING += $$system("$$llvm_config --libnames") + } else { + LLVM_LIBS_STRING += $$system("$$llvm_config --libs") + } + LLVM_LIBS_STRING += $$system("$$llvm_config --system-libs") + CLANG_LIBS += $$split(LLVM_LIBS_STRING, " ") + + !equals(QMAKE_HOST.os, Darwin):!msvc: CLANG_LIBS+=-Wl,--end-group + equals(QMAKE_HOST.os, Windows): CLANG_LIBS += -lversion + } + + !versionIsAtLeast($$CLANG_VERSION, "3.9.0") { + log("LLVM/Clang version >= 3.9.0 required, version provided: $${CLANG_VERSION}.$$escape_expand(\\n)") + return(false) + } + + !versionIsAtLeast($$CLANG_VERSION, "8.0.0") { + # if not InitLLVM.h is missing + log("LLVM/Clang version >= 8.0.0 required for Clang-based lupdate parser. \ + Version provided: $${CLANG_VERSION}.$$escape_expand(\\n)") + HAS_CLANGCPP = false + } + + $${1}.libs = $$CLANG_LIBS + export($${1}.libs) + $${1}.cache += libs + + $${1}.includepath = $$CLANG_INCLUDEPATH + export($${1}.includepath) + $${1}.cache += includepath + + $${1}.libdir = $$CLANG_LIBDIR + export($${1}.libdir) + $${1}.cache += libdir + + $${1}.defines = $$CLANG_DEFINES + export($${1}.defines) + $${1}.cache += defines + + $${1}.version = $$CLANG_VERSION + export($${1}.version) + $${1}.cache += version + + $${1}.major_version = $$CLANG_MAJOR_VERSION + export($${1}.major_version) + $${1}.cache += major_version + + $${1}.minor_version = $$CLANG_MINOR_VERSION + export($${1}.minor_version) + $${1}.cache += minor_version + + $${1}.patch_version = $$CLANG_PATCH_VERSION + export($${1}.patch_version) + $${1}.cache += patch_version + + $${1}.has_clangcpp = $$HAS_CLANGCPP + export($${1}.has_clangcpp) + $${1}.cache += has_clangcpp + + $${1}.clangcpp_libs = $$CLANGCPP_LIBS + export($${1}.clangcpp_libs) + $${1}.cache += clangcpp_libs + + export($${1}.cache) + + return(true) +} diff --git a/dependencies.yaml b/dependencies.yaml new file mode 100644 index 0000000000..12aa807355 --- /dev/null +++ b/dependencies.yaml @@ -0,0 +1,10 @@ +dependencies: + ../qtactiveqt: + ref: 8aa4712020993be03e53006b2ab1bebf9a29638e + required: false + ../qtbase: + ref: b496064efab47743fff4eb22f68e3acb3315fd9d + required: true + ../qtdeclarative: + ref: 2f556e351d2ebdfc4561063665e266f800ec904f + required: false diff --git a/dist/changes-5.12.10 b/dist/changes-5.12.10 new file mode 100644 index 0000000000..95c6a0b2fd --- /dev/null +++ b/dist/changes-5.12.10 @@ -0,0 +1,26 @@ +Qt 5.12.10 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.9. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.12/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + +**************************************************************************** +* Library * +**************************************************************************** diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4 new file mode 100644 index 0000000000..4796a38281 --- /dev/null +++ b/dist/changes-5.12.4 @@ -0,0 +1,33 @@ +Qt 5.12.4 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.3. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* lupdate * +**************************************************************************** + + - lupdate will now generate an error if it is asked to update a .ts file + with translations, but without a target language. This is to ensure that + plural translations are not destroyed. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - [QTBUG-73058] qdoc now uses #! as a snippet marker in .cmake, + CMakeLists.txt files. diff --git a/dist/changes-5.12.5 b/dist/changes-5.12.5 new file mode 100644 index 0000000000..379f39064c --- /dev/null +++ b/dist/changes-5.12.5 @@ -0,0 +1,37 @@ +Qt 5.12.5 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.12.0 through 5.12.4. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* distancefieldgenerator * +**************************************************************************** + + - [QTBUG-76188] Fixed bug where the tool would fail for valid fonts with + the message "end of cmap table reached when parsing subtable". + - [QTBUG-76528] Fixed a bug where the generated textures might exceed the + maximum height. + - [QTBUG-76188][QTBUG-76528] Fixed possible crash when generating large + number of glyphs with a small texture size. + - [QTBUG-77501] Fixed broken text rendering when generating large glyph + sets. + +**************************************************************************** +* Qt Help * +**************************************************************************** + + - [QDS-779] Fixed possible application freeze when using QtHelp module. diff --git a/dist/changes-5.13.0 b/dist/changes-5.13.0 new file mode 100644 index 0000000000..2859e92607 --- /dev/null +++ b/dist/changes-5.13.0 @@ -0,0 +1,37 @@ +Qt 5.13 introduces many new features and improvements as well as bugfixes +over the 5.12.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Designer * +**************************************************************************** + + - Added a filter line edit to the object inspector. + +**************************************************************************** +* lupdate * +**************************************************************************** + + - lupdate will now generate an error if it is asked to update a .ts file + with translations, but without a target language. This is to ensure that + plural translations are not destroyed. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - [QTBUG-73058] qdoc now uses #! as a snippet marker in .cmake, + CMakeLists.txt files. diff --git a/dist/changes-5.13.1 b/dist/changes-5.13.1 new file mode 100644 index 0000000000..557d7021f5 --- /dev/null +++ b/dist/changes-5.13.1 @@ -0,0 +1,29 @@ +Qt 5.13.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* distancefieldgenerator * +**************************************************************************** + + - [QTBUG-76188] Fixed bug where the tool would fail for valid fonts with + the message "end of cmap table reached when parsing subtable". + - [QTBUG-76528] Fixed a bug where the generated textures might exceed the + maximum height. + - [QTBUG-76188][QTBUG-76528] Fixed possible crash when generating large + number of glyphs with a small texture size. diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 new file mode 100644 index 0000000000..f1a1f9dbbb --- /dev/null +++ b/dist/changes-5.13.2 @@ -0,0 +1,27 @@ +Qt 5.13.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.13.0 through 5.13.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Distance Field Generator * +**************************************************************************** + + - [QTBUG-77499] Improved performance when selecting unicode ranges in + large fonts. + - [QTBUG-77501] Fixed broken text rendering when generating large glyph + sets. diff --git a/dist/changes-5.14.0 b/dist/changes-5.14.0 new file mode 100644 index 0000000000..de2bb6fbdf --- /dev/null +++ b/dist/changes-5.14.0 @@ -0,0 +1,63 @@ +Qt 5.14 introduces many new features and improvements as well as bugfixes +over the 5.13.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* pixeltool * +**************************************************************************** + + - 'c' now copies color under cursor, and shows it in the tool window title. + +**************************************************************************** +* Qt Designer * +**************************************************************************** + + - [QTBUG-76375] A per-form setting for disabling generating calls to + QObject::connectSlotsByName() has been added to support migrating forms + to Qt 5 connection syntax. + - The multiselection-modifier of the buddy/signal slot editors has been + changed to Control instead of (historical) Shift. + +**************************************************************************** +* Qt Linguist * +**************************************************************************** + + - [QTBUG-76265] lupdate now warns about qsTr() calls with template literals + in .qml files. + - [QTBUG-67908] Extra \n when reading translator comment from .po file now + gets removed. + - [QTBUG-76723] CMake: qt5_create_translation was creating a warning when + translation files had the same prefix, separated by a dot. This is now + fixed. + +**************************************************************************** +* windeployqt * +**************************************************************************** + + - [QTBUG-15234] windeployqt does not patch paths in Qt5Core anymore if Qt + is configured with -feature-relocatable. + - [QTBUG-75272] Added option -no-virtualkeyboard to disable deployment of + Qt Virtual Keyboard. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - QDoc no longer attempts to run if 'project' configuration variable is + not set; it now fails with an appropriate error message. + + - [QTBUG-80051] 'depends' configuration now accepts '*' as a value, + instructing QDoc to load all available index files as dependencies. diff --git a/dist/changes-5.14.1 b/dist/changes-5.14.1 new file mode 100644 index 0000000000..ac11cec9df --- /dev/null +++ b/dist/changes-5.14.1 @@ -0,0 +1,26 @@ +Qt 5.14.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.14.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* windeployqt * +**************************************************************************** + + - [QTBUG-80806] windeployqt has been fixed to work with MinGW, again. + - [QTBUG-78146] Fixed possible empty content and index widgets when using + Qt Help module. diff --git a/dist/changes-5.14.2 b/dist/changes-5.14.2 new file mode 100644 index 0000000000..f90f453180 --- /dev/null +++ b/dist/changes-5.14.2 @@ -0,0 +1,24 @@ +Qt 5.14.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.14.0 through 5.14.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.14 series is binary compatible with the 5.13.x series. +Applications compiled for 5.13 will continue to run with 5.14. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - [QTBUG-82252] Fixed "-F" option on macOS diff --git a/dist/changes-5.15.0 b/dist/changes-5.15.0 new file mode 100644 index 0000000000..b061a693f2 --- /dev/null +++ b/dist/changes-5.15.0 @@ -0,0 +1,58 @@ +Qt 5.15 introduces many new features and improvements as well as bugfixes +over the 5.14.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* QtHelp * +**************************************************************************** + + - QHelpLink data structure has been introduced and used in newly added + documentsForIdentifier() and documentsForKeyword() methods. + - Deprecated linksForIdentifier() and linksForKeyword() methods + in favor of the methods above. + - The QHelpFilterSettings class has been added, describing all + the available filter details. + - The QHelpFilterSettingsWidget class has been added, serving + as an editor for all available filters. + +**************************************************************************** +* Qt Designer * +**************************************************************************** + + - The palette editor dialog has been overhauled. + +**************************************************************************** +* macdeployqt * +**************************************************************************** + + - Added "-hardened-runtime" option to support app notarization. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - QDoc now supports DocBook as an output format. + - Introduced configuration variable 'locationinfo' to drop host-specific + paths from the generated output. + - Added capability to display class/method template parameters in the + generated documentation. + - QDoc now generates correct documentation for enum classes. + - QDoc is now aware of the namespace scope of an \fn command without + requiring fully qualified paths. + - Generate output for arguments passed to the \obsolete command. + - [QTBUG-37355] QDoc now generates a note for the name of the + corresponding handler in \qmlsignal documentation. + - Added support for CMake-based example projects. diff --git a/dist/changes-5.15.1 b/dist/changes-5.15.1 new file mode 100644 index 0000000000..018a8c41cc --- /dev/null +++ b/dist/changes-5.15.1 @@ -0,0 +1,47 @@ +Qt 5.15.1 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.15.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt Designer * +**************************************************************************** + + - New command line option --no-scaling allows to disable high-dpi + scaling. + +**************************************************************************** +* qdoc * +**************************************************************************** + + - QDoc now correctly handles templated structs, unions, and type aliases. + +**************************************************************************** +* windeployqt * +**************************************************************************** + + - New command line option --translations allows to pass a comma-separated + list of languages (.qm files) to deploy. + - Fixed an issue where the MSVC Runtime variant (Debug, Release) was + detected incorrectly especially on WinRT. + - Qt3D renderer plugins added in 5.15 are now automatically deployed. + +**************************************************************************** +* macdeployqt * +**************************************************************************** + + - .prl files are not copied anymore to the Resources folder. diff --git a/dist/changes-5.15.2 b/dist/changes-5.15.2 new file mode 100644 index 0000000000..fe9d83781e --- /dev/null +++ b/dist/changes-5.15.2 @@ -0,0 +1,72 @@ +Qt 5.15.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.15.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + + https://doc.qt.io/qt-5.15/index.html + +The Qt version 5.15 series is binary compatible with the 5.14.x series. +Applications compiled for 5.14 will continue to run with 5.15. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Important Behavior Changes * +**************************************************************************** + +**************************************************************************** +* Library * +**************************************************************************** + + - [QTBUG-87802] qdoc: Fix broken links generated by \sincelist + The combination of single-exec mode and outputting to subdirectories + (offline mode) made \sincelist generate href's to new classes and + functions that are missing the target subdirectory. This happened + because we did not pass the relative node to the function(s) that + generate that list - proper link resolution requires a check if the + page containing the \sincelist command comes from a different doc + module, and the relative node is used for that. + The bug was: qdoc: \sincelist generates broken links in certain + conditions + - [QTBUG-84703] qdoc: DocBook generator: Correctly handle enum classes + While commit 46f71fcc fixed handling of enum classes for the code + parser and marker, the DocBook generator has some dedicated code that + also needs to be amended. + The bug was: qdoc: DocBook generator: scoped enums not handled + correctly + - [QTBUG-86988] qdoc: DocBook generator: Remove code for encoding special characters + QXmlStreamWriter already handles this for us. + The bug was: qdoc: DocBook output format: XML special characters are + escaped twice + - [QTBUG-86759] Revert "macdeployqt: Don't copy .prl files into the Resources folder" + This was skipping other files from Resources/ as well, such as + “en-GB.pak” and “QtWebEngineProcess”. This reverts commit + aabba72f7965e06e2e6ed960d8cf8078249dac8c. + The bug was: Missing QtWebEngineProcess Application in application + frameworks + - [QTBUG-84727] QtHelp: Fix documentsFor() when not using filter engine + The bug was: QHelpIndexWidget does not emit documentActivated or + documentsActivated + - [QTBUG-86598] Assistant: fix build with QT_NO_CLIPBOARD + The bug was: Assistant fails to compile if QT_NO_CLIPBOARD is defined + - [QTBUG-86477] Fix static build of assistant + The bug was: [REG 5.15.0->5.15.1] assistant not build when building + whole Qt statically + - [QTBUG-86293] winrtrunner: Remove Windows Phone support + Windows Phone has not been supported for a while now. With newer + Windows versions the functionality causes issues. On build 1909 the + application hangs in CoUninitialize when called with --list-devices + and in build 2004 the needed classes are not registered at all. + The bug was: "winrtrunner --list-devices" hangs + - [QTBUG-86188] qdoc: Fix incorrect loop when processing tagged \fn parameters + This fixes ASSERT: "uint(i) < uint(size())" in file + qt5/qtbase/src/corelib/text/qstring.h, line 1067 + The bug was: qdoc: Crash when using a tagged \fn command + diff --git a/dist/changes-6.0.0 b/dist/changes-6.0.0 new file mode 100644 index 0000000000..c7d04efec3 --- /dev/null +++ b/dist/changes-6.0.0 @@ -0,0 +1,16 @@ +Qt 6.0.0 is a new major version release of Qt. It is not binary compatible with +earlier Qt releases. + +The goal has been to retain as much source compatibility with Qt 5.15 as +possible, but some changes were inevitable to make Qt a better framework. + +To make it easier to port to Qt 6.0, we have created a porting guide to +summarize those changes and provide guidance to handle them. In the guide, you +can find links to articles about changes that may affect your application and +help you transition from Qt 5.15 to Qt 6.0: + +https://doc.qt.io/qt-6/portingguide.html + +For more details refer to the online documentation of Qt 6.0: + +https://doc.qt.io/qt-6/index.html diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..8a360b99e7 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated from examples.pro. + +qt_examples_build_begin() + + +qt_exclude_tool_directories_from_default_target( + assistant +) + +if(TARGET Qt::Widgets) + add_subdirectory(help) + add_subdirectory(linguist) + add_subdirectory(uitools) +endif() +if(QT_FEATURE_process AND TARGET Qt::Widgets) + add_subdirectory(designer) + add_subdirectory(assistant) +endif() + +qt_examples_build_end() diff --git a/examples/assistant/CMakeLists.txt b/examples/assistant/CMakeLists.txt new file mode 100644 index 0000000000..bed9e1c4f8 --- /dev/null +++ b/examples/assistant/CMakeLists.txt @@ -0,0 +1,4 @@ +# Generated from assistant.pro. + +add_subdirectory(simpletextviewer) +add_subdirectory(remotecontrol) diff --git a/examples/assistant/remotecontrol/CMakeLists.txt b/examples/assistant/remotecontrol/CMakeLists.txt new file mode 100644 index 0000000000..6f80e04780 --- /dev/null +++ b/examples/assistant/remotecontrol/CMakeLists.txt @@ -0,0 +1,53 @@ +# Generated from remotecontrol.pro. + +cmake_minimum_required(VERSION 3.14) +project(remotecontrol LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/assistant/remotecontrol") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(remotecontrol + main.cpp + remotecontrol.cpp remotecontrol.h remotecontrol.ui +) +set_target_properties(remotecontrol PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(remotecontrol PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + + +# Resources: +set(remotecontrol_resource_files + "enter.png" +) + +qt6_add_resources(remotecontrol "remotecontrol" + PREFIX + "/remotecontrol" + FILES + ${remotecontrol_resource_files} +) + +install(TARGETS remotecontrol + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/assistant/remotecontrol/remotecontrol.h b/examples/assistant/remotecontrol/remotecontrol.h index 40e370f713..f59ffb7aab 100644 --- a/examples/assistant/remotecontrol/remotecontrol.h +++ b/examples/assistant/remotecontrol/remotecontrol.h @@ -64,7 +64,7 @@ class RemoteControl : public QMainWindow Q_OBJECT public: - RemoteControl(QWidget *parent = nullptr, Qt::WindowFlags flags = 0); + RemoteControl(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); ~RemoteControl(); private: diff --git a/examples/assistant/simpletextviewer/.prev_CMakeLists.txt b/examples/assistant/simpletextviewer/.prev_CMakeLists.txt new file mode 100644 index 0000000000..7721159416 --- /dev/null +++ b/examples/assistant/simpletextviewer/.prev_CMakeLists.txt @@ -0,0 +1,47 @@ +# Generated from simpletextviewer.pro. + +cmake_minimum_required(VERSION 3.14) +project(simpletextviewer LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/assistant/simpletextviewer") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(simpletextviewer + assistant.cpp assistant.h + findfiledialog.cpp findfiledialog.h + main.cpp + mainwindow.cpp mainwindow.h + textedit.cpp textedit.h +) +set_target_properties(simpletextviewer PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_compile_definitions(simpletextviewer PUBLIC + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/\\\" +) + +target_link_libraries(simpletextviewer PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS simpletextviewer + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/assistant/simpletextviewer/CMakeLists.txt b/examples/assistant/simpletextviewer/CMakeLists.txt new file mode 100644 index 0000000000..7340062562 --- /dev/null +++ b/examples/assistant/simpletextviewer/CMakeLists.txt @@ -0,0 +1,47 @@ +# Generated from simpletextviewer.pro. + +cmake_minimum_required(VERSION 3.14) +project(simpletextviewer LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/assistant/simpletextviewer") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(simpletextviewer + assistant.cpp assistant.h + findfiledialog.cpp findfiledialog.h + main.cpp + mainwindow.cpp mainwindow.h + textedit.cpp textedit.h +) +set_target_properties(simpletextviewer PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_compile_definitions(simpletextviewer PUBLIC + SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/" # special case +) + +target_link_libraries(simpletextviewer PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS simpletextviewer + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/assistant/simpletextviewer/assistant.cpp b/examples/assistant/simpletextviewer/assistant.cpp index 58103c14a3..d222bda6e6 100644 --- a/examples/assistant/simpletextviewer/assistant.cpp +++ b/examples/assistant/simpletextviewer/assistant.cpp @@ -50,25 +50,23 @@ #include "assistant.h" +#include #include #include #include #include -#include +#include -Assistant::Assistant() - : proc(0) -{ -} +Assistant::Assistant() = default; //! [0] Assistant::~Assistant() { - if (proc && proc->state() == QProcess::Running) { - proc->terminate(); - proc->waitForFinished(3000); + if (!m_process.isNull() && m_process->state() == QProcess::Running) { + QObject::disconnect(m_process.data(), &QProcess::finished, nullptr, nullptr); + m_process->terminate(); + m_process->waitForFinished(3000); } - delete proc; } //! [0] @@ -81,39 +79,79 @@ void Assistant::showDocumentation(const QString &page) QByteArray ba("SetSource "); ba.append("qthelp://org.qt-project.examples.simpletextviewer/doc/"); - proc->write(ba + page.toLocal8Bit() + '\n'); + m_process->write(ba + page.toLocal8Bit() + '\n'); } //! [1] +QString documentationDirectory() +{ + QStringList paths; +#ifdef SRCDIR + paths.append(QLatin1String(SRCDIR)); +#endif + paths.append(QLibraryInfo::location(QLibraryInfo::ExamplesPath)); + paths.append(QCoreApplication::applicationDirPath()); + paths.append(QStandardPaths::standardLocations(QStandardPaths::AppDataLocation)); + for (const auto &dir : qAsConst(paths)) { + const QString path = dir + QLatin1String("/documentation"); + if (QFileInfo::exists(path)) + return path; + } + return QString(); +} + //! [2] bool Assistant::startAssistant() { - if (!proc) - proc = new QProcess(); + if (m_process.isNull()) { + m_process.reset(new QProcess()); + QObject::connect(m_process.data(), &QProcess::finished, + m_process.data(), [this](int exitCode, QProcess::ExitStatus status) { + this->finished(exitCode, status); + }); + } - if (proc->state() != QProcess::Running) { + if (m_process->state() != QProcess::Running) { QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); -#if !defined(Q_OS_MAC) +#ifndef Q_OS_DARWIN app += QLatin1String("assistant"); #else app += QLatin1String("Assistant.app/Contents/MacOS/Assistant"); #endif - QStringList args; - args << QLatin1String("-collectionFile") - << QLibraryInfo::location(QLibraryInfo::ExamplesPath) - + QLatin1String("/assistant/simpletextviewer/documentation/simpletextviewer.qhc") - << QLatin1String("-enableRemoteControl"); + const QString collectionDirectory = documentationDirectory(); + if (collectionDirectory.isEmpty()) { + showError(tr("The documentation directory cannot be found")); + return false; + } + + QStringList args{QLatin1String("-collectionFile"), + collectionDirectory + QLatin1String("/simpletextviewer.qhc"), + QLatin1String("-enableRemoteControl")}; - proc->start(app, args); + m_process->start(app, args); - if (!proc->waitForStarted()) { - QMessageBox::critical(nullptr, - tr("Simple Text Viewer"), - tr("Unable to launch Qt Assistant (%1)").arg(app)); + if (!m_process->waitForStarted()) { + showError(tr("Unable to launch Qt Assistant (%1): %2").arg(app, m_process->errorString())); return false; } } return true; } //! [2] + +void Assistant::showError(const QString &message) +{ + QMessageBox::critical(QApplication::activeWindow(), + tr("Simple Text Viewer"), message); +} + +void Assistant::finished(int exitCode, QProcess::ExitStatus status) +{ + const QString stdErr = QString::fromLocal8Bit(m_process->readAllStandardError()); + if (status != QProcess::NormalExit) { + showError(tr("Assistant crashed: ").arg(stdErr)); + } else if (exitCode != 0) { + showError(tr("Assistant exited with %1: %2").arg(exitCode).arg(stdErr)); + } +} diff --git a/examples/assistant/simpletextviewer/assistant.h b/examples/assistant/simpletextviewer/assistant.h index 1ea7dd78f2..c513c34284 100644 --- a/examples/assistant/simpletextviewer/assistant.h +++ b/examples/assistant/simpletextviewer/assistant.h @@ -52,11 +52,10 @@ #define ASSISTANT_H #include +#include +#include #include -QT_BEGIN_NAMESPACE -class QProcess; -QT_END_NAMESPACE class Assistant { @@ -69,7 +68,10 @@ class Assistant private: bool startAssistant(); - QProcess *proc; + void showError(const QString &message); + void finished(int exitCode, QProcess::ExitStatus status); + + QScopedPointer m_process; }; #endif diff --git a/examples/assistant/simpletextviewer/findfiledialog.cpp b/examples/assistant/simpletextviewer/findfiledialog.cpp index cf64e9a6a5..e17f7ec0f7 100644 --- a/examples/assistant/simpletextviewer/findfiledialog.cpp +++ b/examples/assistant/simpletextviewer/findfiledialog.cpp @@ -59,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -105,13 +106,11 @@ void FindFileDialog::help() } //! [2] -void FindFileDialog::openFile(QTreeWidgetItem *item) +void FindFileDialog::openFile() { - if (!item) { - item = foundFilesTree->currentItem(); - if (!item) - return; - } + auto item = foundFilesTree->currentItem(); + if (!item) + return; QString fileName = item->text(0); QString path = directoryComboBox->currentText() + QDir::separator(); @@ -129,8 +128,10 @@ void FindFileDialog::update() void FindFileDialog::findFiles() { - QRegExp filePattern(fileNameComboBox->currentText() + "*"); - filePattern.setPatternSyntax(QRegExp::Wildcard); + QString wildCard = fileNameComboBox->currentText(); + if (!wildCard.endsWith('*')) + wildCard += '*'; + QRegularExpression filePattern(QRegularExpression::wildcardToRegularExpression(wildCard)); QDir directory(directoryComboBox->currentText()); @@ -138,7 +139,7 @@ void FindFileDialog::findFiles() QStringList matchingFiles; for (const QString &file : allFiles) { - if (filePattern.exactMatch(file)) + if (filePattern.match(file).hasMatch()) matchingFiles << file; } showFiles(matchingFiles); @@ -161,14 +162,14 @@ void FindFileDialog::createButtons() { browseButton = new QToolButton; browseButton->setText(tr("...")); - connect(browseButton, SIGNAL(clicked()), this, SLOT(browse())); + connect(browseButton, &QAbstractButton::clicked, this, &FindFileDialog::browse); buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel | QDialogButtonBox::Help); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(openFile())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(help())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &FindFileDialog::openFile); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(buttonBox, &QDialogButtonBox::helpRequested, this, &FindFileDialog::help); } void FindFileDialog::createComboBoxes() @@ -182,14 +183,14 @@ void FindFileDialog::createComboBoxes() directoryComboBox->setMinimumContentsLength(30); directoryComboBox->setSizeAdjustPolicy( - QComboBox::AdjustToMinimumContentsLength); + QComboBox::AdjustToContents); directoryComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - connect(fileNameComboBox, SIGNAL(editTextChanged(QString)), - this, SLOT(update())); - connect(directoryComboBox, SIGNAL(currentIndexChanged(QString)), - this, SLOT(update())); + connect(fileNameComboBox, &QComboBox::editTextChanged, + this, &FindFileDialog::update); + connect(directoryComboBox, &QComboBox::currentTextChanged, + this, &FindFileDialog::update); } void FindFileDialog::createFilesTree() @@ -200,8 +201,8 @@ void FindFileDialog::createFilesTree() foundFilesTree->setRootIsDecorated(false); foundFilesTree->setSelectionMode(QAbstractItemView::SingleSelection); - connect(foundFilesTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), - this, SLOT(openFile(QTreeWidgetItem*))); + connect(foundFilesTree, &QTreeWidget::itemActivated, + this, &FindFileDialog::openFile); } void FindFileDialog::createLabels() diff --git a/examples/assistant/simpletextviewer/findfiledialog.h b/examples/assistant/simpletextviewer/findfiledialog.h index 6ca57b061d..605da09543 100644 --- a/examples/assistant/simpletextviewer/findfiledialog.h +++ b/examples/assistant/simpletextviewer/findfiledialog.h @@ -76,7 +76,7 @@ class FindFileDialog : public QDialog private slots: void browse(); void help(); - void openFile(QTreeWidgetItem *item = nullptr); + void openFile(); void update(); private: diff --git a/examples/assistant/simpletextviewer/mainwindow.cpp b/examples/assistant/simpletextviewer/mainwindow.cpp index 5b0564ca12..f70162c218 100644 --- a/examples/assistant/simpletextviewer/mainwindow.cpp +++ b/examples/assistant/simpletextviewer/mainwindow.cpp @@ -112,26 +112,26 @@ void MainWindow::createActions() { assistantAct = new QAction(tr("Help Contents"), this); assistantAct->setShortcut(QKeySequence::HelpContents); - connect(assistantAct, SIGNAL(triggered()), this, SLOT(showDocumentation())); + connect(assistantAct, &QAction::triggered, this, &MainWindow::showDocumentation); //! [4] openAct = new QAction(tr("&Open..."), this); openAct->setShortcut(QKeySequence::Open); - connect(openAct, SIGNAL(triggered()), this, SLOT(open())); + connect(openAct, &QAction::triggered, this, &MainWindow::open); clearAct = new QAction(tr("&Clear"), this); clearAct->setShortcut(tr("Ctrl+C")); - connect(clearAct, SIGNAL(triggered()), textViewer, SLOT(clear())); + connect(clearAct, &QAction::triggered, textViewer, &QTextEdit::clear); exitAct = new QAction(tr("E&xit"), this); exitAct->setShortcuts(QKeySequence::Quit); - connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); + connect(exitAct, &QAction::triggered, this, &QWidget::close); aboutAct = new QAction(tr("&About"), this); - connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); + connect(aboutAct, &QAction::triggered, this, &MainWindow::about); aboutQtAct = new QAction(tr("About &Qt"), this); - connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + connect(aboutQtAct, &QAction::triggered, QApplication::aboutQt); //! [5] } //! [5] diff --git a/examples/assistant/simpletextviewer/mainwindow.h b/examples/assistant/simpletextviewer/mainwindow.h index e8e917ea38..1c7f21761e 100644 --- a/examples/assistant/simpletextviewer/mainwindow.h +++ b/examples/assistant/simpletextviewer/mainwindow.h @@ -67,7 +67,6 @@ class MainWindow : public QMainWindow public: MainWindow(); - void showDocumentation(const QString &file); private slots: void about(); diff --git a/examples/assistant/simpletextviewer/simpletextviewer.pro b/examples/assistant/simpletextviewer/simpletextviewer.pro index 314e75b36a..b0de7f4e7f 100644 --- a/examples/assistant/simpletextviewer/simpletextviewer.pro +++ b/examples/assistant/simpletextviewer/simpletextviewer.pro @@ -8,6 +8,8 @@ SOURCES = main.cpp \ assistant.cpp \ textedit.cpp +DEFINES += SRCDIR=\\\"$$PWD/\\\" + QT += widgets target.path = $$[QT_INSTALL_EXAMPLES]/assistant/simpletextviewer diff --git a/examples/designer/CMakeLists.txt b/examples/designer/CMakeLists.txt new file mode 100644 index 0000000000..f5de4c52fb --- /dev/null +++ b/examples/designer/CMakeLists.txt @@ -0,0 +1,19 @@ +# Generated from designer.pro. + + +qt_exclude_tool_directories_from_default_target( + containerextension + taskmenuextension +) + +add_subdirectory(calculatorform) +if(QT_BUILD_SHARED_LIBS AND NOT solaris-cc_x_) + add_subdirectory(calculatorbuilder) + add_subdirectory(worldtimeclockbuilder) +endif() +if(QT_BUILD_SHARED_LIBS) + add_subdirectory(containerextension) + add_subdirectory(customwidgetplugin) + add_subdirectory(taskmenuextension) + add_subdirectory(worldtimeclockplugin) +endif() diff --git a/examples/designer/calculatorbuilder/CMakeLists.txt b/examples/designer/calculatorbuilder/CMakeLists.txt new file mode 100644 index 0000000000..2cb01e9470 --- /dev/null +++ b/examples/designer/calculatorbuilder/CMakeLists.txt @@ -0,0 +1,55 @@ +# Generated from calculatorbuilder.pro. + +cmake_minimum_required(VERSION 3.14) +project(calculatorbuilder LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/designer/calculatorbuilder") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiTools) + +qt_add_executable(calculatorbuilder + calculatorform.cpp calculatorform.h + main.cpp +) +set_target_properties(calculatorbuilder PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(calculatorbuilder PUBLIC + Qt::Core + Qt::Gui + Qt::UiTools + Qt::Widgets +) + + +# Resources: +set(calculatorbuilder_resource_files + "calculatorform.ui" +) + +qt6_add_resources(calculatorbuilder "calculatorbuilder" + PREFIX + "/forms" + FILES + ${calculatorbuilder_resource_files} +) + +install(TARGETS calculatorbuilder + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/calculatorform/CMakeLists.txt b/examples/designer/calculatorform/CMakeLists.txt new file mode 100644 index 0000000000..ad721d0ccb --- /dev/null +++ b/examples/designer/calculatorform/CMakeLists.txt @@ -0,0 +1,40 @@ +# Generated from calculatorform.pro. + +cmake_minimum_required(VERSION 3.14) +project(calculatorform LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/designer/calculatorform") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(calculatorform + calculatorform.cpp calculatorform.h calculatorform.ui + main.cpp +) +set_target_properties(calculatorform PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(calculatorform PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS calculatorform + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/containerextension/.prev_CMakeLists.txt b/examples/designer/containerextension/.prev_CMakeLists.txt new file mode 100644 index 0000000000..3225c4093e --- /dev/null +++ b/examples/designer/containerextension/.prev_CMakeLists.txt @@ -0,0 +1,44 @@ +# Generated from containerextension.pro. + +cmake_minimum_required(VERSION 3.14) +project(containerextension LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS Designer) + +qt_add_executable(containerextension + multipagewidget.cpp multipagewidget.h + multipagewidgetcontainerextension.cpp multipagewidgetcontainerextension.h + multipagewidgetextensionfactory.cpp multipagewidgetextensionfactory.h + multipagewidgetplugin.cpp multipagewidgetplugin.h +) +set_target_properties(containerextension PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(containerextension PUBLIC + Qt::Core + Qt::Designer + Qt::Gui + Qt::Widgets +) + +install(TARGETS containerextension + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/containerextension/CMakeLists.txt b/examples/designer/containerextension/CMakeLists.txt new file mode 100644 index 0000000000..1a6a0f61b7 --- /dev/null +++ b/examples/designer/containerextension/CMakeLists.txt @@ -0,0 +1,47 @@ +# Generated from containerextension.pro. + +cmake_minimum_required(VERSION 3.14) +project(containerextension LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/plugins/designer") # special case + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS Designer) + +# special case begin +qt_add_plugin(containerextension) +target_sources(containerextension PRIVATE + multipagewidget.cpp multipagewidget.h + multipagewidgetcontainerextension.cpp multipagewidgetcontainerextension.h + multipagewidgetextensionfactory.cpp multipagewidgetextensionfactory.h + multipagewidgetplugin.cpp multipagewidgetplugin.h +) +# special case end +set_target_properties(containerextension PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(containerextension PUBLIC + Qt::Core + Qt::Designer + Qt::Gui + Qt::Widgets +) + +install(TARGETS containerextension + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/containerextension/multipagewidgetcontainerextension.cpp b/examples/designer/containerextension/multipagewidgetcontainerextension.cpp index ca9e79d786..2c8eff6bd7 100644 --- a/examples/designer/containerextension/multipagewidgetcontainerextension.cpp +++ b/examples/designer/containerextension/multipagewidgetcontainerextension.cpp @@ -61,6 +61,11 @@ MultiPageWidgetContainerExtension::MultiPageWidgetContainerExtension(MultiPageWi //! [0] //! [1] +bool MultiPageWidgetContainerExtension::canAddWidget() const +{ + return true; +} + void MultiPageWidgetContainerExtension::addWidget(QWidget *widget) { myWidget->addPage(widget); @@ -89,6 +94,12 @@ void MultiPageWidgetContainerExtension::insertWidget(int index, QWidget *widget) //! [4] //! [5] +bool MultiPageWidgetContainerExtension::canRemove(int index) const +{ + Q_UNUSED(index); + return true; +} + void MultiPageWidgetContainerExtension::remove(int index) { myWidget->removePage(index); diff --git a/examples/designer/containerextension/multipagewidgetcontainerextension.h b/examples/designer/containerextension/multipagewidgetcontainerextension.h index 7813aee9eb..47814c6925 100644 --- a/examples/designer/containerextension/multipagewidgetcontainerextension.h +++ b/examples/designer/containerextension/multipagewidgetcontainerextension.h @@ -68,10 +68,12 @@ class MultiPageWidgetContainerExtension: public QObject, public: explicit MultiPageWidgetContainerExtension(MultiPageWidget *widget, QObject *parent); + bool canAddWidget() const override; void addWidget(QWidget *widget) override; int count() const override; int currentIndex() const override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int index) const override; void remove(int index) override; void setCurrentIndex(int index) override; QWidget *widget(int index) const override; diff --git a/examples/designer/containerextension/multipagewidgetplugin.cpp b/examples/designer/containerextension/multipagewidgetplugin.cpp index d29043ecf1..a5a3272b59 100644 --- a/examples/designer/containerextension/multipagewidgetplugin.cpp +++ b/examples/designer/containerextension/multipagewidgetplugin.cpp @@ -144,19 +144,19 @@ void MultiPageWidgetPlugin::initialize(QDesignerFormEditorInterface *formEditor) //! [7] QString MultiPageWidgetPlugin::domXml() const { - return QLatin1String("\ -\ - \ - \ - \ - \ - \ - MultiPageWidget\ - QWidget\ - addPage\ - \ - \ -"); + return QLatin1String(R"( + + + + + + + MultiPageWidget + QWidget + addPage + + +)"); } //! [7] diff --git a/examples/designer/customwidgetplugin/.prev_CMakeLists.txt b/examples/designer/customwidgetplugin/.prev_CMakeLists.txt new file mode 100644 index 0000000000..1e25517f83 --- /dev/null +++ b/examples/designer/customwidgetplugin/.prev_CMakeLists.txt @@ -0,0 +1,42 @@ +# Generated from customwidgetplugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(customwidgetplugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiPlugin) + +qt_add_executable(customwidgetplugin + analogclock.cpp analogclock.h + customwidgetplugin.cpp customwidgetplugin.h +) +set_target_properties(customwidgetplugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(customwidgetplugin PUBLIC + Qt::Core + Qt::Gui + Qt::UiPlugin + Qt::Widgets +) + +install(TARGETS customwidgetplugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/customwidgetplugin/CMakeLists.txt b/examples/designer/customwidgetplugin/CMakeLists.txt new file mode 100644 index 0000000000..764fe7373b --- /dev/null +++ b/examples/designer/customwidgetplugin/CMakeLists.txt @@ -0,0 +1,45 @@ +# Generated from customwidgetplugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(customwidgetplugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/plugins/designer") # special case + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiPlugin) + +# special case begin +qt_add_plugin(customwidgetplugin) +target_sources(customwidgetplugin PRIVATE + analogclock.cpp analogclock.h + customwidgetplugin.cpp customwidgetplugin.h +) +# special case end +set_target_properties(customwidgetplugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(customwidgetplugin PUBLIC + Qt::Core + Qt::Gui + Qt::UiPlugin + Qt::Widgets +) + +install(TARGETS customwidgetplugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/customwidgetplugin/customwidgetplugin.cpp b/examples/designer/customwidgetplugin/customwidgetplugin.cpp index a3d75d311d..a728a689c8 100644 --- a/examples/designer/customwidgetplugin/customwidgetplugin.cpp +++ b/examples/designer/customwidgetplugin/customwidgetplugin.cpp @@ -129,26 +129,32 @@ bool AnalogClockPlugin::isContainer() const //! [10] QString AnalogClockPlugin::domXml() const { - return "\n" - " \n" + return QLatin1String(R"( + + +)" //! [11] - " \n" - " \n" - " 0\n" - " 0\n" - " 100\n" - " 100\n" - " \n" - " \n" +R"( + + + 0 + 0 + 100 + 100 + + +") //! [11] - " \n" - " The current time\n" - " \n" - " \n" - " The analog clock widget displays the current time.\n" - " \n" - " \n" - "\n"; +R"( + + The current time + + + The analog clock widget displays the current time. + + + +)"); } //! [10] diff --git a/examples/designer/designer.pro b/examples/designer/designer.pro index 2248d3ec19..3ffd443e17 100644 --- a/examples/designer/designer.pro +++ b/examples/designer/designer.pro @@ -1,12 +1,14 @@ TEMPLATE = subdirs SUBDIRS = calculatorform -!static:SUBDIRS += calculatorbuilder \ +!contains(CONFIG, static) { + SUBDIRS += calculatorbuilder \ containerextension \ customwidgetplugin \ taskmenuextension \ worldtimeclockbuilder \ worldtimeclockplugin +} # the sun cc compiler has a problem with the include lines for the form.prf solaris-cc*:SUBDIRS -= calculatorbuilder \ diff --git a/examples/designer/doc/src/containerextension.qdoc b/examples/designer/doc/src/containerextension.qdoc index ce5d161fff..6b3f9c989c 100644 --- a/examples/designer/doc/src/containerextension.qdoc +++ b/examples/designer/doc/src/containerextension.qdoc @@ -171,18 +171,17 @@ another page or changes one of the page titles. To be able to give each page their own title, we have chosen to use the QWidget::windowTitle property to store the page title (for more - information see the MultiPageWidget class \l - {containerextension/multipagewidget.cpp}{implementation}). Note - that currently there is no way of adding a custom property (e.g., - a page title) to the pages without using a predefined property as - placeholder. + information see the MultiPageWidget class implementation in + \e containerextension/multipagewidget.cpp. Note that currently there + is no way of adding a custom property (for example, a page title) to + the pages without using a predefined property as placeholder. The \c MultiPageWidgetPlugin class inherits from both QObject and QDesignerCustomWidgetInterface. It is important to remember, when using multiple inheritance, to ensure that all the interfaces (i.e. the classes that doesn't inherit Q_OBJECT) are made known to the meta object system using the Q_INTERFACES() macro. This - enables \QD to use \l {qobject_cast(QObject * object)} to query for supported + enables \QD to use qobject_cast() to query for supported interfaces using nothing but a QObject pointer. \section1 MultiPageWidgetPlugin Class Implementation @@ -279,8 +278,8 @@ QDesignerPropertySheetExtension::indexOf() function. As previously mentioned, we have chosen to use the QWidget::windowTitle property to store the page title (for more information see the - MultiPageWidget class \l - {containerextension/multipagewidget.cpp}{implementation}). + MultiPageWidget class implementation in + \e containerextension/multipagewidget.cpp. Finally, we implicitly force an update of the page's property sheet by calling the QDesignerPropertySheetExtension::setChanged() function. @@ -429,6 +428,7 @@ \snippet containerextension/multipagewidgetcontainerextension.cpp 3 You must reimplement \l + {QDesignerContainerExtension::canAddWidget()}{canAddWidget()} and \l {QDesignerContainerExtension::addWidget()}{addWidget()} adding a given page to the container, \l {QDesignerContainerExtension::count()}{count()} returning the @@ -447,6 +447,7 @@ You must reimplement \l {QDesignerContainerExtension::insertWidget()}{insertWidget()} adding a given page to the container at a given index, \l + {QDesignerContainerExtension::canRemove()}{canRemove()} and \l {QDesignerContainerExtension::remove()}{remove()} deleting the page at a given index, \l {QDesignerContainerExtension::setCurrentIndex()}{setCurrentIndex()} @@ -489,7 +490,6 @@ updated whenever the user views another page or changes one of the page titles. - See the MultiPageWidget class \l - {containerextension/multipagewidget.cpp}{implementation} - for more details. + See the MultiPageWidget class implementation in + \e containerextension/multipagewidget.cpp for more details. */ diff --git a/examples/designer/doc/src/taskmenuextension.qdoc b/examples/designer/doc/src/taskmenuextension.qdoc index a480fa3a83..6b5df136ab 100644 --- a/examples/designer/doc/src/taskmenuextension.qdoc +++ b/examples/designer/doc/src/taskmenuextension.qdoc @@ -171,7 +171,7 @@ using multiple inheritance, to ensure that all the interfaces (i.e. the classes that doesn't inherit Q_OBJECT) are made known to the meta object system using the Q_INTERFACES() macro. This - enables \QD to use \l {qobject_cast(QObject * object)} to query for supported + enables \QD to use qobject_cast() to query for supported interfaces using nothing but a QObject pointer. \section1 TicTacToePlugin Class Implementation diff --git a/examples/designer/doc/src/worldtimeclockplugin.qdoc b/examples/designer/doc/src/worldtimeclockplugin.qdoc index 99a4528679..19ec83f6b9 100644 --- a/examples/designer/doc/src/worldtimeclockplugin.qdoc +++ b/examples/designer/doc/src/worldtimeclockplugin.qdoc @@ -121,7 +121,7 @@ using multiple inheritance, to ensure that all the interfaces (i.e. the classes that doesn't inherit Q_OBJECT) are made known to the meta object system using the Q_INTERFACES() macro. This - enables \QD to use \l {qobject_cast(QObject * object)} to query for supported + enables \QD to use qobject_cast() to query for supported interfaces using nothing but a QObject pointer. The implementation of the \c WorldTimeClockPlugin is also diff --git a/examples/designer/taskmenuextension/.prev_CMakeLists.txt b/examples/designer/taskmenuextension/.prev_CMakeLists.txt new file mode 100644 index 0000000000..8551d0a466 --- /dev/null +++ b/examples/designer/taskmenuextension/.prev_CMakeLists.txt @@ -0,0 +1,44 @@ +# Generated from taskmenuextension.pro. + +cmake_minimum_required(VERSION 3.14) +project(taskmenuextension LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS Designer) + +qt_add_executable(taskmenuextension + tictactoe.cpp tictactoe.h + tictactoedialog.cpp tictactoedialog.h + tictactoeplugin.cpp tictactoeplugin.h + tictactoetaskmenu.cpp tictactoetaskmenu.h +) +set_target_properties(taskmenuextension PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(taskmenuextension PUBLIC + Qt::Core + Qt::Designer + Qt::Gui + Qt::Widgets +) + +install(TARGETS taskmenuextension + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/taskmenuextension/CMakeLists.txt b/examples/designer/taskmenuextension/CMakeLists.txt new file mode 100644 index 0000000000..a91b58eac9 --- /dev/null +++ b/examples/designer/taskmenuextension/CMakeLists.txt @@ -0,0 +1,47 @@ +# Generated from taskmenuextension.pro. + +cmake_minimum_required(VERSION 3.14) +project(taskmenuextension LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/plugins/designer") # special case + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS Designer) + +# special case begin +qt_add_plugin(taskmenuextension) +target_sources(taskmenuextension PRIVATE + tictactoe.cpp tictactoe.h + tictactoedialog.cpp tictactoedialog.h + tictactoeplugin.cpp tictactoeplugin.h + tictactoetaskmenu.cpp tictactoetaskmenu.h +) +# special case end +set_target_properties(taskmenuextension PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(taskmenuextension PUBLIC + Qt::Core + Qt::Designer + Qt::Gui + Qt::Widgets +) + +install(TARGETS taskmenuextension + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/taskmenuextension/tictactoe.h b/examples/designer/taskmenuextension/tictactoe.h index 1904f9c977..23784d7502 100644 --- a/examples/designer/taskmenuextension/tictactoe.h +++ b/examples/designer/taskmenuextension/tictactoe.h @@ -78,7 +78,9 @@ class TicTacToe : public QWidget void paintEvent(QPaintEvent *event) override; private: - enum : char { Empty = '-', Cross = 'X', Nought = 'O' }; + static constexpr char16_t Empty = '-'; + static constexpr char16_t Cross = 'X'; + static constexpr char16_t Nought = 'O'; QRect cellRect(int row, int col) const; int cellWidth() const { return width() / 3; } diff --git a/examples/designer/taskmenuextension/tictactoeplugin.cpp b/examples/designer/taskmenuextension/tictactoeplugin.cpp index 724720ad53..45075fe62a 100644 --- a/examples/designer/taskmenuextension/tictactoeplugin.cpp +++ b/examples/designer/taskmenuextension/tictactoeplugin.cpp @@ -129,19 +129,20 @@ void TicTacToePlugin::initialize(QDesignerFormEditorInterface *formEditor) QString TicTacToePlugin::domXml() const { - return QLatin1String("\ -\ - \ - \ - \ - TicTacToe\ - \ - Tic Tac Toe state\ - \ - \ - \ - \ -"); + return QLatin1String(R"( + + + + + TicTacToe + + Tic Tac Toe state + + + + + +)"); } //! [3] diff --git a/examples/designer/worldtimeclockbuilder/CMakeLists.txt b/examples/designer/worldtimeclockbuilder/CMakeLists.txt new file mode 100644 index 0000000000..2c93155c75 --- /dev/null +++ b/examples/designer/worldtimeclockbuilder/CMakeLists.txt @@ -0,0 +1,54 @@ +# Generated from worldtimeclockbuilder.pro. + +cmake_minimum_required(VERSION 3.14) +project(worldtimeclockbuilder LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/designer/worldtimeclockbuilder") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiTools) + +qt_add_executable(worldtimeclockbuilder + main.cpp +) +set_target_properties(worldtimeclockbuilder PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(worldtimeclockbuilder PUBLIC + Qt::Core + Qt::Gui + Qt::UiTools + Qt::Widgets +) + + +# Resources: +set(worldtimeclockbuilder_resource_files + "form.ui" +) + +qt6_add_resources(worldtimeclockbuilder "worldtimeclockbuilder" + PREFIX + "/forms" + FILES + ${worldtimeclockbuilder_resource_files} +) + +install(TARGETS worldtimeclockbuilder + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/worldtimeclockplugin/.prev_CMakeLists.txt b/examples/designer/worldtimeclockplugin/.prev_CMakeLists.txt new file mode 100644 index 0000000000..1886b1ce64 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/.prev_CMakeLists.txt @@ -0,0 +1,42 @@ +# Generated from worldtimeclockplugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(worldtimeclockplugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiPlugin) + +qt_add_executable(worldtimeclockplugin + worldtimeclock.cpp worldtimeclock.h + worldtimeclockplugin.cpp worldtimeclockplugin.h +) +set_target_properties(worldtimeclockplugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(worldtimeclockplugin PUBLIC + Qt::Core + Qt::Gui + Qt::UiPlugin + Qt::Widgets +) + +install(TARGETS worldtimeclockplugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/worldtimeclockplugin/CMakeLists.txt b/examples/designer/worldtimeclockplugin/CMakeLists.txt new file mode 100644 index 0000000000..6e675fc9b4 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/CMakeLists.txt @@ -0,0 +1,45 @@ +# Generated from worldtimeclockplugin.pro. + +cmake_minimum_required(VERSION 3.14) +project(worldtimeclockplugin LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/plugins/designer") # special case + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiPlugin) + +# special case begin +qt_add_plugin(worldtimeclockplugin) +target_sources(worldtimeclockplugin PRIVATE + worldtimeclock.cpp worldtimeclock.h + worldtimeclockplugin.cpp worldtimeclockplugin.h +) +# special case end +set_target_properties(worldtimeclockplugin PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(worldtimeclockplugin PUBLIC + Qt::Core + Qt::Gui + Qt::UiPlugin + Qt::Widgets +) + +install(TARGETS worldtimeclockplugin + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp index 8cd059c561..83223d59fc 100644 --- a/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp +++ b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp @@ -108,18 +108,20 @@ bool WorldTimeClockPlugin::isContainer() const QString WorldTimeClockPlugin::domXml() const { - return "\n" - " \n" - " \n" - " \n" - " 0\n" - " 0\n" - " 100\n" - " 100\n" - " \n" - " \n" - " \n" - ""; + return QLatin1String(R"( + + + + + 0 + 0 + 100 + 100 + + + + +)"); } QString WorldTimeClockPlugin::includeFile() const diff --git a/examples/help/CMakeLists.txt b/examples/help/CMakeLists.txt new file mode 100644 index 0000000000..b61829db77 --- /dev/null +++ b/examples/help/CMakeLists.txt @@ -0,0 +1,3 @@ +# Generated from help.pro. + +add_subdirectory(contextsensitivehelp) diff --git a/examples/help/contextsensitivehelp/CMakeLists.txt b/examples/help/contextsensitivehelp/CMakeLists.txt new file mode 100644 index 0000000000..40d89a3e44 --- /dev/null +++ b/examples/help/contextsensitivehelp/CMakeLists.txt @@ -0,0 +1,43 @@ +# Generated from contextsensitivehelp.pro. + +cmake_minimum_required(VERSION 3.14) +project(contextsensitivehelp LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/help/contextsensitivehelp") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Help) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(contextsensitivehelp + helpbrowser.cpp helpbrowser.h + main.cpp + wateringconfigdialog.cpp wateringconfigdialog.h wateringconfigdialog.ui +) +set_target_properties(contextsensitivehelp PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(contextsensitivehelp PUBLIC + Qt::Core + Qt::Gui + Qt::Help + Qt::Widgets +) + +install(TARGETS contextsensitivehelp + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/help/contextsensitivehelp/docs/wateringmachine.qch b/examples/help/contextsensitivehelp/docs/wateringmachine.qch index 35d29be226..1433acfc98 100644 Binary files a/examples/help/contextsensitivehelp/docs/wateringmachine.qch and b/examples/help/contextsensitivehelp/docs/wateringmachine.qch differ diff --git a/examples/help/contextsensitivehelp/docs/wateringmachine.qhc b/examples/help/contextsensitivehelp/docs/wateringmachine.qhc index b5653c3ff7..98cfa14817 100644 Binary files a/examples/help/contextsensitivehelp/docs/wateringmachine.qhc and b/examples/help/contextsensitivehelp/docs/wateringmachine.qhc differ diff --git a/examples/help/contextsensitivehelp/helpbrowser.cpp b/examples/help/contextsensitivehelp/helpbrowser.cpp index 67314374d9..f0cc4a1d72 100644 --- a/examples/help/contextsensitivehelp/helpbrowser.cpp +++ b/examples/help/contextsensitivehelp/helpbrowser.cpp @@ -53,6 +53,7 @@ #include #include "helpbrowser.h" +#include "qhelplink.h" HelpBrowser::HelpBrowser(QWidget *parent) : QTextBrowser(parent) @@ -70,9 +71,9 @@ HelpBrowser::HelpBrowser(QWidget *parent) void HelpBrowser::showHelpForKeyword(const QString &id) { if (m_helpEngine) { - QMap links = m_helpEngine->linksForIdentifier(id); - if (links.count()) - setSource(links.constBegin().value()); + QList documents = m_helpEngine->documentsForIdentifier(id); + if (documents.count()) + setSource(documents.first().url); } } diff --git a/examples/linguist/CMakeLists.txt b/examples/linguist/CMakeLists.txt new file mode 100644 index 0000000000..612ae91cc4 --- /dev/null +++ b/examples/linguist/CMakeLists.txt @@ -0,0 +1,5 @@ +# Generated from linguist.pro. + +add_subdirectory(arrowpad) +add_subdirectory(hellotr) +add_subdirectory(trollprint) diff --git a/examples/linguist/arrowpad/CMakeLists.txt b/examples/linguist/arrowpad/CMakeLists.txt new file mode 100644 index 0000000000..cf652c8f2b --- /dev/null +++ b/examples/linguist/arrowpad/CMakeLists.txt @@ -0,0 +1,41 @@ +# Generated from arrowpad.pro. + +cmake_minimum_required(VERSION 3.14) +project(arrowpad LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/linguist/arrowpad") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(arrowpad + arrowpad.cpp arrowpad.h + main.cpp + mainwindow.cpp mainwindow.h +) +set_target_properties(arrowpad PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(arrowpad PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS arrowpad + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/linguist/hellotr/CMakeLists.txt b/examples/linguist/hellotr/CMakeLists.txt new file mode 100644 index 0000000000..c9c65ac6ce --- /dev/null +++ b/examples/linguist/hellotr/CMakeLists.txt @@ -0,0 +1,39 @@ +# Generated from hellotr.pro. + +cmake_minimum_required(VERSION 3.14) +project(hellotr LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/linguist/hellotr") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(hellotr + main.cpp +) +set_target_properties(hellotr PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(hellotr PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS hellotr + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/linguist/hellotr/main.cpp b/examples/linguist/hellotr/main.cpp index bf7effc46d..24206f093e 100644 --- a/examples/linguist/hellotr/main.cpp +++ b/examples/linguist/hellotr/main.cpp @@ -64,7 +64,8 @@ int main(int argc, char *argv[]) //! [5] QTranslator translator; //! [5] //! [6] - translator.load("hellotr_la"); + if (!translator.load("hellotr_la")) + return 1; //! [6] //! [7] app.installTranslator(&translator); //! [4] //! [7] diff --git a/examples/linguist/trollprint/CMakeLists.txt b/examples/linguist/trollprint/CMakeLists.txt new file mode 100644 index 0000000000..e1c953cdfb --- /dev/null +++ b/examples/linguist/trollprint/CMakeLists.txt @@ -0,0 +1,41 @@ +# Generated from trollprint.pro. + +cmake_minimum_required(VERSION 3.14) +project(trollprint LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/linguist/trollprint") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(trollprint + main.cpp + mainwindow.cpp mainwindow.h + printpanel.cpp printpanel.h +) +set_target_properties(trollprint PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(trollprint PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS trollprint + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/uitools/CMakeLists.txt b/examples/uitools/CMakeLists.txt new file mode 100644 index 0000000000..a31646da0f --- /dev/null +++ b/examples/uitools/CMakeLists.txt @@ -0,0 +1,4 @@ +# Generated from uitools.pro. + +add_subdirectory(multipleinheritance) +add_subdirectory(textfinder) diff --git a/examples/uitools/multipleinheritance/CMakeLists.txt b/examples/uitools/multipleinheritance/CMakeLists.txt new file mode 100644 index 0000000000..7a942d53a0 --- /dev/null +++ b/examples/uitools/multipleinheritance/CMakeLists.txt @@ -0,0 +1,40 @@ +# Generated from multipleinheritance.pro. + +cmake_minimum_required(VERSION 3.14) +project(multipleinheritance LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/uitools/multipleinheritance") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) + +qt_add_executable(multipleinheritance + calculatorform.cpp calculatorform.h calculatorform.ui + main.cpp +) +set_target_properties(multipleinheritance PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(multipleinheritance PUBLIC + Qt::Core + Qt::Gui + Qt::Widgets +) + +install(TARGETS multipleinheritance + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/uitools/textfinder/CMakeLists.txt b/examples/uitools/textfinder/CMakeLists.txt new file mode 100644 index 0000000000..84fbd72c4e --- /dev/null +++ b/examples/uitools/textfinder/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated from textfinder.pro. + +cmake_minimum_required(VERSION 3.14) +project(textfinder LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/uitools/textfinder") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Widgets) +find_package(Qt6 COMPONENTS UiTools) + +qt_add_executable(textfinder + main.cpp + textfinder.cpp textfinder.h +) +set_target_properties(textfinder PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(textfinder PUBLIC + Qt::Core + Qt::Gui + Qt::UiTools + Qt::Widgets +) + + +# Resources: +set(textfinder_resource_files + "forms/input.txt" + "forms/textfinder.ui" +) + +qt6_add_resources(textfinder "textfinder" + PREFIX + "/" + FILES + ${textfinder_resource_files} +) + +install(TARGETS textfinder + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/uitools/textfinder/textfinder.cpp b/examples/uitools/textfinder/textfinder.cpp index a18505c8c1..d6c11906b8 100644 --- a/examples/uitools/textfinder/textfinder.cpp +++ b/examples/uitools/textfinder/textfinder.cpp @@ -75,7 +75,6 @@ static QString loadTextFile() QFile inputFile(":/forms/input.txt"); inputFile.open(QIODevice::ReadOnly); QTextStream in(&inputFile); - in.setCodec("UTF-8"); return in.readAll(); } //! [5] diff --git a/qt_cmdline.cmake b/qt_cmdline.cmake new file mode 100644 index 0000000000..e69de29bb2 diff --git a/qttools.pro b/qttools.pro deleted file mode 100644 index 58c33f27ca..0000000000 --- a/qttools.pro +++ /dev/null @@ -1 +0,0 @@ -load(qt_parts) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..416c98a911 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,69 @@ +# Generated from src.pro. + +# special case begin +# Need to stop building these apps by default because they would fail +# in device_and_simulator builds. +if(IOS) + set(_qt_additional_tools_to_exclude qtplugininfo qtpaths) +endif() +# special case end + +qt_exclude_tool_directories_from_default_target( + distancefieldgenerator + pixeltool + ${_qt_additional_tools_to_exclude} # special case +) + +# Check whether the sqlite plugin is available. +set(sqlite_plugin_available FALSE) +if(TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::Sql) + get_target_property(sql_plugins ${QT_CMAKE_EXPORT_NAMESPACE}::Sql QT_PLUGINS) + if(QSQLiteDriverPlugin IN_LIST sql_plugins) + set(sqlite_plugin_available TRUE) + endif() +endif() + +# special case begin +# Evaluate features to decide what to build. +# The config files will be written in the src/global module. +qt_feature_evaluate_features("${CMAKE_CURRENT_SOURCE_DIR}/../configure.cmake") +# special case end + +add_subdirectory(global) # special case add as first directory +add_subdirectory(linguist) +# add_subdirectory(global) # special case remove +if(QT_FEATURE_png AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets) + add_subdirectory(designer) + add_subdirectory(pixeltool) +endif() +if(QT_FEATURE_png AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets + AND (sqlite_plugin_available OR QT_BUILD_SHARED_LIBS)) + add_subdirectory(assistant) +endif() +if(QT_FEATURE_png AND QT_FEATURE_thread AND QT_FEATURE_toolbutton AND TARGET Qt::Quick AND TARGET Qt::Widgets) + add_subdirectory(distancefieldgenerator) +endif() +if(QT_FEATURE_commandlineparser) + add_subdirectory(qtattributionsscanner) +endif() +if(QT_FEATURE_commandlineparser AND QT_FEATURE_library AND (android_app OR NOT ANDROID)) + add_subdirectory(qtplugininfo) +endif() +if(QT_FEATURE_clang AND QT_FEATURE_commandlineparser AND QT_FEATURE_thread) + add_subdirectory(qdoc) +endif() +if(android_app OR (QT_FEATURE_commandlineparser AND NOT ANDROID)) + add_subdirectory(qtpaths) +endif() +if(MACOS) + add_subdirectory(macdeployqt) +endif() +if(TARGET Qt::DBus) + add_subdirectory(qdbus) +endif() +if(QT_FEATURE_windeployqt) # special case + add_subdirectory(windeployqt) +endif() +if(QT_FEATURE_commandlineparser AND TARGET Qt::Gui AND NOT ANDROID AND NOT QNX AND NOT UIKIT AND NOT WASM) + add_subdirectory(qtdiag) +endif() diff --git a/src/assistant/.gitignore b/src/assistant/.gitignore deleted file mode 100644 index 146319596b..0000000000 --- a/src/assistant/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -clucene/qtcluceneversion.h -help/qthelpversion.h diff --git a/src/assistant/CMakeLists.txt b/src/assistant/CMakeLists.txt new file mode 100644 index 0000000000..27f9024f8f --- /dev/null +++ b/src/assistant/CMakeLists.txt @@ -0,0 +1,22 @@ +# Generated from assistant.pro. + +# special case begin +if(NOT TARGET Qt::Sql OR NOT TARGET Qt::PrintSupport) + return() +endif() +# special case end + +qt_exclude_tool_directories_from_default_target( + assistant + qhelpgenerator +) + +if(NOT TARGET Qt::Sql) + return() +endif() +if(NOT QT_FEATURE_assistant) + return() +endif() +add_subdirectory(help) +add_subdirectory(assistant) +add_subdirectory(qhelpgenerator) diff --git a/src/assistant/assistant.pro b/src/assistant/assistant.pro deleted file mode 100644 index 1529167c05..0000000000 --- a/src/assistant/assistant.pro +++ /dev/null @@ -1,17 +0,0 @@ -requires(qtHaveModule(sql)) -TEMPLATE = subdirs - -SUBDIRS += \ - help \ - assistant \ - qhelpgenerator \ - qcollectiongenerator - -assistant.depends = help -qhelpgenerator.depends = help - -qtNomakeTools( \ - assistant \ - qhelpgenerator \ - qcollectiongenerator \ -) diff --git a/src/assistant/assistant/CMakeLists.txt b/src/assistant/assistant/CMakeLists.txt new file mode 100644 index 0000000000..cada391a54 --- /dev/null +++ b/src/assistant/assistant/CMakeLists.txt @@ -0,0 +1,215 @@ +# Generated from assistant.pro. + +##################################################################### +## assistant App: +##################################################################### + +qt_internal_add_app(assistant + SOURCES + ../../shared/fontpanel/fontpanel.cpp ../../shared/fontpanel/fontpanel.h + ../shared/collectionconfiguration.cpp ../shared/collectionconfiguration.h + aboutdialog.cpp aboutdialog.h + bookmarkdialog.cpp bookmarkdialog.h bookmarkdialog.ui + bookmarkfiltermodel.cpp bookmarkfiltermodel.h + bookmarkitem.cpp bookmarkitem.h + bookmarkmanager.cpp bookmarkmanager.h + bookmarkmanagerwidget.cpp bookmarkmanagerwidget.h bookmarkmanagerwidget.ui + bookmarkmodel.cpp bookmarkmodel.h + bookmarkwidget.ui + centralwidget.cpp centralwidget.h + cmdlineparser.cpp cmdlineparser.h + contentwindow.cpp contentwindow.h + findwidget.cpp findwidget.h + globalactions.cpp globalactions.h + helpbrowsersupport.cpp helpbrowsersupport.h + helpdocsettings.cpp helpdocsettings.h + helpdocsettingswidget.cpp helpdocsettingswidget.h helpdocsettingswidget.ui + helpenginewrapper.cpp helpenginewrapper.h + helpviewer.cpp helpviewer.h helpviewer_p.h + indexwindow.cpp indexwindow.h + main.cpp + mainwindow.cpp mainwindow.h + openpagesmanager.cpp openpagesmanager.h + openpagesmodel.cpp openpagesmodel.h + openpagesswitcher.cpp openpagesswitcher.h + openpageswidget.cpp openpageswidget.h + preferencesdialog.cpp preferencesdialog.h preferencesdialog.ui + qtdocinstaller.cpp qtdocinstaller.h + remotecontrol.cpp remotecontrol.h + searchwidget.cpp searchwidget.h + topicchooser.cpp topicchooser.h topicchooser.ui + tracer.h + xbelsupport.cpp xbelsupport.h + INCLUDE_DIRECTORIES + ../../shared/fontpanel + PUBLIC_LIBRARIES + Qt::Gui + Qt::Help + Qt::Network + Qt::Sql + Qt::Widgets + Qt::PrintSupport # special case + ENABLE_AUTOGEN_TOOLS + uic +) + +# Resources: +set(assistant_resource_files + "assistant.qch" +) + +qt_internal_add_resource(assistant "assistant" + PREFIX + "/qt-project.org/assistant" + FILES + ${assistant_resource_files} +) +set(assistant_images_resource_files + "images/assistant-128.png" + "images/assistant.png" + "images/bookmark.png" + "images/closebutton.png" + "images/darkclosebutton.png" + "images/mac/addtab.png" + "images/mac/book.png" + "images/mac/closetab.png" + "images/mac/editcopy.png" + "images/mac/find.png" + "images/mac/home.png" + "images/mac/next.png" + "images/mac/previous.png" + "images/mac/print.png" + "images/mac/resetzoom.png" + "images/mac/synctoc.png" + "images/mac/zoomin.png" + "images/mac/zoomout.png" + "images/win/addtab.png" + "images/win/book.png" + "images/win/closetab.png" + "images/win/editcopy.png" + "images/win/find.png" + "images/win/home.png" + "images/win/next.png" + "images/win/previous.png" + "images/win/print.png" + "images/win/resetzoom.png" + "images/win/synctoc.png" + "images/win/zoomin.png" + "images/win/zoomout.png" + "images/wrap.png" +) + +qt_internal_add_resource(assistant "assistant_images" + PREFIX + "/qt-project.org/assistant" + FILES + ${assistant_images_resource_files} +) + +set_target_properties(assistant PROPERTIES + QT_TARGET_DESCRIPTION "Qt Assistant" +) + +#### Keys ignored in scope 1:.:.:assistant.pro:: +# PROJECTNAME = "Assistant" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:assistant.pro:TARGET Qt::WebKitWidgets AND NOT QT_CONFIG___contains___static: +# BROWSER = "qtwebkit" + +#### Keys ignored in scope 3:.:.:assistant.pro:TARGET Qt::WebEngineWidgets AND NOT QT_CONFIG___contains___static: +# BROWSER = "qtwebengine" +find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS WebEngineWidgets) + +IF( ${QT_CMAKE_EXPORT_NAMESPACE}WebEngineWidgets_FOUND ) + set(BROWSER "qtwebengine") +ENDIF() + +## Keys ignored in scope 4:.:.:assistant.pro:else: +# BROWSER = "qtextbrowser" + +qt_internal_extend_target(assistant CONDITION TARGET Qt::PrintSupport + PUBLIC_LIBRARIES + Qt::PrintSupport +) + +qt_internal_extend_target(assistant CONDITION BROWSER STREQUAL qtwebkit + SOURCES + helpviewer_qwv.cpp + DEFINES + BROWSER_QTWEBKIT + PUBLIC_LIBRARIES + Qt::WebKitWidgets +) + +qt_internal_extend_target(assistant CONDITION BROWSER STREQUAL qtwebengine AND NOT BROWSER STREQUAL qtwebkit + SOURCES + helpviewer_qwev.cpp + DEFINES + BROWSER_QTWEBENGINE + PUBLIC_LIBRARIES + Qt::WebEngineWidgets +) + +qt_internal_extend_target(assistant CONDITION NOT BROWSER STREQUAL qtwebkit AND NOT BROWSER STREQUAL qtwebengine + SOURCES + helpviewer_qtb.cpp + DEFINES + BROWSER_QTEXTBROWSER +) + +if(WIN32) + set_target_properties(assistant PROPERTIES + QT_TARGET_RC_ICONS "${CMAKE_CURRENT_SOURCE_DIR}/assistant.ico" + ) +endif() + +if(WIN32) + set_target_properties(assistant PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}.0" + ) +endif() + +qt_internal_extend_target(assistant CONDITION WIN32 + SOURCES + stdinlistener_win.cpp stdinlistener_win.h + PUBLIC_LIBRARIES + shell32 +) + +if(UNIX) + set_target_properties(assistant PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}" + ) +endif() + +qt_internal_extend_target(assistant CONDITION UNIX + SOURCES + stdinlistener.cpp stdinlistener.h +) + +if(APPLE) + set_target_properties(assistant PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist" + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "assistant.icns" + OUTPUT_NAME "Assistant" + ) + set_source_files_properties(assistant.icns PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + target_sources(assistant PRIVATE + assistant.icns + ) + # special case end + # Set values to be replaced in the custom Info_mac.plist. + set(ICON "assistant.icns") + set(EXECUTABLE "Assistant") + # special case end +endif() +qt_internal_add_docs(assistant + doc/qtassistant.qdocconf +) + diff --git a/src/assistant/assistant/aboutdialog.cpp b/src/assistant/assistant/aboutdialog.cpp index 3682f1291a..774b6fd4bb 100644 --- a/src/assistant/assistant/aboutdialog.cpp +++ b/src/assistant/assistant/aboutdialog.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -82,9 +81,17 @@ QVariant AboutLabel::loadResource(int type, const QUrl &name) return QVariant(); } + +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void AboutLabel::setSource(const QUrl &url) +#else +void AboutLabel::doSetSource(const QUrl &url, QTextDocument::ResourceType type) +#endif { TRACE_OBJ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + Q_UNUSED(type); +#endif if (url.isValid() && (!HelpViewer::isLocalUrl(url) || !HelpViewer::canOpenPage(url.path()))) { if (!QDesktopServices::openUrl(url)) { diff --git a/src/assistant/assistant/aboutdialog.h b/src/assistant/assistant/aboutdialog.h index b791a4891a..720292d7b3 100644 --- a/src/assistant/assistant/aboutdialog.h +++ b/src/assistant/assistant/aboutdialog.h @@ -49,7 +49,12 @@ class AboutLabel : public QTextBrowser private: QVariant loadResource(int type, const QUrl &name) override; + +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void setSource(const QUrl &url) override; +#else + void doSetSource(const QUrl &name, QTextDocument::ResourceType type) override; +#endif QMap m_resourceMap; }; diff --git a/src/assistant/assistant/assistant.pro b/src/assistant/assistant/assistant.pro deleted file mode 100644 index b63be28c72..0000000000 --- a/src/assistant/assistant/assistant.pro +++ /dev/null @@ -1,123 +0,0 @@ -qtHaveModule(webkitwidgets):!contains(QT_CONFIG, static) { - BROWSER = qtwebkit -} else { - BROWSER = qtextbrowser -} - -QT += widgets network help sql -qtHaveModule(printsupport): QT += printsupport -PROJECTNAME = Assistant - -include(../../shared/fontpanel/fontpanel.pri) - -QMAKE_DOCS = $$PWD/doc/qtassistant.qdocconf - -HEADERS += aboutdialog.h \ - bookmarkdialog.h \ - bookmarkfiltermodel.h \ - bookmarkitem.h \ - bookmarkmanager.h \ - bookmarkmanagerwidget.h \ - bookmarkmodel.h \ - centralwidget.h \ - cmdlineparser.h \ - contentwindow.h \ - findwidget.h \ - filternamedialog.h \ - helpenginewrapper.h \ - helpbrowsersupport.h \ - helpviewer.h \ - helpviewer_p.h \ - indexwindow.h \ - mainwindow.h \ - optionswidget.h \ - preferencesdialog.h \ - qtdocinstaller.h \ - remotecontrol.h \ - searchwidget.h \ - topicchooser.h \ - tracer.h \ - xbelsupport.h \ - ../shared/collectionconfiguration.h \ - openpagesmodel.h \ - globalactions.h \ - openpageswidget.h \ - openpagesmanager.h \ - openpagesswitcher.h - -SOURCES += aboutdialog.cpp \ - bookmarkdialog.cpp \ - bookmarkfiltermodel.cpp \ - bookmarkitem.cpp \ - bookmarkmanager.cpp \ - bookmarkmanagerwidget.cpp \ - bookmarkmodel.cpp \ - centralwidget.cpp \ - cmdlineparser.cpp \ - contentwindow.cpp \ - findwidget.cpp \ - filternamedialog.cpp \ - helpenginewrapper.cpp \ - helpbrowsersupport.cpp \ - helpviewer.cpp \ - indexwindow.cpp \ - main.cpp \ - mainwindow.cpp \ - optionswidget.cpp \ - preferencesdialog.cpp \ - qtdocinstaller.cpp \ - remotecontrol.cpp \ - searchwidget.cpp \ - topicchooser.cpp \ - xbelsupport.cpp \ - ../shared/collectionconfiguration.cpp \ - openpagesmodel.cpp \ - globalactions.cpp \ - openpageswidget.cpp \ - openpagesmanager.cpp \ - openpagesswitcher.cpp - -equals(BROWSER, "qtwebkit") { - DEFINES += BROWSER_QTWEBKIT - QT += webkitwidgets - SOURCES += helpviewer_qwv.cpp -} else { - DEFINES += BROWSER_QTEXTBROWSER - SOURCES += helpviewer_qtb.cpp -} - -win32 { - HEADERS += stdinlistener_win.h - SOURCES += stdinlistener_win.cpp -} else { - HEADERS += stdinlistener.h - SOURCES += stdinlistener.cpp -} - -FORMS += bookmarkdialog.ui \ - bookmarkmanagerwidget.ui \ - bookmarkwidget.ui \ - filternamedialog.ui \ - preferencesdialog.ui \ - topicchooser.ui - -RESOURCES += assistant.qrc \ - assistant_images.qrc - -QMAKE_TARGET_DESCRIPTION = Qt Assistant - -win32 { - LIBS += -lshell32 - RC_ICONS = assistant.ico - VERSION = $${QT_VERSION}.0 -} else { - VERSION = $${QT_VERSION} -} - -mac { - ICON = assistant.icns - TARGET = Assistant - QMAKE_INFO_PLIST = Info_mac.plist -} - -load(qt_app) diff --git a/src/assistant/assistant/assistant.qch b/src/assistant/assistant/assistant.qch index fded08e620..9da49aa5fe 100644 Binary files a/src/assistant/assistant/assistant.qch and b/src/assistant/assistant/assistant.qch differ diff --git a/src/assistant/assistant/assistant_images.qrc b/src/assistant/assistant/assistant_images.qrc index e55b6b27e7..948de970f7 100644 --- a/src/assistant/assistant/assistant_images.qrc +++ b/src/assistant/assistant/assistant_images.qrc @@ -10,9 +10,7 @@ images/mac/editcopy.png images/mac/find.png images/mac/home.png - images/mac/minus.png images/mac/next.png - images/mac/plus.png images/mac/previous.png images/mac/print.png images/mac/synctoc.png @@ -25,9 +23,7 @@ images/win/editcopy.png images/win/find.png images/win/home.png - images/win/minus.png images/win/next.png - images/win/plus.png images/win/previous.png images/win/print.png images/win/synctoc.png diff --git a/src/assistant/assistant/bookmarkdialog.cpp b/src/assistant/assistant/bookmarkdialog.cpp index 8207da04e1..cb775d30af 100644 --- a/src/assistant/assistant/bookmarkdialog.cpp +++ b/src/assistant/assistant/bookmarkdialog.cpp @@ -60,7 +60,7 @@ BookmarkDialog::BookmarkDialog(BookmarkModel *sourceModel, const QString &title, bookmarkProxyModel = new BookmarkFilterModel(this); bookmarkProxyModel->setSourceModel(bookmarkModel); ui.bookmarkFolders->setModel(bookmarkProxyModel); - connect(ui.bookmarkFolders, QOverload::of(&QComboBox::currentIndexChanged), + connect(ui.bookmarkFolders, &QComboBox::currentIndexChanged, this, QOverload::of(&BookmarkDialog::currentIndexChanged)); bookmarkTreeModel = new BookmarkTreeModel(this); diff --git a/src/assistant/assistant/bookmarkitem.h b/src/assistant/assistant/bookmarkitem.h index 31ecff80bf..c7e37dc55a 100644 --- a/src/assistant/assistant/bookmarkitem.h +++ b/src/assistant/assistant/bookmarkitem.h @@ -30,7 +30,7 @@ #define BOOKMARKITEM_H #include -#include +#include QT_BEGIN_NAMESPACE @@ -40,7 +40,7 @@ enum { UserRoleExpanded = Qt::UserRole + 150 }; -typedef QVector DataVector; +typedef QList DataVector; class BookmarkItem { diff --git a/src/assistant/assistant/bookmarkmanager.cpp b/src/assistant/assistant/bookmarkmanager.cpp index 331cea8647..5daab74e8a 100644 --- a/src/assistant/assistant/bookmarkmanager.cpp +++ b/src/assistant/assistant/bookmarkmanager.cpp @@ -270,14 +270,14 @@ bool BookmarkManager::eventFilter(QObject *object, QEvent *event) if (event->type() == QEvent::MouseButtonRelease && !isWidget) { QMouseEvent *me = static_cast(event); switch (me->button()) { - case Qt::LeftButton: { + case Qt::LeftButton: if (me->modifiers() & Qt::ControlModifier) setSourceFromIndex(bookmarkTreeView->currentIndex(), true); - } break; + break; - case Qt::MidButton: { + case Qt::MiddleButton: setSourceFromIndex(bookmarkTreeView->currentIndex(), true); - } break; + break; default: break; } @@ -543,7 +543,7 @@ void BookmarkManager::textChanged(const QString &text) bookmarkTreeView->setRootIsDecorated(false); bookmarkTreeView->setModel(typeAndSearchModel); } - typeAndSearchModel->setFilterRegExp(QRegExp(text)); + typeAndSearchModel->setFilterRegularExpression(text); } else { typeAndSearch = false; bookmarkTreeView->setModel(bookmarkModel); diff --git a/src/assistant/assistant/bookmarkmanagerwidget.cpp b/src/assistant/assistant/bookmarkmanagerwidget.cpp index ba4f5cfd43..090d7c754f 100644 --- a/src/assistant/assistant/bookmarkmanagerwidget.cpp +++ b/src/assistant/assistant/bookmarkmanagerwidget.cpp @@ -31,15 +31,16 @@ #include "tracer.h" #include "xbelsupport.h" -#include -#include -#include +#include +#include #include -#include #include -#include -#include +#include + +#include +#include +#include QT_BEGIN_NAMESPACE @@ -143,13 +144,13 @@ bool BookmarkManagerWidget::eventFilter(QObject *object, QEvent *event) if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); switch (ke->key()) { - case Qt::Key_F2: { + case Qt::Key_F2: renameItem(ui.treeView->currentIndex()); - } break; + break; - case Qt::Key_Delete: { + case Qt::Key_Delete: removeItem(ui.treeView->currentIndex()); - } break; + break; default: break; } @@ -158,14 +159,14 @@ bool BookmarkManagerWidget::eventFilter(QObject *object, QEvent *event) if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *me = static_cast(event); switch (me->button()) { - case Qt::LeftButton: { + case Qt::LeftButton: if (me->modifiers() & Qt::ControlModifier) setSourceFromIndex(ui.treeView->currentIndex(), true); - } break; + break; - case Qt::MidButton: { + case Qt::MiddleButton: setSourceFromIndex(ui.treeView->currentIndex(), true); - } break; + break; default: break; } diff --git a/src/assistant/assistant/bookmarkmodel.cpp b/src/assistant/assistant/bookmarkmodel.cpp index e80842d457..3f8b5e8936 100644 --- a/src/assistant/assistant/bookmarkmodel.cpp +++ b/src/assistant/assistant/bookmarkmodel.cpp @@ -28,6 +28,7 @@ #include "bookmarkmodel.h" #include "bookmarkitem.h" +#include #include #include @@ -127,7 +128,7 @@ BookmarkModel::setItemsEditable(bool editable) void BookmarkModel::expandFoldersIfNeeeded(QTreeView *treeView) { - for (const QModelIndex &index : qAsConst(cache)) + for (QModelIndex index : qAsConst(cache)) treeView->setExpanded(index, index.data(UserRoleExpanded).toBool()); } diff --git a/src/assistant/assistant/bookmarkmodel.h b/src/assistant/assistant/bookmarkmodel.h index 998e7d7ca8..73e6595af0 100644 --- a/src/assistant/assistant/bookmarkmodel.h +++ b/src/assistant/assistant/bookmarkmodel.h @@ -66,7 +66,7 @@ class BookmarkModel : public QAbstractItemModel Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role) const override; - void setData(const QModelIndex &index, const QVector &data); + void setData(const QModelIndex &index, const QList &data); bool setData(const QModelIndex &index, const QVariant &value, int role) override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override; diff --git a/src/assistant/assistant/centralwidget.cpp b/src/assistant/assistant/centralwidget.cpp index 34304f737c..4f3d749f4b 100644 --- a/src/assistant/assistant/centralwidget.cpp +++ b/src/assistant/assistant/centralwidget.cpp @@ -34,7 +34,7 @@ #include "openpagesmanager.h" #include "tracer.h" -#include +#include #include #include @@ -330,7 +330,7 @@ void CentralWidget::connectTabBar() // -- public slots -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void CentralWidget::copy() { TRACE_OBJ @@ -396,9 +396,9 @@ void CentralWidget::print() QPrintDialog dlg(m_printer, this); if (!currentHelpViewer()->selectedText().isEmpty()) - dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection); - dlg.addEnabledOption(QAbstractPrintDialog::PrintPageRange); - dlg.addEnabledOption(QAbstractPrintDialog::PrintCollateCopies); + dlg.setOption(QAbstractPrintDialog::PrintSelection); + dlg.setOption(QAbstractPrintDialog::PrintPageRange); + dlg.setOption(QAbstractPrintDialog::PrintCollateCopies); dlg.setWindowTitle(tr("Print Document")); if (dlg.exec() == QDialog::Accepted) currentHelpViewer()->print(m_printer); @@ -545,10 +545,10 @@ void CentralWidget::highlightSearchTerms() const bool wholePhrase = searchInput.startsWith(QLatin1Char('"')) && searchInput.endsWith(QLatin1Char('"')); const QStringList &words = wholePhrase ? QStringList(searchInput.mid(1, searchInput.length() - 2)) : - searchInput.split(QRegExp("\\W+"), QString::SkipEmptyParts); + searchInput.split(QRegularExpression("\\W+"), Qt::SkipEmptyParts); HelpViewer *viewer = currentHelpViewer(); for (const QString &word : words) - viewer->findText(word, nullptr, false, true); + viewer->findText(word, {}, false, true); disconnect(viewer, &HelpViewer::loadFinished, this, &CentralWidget::highlightSearchTerms); } @@ -568,12 +568,12 @@ void CentralWidget::handleSourceChanged(const QUrl &url) emit sourceChanged(url); } -void CentralWidget::slotHighlighted(const QString &link) +void CentralWidget::slotHighlighted(const QUrl &link) { TRACE_OBJ - QString resolvedLink = m_resolvedLinks.value(link); + QUrl resolvedLink = m_resolvedLinks.value(link); if (!link.isEmpty() && resolvedLink.isEmpty()) { - resolvedLink = HelpEngineWrapper::instance().findFile(link).toString(); + resolvedLink = HelpEngineWrapper::instance().findFile(link); m_resolvedLinks.insert(link, resolvedLink); } emit highlighted(resolvedLink); @@ -597,15 +597,17 @@ void CentralWidget::connectSignals(HelpViewer *page) connect(page, &HelpViewer::printRequested, this, &CentralWidget::print); #endif +#if QT_CONFIG(clipboard) connect(page, &HelpViewer::copyAvailable, this, &CentralWidget::copyAvailable); +#endif connect(page, &HelpViewer::forwardAvailable, this, &CentralWidget::forwardAvailable); connect(page, &HelpViewer::backwardAvailable, this, &CentralWidget::backwardAvailable); connect(page, &HelpViewer::sourceChanged, this, &CentralWidget::handleSourceChanged); - connect(page, QOverload::of(&HelpViewer::highlighted), + connect(page, QOverload::of(&HelpViewer::highlighted), this, &CentralWidget::slotHighlighted); } diff --git a/src/assistant/assistant/centralwidget.h b/src/assistant/assistant/centralwidget.h index 34de716a40..6962c9931a 100644 --- a/src/assistant/assistant/centralwidget.h +++ b/src/assistant/assistant/centralwidget.h @@ -30,6 +30,7 @@ #define CENTRALWIDGET_H #include +#include #include #include @@ -94,7 +95,7 @@ class CentralWidget : public QWidget void connectTabBar(); public slots: -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void copy(); #endif void home(); @@ -127,9 +128,11 @@ public slots: signals: void currentViewerChanged(); +#if QT_CONFIG(clipboard) void copyAvailable(bool yes); +#endif void sourceChanged(const QUrl &url); - void highlighted(const QString &link); + void highlighted(const QUrl &link); void forwardAvailable(bool available); void backwardAvailable(bool available); void addBookmark(const QString &title, const QString &url); @@ -142,7 +145,7 @@ private slots: void highlightSearchTerms(); void printPreviewToPrinter(QPrinter *printer); void handleSourceChanged(const QUrl &url); - void slotHighlighted(const QString &link); + void slotHighlighted(const QUrl& link); private: void initPrinter(); @@ -160,7 +163,7 @@ private slots: FindWidget *m_findWidget; QStackedWidget *m_stackedWidget; TabBar *m_tabBar; - QHash m_resolvedLinks; + QHash m_resolvedLinks; }; QT_END_NAMESPACE diff --git a/src/assistant/assistant/contentwindow.cpp b/src/assistant/assistant/contentwindow.cpp index c932c06b73..fdfc7b5ff3 100644 --- a/src/assistant/assistant/contentwindow.cpp +++ b/src/assistant/assistant/contentwindow.cpp @@ -77,6 +77,7 @@ bool ContentWindow::syncToContent(const QUrl& url) if (!idx.isValid()) return false; m_contentWidget->setCurrentIndex(idx); + m_contentWidget->scrollTo(idx); return true; } @@ -131,7 +132,7 @@ bool ContentWindow::eventFilter(QObject *o, QEvent *e) QItemSelectionModel *sm = m_contentWidget->selectionModel(); if (sm->isSelected(index)) { if ((button == Qt::LeftButton && (me->modifiers() & Qt::ControlModifier)) - || (button == Qt::MidButton)) { + || (button == Qt::MiddleButton)) { QHelpContentModel *contentModel = qobject_cast(m_contentWidget->model()); if (contentModel) { diff --git a/src/assistant/assistant/doc/images/assistant-assistant.png b/src/assistant/assistant/doc/images/assistant-assistant.png index d76ec04209..368b5c9325 100644 Binary files a/src/assistant/assistant/doc/images/assistant-assistant.png and b/src/assistant/assistant/doc/images/assistant-assistant.png differ diff --git a/src/assistant/assistant/doc/images/assistant-bookmarks.png b/src/assistant/assistant/doc/images/assistant-bookmarks.png index 810d239606..9acdb83006 100644 Binary files a/src/assistant/assistant/doc/images/assistant-bookmarks.png and b/src/assistant/assistant/doc/images/assistant-bookmarks.png differ diff --git a/src/assistant/assistant/doc/images/assistant-dockwidgets.png b/src/assistant/assistant/doc/images/assistant-dockwidgets.png index 7a9c386a6f..c657426e99 100644 Binary files a/src/assistant/assistant/doc/images/assistant-dockwidgets.png and b/src/assistant/assistant/doc/images/assistant-dockwidgets.png differ diff --git a/src/assistant/assistant/doc/images/assistant-index.png b/src/assistant/assistant/doc/images/assistant-index.png index 548c349e5b..685396c977 100644 Binary files a/src/assistant/assistant/doc/images/assistant-index.png and b/src/assistant/assistant/doc/images/assistant-index.png differ diff --git a/src/assistant/assistant/doc/images/assistant-preferences-documentation.png b/src/assistant/assistant/doc/images/assistant-preferences-documentation.png index e640176ac7..92e8e0568b 100644 Binary files a/src/assistant/assistant/doc/images/assistant-preferences-documentation.png and b/src/assistant/assistant/doc/images/assistant-preferences-documentation.png differ diff --git a/src/assistant/assistant/doc/images/assistant-preferences-filters.png b/src/assistant/assistant/doc/images/assistant-preferences-filters.png index 3af2830850..cdeda5c3d1 100644 Binary files a/src/assistant/assistant/doc/images/assistant-preferences-filters.png and b/src/assistant/assistant/doc/images/assistant-preferences-filters.png differ diff --git a/src/assistant/assistant/doc/images/assistant-preferences-fonts.png b/src/assistant/assistant/doc/images/assistant-preferences-fonts.png index 4d93759177..a3879ec89b 100644 Binary files a/src/assistant/assistant/doc/images/assistant-preferences-fonts.png and b/src/assistant/assistant/doc/images/assistant-preferences-fonts.png differ diff --git a/src/assistant/assistant/doc/images/assistant-preferences-options.png b/src/assistant/assistant/doc/images/assistant-preferences-options.png index 3a9efad6ab..38233b7cfa 100644 Binary files a/src/assistant/assistant/doc/images/assistant-preferences-options.png and b/src/assistant/assistant/doc/images/assistant-preferences-options.png differ diff --git a/src/assistant/assistant/doc/images/assistant-search.png b/src/assistant/assistant/doc/images/assistant-search.png index 3ab3caf9dd..847af8ba27 100644 Binary files a/src/assistant/assistant/doc/images/assistant-search.png and b/src/assistant/assistant/doc/images/assistant-search.png differ diff --git a/src/assistant/assistant/doc/qtassistant.qdocconf b/src/assistant/assistant/doc/qtassistant.qdocconf index d6c714a6d2..7788191766 100644 --- a/src/assistant/assistant/doc/qtassistant.qdocconf +++ b/src/assistant/assistant/doc/qtassistant.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtAssistant description = Qt Assistant Manual @@ -39,3 +40,5 @@ depends += qtdoc qmake manifestmeta.thumbnail.names += "QtAssistant/Remote Control Example" navigation.landingpage = "Qt Assistant Manual" + +warninglimit = 0 diff --git a/src/assistant/assistant/doc/snippets/doc_src_assistant-manual.qdoc b/src/assistant/assistant/doc/snippets/doc_src_assistant-manual.qdoc index feae787840..7c1e5f1df8 100644 --- a/src/assistant/assistant/doc/snippets/doc_src_assistant-manual.qdoc +++ b/src/assistant/assistant/doc/snippets/doc_src_assistant-manual.qdoc @@ -150,7 +150,7 @@ assistant -collectionFile mycollection.qhc //! [8] //! [9] -%QDesktopServices::DataLocation%/mycompany/myapplication/mycollection.qhc +%QDesktopServices::AppDataLocation%/mycompany/myapplication/mycollection.qhc //! [9] //! [10] diff --git a/src/assistant/assistant/doc/src/assistant-manual.qdoc b/src/assistant/assistant/doc/src/assistant-manual.qdoc index c86a19cac0..8c2ae44fae 100644 --- a/src/assistant/assistant/doc/src/assistant-manual.qdoc +++ b/src/assistant/assistant/doc/src/assistant-manual.qdoc @@ -62,7 +62,6 @@ \page assistant-custom-help-viewer.html \title Customizing Qt Assistant - \contentspage {Qt Assistant Manual}{Contents} \previouspage Using Qt Assistant Using \QA as custom help viewer requires more than just being able to @@ -120,7 +119,7 @@ To solve this dilemma, \QA creates user specific collection files which are more or less copied from the original collection file. The user-specific collection file will be saved in a subdirectory of the path returned by - QDesktopServices::DataLocation. The subdirectory, or \e{cache directory} + QDesktopServices::AppDataLocation. The subdirectory, or \e{cache directory} within this user-specific location, can be defined in the help collection project file. For example: @@ -261,7 +260,7 @@ relative to the directory the collection file resides in. If the attribute is set to "default" or if it is missing, the path is relative to the directory given by - QDesktopServices::DataLocation. The first form is useful for + QDesktopServices::AppDataLocation. The first form is useful for collections that are used in a \e mobile way, such as carried around on a USB stick. \row diff --git a/src/assistant/assistant/doc/src/assistant-quick-guide.qdoc b/src/assistant/assistant/doc/src/assistant-quick-guide.qdoc index 28590fa259..2a8dc01e1d 100644 --- a/src/assistant/assistant/doc/src/assistant-quick-guide.qdoc +++ b/src/assistant/assistant/doc/src/assistant-quick-guide.qdoc @@ -27,7 +27,6 @@ /*! \if !defined(ASSISTANT_INTERNAL) - \contentspage {Qt Assistant Manual}{Contents} \previouspage Qt Assistant Manual \endif \page assistant-quick-guide.html @@ -99,7 +98,6 @@ /*! \if !defined(ASSISTANT_INTERNAL) - \contentspage {Qt Assistant Manual}{Contents} \nextpage Customizing Qt Assistant \endif \page assistant-details.html @@ -169,8 +167,12 @@ \QA provides a powerful full text search engine. You can search for certain words or text in the \gui Search window. Enter the text you want to look for and press \key{Enter} or click \gui{Search}. The search is not case sensitive. - For example, \b Foo, \b fOo and \b FOO are all treated as the same. The - following are examples of common search patterns: + For example, \b Foo, \b fOo and \b FOO are all treated as the same. + + You can create complex queries using the + \l{https://sqlite.org/fts5.html#full_text_query_syntax}{FTS query syntax}. + + The following are examples of common search patterns: \list \li \c deep -- lists all the documents that contain the word \b deep @@ -182,19 +184,6 @@ \b {deep copy} \endlist - Use the \gui{Advanced search} for more flexibility. - You can specify some words so that hits containing these are excluded from the - result, or you can search for an exact phrase. Searching for similar words will - give results like these: - - \list - \li \c{QStin} -- lists all the documents with titles that are similar, such as \c{QString} - \li \c{QSting} -- lists all the documents with titles that are similar, such as \c{QString} - \li \c{QStrin} -- lists all the documents with titles that are similar, such as \c{QString} - \endlist - - Options can be combined to improve the search results. - The list of documents found is ordered according to the number of occurrences of the search text which they contain, with those containing the highest number of occurrences appearing first. Simply click any diff --git a/src/assistant/assistant/globalactions.cpp b/src/assistant/assistant/globalactions.cpp index 6accd6dcdd..a46a615657 100644 --- a/src/assistant/assistant/globalactions.cpp +++ b/src/assistant/assistant/globalactions.cpp @@ -32,11 +32,18 @@ #include "helpviewer.h" #include "tracer.h" -#include #include +#include + #if defined(BROWSER_QTWEBKIT) # include +# define WEBHISTORY QWebHistory +# define WEBHISTORYITEM QWebHistoryItem +#elif defined(BROWSER_QTWEBENGINE) +# include +# define WEBHISTORY QWebEngineHistory +# define WEBHISTORYITEM QWebEngineHistoryItem #endif GlobalActions *GlobalActions::instance(QObject *parent) @@ -105,6 +112,7 @@ GlobalActions::GlobalActions(QObject *parent) : QObject(parent) separator->setSeparator(true); m_actionList << separator; +#if QT_CONFIG(clipboard) m_copyAction = new QAction(tr("&Copy selected Text"), parent); m_copyAction->setPriority(QAction::LowPriority); m_copyAction->setIconText("&Copy"); @@ -113,6 +121,7 @@ GlobalActions::GlobalActions(QObject *parent) : QObject(parent) m_copyAction->setEnabled(false); connect(m_copyAction, &QAction::triggered, centralWidget, &CentralWidget::copy); m_actionList << m_copyAction; +#endif m_printAction = new QAction(tr("&Print..."), parent); m_printAction->setPriority(QAction::LowPriority); @@ -133,7 +142,9 @@ GlobalActions::GlobalActions(QObject *parent) : QObject(parent) m_nextAction->setIcon(QIcon::fromTheme(QStringLiteral("go-next") , m_nextAction->icon())); m_zoomInAction->setIcon(QIcon::fromTheme(QStringLiteral("zoom-in") , m_zoomInAction->icon())); m_zoomOutAction->setIcon(QIcon::fromTheme(QStringLiteral("zoom-out") , m_zoomOutAction->icon())); +#if QT_CONFIG(clipboard) m_copyAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy") , m_copyAction->icon())); +#endif m_findAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find") , m_findAction->icon())); m_homeAction->setIcon(QIcon::fromTheme(QStringLiteral("go-home") , m_homeAction->icon())); m_printAction->setIcon(QIcon::fromTheme(QStringLiteral("document-print") , m_printAction->icon())); @@ -144,26 +155,30 @@ void GlobalActions::updateActions() { TRACE_OBJ CentralWidget *centralWidget = CentralWidget::instance(); +#if QT_CONFIG(clipboard) m_copyAction->setEnabled(centralWidget->hasSelection()); +#endif m_nextAction->setEnabled(centralWidget->isForwardAvailable()); m_backAction->setEnabled(centralWidget->isBackwardAvailable()); } +#if QT_CONFIG(clipboard) void GlobalActions::setCopyAvailable(bool available) { TRACE_OBJ m_copyAction->setEnabled(available); } +#endif -#if defined(BROWSER_QTWEBKIT) +#if defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) void GlobalActions::slotAboutToShowBackMenu() { TRACE_OBJ m_backMenu->clear(); - if (QWebHistory *history = CentralWidget::instance()->currentHelpViewer()->history()) { + if (WEBHISTORY *history = CentralWidget::instance()->currentHelpViewer()->history()) { const int currentItemIndex = history->currentItemIndex(); - QList items = history->backItems(history->count()); + QList items = history->backItems(history->count()); for (int i = items.count() - 1; i >= 0; --i) { QAction *action = new QAction(this); action->setText(items.at(i).title()); @@ -177,9 +192,9 @@ void GlobalActions::slotAboutToShowNextMenu() { TRACE_OBJ m_nextMenu->clear(); - if (QWebHistory *history = CentralWidget::instance()->currentHelpViewer()->history()) { + if (WEBHISTORY *history = CentralWidget::instance()->currentHelpViewer()->history()) { const int count = history->count(); - QList items = history->forwardItems(count); + QList items = history->forwardItems(count); for (int i = 0; i < items.count(); ++i) { QAction *action = new QAction(this); action->setData(count - i); @@ -194,7 +209,7 @@ void GlobalActions::slotOpenActionUrl(QAction *action) TRACE_OBJ if (HelpViewer* viewer = CentralWidget::instance()->currentHelpViewer()) { const int offset = action->data().toInt(); - QWebHistory *history = viewer->history(); + WEBHISTORY *history = viewer->history(); if (offset > 0) { history->goToItem(history->forwardItems(history->count() - offset + 1).back()); // forward @@ -204,12 +219,12 @@ void GlobalActions::slotOpenActionUrl(QAction *action) } } -#endif // BROWSER_QTWEBKIT +#endif // BROWSER_QTWEBKIT || BROWSER_QTWEBENGINE void GlobalActions::setupNavigationMenus(QAction *back, QAction *next, QWidget *parent) { -#if defined(BROWSER_QTWEBKIT) +#if defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) m_backMenu = new QMenu(parent); connect(m_backMenu, &QMenu::aboutToShow, this, &GlobalActions::slotAboutToShowBackMenu); diff --git a/src/assistant/assistant/globalactions.h b/src/assistant/assistant/globalactions.h index a3a4dec63f..338672fa26 100644 --- a/src/assistant/assistant/globalactions.h +++ b/src/assistant/assistant/globalactions.h @@ -26,11 +26,12 @@ ** ****************************************************************************/ -#ifndef GLOBALACTION_H -#define GLOBALACTION_H +#ifndef GLOBALACTIONS_H +#define GLOBALACTIONS_H #include #include +#include QT_BEGIN_NAMESPACE @@ -50,14 +51,19 @@ class GlobalActions : public QObject QAction *homeAction() const { return m_homeAction; } QAction *zoomInAction() const { return m_zoomInAction; } QAction *zoomOutAction() const { return m_zoomOutAction; } +#if QT_CONFIG(clipboard) QAction *copyAction() const { return m_copyAction; } +#endif QAction *printAction() const { return m_printAction; } QAction *findAction() const { return m_findAction; } - Q_SLOT void updateActions(); - Q_SLOT void setCopyAvailable(bool available); +public slots: +#if QT_CONFIG(clipboard) + void setCopyAvailable(bool available); +#endif + void updateActions(); -#if defined(BROWSER_QTWEBKIT) +#if defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) private slots: void slotAboutToShowBackMenu(); void slotAboutToShowNextMenu(); @@ -77,7 +83,9 @@ private slots: QAction *m_homeAction; QAction *m_zoomInAction; QAction *m_zoomOutAction; +#if QT_CONFIG(clipboard) QAction *m_copyAction; +#endif QAction *m_printAction; QAction *m_findAction; @@ -89,4 +97,4 @@ private slots: QT_END_NAMESPACE -#endif // GLOBALACTION_H +#endif // GLOBALACTIONS_H diff --git a/src/assistant/assistant/helpbrowsersupport.cpp b/src/assistant/assistant/helpbrowsersupport.cpp index 86f44f9c8c..921da11c30 100644 --- a/src/assistant/assistant/helpbrowsersupport.cpp +++ b/src/assistant/assistant/helpbrowsersupport.cpp @@ -42,6 +42,11 @@ #include #include +#ifdef BROWSER_QTWEBENGINE +#include +#include +#endif + QT_BEGIN_NAMESPACE // -- messages @@ -159,6 +164,57 @@ class HelpRedirectNetworkReply : public QNetworkReply qint64 readData(char*, qint64) override { TRACE_OBJ return qint64(-1); } }; +// -- HelpDeviceReply + +#if defined(BROWSER_QTWEBENGINE) +class HelpDeviceReply : public QIODevice +{ +public: + HelpDeviceReply(const QUrl &request, const QByteArray &fileData); + + qint64 bytesAvailable() const override + { return data.length() + QIODevice::bytesAvailable(); } + + void close() override + { QIODevice::close(); deleteLater(); } + +protected: + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 maxlen) override; + +private: + QByteArray data; + const qint64 origLen; +}; + +HelpDeviceReply::HelpDeviceReply(const QUrl &/*request*/, const QByteArray &fileData) + : data(fileData), origLen(fileData.length()) +{ + TRACE_OBJ + setOpenMode(QIODevice::ReadOnly); + + QTimer::singleShot(0, this, &QIODevice::readyRead); + QTimer::singleShot(0, this, &QIODevice::readChannelFinished); +} + +qint64 HelpDeviceReply::readData(char *buffer, qint64 maxlen) +{ + TRACE_OBJ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + memcpy(buffer, data.constData(), len); + data.remove(0, len); + } + return len; +} + +qint64 HelpDeviceReply::writeData(const char */*buffer*/, qint64 /*maxlen*/) +{ + TRACE_OBJ + return 0; +} +#endif + // -- HelpNetworkAccessManager class HelpNetworkAccessManager : public QNetworkAccessManager @@ -229,4 +285,52 @@ QNetworkAccessManager *HelpBrowserSupport::createNetworkAccessManager(QObject *p return new HelpNetworkAccessManager(parent); } +#if defined(BROWSER_QTWEBENGINE) +// -- HelpUrlSchemeHandler + +class HelpUrlSchemeHandler : public QWebEngineUrlSchemeHandler +{ +public: + HelpUrlSchemeHandler(QObject *parent); + + void requestStarted(QWebEngineUrlRequestJob *job) override; +}; + +HelpUrlSchemeHandler::HelpUrlSchemeHandler(QObject *parent) + : QWebEngineUrlSchemeHandler(parent) +{ + TRACE_OBJ +} + +void HelpUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) +{ + TRACE_OBJ + + QByteArray data; + const QUrl url = job->requestUrl(); + QUrl redirectedUrl; + switch (HelpBrowserSupport::resolveUrl(url, &redirectedUrl, &data)) { + case HelpBrowserSupport::UrlRedirect: + job->redirect(redirectedUrl); + return; + case HelpBrowserSupport::UrlLocalData: { + const QString mimeType = HelpViewer::mimeFromUrl(url); + QIODevice *reply = new HelpDeviceReply(url, data); + job->reply(mimeType.toLatin1(), reply); + return; + } + case HelpBrowserSupport::UrlResolveError: + job->fail(QWebEngineUrlRequestJob::UrlInvalid); + return; + } + Q_UNREACHABLE(); +} + +QWebEngineUrlSchemeHandler *HelpBrowserSupport::createUrlSchemeHandler(QObject *parent) +{ + return new HelpUrlSchemeHandler(parent); +} +#endif + + QT_END_NAMESPACE diff --git a/src/assistant/assistant/helpbrowsersupport.h b/src/assistant/assistant/helpbrowsersupport.h index d10056645f..ddf4770f11 100644 --- a/src/assistant/assistant/helpbrowsersupport.h +++ b/src/assistant/assistant/helpbrowsersupport.h @@ -38,6 +38,7 @@ class QObject; class QString; class QByteArray; class QUrl; +class QWebEngineUrlSchemeHandler; // Provide helper functions for feeding the QtHelp data stored in the help database // into various browsers. @@ -62,6 +63,10 @@ class HelpBrowserSupport // Create an instance of QNetworkAccessManager for WebKit-type browsers. static QNetworkAccessManager *createNetworkAccessManager(QObject *parent = nullptr); + +#if defined(BROWSER_QTWEBENGINE) + static QWebEngineUrlSchemeHandler *createUrlSchemeHandler(QObject *parent = nullptr); +#endif }; QT_END_NAMESPACE diff --git a/src/assistant/assistant/helpdocsettings.cpp b/src/assistant/assistant/helpdocsettings.cpp new file mode 100644 index 0000000000..dc4afdb865 --- /dev/null +++ b/src/assistant/assistant/helpdocsettings.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpdocsettings.h" + +#include +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +class HelpDocSettingsPrivate : public QSharedData +{ +public: + HelpDocSettingsPrivate() = default; + HelpDocSettingsPrivate(const HelpDocSettingsPrivate &other) = default; + ~HelpDocSettingsPrivate() = default; + + QMap m_namespaceToComponent; + QMap m_componentToNamespace; + + QMap m_namespaceToVersion; + QMap m_versionToNamespace; + + QMap m_namespaceToFileName; + QMap m_fileNameToNamespace; +}; + + +HelpDocSettings::HelpDocSettings() + : d(new HelpDocSettingsPrivate) +{ +} + +HelpDocSettings::HelpDocSettings(const HelpDocSettings &) = default; + +HelpDocSettings::HelpDocSettings(HelpDocSettings &&) = default; + +HelpDocSettings::~HelpDocSettings() = default; + +HelpDocSettings &HelpDocSettings::operator=(const HelpDocSettings &) = default; + +HelpDocSettings &HelpDocSettings::operator=(HelpDocSettings &&) = default; + +bool HelpDocSettings::addDocumentation(const QString &fileName) +{ + const QCompressedHelpInfo info = QCompressedHelpInfo::fromCompressedHelpFile(fileName); + + if (info.isNull()) + return false; + + const QString namespaceName = info.namespaceName(); + + if (d->m_namespaceToFileName.contains(namespaceName)) + return false; + + if (d->m_fileNameToNamespace.contains(fileName)) + return false; + + const QString component = info.component(); + const QVersionNumber version = info.version(); + + d->m_namespaceToFileName.insert(namespaceName, fileName); + d->m_fileNameToNamespace.insert(fileName, namespaceName); + + d->m_namespaceToComponent.insert(namespaceName, component); + d->m_componentToNamespace[component].append(namespaceName); + + d->m_namespaceToVersion.insert(namespaceName, version); + d->m_versionToNamespace[version].append(namespaceName); + + return true; +} + +bool HelpDocSettings::removeDocumentation(const QString &namespaceName) +{ + if (namespaceName.isEmpty()) + return false; + + const QString fileName = d->m_namespaceToFileName.value(namespaceName); + if (fileName.isEmpty()) + return false; + + const QString component = d->m_namespaceToComponent.value(namespaceName); + const QVersionNumber version = d->m_namespaceToVersion.value(namespaceName); + + d->m_namespaceToComponent.remove(namespaceName); + d->m_namespaceToVersion.remove(namespaceName); + d->m_namespaceToFileName.remove(namespaceName); + d->m_fileNameToNamespace.remove(fileName); + d->m_componentToNamespace[component].removeOne(namespaceName); + if (d->m_componentToNamespace[component].isEmpty()) + d->m_componentToNamespace.remove(component); + d->m_versionToNamespace[version].removeOne(namespaceName); + if (d->m_versionToNamespace[version].isEmpty()) + d->m_versionToNamespace.remove(version); + + return true; +} + +QString HelpDocSettings::namespaceName(const QString &fileName) const +{ + return d->m_fileNameToNamespace.value(fileName); +} + +QStringList HelpDocSettings::components() const +{ + return d->m_componentToNamespace.keys(); +} + +QList HelpDocSettings::versions() const +{ + return d->m_versionToNamespace.keys(); +} + +QStringList HelpDocSettings::namespaces() const +{ + return d->m_namespaceToFileName.keys(); +} + +QMap HelpDocSettings::namespaceToFileName() const +{ + return d->m_namespaceToFileName; +} + +HelpDocSettings HelpDocSettings::readSettings(QHelpEngineCore *helpEngine) +{ + QHelpFilterEngine *filterEngine = helpEngine->filterEngine(); + + HelpDocSettings docSettings; + docSettings.d->m_namespaceToComponent = filterEngine->namespaceToComponent(); + docSettings.d->m_namespaceToVersion = filterEngine->namespaceToVersion(); + for (auto it = docSettings.d->m_namespaceToComponent.constBegin(); + it != docSettings.d->m_namespaceToComponent.constEnd(); ++it) { + const QString namespaceName = it.key(); + const QString namespaceFileName = helpEngine->documentationFileName(namespaceName); + docSettings.d->m_namespaceToFileName.insert(namespaceName, namespaceFileName); + docSettings.d->m_fileNameToNamespace.insert(namespaceFileName, namespaceName); + docSettings.d->m_componentToNamespace[it.value()].append(namespaceName); + } + for (auto it = docSettings.d->m_namespaceToVersion.constBegin(); + it != docSettings.d->m_namespaceToVersion.constEnd(); ++it) { + docSettings.d->m_versionToNamespace[it.value()].append(it.key()); + } + + return docSettings; +} + +static QMap subtract(const QMap &minuend, + const QMap &subtrahend) +{ + auto result = minuend; + + for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) { + auto itResult = result.find(itSubtrahend.key()); + if (itResult != result.end() && itSubtrahend.value() == itResult.value()) + result.erase(itResult); + } + + return result; +} + +bool HelpDocSettings::applySettings(QHelpEngineCore *helpEngine, + const HelpDocSettings &settings) +{ + const HelpDocSettings oldSettings = readSettings(helpEngine); + + const QMap docsToRemove = subtract( + oldSettings.namespaceToFileName(), + settings.namespaceToFileName()); + const QMap docsToAdd = subtract( + settings.namespaceToFileName(), + oldSettings.namespaceToFileName()); + + bool changed = false; + for (const QString &namespaceName : docsToRemove.keys()) { + if (!helpEngine->unregisterDocumentation(namespaceName)) + qWarning() << "Cannot unregister documentation:" << namespaceName; + changed = true; + } + + for (const QString &fileName : docsToAdd.values()) { + if (!helpEngine->registerDocumentation(fileName)) + qWarning() << "Cannot register documentation file:" << fileName; + changed = true; + } + + return changed; +} + +QT_END_NAMESPACE diff --git a/src/winrtrunner/runner.h b/src/assistant/assistant/helpdocsettings.h similarity index 57% rename from src/winrtrunner/runner.h rename to src/assistant/assistant/helpdocsettings.h index 00b251be80..7476eb63a2 100644 --- a/src/winrtrunner/runner.h +++ b/src/assistant/assistant/helpdocsettings.h @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -37,54 +37,46 @@ ** ****************************************************************************/ -#ifndef RUNNER_H -#define RUNNER_H +#ifndef HELPDOCSETTINGS_H +#define HELPDOCSETTINGS_H -#include -#include -#include -#include -#include +#include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE -class RunnerPrivate; -class Runner +class QVersionNumber; +class QHelpEngineCore; +class HelpDocSettingsPrivate; + +class HelpDocSettings final { public: - static QMap deviceNames(); + HelpDocSettings(); + HelpDocSettings(const HelpDocSettings &other); + HelpDocSettings(HelpDocSettings &&other); + ~HelpDocSettings(); + + HelpDocSettings &operator=(const HelpDocSettings &other); + HelpDocSettings &operator=(HelpDocSettings &&other); - Runner(const QString &app, const QStringList &arguments, const QString &profile = QString(), - const QString &device = QString()); - ~Runner(); + void swap(HelpDocSettings &other) noexcept + { d.swap(other.d); } - bool isValid() const; - QString app() const; - QStringList arguments() const; - int deviceIndex() const; + bool addDocumentation(const QString &fileName); + bool removeDocumentation(const QString &namespaceName); + QString namespaceName(const QString &fileName) const; + QStringList components() const; + QList versions() const; + QStringList namespaces() const; + QMap namespaceToFileName() const; - bool install(bool removeFirst = false); - bool remove(); - bool start(); - bool enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments); - bool disableDebugging(); - bool setLoopbackExemptClientEnabled(bool enabled); - bool setLoopbackExemptServerEnabled(bool enabled); - bool setLoggingRules(const QByteArray &rules); - bool suspend(); - bool stop(); - bool wait(int maxWaitTime = 0); - bool setupTest(); - bool collectTest(); - qint64 pid(); - int exitCode(); + static HelpDocSettings readSettings(QHelpEngineCore *helpEngine); + static bool applySettings(QHelpEngineCore *helpEngine, const HelpDocSettings &settings); private: - QScopedPointer d_ptr; - Q_DECLARE_PRIVATE(Runner) + QSharedDataPointer d; }; -Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunner) -Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunnerApp) +QT_END_NAMESPACE -#endif // RUNNER_H +#endif // HELPDOCSETTINGS_H diff --git a/src/assistant/assistant/helpdocsettingswidget.cpp b/src/assistant/assistant/helpdocsettingswidget.cpp new file mode 100644 index 0000000000..646026a23a --- /dev/null +++ b/src/assistant/assistant/helpdocsettingswidget.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpdocsettings.h" +#include "helpdocsettingswidget.h" +#include "ui_helpdocsettingswidget.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class HelpDocSettingsWidgetPrivate +{ + HelpDocSettingsWidget *q_ptr; + Q_DECLARE_PUBLIC(HelpDocSettingsWidget) +public: + HelpDocSettingsWidgetPrivate() = default; + + void addDocumentation(); + void removeDocumentation(); + void applyDocListFilter(QListWidgetItem *item); + + QMap m_namespaceToItem; + QHash m_itemToNamespace; + + Ui::HelpDocSettingsWidget m_ui; + HelpDocSettings m_settings; +}; + +void HelpDocSettingsWidgetPrivate::addDocumentation() +{ + Q_Q(HelpDocSettingsWidget); + + const QStringList &fileNames = + QFileDialog::getOpenFileNames(q, HelpDocSettingsWidget::tr("Add Documentation"), {}, + HelpDocSettingsWidget::tr("Qt Compressed Help Files (*.qch)")); + if (fileNames.isEmpty()) + return; + + bool added = false; + + for (const QString &fileName : fileNames) { + if (!m_settings.addDocumentation(fileName)) + continue; + + if (!added) { + added = true; + m_ui.registeredDocsListWidget->clearSelection(); + } + + const QString namespaceName = m_settings.namespaceName(fileName); + QListWidgetItem *item = new QListWidgetItem(namespaceName); + m_namespaceToItem.insert(namespaceName, item); + m_itemToNamespace.insert(item, namespaceName); + m_ui.registeredDocsListWidget->insertItem(m_namespaceToItem.keys().indexOf(namespaceName), item); + + item->setSelected(true); + applyDocListFilter(item); + } + + if (added) + emit q->docSettingsChanged(m_settings); +} + +void HelpDocSettingsWidgetPrivate::removeDocumentation() +{ + Q_Q(HelpDocSettingsWidget); + + const QList selectedItems = m_ui.registeredDocsListWidget->selectedItems(); + if (selectedItems.isEmpty()) + return; + + for (QListWidgetItem *item : selectedItems) { + const QString namespaceName = m_itemToNamespace.value(item); + m_itemToNamespace.remove(item); + m_namespaceToItem.remove(namespaceName); + delete item; + + m_settings.removeDocumentation(namespaceName); + } + + emit q->docSettingsChanged(m_settings); +} + +void HelpDocSettingsWidgetPrivate::applyDocListFilter(QListWidgetItem *item) +{ + const QString namespaceName = m_itemToNamespace.value(item); + const QString nameFilter = m_ui.registeredDocsFilterLineEdit->text(); + + const bool matches = nameFilter.isEmpty() || namespaceName.contains(nameFilter); + + if (!matches) + item->setSelected(false); + item->setHidden(!matches); +} + +HelpDocSettingsWidget::HelpDocSettingsWidget(QWidget *parent) + : QWidget(parent) + , d_ptr(new HelpDocSettingsWidgetPrivate()) +{ + Q_D(HelpDocSettingsWidget); + d->q_ptr = this; + d->m_ui.setupUi(this); + + connect(d->m_ui.docAddButton, &QAbstractButton::clicked, + [this]() { + Q_D(HelpDocSettingsWidget); + d->addDocumentation(); + }); + connect(d->m_ui.docRemoveButton, &QAbstractButton::clicked, + [this]() { + Q_D(HelpDocSettingsWidget); + d->removeDocumentation(); + }); + connect(d->m_ui.registeredDocsFilterLineEdit, &QLineEdit::textChanged, + [this](const QString &) { + Q_D(HelpDocSettingsWidget); + for (const auto item : d->m_namespaceToItem) + d->applyDocListFilter(item); + }); + connect(d->m_ui.registeredDocsListWidget, &QListWidget::itemSelectionChanged, + [this]() { + Q_D(HelpDocSettingsWidget); + d->m_ui.docRemoveButton->setEnabled( + !d->m_ui.registeredDocsListWidget->selectedItems().isEmpty()); + }); +} + +HelpDocSettingsWidget::~HelpDocSettingsWidget() = default; + +void HelpDocSettingsWidget::setDocSettings(const HelpDocSettings &settings) +{ + Q_D(HelpDocSettingsWidget); + d->m_settings = settings; + + d->m_ui.registeredDocsListWidget->clear(); + d->m_namespaceToItem.clear(); + d->m_itemToNamespace.clear(); + + for (const QString &namespaceName : d->m_settings.namespaces()) { + QListWidgetItem *item = new QListWidgetItem(namespaceName); + d->m_namespaceToItem.insert(namespaceName, item); + d->m_itemToNamespace.insert(item, namespaceName); + d->m_ui.registeredDocsListWidget->addItem(item); + d->applyDocListFilter(item); + } + + d->m_ui.docRemoveButton->setEnabled( + !d->m_ui.registeredDocsListWidget->selectedItems().isEmpty()); +} + +HelpDocSettings HelpDocSettingsWidget::docSettings() const +{ + Q_D(const HelpDocSettingsWidget); + return d->m_settings; +} + +QT_END_NAMESPACE diff --git a/src/winrtrunner/appxengine.h b/src/assistant/assistant/helpdocsettingswidget.h similarity index 64% rename from src/winrtrunner/appxengine.h rename to src/assistant/assistant/helpdocsettingswidget.h index c2d235ec67..3ed0893537 100644 --- a/src/winrtrunner/appxengine.h +++ b/src/assistant/assistant/helpdocsettingswidget.h @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -37,40 +37,37 @@ ** ****************************************************************************/ -#ifndef APPXENGINE_H -#define APPXENGINE_H +#ifndef HELPDOCSETTINGSWIDGET_H +#define HELPDOCSETTINGSWIDGET_H -#include "runnerengine.h" -#include "runner.h" +#include -#include -#include +QT_BEGIN_NAMESPACE -QT_USE_NAMESPACE +class HelpDocSettings; +class HelpDocSettingsWidgetPrivate; -struct IAppxManifestReader; -class AppxEnginePrivate; -class AppxEngine : public RunnerEngine +class HelpDocSettingsWidget : public QWidget { + Q_OBJECT public: - qint64 pid() const override; - int exitCode() const override; - QString executable() const override; + HelpDocSettingsWidget(QWidget *parent = nullptr); -protected: - explicit AppxEngine(Runner *runner, AppxEnginePrivate *dd); - ~AppxEngine(); + ~HelpDocSettingsWidget(); - virtual QString extensionSdkPath() const = 0; - virtual bool installPackage(IAppxManifestReader *reader, const QString &filePath) = 0; + void setDocSettings(const HelpDocSettings &settings); + HelpDocSettings docSettings() const; - bool installDependencies(); - bool createPackage(const QString &packageFileName); - bool sign(const QString &fileName); - static bool getManifestFile(const QString &fileName, QString *manifest = 0); +Q_SIGNALS: + void docSettingsChanged(const HelpDocSettings &settings); - QScopedPointer d_ptr; - Q_DECLARE_PRIVATE(AppxEngine) +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(HelpDocSettingsWidget) + Q_DISABLE_COPY_MOVE(HelpDocSettingsWidget) }; -#endif // APPXENGINE_H +QT_END_NAMESPACE + +#endif + diff --git a/src/assistant/assistant/helpdocsettingswidget.ui b/src/assistant/assistant/helpdocsettingswidget.ui new file mode 100644 index 0000000000..4897dfe865 --- /dev/null +++ b/src/assistant/assistant/helpdocsettingswidget.ui @@ -0,0 +1,76 @@ + + + HelpDocSettingsWidget + + + + 0 + 0 + 268 + 128 + + + + Form + + + + + + Registered Documentation + + + + + + + <Filter> + + + true + + + + + + + + + Add... + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QAbstractItemView::ExtendedSelection + + + + + + + + diff --git a/src/assistant/assistant/helpenginewrapper.cpp b/src/assistant/assistant/helpenginewrapper.cpp index 17e4bde8c9..6f077d60bd 100644 --- a/src/assistant/assistant/helpenginewrapper.cpp +++ b/src/assistant/assistant/helpenginewrapper.cpp @@ -30,6 +30,7 @@ #include "helpenginewrapper.h" #include "../shared/collectionconfiguration.h" #include "../help/qhelpengine_p.h" +#include "helpbrowsersupport.h" #include #include @@ -41,8 +42,13 @@ #include #include #include +#include #include +#if defined(BROWSER_QTWEBENGINE) +#include +#endif + QT_BEGIN_NAMESPACE namespace { @@ -102,6 +108,9 @@ private slots: QFileSystemWatcher * const m_qchWatcher; typedef QPair > RecentSignal; QMap m_recentQchUpdates; +#if defined(BROWSER_QTWEBENGINE) + QWebEngineUrlSchemeHandler *m_helpSchemeHandler; +#endif }; HelpEngineWrapper *HelpEngineWrapper::helpEngineWrapper = nullptr; @@ -153,6 +162,10 @@ HelpEngineWrapper::HelpEngineWrapper(const QString &collectionFile) HelpEngineWrapper::~HelpEngineWrapper() { TRACE_OBJ +#if defined(BROWSER_QTWEBENGINE) + QWebEngineProfile::defaultProfile()->removeUrlSchemeHandler(d->m_helpSchemeHandler); +#endif + const QStringList &namespaces = d->m_helpEngine->registeredDocumentations(); for (const QString &nameSpace : namespaces) { const QString &docFile @@ -261,10 +274,10 @@ QByteArray HelpEngineWrapper::fileData(const QUrl &url) const return d->m_helpEngine->fileData(url); } -QMap HelpEngineWrapper::linksForIdentifier(const QString &id) const +QList HelpEngineWrapper::documentsForIdentifier(const QString &id) const { TRACE_OBJ - return d->m_helpEngine->linksForIdentifier(id); + return d->m_helpEngine->documentsForIdentifier(id); } QString HelpEngineWrapper::error() const @@ -670,6 +683,12 @@ void HelpEngineWrapper::setTopicChooserGeometry(const QByteArray &geometry) d->m_helpEngine->setCustomValue(TopicChooserGeometryKey, geometry); } +QHelpEngineCore *HelpEngineWrapper::helpEngine() const +{ + return d->m_helpEngine; +} + + // -- TimeoutForwarder TimeoutForwarder::TimeoutForwarder(const QString &fileName) @@ -687,12 +706,16 @@ void TimeoutForwarder::forward() // -- HelpEngineWrapperPrivate HelpEngineWrapperPrivate::HelpEngineWrapperPrivate(const QString &collectionFile) - : m_helpEngine(new QHelpEngine(collectionFile, this)), - m_qchWatcher(new QFileSystemWatcher(this)) + : m_helpEngine(new QHelpEngine(collectionFile, this)) + , m_qchWatcher(new QFileSystemWatcher(this)) +#if defined(BROWSER_QTWEBENGINE) + , m_helpSchemeHandler(0) +#endif { TRACE_OBJ - initFileSystemWatchers(); + m_helpEngine->setReadOnly(false); m_helpEngine->setUsesFilterEngine(true); + initFileSystemWatchers(); } void HelpEngineWrapperPrivate::initFileSystemWatchers() @@ -791,6 +814,17 @@ void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName, m_recentQchUpdates.erase(it); } +#if defined(BROWSER_QTWEBENGINE) + +void HelpEngineWrapper::ensureUrlSchemeHandler() +{ + if (!d->m_helpSchemeHandler) { + d->m_helpSchemeHandler = HelpBrowserSupport::createUrlSchemeHandler(this); + QWebEngineProfile::defaultProfile()->installUrlSchemeHandler(QByteArrayLiteral("qthelp"), d->m_helpSchemeHandler); + } +} +#endif + QT_END_NAMESPACE #include "helpenginewrapper.moc" diff --git a/src/assistant/assistant/helpenginewrapper.h b/src/assistant/assistant/helpenginewrapper.h index 6026a04736..c3ccef13f4 100644 --- a/src/assistant/assistant/helpenginewrapper.h +++ b/src/assistant/assistant/helpenginewrapper.h @@ -37,6 +37,8 @@ #include #include +#include "qhelplink.h" + QT_BEGIN_NAMESPACE class QFileSystemWatcher; @@ -46,6 +48,7 @@ class QHelpIndexModel; class QHelpIndexWidget; class QHelpSearchEngine; class QHelpFilterEngine; +class QHelpEngineCore; enum { ShowHomePage = 0, @@ -79,7 +82,7 @@ class HelpEngineWrapper : public QObject bool unregisterDocumentation(const QString &namespaceName); QUrl findFile(const QUrl &url) const; QByteArray fileData(const QUrl &url) const; - QMap linksForIdentifier(const QString &id) const; + QList documentsForIdentifier(const QString &id) const; QString error() const; QHelpFilterEngine *filterEngine() const; @@ -175,6 +178,13 @@ class HelpEngineWrapper : public QObject const QByteArray topicChooserGeometry() const; void setTopicChooserGeometry(const QByteArray &geometry); + QHelpEngineCore *helpEngine() const; + +#if defined(BROWSER_QTWEBENGINE) + void ensureUrlSchemeHandler(); +#endif + + signals: // For asynchronous doc updates triggered by external actions. diff --git a/src/assistant/assistant/helpviewer.h b/src/assistant/assistant/helpviewer.h index 00e941000e..882323abdd 100644 --- a/src/assistant/assistant/helpviewer.h +++ b/src/assistant/assistant/helpviewer.h @@ -34,11 +34,13 @@ #include #include -#include +#include #include #if defined(BROWSER_QTWEBKIT) # include +#elif defined(BROWSER_QTWEBENGINE) +# include #elif defined(BROWSER_QTEXTBROWSER) # include #endif @@ -46,10 +48,14 @@ QT_BEGIN_NAMESPACE class HelpEngineWrapper; +class QPrinter; #if defined(BROWSER_QTWEBKIT) #define TEXTBROWSER_OVERRIDE class HelpViewer : public QWebView +#elif defined(BROWSER_QTWEBENGINE) +#define TEXTBROWSER_OVERRIDE +class HelpViewer : public QWebEngineView #elif defined(BROWSER_QTEXTBROWSER) #define TEXTBROWSER_OVERRIDE override class HelpViewer : public QTextBrowser @@ -82,7 +88,11 @@ class HelpViewer : public QTextBrowser void setTitle(const QString &title); QUrl source() const; +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) || BROWSER_QTWEBENGINE void setSource(const QUrl &url) TEXTBROWSER_OVERRIDE; +#else + void doSetSource(const QUrl &url, QTextDocument::ResourceType type) TEXTBROWSER_OVERRIDE; +#endif QString selectedText() const; bool isForwardAvailable() const; @@ -101,7 +111,7 @@ class HelpViewer : public QTextBrowser static bool launchWithExternalApp(const QUrl &url); public slots: -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void copy(); #endif void home() TEXTBROWSER_OVERRIDE; @@ -117,7 +127,7 @@ public slots: void sourceChanged(const QUrl &url); void forwardAvailable(bool enabled); void backwardAvailable(bool enabled); - void highlighted(const QString &link); + void highlighted(const QUrl &link); void printRequested(); #elif !defined(BROWSER_QTWEBKIT) // Provide signals present in QWebView for browsers that do not inherit QWebView @@ -130,6 +140,7 @@ public slots: void wheelEvent(QWheelEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + void resizeEvent(QResizeEvent *e) override; private slots: void actionChanged(); @@ -141,6 +152,7 @@ private slots: void contextMenuEvent(QContextMenuEvent *event) override; QVariant loadResource(int type, const QUrl &name) TEXTBROWSER_OVERRIDE; bool handleForwardBackwardMouseButtons(QMouseEvent *e); + void scrollToTextPosition(int position); private: HelpViewerPrivate *d; diff --git a/src/assistant/assistant/helpviewer_p.h b/src/assistant/assistant/helpviewer_p.h index 8a85fdcea5..47615feb81 100644 --- a/src/assistant/assistant/helpviewer_p.h +++ b/src/assistant/assistant/helpviewer_p.h @@ -36,7 +36,7 @@ #include #if defined(BROWSER_QTEXTBROWSER) # include -#elif defined(BROWSER_QTWEBKIT) +#elif defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) # include # include #endif // BROWSER_QTWEBKIT @@ -52,7 +52,7 @@ class HelpViewer::HelpViewerPrivate : public QObject HelpViewerPrivate(int zoom) : zoomCount(zoom) { } -#elif defined(BROWSER_QTWEBKIT) +#elif defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) HelpViewerPrivate() : m_loadFinished(false) { @@ -112,7 +112,7 @@ public slots: lastAnchor.clear(); } -#elif defined(BROWSER_QTWEBKIT) +#elif defined(BROWSER_QTWEBKIT) || defined(BROWSER_QTWEBENGINE) qreal webDpiRatio; #endif // BROWSER_QTWEBKIT diff --git a/src/assistant/assistant/helpviewer_qtb.cpp b/src/assistant/assistant/helpviewer_qtb.cpp index b522e1ba2d..e8eb273389 100644 --- a/src/assistant/assistant/helpviewer_qtb.cpp +++ b/src/assistant/assistant/helpviewer_qtb.cpp @@ -38,7 +38,8 @@ #include #include -#ifndef QT_NO_CLIPBOARD +#include +#if QT_CONFIG(clipboard) #include #endif #include @@ -143,9 +144,16 @@ QUrl HelpViewer::source() const return QTextBrowser::source(); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void HelpViewer::setSource(const QUrl &url) +#else +void HelpViewer::doSetSource(const QUrl &url, QTextDocument::ResourceType type) +#endif { TRACE_OBJ +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + Q_UNUSED(type); +#endif if (launchWithExternalApp(url)) return; @@ -153,7 +161,7 @@ void HelpViewer::setSource(const QUrl &url) bool helpOrAbout = (url.toString() == QLatin1String("help")); const QUrl resolvedUrl = (helpOrAbout ? LocalHelpFile : HelpEngineWrapper::instance().findFile(url)); - QTextBrowser::setSource(resolvedUrl); + QTextBrowser::doSetSource(resolvedUrl, type); if (!resolvedUrl.isValid()) { helpOrAbout = (url.toString() == QLatin1String("about:blank")); @@ -237,7 +245,7 @@ bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental // -- public slots -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void HelpViewer::copy() { TRACE_OBJ @@ -277,7 +285,7 @@ void HelpViewer::wheelEvent(QWheelEvent *e) TRACE_OBJ if (e->modifiers() == Qt::ControlModifier) { e->accept(); - e->delta() > 0 ? scaleUp() : scaleDown(); + e->angleDelta().y() > 0 ? scaleUp() : scaleDown(); } else { QTextBrowser::wheelEvent(e); } @@ -304,7 +312,7 @@ void HelpViewer::mouseReleaseEvent(QMouseEvent *e) bool controlPressed = e->modifiers() & Qt::ControlModifier; if ((controlPressed && d->hasAnchorAt(this, e->pos())) || - (e->button() == Qt::MidButton && d->hasAnchorAt(this, e->pos()))) { + (e->button() == Qt::MiddleButton && d->hasAnchorAt(this, e->pos()))) { d->openLinkInNewPage(); return; } @@ -312,6 +320,14 @@ void HelpViewer::mouseReleaseEvent(QMouseEvent *e) QTextBrowser::mouseReleaseEvent(e); } + +void HelpViewer::resizeEvent(QResizeEvent *e) +{ + const int topTextPosition = cursorForPosition({width() / 2, 0}).position(); + QTextBrowser::resizeEvent(e); + scrollToTextPosition(topTextPosition); +} + // -- private slots void HelpViewer::actionChanged() @@ -336,7 +352,9 @@ void HelpViewer::contextMenuEvent(QContextMenuEvent *event) QMenu menu(QString(), nullptr); QUrl link; +#if QT_CONFIG(clipboard) QAction *copyAnchorAction = nullptr; +#endif if (d->hasAnchorAt(this, event->pos())) { link = anchorAt(event->pos()); if (link.isRelative()) @@ -344,17 +362,19 @@ void HelpViewer::contextMenuEvent(QContextMenuEvent *event) menu.addAction(tr("Open Link"), d, &HelpViewerPrivate::openLink); menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), d, &HelpViewerPrivate::openLinkInNewPage); +#if QT_CONFIG(clipboard) if (!link.isEmpty() && link.isValid()) copyAnchorAction = menu.addAction(tr("Copy &Link Location")); +#endif } else if (!selectedText().isEmpty()) { -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) menu.addAction(tr("Copy"), this, &HelpViewer::copy); #endif } else { menu.addAction(tr("Reload"), this, &HelpViewer::reload); } -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) if (copyAnchorAction == menu.exec(event->globalPos())) QApplication::clipboard()->setText(link.toString()); #endif @@ -377,4 +397,16 @@ QVariant HelpViewer::loadResource(int type, const QUrl &name) return ba; } + +void HelpViewer::scrollToTextPosition(int position) +{ + QTextCursor tc(document()); + tc.setPosition(position); + const int dy = cursorRect(tc).top(); + if (verticalScrollBar()) { + verticalScrollBar()->setValue( + std::min(verticalScrollBar()->value() + dy, verticalScrollBar()->maximum())); + } +} + QT_END_NAMESPACE diff --git a/src/assistant/assistant/helpviewer_qwev.cpp b/src/assistant/assistant/helpviewer_qwev.cpp new file mode 100644 index 0000000000..ddd9a19208 --- /dev/null +++ b/src/assistant/assistant/helpviewer_qwev.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer.h" +#include "helpviewer_p.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpbrowsersupport.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +// -- HelpPage + +class HelpPage : public QWebEnginePage +{ +public: + HelpPage(QObject *parent); + void upcomingLoad(const QUrl &url); + +protected: + QWebEnginePage *createWindow(QWebEnginePage::WebWindowType) override; + void triggerAction(WebAction action, bool checked = false) override; + + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override; + +private: + bool closeNewTabIfNeeded; + + friend class HelpViewer; + QUrl m_loadingUrl; + Qt::MouseButtons m_pressedButtons; + Qt::KeyboardModifiers m_keyboardModifiers; +}; + +HelpPage::HelpPage(QObject *parent) + : QWebEnginePage(parent) + , closeNewTabIfNeeded(false) + , m_pressedButtons(Qt::NoButton) + , m_keyboardModifiers(Qt::NoModifier) +{ + TRACE_OBJ +} + +QWebEnginePage *HelpPage::createWindow(QWebEnginePage::WebWindowType) +{ + TRACE_OBJ + HelpPage* newPage = static_cast(OpenPagesManager::instance() + ->createBlankPage()->page()); + newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + return newPage; +} + +void HelpPage::triggerAction(WebAction action, bool checked) +{ + TRACE_OBJ + switch (action) { + case OpenLinkInNewWindow: + closeNewTabIfNeeded = true; + Q_FALLTHROUGH(); + default: + QWebEnginePage::triggerAction(action, checked); + break; + } + +#ifndef QT_NO_CLIPBOARD + if (action == CopyLinkToClipboard || action == CopyImageUrlToClipboard) { + const QString link = QApplication::clipboard()->text(); + QApplication::clipboard()->setText(HelpEngineWrapper::instance().findFile(link).toString()); + } +#endif +} + +bool HelpPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool /*isMainFrame*/) +{ + TRACE_OBJ + const bool closeNewTab = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + + if (HelpViewer::launchWithExternalApp(url)) { + if (closeNewTab) + QMetaObject::invokeMethod(OpenPagesManager::instance(), "closeCurrentPage"); + return false; + } + + if (type == QWebEnginePage::NavigationTypeLinkClicked && + (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MiddleButton)) { + m_pressedButtons = Qt::NoButton; + m_keyboardModifiers = Qt::NoModifier; + OpenPagesManager::instance()->createPage(url); + return false; + } + + m_loadingUrl = url; // because of async page loading, we will hit some kind + // of race condition while using a remote command, like a combination of + // SetSource; SyncContent. SetSource would be called and SyncContents shortly + // afterwards, but the page might not have finished loading and the old url + // would be returned. + return true; +} + +void HelpPage::upcomingLoad(const QUrl &url) +{ + m_loadingUrl = url; +} + +// -- HelpViewer + +HelpViewer::HelpViewer(qreal zoom, QWidget *parent) + : QWebEngineView(parent) + , d(new HelpViewerPrivate) +{ + TRACE_OBJ + setAcceptDrops(false); + settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); + settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); + settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + + HelpEngineWrapper::instance().ensureUrlSchemeHandler(); + setPage(new HelpPage(this)); + + QAction* action = pageAction(QWebEnginePage::OpenLinkInNewWindow); + action->setText(tr("Open Link in New Page")); + + pageAction(QWebEnginePage::DownloadLinkToDisk)->setVisible(false); + pageAction(QWebEnginePage::DownloadImageToDisk)->setVisible(false); + + connect(pageAction(QWebEnginePage::Copy), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebEnginePage::Back), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebEnginePage::Forward), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(page(), SIGNAL(linkHovered(QString)), this, + SIGNAL(highlighted(QString))); + connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); + connect(this, SIGNAL(loadStarted()), this, SLOT(setLoadStarted())); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); + connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged())); + + setFont(viewerFont()); + setZoomFactor(d->webDpiRatio * (zoom == 0.0 ? 1.0 : zoom)); +} + +QFont HelpViewer::viewerFont() const +{ + TRACE_OBJ + if (HelpEngineWrapper::instance().usesBrowserFont()) + return HelpEngineWrapper::instance().browserFont(); + + QWebEngineSettings *webSettings = QWebEngineProfile::defaultProfile()->settings(); + return QFont(webSettings->fontFamily(QWebEngineSettings::StandardFont), + webSettings->fontSize(QWebEngineSettings::DefaultFontSize)); +} + +void HelpViewer::setViewerFont(const QFont &font) +{ + TRACE_OBJ + QWebEngineSettings *webSettings = settings(); + webSettings->setFontFamily(QWebEngineSettings::StandardFont, font.family()); + webSettings->setFontSize(QWebEngineSettings::DefaultFontSize, font.pointSize()); +} + +void HelpViewer::scaleUp() +{ + TRACE_OBJ + setZoomFactor(zoomFactor() + 1./16); +} + +void HelpViewer::scaleDown() +{ + TRACE_OBJ + setZoomFactor(qMax(1./16, zoomFactor() - 1./16)); +} + +void HelpViewer::resetScale() +{ + TRACE_OBJ + setZoomFactor(d->webDpiRatio); +} + +qreal HelpViewer::scale() const +{ + TRACE_OBJ + return zoomFactor() / d->webDpiRatio; +} + +QString HelpViewer::title() const +{ + TRACE_OBJ + return QWebEngineView::title(); +} + +void HelpViewer::setTitle(const QString &title) +{ + TRACE_OBJ + Q_UNUSED(title) +} + +QUrl HelpViewer::source() const +{ + TRACE_OBJ + HelpPage *currentPage = static_cast (page()); + if (currentPage && !d->m_loadFinished) { + // see HelpPage::acceptNavigationRequest(...) + return currentPage->m_loadingUrl; + } + return url(); +} + +void HelpViewer::setSource(const QUrl &url) +{ + TRACE_OBJ + if (url.toString() == QLatin1String("help")) + load(LocalHelpFile); + else { + // because of async page loading, we will hit some kind + // of race condition while using a remote command, like a combination of + // SetSource; SyncContent. SetSource would be called and SyncContents shortly + // afterwards, but the page might not have finished loading and the old url + // would be returned. + d->m_loadFinished = false; + static_cast(page())->upcomingLoad(url); + load(url); + } +} + +QString HelpViewer::selectedText() const +{ + TRACE_OBJ + return QWebEngineView::selectedText(); +} + +bool HelpViewer::isForwardAvailable() const +{ + TRACE_OBJ + return pageAction(QWebEnginePage::Forward)->isEnabled(); +} + +bool HelpViewer::isBackwardAvailable() const +{ + TRACE_OBJ + return pageAction(QWebEnginePage::Back)->isEnabled(); +} + +bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental, bool fromSearch) +{ + Q_UNUSED(incremental) + Q_UNUSED(fromSearch) + QWebEnginePage::FindFlags webEngineFlags(0); + if (flags & FindBackward) + webEngineFlags |= QWebEnginePage::FindBackward; + if (flags & FindCaseSensitively) + webEngineFlags |= QWebEnginePage::FindCaseSensitively; + // QWebEngineView's findText is asynchronous, and the variant taking a callback runs the + // callback on the main thread, so blocking here becomes ugly too + // So we just claim that the search succeeded + QWebEngineView::findText(text, webEngineFlags); + return true; +} + +// -- public slots + +#ifndef QT_NO_CLIPBOARD +void HelpViewer::copy() +{ + TRACE_OBJ + triggerPageAction(QWebEnginePage::Copy); +} +#endif + +void HelpViewer::forward() +{ + TRACE_OBJ + QWebEngineView::forward(); +} + +void HelpViewer::backward() +{ + TRACE_OBJ + back(); +} + +// -- protected + +void HelpViewer::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + // TODO: remove this once we support multiple keysequences per command +#ifndef QT_NO_CLIPBOARD + if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) { + if (!selectedText().isEmpty()) + copy(); + } +#endif + QWebEngineView::keyPressEvent(e); +} + +void HelpViewer::wheelEvent(QWheelEvent *event) +{ + TRACE_OBJ + if (event->modifiers() & Qt::ControlModifier) { + event->accept(); + event->angleDelta().y() > 0 ? scaleUp() : scaleDown(); + } else { + QWebEngineView::wheelEvent(event); + } +} + +void HelpViewer::mousePressEvent(QMouseEvent *event) +{ + TRACE_OBJ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + if (HelpPage *currentPage = static_cast (page())) { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + + QWebEngineView::mousePressEvent(event); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *event) +{ + TRACE_OBJ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + if (HelpPage *currentPage = static_cast (page())) { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + + QWebEngineView::mouseReleaseEvent(event); +} + +void HelpViewer::resizeEvent(QResizeEvent *e) +{ + //const int topTextPosition = cursorForPosition({width() / 2, 0}).position(); + QWebEngineView::resizeEvent(e); + //scrollToTextPosition(topTextPosition); +} + +// -- private slots + +void HelpViewer::actionChanged() +{ + TRACE_OBJ + QAction *a = qobject_cast(sender()); + if (a == pageAction(QWebEnginePage::Copy)) + emit copyAvailable(a->isEnabled()); + else if (a == pageAction(QWebEnginePage::Back)) + emit backwardAvailable(a->isEnabled()); + else if (a == pageAction(QWebEnginePage::Forward)) + emit forwardAvailable(a->isEnabled()); +} + +// -- private + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + TRACE_OBJ + return QWebEngineView::eventFilter(obj, event); +} + +void HelpViewer::contextMenuEvent(QContextMenuEvent *event) +{ + TRACE_OBJ + QWebEngineView::contextMenuEvent(event); +} + +QT_END_NAMESPACE diff --git a/src/assistant/assistant/helpviewer_qwv.cpp b/src/assistant/assistant/helpviewer_qwv.cpp index f8acb7b46d..7ed073eb85 100644 --- a/src/assistant/assistant/helpviewer_qwv.cpp +++ b/src/assistant/assistant/helpviewer_qwv.cpp @@ -101,7 +101,7 @@ void HelpPage::triggerAction(WebAction action, bool checked) break; } -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) if (action == CopyLinkToClipboard || action == CopyImageUrlToClipboard) { const QString link = QApplication::clipboard()->text(); QApplication::clipboard()->setText(HelpEngineWrapper::instance().findFile(link).toString()); @@ -124,11 +124,12 @@ bool HelpPage::acceptNavigationRequest(QWebFrame *, } if (type == QWebPage::NavigationTypeLinkClicked - && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) { - m_pressedButtons = Qt::NoButton; - m_keyboardModifiers = Qt::NoModifier; - OpenPagesManager::instance()->createPage(url); - return false; + && (m_keyboardModifiers & Qt::ControlModifier + || m_pressedButtons == Qt::MiddleButton)) { + m_pressedButtons = Qt::NoButton; + m_keyboardModifiers = Qt::NoModifier; + OpenPagesManager::instance()->createPage(url); + return false; } m_loadingUrl = url; // because of async page loading, we will hit some kind @@ -166,8 +167,10 @@ HelpViewer::HelpViewer(qreal zoom, QWidget *parent) SLOT(actionChanged())); connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, SLOT(actionChanged())); - connect(page(), SIGNAL(linkHovered(QString,QString,QString)), this, - SIGNAL(highlighted(QString))); + connect(page(), &QWebPage::linkHovered, this, + [this] (const QString &link, const QString &, const QString &) { + emit this->highlighted(QUrl(link)); + }); connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); connect(this, SIGNAL(loadStarted()), this, SLOT(setLoadStarted())); connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); @@ -288,7 +291,7 @@ bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental // -- public slots -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void HelpViewer::copy() { TRACE_OBJ @@ -314,7 +317,7 @@ void HelpViewer::keyPressEvent(QKeyEvent *e) { TRACE_OBJ // TODO: remove this once we support multiple keysequences per command -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) { if (!selectedText().isEmpty()) copy(); diff --git a/src/assistant/assistant/indexwindow.cpp b/src/assistant/assistant/indexwindow.cpp index d8c0f8212e..5e7ece6cbe 100644 --- a/src/assistant/assistant/indexwindow.cpp +++ b/src/assistant/assistant/indexwindow.cpp @@ -44,6 +44,8 @@ #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -71,10 +73,12 @@ IndexWindow::IndexWindow(QWidget *parent) this, &IndexWindow::disableSearchLineEdit); connect(helpEngine.indexModel(), &QHelpIndexModel::indexCreated, this, &IndexWindow::enableSearchLineEdit); - connect(m_indexWidget, &QHelpIndexWidget::linkActivated, - this, &IndexWindow::linkActivated); - connect(m_indexWidget, &QHelpIndexWidget::linksActivated, - this, &IndexWindow::linksActivated); + connect(m_indexWidget, &QHelpIndexWidget::documentActivated, + this, [this](const QHelpLink &link) { + emit linkActivated(link.url); + }); + connect(m_indexWidget, &QHelpIndexWidget::documentsActivated, + this, &IndexWindow::documentsActivated); connect(m_searchLineEdit, &QLineEdit::returnPressed, m_indexWidget, &QHelpIndexWidget::activateCurrentItem); layout->addWidget(m_indexWidget); @@ -147,7 +151,7 @@ bool IndexWindow::eventFilter(QObject *obj, QEvent *e) if (idx.isValid()) { Qt::MouseButtons button = mouseEvent->button(); if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier)) - || (button == Qt::MidButton)) { + || (button == Qt::MiddleButton)) { open(m_indexWidget, idx); } } @@ -196,15 +200,15 @@ void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index) QHelpIndexModel *model = qobject_cast(indexWidget->model()); if (model) { const QString keyword = model->data(index, Qt::DisplayRole).toString(); - const QMap links = model->linksForKeyword(keyword); + const QList docs = model->helpEngine()->documentsForKeyword(keyword); QUrl url; - if (links.count() > 1) { - TopicChooser tc(this, keyword, links); + if (docs.count() > 1) { + TopicChooser tc(this, keyword, docs); if (tc.exec() == QDialog::Accepted) url = tc.link(); - } else if (!links.isEmpty()) { - url = links.first(); + } else if (!docs.isEmpty()) { + url = docs.first().url; } else { return; } diff --git a/src/assistant/assistant/indexwindow.h b/src/assistant/assistant/indexwindow.h index 647d3b3b95..b20531799b 100644 --- a/src/assistant/assistant/indexwindow.h +++ b/src/assistant/assistant/indexwindow.h @@ -37,10 +37,12 @@ QT_BEGIN_NAMESPACE class QHelpIndexWidget; class QModelIndex; +struct QHelpLink; class IndexWindow : public QWidget { Q_OBJECT + Q_MOC_INCLUDE() public: IndexWindow(QWidget *parent = nullptr); @@ -54,8 +56,7 @@ class IndexWindow : public QWidget signals: void linkActivated(const QUrl &link); - void linksActivated(const QMap &links, - const QString &keyword); + void documentsActivated(const QList &documents, const QString &keyword); void escapePressed(); private slots: diff --git a/src/assistant/assistant/main.cpp b/src/assistant/assistant/main.cpp index 3ddbdbc29e..b5d8ddfe2d 100644 --- a/src/assistant/assistant/main.cpp +++ b/src/assistant/assistant/main.cpp @@ -49,13 +49,16 @@ #include #endif +#if defined(BROWSER_QTWEBENGINE) +#include +#endif + #include "../shared/collectionconfiguration.h" #include "helpenginewrapper.h" #include "mainwindow.h" #include "cmdlineparser.h" // #define TRACING_REQUESTED -// #define DEBUG_TRANSLATIONS QT_USE_NAMESPACE @@ -241,93 +244,64 @@ bool unregisterDocumentation(QHelpEngineCore &collection, void setupTranslation(const QString &fileName, const QString &dir) { QTranslator *translator = new QTranslator(QCoreApplication::instance()); - if (translator->load(fileName, dir)) + if (translator->load(QLocale(), fileName, QLatin1String("_"), dir)) QCoreApplication::installTranslator(translator); -#ifdef DEBUG_TRANSLATIONS - else if (!fileName.endsWith(QLatin1String("en_US")) - && !fileName.endsWith(QLatin1String("_C"))) { - qDebug("Could not load translation file %s in directory %s.", - qPrintable(fileName), qPrintable(dir)); - } -#endif } void setupTranslations() { TRACE_OBJ - const QString& locale = QLocale::system().name(); const QString &resourceDir - = QLibraryInfo::location(QLibraryInfo::TranslationsPath); - setupTranslation(QLatin1String("assistant_") + locale, resourceDir); - setupTranslation(QLatin1String("qt_") + locale, resourceDir); - setupTranslation(QLatin1String("qt_help_") + locale, resourceDir); + = QLibraryInfo::path(QLibraryInfo::TranslationsPath); + setupTranslation(QLatin1String("assistant"), resourceDir); + setupTranslation(QLatin1String("qt"), resourceDir); + setupTranslation(QLatin1String("qt_help"), resourceDir); } } // Anonymous namespace. -int main(int argc, char *argv[]) -{ - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); - TRACE_OBJ - QScopedPointer a(createApplication(argc, argv)); -#if QT_CONFIG(library) - a->addLibraryPath(a->applicationDirPath() + QLatin1String("/plugins")); -#endif - setupTranslations(); - -#if defined(BROWSER_QTWEBKIT) - if (qobject_cast(a.data())) { - QFont f; - f.setStyleHint(QFont::SansSerif); - QWebSettings::globalSettings()->setFontFamily(QWebSettings::StandardFont, f.defaultFamily()); - } -#endif // BROWSER_QTWEBKIT - - // Parse arguments. - CmdLineParser cmd(a->arguments()); - CmdLineParser::Result res = cmd.parse(); - if (res == CmdLineParser::Help) - return 0; - else if (res == CmdLineParser::Error) - return -1; +enum ExitStatus { + ExitSuccess = 0, + ExitFailure, + NoExit +}; +static ExitStatus preliminarySetup(CmdLineParser *cmd) +{ /* * Create the collection objects that we need. We always have the * cached collection file. Depending on whether the user specified * one, we also may have an input collection file. */ - const QString collectionFile = cmd.collectionFile(); + const QString collectionFile = cmd->collectionFile(); const bool collectionFileGiven = !collectionFile.isEmpty(); QScopedPointer collection; if (collectionFileGiven) { collection.reset(new QHelpEngineCore(collectionFile)); - collection->setProperty("_q_readonly", QVariant::fromValue(true)); if (!collection->setupData()) { - cmd.showMessage(QCoreApplication::translate("Assistant", - "Error reading collection file '%1': %2."). - arg(collectionFile).arg(collection->error()), true); - return EXIT_FAILURE; + cmd->showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2.") + .arg(collectionFile).arg(collection->error()), true); + return ExitFailure; } } const QString &cachedCollectionFile = collectionFileGiven - ? constructCachedCollectionFilePath(*collection) - : MainWindow::defaultHelpCollectionFileName(); + ? constructCachedCollectionFilePath(*collection) + : MainWindow::defaultHelpCollectionFileName(); if (collectionFileGiven && !QFileInfo(cachedCollectionFile).exists() - && !collection->copyCollectionFile(cachedCollectionFile)) { - cmd.showMessage(QCoreApplication::translate("Assistant", - "Error creating collection file '%1': %2."). - arg(cachedCollectionFile).arg(collection->error()), true); - return EXIT_FAILURE; + && !collection->copyCollectionFile(cachedCollectionFile)) { + cmd->showMessage(QCoreApplication::translate("Assistant", + "Error creating collection file '%1': %2.") + .arg(cachedCollectionFile).arg(collection->error()), true); + return ExitFailure; } QHelpEngineCore cachedCollection(cachedCollectionFile); if (!cachedCollection.setupData()) { - cmd.showMessage(QCoreApplication::translate("Assistant", - "Error reading collection file '%1': %2."). - arg(cachedCollectionFile). - arg(cachedCollection.error()), true); - return EXIT_FAILURE; + cmd->showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2.") + .arg(cachedCollectionFile) + .arg(cachedCollection.error()), true); + return ExitFailure; } stripNonexistingDocs(cachedCollection); @@ -335,56 +309,98 @@ int main(int argc, char *argv[]) if (CollectionConfiguration::isNewer(*collection, cachedCollection)) CollectionConfiguration::copyConfiguration(*collection, cachedCollection); - if (!synchronizeDocs(*collection, cachedCollection, cmd)) - return EXIT_FAILURE; + if (!synchronizeDocs(*collection, cachedCollection, *cmd)) + return ExitFailure; } - if (cmd.registerRequest() != CmdLineParser::None) { + if (cmd->registerRequest() != CmdLineParser::None) { const QStringList &cachedDocs = - cachedCollection.registeredDocumentations(); + cachedCollection.registeredDocumentations(); const QString &namespaceName = - QHelpEngineCore::namespaceName(cmd.helpFile()); - if (cmd.registerRequest() == CmdLineParser::Register) { + QHelpEngineCore::namespaceName(cmd->helpFile()); + if (cmd->registerRequest() == CmdLineParser::Register) { if (collectionFileGiven - && !registerDocumentation(*collection, cmd, true)) - return EXIT_FAILURE; + && !registerDocumentation(*collection, *cmd, true)) + return ExitFailure; if (!cachedDocs.contains(namespaceName) - && !registerDocumentation(cachedCollection, cmd, !collectionFileGiven)) - return EXIT_FAILURE; - return EXIT_SUCCESS; + && !registerDocumentation(cachedCollection, *cmd, !collectionFileGiven)) + return ExitFailure; + return ExitSuccess; } - if (cmd.registerRequest() == CmdLineParser::Unregister) { + if (cmd->registerRequest() == CmdLineParser::Unregister) { if (collectionFileGiven - && !unregisterDocumentation(*collection, namespaceName, cmd, true)) - return EXIT_FAILURE; + && !unregisterDocumentation(*collection, namespaceName, *cmd, true)) + return ExitFailure; if (cachedDocs.contains(namespaceName) - && !unregisterDocumentation(cachedCollection, namespaceName, - cmd, !collectionFileGiven)) - return EXIT_FAILURE; - return EXIT_SUCCESS; + && !unregisterDocumentation(cachedCollection, namespaceName, + *cmd, !collectionFileGiven)) + return ExitFailure; + return ExitSuccess; } } - if (cmd.removeSearchIndex()) { + if (cmd->removeSearchIndex()) { return removeSearchIndex(cachedCollectionFile) - ? EXIT_SUCCESS : EXIT_FAILURE; + ? ExitSuccess : ExitFailure; } if (!QSqlDatabase::isDriverAvailable(QLatin1String("QSQLITE"))) { - cmd.showMessage(QCoreApplication::translate("Assistant", - "Cannot load sqlite database driver!"), - true); - return EXIT_FAILURE; + cmd->showMessage(QCoreApplication::translate("Assistant", + "Cannot load sqlite database driver!"), + true); + return ExitFailure; } - if (!cmd.currentFilter().isEmpty()) { + if (!cmd->currentFilter().isEmpty()) { if (collectionFileGiven) - collection->setCurrentFilter(cmd.currentFilter()); - cachedCollection.setCurrentFilter(cmd.currentFilter()); + collection->setCurrentFilter(cmd->currentFilter()); + cachedCollection.setCurrentFilter(cmd->currentFilter()); } if (collectionFileGiven) - cmd.setCollectionFile(cachedCollectionFile); + cmd->setCollectionFile(cachedCollectionFile); + + return NoExit; +} + +int main(int argc, char *argv[]) +{ + TRACE_OBJ + QScopedPointer a(createApplication(argc, argv)); +#if QT_CONFIG(library) + a->addLibraryPath(a->applicationDirPath() + QLatin1String("/plugins")); +#endif + setupTranslations(); + +#if defined(BROWSER_QTWEBKIT) + if (qobject_cast(a.data())) { + QFont f; + f.setStyleHint(QFont::SansSerif); + QWebSettings::globalSettings()->setFontFamily(QWebSettings::StandardFont, f.defaultFamily()); + } +#endif // BROWSER_QTWEBKIT + +#if defined(BROWSER_QTWEBENGINE) + QWebEngineUrlScheme scheme(QByteArrayLiteral("qthelp")); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::Path); + scheme.setFlags(QWebEngineUrlScheme::SecureScheme); + QWebEngineUrlScheme::registerScheme(scheme); +#endif // BROWSER_QTWEBENGINE + + // Parse arguments. + CmdLineParser cmd(a->arguments()); + CmdLineParser::Result res = cmd.parse(); + if (res == CmdLineParser::Help) + return 0; + else if (res == CmdLineParser::Error) + return -1; + + const ExitStatus status = preliminarySetup(&cmd); + switch (status) { + case ExitFailure: return EXIT_FAILURE; + case ExitSuccess: return EXIT_SUCCESS; + default: break; + } MainWindow *w = new MainWindow(&cmd); w->show(); diff --git a/src/assistant/assistant/mainwindow.cpp b/src/assistant/assistant/mainwindow.cpp index 2b9c87bbf0..7d3447a8fd 100644 --- a/src/assistant/assistant/mainwindow.cpp +++ b/src/assistant/assistant/mainwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Assistant of the Qt Toolkit. @@ -58,13 +58,14 @@ #include #include -#include -#include -#include -#include +#include #include #include #include +#include + +#include +#include #include #include #include @@ -72,7 +73,6 @@ #include #include #include -#include #include #include #include @@ -418,7 +418,7 @@ static const char *docs[] = { static QStringList newQtDocumentation() { QStringList result; - const QDir docDirectory(QLibraryInfo::location(QLibraryInfo::DocumentationPath)); + const QDir docDirectory(QLibraryInfo::path(QLibraryInfo::DocumentationPath)); const QFileInfoList entries = docDirectory.entryInfoList(QStringList(QStringLiteral("*.qch")), QDir::Files, QDir::Name); if (!entries.isEmpty()) { @@ -556,7 +556,9 @@ void MainWindow::setupActions() tmp->setMenuRole(QAction::QuitRole); menu = menuBar()->addMenu(tr("&Edit")); +#if QT_CONFIG(clipboard) menu->addAction(globalActions->copyAction()); +#endif menu->addAction(globalActions->findAction()); QAction *findNextAction = menu->addAction(tr("Find &Next"), @@ -610,12 +612,12 @@ void MainWindow::setupActions() tmp = menu->addAction(tr("Next Page"), openPages, &OpenPagesManager::nextPage); tmp->setShortcuts(QList() << QKeySequence(tr("Ctrl+Alt+Right")) - << QKeySequence(Qt::CTRL + Qt::Key_PageDown)); + << QKeySequence(Qt::CTRL | Qt::Key_PageDown)); tmp = menu->addAction(tr("Previous Page"), openPages, &OpenPagesManager::previousPage); tmp->setShortcuts(QList() << QKeySequence(tr("Ctrl+Alt+Left")) - << QKeySequence(Qt::CTRL + Qt::Key_PageUp)); + << QKeySequence(Qt::CTRL | Qt::Key_PageUp)); const Qt::Modifier modifier = #ifdef Q_OS_MAC @@ -624,10 +626,10 @@ void MainWindow::setupActions() Qt::CTRL; #endif - QShortcut *sct = new QShortcut(QKeySequence(modifier + Qt::Key_Tab), this); + QShortcut *sct = new QShortcut(QKeySequence(modifier | Qt::Key_Tab), this); connect(sct, &QShortcut::activated, openPages, &OpenPagesManager::nextPageWithSwitcher); - sct = new QShortcut(QKeySequence(modifier + Qt::SHIFT + Qt::Key_Tab), this); + sct = new QShortcut(QKeySequence(modifier | Qt::SHIFT | Qt::Key_Tab), this); connect(sct, &QShortcut::activated, openPages, &OpenPagesManager::previousPageWithSwitcher); @@ -650,7 +652,9 @@ void MainWindow::setupActions() navigationBar->addAction(globalActions->homeAction()); navigationBar->addAction(m_syncAction); navigationBar->addSeparator(); +#if QT_CONFIG(clipboard) navigationBar->addAction(globalActions->copyAction()); +#endif navigationBar->addAction(globalActions->printAction()); navigationBar->addAction(globalActions->findAction()); navigationBar->addSeparator(); @@ -668,8 +672,10 @@ void MainWindow::setupActions() #endif // content viewer connections +#if QT_CONFIG(clipboard) connect(m_centralWidget, &CentralWidget::copyAvailable, globalActions, &GlobalActions::setCopyAvailable); +#endif connect(m_centralWidget, &CentralWidget::currentViewerChanged, globalActions, &GlobalActions::updateActions); connect(m_centralWidget, &CentralWidget::forwardAvailable, @@ -677,12 +683,12 @@ void MainWindow::setupActions() connect(m_centralWidget, &CentralWidget::backwardAvailable, globalActions, &GlobalActions::updateActions); connect(m_centralWidget, &CentralWidget::highlighted, - this, [this](const QString &link) { statusBar()->showMessage(link);} ); + this, [this](const QUrl &link) { statusBar()->showMessage(link.toString());} ); // index window connect(m_indexWindow, &IndexWindow::linkActivated, m_centralWidget, &CentralWidget::setSource); - connect(m_indexWindow, &IndexWindow::linksActivated, + connect(m_indexWindow, &IndexWindow::documentsActivated, this, &MainWindow::showTopicChooser); connect(m_indexWindow, &IndexWindow::escapePressed, this, &MainWindow::activateCurrentCentralWidgetTab); @@ -739,7 +745,7 @@ void MainWindow::setupFilterToolbar() connect(&helpEngine, &HelpEngineWrapper::setupFinished, this, &MainWindow::setupFilterCombo, Qt::QueuedConnection); - connect(m_filterCombo, QOverload::of(&QComboBox::activated), + connect(m_filterCombo, &QComboBox::activated, this, &MainWindow::filterDocumentation); connect(helpEngine.filterEngine(), &QHelpFilterEngine::filterActivated, this, &MainWindow::currentFilterChanged); @@ -822,11 +828,11 @@ void MainWindow::gotoAddress() m_centralWidget->setSource(m_addressLineEdit->text()); } -void MainWindow::showTopicChooser(const QMap &links, +void MainWindow::showTopicChooser(const QList &documents, const QString &keyword) { TRACE_OBJ - TopicChooser tc(this, keyword, links); + TopicChooser tc(this, keyword, documents); if (tc.exec() == QDialog::Accepted) { m_centralWidget->setSource(tc.link()); } @@ -842,7 +848,7 @@ void MainWindow::showPreferences() m_centralWidget, &CentralWidget::updateBrowserFont); connect(&dia, &PreferencesDialog::updateUserInterface, m_centralWidget, &CentralWidget::updateUserInterface); - dia.showDialog(); + dia.exec(); } void MainWindow::syncContents() @@ -899,6 +905,8 @@ void MainWindow::showAboutDialog() QByteArray resources; #if defined(BROWSER_QTWEBKIT) const QString browser = QStringLiteral("Qt WebKit"); +#elif defined(BROWSER_QTWEBENGINE) + const QString browser = QStringLiteral("Qt WebEngine"); #else const QString browser = QStringLiteral("QTextBrowser"); #endif @@ -907,7 +915,7 @@ void MainWindow::showAboutDialog() "

Version %2

" "

Browser: %3

" "

Copyright (C) %4 The Qt Company Ltd.

") - .arg(tr("Qt Assistant"), QLatin1String(QT_VERSION_STR), browser, QStringLiteral("2019")), + .arg(tr("Qt Assistant"), QLatin1String(QT_VERSION_STR), browser, QStringLiteral("2021")), resources); QLatin1String path(":/qt-project.org/assistant/images/assistant-128.png"); aboutDia.setPixmap(QString(path)); diff --git a/src/assistant/assistant/mainwindow.h b/src/assistant/assistant/mainwindow.h index c5bf5837e1..22983c7877 100644 --- a/src/assistant/assistant/mainwindow.h +++ b/src/assistant/assistant/mainwindow.h @@ -46,10 +46,12 @@ class ContentWindow; class IndexWindow; class QtDocInstaller; class SearchWidget; +struct QHelpLink; class MainWindow : public QMainWindow { Q_OBJECT + Q_MOC_INCLUDE() public: explicit MainWindow(CmdLineParser *cmdLine, QWidget *parent = nullptr); @@ -88,7 +90,7 @@ private slots: void showNewAddress(); void showAboutDialog(); void showNewAddress(const QUrl &url); - void showTopicChooser(const QMap &links, const QString &keyword); + void showTopicChooser(const QList &documents, const QString &keyword); void updateApplicationFont(); void filterDocumentation(int filterIndex); void setupFilterCombo(); diff --git a/src/assistant/assistant/openpageswidget.cpp b/src/assistant/assistant/openpageswidget.cpp index 6400fd97d1..2be24c164a 100644 --- a/src/assistant/assistant/openpageswidget.cpp +++ b/src/assistant/assistant/openpageswidget.cpp @@ -52,8 +52,11 @@ void OpenPagesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt { TRACE_OBJ if (option.state & QStyle::State_MouseOver) { +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED if ((QApplication::mouseButtons() & Qt::LeftButton) == 0) pressedIndex = QModelIndex(); +QT_WARNING_POP QBrush brush = option.palette.alternateBase(); if (index == pressedIndex) brush = option.palette.dark(); @@ -184,7 +187,7 @@ void OpenPagesWidget::handleClicked(const QModelIndex &index) QWidget *vp = viewport(); const QPoint &cursorPos = QCursor::pos(); QMouseEvent e(QEvent::MouseMove, vp->mapFromGlobal(cursorPos), cursorPos, - Qt::NoButton, nullptr, nullptr); + Qt::NoButton, {}, {}); QCoreApplication::sendEvent(vp, &e); } } diff --git a/src/assistant/assistant/preferencesdialog.cpp b/src/assistant/assistant/preferencesdialog.cpp index 7955e08dfc..9af0ff1889 100644 --- a/src/assistant/assistant/preferencesdialog.cpp +++ b/src/assistant/assistant/preferencesdialog.cpp @@ -28,42 +28,24 @@ #include "preferencesdialog.h" #include "centralwidget.h" -#include "filternamedialog.h" #include "fontpanel.h" #include "helpenginewrapper.h" #include "openpagesmanager.h" +#include "helpdocsettingswidget.h" #include + #include -#include -#include #include #include #include - -#include +#include #include QT_BEGIN_NAMESPACE -static QStringList versionsToStringList(const QList &versions) -{ - QStringList versionList; - for (const QVersionNumber &version : versions) - versionList.append(version.isNull() ? QString() : version.toString()); - return versionList; -} - -static QList stringListToVersions(const QStringList &versionList) -{ - QList versions; - for (const QString &versionString : versionList) - versions.append(QVersionNumber::fromString(versionString)); - return versions; -} - PreferencesDialog::PreferencesDialog(QWidget *parent) : QDialog(parent) , m_appFontChanged(false) @@ -74,18 +56,6 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) { m_ui.setupUi(this); - QString resourcePath = QLatin1String(":/qt-project.org/assistant/images/"); -#ifdef Q_OS_MACOS - resourcePath.append(QLatin1String("mac")); -#else - resourcePath.append(QLatin1String("win")); -#endif - - m_ui.filterAddButton->setIcon(QIcon(resourcePath + QLatin1String("/plus.png"))); - m_ui.filterRemoveButton->setIcon(QIcon(resourcePath + QLatin1String("/minus.png"))); - - // TODO: filter docs via lineedit - connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), &QAbstractButton::clicked, this, &PreferencesDialog::okClicked); connect(m_ui.buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, @@ -93,46 +63,30 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &QDialog::reject); - m_originalSetup = readOriginalSetup(); - m_currentSetup = m_originalSetup; + m_docSettings = HelpDocSettings::readSettings(helpEngine.helpEngine()); if (m_hideDocsTab) { m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); } else { - connect(m_ui.docAddButton, &QAbstractButton::clicked, - this, &PreferencesDialog::addDocumentation); - connect(m_ui.docRemoveButton, &QAbstractButton::clicked, - this, &PreferencesDialog::removeDocumentation); + connect(m_ui.docSettingsWidget, &HelpDocSettingsWidget::docSettingsChanged, + [this](const HelpDocSettings &settings) { + m_docSettings = settings; + if (m_hideFiltersTab) + return; - updateDocumentationPage(); + m_ui.filterSettingsWidget->setAvailableComponents(m_docSettings.components()); + m_ui.filterSettingsWidget->setAvailableVersions(m_docSettings.versions()); + }); + + m_ui.docSettingsWidget->setDocSettings(m_docSettings); } if (m_hideFiltersTab) { m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.filtersTab)); } else { - connect(m_ui.componentWidget, &OptionsWidget::optionSelectionChanged, - this, &PreferencesDialog::componentsChanged); - connect(m_ui.versionWidget, &OptionsWidget::optionSelectionChanged, - this, &PreferencesDialog::versionsChanged); - connect(m_ui.filterWidget, &QListWidget::currentItemChanged, - this, &PreferencesDialog::filterSelected); - connect(m_ui.filterWidget, &QListWidget::itemDoubleClicked, - this, &PreferencesDialog::renameFilterClicked); - - // TODO: repeat these actions on context menu - connect(m_ui.filterAddButton, &QAbstractButton::clicked, - this, &PreferencesDialog::addFilterClicked); - connect(m_ui.filterRenameButton, &QAbstractButton::clicked, - this, &PreferencesDialog::renameFilterClicked); - connect(m_ui.filterRemoveButton, &QAbstractButton::clicked, - this, &PreferencesDialog::removeFilterClicked); - - m_ui.componentWidget->setNoOptionText(tr("No Component")); - m_ui.componentWidget->setInvalidOptionText(tr("Invalid Component")); - m_ui.versionWidget->setNoOptionText(tr("No Version")); - m_ui.versionWidget->setInvalidOptionText(tr("Invalid Version")); - - updateFilterPage(); + m_ui.filterSettingsWidget->setAvailableComponents(m_docSettings.components()); + m_ui.filterSettingsWidget->setAvailableVersions(m_docSettings.versions()); + m_ui.filterSettingsWidget->readSettings(helpEngine.filterEngine()); } updateFontSettingsPage(); @@ -142,342 +96,6 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) setFont(helpEngine.appFont()); } -PreferencesDialog::~PreferencesDialog() -{ - if (m_appFontChanged) { - helpEngine.setAppFont(m_appFontPanel->selectedFont()); - helpEngine.setUseAppFont(m_appFontPanel->isChecked()); - helpEngine.setAppWritingSystem(m_appFontPanel->writingSystem()); - emit updateApplicationFont(); - } - - if (m_browserFontChanged) { - helpEngine.setBrowserFont(m_browserFontPanel->selectedFont()); - helpEngine.setUseBrowserFont(m_browserFontPanel->isChecked()); - helpEngine.setBrowserWritingSystem(m_browserFontPanel->writingSystem()); - emit updateBrowserFont(); - } - - QString homePage = m_ui.homePageLineEdit->text(); - if (homePage.isEmpty()) - homePage = QLatin1String("help"); - helpEngine.setHomePage(homePage); - - int option = m_ui.helpStartComboBox->currentIndex(); - helpEngine.setStartOption(option); -} - -FilterSetup PreferencesDialog::readOriginalSetup() const -{ - FilterSetup filterSetup; - - filterSetup.m_namespaceToComponent = helpEngine.filterEngine()->namespaceToComponent(); - filterSetup.m_namespaceToVersion = helpEngine.filterEngine()->namespaceToVersion(); - for (auto it = filterSetup.m_namespaceToComponent.constBegin(); - it != filterSetup.m_namespaceToComponent.constEnd(); ++it) { - const QString namespaceName = it.key(); - const QString namespaceFileName = helpEngine.documentationFileName(namespaceName); - filterSetup.m_namespaceToFileName.insert(namespaceName, namespaceFileName); - filterSetup.m_fileNameToNamespace.insert(namespaceFileName, namespaceName); - filterSetup.m_componentToNamespace[it.value()].append(namespaceName); - } - for (auto it = filterSetup.m_namespaceToVersion.constBegin(); - it != filterSetup.m_namespaceToVersion.constEnd(); ++it) { - filterSetup.m_versionToNamespace[it.value()].append(it.key()); - } - - const QStringList allFilters = helpEngine.filterEngine()->filters(); - for (const QString &filter : allFilters) - filterSetup.m_filterToData.insert(filter, helpEngine.filterEngine()->filterData(filter)); - - filterSetup.m_currentFilter = helpEngine.filterEngine()->activeFilter(); - - return filterSetup; -} - -void PreferencesDialog::showDialog() -{ - if (exec() != Accepted) - m_appFontChanged = m_browserFontChanged = false; -} - -void PreferencesDialog::updateFilterPage() -{ - if (m_hideFiltersTab) - return; - - QString currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - if (currentFilter.isEmpty()) - currentFilter = m_currentSetup.m_currentFilter; - - m_currentSetup = m_originalSetup; - - m_ui.filterWidget->clear(); - m_ui.componentWidget->clear(); - m_ui.versionWidget->clear(); - m_itemToFilter.clear(); - m_filterToItem.clear(); - - for (const QString &filterName : m_currentSetup.m_filterToData.keys()) { - QListWidgetItem *item = new QListWidgetItem(filterName); - m_ui.filterWidget->addItem(item); - m_itemToFilter.insert(item, filterName); - m_filterToItem.insert(filterName, item); - if (filterName == currentFilter) - m_ui.filterWidget->setCurrentItem(item); - } - - if (!m_ui.filterWidget->currentItem() && !m_filterToItem.isEmpty()) - m_ui.filterWidget->setCurrentItem(m_filterToItem.first()); - - updateCurrentFilter(); -} - -void PreferencesDialog::updateCurrentFilter() -{ - if (m_hideFiltersTab) - return; - - const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - - const bool filterSelected = !currentFilter.isEmpty(); - m_ui.componentWidget->setEnabled(filterSelected); - m_ui.versionWidget->setEnabled(filterSelected); - m_ui.filterRenameButton->setEnabled(filterSelected); - m_ui.filterRemoveButton->setEnabled(filterSelected); - - m_ui.componentWidget->setOptions(m_currentSetup.m_componentToNamespace.keys(), - m_currentSetup.m_filterToData.value(currentFilter).components()); - m_ui.versionWidget->setOptions(versionsToStringList(m_currentSetup.m_versionToNamespace.keys()), - versionsToStringList(m_currentSetup.m_filterToData.value(currentFilter).versions())); -} - -void PreferencesDialog::updateDocumentationPage() -{ - if (m_hideDocsTab) - return; - - m_ui.registeredDocsListWidget->clear(); - m_namespaceToItem.clear(); - m_itemToNamespace.clear(); - - for (const QString &namespaceName : m_currentSetup.m_namespaceToFileName.keys()) { - QListWidgetItem *item = new QListWidgetItem(namespaceName); - m_namespaceToItem.insert(namespaceName, item); - m_itemToNamespace.insert(item, namespaceName); - m_ui.registeredDocsListWidget->addItem(item); - } -} - -void PreferencesDialog::filterSelected(QListWidgetItem *item) -{ - Q_UNUSED(item) - - updateCurrentFilter(); -} - -void PreferencesDialog::componentsChanged(const QStringList &components) -{ - const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - if (currentFilter.isEmpty()) - return; - - m_currentSetup.m_filterToData[currentFilter].setComponents(components); -} - -void PreferencesDialog::versionsChanged(const QStringList &versions) -{ - const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - if (currentFilter.isEmpty()) - return; - - m_currentSetup.m_filterToData[currentFilter].setVersions(stringListToVersions(versions)); -} - -QString PreferencesDialog::suggestedNewFilterName(const QString &initialFilterName) const -{ - QString newFilterName = initialFilterName; - - int counter = 1; - while (m_filterToItem.contains(newFilterName)) { - newFilterName = initialFilterName + QLatin1Char(' ') - + QString::number(++counter); - } - - return newFilterName; -} - -QString PreferencesDialog::getUniqueFilterName(const QString &windowTitle, - const QString &initialFilterName) -{ - QString newFilterName = initialFilterName; - while (1) { - FilterNameDialog dialog(this); - dialog.setWindowTitle(windowTitle); - dialog.setFilterName(newFilterName); - if (dialog.exec() == QDialog::Rejected) - return QString(); - - newFilterName = dialog.filterName(); - if (!m_filterToItem.contains(newFilterName)) - break; - - if (QMessageBox::warning(this, tr("Filter Exists"), - tr("The filter \"%1\" already exists.") - .arg(newFilterName), - QMessageBox::Retry | QMessageBox::Cancel) - == QMessageBox::Cancel) { - return QString(); - } - } - - return newFilterName; -} - -void PreferencesDialog::addFilterClicked() -{ - const QString newFilterName = getUniqueFilterName(tr("Add Filter"), - suggestedNewFilterName(tr("New Filter"))); - if (newFilterName.isEmpty()) - return; - - addFilter(newFilterName); -} - -void PreferencesDialog::renameFilterClicked() -{ - const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - if (currentFilter.isEmpty()) - return; - - const QString newFilterName = getUniqueFilterName(tr("Rename Filter"), currentFilter); - if (newFilterName.isEmpty()) - return; - - const QHelpFilterData oldFilterData = m_currentSetup.m_filterToData.value(currentFilter); - removeFilter(currentFilter); - addFilter(newFilterName, oldFilterData); - - if (m_currentSetup.m_currentFilter == currentFilter) - m_currentSetup.m_currentFilter = newFilterName; -} - -void PreferencesDialog::removeFilterClicked() -{ - const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); - if (currentFilter.isEmpty()) - return; - - if (QMessageBox::question(this, tr("Remove Filter"), - tr("Are you sure you want to remove the \"%1\" filter?") - .arg(currentFilter), - QMessageBox::Yes | QMessageBox::No) - != QMessageBox::Yes) { - return; - } - - removeFilter(currentFilter); - - if (m_currentSetup.m_currentFilter == currentFilter) - m_currentSetup.m_currentFilter.clear(); -} - -void PreferencesDialog::addFilter(const QString &filterName, - const QHelpFilterData &filterData) -{ - QListWidgetItem *item = new QListWidgetItem(filterName); - m_currentSetup.m_filterToData.insert(filterName, filterData); - m_filterToItem.insert(filterName, item); - m_itemToFilter.insert(item, filterName); - m_ui.filterWidget->insertItem(m_filterToItem.keys().indexOf(filterName), item); - - m_ui.filterWidget->setCurrentItem(item); - updateCurrentFilter(); -} - -void PreferencesDialog::removeFilter(const QString &filterName) -{ - QListWidgetItem *item = m_filterToItem.value(filterName); - m_itemToFilter.remove(item); - m_filterToItem.remove(filterName); - delete item; - - m_currentSetup.m_filterToData.remove(filterName); -} - -void PreferencesDialog::addDocumentation() -{ - const QStringList &fileNames = QFileDialog::getOpenFileNames(this, - tr("Add Documentation"), QString(), tr("Qt Compressed Help Files (*.qch)")); - if (fileNames.isEmpty()) - return; - - bool added = false; - - for (const QString &fileName : fileNames) { - const QCompressedHelpInfo info = QCompressedHelpInfo::fromCompressedHelpFile(fileName); - const QString namespaceName = info.namespaceName(); - - if (m_currentSetup.m_namespaceToFileName.contains(namespaceName)) - continue; - - if (m_currentSetup.m_fileNameToNamespace.contains(fileName)) - continue; - - const QString component = info.component(); - const QVersionNumber version = info.version(); - - m_currentSetup.m_namespaceToFileName.insert(namespaceName, fileName); - m_currentSetup.m_fileNameToNamespace.insert(fileName, namespaceName); - - m_currentSetup.m_namespaceToComponent.insert(namespaceName, component); - m_currentSetup.m_componentToNamespace[component].append(namespaceName); - - m_currentSetup.m_namespaceToVersion.insert(namespaceName, version); - m_currentSetup.m_versionToNamespace[version].append(namespaceName); - - QListWidgetItem *item = new QListWidgetItem(namespaceName); - m_namespaceToItem.insert(namespaceName, item); - m_itemToNamespace.insert(item, namespaceName); - m_ui.registeredDocsListWidget->insertItem(m_namespaceToItem.keys().indexOf(namespaceName), item); - - added = true; - } - - if (added) - updateCurrentFilter(); -} - -void PreferencesDialog::removeDocumentation() -{ - const QList selectedItems = m_ui.registeredDocsListWidget->selectedItems(); - if (selectedItems.isEmpty()) - return; - - for (QListWidgetItem *item : selectedItems) { - const QString namespaceName = m_itemToNamespace.value(item); - m_itemToNamespace.remove(item); - m_namespaceToItem.remove(namespaceName); - delete item; - - const QString fileName = m_currentSetup.m_namespaceToFileName.value(namespaceName); - const QString component = m_currentSetup.m_namespaceToComponent.value(namespaceName); - const QVersionNumber version = m_currentSetup.m_namespaceToVersion.value(namespaceName); - m_currentSetup.m_namespaceToComponent.remove(namespaceName); - m_currentSetup.m_namespaceToVersion.remove(namespaceName); - m_currentSetup.m_namespaceToFileName.remove(namespaceName); - m_currentSetup.m_fileNameToNamespace.remove(fileName); - m_currentSetup.m_componentToNamespace[component].removeOne(namespaceName); - if (m_currentSetup.m_componentToNamespace[component].isEmpty()) - m_currentSetup.m_componentToNamespace.remove(component); - m_currentSetup.m_versionToNamespace[version].removeOne(namespaceName); - if (m_currentSetup.m_versionToNamespace[version].isEmpty()) - m_currentSetup.m_versionToNamespace.remove(version); - } - - updateCurrentFilter(); -} - void PreferencesDialog::okClicked() { applyChanges(); @@ -487,74 +105,27 @@ void PreferencesDialog::okClicked() void PreferencesDialog::applyClicked() { applyChanges(); - m_originalSetup = readOriginalSetup(); - m_currentSetup = m_originalSetup; - updateDocumentationPage(); - updateFilterPage(); -} -template -static QMap subtract(const QMap &minuend, - const QMap &subtrahend) -{ - QMap result = minuend; + m_docSettings = HelpDocSettings::readSettings(helpEngine.helpEngine()); - for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) { - auto itResult = result.find(itSubtrahend.key()); - if (itResult != result.end() && itSubtrahend.value() == itResult.value()) - result.erase(itResult); + if (!m_hideDocsTab) + m_ui.docSettingsWidget->setDocSettings(m_docSettings); + if (!m_hideFiltersTab) { + m_ui.filterSettingsWidget->setAvailableComponents(m_docSettings.components()); + m_ui.filterSettingsWidget->setAvailableVersions(m_docSettings.versions()); + m_ui.filterSettingsWidget->readSettings(helpEngine.filterEngine()); } - - return result; } void PreferencesDialog::applyChanges() { bool changed = false; - - const QMap docsToRemove = subtract( - m_originalSetup.m_namespaceToFileName, - m_currentSetup.m_namespaceToFileName); - const QMap docsToAdd = subtract( - m_currentSetup.m_namespaceToFileName, - m_originalSetup.m_namespaceToFileName); - - for (const QString &namespaceName : docsToRemove.keys()) { - if (!helpEngine.unregisterDocumentation(namespaceName)) - qWarning() << "Cannot unregister documentation:" << namespaceName; - changed = true; - } - - for (const QString &fileName : docsToAdd.values()) { - if (!helpEngine.registerDocumentation(fileName)) - qWarning() << "Cannot register documentation file:" << fileName; - changed = true; - } - - const QMap filtersToRemove = subtract( - m_originalSetup.m_filterToData, - m_currentSetup.m_filterToData); - const QMap filtersToAdd = subtract( - m_currentSetup.m_filterToData, - m_originalSetup.m_filterToData); - - const QString ¤tFilter = helpEngine.filterEngine()->activeFilter(); - - for (const QString &filter : filtersToRemove.keys()) { - helpEngine.filterEngine()->removeFilter(filter); - if (currentFilter == filter && !filtersToAdd.contains(filter)) - helpEngine.filterEngine()->setActiveFilter(QString()); - changed = true; - } - - for (auto it = filtersToAdd.cbegin(); it != filtersToAdd.cend(); ++it) { - helpEngine.filterEngine()->setFilterData(it.key(), it.value()); - changed = true; - } + if (!m_hideDocsTab) + changed = HelpDocSettings::applySettings(helpEngine.helpEngine(), m_docSettings); + if (!m_hideFiltersTab) + changed = changed || m_ui.filterSettingsWidget->applySettings(helpEngine.filterEngine()); if (changed) { - helpEngine.filterEngine()->setActiveFilter(m_currentSetup.m_currentFilter); - // In order to update the filtercombobox and indexwidget // according to the new filter configuration. helpEngine.setupData(); @@ -563,6 +134,30 @@ void PreferencesDialog::applyChanges() helpEngine.setShowTabs(m_ui.showTabs->isChecked()); if (m_showTabs != m_ui.showTabs->isChecked()) emit updateUserInterface(); + + if (m_appFontChanged) { + helpEngine.setAppFont(m_appFontPanel->selectedFont()); + helpEngine.setUseAppFont(m_appFontPanel->isChecked()); + helpEngine.setAppWritingSystem(m_appFontPanel->writingSystem()); + emit updateApplicationFont(); + m_appFontChanged = false; + } + + if (m_browserFontChanged) { + helpEngine.setBrowserFont(m_browserFontPanel->selectedFont()); + helpEngine.setUseBrowserFont(m_browserFontPanel->isChecked()); + helpEngine.setBrowserWritingSystem(m_browserFontPanel->writingSystem()); + emit updateBrowserFont(); + m_browserFontChanged = false; + } + + QString homePage = m_ui.homePageLineEdit->text(); + if (homePage.isEmpty()) + homePage = QLatin1String("help"); + helpEngine.setHomePage(homePage); + + const int option = m_ui.helpStartComboBox->currentIndex(); + helpEngine.setStartOption(option); } void PreferencesDialog::updateFontSettingsPage() @@ -605,13 +200,13 @@ void PreferencesDialog::updateFontSettingsPage() const QList &appCombos = m_appFontPanel->findChildren(); for (QComboBox* box : appCombos) { - connect(box, QOverload::of(&QComboBox::currentIndexChanged), + connect(box, &QComboBox::currentIndexChanged, this, &PreferencesDialog::appFontSettingChanged); } const QList &browserCombos = m_browserFontPanel->findChildren(); for (QComboBox* box : browserCombos) { - connect(box, QOverload::of(&QComboBox::currentIndexChanged), + connect(box, &QComboBox::currentIndexChanged, this, &PreferencesDialog::browserFontSettingChanged); } } diff --git a/src/assistant/assistant/preferencesdialog.h b/src/assistant/assistant/preferencesdialog.h index 89c30c5683..a65066fde6 100644 --- a/src/assistant/assistant/preferencesdialog.h +++ b/src/assistant/assistant/preferencesdialog.h @@ -29,30 +29,17 @@ #ifndef PREFERENCESDIALOG_H #define PREFERENCESDIALOG_H +#include #include #include #include "ui_preferencesdialog.h" +#include "helpdocsettings.h" QT_BEGIN_NAMESPACE class FontPanel; class HelpEngineWrapper; class QFileSystemWatcher; -class QVersionNumber; - -struct FilterSetup { - QMap m_namespaceToComponent; - QMap m_componentToNamespace; - - QMap m_namespaceToVersion; - QMap m_versionToNamespace; - - QMap m_namespaceToFileName; - QMap m_fileNameToNamespace; - - QMap m_filterToData; - QString m_currentFilter; -}; class PreferencesDialog : public QDialog { @@ -60,22 +47,8 @@ class PreferencesDialog : public QDialog public: PreferencesDialog(QWidget *parent = nullptr); - ~PreferencesDialog() override; - - void showDialog(); private slots: - void filterSelected(QListWidgetItem *item); - void componentsChanged(const QStringList &components); - void versionsChanged(const QStringList &versions); - void addFilterClicked(); - void renameFilterClicked(); - void removeFilterClicked(); - void addFilter(const QString &filterName, - const QHelpFilterData &filterData = QHelpFilterData()); - void removeFilter(const QString &filterName); - void addDocumentation(); - void removeDocumentation(); void okClicked(); void applyClicked(); void applyChanges(); @@ -94,26 +67,12 @@ private slots: void updateUserInterface(); private: - QString suggestedNewFilterName(const QString &initialFilterName) const; - QString getUniqueFilterName(const QString &windowTitle, - const QString &initialFilterName = QString()); - void updateFilterPage(); - void updateCurrentFilter(); - void updateDocumentationPage(); void updateFontSettingsPage(); void updateOptionsPage(); - FilterSetup readOriginalSetup() const; Ui::PreferencesDialogClass m_ui; - FilterSetup m_originalSetup; - FilterSetup m_currentSetup; - - QMap m_namespaceToItem; - QHash m_itemToNamespace; - - QMap m_filterToItem; - QHash m_itemToFilter; + HelpDocSettings m_docSettings; FontPanel *m_appFontPanel; FontPanel *m_browserFontPanel; diff --git a/src/assistant/assistant/preferencesdialog.ui b/src/assistant/assistant/preferencesdialog.ui index 68dbf68e25..2d1c480a60 100644 --- a/src/assistant/assistant/preferencesdialog.ui +++ b/src/assistant/assistant/preferencesdialog.ui @@ -7,7 +7,7 @@ 0 0 395 - 341 + 376 @@ -17,7 +17,7 @@ - 1 + 2 @@ -69,60 +69,21 @@ Filters - - - - - QFrame::NoFrame - - - Components: - - - - - - - Versions: - - - - - - - - - - - - - - - - Add... - - - - - - - Rename... - - - - - - - Remove - - - - - - - Filter: - - + + + 0 + + + 0 + + + 0 + + + 0 + + + @@ -130,61 +91,21 @@ Documentation - - - - - Registered Documentation: - - - - - - - <Filter> - - - true - - - - - - - - - Add... - - - - - - - Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - QAbstractItemView::ExtendedSelection - - + + + 0 + + + 0 + + + 0 + + + 0 + + + @@ -359,9 +280,15 @@ - OptionsWidget + HelpDocSettingsWidget + QWidget +
helpdocsettingswidget.h
+ 1 +
+ + QHelpFilterSettingsWidget QWidget -
optionswidget.h
+
qhelpfiltersettingswidget.h
1
diff --git a/src/assistant/assistant/qtdocinstaller.cpp b/src/assistant/assistant/qtdocinstaller.cpp index b25aa2b72f..1a758577c0 100644 --- a/src/assistant/assistant/qtdocinstaller.cpp +++ b/src/assistant/assistant/qtdocinstaller.cpp @@ -63,7 +63,7 @@ void QtDocInstaller::installDocs() void QtDocInstaller::run() { TRACE_OBJ - m_qchDir.setPath(QLibraryInfo::location(QLibraryInfo::DocumentationPath)); + m_qchDir.setPath(QLibraryInfo::path(QLibraryInfo::DocumentationPath)); m_qchFiles = m_qchDir.entryList(QStringList() << QLatin1String("*.qch")); bool changes = false; diff --git a/src/assistant/assistant/remotecontrol.cpp b/src/assistant/assistant/remotecontrol.cpp index 7fdbee41ef..0c9cc6c14d 100644 --- a/src/assistant/assistant/remotecontrol.cpp +++ b/src/assistant/assistant/remotecontrol.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #ifdef Q_OS_WIN @@ -199,9 +200,9 @@ void RemoteControl::handleActivateIdentifierCommand(const QString &arg) clearCache(); m_activateIdentifier = arg; } else { - const QMap links = helpEngine.linksForIdentifier(arg); - if (!links.isEmpty()) - CentralWidget::instance()->setSource(links.first()); + const auto docs = helpEngine.documentsForIdentifier(arg); + if (!docs.isEmpty()) + CentralWidget::instance()->setSource(docs.first().url); } } @@ -266,10 +267,10 @@ void RemoteControl::applyCache() m_mainWindow->setIndexString(m_activateKeyword); helpEngine.indexWidget()->activateCurrentItem(); } else if (!m_activateIdentifier.isEmpty()) { - const QMap links = - helpEngine.linksForIdentifier(m_activateIdentifier); - if (!links.isEmpty()) - CentralWidget::instance()->setSource(links.first()); + const auto docs = + helpEngine.documentsForIdentifier(m_activateIdentifier); + if (!docs.isEmpty()) + CentralWidget::instance()->setSource(docs.first().url); } else if (!m_currentFilter.isEmpty()) { helpEngine.filterEngine()->setActiveFilter(m_currentFilter); } diff --git a/src/assistant/assistant/searchwidget.cpp b/src/assistant/assistant/searchwidget.cpp index f4d991df72..d6466b1cc8 100644 --- a/src/assistant/assistant/searchwidget.cpp +++ b/src/assistant/assistant/searchwidget.cpp @@ -38,7 +38,7 @@ #include #include #include -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) #include #endif #include @@ -149,8 +149,8 @@ bool SearchWidget::eventFilter(QObject* o, QEvent *e) QUrl link = resultWidget->linkAt(me->pos()); if (!link.isEmpty() || link.isValid()) { bool controlPressed = me->modifiers() & Qt::ControlModifier; - if((me->button() == Qt::LeftButton && controlPressed) - || (me->button() == Qt::MidButton)) { + if ((me->button() == Qt::LeftButton && controlPressed) + || (me->button() == Qt::MiddleButton)) { emit requestShowLinkInNewTab(link); } } @@ -184,15 +184,15 @@ void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) QUrl link = browser->anchorAt(point); QKeySequence keySeq; -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) keySeq = QKeySequence::Copy; QAction *copyAction = menu.addAction(tr("&Copy") + QLatin1Char('\t') + keySeq.toString(QKeySequence::NativeText)); copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection()); -#endif QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location")); copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); +#endif keySeq = QKeySequence(Qt::CTRL); QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") + @@ -207,7 +207,7 @@ void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) QLatin1Char('\t') + keySeq.toString(QKeySequence::NativeText)); QAction *usedAction = menu.exec(mapToGlobal(contextMenuEvent->pos())); -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) if (usedAction == copyAction) { QTextCursor cursor = browser->textCursor(); if (!cursor.isNull() && cursor.hasSelection()) { diff --git a/src/assistant/assistant/topicchooser.cpp b/src/assistant/assistant/topicchooser.cpp index 478ca65ed8..ec9faddb60 100644 --- a/src/assistant/assistant/topicchooser.cpp +++ b/src/assistant/assistant/topicchooser.cpp @@ -35,9 +35,11 @@ #include #include +#include + QT_BEGIN_NAMESPACE -TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, const QMap &links) +TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, const QList &docs) : QDialog(parent) , m_filterModel(new QSortFilterProxyModel(this)) { @@ -53,10 +55,10 @@ TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, const QMapsetSourceModel(model); m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - for (auto it = links.cbegin(), end = links.cend(); it != end; ++it) { - m_links.append(it.value()); - QStandardItem *item = new QStandardItem(it.key()); - item->setToolTip(it.value().toString()); + for (const auto &doc : docs) { + m_links.append(doc.url); + QStandardItem *item = new QStandardItem(doc.title); + item->setToolTip(doc.url.toString()); model->appendRow(item); } @@ -120,23 +122,14 @@ bool TopicChooser::eventFilter(QObject *object, QEvent *event) { TRACE_OBJ if (object == ui.lineEdit && event->type() == QEvent::KeyPress) { - QModelIndex idx = ui.listWidget->currentIndex(); - switch ((static_cast(event)->key())) { - case Qt::Key_Up: - idx = m_filterModel->index(idx.row() - 1, idx.column(), - idx.parent()); - if (idx.isValid()) - ui.listWidget->setCurrentIndex(idx); - break; - - case Qt::Key_Down: - idx = m_filterModel->index(idx.row() + 1, idx.column(), - idx.parent()); - if (idx.isValid()) - ui.listWidget->setCurrentIndex(idx); - break; - - default: ; + QKeyEvent *keyEvent = static_cast(event); + switch (keyEvent->key()) { + case Qt::Key_Up: + case Qt::Key_Down: + case Qt::Key_PageUp: + case Qt::Key_PageDown: + QCoreApplication::sendEvent(ui.listWidget, event); + break; } } else if (ui.lineEdit && event->type() == QEvent::FocusIn && static_cast(event)->reason() != Qt::MouseFocusReason) { diff --git a/src/assistant/assistant/topicchooser.h b/src/assistant/assistant/topicchooser.h index 730ad68a01..2406ef99fa 100644 --- a/src/assistant/assistant/topicchooser.h +++ b/src/assistant/assistant/topicchooser.h @@ -36,13 +36,14 @@ QT_BEGIN_NAMESPACE class QSortFilterProxyModel; +struct QHelpLink; class TopicChooser : public QDialog { Q_OBJECT public: - TopicChooser(QWidget *parent, const QString &keyword, const QMap &links); + TopicChooser(QWidget *parent, const QString &keyword, const QList &docs); ~TopicChooser() override; QUrl link() const; diff --git a/src/assistant/help/CMakeLists.txt b/src/assistant/help/CMakeLists.txt new file mode 100644 index 0000000000..f2673fb041 --- /dev/null +++ b/src/assistant/help/CMakeLists.txt @@ -0,0 +1,69 @@ +# Generated from help.pro. + +##################################################################### +## Help Module: +##################################################################### + +qt_internal_add_module(Help + SOURCES + qcompressedhelpinfo.cpp qcompressedhelpinfo.h + qfilternamedialog.cpp qfilternamedialog.ui qfilternamedialog_p.h + qhelp_global.cpp qhelp_global.h + qhelpcollectionhandler.cpp qhelpcollectionhandler_p.h + qhelpcontentwidget.cpp qhelpcontentwidget.h + qhelpdbreader.cpp qhelpdbreader_p.h + qhelpengine.cpp qhelpengine.h qhelpengine_p.h + qhelpenginecore.cpp qhelpenginecore.h + qhelpfilterdata.cpp qhelpfilterdata.h + qhelpfilterengine.cpp qhelpfilterengine.h + qhelpfiltersettings.cpp qhelpfiltersettings_p.h + qhelpfiltersettingswidget.cpp qhelpfiltersettingswidget.h qhelpfiltersettingswidget.ui + qhelpindexwidget.cpp qhelpindexwidget.h + qhelplink.cpp qhelplink.h + qhelpsearchengine.cpp qhelpsearchengine.h + qhelpsearchindexreader.cpp qhelpsearchindexreader_p.h + qhelpsearchindexreader_default.cpp qhelpsearchindexreader_default_p.h + qhelpsearchindexwriter_default.cpp qhelpsearchindexwriter_default_p.h + qhelpsearchquerywidget.cpp qhelpsearchquerywidget.h + qhelpsearchresultwidget.cpp qhelpsearchresultwidget.h + qoptionswidget.cpp qoptionswidget_p.h + DEFINES + # -QT_ASCII_CAST_WARNINGS # special case remove + QHELP_LIB + LIBRARIES + Qt::CorePrivate + Qt::Network + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::Sql + Qt::Widgets + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + ENABLE_AUTOGEN_TOOLS + uic +) + +# Resources: +set(helpsystem_resource_files + "images/1leftarrow.png" + "images/1rightarrow.png" + "images/3leftarrow.png" + "images/3rightarrow.png" + "images/mac/minus.png" + "images/mac/plus.png" + "images/win/minus.png" + "images/win/plus.png" +) + +qt_internal_add_resource(Help "helpsystem" + PREFIX + "/qt-project.org/assistant" + FILES + ${helpsystem_resource_files} +) + +qt_internal_add_docs(Help + doc/qthelp.qdocconf +) + diff --git a/src/assistant/help/Qt5HelpConfigExtras.cmake.in b/src/assistant/help/Qt5HelpConfigExtras.cmake.in index 3b97923a99..1f7544b623 100644 --- a/src/assistant/help/Qt5HelpConfigExtras.cmake.in +++ b/src/assistant/help/Qt5HelpConfigExtras.cmake.in @@ -28,3 +28,14 @@ if (NOT TARGET Qt5::qhelpgenerator) IMPORTED_LOCATION ${imported_location} ) endif() + +# Create versionless tool targets. +foreach(__qt_tool qcollectiongenerator qhelpgenerator) + if(NOT \"${QT_NO_CREATE_VERSIONLESS_TARGETS}\" AND NOT TARGET Qt::${__qt_tool} + AND TARGET Qt5::${__qt_tool}) + add_executable(Qt::${__qt_tool} IMPORTED) + get_target_property(__qt_imported_location Qt5::${__qt_tool} IMPORTED_LOCATION) + set_target_properties(Qt::${__qt_tool} + PROPERTIES IMPORTED_LOCATION \"${__qt_imported_location}\") + endif() +endforeach() diff --git a/src/assistant/help/doc/qthelp.qdocconf b/src/assistant/help/doc/qthelp.qdocconf index 05f34e9f3e..89437e75ac 100644 --- a/src/assistant/help/doc/qthelp.qdocconf +++ b/src/assistant/help/doc/qthelp.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtHelp description = Qt Help Reference Documentation @@ -25,7 +26,7 @@ qhp.QtHelp.subprojects.classes.sortPages = true language = Cpp -depends += qtdoc qtcore qtassistant qtwidgets qmake +depends += qtdoc qtcore qtwidgets qmake headerdirs += .. @@ -38,3 +39,5 @@ imagedirs = images navigation.landingpage = "Qt Help" navigation.cppclassespage = "Qt Help C++ Classes" + +warninglimit = 0 diff --git a/src/assistant/help/doc/snippets/doc_src_qthelp.cpp b/src/assistant/help/doc/snippets/doc_src_qthelp.cpp index aa8ef23dc3..04d0b7377a 100644 --- a/src/assistant/help/doc/snippets/doc_src_qthelp.cpp +++ b/src/assistant/help/doc/snippets/doc_src_qthelp.cpp @@ -57,13 +57,13 @@ QHelpEngineCore helpEngine("mycollection.qhc"); ... // get all file references for the identifier -QMap links = - helpEngine.linksForIdentifier(QLatin1String("MyDialog::ChangeButton")); +QList links = + helpEngine.documentsForIdentifier(QLatin1String("MyDialog::ChangeButton")); // If help is available for this keyword, get the help data // of the first file reference. if (links.count()) { - QByteArray helpData = helpEngine->fileData(links.constBegin().value()); + QByteArray helpData = helpEngine->fileData(links.constBegin()->url); // show the documentation to the user if (!helpData.isEmpty()) displayHelp(helpData); diff --git a/src/assistant/help/doc/src/qthelp-module.qdoc b/src/assistant/help/doc/src/qthelp-module.qdoc index fe9d886992..9cd8ab3327 100644 --- a/src/assistant/help/doc/src/qthelp-module.qdoc +++ b/src/assistant/help/doc/src/qthelp-module.qdoc @@ -29,6 +29,7 @@ \module QtHelp \title Qt Help C++ Classes \ingroup modules + \qtcmakepackage Help \qtvariable help \brief Provides classes for integrating online documentation in diff --git a/src/assistant/help/doc/src/qthelp.qdoc b/src/assistant/help/doc/src/qthelp.qdoc index 9b02c96126..8db90f0ea8 100644 --- a/src/assistant/help/doc/src/qthelp.qdoc +++ b/src/assistant/help/doc/src/qthelp.qdoc @@ -118,17 +118,16 @@ \li \l {Qt Help Collection Project} \li .qhcp \li An XML file that contains references to the compressed help - files that should be included in the help collection. In - addition, it may contain information for customizing Qt - Assistant. This file can be passed to the help generator for - creating a help collection file. + files that should be included in the help collection. This file + can be passed to the help generator for creating a help collection + file. \row \li Qt Help Collection \li .qhc \li The help collection file that QHelpEngine operates on. It can contain references to any number of compressed help files as - well as additional information, such as custom filters. + well as additional information. \endtable \section1 Generating Qt Help @@ -174,31 +173,13 @@ \c generate or \c register section, so any number of compressed help files can be generated and registered in one go. - \section1 Using Qt Help + \section1 Using QHelpEngine API - Accessing the help contents can be done in two ways: Using Qt - Assistant as documentation browser or using the QHelpEngine - API for embedding the help contents directly in an application. + QHelpEngine allows embedding the help contents directly in an + application. - \section2 Using Qt Assistant - - \QA operates on a collection file which can be specified - before startup. If no collection file is given, a default one - will be created and used. In either case, it is possible to - register any Qt compressed help file and access the help contents. - - When using Qt Assistant as the help browser for an application, it - should be possible to customize it to fit the application - better, so that it does not look like an independent, standalone - help browser. To achieve this, several additional properties can - be set in a Qt help collection file, to change for example the title - or application icon of Qt Assistant. For more information, see the - \l{Qt Assistant Manual}. - - \section2 Using QHelpEngine API - - Instead of showing the help in an external application like the - Qt Assistant, it is also possible to embed the online help in + Instead of showing the help in an external application such as a + web browser, it is also possible to embed the online help in the application. The contents can then be retrieved via the QHelpEngine class and can be displayed in nearly any form. Showing the help in a QTextBrowser is probably the most common way, but @@ -227,7 +208,7 @@ the table of contents, index keywords and help documents, it contains some extra information like a namespace to identify the help file. One help project stands for one documentation set, - for example the \l{Qt Assistant Manual}. + for example the \l{qmake Manual}. \section1 Qt Help Project File Format @@ -275,48 +256,14 @@ The virtual folder tag is mandatory and the folder name must not contain any slashes (/). - \target Custom Filters - \section2 Custom Filters - - The Qt help project file contains optional definitions of - custom filters. A custom filter contains a list of filter - attributes which will be used later to display only the documentation - set that has all those attributes assigned. So, when setting the - current filter in the QHelpEngine to \e {My Application 1.0} only - the documentation which has \e myapp and \e {1.0} set as filter - attributes will be shown. - - \snippet doc_src_qthelp.qdoc 9 - - You can define any number of custom filters in a help project file. - It is important to know that you do not have to specify the filter - attributes in the same project file. These attributes can be defined - in any help file, in a filter section. - \target Filter Section \section2 Filter Section - A filter section contains the actual documentation. One Qt help project - file may contain more than one filter sections. Every filter section - consists of four parts, the filter attributes section, the table of - contents, the keywords and the files list. In theory all parts are - optional but not specifying anything there will result in an empty - documentation set. - - \section3 Filter Attributes - - Every filter section should have filter attributes assigned to it, to - enable documentation filtering. If no filter attribute is defined, the - documentation will only be shown if no filtering occurs, meaning the - current custom filter in the QHelpEngine does not contain any filter - attributes. - - \snippet doc_src_qthelp.qdoc 10 - - In this case, the filter attributes \e myapp and \e {1.0} are assigned to - the filter section. This means that all contents specified in this section - will only be shown if the current custom filter has \e myapp or \e {1.0}, - or both, as filter attributes. + A filter section contains the actual documentation. A Qt help project + file may contain more than one filter section. Every filter section + consists of the table of contents, the keywords, and the files list. + In theory all parts are optional but not specifying anything there will + result in an empty documentation set. \section3 Table of Contents @@ -340,8 +287,8 @@ attribute \e name is used, the keyword specified there will appear in the visible index. That is, it will be accessible through the QHelpIndexModel class. If \e id is used, the keyword does not appear in the index and is - only accessible via \l QHelpEngineCore::linksForIdentifier(). \e name and - \e id can be specified at the same time. + only accessible via \l QHelpEngineCore::documentsForIdentifier(). \e name + and \e id can be specified at the same time. \section3 Files diff --git a/src/assistant/help/help.pro b/src/assistant/help/help.pro deleted file mode 100644 index cd7781ddef..0000000000 --- a/src/assistant/help/help.pro +++ /dev/null @@ -1,50 +0,0 @@ -TARGET = QtHelp - -QT = core-private gui widgets sql -QT_PRIVATE = network - -DEFINES += QHELP_LIB - -QMAKE_DOCS = $$PWD/doc/qthelp.qdocconf - -DEFINES -= QT_ASCII_CAST_WARNINGS - -RESOURCES += helpsystem.qrc -SOURCES += \ - qcompressedhelpinfo.cpp \ - qhelpenginecore.cpp \ - qhelpengine.cpp \ - qhelpfilterdata.cpp \ - qhelpfilterengine.cpp \ - qhelpdbreader.cpp \ - qhelpcontentwidget.cpp \ - qhelpindexwidget.cpp \ - qhelpcollectionhandler.cpp \ - qhelpsearchengine.cpp \ - qhelpsearchquerywidget.cpp \ - qhelpsearchresultwidget.cpp \ - qhelpsearchindexwriter_default.cpp \ - qhelpsearchindexreader_default.cpp \ - qhelpsearchindexreader.cpp \ - qhelp_global.cpp - -HEADERS += \ - qcompressedhelpinfo.h \ - qhelpenginecore.h \ - qhelpengine.h \ - qhelpengine_p.h \ - qhelpfilterdata.h \ - qhelpfilterengine.h \ - qhelp_global.h \ - qhelpdbreader_p.h \ - qhelpcontentwidget.h \ - qhelpindexwidget.h \ - qhelpcollectionhandler_p.h \ - qhelpsearchengine.h \ - qhelpsearchquerywidget.h \ - qhelpsearchresultwidget.h \ - qhelpsearchindexwriter_default_p.h \ - qhelpsearchindexreader_default_p.h \ - qhelpsearchindexreader_p.h - -load(qt_module) diff --git a/src/assistant/help/helpsystem.qrc b/src/assistant/help/helpsystem.qrc index 785923aad0..611008639a 100644 --- a/src/assistant/help/helpsystem.qrc +++ b/src/assistant/help/helpsystem.qrc @@ -4,5 +4,9 @@ images/1rightarrow.png images/3leftarrow.png images/3rightarrow.png + images/mac/minus.png + images/mac/plus.png + images/win/minus.png + images/win/plus.png diff --git a/src/assistant/assistant/images/mac/minus.png b/src/assistant/help/images/mac/minus.png similarity index 100% rename from src/assistant/assistant/images/mac/minus.png rename to src/assistant/help/images/mac/minus.png diff --git a/src/assistant/assistant/images/mac/plus.png b/src/assistant/help/images/mac/plus.png similarity index 100% rename from src/assistant/assistant/images/mac/plus.png rename to src/assistant/help/images/mac/plus.png diff --git a/src/assistant/assistant/images/win/minus.png b/src/assistant/help/images/win/minus.png similarity index 100% rename from src/assistant/assistant/images/win/minus.png rename to src/assistant/help/images/win/minus.png diff --git a/src/assistant/assistant/images/win/plus.png b/src/assistant/help/images/win/plus.png similarity index 100% rename from src/assistant/assistant/images/win/plus.png rename to src/assistant/help/images/win/plus.png diff --git a/src/assistant/help/qcompressedhelpinfo.cpp b/src/assistant/help/qcompressedhelpinfo.cpp index bbdc641574..a3c5b75d5e 100644 --- a/src/assistant/help/qcompressedhelpinfo.cpp +++ b/src/assistant/help/qcompressedhelpinfo.cpp @@ -55,12 +55,14 @@ class QCompressedHelpInfoPrivate : public QSharedData , m_namespaceName(other.m_namespaceName) , m_component(other.m_component) , m_version(other.m_version) + , m_isNull(other.m_isNull) { } ~QCompressedHelpInfoPrivate() = default; QString m_namespaceName; QString m_component; QVersionNumber m_version; + bool m_isNull = true; }; /*! @@ -150,6 +152,15 @@ QVersionNumber QCompressedHelpInfo::version() const return d->m_version; } +/*! + Returns \c true if the info is invalid, otherwise returns + \c false. +*/ +bool QCompressedHelpInfo::isNull() const +{ + return d->m_isNull; +} + /*! Returns the QCompressedHelpInfo instance for the \a documentationFileName of the existing qch file. @@ -164,6 +175,7 @@ QCompressedHelpInfo QCompressedHelpInfo::fromCompressedHelpFile(const QString &d info.d->m_namespaceName = reader.namespaceName(); info.d->m_component = reader.virtualFolder(); info.d->m_version = QVersionNumber::fromString(reader.version()); + info.d->m_isNull = false; return info; } return QCompressedHelpInfo(); diff --git a/src/assistant/help/qcompressedhelpinfo.h b/src/assistant/help/qcompressedhelpinfo.h index c392bb74cd..7b3c78c12b 100644 --- a/src/assistant/help/qcompressedhelpinfo.h +++ b/src/assistant/help/qcompressedhelpinfo.h @@ -66,6 +66,7 @@ class QHELP_EXPORT QCompressedHelpInfo final QString namespaceName() const; QString component() const; QVersionNumber version() const; + bool isNull() const; static QCompressedHelpInfo fromCompressedHelpFile(const QString &documentationFileName); diff --git a/src/assistant/assistant/filternamedialog.cpp b/src/assistant/help/qfilternamedialog.cpp similarity index 85% rename from src/assistant/assistant/filternamedialog.cpp rename to src/assistant/help/qfilternamedialog.cpp index 4c17d33328..8563a33554 100644 --- a/src/assistant/assistant/filternamedialog.cpp +++ b/src/assistant/help/qfilternamedialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Assistant of the Qt Toolkit. @@ -28,11 +28,11 @@ #include -#include "filternamedialog.h" +#include "qfilternamedialog_p.h" QT_BEGIN_NAMESPACE -FilterNameDialog::FilterNameDialog(QWidget *parent) +QFilterNameDialog::QFilterNameDialog(QWidget *parent) : QDialog(parent) { m_ui.setupUi(this); @@ -41,22 +41,22 @@ FilterNameDialog::FilterNameDialog(QWidget *parent) connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), &QAbstractButton::clicked, this, &QDialog::reject); connect(m_ui.lineEdit, &QLineEdit::textChanged, - this, &FilterNameDialog::updateOkButton); + this, &QFilterNameDialog::updateOkButton); m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); } -void FilterNameDialog::setFilterName(const QString &filter) +void QFilterNameDialog::setFilterName(const QString &filter) { m_ui.lineEdit->setText(filter); m_ui.lineEdit->selectAll(); } -QString FilterNameDialog::filterName() const +QString QFilterNameDialog::filterName() const { return m_ui.lineEdit->text(); } -void FilterNameDialog::updateOkButton() +void QFilterNameDialog::updateOkButton() { m_ui.buttonBox->button(QDialogButtonBox::Ok) ->setDisabled(m_ui.lineEdit->text().isEmpty()); diff --git a/src/assistant/assistant/filternamedialog.ui b/src/assistant/help/qfilternamedialog.ui similarity index 100% rename from src/assistant/assistant/filternamedialog.ui rename to src/assistant/help/qfilternamedialog.ui diff --git a/src/assistant/assistant/filternamedialog.h b/src/assistant/help/qfilternamedialog_p.h similarity index 74% rename from src/assistant/assistant/filternamedialog.h rename to src/assistant/help/qfilternamedialog_p.h index 522b611afc..76a495d78f 100644 --- a/src/assistant/assistant/filternamedialog.h +++ b/src/assistant/help/qfilternamedialog_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Assistant of the Qt Toolkit. @@ -26,20 +26,31 @@ ** ****************************************************************************/ -#ifndef FILTERNAMEDIALOG_H -#define FILTERNAMEDIALOG_H +#ifndef QFILTERNAMEDIALOG_H +#define QFILTERNAMEDIALOG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// #include -#include "ui_filternamedialog.h" +#include "ui_qfilternamedialog.h" QT_BEGIN_NAMESPACE -class FilterNameDialog : public QDialog +class QFilterNameDialog : public QDialog { Q_OBJECT public: - FilterNameDialog(QWidget *parent = nullptr); + QFilterNameDialog(QWidget *parent = nullptr); void setFilterName(const QString &filter); QString filterName() const; @@ -53,4 +64,4 @@ private slots: QT_END_NAMESPACE -#endif // FILTERNAMEDIALOG_H +#endif // QFILTERNAMEDIALOG_H diff --git a/src/assistant/help/qhelp_global.cpp b/src/assistant/help/qhelp_global.cpp index 6316aa4942..d86ce767b0 100644 --- a/src/assistant/help/qhelp_global.cpp +++ b/src/assistant/help/qhelp_global.cpp @@ -38,7 +38,7 @@ ****************************************************************************/ #include -#include +#include #include #include @@ -72,39 +72,3 @@ QString QHelpGlobal::documentTitle(const QString &content) } return title; } - -QString QHelpGlobal::codecFromData(const QByteArray &data) -{ - QString codec = codecFromXmlData(data); - if (codec.isEmpty()) - codec = codecFromHtmlData(data); - return codec.isEmpty() ? QLatin1String("utf-8") : codec; -} - -QString QHelpGlobal::codecFromHtmlData(const QByteArray &data) -{ - const QString &head = QString::fromUtf8(data.constData(), qMin(1000, data.size())); - int start = head.indexOf(QLatin1String(" 0) { - const QRegExp r(QLatin1String("charset=([^\"\\s]+)")); - while (start != -1) { - const int end = head.indexOf(QLatin1Char('>'), start) + 1; - if (end <= start) - break; - const QString &meta = head.mid(start, end - start).toLower(); - if (r.indexIn(meta) != -1) - return r.cap(1); - start = head.indexOf(QLatin1String(".*")); - return encodingExp.exactMatch(head) ? encodingExp.cap(1) : QString(); -} diff --git a/src/assistant/help/qhelp_global.h b/src/assistant/help/qhelp_global.h index 49828c8d76..c0354083db 100644 --- a/src/assistant/help/qhelp_global.h +++ b/src/assistant/help/qhelp_global.h @@ -59,11 +59,6 @@ class QHELP_EXPORT QHelpGlobal { public: static QString uniquifyConnectionName(const QString &name, void *pointer); static QString documentTitle(const QString &content); - static QString codecFromData(const QByteArray &data); - -private: - static QString codecFromHtmlData(const QByteArray &data); - static QString codecFromXmlData(const QByteArray &data); }; QT_END_NAMESPACE diff --git a/src/assistant/help/qhelpcollectionhandler.cpp b/src/assistant/help/qhelpcollectionhandler.cpp index a7bea5494a..595cc0e295 100644 --- a/src/assistant/help/qhelpcollectionhandler.cpp +++ b/src/assistant/help/qhelpcollectionhandler.cpp @@ -47,10 +47,12 @@ #include #include #include +#include #include -#include #include +#include + #include #include @@ -235,7 +237,7 @@ bool QHelpCollectionHandler::openCollectionFile() timeStamps.append(timeStamp); } - QVector toRemove; + QList toRemove; for (const TimeStamp &timeStamp : timeStamps) { if (!isTimeStampCorrect(timeStamp)) toRemove.append(timeStamp); @@ -379,6 +381,7 @@ bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) if (!createTables(copyQuery) || !recreateIndexAndNamespaceFilterTables(copyQuery)) { emit error(tr("Cannot copy collection file: %1").arg(colFile)); + delete copyQuery; return false; } @@ -588,13 +591,13 @@ QStringList QHelpCollectionHandler::availableComponents() const return list; } -QStringList QHelpCollectionHandler::availableVersions() const +QList QHelpCollectionHandler::availableVersions() const { - QStringList list; + QList list; if (m_query) { m_query->exec(QLatin1String("SELECT DISTINCT Version FROM VersionTable ORDER BY Version")); while (m_query->next()) - list.append(m_query->value(0).toString()); + list.append(QVersionNumber::fromString(m_query->value(0).toString())); } return list; } @@ -1177,7 +1180,7 @@ QString QHelpCollectionHandler::namespaceForFile(const QUrl &url, if (!m_query->exec()) return QString(); - QVector namespaceList; + QList namespaceList; while (m_query->next()) namespaceList.append(m_query->value(0).toString()); @@ -1232,7 +1235,7 @@ QString QHelpCollectionHandler::namespaceForFile(const QUrl &url, if (!m_query->exec()) return QString(); - QVector namespaceList; + QList namespaceList; while (m_query->next()) namespaceList.append(m_query->value(0).toString()); @@ -2194,7 +2197,15 @@ bool QHelpCollectionHandler::registerIndexTable(const QHelpDBReader::IndexTable m_query->addBindValue(fileName); const QFileInfo fi(absoluteDocPath(fileName)); m_query->addBindValue(fi.size()); - m_query->addBindValue(fi.lastModified().toString(Qt::ISODate)); + QDateTime lastModified = fi.lastModified(); + if (qEnvironmentVariableIsSet("SOURCE_DATE_EPOCH")) { + const QString sourceDateEpochStr = qEnvironmentVariable("SOURCE_DATE_EPOCH"); + bool ok; + const qlonglong sourceDateEpoch = sourceDateEpochStr.toLongLong(&ok); + if (ok && sourceDateEpoch < lastModified.toSecsSinceEpoch()) + lastModified.setSecsSinceEpoch(sourceDateEpoch); + } + m_query->addBindValue(lastModified.toString(Qt::ISODate)); if (!m_query->exec()) return false; @@ -2298,26 +2309,56 @@ static QUrl buildQUrl(const QString &ns, const QString &folder, return url; } -QMap QHelpCollectionHandler::linksForIdentifier(const QString &id, - const QStringList &filterAttributes) const +QMultiMap QHelpCollectionHandler::linksForIdentifier( + const QString &id, + const QStringList &filterAttributes) const { return linksForField(QLatin1String("Identifier"), id, filterAttributes); } -QMap QHelpCollectionHandler::linksForKeyword(const QString &keyword, - const QStringList &filterAttributes) const +QMultiMap QHelpCollectionHandler::linksForKeyword( + const QString &keyword, + const QStringList &filterAttributes) const { return linksForField(QLatin1String("Name"), keyword, filterAttributes); } -QMap QHelpCollectionHandler::linksForField(const QString &fieldName, - const QString &fieldValue, - const QStringList &filterAttributes) const +QList QHelpCollectionHandler::documentsForIdentifier( + const QString &id, + const QStringList &filterAttributes) const +{ + return documentsForField(QLatin1String("Identifier"), id, filterAttributes); +} + +QList QHelpCollectionHandler::documentsForKeyword( + const QString &keyword, + const QStringList &filterAttributes) const +{ + return documentsForField(QLatin1String("Name"), keyword, filterAttributes); +} + +QMultiMap QHelpCollectionHandler::linksForField( + const QString &fieldName, + const QString &fieldValue, + const QStringList &filterAttributes) const { - QMap linkMap; + QMultiMap linkMap; + const auto documents = documentsForField(fieldName, fieldValue, filterAttributes); + for (const auto &document : documents) + linkMap.insert(document.title, document.url); + + return linkMap; +} + +QList QHelpCollectionHandler::documentsForField( + const QString &fieldName, + const QString &fieldValue, + const QStringList &filterAttributes) const +{ + QList docList; if (!isDBOpened()) - return linkMap; + return docList; const QString filterlessQuery = QString::fromLatin1( "SELECT " @@ -2354,34 +2395,65 @@ QMap QHelpCollectionHandler::linksForField(const QString &fieldNa if (title.isEmpty()) // generate a title + corresponding path title = fieldValue + QLatin1String(" : ") + m_query->value(3).toString(); - linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(), - m_query->value(2).toString(), - m_query->value(3).toString(), - m_query->value(4).toString())); + const QUrl url = buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), + m_query->value(3).toString(), + m_query->value(4).toString()); + docList.append(QHelpLink {url, title}); } - return linkMap; + return docList; } -QMap QHelpCollectionHandler::linksForIdentifier(const QString &id, - const QString &filterName) const +QMultiMap QHelpCollectionHandler::linksForIdentifier( + const QString &id, + const QString &filterName) const { return linksForField(QLatin1String("Identifier"), id, filterName); } -QMap QHelpCollectionHandler::linksForKeyword(const QString &keyword, - const QString &filterName) const +QMultiMap QHelpCollectionHandler::linksForKeyword( + const QString &keyword, + const QString &filterName) const { return linksForField(QLatin1String("Name"), keyword, filterName); } -QMap QHelpCollectionHandler::linksForField(const QString &fieldName, - const QString &fieldValue, - const QString &filterName) const +QList QHelpCollectionHandler::documentsForIdentifier( + const QString &id, + const QString &filterName) const +{ + return documentsForField(QLatin1String("Identifier"), id, filterName); +} + +QList QHelpCollectionHandler::documentsForKeyword( + const QString &keyword, + const QString &filterName) const +{ + return documentsForField(QLatin1String("Name"), keyword, filterName); +} + +QMultiMap QHelpCollectionHandler::linksForField( + const QString &fieldName, + const QString &fieldValue, + const QString &filterName) const { - QMap linkMap; + QMultiMap linkMap; + const auto documents = documentsForField(fieldName, fieldValue, filterName); + for (const auto &document : documents) + linkMap.insert(document.title, document.url); + + return linkMap; +} + +QList QHelpCollectionHandler::documentsForField( + const QString &fieldName, + const QString &fieldValue, + const QString &filterName) const +{ + QList docList; if (!isDBOpened()) - return linkMap; + return docList; const QString filterlessQuery = QString::fromLatin1( "SELECT " @@ -2401,7 +2473,8 @@ QMap QHelpCollectionHandler::linksForField(const QString &fieldNa "AND IndexTable.%1 = ?").arg(fieldName); const QString filterQuery = filterlessQuery - + prepareFilterQuery(filterName); + + prepareFilterQuery(filterName) + + QLatin1String(" ORDER BY LOWER(FileNameTable.Title), FileNameTable.Title"); m_query->prepare(filterQuery); m_query->bindValue(0, fieldValue); @@ -2414,12 +2487,13 @@ QMap QHelpCollectionHandler::linksForField(const QString &fieldNa if (title.isEmpty()) // generate a title + corresponding path title = fieldValue + QLatin1String(" : ") + m_query->value(3).toString(); - linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(), - m_query->value(2).toString(), - m_query->value(3).toString(), - m_query->value(4).toString())); + const QUrl url = buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), + m_query->value(3).toString(), + m_query->value(4).toString()); + docList.append(QHelpLink {url, title}); } - return linkMap; + return docList; } QStringList QHelpCollectionHandler::namespacesForFilter(const QString &filterName) const diff --git a/src/assistant/help/qhelpcollectionhandler_p.h b/src/assistant/help/qhelpcollectionhandler_p.h index 7679fccf7a..fb26aabb5f 100644 --- a/src/assistant/help/qhelpcollectionhandler_p.h +++ b/src/assistant/help/qhelpcollectionhandler_p.h @@ -60,6 +60,7 @@ #include #include "qhelpdbreader_p.h" +#include "qhelplink.h" QT_BEGIN_NAMESPACE @@ -146,19 +147,25 @@ class QHelpCollectionHandler : public QObject QList filterAttributeSets(const QString &namespaceName) const; // use linksForIdentifier(const QString &, const QString &) instead - QMap linksForIdentifier(const QString &id, - const QStringList &filterAttributes) const; + QMultiMap linksForIdentifier(const QString &id, + const QStringList &filterAttributes) const; // use linksForKeyword(const QString &, const QString &) instead - QMap linksForKeyword(const QString &keyword, - const QStringList &filterAttributes) const; + QMultiMap linksForKeyword(const QString &keyword, + const QStringList &filterAttributes) const; + + // use documentsForIdentifier instead + QMultiMap linksForIdentifier(const QString &id, const QString &filterName) const; + // use documentsForKeyword instead + QMultiMap linksForKeyword(const QString &keyword, + const QString &filterName) const; // *** Legacy block end *** QStringList filters() const; QStringList availableComponents() const; - QStringList availableVersions() const; + QList availableVersions() const; QMap namespaceToComponent() const; QMap namespaceToVersion() const; QHelpFilterData filterData(const QString &filterName) const; @@ -196,10 +203,15 @@ class QHelpCollectionHandler : public QObject int registerComponent(const QString &componentName, int namespaceId); bool registerVersion(const QString &version, int namespaceId); - QMap linksForIdentifier(const QString &id, - const QString &filterName) const; - QMap linksForKeyword(const QString &keyword, - const QString &filterName) const; + QList documentsForIdentifier(const QString &id, + const QString &filterName) const; + QList documentsForKeyword(const QString &keyword, + const QString &filterName) const; + QList documentsForIdentifier(const QString &id, + const QStringList &filterAttributes) const; + QList documentsForKeyword(const QString &keyword, + const QStringList &filterAttributes) const; + QStringList namespacesForFilter(const QString &filterName) const; void setReadOnly(bool readOnly); @@ -209,14 +221,20 @@ class QHelpCollectionHandler : public QObject private: // legacy stuff - QMap linksForField(const QString &fieldName, - const QString &fieldValue, - const QStringList &filterAttributes) const; + QMultiMap linksForField(const QString &fieldName, + const QString &fieldValue, + const QStringList &filterAttributes) const; + QList documentsForField(const QString &fieldName, + const QString &fieldValue, + const QStringList &filterAttributes) const; QString namespaceVersion(const QString &namespaceName) const; - QMap linksForField(const QString &fieldName, - const QString &fieldValue, - const QString &filterName) const; + QMultiMap linksForField(const QString &fieldName, const QString &fieldValue, + const QString &filterName) const; + QList documentsForField(const QString &fieldName, + const QString &fieldValue, + const QString &filterName) const; + bool isDBOpened() const; bool createTables(QSqlQuery *query); void closeDB(); @@ -239,7 +257,7 @@ class QHelpCollectionHandler : public QObject QString m_connectionName; QSqlQuery *m_query = nullptr; bool m_vacuumScheduled = false; - bool m_readOnly = false; + bool m_readOnly = true; }; QT_END_NAMESPACE diff --git a/src/assistant/help/qhelpdbreader.cpp b/src/assistant/help/qhelpdbreader.cpp index faf8be4655..2d99a2a3c1 100644 --- a/src/assistant/help/qhelpdbreader.cpp +++ b/src/assistant/help/qhelpdbreader.cpp @@ -40,9 +40,9 @@ #include "qhelpdbreader_p.h" #include "qhelp_global.h" -#include -#include #include +#include +#include #include #include @@ -222,7 +222,7 @@ QHelpDBReader::IndexTable QHelpDBReader::indexTable() const // Maybe some are unused and specified erroneously in the named filter only, // like it was in case of qtlocation.qch <= qt 5.9 - QVector usedAttributeIds; + QList usedAttributeIds; for (auto it = attributeIds.cbegin(), end = attributeIds.cend(); it != end; ++it) { const int attributeId = it.key(); if (isAttributeUsed(m_query, QLatin1String("IndexFilterTable"), attributeId) @@ -481,11 +481,10 @@ QStringList QHelpDBReader::filterAttributes(const QString &filterName) const return lst; } -QMap QHelpDBReader::filesData( - const QStringList &filterAttributes, - const QString &extensionFilter) const +QMultiMap QHelpDBReader::filesData(const QStringList &filterAttributes, + const QString &extensionFilter) const { - QMap result; + QMultiMap result; if (!m_query) return result; diff --git a/src/assistant/help/qhelpdbreader_p.h b/src/assistant/help/qhelpdbreader_p.h index 6268daeef7..9abc3c06f9 100644 --- a/src/assistant/help/qhelpdbreader_p.h +++ b/src/assistant/help/qhelpdbreader_p.h @@ -115,8 +115,8 @@ class QHelpDBReader : public QObject QString version() const; IndexTable indexTable() const; QList filterAttributeSets() const; - QMap filesData(const QStringList &filterAttributes, - const QString &extensionFilter = QString()) const; + QMultiMap filesData(const QStringList &filterAttributes, + const QString &extensionFilter = QString()) const; QByteArray fileData(const QString &virtualFolder, const QString &filePath) const; diff --git a/src/assistant/help/qhelpengine.cpp b/src/assistant/help/qhelpengine.cpp index 19e44cd915..bb1475fdfb 100644 --- a/src/assistant/help/qhelpengine.cpp +++ b/src/assistant/help/qhelpengine.cpp @@ -97,28 +97,28 @@ void QHelpEnginePrivate::applyCurrentFilter() void QHelpEnginePrivate::setContentsWidgetBusy() { -#ifndef QT_NO_CURSOR +#if QT_CONFIG(cursor) contentWidget->setCursor(Qt::WaitCursor); #endif } void QHelpEnginePrivate::unsetContentsWidgetBusy() { -#ifndef QT_NO_CURSOR +#if QT_CONFIG(cursor) contentWidget->unsetCursor(); #endif } void QHelpEnginePrivate::setIndexWidgetBusy() { -#ifndef QT_NO_CURSOR +#if QT_CONFIG(cursor) indexWidget->setCursor(Qt::WaitCursor); #endif } void QHelpEnginePrivate::unsetIndexWidgetBusy() { -#ifndef QT_NO_CURSOR +#if QT_CONFIG(cursor) indexWidget->unsetCursor(); #endif } diff --git a/src/assistant/help/qhelpengine_p.h b/src/assistant/help/qhelpengine_p.h index 558013e777..76bdbb4219 100644 --- a/src/assistant/help/qhelpengine_p.h +++ b/src/assistant/help/qhelpengine_p.h @@ -89,6 +89,7 @@ class QHelpEngineCorePrivate : public QObject bool needsSetup = true; bool autoSaveFilter = true; bool usesFilterEngine = false; + bool readOnly = true; protected: QHelpEngineCore *q; @@ -97,7 +98,6 @@ private slots: void errorReceived(const QString &msg); }; - class QHelpEnginePrivate : public QHelpEngineCorePrivate { Q_OBJECT diff --git a/src/assistant/help/qhelpenginecore.cpp b/src/assistant/help/qhelpenginecore.cpp index f61c2207d2..b5e1b9b9fa 100644 --- a/src/assistant/help/qhelpenginecore.cpp +++ b/src/assistant/help/qhelpenginecore.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -80,7 +81,7 @@ bool QHelpEngineCorePrivate::setup() const QVariant readOnlyVariant = q->property("_q_readonly"); const bool readOnly = readOnlyVariant.isValid() - ? readOnlyVariant.toBool() : false; + ? readOnlyVariant.toBool() : q->isReadOnly(); collectionHandler->setReadOnly(readOnly); const bool opened = collectionHandler->openCollectionFile(); if (opened) @@ -110,36 +111,39 @@ void QHelpEngineCorePrivate::errorReceived(const QString &msg) undefined meaning unusable state. The core help engine can be used to perform different tasks. - By calling linksForIdentifier() the engine returns + By calling documentsForIdentifier() the engine returns URLs specifying the file locations inside the help system. The - actual file data can then be retrived by calling fileData(). In - contrast to all other functions in this class, linksForIdentifier() - depends on the currently set custom filter. Depending on the filter, - the function may return different results. + actual file data can then be retrived by calling fileData(). The help engine can contain any number of custom filters. The management of the filters, including adding new filters, changing filter definitions, or removing existing filters, is done through the QHelpFilterEngine class, which can be accessed - by the filterEngine() method. This replaces older filter API that is - deprecated since Qt 5.13. Please call setUsesFilterEngine() with - \c true to enable the new functionality. - + by the filterEngine() method. + + \note QHelpFilterEngine replaces the older filter API that is + deprecated since Qt 5.13. Call setUsesFilterEngine() with \c true to + enable the new functionality. + + The core help engine has two modes: + \list + \li Read-only mode, where the help collection file is not changed + unless explicitly requested. This also works if the + collection file is in a read-only location, + and is the default. + \li Fully writable mode, which requires the help collection + file to be writable. + \endlist + The mode can be changed by calling setReadOnly() method, prior to + calling setupData(). The help engine also offers the possibility to set and read values - in a persistant way comparable to ini files or Windows registry + in a persistent way comparable to ini files or Windows registry entries. For more information see setValue() or value(). This class does not offer any GUI components or functionality for indices or contents. If you need one of those use QHelpEngine instead. - - When creating a custom help viewer the viewer can be - configured by writing a custom collection file which could contain various - keywords to be used to configure the help engine. These keywords and values - and their meaning can be found in the help information for - \l{assistant-custom-help-viewer.html#creating-a-custom-help-collection-file} - {creating a custom help collection file} for Assistant. */ /*! @@ -235,6 +239,31 @@ void QHelpEngineCore::setCollectionFile(const QString &fileName) d->needsSetup = true; } +/*! + \property QHelpEngineCore::readOnly + \brief whether the help engine is read-only. + \since 6.0 + + In read-only mode, the user can use the help engine + with a collection file installed in a read-only location. + In this case, some functionality won't be accessible, + like registering additional documentation, filter editing, + or any action that would require changes to the + collection file. Setting it to \c false enables the full + functionality of the help engine. + + By default, this property is \c true. +*/ +bool QHelpEngineCore::isReadOnly() const +{ + return d->readOnly; +} + +void QHelpEngineCore::setReadOnly(bool enable) +{ + d->readOnly = enable; +} + /*! \since 5.13 @@ -613,38 +642,69 @@ QByteArray QHelpEngineCore::fileData(const QUrl &url) const } /*! - Returns a map of the documents found for the \a id. The map contains the - document titles and their URLs. The returned map contents depend on - the current filter, and therefore only the identifiers registered for - the current filter will be returned. + \since 5.15 + + Returns a list of all the document links found for the \a id. + The returned list contents depend on the current filter, and therefore only the keywords + registered for the current filter will be returned. +*/ +QList QHelpEngineCore::documentsForIdentifier(const QString &id) const +{ + return documentsForIdentifier(id, d->usesFilterEngine + ? d->filterEngine->activeFilter() + : d->currentFilter); +} + +/*! + \since 5.15 + + Returns a list of the document links found for the \a id, filtered by \a filterName. + The returned list contents depend on the passed filter, and therefore only the keywords + registered for this filter will be returned. If you want to get all results unfiltered, + pass empty string as \a filterName. */ -QMap QHelpEngineCore::linksForIdentifier(const QString &id) const +QList QHelpEngineCore::documentsForIdentifier(const QString &id, const QString &filterName) const { if (!d->setup()) - return QMap(); + return QList(); if (d->usesFilterEngine) - return d->collectionHandler->linksForIdentifier(id, d->filterEngine->activeFilter()); + return d->collectionHandler->documentsForIdentifier(id, filterName); - // obsolete - return d->collectionHandler->linksForIdentifier(id, filterAttributes(d->currentFilter)); + return d->collectionHandler->documentsForIdentifier(id, filterAttributes(filterName)); } /*! - Returns a map of all the documents found for the \a keyword. The map - contains the document titles and URLs. The returned map contents depend - on the current filter, and therefore only the keywords registered for - the current filter will be returned. + \since 5.15 + + Returns a list of all the document links found for the \a keyword. + The returned list contents depend on the current filter, and therefore only the keywords + registered for the current filter will be returned. +*/ +QList QHelpEngineCore::documentsForKeyword(const QString &keyword) const +{ + return documentsForKeyword(keyword, d->usesFilterEngine + ? d->filterEngine->activeFilter() + : d->currentFilter); +} + +/*! + \since 5.15 + + Returns a list of the document links found for the \a keyword, filtered by \a filterName. + The returned list contents depend on the passed filter, and therefore only the keywords + registered for this filter will be returned. If you want to get all results unfiltered, + pass empty string as \a filterName. */ -QMap QHelpEngineCore::linksForKeyword(const QString &keyword) const +QList QHelpEngineCore::documentsForKeyword(const QString &keyword, const QString &filterName) const { if (!d->setup()) - return QMap(); + return QList(); if (d->usesFilterEngine) - return d->collectionHandler->linksForKeyword(keyword, d->filterEngine->activeFilter()); + return d->collectionHandler->documentsForKeyword(keyword, filterName); - return d->collectionHandler->linksForKeyword(keyword, filterAttributes(d->currentFilter)); + return d->collectionHandler->documentsForKeyword(keyword, filterAttributes(filterName)); } /*! diff --git a/src/assistant/help/qhelpenginecore.h b/src/assistant/help/qhelpenginecore.h index 91950290e6..dc4cd76958 100644 --- a/src/assistant/help/qhelpenginecore.h +++ b/src/assistant/help/qhelpenginecore.h @@ -51,18 +51,25 @@ QT_BEGIN_NAMESPACE class QHelpEngineCorePrivate; class QHelpFilterEngine; +struct QHelpLink; class QHELP_EXPORT QHelpEngineCore : public QObject { Q_OBJECT Q_PROPERTY(bool autoSaveFilter READ autoSaveFilter WRITE setAutoSaveFilter) Q_PROPERTY(QString collectionFile READ collectionFile WRITE setCollectionFile) + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) +#if QT_DEPRECATED_SINCE(5, 15) Q_PROPERTY(QString currentFilter READ currentFilter WRITE setCurrentFilter) +#endif public: explicit QHelpEngineCore(const QString &collectionFile, QObject *parent = nullptr); virtual ~QHelpEngineCore(); + bool isReadOnly() const; + void setReadOnly(bool enable); + QHelpFilterEngine *filterEngine() const; bool setupData(); @@ -102,8 +109,10 @@ class QHELP_EXPORT QHelpEngineCore : public QObject const QString &extensionFilter = QString()); QUrl findFile(const QUrl &url) const; - QMap linksForIdentifier(const QString &id) const; - QMap linksForKeyword(const QString &keyword) const; + QList documentsForIdentifier(const QString &id) const; + QList documentsForIdentifier(const QString &id, const QString &filterName) const; + QList documentsForKeyword(const QString &keyword) const; + QList documentsForKeyword(const QString &keyword, const QString &filterName) const; bool removeCustomValue(const QString &key); QVariant customValue(const QString &key, diff --git a/src/assistant/help/qhelpfilterdata.cpp b/src/assistant/help/qhelpfilterdata.cpp index 37b209541a..b90aeb6c8c 100644 --- a/src/assistant/help/qhelpfilterdata.cpp +++ b/src/assistant/help/qhelpfilterdata.cpp @@ -107,7 +107,7 @@ QHelpFilterData &QHelpFilterData::operator=(const QHelpFilterData &) = default; QHelpFilterData &QHelpFilterData::operator=(QHelpFilterData &&) = default; /*! - \fn void QHelpFilterData::swap(QCompressedHelpInfo &other) + \fn void QHelpFilterData::swap(QHelpFilterData &other) Swaps the filter \a other with this filter. This operation is very fast and never fails. diff --git a/src/assistant/help/qhelpfilterengine.cpp b/src/assistant/help/qhelpfilterengine.cpp index a53be506e0..b465d6c91e 100644 --- a/src/assistant/help/qhelpfilterengine.cpp +++ b/src/assistant/help/qhelpfilterengine.cpp @@ -70,11 +70,16 @@ bool QHelpFilterEnginePrivate::setup() if (!m_needsSetup) return true; - if (!m_helpEngine->setupData()) - return false; - + // Prevent endless loop when connected to setupFinished() signal + // and using from there QHelpFilterEngine, causing setup() to be + // called in turn. m_needsSetup = false; + if (!m_helpEngine->setupData()) { + m_needsSetup = true; + return false; + } + const QString filter = m_collectionHandler->customValue( QLatin1String(ActiveFilter), QString()).toString(); if (!filter.isEmpty() && m_collectionHandler->filters().contains(filter)) @@ -203,6 +208,19 @@ QStringList QHelpFilterEngine::availableComponents() const return d->m_collectionHandler->availableComponents(); } +/*! + \since 5.15 + + Returns the list of all available versions defined in all + registered documentation files. +*/ +QList QHelpFilterEngine::availableVersions() const +{ + if (!d->setup()) + return QList(); + return d->m_collectionHandler->availableVersions(); +} + /*! Returns the filter details associated with \a filterName. */ @@ -287,4 +305,32 @@ QStringList QHelpFilterEngine::namespacesForFilter(const QString &filterName) co return d->m_collectionHandler->namespacesForFilter(filterName); } +/*! + \since 5.15 + + Returns a sorted list of available indices. + The returned list contents depend on the active filter, and therefore only + the indices registered for the active filter will be returned. +*/ +QStringList QHelpFilterEngine::indices() const +{ + return indices(activeFilter()); +} + +/*! + \since 5.15 + + Returns a sorted list of available indices, filtered by \a filterName. + The returned list contents depend on the passed filter, and therefore only + the indices registered for this filter will be returned. + If you want to get all available indices unfiltered, + pass empty string as \a filterName. +*/ +QStringList QHelpFilterEngine::indices(const QString &filterName) const +{ + if (!d->setup()) + return QStringList(); + return d->m_collectionHandler->indicesForFilter(filterName); +} + QT_END_NAMESPACE diff --git a/src/assistant/help/qhelpfilterengine.h b/src/assistant/help/qhelpfilterengine.h index c4bd139f25..d06d18b045 100644 --- a/src/assistant/help/qhelpfilterengine.h +++ b/src/assistant/help/qhelpfilterengine.h @@ -68,6 +68,7 @@ class QHELP_EXPORT QHelpFilterEngine : public QObject bool setActiveFilter(const QString &filterName); QStringList availableComponents() const; + QList availableVersions() const; QHelpFilterData filterData(const QString &filterName) const; bool setFilterData(const QString &filterName, const QHelpFilterData &filterData); @@ -76,6 +77,9 @@ class QHELP_EXPORT QHelpFilterEngine : public QObject QStringList namespacesForFilter(const QString &filterName) const; + QStringList indices() const; + QStringList indices(const QString &filterName) const; + Q_SIGNALS: void filterActivated(const QString &newFilter); diff --git a/src/assistant/help/qhelpfiltersettings.cpp b/src/assistant/help/qhelpfiltersettings.cpp new file mode 100644 index 0000000000..206692179d --- /dev/null +++ b/src/assistant/help/qhelpfiltersettings.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpfiltersettings_p.h" +#include "qhelpfilterdata.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpFilterSettingsPrivate : public QSharedData +{ +public: + QHelpFilterSettingsPrivate() = default; + QHelpFilterSettingsPrivate(const QHelpFilterSettingsPrivate &other) = default; + ~QHelpFilterSettingsPrivate() = default; + + QMap m_filterToData; + QString m_currentFilter; +}; + +QHelpFilterSettings::QHelpFilterSettings() + : d(new QHelpFilterSettingsPrivate) +{ +} + +QHelpFilterSettings::QHelpFilterSettings(const QHelpFilterSettings &) = default; + +QHelpFilterSettings::QHelpFilterSettings(QHelpFilterSettings &&) = default; + +QHelpFilterSettings::~QHelpFilterSettings() = default; + +QHelpFilterSettings &QHelpFilterSettings::operator=(const QHelpFilterSettings &) = default; + +QHelpFilterSettings &QHelpFilterSettings::operator=(QHelpFilterSettings &&) = default; + +void QHelpFilterSettings::setFilter(const QString &filterName, + const QHelpFilterData &filterData) +{ + d->m_filterToData.insert(filterName, filterData); +} + +void QHelpFilterSettings::removeFilter(const QString &filterName) +{ + d->m_filterToData.remove(filterName); +} + +QStringList QHelpFilterSettings::filterNames() const +{ + return d->m_filterToData.keys(); +} + +QHelpFilterData QHelpFilterSettings::filterData(const QString &filterName) const +{ + return d->m_filterToData.value(filterName); +} + +QMap QHelpFilterSettings::filters() const +{ + return d->m_filterToData; +} + +void QHelpFilterSettings::setCurrentFilter(const QString &filterName) +{ + d->m_currentFilter = filterName; +} + +QString QHelpFilterSettings::currentFilter() const +{ + return d->m_currentFilter; +} + +QHelpFilterSettings QHelpFilterSettings::readSettings(const QHelpFilterEngine *filterEngine) +{ + QHelpFilterSettings filterSettings; + + const QStringList allFilters = filterEngine->filters(); + for (const QString &filter : allFilters) + filterSettings.setFilter(filter, filterEngine->filterData(filter)); + + filterSettings.setCurrentFilter(filterEngine->activeFilter()); + + return filterSettings; +} + +static QMap subtract(const QMap &minuend, + const QMap &subtrahend) +{ + QMap result = minuend; + + for (auto itSubtrahend = subtrahend.cbegin(); itSubtrahend != subtrahend.cend(); ++itSubtrahend) { + auto itResult = result.find(itSubtrahend.key()); + if (itResult != result.end() && itSubtrahend.value() == itResult.value()) + result.erase(itResult); + } + + return result; +} + +bool QHelpFilterSettings::applySettings(QHelpFilterEngine *filterEngine, + const QHelpFilterSettings &settings) +{ + bool changed = false; + const QHelpFilterSettings oldSettings = readSettings(filterEngine); + + const QMap filtersToRemove = subtract( + oldSettings.filters(), + settings.filters()); + const QMap filtersToAdd = subtract( + settings.filters(), + oldSettings.filters()); + + const QString ¤tFilter = filterEngine->activeFilter(); + + for (const QString &filter : filtersToRemove.keys()) { + filterEngine->removeFilter(filter); + if (currentFilter == filter && !filtersToAdd.contains(filter)) + filterEngine->setActiveFilter(QString()); + changed = true; + } + + for (auto it = filtersToAdd.cbegin(); it != filtersToAdd.cend(); ++it) { + filterEngine->setFilterData(it.key(), it.value()); + changed = true; + } + + if (changed) + filterEngine->setActiveFilter(settings.currentFilter()); + + return changed; +} + +QT_END_NAMESPACE diff --git a/src/winrtrunner/appxlocalengine.h b/src/assistant/help/qhelpfiltersettings_p.h similarity index 52% rename from src/winrtrunner/appxlocalengine.h rename to src/assistant/help/qhelpfiltersettings_p.h index 0049b6ba4e..cf5622b6d1 100644 --- a/src/winrtrunner/appxlocalengine.h +++ b/src/assistant/help/qhelpfiltersettings_p.h @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -37,52 +37,60 @@ ** ****************************************************************************/ -#ifndef APPXLOCALENGINE_H -#define APPXLOCALENGINE_H +#ifndef QHELPFILTERSETTINGS_H +#define QHELPFILTERSETTINGS_H -#include "appxengine.h" -#include "runner.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// -#include -#include +#include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE -class AppxLocalEnginePrivate; -class AppxLocalEngine : public AppxEngine +template +class QMap; +class QHelpFilterData; +class QHelpFilterEngine; +class QHelpFilterSettingsPrivate; + +class QHelpFilterSettings final { public: - static bool canHandle(Runner *runner); - static RunnerEngine *create(Runner *runner); - static QStringList deviceNames(); + QHelpFilterSettings(); + QHelpFilterSettings(const QHelpFilterSettings &other); + QHelpFilterSettings(QHelpFilterSettings &&other); + ~QHelpFilterSettings(); - bool install(bool removeFirst = false) override; - bool remove() override; - bool start() override; - bool enableDebugging(const QString &debuggerExecutable, - const QString &debuggerArguments) override; - bool disableDebugging() override; - bool setLoopbackExemptClientEnabled(bool enabled) override; - bool setLoopbackExemptServerEnabled(bool enabled) override; - bool setLoggingRules(const QByteArray &rules) override; - bool suspend() override; - bool waitForFinished(int secs) override; - bool stop() override; + QHelpFilterSettings &operator=(const QHelpFilterSettings &other); + QHelpFilterSettings &operator=(QHelpFilterSettings &&other); - QString devicePath(const QString &relativePath) const override; - bool sendFile(const QString &localFile, const QString &deviceFile) override; - bool receiveFile(const QString &deviceFile, const QString &localFile) override; + void swap(QHelpFilterSettings &other) noexcept + { d.swap(other.d); } -private: - explicit AppxLocalEngine(Runner *runner); - ~AppxLocalEngine(); + void setFilter(const QString &filterName, const QHelpFilterData &filterData); + void removeFilter(const QString &filterName); + QStringList filterNames() const; + QHelpFilterData filterData(const QString &filterName) const; + QMap filters() const; + + void setCurrentFilter(const QString &filterName); + QString currentFilter() const; - QString extensionSdkPath() const override; - bool installPackage(IAppxManifestReader *reader, const QString &filePath) override; + static QHelpFilterSettings readSettings(const QHelpFilterEngine *filterEngine); + static bool applySettings(QHelpFilterEngine *filterEngine, const QHelpFilterSettings &settings); - bool parseExitCode(); - friend struct QScopedPointerDeleter; - Q_DECLARE_PRIVATE(AppxLocalEngine) +private: + QSharedDataPointer d; }; -#endif // APPXLOCALENGINE_H +QT_END_NAMESPACE + +#endif // QHELPFILTERSETTINGS_H diff --git a/src/assistant/help/qhelpfiltersettingswidget.cpp b/src/assistant/help/qhelpfiltersettingswidget.cpp new file mode 100644 index 0000000000..c5f8ac29c3 --- /dev/null +++ b/src/assistant/help/qhelpfiltersettingswidget.cpp @@ -0,0 +1,424 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpfilterdata.h" +#include "qhelpfiltersettings_p.h" +#include "qhelpfiltersettingswidget.h" +#include "ui_qhelpfiltersettingswidget.h" +#include "qfilternamedialog_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +static QStringList versionsToStringList(const QList &versions) +{ + QStringList versionList; + for (const QVersionNumber &version : versions) + versionList.append(version.isNull() ? QString() : version.toString()); + return versionList; +} + +static QList stringListToVersions(const QStringList &versionList) +{ + QList versions; + for (const QString &versionString : versionList) + versions.append(QVersionNumber::fromString(versionString)); + return versions; +} + +class QHelpFilterSettingsWidgetPrivate +{ + QHelpFilterSettingsWidget *q_ptr; + Q_DECLARE_PUBLIC(QHelpFilterSettingsWidget) +public: + QHelpFilterSettingsWidgetPrivate() = default; + + QHelpFilterSettings filterSettings() const; + void setFilterSettings(const QHelpFilterSettings &settings); + + void updateCurrentFilter(); + void componentsChanged(const QStringList &components); + void versionsChanged(const QStringList &versions); + void addFilterClicked(); + void renameFilterClicked(); + void removeFilterClicked(); + void addFilter(const QString &filterName, + const QHelpFilterData &filterData = QHelpFilterData()); + void removeFilter(const QString &filterName); + QString getUniqueFilterName(const QString &windowTitle, + const QString &initialFilterName); + QString suggestedNewFilterName(const QString &initialFilterName) const; + + QMap m_filterToItem; + QHash m_itemToFilter; + + Ui::QHelpFilterSettingsWidget m_ui; + QStringList m_components; + QList m_versions; + QHelpFilterSettings m_filterSettings; +}; + +void QHelpFilterSettingsWidgetPrivate::setFilterSettings(const QHelpFilterSettings &settings) +{ + QString currentFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) { + if (!m_filterSettings.currentFilter().isEmpty()) + currentFilter = m_filterSettings.currentFilter(); + else + currentFilter = settings.currentFilter(); + } + + m_filterSettings = settings; + + m_ui.filterWidget->clear(); + m_ui.componentWidget->clear(); + m_ui.versionWidget->clear(); + m_itemToFilter.clear(); + m_filterToItem.clear(); + + for (const QString &filterName : m_filterSettings.filterNames()) { + QListWidgetItem *item = new QListWidgetItem(filterName); + m_ui.filterWidget->addItem(item); + m_itemToFilter.insert(item, filterName); + m_filterToItem.insert(filterName, item); + if (filterName == currentFilter) + m_ui.filterWidget->setCurrentItem(item); + } + + if (!m_ui.filterWidget->currentItem() && !m_filterToItem.isEmpty()) + m_ui.filterWidget->setCurrentItem(m_filterToItem.first()); + + updateCurrentFilter(); +} + +QHelpFilterSettings QHelpFilterSettingsWidgetPrivate::filterSettings() const +{ + return m_filterSettings; +} + +void QHelpFilterSettingsWidgetPrivate::updateCurrentFilter() +{ + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + + const bool filterSelected = !currentFilter.isEmpty(); + m_ui.componentWidget->setEnabled(filterSelected); + m_ui.versionWidget->setEnabled(filterSelected); + m_ui.renameButton->setEnabled(filterSelected); + m_ui.removeButton->setEnabled(filterSelected); + + m_ui.componentWidget->setOptions(m_components, + m_filterSettings.filterData(currentFilter).components()); + m_ui.versionWidget->setOptions(versionsToStringList(m_versions), + versionsToStringList(m_filterSettings.filterData(currentFilter).versions())); +} + +void QHelpFilterSettingsWidgetPrivate::componentsChanged(const QStringList &components) +{ + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) + return; + + QHelpFilterData filterData = m_filterSettings.filterData(currentFilter); + filterData.setComponents(components); + m_filterSettings.setFilter(currentFilter, filterData); +} + +void QHelpFilterSettingsWidgetPrivate::versionsChanged(const QStringList &versions) +{ + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) + return; + + QHelpFilterData filterData = m_filterSettings.filterData(currentFilter); + filterData.setVersions(stringListToVersions(versions)); + m_filterSettings.setFilter(currentFilter, filterData); +} + +void QHelpFilterSettingsWidgetPrivate::addFilterClicked() +{ + const QString newFilterName = getUniqueFilterName(QHelpFilterSettingsWidget::tr("Add Filter"), + suggestedNewFilterName(QHelpFilterSettingsWidget::tr("New Filter"))); + if (newFilterName.isEmpty()) + return; + + addFilter(newFilterName); +} + +void QHelpFilterSettingsWidgetPrivate::renameFilterClicked() +{ + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) + return; + + const QString newFilterName = getUniqueFilterName(QHelpFilterSettingsWidget::tr("Rename Filter"), currentFilter); + if (newFilterName.isEmpty()) + return; + + const QHelpFilterData oldFilterData = m_filterSettings.filterData(currentFilter); + removeFilter(currentFilter); + addFilter(newFilterName, oldFilterData); + + if (m_filterSettings.currentFilter() == currentFilter) + m_filterSettings.setCurrentFilter(newFilterName); +} + +void QHelpFilterSettingsWidgetPrivate::removeFilterClicked() +{ + Q_Q(QHelpFilterSettingsWidget); + + const QString ¤tFilter = m_itemToFilter.value(m_ui.filterWidget->currentItem()); + if (currentFilter.isEmpty()) + return; + + if (QMessageBox::question(q, QHelpFilterSettingsWidget::tr("Remove Filter"), + QHelpFilterSettingsWidget::tr("Are you sure you want to remove the \"%1\" filter?") + .arg(currentFilter), + QMessageBox::Yes | QMessageBox::No) + != QMessageBox::Yes) { + return; + } + + removeFilter(currentFilter); + + if (m_filterSettings.currentFilter() == currentFilter) + m_filterSettings.setCurrentFilter(QString()); +} + +void QHelpFilterSettingsWidgetPrivate::addFilter(const QString &filterName, + const QHelpFilterData &filterData) +{ + QListWidgetItem *item = new QListWidgetItem(filterName); + m_filterSettings.setFilter(filterName, filterData); + m_filterToItem.insert(filterName, item); + m_itemToFilter.insert(item, filterName); + m_ui.filterWidget->insertItem(m_filterToItem.keys().indexOf(filterName), item); + + m_ui.filterWidget->setCurrentItem(item); + updateCurrentFilter(); +} + +void QHelpFilterSettingsWidgetPrivate::removeFilter(const QString &filterName) +{ + QListWidgetItem *item = m_filterToItem.value(filterName); + m_itemToFilter.remove(item); + m_filterToItem.remove(filterName); + delete item; + + m_filterSettings.removeFilter(filterName); +} + +QString QHelpFilterSettingsWidgetPrivate::getUniqueFilterName(const QString &windowTitle, + const QString &initialFilterName) +{ + Q_Q(QHelpFilterSettingsWidget); + + QString newFilterName = initialFilterName; + while (1) { + QFilterNameDialog dialog(q); + dialog.setWindowTitle(windowTitle); + dialog.setFilterName(newFilterName); + if (dialog.exec() == QDialog::Rejected) + return QString(); + + newFilterName = dialog.filterName(); + if (!m_filterToItem.contains(newFilterName)) + break; + + if (QMessageBox::warning(q, QHelpFilterSettingsWidget::tr("Filter Exists"), + QHelpFilterSettingsWidget::tr("The filter \"%1\" already exists.") + .arg(newFilterName), + QMessageBox::Retry | QMessageBox::Cancel) + == QMessageBox::Cancel) { + return QString(); + } + } + + return newFilterName; +} + +QString QHelpFilterSettingsWidgetPrivate::suggestedNewFilterName(const QString &initialFilterName) const +{ + QString newFilterName = initialFilterName; + + int counter = 1; + while (m_filterToItem.contains(newFilterName)) { + newFilterName = initialFilterName + QLatin1Char(' ') + + QString::number(++counter); + } + + return newFilterName; +} + +/*! + \class QHelpFilterSettingsWidget + \inmodule QtHelp + \since 5.15 + \brief The QHelpFilterSettingsWidget class provides a widget that allows + for creating, editing and removing filters. + + The instance of QHelpFilterSettingsWidget may be a part of + a preferences dialog. Before showing the dialog, \l setAvailableComponents() + and \l setAvailableVersions() should be called, otherwise the filter + settings widget will only offer a creation of empty filters, + which wouldn't be useful. In addition, \l readSettings should also + be called to fill up the filter settings widget with the list of filters + already stored in the filter engine. The creation of new filters, + modifications to existing filters and removal of unneeded filters are + handled by the widget automatically. If you want to store the current + state of the widget and apply it to the filter engine e.g. after + the user clicked the apply button - call \l applySettings(). +*/ + +/*! + Constructs a filter settings widget with \a parent as parent widget. +*/ +QHelpFilterSettingsWidget::QHelpFilterSettingsWidget(QWidget *parent) + : QWidget(parent) + , d_ptr(new QHelpFilterSettingsWidgetPrivate()) +{ + Q_D(QHelpFilterSettingsWidget); + d->q_ptr = this; + d->m_ui.setupUi(this); + + // TODO: make resources configurable + QString resourcePath = QLatin1String(":/qt-project.org/assistant/images/"); +#ifdef Q_OS_MACOS + resourcePath.append(QLatin1String("mac")); +#else + resourcePath.append(QLatin1String("win")); +#endif + d->m_ui.addButton->setIcon(QIcon(resourcePath + QLatin1String("/plus.png"))); + d->m_ui.removeButton->setIcon(QIcon(resourcePath + QLatin1String("/minus.png"))); + + connect(d->m_ui.componentWidget, &QOptionsWidget::optionSelectionChanged, + [this](const QStringList &options) { + Q_D(QHelpFilterSettingsWidget); + d->componentsChanged(options); + }); + connect(d->m_ui.versionWidget, &QOptionsWidget::optionSelectionChanged, + [this](const QStringList &options) { + Q_D(QHelpFilterSettingsWidget); + d->versionsChanged(options); + }); + connect(d->m_ui.filterWidget, &QListWidget::currentItemChanged, + this, [this](QListWidgetItem *) { + Q_D(QHelpFilterSettingsWidget); + d->updateCurrentFilter(); + }); + connect(d->m_ui.filterWidget, &QListWidget::itemDoubleClicked, + [this](QListWidgetItem *) { + Q_D(QHelpFilterSettingsWidget); + d->renameFilterClicked(); + }); + + // TODO: repeat these actions on context menu + connect(d->m_ui.addButton, &QAbstractButton::clicked, + [this]() { + Q_D(QHelpFilterSettingsWidget); + d->addFilterClicked(); + }); + connect(d->m_ui.renameButton, &QAbstractButton::clicked, + [this]() { + Q_D(QHelpFilterSettingsWidget); + d->renameFilterClicked(); + }); + connect(d->m_ui.removeButton, &QAbstractButton::clicked, + [this]() { + Q_D(QHelpFilterSettingsWidget); + d->removeFilterClicked(); + }); + + d->m_ui.componentWidget->setNoOptionText(tr("No Component")); + d->m_ui.componentWidget->setInvalidOptionText(tr("Invalid Component")); + d->m_ui.versionWidget->setNoOptionText(tr("No Version")); + d->m_ui.versionWidget->setInvalidOptionText(tr("Invalid Version")); +} + +/*! + Destroys the filter settings widget. +*/ +QHelpFilterSettingsWidget::~QHelpFilterSettingsWidget() = default; + +/*! + Sets the list of all available components to \a components. + \sa QHelpFilterEngine::availableComponents() +*/ +void QHelpFilterSettingsWidget::setAvailableComponents(const QStringList &components) +{ + Q_D(QHelpFilterSettingsWidget); + d->m_components = components; + d->updateCurrentFilter(); +} + +/*! + Sets the list of all available version numbers to \a versions. + \sa QHelpFilterEngine::availableVersions() +*/ +void QHelpFilterSettingsWidget::setAvailableVersions(const QList &versions) +{ + Q_D(QHelpFilterSettingsWidget); + d->m_versions = versions; + d->updateCurrentFilter(); +} + +/*! + Reads the filter settings stored inside \a filterEngine and sets up + this filter settings widget accordingly. +*/ +void QHelpFilterSettingsWidget::readSettings(const QHelpFilterEngine *filterEngine) +{ + Q_D(QHelpFilterSettingsWidget); + const QHelpFilterSettings settings = QHelpFilterSettings::readSettings(filterEngine); + d->setFilterSettings(settings); +} + +/*! + Writes the filter settings, currently presented in this filter settings + widget, to the \a filterEngine. The old settings stored in the filter + engine will be overwritten. Returns \c true on success. +*/ +bool QHelpFilterSettingsWidget::applySettings(QHelpFilterEngine *filterEngine) const +{ + Q_D(const QHelpFilterSettingsWidget); + return QHelpFilterSettings::applySettings(filterEngine, d->filterSettings()); +} + +QT_END_NAMESPACE diff --git a/src/winrtrunner/runnerengine.h b/src/assistant/help/qhelpfiltersettingswidget.h similarity index 60% rename from src/winrtrunner/runnerengine.h rename to src/assistant/help/qhelpfiltersettingswidget.h index 44565c46c2..c3c77305fe 100644 --- a/src/winrtrunner/runnerengine.h +++ b/src/assistant/help/qhelpfiltersettingswidget.h @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -37,34 +37,41 @@ ** ****************************************************************************/ -#ifndef RUNNERENGINE_H -#define RUNNERENGINE_H +#ifndef QHELPFILTERSETTINGSWIDGET_H +#define QHELPFILTERSETTINGSWIDGET_H -#include +#include -QT_USE_NAMESPACE +#include -class RunnerEngine +QT_BEGIN_NAMESPACE + +class QVersionNumber; + +class QHelpFilterEngine; +class QHelpFilterSettingsWidgetPrivate; + +class QHELP_EXPORT QHelpFilterSettingsWidget : public QWidget { + Q_OBJECT public: - virtual ~RunnerEngine() { } - virtual bool install(bool removeFirst = false) = 0; - virtual bool remove() = 0; - virtual bool start() = 0; - virtual bool enableDebugging(const QString &debugger, const QString &debuggerArguments) = 0; - virtual bool disableDebugging() = 0; - virtual bool setLoopbackExemptClientEnabled(bool enabled) = 0; - virtual bool setLoopbackExemptServerEnabled(bool enabled) = 0; - virtual bool setLoggingRules(const QByteArray &rules) = 0; - virtual bool suspend() = 0; - virtual bool waitForFinished(int secs) = 0; - virtual bool stop() = 0; - virtual qint64 pid() const = 0; - virtual int exitCode() const = 0; - virtual QString executable() const = 0; - virtual QString devicePath(const QString &relativePath) const = 0; - virtual bool sendFile(const QString &localFile, const QString &deviceFile) = 0; - virtual bool receiveFile(const QString &deviceFile, const QString &localFile) = 0; + explicit QHelpFilterSettingsWidget(QWidget *parent = nullptr); + + ~QHelpFilterSettingsWidget(); + + void setAvailableComponents(const QStringList &components); + void setAvailableVersions(const QList &versions); + + // TODO: filterEngine may be moved to c'tor or to setFilterEngine() setter + void readSettings(const QHelpFilterEngine *filterEngine); + bool applySettings(QHelpFilterEngine *filterEngine) const; + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QHelpFilterSettingsWidget) + Q_DISABLE_COPY_MOVE(QHelpFilterSettingsWidget) }; -#endif // RUNNERENGINE_H +QT_END_NAMESPACE + +#endif // QHELPFILTERSETTINGSWIDGET_H diff --git a/src/assistant/help/qhelpfiltersettingswidget.ui b/src/assistant/help/qhelpfiltersettingswidget.ui new file mode 100644 index 0000000000..7e16e3f7b8 --- /dev/null +++ b/src/assistant/help/qhelpfiltersettingswidget.ui @@ -0,0 +1,83 @@ + + + QHelpFilterSettingsWidget + + + + 0 + 0 + 347 + 127 + + + + Form + + + + + + Filter + + + + + + + QFrame::NoFrame + + + Components + + + + + + + Versions + + + + + + + + + + + + + + + + Add... + + + + + + + Rename... + + + + + + + Remove + + + + + + + + QOptionsWidget + QWidget +
qoptionswidget_p.h
+ 1 +
+
+ + +
diff --git a/src/assistant/help/qhelpindexwidget.cpp b/src/assistant/help/qhelpindexwidget.cpp index fa70dd438a..96fea14335 100644 --- a/src/assistant/help/qhelpindexwidget.cpp +++ b/src/assistant/help/qhelpindexwidget.cpp @@ -45,6 +45,7 @@ #include #include +#include #include #include @@ -222,12 +223,13 @@ bool QHelpIndexModel::isCreatingIndex() const } /*! - \obsolete - Use QHelpEngineCore::linksForKeyword() instead. + \since 5.15 + + Returns the associated help engine that manages this model. */ -QMap QHelpIndexModel::linksForKeyword(const QString &keyword) const +QHelpEngineCore *QHelpIndexModel::helpEngine() const { - return d->helpEngine->q->linksForKeyword(keyword); + return d->helpEngine->q; } /*! @@ -252,7 +254,9 @@ QModelIndex QHelpIndexModel::filter(const QString &filter, const QString &wildca int perfectMatch = -1; if (!wildcard.isEmpty()) { - const QRegExp regExp(wildcard, Qt::CaseInsensitive, QRegExp::Wildcard); + auto re = QRegularExpression::wildcardToRegularExpression(wildcard, + QRegularExpression::UnanchoredWildcardConversion); + const QRegularExpression regExp(re, QRegularExpression::CaseInsensitiveOption); for (const QString &index : qAsConst(d->indices)) { if (index.contains(regExp)) { lst.append(index); @@ -306,18 +310,35 @@ QModelIndex QHelpIndexModel::filter(const QString &filter, const QString &wildca \fn void QHelpIndexWidget::linkActivated(const QUrl &link, const QString &keyword) + \obsolete + + Use documentActivated() instead. + This signal is emitted when an item is activated and its associated \a link should be shown. To know where the link - belongs to, the \a keyword is given as a second paremeter. + belongs to, the \a keyword is given as a second parameter. +*/ + +/*! + \fn void QHelpIndexWidget::documentActivated(const QHelpLink &document, + const QString &keyword) + + \since 5.15 + + This signal is emitted when an item is activated and its + associated \a document should be shown. To know where the link + belongs to, the \a keyword is given as a second parameter. */ /*! - \fn void QHelpIndexWidget::linksActivated(const QMap &links, + \fn void QHelpIndexWidget::documentsActivated(const QList &documents, const QString &keyword) + \since 5.15 + This signal is emitted when the item representing the \a keyword - is activated and the item has more than one link associated. - The \a links consist of the document titles and their URLs. + is activated and the item has more than one document associated. + The \a documents consist of the document titles and their URLs. */ QHelpIndexWidget::QHelpIndexWidget() @@ -341,11 +362,23 @@ void QHelpIndexWidget::showLink(const QModelIndex &index) const QVariant &v = indexModel->data(index, Qt::DisplayRole); const QString name = v.isValid() ? v.toString() : QString(); - const QMap &links = indexModel->linksForKeyword(name); - if (links.count() > 1) + const QList &docs = indexModel->helpEngine()->documentsForKeyword(name); + if (docs.count() > 1) { + emit documentsActivated(docs, name); + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + QMultiMap links; + for (const auto &doc : docs) + links.insert(doc.title, doc.url); emit linksActivated(links, name); - else if (!links.isEmpty()) - emit linkActivated(links.first(), name); + QT_WARNING_POP + } else if (!docs.isEmpty()) { + emit documentActivated(docs.first(), name); + QT_WARNING_PUSH + QT_WARNING_DISABLE_DEPRECATED + emit linkActivated(docs.first().url, name); + QT_WARNING_POP + } } /*! diff --git a/src/assistant/help/qhelpindexwidget.h b/src/assistant/help/qhelpindexwidget.h index 58dda5e394..e3ffcba80b 100644 --- a/src/assistant/help/qhelpindexwidget.h +++ b/src/assistant/help/qhelpindexwidget.h @@ -50,7 +50,9 @@ QT_BEGIN_NAMESPACE class QHelpEnginePrivate; +class QHelpEngineCore; class QHelpIndexModelPrivate; +struct QHelpLink; class QHELP_EXPORT QHelpIndexModel : public QStringListModel { @@ -61,8 +63,8 @@ class QHELP_EXPORT QHelpIndexModel : public QStringListModel QModelIndex filter(const QString &filter, const QString &wildcard = QString()); - QMap linksForKeyword(const QString &keyword) const; bool isCreatingIndex() const; + QHelpEngineCore *helpEngine() const; Q_SIGNALS: void indexCreationStarted(); @@ -82,11 +84,19 @@ private Q_SLOTS: class QHELP_EXPORT QHelpIndexWidget : public QListView { Q_OBJECT + Q_MOC_INCLUDE() Q_SIGNALS: +#if QT_DEPRECATED_SINCE(5, 15) + QT_DEPRECATED_X("Use documentActivated() instead") void linkActivated(const QUrl &link, const QString &keyword); - void linksActivated(const QMap &links, - const QString &keyword); + QT_DEPRECATED_X("Use documentsActivated() instead") + void linksActivated(const QMultiMap &links, const QString &keyword); +#endif + void documentActivated(const QHelpLink &document, + const QString &keyword); + void documentsActivated(const QList &documents, + const QString &keyword); public Q_SLOTS: void filterIndices(const QString &filter, diff --git a/src/assistant/help/qhelplink.cpp b/src/assistant/help/qhelplink.cpp new file mode 100644 index 0000000000..75cb16ab88 --- /dev/null +++ b/src/assistant/help/qhelplink.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelplink.h" + +/*! + \class QHelpLink + \since 5.15 + \inmodule QtHelp + \brief The QHelpLink struct provides the data associated with a help link. + + The QHelpLink object is a data object that describes a link to a documentation file. + The description of the help link contains the document title and URL of the document. + \sa QHelpEngineCore +*/ + +/*! + \variable QHelpLink::url + \brief The target url of the link. +*/ +/*! + \variable QHelpLink::title + \brief The title of the link. +*/ diff --git a/src/winrtrunner/appxphoneengine.h b/src/assistant/help/qhelplink.h similarity index 52% rename from src/winrtrunner/appxphoneengine.h rename to src/assistant/help/qhelplink.h index b462e797fd..92b5ec6d0e 100644 --- a/src/winrtrunner/appxphoneengine.h +++ b/src/assistant/help/qhelplink.h @@ -1,9 +1,9 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the tools applications of the Qt Toolkit. +** This file is part of the Qt Assistant of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage @@ -37,53 +37,21 @@ ** ****************************************************************************/ -#ifndef APPXPHONEENGINE_H -#define APPXPHONEENGINE_H +#ifndef QHELPLINK_H +#define QHELPLINK_H -#include "appxengine.h" -#include "runnerengine.h" -#include "runner.h" +#include -#include +#include -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE -class AppxPhoneEnginePrivate; -class AppxPhoneEngine : public AppxEngine +struct QHELP_EXPORT QHelpLink final { -public: - static bool canHandle(Runner *runner); - static RunnerEngine *create(Runner *runner); - static QStringList deviceNames(); - - bool install(bool removeFirst = false) override; - bool remove() override; - bool start() override; - bool enableDebugging(const QString &debuggerExecutable, - const QString &debuggerArguments) override; - bool disableDebugging() override; - bool setLoopbackExemptClientEnabled(bool enabled) override; - bool setLoopbackExemptServerEnabled(bool enabled) override; - bool setLoggingRules(const QByteArray &rules) override; - bool suspend() override; - bool waitForFinished(int secs) override; - bool stop() override; - - QString devicePath(const QString &relativePath) const override; - bool sendFile(const QString &localFile, const QString &deviceFile) override; - bool receiveFile(const QString &deviceFile, const QString &localFile) override; - -private: - explicit AppxPhoneEngine(Runner *runner); - ~AppxPhoneEngine(); - - QString extensionSdkPath() const; - bool installPackage(IAppxManifestReader *reader, const QString &filePath) override; - - bool connect(); - - friend struct QScopedPointerDeleter; - Q_DECLARE_PRIVATE(AppxPhoneEngine) + QUrl url; + QString title; }; -#endif // APPXPHONEENGINE_H +QT_END_NAMESPACE + +#endif // QHELPLINK_H diff --git a/src/assistant/help/qhelpsearchengine.cpp b/src/assistant/help/qhelpsearchengine.cpp index af7247cc3a..c3dcc44229 100644 --- a/src/assistant/help/qhelpsearchengine.cpp +++ b/src/assistant/help/qhelpsearchengine.cpp @@ -178,11 +178,11 @@ class QHelpSearchEnginePrivate : public QObject return indexReader ? indexReader->searchResultCount() : 0; } - QVector searchResults(int start, int end) const + QList searchResults(int start, int end) const { return indexReader ? indexReader->searchResults(start, end) : - QVector(); + QList(); } void updateIndex(bool reindex = false) @@ -490,7 +490,7 @@ QList QHelpSearchEngine::hits(int start, int end) Returns a list of search results within the range from the index specified by \a start to the index specified by \a end. */ -QVector QHelpSearchEngine::searchResults(int start, int end) const +QList QHelpSearchEngine::searchResults(int start, int end) const { return d->searchResults(start, end); } diff --git a/src/assistant/help/qhelpsearchengine.h b/src/assistant/help/qhelpsearchengine.h index ef4953c688..f1ddb1634b 100644 --- a/src/assistant/help/qhelpsearchengine.h +++ b/src/assistant/help/qhelpsearchengine.h @@ -110,7 +110,7 @@ class QHELP_EXPORT QHelpSearchEngine : public QObject #endif int searchResultCount() const; - QVector searchResults(int start, int end) const; + QList searchResults(int start, int end) const; QString searchInput() const; public Q_SLOTS: diff --git a/src/assistant/help/qhelpsearchindexreader.cpp b/src/assistant/help/qhelpsearchindexreader.cpp index 8aaa5cc479..e2172deda3 100644 --- a/src/assistant/help/qhelpsearchindexreader.cpp +++ b/src/assistant/help/qhelpsearchindexreader.cpp @@ -76,7 +76,7 @@ int QHelpSearchIndexReader::searchResultCount() const return m_searchResults.count(); } -QVector QHelpSearchIndexReader::searchResults(int start, +QList QHelpSearchIndexReader::searchResults(int start, int end) const { QMutexLocker lock(&m_mutex); diff --git a/src/assistant/help/qhelpsearchindexreader_default.cpp b/src/assistant/help/qhelpsearchindexreader_default.cpp index 06a8a8b190..cbd01ee7b1 100644 --- a/src/assistant/help/qhelpsearchindexreader_default.cpp +++ b/src/assistant/help/qhelpsearchindexreader_default.cpp @@ -135,7 +135,7 @@ static void bindNamespacesAndAttributes(QSqlQuery *query, const QStringList &nam query->addBindValue(ns); } -QVector Reader::queryTable(const QSqlDatabase &db, +QList Reader::queryTable(const QSqlDatabase &db, const QString &tableName, const QString &searchInput) const { @@ -154,7 +154,7 @@ QVector Reader::queryTable(const QSqlDatabase &db, query.addBindValue(searchInput); query.exec(); - QVector results; + QList results; while (query.next()) { const QString &url = query.value(QLatin1String("url")).toString(); @@ -175,13 +175,13 @@ void Reader::searchInDB(const QString &searchInput) db.setDatabaseName(m_indexPath + QLatin1String("/fts")); if (db.open()) { - const QVector titleResults = queryTable(db, + const QList titleResults = queryTable(db, QLatin1String("titles"), searchInput); - const QVector contentResults = queryTable(db, + const QList contentResults = queryTable(db, QLatin1String("contents"), searchInput); // merge results form title and contents searches - m_searchResults = QVector(); + m_searchResults = QList(); QSet urls; @@ -205,7 +205,7 @@ void Reader::searchInDB(const QString &searchInput) QSqlDatabase::removeDatabase(uniqueId); } -QVector Reader::searchResults() const +QList Reader::searchResults() const { return m_searchResults; } diff --git a/src/assistant/help/qhelpsearchindexreader_default_p.h b/src/assistant/help/qhelpsearchindexreader_default_p.h index c183a23575..6990b2c216 100644 --- a/src/assistant/help/qhelpsearchindexreader_default_p.h +++ b/src/assistant/help/qhelpsearchindexreader_default_p.h @@ -68,16 +68,16 @@ class Reader void setFilterEngineNamespaceList(const QStringList &namespaceList); void searchInDB(const QString &term); - QVector searchResults() const; + QList searchResults() const; private: - QVector queryTable(const QSqlDatabase &db, + QList queryTable(const QSqlDatabase &db, const QString &tableName, const QString &searchInput) const; QMultiMap m_namespaceAttributes; QStringList m_filterEngineNamespaceList; - QVector m_searchResults; + QList m_searchResults; QString m_indexPath; bool m_useFilterEngine = false; }; diff --git a/src/assistant/help/qhelpsearchindexreader_p.h b/src/assistant/help/qhelpsearchindexreader_p.h index 57295693b5..883446fea5 100644 --- a/src/assistant/help/qhelpsearchindexreader_p.h +++ b/src/assistant/help/qhelpsearchindexreader_p.h @@ -56,7 +56,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -77,7 +76,7 @@ class QHelpSearchIndexReader : public QThread const QString &searchInput, bool usesFilterEngine = false); int searchResultCount() const; - QVector searchResults(int start, int end) const; + QList searchResults(int start, int end) const; signals: void searchingStarted(); @@ -85,7 +84,7 @@ class QHelpSearchIndexReader : public QThread protected: mutable QMutex m_mutex; - QVector m_searchResults; + QList m_searchResults; bool m_cancel = false; QString m_collectionFile; QString m_searchInput; diff --git a/src/assistant/help/qhelpsearchindexwriter_default.cpp b/src/assistant/help/qhelpsearchindexwriter_default.cpp index 806d0182a2..a814598f34 100644 --- a/src/assistant/help/qhelpsearchindexwriter_default.cpp +++ b/src/assistant/help/qhelpsearchindexwriter_default.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include @@ -458,14 +458,14 @@ void QHelpSearchIndexWriter::run() for (const QStringList &attributes : attributeSets) { const QString &attributesString = attributes.join(QLatin1Char('|')); - const QMap htmlFiles - = reader.filesData(attributes, QLatin1String("html")); - const QMap htmFiles - = reader.filesData(attributes, QLatin1String("htm")); - const QMap txtFiles - = reader.filesData(attributes, QLatin1String("txt")); + const QMultiMap htmlFiles = + reader.filesData(attributes, QLatin1String("html")); + const QMultiMap htmFiles = + reader.filesData(attributes, QLatin1String("htm")); + const QMultiMap txtFiles = + reader.filesData(attributes, QLatin1String("txt")); - QMap files = htmlFiles; + QMultiMap files = htmlFiles; files.unite(htmFiles); files.unite(txtFiles); @@ -502,8 +502,9 @@ void QHelpSearchIndexWriter::run() } QTextStream s(data); - const QString &en = QHelpGlobal::codecFromData(data); - s.setCodec(QTextCodec::codecForName(en.toLatin1().constData())); + auto encoding = QStringDecoder::encodingForHtml(data); + if (encoding) + s.setEncoding(*encoding); const QString &text = s.readAll(); if (text.isEmpty()) diff --git a/src/assistant/help/qhelpsearchquerywidget.cpp b/src/assistant/help/qhelpsearchquerywidget.cpp index 4cbd4b069b..183e317aa0 100644 --- a/src/assistant/help/qhelpsearchquerywidget.cpp +++ b/src/assistant/help/qhelpsearchquerywidget.cpp @@ -111,9 +111,11 @@ class QHelpSearchQueryWidgetPrivate : public QObject void retranslate() { m_searchLabel->setText(QHelpSearchQueryWidget::tr("Search for:")); + m_searchButton->setText(QHelpSearchQueryWidget::tr("Search")); +#if QT_CONFIG(tooltip) m_prevQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Previous search")); m_nextQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Next search")); - m_searchButton->setText(QHelpSearchQueryWidget::tr("Search")); +#endif } void saveQuery(const QString &query) @@ -300,7 +302,7 @@ void QHelpSearchQueryWidget::collapseExtendedSearch() QList QHelpSearchQueryWidget::query() const { return QList() << QHelpSearchQuery(QHelpSearchQuery::DEFAULT, - searchInput().split(QChar::Space, QString::SkipEmptyParts)); + searchInput().split(QChar::Space, Qt::SkipEmptyParts)); } /*! diff --git a/src/assistant/help/qhelpsearchresultwidget.cpp b/src/assistant/help/qhelpsearchresultwidget.cpp index b7d61b4944..9d67935f33 100644 --- a/src/assistant/help/qhelpsearchresultwidget.cpp +++ b/src/assistant/help/qhelpsearchresultwidget.cpp @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QResultWidget : public QTextBrowser { Q_OBJECT + Q_PROPERTY(QColor linkColor READ linkColor WRITE setLinkColor) public: QResultWidget(QWidget *parent = nullptr) @@ -68,9 +69,18 @@ class QResultWidget : public QTextBrowser connect(this, &QTextBrowser::anchorClicked, this, &QResultWidget::requestShowLink); setContextMenuPolicy(Qt::NoContextMenu); + setLinkColor(palette().color(QPalette::Link)); } - void showResultPage(const QVector results, bool isIndexing) + QColor linkColor() const { return m_linkColor; } + void setLinkColor(const QColor &color) + { + m_linkColor = color; + const QString sheet = QString::fromLatin1("a { text-decoration: underline; color: %1 }").arg(m_linkColor.name()); + document()->setDefaultStyleSheet(sheet); + } + + void showResultPage(const QList &results, bool isIndexing) { QString htmlFile; QTextStream str(&htmlFile); @@ -88,10 +98,10 @@ class QResultWidget : public QTextBrowser } for (const QHelpSearchResult &result : results) { - str << "
" << result.title() << "" - "
" << result.snippet() << "

"; + str << "" + "
" << result.snippet() << "
"; } } else { str << "


" @@ -113,9 +123,15 @@ class QResultWidget : public QTextBrowser void requestShowLink(const QUrl &url); private slots: +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) void setSource(const QUrl & /* name */) override {} -}; +#else + void doSetSource(const QUrl & /*name*/, QTextDocument::ResourceType /*type*/) override {} +#endif +private: + QColor m_linkColor; +}; class QHelpSearchResultWidgetPrivate : public QObject { diff --git a/src/assistant/assistant/optionswidget.cpp b/src/assistant/help/qoptionswidget.cpp similarity index 88% rename from src/assistant/assistant/optionswidget.cpp rename to src/assistant/help/qoptionswidget.cpp index bc089c5bf8..21fdfe07a0 100644 --- a/src/assistant/assistant/optionswidget.cpp +++ b/src/assistant/help/qoptionswidget.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Assistant of the Qt Toolkit. @@ -26,20 +26,17 @@ ** ****************************************************************************/ -#include "optionswidget.h" +#include "qoptionswidget_p.h" #include #include #include #include -#include - QT_BEGIN_NAMESPACE class ListWidgetDelegate : public QItemDelegate { -// Q_OBJECT not needed public: ListWidgetDelegate(QWidget *w) : QItemDelegate(w), m_widget(w) {} @@ -87,9 +84,7 @@ static QStringList subtract(const QStringList &minuend, const QStringList &subtr return result; } -///////////////// - -OptionsWidget::OptionsWidget(QWidget *parent) +QOptionsWidget::QOptionsWidget(QWidget *parent) : QWidget(parent) , m_noOptionText(tr("No Option")) , m_invalidOptionText(tr("Invalid Option")) @@ -100,16 +95,16 @@ OptionsWidget::OptionsWidget(QWidget *parent) layout->addWidget(m_listWidget); layout->setContentsMargins(QMargins()); - connect(m_listWidget, &QListWidget::itemChanged, this, &OptionsWidget::itemChanged); + connect(m_listWidget, &QListWidget::itemChanged, this, &QOptionsWidget::itemChanged); } -void OptionsWidget::clear() +void QOptionsWidget::clear() { setOptions(QStringList(), QStringList()); } -void OptionsWidget::setOptions(const QStringList &validOptions, - const QStringList &selectedOptions) +void QOptionsWidget::setOptions(const QStringList &validOptions, + const QStringList &selectedOptions) { m_listWidget->clear(); m_optionToItem.clear(); @@ -145,17 +140,17 @@ void OptionsWidget::setOptions(const QStringList &validOptions, } } -QStringList OptionsWidget::validOptions() const +QStringList QOptionsWidget::validOptions() const { return m_validOptions; } -QStringList OptionsWidget::selectedOptions() const +QStringList QOptionsWidget::selectedOptions() const { return m_selectedOptions; } -void OptionsWidget::setNoOptionText(const QString &text) +void QOptionsWidget::setNoOptionText(const QString &text) { if (m_noOptionText == text) return; @@ -171,7 +166,7 @@ void OptionsWidget::setNoOptionText(const QString &text) } } -void OptionsWidget::setInvalidOptionText(const QString &text) +void QOptionsWidget::setInvalidOptionText(const QString &text) { if (m_invalidOptionText == text) return; @@ -183,7 +178,7 @@ void OptionsWidget::setInvalidOptionText(const QString &text) m_optionToItem.value(option)->setText(optionText(option, false)); } -QString OptionsWidget::optionText(const QString &optionName, bool valid) const +QString QOptionsWidget::optionText(const QString &optionName, bool valid) const { QString text = optionName; if (optionName.isEmpty()) @@ -193,7 +188,7 @@ QString OptionsWidget::optionText(const QString &optionName, bool valid) const return text; } -QListWidgetItem *OptionsWidget::appendItem(const QString &optionName, bool valid, bool selected) +QListWidgetItem *QOptionsWidget::appendItem(const QString &optionName, bool valid, bool selected) { QListWidgetItem *optionItem = new QListWidgetItem(optionText(optionName, valid), m_listWidget); optionItem->setCheckState(selected ? Qt::Checked : Qt::Unchecked); @@ -203,14 +198,14 @@ QListWidgetItem *OptionsWidget::appendItem(const QString &optionName, bool valid return optionItem; } -void OptionsWidget::appendSeparator() +void QOptionsWidget::appendSeparator() { QListWidgetItem *separatorItem = new QListWidgetItem(m_listWidget); ListWidgetDelegate::setSeparator(separatorItem); m_listWidget->insertItem(m_listWidget->count(), separatorItem); } -void OptionsWidget::itemChanged(QListWidgetItem *item) +void QOptionsWidget::itemChanged(QListWidgetItem *item) { const auto it = m_itemToOption.constFind(item); if (it == m_itemToOption.constEnd()) diff --git a/src/assistant/assistant/optionswidget.h b/src/assistant/help/qoptionswidget_p.h similarity index 84% rename from src/assistant/assistant/optionswidget.h rename to src/assistant/help/qoptionswidget_p.h index 52c876badd..a6700c1d73 100644 --- a/src/assistant/assistant/optionswidget.h +++ b/src/assistant/help/qoptionswidget_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Assistant of the Qt Toolkit. @@ -26,8 +26,19 @@ ** ****************************************************************************/ -#ifndef OPTIONSWIDGET_H -#define OPTIONSWIDGET_H +#ifndef QOPTIONSWIDGET_H +#define QOPTIONSWIDGET_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// #include #include @@ -37,11 +48,11 @@ QT_BEGIN_NAMESPACE class QListWidget; class QListWidgetItem; -class OptionsWidget : public QWidget +class QOptionsWidget : public QWidget { Q_OBJECT public: - OptionsWidget(QWidget *parent = nullptr); + QOptionsWidget(QWidget *parent = nullptr); void clear(); void setOptions(const QStringList &validOptions, diff --git a/src/assistant/qcollectiongenerator/main.c b/src/assistant/qcollectiongenerator/main.c deleted file mode 100644 index 5e4e026304..0000000000 --- a/src/assistant/qcollectiongenerator/main.c +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Assistant of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#else -#include -#endif - -static const char collectionGeneratorName[] = "qcollectiongenerator"; -static const char helpGeneratorName[] = "qhelpgenerator"; - -#ifdef _WIN32 -static const char separator = '\\'; -#else -static const char separator = '/'; -#endif - -int main(int argc, char *argv[]) -{ - printf("The \"%s\" tool is deprecated, use \"%s\" instead.\n\n", - collectionGeneratorName, helpGeneratorName); - - // Replace the "qcollectiongenerator" with "qhelpgenerator" - // in passed argv[0], keeping the path. - - const size_t currentNameSize = strlen(argv[0]); - const size_t collectionGeneratorNameSize = strlen(collectionGeneratorName); - const ptrdiff_t maxPathOffset = currentNameSize - collectionGeneratorNameSize; - ptrdiff_t pathOffset = maxPathOffset; - - if (maxPathOffset >= 0 && strchr(argv[0] + maxPathOffset, separator)) - pathOffset = -1; // Separator detected. Wrong filename. - - while (pathOffset >= 0) { - const char *fileName = argv[0] + pathOffset; - - if (fileName[0] == separator) { // Separator detected. Wrong filename. - pathOffset = -1; - break; - } - - if (!strncmp(fileName, collectionGeneratorName, collectionGeneratorNameSize)) - break; - - --pathOffset; - } - - if (pathOffset < 0) { - fprintf(stderr, "Wrong tool name. " - "The tool name is expected to contain: \"%s\", got: \"%s\" instead.\n", - collectionGeneratorName, argv[0]); - return 3; - } - - const size_t helpGeneratorNameSize = strlen(helpGeneratorName); - // Allocate a buffer for the new full path, consisting of the pathSize + new name - char *newPath = (char *) malloc((maxPathOffset + helpGeneratorNameSize + 1) * sizeof(char)); - // Copy the path - memcpy(newPath, argv[0], pathOffset); - // Copy the new name - memcpy(newPath + pathOffset, helpGeneratorName, helpGeneratorNameSize); - // Copy the remaining part - memcpy(newPath + pathOffset + helpGeneratorNameSize, - argv[0] + pathOffset + collectionGeneratorNameSize, - currentNameSize - pathOffset - collectionGeneratorNameSize + 1); - - argv[0] = newPath; -#ifdef _WIN32 - const intptr_t ret = _spawnvp(_P_WAIT, newPath, argv); - if (ret == -1) { - fprintf(stderr, "Error while executing \"%s\" tool.\n", newPath); - return 3; - } - return ret; -#else - execvp(newPath, argv); - fprintf(stderr, "Error while executing \"%s\" tool.\n", newPath); - return 3; -#endif -} - diff --git a/src/assistant/qcollectiongenerator/qcollectiongenerator.pro b/src/assistant/qcollectiongenerator/qcollectiongenerator.pro deleted file mode 100644 index 491c8f927a..0000000000 --- a/src/assistant/qcollectiongenerator/qcollectiongenerator.pro +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG += console -CONFIG -= qt app_bundle -SOURCES += main.c - -QMAKE_TARGET_DESCRIPTION = "Qt Help Collection File Generator" -load(qt_tool) - diff --git a/src/assistant/qhelpgenerator/CMakeLists.txt b/src/assistant/qhelpgenerator/CMakeLists.txt new file mode 100644 index 0000000000..688d4bcc9a --- /dev/null +++ b/src/assistant/qhelpgenerator/CMakeLists.txt @@ -0,0 +1,27 @@ +# Generated from qhelpgenerator.pro. + +##################################################################### +## qhelpgenerator Tool: +##################################################################### + +qt_get_tool_target_name(target_name qhelpgenerator) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Compressed Help File Generator" + TOOLS_TARGET Tools # special case + SOURCES + ../shared/collectionconfiguration.cpp ../shared/collectionconfiguration.h + collectionconfigreader.cpp collectionconfigreader.h + helpgenerator.cpp helpgenerator.h + main.cpp + qhelpdatainterface.cpp qhelpdatainterface_p.h + qhelpprojectdata.cpp qhelpprojectdata_p.h + PUBLIC_LIBRARIES + Qt::Gui + Qt::HelpPrivate + Qt::Network +) + +#### Keys ignored in scope 1:.:.:qhelpgenerator.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Compressed Help File Generator" +# QTPLUGIN.platforms = "qminimal" +# QTPLUGIN.sqldrivers = "qsqlite" diff --git a/src/assistant/qhelpgenerator/collectionconfigreader.cpp b/src/assistant/qhelpgenerator/collectionconfigreader.cpp index 155430c9c5..4928b695e3 100644 --- a/src/assistant/qhelpgenerator/collectionconfigreader.cpp +++ b/src/assistant/qhelpgenerator/collectionconfigreader.cpp @@ -126,7 +126,7 @@ void CollectionConfigReader::readAssistantSettings() readMenuTexts(); } else if (name() == QLatin1String("aboutDialog")) { readAboutDialog(); - } else if (name() == "cacheDirectory") { + } else if (name() == u"cacheDirectory") { m_cacheDirRelativeToCollection = attributes().value(QLatin1String("base")) == QLatin1String("collection"); diff --git a/src/assistant/qhelpgenerator/helpgenerator.cpp b/src/assistant/qhelpgenerator/helpgenerator.cpp index feab1e2d5d..47a11163f4 100644 --- a/src/assistant/qhelpgenerator/helpgenerator.cpp +++ b/src/assistant/qhelpgenerator/helpgenerator.cpp @@ -46,11 +46,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include #include @@ -484,10 +484,10 @@ bool HelpGeneratorPrivate::insertFiles(const QStringList &files, const QString & QByteArray data = fi.readAll(); if (fileName.endsWith(QLatin1String(".html")) || fileName.endsWith(QLatin1String(".htm"))) { - charSet = QHelpGlobal::codecFromData(data); - QTextStream stream(&data); - stream.setCodec(QTextCodec::codecForName(charSet.toLatin1().constData())); - title = QHelpGlobal::documentTitle(stream.readAll()); + auto encoding = QStringDecoder::encodingForHtml(data); + if (!encoding) + encoding = QStringDecoder::Utf8; + title = QHelpGlobal::documentTitle(QStringDecoder(*encoding)(data)); } else { title = fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1); } @@ -807,15 +807,17 @@ bool HelpGeneratorPrivate::checkLinks(const QHelpProjectData &helpData) emit warning(tr("File \"%1\" cannot be opened.").arg(fileName)); continue; } - const QRegExp linkPattern(QLatin1String("<(?:a href|img src)=\"?([^#\">]+)[#\">]")); - QTextStream stream(&htmlFile); - const QString codec = QHelpGlobal::codecFromData(htmlFile.read(1000)); - stream.setCodec(QTextCodec::codecForName(codec.toLatin1().constData())); - const QString &content = stream.readAll(); + const QRegularExpression linkPattern(QLatin1String("<(?:a href|img src)=\"?([^#\">]+)[#\">]")); + QByteArray data = htmlFile.readAll(); + auto encoding = QStringDecoder::encodingForHtml(data); + if (!encoding) + encoding = QStringDecoder::Utf8; + const QString &content = QStringDecoder(*encoding)(data); QStringList invalidLinks; - for (int pos = linkPattern.indexIn(content); pos != -1; - pos = linkPattern.indexIn(content, pos + 1)) { - const QString &linkedFileName = linkPattern.cap(1); + QRegularExpressionMatch match; + int pos = 0; + while ((match = linkPattern.match(content, pos)).hasMatch()) { + const QString &linkedFileName = match.captured(1); if (linkedFileName.contains(QLatin1String("://"))) continue; const QString &curDir = QFileInfo(fileName).dir().path(); @@ -828,6 +830,7 @@ bool HelpGeneratorPrivate::checkLinks(const QHelpProjectData &helpData) allLinksOk = false; invalidLinks.append(canonicalLinkedFileName); } + pos = match.capturedEnd(); } } diff --git a/src/assistant/qhelpgenerator/main.cpp b/src/assistant/qhelpgenerator/main.cpp index ec8079c476..c4fae724c7 100644 --- a/src/assistant/qhelpgenerator/main.cpp +++ b/src/assistant/qhelpgenerator/main.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include @@ -102,6 +102,7 @@ int generateCollectionFile(const QByteArray &data, const QString &basePath, cons } QHelpEngineCore helpEngine(outputFile); + helpEngine.setReadOnly(false); if (!helpEngine.setupData()) { fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); return 1; @@ -194,10 +195,8 @@ int generateCollectionFile(const QByteArray &data, const QString &basePath, cons QDataStream s(&ba, QIODevice::WriteOnly); QMap imgData; - QRegExp srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>")); - srcRegExp.setMinimal(true); - QRegExp imgRegExp(QLatin1String("(]+>)")); - imgRegExp.setMinimal(true); + QRegularExpression srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>"), QRegularExpression::InvertedGreedinessOption); + QRegularExpression imgRegExp(QLatin1String("(]+>)"), QRegularExpression::InvertedGreedinessOption); const QMap &aboutMenuTexts = config.aboutTextFiles(); for (auto it = aboutMenuTexts.cbegin(), end = aboutMenuTexts.cend(); it != end; ++it) { @@ -213,14 +212,15 @@ int generateCollectionFile(const QByteArray &data, const QString &basePath, cons QString contents = QString::fromUtf8(data); int pos = 0; - while ((pos = imgRegExp.indexIn(contents, pos)) != -1) { - QString imgTag = imgRegExp.cap(1); - pos += imgRegExp.matchedLength(); + QRegularExpressionMatch match; + while ((match = imgRegExp.match(contents, pos)).hasMatch()) { + QString imgTag = match.captured(1); + pos = match.capturedEnd(); - if (srcRegExp.indexIn(imgTag, 0) != -1) { - QString src = srcRegExp.cap(2); + if ((match = srcRegExp.match(imgTag)).hasMatch()) { + QString src = match.captured(2); if (src.isEmpty()) - src = srcRegExp.cap(3); + src = match.captured(3); QFile img(fi.absolutePath() + QDir::separator() + src); if (img.open(QIODevice::ReadOnly)) { @@ -266,7 +266,7 @@ int main(int argc, char *argv[]) QTranslator qtTranslator; QTranslator qt_helpTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir) && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) { diff --git a/src/assistant/qhelpgenerator/qhelpgenerator.pro b/src/assistant/qhelpgenerator/qhelpgenerator.pro deleted file mode 100644 index dabd87ccce..0000000000 --- a/src/assistant/qhelpgenerator/qhelpgenerator.pro +++ /dev/null @@ -1,19 +0,0 @@ -QT += network help-private - -QTPLUGIN.platforms = qminimal - -SOURCES += ../shared/collectionconfiguration.cpp \ - helpgenerator.cpp \ - collectionconfigreader.cpp \ - qhelpprojectdata.cpp \ - qhelpdatainterface.cpp \ - main.cpp - -HEADERS += ../shared/collectionconfiguration.h \ - helpgenerator.h \ - collectionconfigreader.h \ - qhelpprojectdata_p.h \ - qhelpdatainterface_p.h - -QMAKE_TARGET_DESCRIPTION = "Qt Compressed Help File Generator" -load(qt_tool) diff --git a/src/assistant/qhelpgenerator/qhelpprojectdata.cpp b/src/assistant/qhelpgenerator/qhelpprojectdata.cpp index 23419bfd9a..5b7d84e9ce 100644 --- a/src/assistant/qhelpgenerator/qhelpprojectdata.cpp +++ b/src/assistant/qhelpgenerator/qhelpprojectdata.cpp @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include #include #include @@ -318,13 +318,14 @@ void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) bool matchFound = false; #ifdef Q_OS_WIN - Qt::CaseSensitivity cs = Qt::CaseInsensitive; + auto cs = QRegularExpression::CaseInsensitiveOption; #else - Qt::CaseSensitivity cs = Qt::CaseSensitive; + auto cs = QRegularExpression::NoPatternOption; #endif - const QRegExp regExp(fileInfo.fileName(), cs, QRegExp::Wildcard); + const QRegularExpression regExp(QRegularExpression::wildcardToRegularExpression(fileInfo.fileName()), cs); for (const QString &file : entries) { - if (regExp.exactMatch(file)) { + auto match = regExp.match(file); + if (match.hasMatch()) { matchFound = true; filterSectionList.last(). addFile(QFileInfo(pattern).dir().path() + QLatin1Char('/') + file); diff --git a/src/assistant/shared/collectionconfiguration.cpp b/src/assistant/shared/collectionconfiguration.cpp index a1b63c9bdf..562cbfaabc 100644 --- a/src/assistant/shared/collectionconfiguration.cpp +++ b/src/assistant/shared/collectionconfiguration.cpp @@ -239,7 +239,7 @@ void CollectionConfiguration::setDefaultHomePage(QHelpEngineCore &helpEngine, const QStringList CollectionConfiguration::lastShownPages(const QHelpEngineCore &helpEngine) { return helpEngine.customValue(LastShownPagesKey).toString(). - split(ListSeparator, QString::SkipEmptyParts); + split(ListSeparator, Qt::SkipEmptyParts); } void CollectionConfiguration::setLastShownPages(QHelpEngineCore &helpEngine, @@ -252,7 +252,7 @@ void CollectionConfiguration::setLastShownPages(QHelpEngineCore &helpEngine, const QStringList CollectionConfiguration::lastZoomFactors(const QHelpEngineCore &helpEngine) { return helpEngine.customValue(LastZoomFactorsKey).toString(). - split(ListSeparator, QString::SkipEmptyParts); + split(ListSeparator, Qt::SkipEmptyParts); } void CollectionConfiguration::setLastZoomFactors(QHelpEngineCore &helpEngine, diff --git a/src/designer/CMakeLists.txt b/src/designer/CMakeLists.txt new file mode 100644 index 0000000000..35b6eeace2 --- /dev/null +++ b/src/designer/CMakeLists.txt @@ -0,0 +1,6 @@ +# Generated from designer.pro. + +if(NOT QT_FEATURE_designer) + return() +endif() +add_subdirectory(src) diff --git a/src/designer/data/generate_header.xsl b/src/designer/data/generate_header.xsl index 334d3a73c9..af39044be4 100644 --- a/src/designer/data/generate_header.xsl +++ b/src/designer/data/generate_header.xsl @@ -310,7 +310,7 @@ class QDESIGNER_UILIB_EXPORT - {&endl; Q_DISABLE_COPY( + {&endl; Q_DISABLE_COPY_MOVE( )&endl; public:&endl; @@ -421,7 +421,6 @@ #include <qlist.h> #include <qstring.h> #include <qstringlist.h> -#include <qvector.h> #include <qxmlstream.h> #include <qglobal.h> diff --git a/src/designer/data/generate_impl.xsl b/src/designer/data/generate_impl.xsl index da7a043b21..2002c71a17 100644 --- a/src/designer/data/generate_impl.xsl +++ b/src/designer/data/generate_impl.xsl @@ -194,7 +194,7 @@ const QXmlStreamAttributes &attributes = reader.attributes();&endl; for (const QXmlStreamAttribute &attribute : attributes) {&endl; - const QStringRef name = attribute.name();&endl; + const auto name = attribute.name();&endl; @@ -347,7 +347,7 @@ while (!reader.hasError()) {&endl; switch (reader.readNext()) {&endl; case QXmlStreamReader::StartElement : {&endl; - const QStringRef tag = reader.name();&endl; + const auto tag = reader.name();&endl; diff --git a/src/designer/data/generate_shared.xsl b/src/designer/data/generate_shared.xsl index 3ac05a42ba..38269cd615 100644 --- a/src/designer/data/generate_shared.xsl +++ b/src/designer/data/generate_shared.xsl @@ -260,11 +260,7 @@ QList<qlonglong> QList<uint> QList<qulonglong> - - QList<DomProperty *> - QVector<Dom *> + QList<Dom *> @@ -297,8 +293,7 @@ QList<qlonglong> QList<uint> QList<qulonglong> - QList<DomProperty*> - QVector<Dom *> + QList<Dom *> @@ -331,8 +326,7 @@ const QList<qlonglong> & const QList<uint> & const QList<qulonglong> & - const QList<DomProperty *> & - const QVector<Dom *> & + const QList<Dom *> & diff --git a/src/designer/data/ui4.xsd b/src/designer/data/ui4.xsd index 8448a62b40..e1dc35d493 100644 --- a/src/designer/data/ui4.xsd +++ b/src/designer/data/ui4.xsd @@ -27,6 +27,7 @@ + diff --git a/src/designer/designer.pro b/src/designer/designer.pro deleted file mode 100644 index be734fb115..0000000000 --- a/src/designer/designer.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = src diff --git a/src/designer/src/CMakeLists.txt b/src/designer/src/CMakeLists.txt new file mode 100644 index 0000000000..32fb45160d --- /dev/null +++ b/src/designer/src/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated from src.pro. + + +qt_exclude_tool_directories_from_default_target( + lib + components + designer + plugins +) + +add_subdirectory(uiplugin) +add_subdirectory(uitools) +if(QT_FEATURE_process) + add_subdirectory(lib) + add_subdirectory(components) + add_subdirectory(designer) +endif() +if(QT_BUILD_SHARED_LIBS AND QT_FEATURE_process) + add_subdirectory(plugins) +endif() diff --git a/src/designer/src/components/CMakeLists.txt b/src/designer/src/components/CMakeLists.txt new file mode 100644 index 0000000000..df5b03f92a --- /dev/null +++ b/src/designer/src/components/CMakeLists.txt @@ -0,0 +1,3 @@ +# Generated from components.pro. + +add_subdirectory(lib) diff --git a/src/designer/src/components/buddyeditor/buddyeditor.cpp b/src/designer/src/components/buddyeditor/buddyeditor.cpp index 7593326db7..38a865cee3 100644 --- a/src/designer/src/components/buddyeditor/buddyeditor.cpp +++ b/src/designer/src/components/buddyeditor/buddyeditor.cpp @@ -40,12 +40,15 @@ #include #include -#include #include #include -#include #include +#include + +#include +#include + #include QT_BEGIN_NAMESPACE @@ -83,8 +86,6 @@ static QString buddy(QLabel *label, QDesignerFormEditorInterface *core) return sheet->property(prop_idx).toString(); } -using LabelList = QList; - namespace qdesigner_internal { /******************************************************************************* @@ -144,7 +145,7 @@ void BuddyEditor::updateBackground() m_updating = true; QList newList; - const LabelList label_list = background()->findChildren(); + const auto label_list = background()->findChildren(); for (QLabel *label : label_list) { const QString buddy_name = buddy(label, m_formWindow->core()); if (buddy_name.isEmpty()) @@ -211,8 +212,10 @@ void BuddyEditor::setBackground(QWidget *background) { clear(); ConnectionEdit::setBackground(background); + if (background == nullptr) + return; - const LabelList label_list = background->findChildren(); + const auto label_list = background->findChildren(); for (QLabel *label : label_list) { const QString buddy_name = buddy(label, m_formWindow->core()); if (buddy_name.isEmpty()) @@ -328,8 +331,8 @@ void BuddyEditor::deleteSelected() void BuddyEditor::autoBuddy() { // Any labels? - LabelList labelList = background()->findChildren(); - if (labelList.empty()) + auto labelList = background()->findChildren(); + if (labelList.isEmpty()) return; // Find already used buddies QWidgetList usedBuddies; @@ -338,7 +341,7 @@ void BuddyEditor::autoBuddy() usedBuddies.push_back(c->widget(EndPoint::Target)); // Find potential new buddies, keep lists in sync QWidgetList buddies; - for (LabelList::iterator it = labelList.begin(); it != labelList.end(); ) { + for (auto it = labelList.begin(); it != labelList.end(); ) { QLabel *label = *it; QWidget *newBuddy = nullptr; if (m_formWindow->isManaged(label)) { @@ -355,7 +358,7 @@ void BuddyEditor::autoBuddy() } } // Add the list in one go. - if (labelList.empty()) + if (labelList.isEmpty()) return; const int count = labelList.size(); Q_ASSERT(count == buddies.size()); diff --git a/src/designer/src/components/buddyeditor/buddyeditor.pri b/src/designer/src/components/buddyeditor/buddyeditor.pri deleted file mode 100644 index b6e9614c11..0000000000 --- a/src/designer/src/components/buddyeditor/buddyeditor.pri +++ /dev/null @@ -1,17 +0,0 @@ - -QT += xml - -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/buddyeditor.h \ - $$PWD/buddyeditor_plugin.h \ - $$PWD/buddyeditor_tool.h \ - $$PWD/buddyeditor_global.h - -SOURCES += \ - $$PWD/buddyeditor.cpp \ - $$PWD/buddyeditor_tool.cpp \ - $$PWD/buddyeditor_plugin.cpp - -OTHER_FILES += $$PWD/buddyeditor.json diff --git a/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp b/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp index ec7a13941f..868c52125f 100644 --- a/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp +++ b/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include +#include #include "buddyeditor_plugin.h" #include "buddyeditor_tool.h" diff --git a/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp b/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp index 51b6e49883..2cbb5ec8be 100644 --- a/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp +++ b/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp @@ -31,7 +31,7 @@ #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/components.pro b/src/designer/src/components/components.pro deleted file mode 100644 index dac34e57f8..0000000000 --- a/src/designer/src/components/components.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = lib diff --git a/src/designer/src/components/formeditor/default_actionprovider.cpp b/src/designer/src/components/formeditor/default_actionprovider.cpp index 663ce87316..6a479e4b1a 100644 --- a/src/designer/src/components/formeditor/default_actionprovider.cpp +++ b/src/designer/src/components/formeditor/default_actionprovider.cpp @@ -30,8 +30,10 @@ #include "invisible_widget_p.h" #include "qdesigner_toolbar_p.h" -#include #include + +#include + #include #include diff --git a/src/designer/src/components/formeditor/default_container.h b/src/designer/src/components/formeditor/default_container.h index f79fbd6e57..3781d713d1 100644 --- a/src/designer/src/components/formeditor/default_container.h +++ b/src/designer/src/components/formeditor/default_container.h @@ -57,8 +57,10 @@ class QStackedWidgetContainer: public QObject, public QDesignerContainerExtensio int currentIndex() const override { return m_widget->currentIndex(); } void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; private: @@ -79,8 +81,10 @@ class QTabWidgetContainer: public QObject, public QDesignerContainerExtension int currentIndex() const override { return m_widget->currentIndex(); } void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; private: @@ -101,8 +105,10 @@ class QToolBoxContainer: public QObject, public QDesignerContainerExtension int currentIndex() const override { return m_widget->currentIndex(); } void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; private: diff --git a/src/designer/src/components/formeditor/deviceprofiledialog.cpp b/src/designer/src/components/formeditor/deviceprofiledialog.cpp index 40a9e6ab6f..ef1693c39b 100644 --- a/src/designer/src/components/formeditor/deviceprofiledialog.cpp +++ b/src/designer/src/components/formeditor/deviceprofiledialog.cpp @@ -73,7 +73,7 @@ DeviceProfileDialog::DeviceProfileDialog(QDesignerDialogGuiInterface *dlgGui, QW setModal(true); m_ui->setupUi(this); - const QList standardFontSizes = QFontDatabase::standardSizes(); + const auto standardFontSizes = QFontDatabase::standardSizes(); populateNumericCombo(standardFontSizes.constBegin(), standardFontSizes.constEnd(), m_ui->m_systemFontSizeCombo); // 288pt observed on macOS. diff --git a/src/designer/src/components/formeditor/deviceprofiledialog.h b/src/designer/src/components/formeditor/deviceprofiledialog.h index e44ba06636..ebccd31d96 100644 --- a/src/designer/src/components/formeditor/deviceprofiledialog.h +++ b/src/designer/src/components/formeditor/deviceprofiledialog.h @@ -76,7 +76,7 @@ private slots: void setOkButtonEnabled(bool); void nameChanged(const QString &name); void save(); - void open(); + void open() override; private: void critical(const QString &title, const QString &msg); diff --git a/src/designer/src/components/formeditor/dpi_chooser.cpp b/src/designer/src/components/formeditor/dpi_chooser.cpp index 5e2f9f6059..8155016c0c 100644 --- a/src/designer/src/components/formeditor/dpi_chooser.cpp +++ b/src/designer/src/components/formeditor/dpi_chooser.cpp @@ -94,7 +94,7 @@ DPI_Chooser::DPI_Chooser(QWidget *parent) : setFocusProxy(m_predefinedCombo); m_predefinedCombo->setEditable(false); m_predefinedCombo->setCurrentIndex(0); - connect(m_predefinedCombo, QOverload::of(&QComboBox::currentIndexChanged), + connect(m_predefinedCombo, &QComboBox::currentIndexChanged, this, &DPI_Chooser::syncSpinBoxes); // top row with predefined settings QVBoxLayout *vBoxLayout = new QVBoxLayout; @@ -145,7 +145,7 @@ void DPI_Chooser::setDPI(int dpiX, int dpiY) int predefinedIndex = -1; for (int i = 0; i < count; i++) { const QVariant data = m_predefinedCombo->itemData(i); - if (data.type() != QVariant::Invalid) { + if (data.metaType().id() != QMetaType::UnknownType) { const struct DPI_Entry *entry = qvariant_cast(data); if (entry->dpiX == dpiX && entry->dpiY == dpiY) { predefinedIndex = i; @@ -178,7 +178,7 @@ void DPI_Chooser::syncSpinBoxes() const QVariant data = m_predefinedCombo->itemData(predefIdx); // Predefined mode in which spin boxes are disabled or user defined? - const bool userSetting = data.type() == QVariant::Invalid; + const bool userSetting = data.metaType().id() == QMetaType::UnknownType; m_dpiXSpinBox->setEnabled(userSetting); m_dpiYSpinBox->setEnabled(userSetting); diff --git a/src/designer/src/components/formeditor/embeddedoptionspage.cpp b/src/designer/src/components/formeditor/embeddedoptionspage.cpp index 96a6c7c4a0..4a1c270352 100644 --- a/src/designer/src/components/formeditor/embeddedoptionspage.cpp +++ b/src/designer/src/components/formeditor/embeddedoptionspage.cpp @@ -52,6 +52,7 @@ #include #include +#include #include @@ -144,7 +145,7 @@ void EmbeddedOptionsControlPrivate::init(EmbeddedOptionsControl *q) m_profileCombo->setEditable(false); hLayout->addWidget(m_profileCombo); m_profileCombo->addItem(EmbeddedOptionsControl::tr("None")); - EmbeddedOptionsControl::connect(m_profileCombo, QOverload::of(&QComboBox::currentIndexChanged), + EmbeddedOptionsControl::connect(m_profileCombo, &QComboBox::currentIndexChanged, m_q, &EmbeddedOptionsControl::slotProfileIndexChanged); m_addButton->setIcon(createIconSet(QString::fromUtf8("plus.png"))); @@ -265,7 +266,7 @@ void EmbeddedOptionsControlPrivate::sortAndPopulateProfileCombo() // Clear items until only "None" is left for (int i = m_profileCombo->count() - 1; i > 0; i--) m_profileCombo->removeItem(i); - if (!m_sortedProfiles.empty()) { + if (!m_sortedProfiles.isEmpty()) { std::sort(m_sortedProfiles.begin(), m_sortedProfiles.end(), deviceProfileLessThan); m_profileCombo->addItems(existingProfileNames()); } diff --git a/src/designer/src/components/formeditor/formeditor.cpp b/src/designer/src/components/formeditor/formeditor.cpp index 335241e5fc..05e7fc4eee 100644 --- a/src/designer/src/components/formeditor/formeditor.cpp +++ b/src/designer/src/components/formeditor/formeditor.cpp @@ -44,6 +44,7 @@ #include "spacer_propertysheet.h" #include "line_propertysheet.h" #include "layout_propertysheet.h" +#include "qdesigner_dockwidget_p.h" #include "qdesigner_stackedbox_p.h" #include "qdesigner_toolbox_p.h" #include "qdesigner_tabwidget_p.h" @@ -111,6 +112,7 @@ FormEditor::FormEditor(QObject *parent) QMenuActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); QDesignerDefaultPropertySheetFactory::registerExtension(mgr); + QDockWidgetPropertySheetFactory::registerExtension(mgr); QLayoutWidgetPropertySheetFactory::registerExtension(mgr); SpacerPropertySheetFactory::registerExtension(mgr); LinePropertySheetFactory::registerExtension(mgr); diff --git a/src/designer/src/components/formeditor/formeditor.pri b/src/designer/src/components/formeditor/formeditor.pri deleted file mode 100644 index 7e4afd021c..0000000000 --- a/src/designer/src/components/formeditor/formeditor.pri +++ /dev/null @@ -1,67 +0,0 @@ - -QT += xml - -INCLUDEPATH += $$PWD - -FORMS += $$PWD/deviceprofiledialog.ui \ - $$PWD/formwindowsettings.ui \ - $$PWD/templateoptionspage.ui - -HEADERS += $$PWD/qdesigner_resource.h \ - $$PWD/formwindow.h \ - $$PWD/formwindow_widgetstack.h \ - $$PWD/formwindow_dnditem.h \ - $$PWD/formwindowcursor.h \ - $$PWD/widgetselection.h \ - $$PWD/formwindowmanager.h \ - $$PWD/formeditor.h \ - $$PWD/formeditor_global.h \ - $$PWD/qlayoutwidget_propertysheet.h \ - $$PWD/layout_propertysheet.h \ - $$PWD/spacer_propertysheet.h \ - $$PWD/line_propertysheet.h \ - $$PWD/default_container.h \ - $$PWD/default_actionprovider.h \ - $$PWD/qmainwindow_container.h \ - $$PWD/qmdiarea_container.h \ - $$PWD/qwizard_container.h \ - $$PWD/default_layoutdecoration.h \ - $$PWD/tool_widgeteditor.h \ - $$PWD/formeditor_optionspage.h \ - $$PWD/embeddedoptionspage.h \ - $$PWD/formwindowsettings.h \ - $$PWD/deviceprofiledialog.h \ - $$PWD/dpi_chooser.h \ - $$PWD/previewactiongroup.h \ - $$PWD/itemview_propertysheet.h \ - $$PWD/templateoptionspage.h - -SOURCES += $$PWD/qdesigner_resource.cpp \ - $$PWD/formwindow.cpp \ - $$PWD/formwindow_widgetstack.cpp \ - $$PWD/formwindow_dnditem.cpp \ - $$PWD/formwindowcursor.cpp \ - $$PWD/widgetselection.cpp \ - $$PWD/formwindowmanager.cpp \ - $$PWD/formeditor.cpp \ - $$PWD/qlayoutwidget_propertysheet.cpp \ - $$PWD/layout_propertysheet.cpp \ - $$PWD/spacer_propertysheet.cpp \ - $$PWD/line_propertysheet.cpp \ - $$PWD/qmainwindow_container.cpp \ - $$PWD/qmdiarea_container.cpp \ - $$PWD/qwizard_container.cpp \ - $$PWD/default_container.cpp \ - $$PWD/default_layoutdecoration.cpp \ - $$PWD/default_actionprovider.cpp \ - $$PWD/tool_widgeteditor.cpp \ - $$PWD/formeditor_optionspage.cpp \ - $$PWD/embeddedoptionspage.cpp \ - $$PWD/formwindowsettings.cpp \ - $$PWD/deviceprofiledialog.cpp \ - $$PWD/dpi_chooser.cpp \ - $$PWD/previewactiongroup.cpp \ - $$PWD/itemview_propertysheet.cpp \ - $$PWD/templateoptionspage.cpp - -RESOURCES += $$PWD/formeditor.qrc diff --git a/src/designer/src/components/formeditor/formeditor_optionspage.cpp b/src/designer/src/components/formeditor/formeditor_optionspage.cpp index 03bc44d150..c7ca46b42f 100644 --- a/src/designer/src/components/formeditor/formeditor_optionspage.cpp +++ b/src/designer/src/components/formeditor/formeditor_optionspage.cpp @@ -70,7 +70,7 @@ ZoomSettingsWidget::ZoomSettingsWidget(QWidget *parent) : m_zoomCombo(new QComboBox) { m_zoomCombo->setEditable(false); - const QVector &zoomValues = ZoomMenu::zoomValues(); + const QList &zoomValues = ZoomMenu::zoomValues(); for (int z : zoomValues) { //: Zoom percentage m_zoomCombo->addItem(QCoreApplication::translate("FormEditorOptionsPage", "%1 %").arg(z), QVariant(z)); diff --git a/src/designer/src/components/formeditor/formwindow.cpp b/src/designer/src/components/formeditor/formwindow.cpp index 464d7f618c..dda88489f0 100644 --- a/src/designer/src/components/formeditor/formwindow.cpp +++ b/src/designer/src/components/formeditor/formwindow.cpp @@ -72,22 +72,11 @@ #include -#include -#include -#include -#include #include -#include -#include -#if QT_CONFIG(clipboard) -#include -#endif -#include #include #include #include #include -#include #include #include #include @@ -95,6 +84,20 @@ #include #include +#include +#include +#if QT_CONFIG(clipboard) +# include +#endif +#include +#include + +#include +#include +#include +#include +#include + Q_DECLARE_METATYPE(QWidget*) QT_BEGIN_NAMESPACE @@ -178,7 +181,7 @@ FormWindow::Selection::~Selection() void FormWindow::Selection::clear() { - if (!m_usedSelections.empty()) { + if (!m_usedSelections.isEmpty()) { for (auto it = m_usedSelections.begin(), mend = m_usedSelections.end(); it != mend; ++it) it.value()->setWidget(nullptr); m_usedSelections.clear(); @@ -595,21 +598,21 @@ bool FormWindow::handleMousePressEvent(QWidget * widget, QWidget *managedWidget, core()->formWindowManager()->setActiveFormWindow(this); const Qt::MouseButtons buttons = e->buttons(); - if (buttons != Qt::LeftButton && buttons != Qt::MidButton) + if (buttons != Qt::LeftButton && buttons != Qt::MiddleButton) return true; - m_startPos = mapFromGlobal(e->globalPos()); + m_startPos = mapFromGlobal(e->globalPosition().toPoint()); if (debugFormWindow) qDebug() << "handleMousePressEvent:" << widget << ',' << managedWidget; - if (buttons == Qt::MidButton || isMainContainer(managedWidget)) { // press was on the formwindow + if (buttons == Qt::MiddleButton || isMainContainer(managedWidget)) { // press was on the formwindow clearObjectInspectorSelection(m_core); // We might have a toolbar or non-widget selected in the object inspector. clearSelection(false); m_mouseState = MouseDrawRubber; m_currRect = QRect(); - startRectDraw(mapFromGlobal(e->globalPos()), this, Rubber); + startRectDraw(mapFromGlobal(e->globalPosition().toPoint()), this, Rubber); return true; } if (buttons != Qt::LeftButton) @@ -660,7 +663,7 @@ bool FormWindow::handleMouseMoveEvent(QWidget *, QWidget *, QMouseEvent *e) if (m_startPos.isNull()) return true; - const QPoint pos = mapFromGlobal(e->globalPos()); + const QPoint pos = mapFromGlobal(e->globalPosition().toPoint()); switch (m_mouseState) { case MouseDrawRubber: // Rubber band with left/middle mouse @@ -684,6 +687,7 @@ bool FormWindow::handleMouseMoveEvent(QWidget *, QWidget *, QMouseEvent *e) const bool blocked = blockSelectionChanged(true); QWidgetList sel = selectedWidgets(); + const QWidgetList originalSelection = sel; simplifySelection(&sel); QSet widget_set; @@ -733,9 +737,14 @@ bool FormWindow::handleMouseMoveEvent(QWidget *, QWidget *, QMouseEvent *e) } } + // In case when we have reduced the selection (by calling simplifySelection() + // beforehand) we still need to hide selection handles for children widgets + for (auto *widget : originalSelection) + m_selection->hide(widget); + blockSelectionChanged(blocked); - if (!sel.empty()) // reshow selection? + if (!sel.isEmpty()) // reshow selection? if (QDesignerMimeData::execDrag(item_list, core()->topLevel()) == Qt::IgnoreAction && dropType == QDesignerDnDItemInterface::MoveDrop) for (QWidget *widget : qAsConst(sel)) m_selection->show(widget); @@ -781,7 +790,7 @@ bool FormWindow::handleMouseReleaseEvent(QWidget *w, QWidget *mw, QMouseEvent *e * MousePressEvent. */ switch (e->button()) { case Qt::LeftButton: - case Qt::MidButton: + case Qt::MiddleButton: case Qt::RightButton: emitSelectionChanged(); break; @@ -940,7 +949,7 @@ bool FormWindow::isMainContainer(const QWidget *w) const void FormWindow::updateChildSelections(QWidget *w) { const QWidgetList l = w->findChildren(); - if (!l.empty()) { + if (!l.isEmpty()) { const QWidgetList::const_iterator lcend = l.constEnd(); for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) { QWidget *w = *it; @@ -1150,19 +1159,19 @@ bool FormWindow::unify(QObject *w, QString &s, bool changeIt) const QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); const QWidgetList widgetChildren = main->findChildren(); - if (!widgetChildren.empty()) + if (!widgetChildren.isEmpty()) insertNames(metaDataBase, widgetChildren.constBegin(), widgetChildren.constEnd(), w, existingNames); - const QList layoutChildren = main->findChildren(); - if (!layoutChildren.empty()) + const auto layoutChildren = main->findChildren(); + if (!layoutChildren.isEmpty()) insertNames(metaDataBase, layoutChildren.constBegin(), layoutChildren.constEnd(), w, existingNames); - const QList actionChildren = main->findChildren(); - if (!actionChildren.empty()) + const auto actionChildren = main->findChildren(); + if (!actionChildren.isEmpty()) insertNames(metaDataBase, actionChildren.constBegin(), actionChildren.constEnd(), w, existingNames); - const QList buttonGroupChildren = main->findChildren(); - if (!buttonGroupChildren.empty()) + const auto buttonGroupChildren = main->findChildren(); + if (!buttonGroupChildren.isEmpty()) insertNames(metaDataBase, buttonGroupChildren.constBegin(), buttonGroupChildren.constEnd(), w, existingNames); const StringSet::const_iterator enEnd = existingNames.constEnd(); @@ -1223,8 +1232,19 @@ void FormWindow::insertWidget(QWidget *w, const QRect &rect, QWidget *container, m_undoStack.push(geom_cmd); - InsertWidgetCommand *cmd = new InsertWidgetCommand(this); - cmd->init(w, already_in_form); + QUndoCommand *cmd = nullptr; + if (auto dockWidget = qobject_cast(w)) { + if (auto mainWindow = qobject_cast(container)) { + auto addDockCmd = new AddDockWidgetCommand(this); + addDockCmd->init(mainWindow, dockWidget); + cmd = addDockCmd; + } + } + if (cmd == nullptr) { + auto insertCmd = new InsertWidgetCommand(this); + insertCmd->init(w, already_in_form); + cmd = insertCmd; + } m_undoStack.push(cmd); endCommand(); @@ -1695,7 +1715,7 @@ QWidget *FormWindow::containerForPaste() const // Try to find a close parent, for example a non-laid-out // QFrame/QGroupBox when a widget within it is selected. QWidgetList selection = selectedWidgets(); - if (selection.empty()) + if (selection.isEmpty()) break; simplifySelection(&selection); @@ -1779,6 +1799,7 @@ static inline QString pasteCommandDescription(int widgetCount, int actionCount) return FormWindow::tr("Paste (%1 widgets, %2 actions)").arg(widgetCount).arg(actionCount); } +#if QT_CONFIG(clipboard) static void positionPastedWidgetsAtMousePosition(FormWindow *fw, const QPoint &contextMenuPosition, QWidget *parent, const QWidgetList &l) { // Try to position pasted widgets at mouse position (current mouse position for Ctrl-V or position of context menu) @@ -1811,7 +1832,6 @@ static void positionPastedWidgetsAtMousePosition(FormWindow *fw, const QPoint &c (*it)->move((*it)->pos() + offset); } -#if QT_CONFIG(clipboard) void FormWindow::paste(PasteMode pasteMode) { // Avoid QDesignerResource constructing widgets that are not used as @@ -2252,7 +2272,7 @@ QAction *FormWindow::createSelectAncestorSubMenu(QWidget *w) for (QWidget *p = w->parentWidget(); p && p != mc; p = p->parentWidget()) if (isManaged(p) && !isWidgetSelected(p)) parents.push_back(p); - if (parents.empty()) + if (parents.isEmpty()) return nullptr; // Create a submenu listing the managed, unselected parents QMenu *menu = new QMenu; @@ -2296,11 +2316,15 @@ QMenu *FormWindow::createPopupMenu(QWidget *w) popup->addAction(manager->action(QDesignerFormWindowManagerInterface::RaiseAction)); popup->addSeparator(); } +#if QT_CONFIG(clipboard) popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CutAction)); popup->addAction(manager->action(QDesignerFormWindowManagerInterface::CopyAction)); +#endif } +#if QT_CONFIG(clipboard) popup->addAction(manager->action(QDesignerFormWindowManagerInterface::PasteAction)); +#endif if (QAction *selectAncestorAction = createSelectAncestorSubMenu(w)) popup->addAction(selectAncestorAction); @@ -2413,8 +2437,7 @@ void FormWindow::simplifySelection(QWidgetList *sel) const sel->push_back(mainC); return; } - using WidgetVector = QVector; - WidgetVector toBeRemoved; + QWidgetList toBeRemoved; toBeRemoved.reserve(sel->size()); const QWidgetList::const_iterator scend = sel->constEnd(); for (QWidgetList::const_iterator it = sel->constBegin(); it != scend; ++it) { @@ -2433,8 +2456,8 @@ void FormWindow::simplifySelection(QWidgetList *sel) const // Now we can actually remove the widgets that were marked // for removal in the previous pass. if (!toBeRemoved.isEmpty()) { - const WidgetVector::const_iterator rcend = toBeRemoved.constEnd(); - for (WidgetVector::const_iterator it = toBeRemoved.constBegin(); it != rcend; ++it) + const QWidgetList::const_iterator rcend = toBeRemoved.constEnd(); + for (QWidgetList::const_iterator it = toBeRemoved.constBegin(); it != rcend; ++it) sel->removeAll(*it); } } diff --git a/src/designer/src/components/formeditor/formwindow.h b/src/designer/src/components/formeditor/formwindow.h index abecc8252b..a2d16fe5f2 100644 --- a/src/designer/src/components/formeditor/formwindow.h +++ b/src/designer/src/components/formeditor/formwindow.h @@ -33,7 +33,7 @@ #include // Qt -#include +#include #include #include #include diff --git a/src/designer/src/components/formeditor/formwindow_widgetstack.cpp b/src/designer/src/components/formeditor/formwindow_widgetstack.cpp index 18126c1456..da6512211c 100644 --- a/src/designer/src/components/formeditor/formwindow_widgetstack.cpp +++ b/src/designer/src/components/formeditor/formwindow_widgetstack.cpp @@ -29,11 +29,12 @@ #include "formwindow_widgetstack.h" #include -#include -#include -#include #include #include +#include + +#include +#include #include @@ -165,7 +166,7 @@ void FormWindowWidgetStack::addTool(QDesignerFormWindowToolInterface *tool) m_layout->addWidget(w); } else { // The form editor might not have a tool initially, use dummy. Assert on anything else - Q_ASSERT(m_tools.empty()); + Q_ASSERT(m_tools.isEmpty()); m_layout->addWidget(m_formContainer); } diff --git a/src/designer/src/components/formeditor/formwindowmanager.cpp b/src/designer/src/components/formeditor/formwindowmanager.cpp index d1edb231c3..c0f84061a9 100644 --- a/src/designer/src/components/formeditor/formwindowmanager.cpp +++ b/src/designer/src/components/formeditor/formwindowmanager.cpp @@ -60,19 +60,19 @@ #include #include -#include -#include -#include -#include #include #include -#if QT_CONFIG(clipboard) -#include -#endif #include #include -#include #include +#include + +#include +#if QT_CONFIG(clipboard) +# include +#endif +#include +#include #include @@ -410,7 +410,7 @@ void FormWindowManager::setupActions() m_actionRaise = new QAction(createIconSet(QStringLiteral("editraise.png")), tr("Bring to &Front"), this); m_actionRaise->setObjectName(QStringLiteral("__qt_raise_action")); - m_actionRaise->setShortcut(Qt::CTRL + Qt::Key_L); + m_actionRaise->setShortcut(Qt::CTRL | Qt::Key_L); m_actionRaise->setStatusTip(tr("Raises the selected widgets")); m_actionRaise->setWhatsThis(tr("Raises the selected widgets")); connect(m_actionRaise, &QAction::triggered, this, &FormWindowManager::slotActionRaiseActivated); @@ -418,7 +418,7 @@ void FormWindowManager::setupActions() m_actionLower = new QAction(createIconSet(QStringLiteral("editlower.png")), tr("Send to &Back"), this); m_actionLower->setObjectName(QStringLiteral("__qt_lower_action")); - m_actionLower->setShortcut(Qt::CTRL + Qt::Key_K); + m_actionLower->setShortcut(Qt::CTRL | Qt::Key_K); m_actionLower->setStatusTip(tr("Lowers the selected widgets")); m_actionLower->setWhatsThis(tr("Lowers the selected widgets")); connect(m_actionLower, &QAction::triggered, this, &FormWindowManager::slotActionLowerActivated); @@ -426,7 +426,7 @@ void FormWindowManager::setupActions() m_actionAdjustSize = new QAction(createIconSet(QStringLiteral("adjustsize.png")), tr("Adjust &Size"), this); m_actionAdjustSize->setObjectName(QStringLiteral("__qt_adjust_size_action")); - m_actionAdjustSize->setShortcut(Qt::CTRL + Qt::Key_J); + m_actionAdjustSize->setShortcut(Qt::CTRL | Qt::Key_J); m_actionAdjustSize->setStatusTip(tr("Adjusts the size of the selected widget")); m_actionAdjustSize->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Adjust Size"))); connect(m_actionAdjustSize, &QAction::triggered, this, &FormWindowManager::slotActionAdjustSizeActivated); @@ -435,7 +435,7 @@ void FormWindowManager::setupActions() m_actionHorizontalLayout = new QAction(createIconSet(QStringLiteral("edithlayout.png")), tr("Lay Out &Horizontally"), this); m_actionHorizontalLayout->setObjectName(QStringLiteral("__qt_horizontal_layout_action")); - m_actionHorizontalLayout->setShortcut(Qt::CTRL + Qt::Key_1); + m_actionHorizontalLayout->setShortcut(Qt::CTRL | Qt::Key_1); m_actionHorizontalLayout->setStatusTip(tr("Lays out the selected widgets horizontally")); m_actionHorizontalLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Horizontally"))); m_actionHorizontalLayout->setData(LayoutInfo::HBox); @@ -444,7 +444,7 @@ void FormWindowManager::setupActions() m_actionVerticalLayout = new QAction(createIconSet(QStringLiteral("editvlayout.png")), tr("Lay Out &Vertically"), this); m_actionVerticalLayout->setObjectName(QStringLiteral("__qt_vertical_layout_action")); - m_actionVerticalLayout->setShortcut(Qt::CTRL + Qt::Key_2); + m_actionVerticalLayout->setShortcut(Qt::CTRL | Qt::Key_2); m_actionVerticalLayout->setStatusTip(tr("Lays out the selected widgets vertically")); m_actionVerticalLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Vertically"))); m_actionVerticalLayout->setData(LayoutInfo::VBox); @@ -454,7 +454,7 @@ void FormWindowManager::setupActions() QIcon formIcon = QIcon::fromTheme(QStringLiteral("designer-form-layout"), createIconSet(QStringLiteral("editform.png"))); m_actionFormLayout = new QAction(formIcon, tr("Lay Out in a &Form Layout"), this); m_actionFormLayout->setObjectName(QStringLiteral("__qt_form_layout_action")); - m_actionFormLayout->setShortcut(Qt::CTRL + Qt::Key_6); + m_actionFormLayout->setShortcut(Qt::CTRL | Qt::Key_6); m_actionFormLayout->setStatusTip(tr("Lays out the selected widgets in a form layout")); m_actionFormLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out in a Form"))); m_actionFormLayout->setData(LayoutInfo::Form); @@ -463,7 +463,7 @@ void FormWindowManager::setupActions() m_actionGridLayout = new QAction(createIconSet(QStringLiteral("editgrid.png")), tr("Lay Out in a &Grid"), this); m_actionGridLayout->setObjectName(QStringLiteral("__qt_grid_layout_action")); - m_actionGridLayout->setShortcut(Qt::CTRL + Qt::Key_5); + m_actionGridLayout->setShortcut(Qt::CTRL | Qt::Key_5); m_actionGridLayout->setStatusTip(tr("Lays out the selected widgets in a grid")); m_actionGridLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out in a Grid"))); m_actionGridLayout->setData(LayoutInfo::Grid); @@ -473,7 +473,7 @@ void FormWindowManager::setupActions() m_actionSplitHorizontal = new QAction(createIconSet(QStringLiteral("edithlayoutsplit.png")), tr("Lay Out Horizontally in S&plitter"), this); m_actionSplitHorizontal->setObjectName(QStringLiteral("__qt_split_horizontal_action")); - m_actionSplitHorizontal->setShortcut(Qt::CTRL + Qt::Key_3); + m_actionSplitHorizontal->setShortcut(Qt::CTRL | Qt::Key_3); m_actionSplitHorizontal->setStatusTip(tr("Lays out the selected widgets horizontally in a splitter")); m_actionSplitHorizontal->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Horizontally in Splitter"))); m_actionSplitHorizontal->setData(LayoutInfo::HSplitter); @@ -483,7 +483,7 @@ void FormWindowManager::setupActions() m_actionSplitVertical = new QAction(createIconSet(QStringLiteral("editvlayoutsplit.png")), tr("Lay Out Vertically in Sp&litter"), this); m_actionSplitVertical->setObjectName(QStringLiteral("__qt_split_vertical_action")); - m_actionSplitVertical->setShortcut(Qt::CTRL + Qt::Key_4); + m_actionSplitVertical->setShortcut(Qt::CTRL | Qt::Key_4); m_actionSplitVertical->setStatusTip(tr("Lays out the selected widgets vertically in a splitter")); m_actionSplitVertical->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Lay Out Vertically in Splitter"))); connect(m_actionSplitVertical, &QAction::triggered, this, &FormWindowManager::createLayout); @@ -493,7 +493,7 @@ void FormWindowManager::setupActions() m_actionBreakLayout = new QAction(createIconSet(QStringLiteral("editbreaklayout.png")), tr("&Break Layout"), this); m_actionBreakLayout->setObjectName(QStringLiteral("__qt_break_layout_action")); - m_actionBreakLayout->setShortcut(Qt::CTRL + Qt::Key_0); + m_actionBreakLayout->setShortcut(Qt::CTRL | Qt::Key_0); m_actionBreakLayout->setStatusTip(tr("Breaks the selected layout")); m_actionBreakLayout->setWhatsThis(whatsThisFrom(QStringLiteral("Layout|Break Layout"))); connect(m_actionBreakLayout, &QAction::triggered, this, &FormWindowManager::slotActionBreakLayoutActivated); @@ -567,7 +567,7 @@ static inline QWidget *findLayoutContainer(const FormWindow *fw) { QWidgetList l(fw->selectedWidgets()); fw->simplifySelection(&l); - return l.empty() ? fw->mainContainer() : l.front(); + return l.isEmpty() ? fw->mainContainer() : l.constFirst(); } void FormWindowManager::createLayout() @@ -617,7 +617,7 @@ void FormWindowManager::slotActionSimplifyLayoutActivated() if (selectedWidgets.size() != 1) return; SimplifyLayoutCommand *cmd = new SimplifyLayoutCommand(m_activeFormWindow); - if (cmd->init(selectedWidgets.front())) { + if (cmd->init(selectedWidgets.constFirst())) { m_activeFormWindow->commandHistory()->push(cmd); } else { delete cmd; @@ -754,7 +754,7 @@ QSet FormWindowManager::getUnsortedLayoutsToBeBroken(bool firstOnly) for (QWidget *selectedWidget : qAsConst(selection)) { // find all layouts const QWidgetList &list = layoutsToBeBroken(selectedWidget); - if (!list.empty()) { + if (!list.isEmpty()) { for (QWidget *widget : list) layouts.insert(widget); if (firstOnly) diff --git a/src/designer/src/components/formeditor/formwindowsettings.cpp b/src/designer/src/components/formeditor/formwindowsettings.cpp index 2ed718d887..3e24b76237 100644 --- a/src/designer/src/components/formeditor/formwindowsettings.cpp +++ b/src/designer/src/components/formeditor/formwindowsettings.cpp @@ -67,6 +67,7 @@ struct FormWindowData { bool hasFormGrid{false}; Grid grid; bool idBasedTranslations{false}; + bool connectSlotsByName{true}; }; inline bool operator==(const FormWindowData &fd1, const FormWindowData &fd2) { return fd1.equals(fd2); } @@ -80,6 +81,7 @@ QDebug operator<<(QDebug str, const FormWindowData &d) << d.pixFunction << " Author=" << d.author << " Hints=" << d.includeHints << " Grid=" << d.hasFormGrid << d.grid.deltaX() << d.grid.deltaY() << " ID-based translations" << d.idBasedTranslations + << " Connect slots by name" << d.connectSlotsByName << '\n'; return str; } @@ -97,7 +99,8 @@ bool FormWindowData::equals(const FormWindowData &rhs) const includeHints == rhs.includeHints && hasFormGrid == rhs.hasFormGrid && grid == rhs.grid && - idBasedTranslations == rhs.idBasedTranslations; + idBasedTranslations == rhs.idBasedTranslations && + connectSlotsByName == rhs.connectSlotsByName; } void FormWindowData::fromFormWindow(FormWindowBase* fw) @@ -105,12 +108,13 @@ void FormWindowData::fromFormWindow(FormWindowBase* fw) defaultMargin = defaultSpacing = INT_MIN; fw->layoutDefault(&defaultMargin, &defaultSpacing); - QStyle *style = fw->formContainer()->style(); + auto container = fw->formContainer(); + QStyle *style = container->style(); layoutDefaultEnabled = defaultMargin != INT_MIN || defaultSpacing != INT_MIN; if (defaultMargin == INT_MIN) - defaultMargin = style->pixelMetric(QStyle::PM_DefaultChildMargin, nullptr); + defaultMargin = style->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, container); if (defaultSpacing == INT_MIN) - defaultSpacing = style->pixelMetric(QStyle::PM_DefaultLayoutSpacing, nullptr); + defaultSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr); marginFunction.clear(); @@ -128,6 +132,7 @@ void FormWindowData::fromFormWindow(FormWindowBase* fw) hasFormGrid = fw->hasFormGrid(); grid = hasFormGrid ? fw->designerGrid() : FormWindowBase::defaultDesignerGrid(); idBasedTranslations = fw->useIdBasedTranslations(); + connectSlotsByName = fw->connectSlotsByName(); } void FormWindowData::applyToFormWindow(FormWindowBase* fw) const @@ -154,6 +159,7 @@ void FormWindowData::applyToFormWindow(FormWindowBase* fw) const if (hasFormGrid || hadFormGrid != hasFormGrid) fw->setDesignerGrid(hasFormGrid ? grid : FormWindowBase::defaultDesignerGrid()); fw->setUseIdBasedTranslations(idBasedTranslations); + fw->setConnectSlotsByName(connectSlotsByName); } // -------------------------- FormWindowSettings @@ -220,6 +226,7 @@ FormWindowData FormWindowSettings::data() const rc.hasFormGrid = m_ui->gridPanel->isChecked(); rc.grid = m_ui->gridPanel->grid(); rc.idBasedTranslations = m_ui->idBasedTranslationsCheckBox->isChecked(); + rc.connectSlotsByName = m_ui->connectSlotsByNameCheckBox->isChecked(); return rc; } @@ -238,7 +245,7 @@ void FormWindowSettings::setData(const FormWindowData &data) m_ui->authorLineEdit->setText(data.author); - if (data.includeHints.empty()) { + if (data.includeHints.isEmpty()) { m_ui->includeHintsTextEdit->clear(); } else { m_ui->includeHintsTextEdit->setText(data.includeHints.join(QLatin1Char('\n'))); @@ -247,6 +254,7 @@ void FormWindowSettings::setData(const FormWindowData &data) m_ui->gridPanel->setChecked(data.hasFormGrid); m_ui->gridPanel->setGrid(data.grid); m_ui->idBasedTranslationsCheckBox->setChecked(data.idBasedTranslations); + m_ui->connectSlotsByNameCheckBox->setChecked(data.connectSlotsByName); } void FormWindowSettings::accept() diff --git a/src/designer/src/components/formeditor/formwindowsettings.ui b/src/designer/src/components/formeditor/formwindowsettings.ui index 6bb092078a..a71ae35427 100644 --- a/src/designer/src/components/formeditor/formwindowsettings.ui +++ b/src/designer/src/components/formeditor/formwindowsettings.ui @@ -33,20 +33,201 @@ 0 0 - 470 - 466 + 463 + 654 Form Settings + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Grid + + + + + + + &Include Hints + + + + 6 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + + + + + + + Translations + + + + + + ID-based + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + &Pixmap Function + + + true + + + + 6 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + &Author + + + + 6 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + + + + + + + Qt::Vertical + + + + 111 + 115 + + + + + + + + Embedded Design + + + + + + TextLabel + + + + + + 6 - + + 0 + + + 0 + + + 0 + + 0 @@ -58,7 +239,16 @@ true - + + 8 + + + 8 + + + 8 + + 8 @@ -102,7 +292,16 @@ true - + + 8 + + + 8 + + + 8 + + 8 @@ -139,142 +338,22 @@ - - - - 6 - - - 0 - - - - - &Pixmap Function - - - true - - - - 6 - - - 8 - - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Qt::Horizontal - - - - - + + - &Include Hints + Connections - - - 6 - - - 8 - - - - - - - - - - - Grid - - - - - - - Embedded Design - - - - - - TextLabel - - - - - - - - - - &Author - - - - 6 - - - 8 - - - - - - - - - - - Translations - - + - + - ID-based + Connect slots by name - - - - Qt::Vertical - - - - 111 - 115 - - - - diff --git a/src/designer/src/components/formeditor/layout_propertysheet.cpp b/src/designer/src/components/formeditor/layout_propertysheet.cpp index e0e456d325..d9d29a11da 100644 --- a/src/designer/src/components/formeditor/layout_propertysheet.cpp +++ b/src/designer/src/components/formeditor/layout_propertysheet.cpp @@ -57,7 +57,6 @@ static const char *bottomMargin = "bottomMargin"; static const char *horizontalSpacing = "horizontalSpacing"; static const char *verticalSpacing = "verticalSpacing"; static const char *spacing = "spacing"; -static const char *margin = "margin"; static const char *sizeConstraint = "sizeConstraint"; static const char *boxStretchPropertyC = "stretch"; static const char *gridRowStretchPropertyC = "rowStretch"; @@ -68,7 +67,6 @@ static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth"; namespace { enum LayoutPropertyType { LayoutPropertyNone, - LayoutPropertyMargin, // Deprecated LayoutPropertyLeftMargin, LayoutPropertyTopMargin, LayoutPropertyRightMargin, @@ -102,23 +100,21 @@ static bool isIntegerList(const QString &s) // Quick lookup by name static LayoutPropertyType layoutPropertyType(const QString &name) { - static QHash namePropertyMap; - if (namePropertyMap.empty()) { - namePropertyMap.insert(QLatin1String(leftMargin), LayoutPropertyLeftMargin); - namePropertyMap.insert(QLatin1String(topMargin), LayoutPropertyTopMargin); - namePropertyMap.insert(QLatin1String(rightMargin), LayoutPropertyRightMargin); - namePropertyMap.insert(QLatin1String(bottomMargin), LayoutPropertyBottomMargin); - namePropertyMap.insert(QLatin1String(horizontalSpacing), LayoutPropertyHorizontalSpacing); - namePropertyMap.insert(QLatin1String(verticalSpacing), LayoutPropertyVerticalSpacing); - namePropertyMap.insert(QLatin1String(spacing), LayoutPropertySpacing); - namePropertyMap.insert(QLatin1String(margin), LayoutPropertyMargin); - namePropertyMap.insert(QLatin1String(sizeConstraint), LayoutPropertySizeConstraint); - namePropertyMap.insert(QLatin1String(boxStretchPropertyC ), LayoutPropertyBoxStretch); - namePropertyMap.insert(QLatin1String(gridRowStretchPropertyC), LayoutPropertyGridRowStretch); - namePropertyMap.insert(QLatin1String(gridColumnStretchPropertyC), LayoutPropertyGridColumnStretch); - namePropertyMap.insert(QLatin1String(gridRowMinimumHeightPropertyC), LayoutPropertyGridRowMinimumHeight); - namePropertyMap.insert(QLatin1String(gridColumnMinimumWidthPropertyC), LayoutPropertyGridColumnMinimumWidth); - } + static const QHash namePropertyMap = { + {QLatin1String(leftMargin), LayoutPropertyLeftMargin}, + {QLatin1String(topMargin), LayoutPropertyTopMargin}, + {QLatin1String(rightMargin), LayoutPropertyRightMargin}, + {QLatin1String(bottomMargin), LayoutPropertyBottomMargin}, + {QLatin1String(horizontalSpacing), LayoutPropertyHorizontalSpacing}, + {QLatin1String(verticalSpacing), LayoutPropertyVerticalSpacing}, + {QLatin1String(spacing), LayoutPropertySpacing}, + {QLatin1String(sizeConstraint), LayoutPropertySizeConstraint}, + {QLatin1String(boxStretchPropertyC ), LayoutPropertyBoxStretch}, + {QLatin1String(gridRowStretchPropertyC), LayoutPropertyGridRowStretch}, + {QLatin1String(gridColumnStretchPropertyC), LayoutPropertyGridColumnStretch}, + {QLatin1String(gridRowMinimumHeightPropertyC), LayoutPropertyGridRowMinimumHeight}, + {QLatin1String(gridColumnMinimumWidthPropertyC), LayoutPropertyGridColumnMinimumWidth} + }; return namePropertyMap.value(name, LayoutPropertyNone); } @@ -203,7 +199,6 @@ LayoutPropertySheet::LayoutPropertySheet(QLayout *l, QObject *parent) setAttribute(indexOf(QLatin1String(spacing)), true); } - setAttribute(indexOf(QLatin1String(margin)), true); // Stretch if (visibleMask & LayoutProperties::BoxStretchProperty) { pindex = createFakeProperty(QLatin1String(boxStretchPropertyC), QByteArray()); @@ -256,14 +251,6 @@ void LayoutPropertySheet::setProperty(int index, const QVariant &value) case LayoutPropertyBottomMargin: lw->setLayoutBottomMargin(value.toInt()); return; - case LayoutPropertyMargin: { - const int v = value.toInt(); - lw->setLayoutLeftMargin(v); - lw->setLayoutTopMargin(v); - lw->setLayoutRightMargin(v); - lw->setLayoutBottomMargin(v); - } - return; default: break; } @@ -455,12 +442,6 @@ void LayoutPropertySheet::setChanged(int index, bool changed) setChanged(indexOf(QLatin1String(verticalSpacing)), changed); } break; - case LayoutPropertyMargin: - setChanged(indexOf(QLatin1String(leftMargin)), changed); - setChanged(indexOf(QLatin1String(topMargin)), changed); - setChanged(indexOf(QLatin1String(rightMargin)), changed); - setChanged(indexOf(QLatin1String(bottomMargin)), changed); - break; default: break; } diff --git a/src/designer/src/components/formeditor/previewactiongroup.cpp b/src/designer/src/components/formeditor/previewactiongroup.cpp index 89c3a0ae7b..ea388da33f 100644 --- a/src/designer/src/components/formeditor/previewactiongroup.cpp +++ b/src/designer/src/components/formeditor/previewactiongroup.cpp @@ -91,14 +91,11 @@ PreviewActionGroup::PreviewActionGroup(QDesignerFormEditorInterface *core, QObje void PreviewActionGroup::updateDeviceProfiles() { - using DeviceProfileList = QList; - using ActionList = QList; - const QDesignerSharedSettings settings(m_core); - const DeviceProfileList profiles = settings.deviceProfiles(); - const ActionList al = actions(); + const auto profiles = settings.deviceProfiles(); + const auto al = actions(); // Separator? - const bool hasProfiles = !profiles.empty(); + const bool hasProfiles = !profiles.isEmpty(); al.at(MaxDeviceActions)->setVisible(hasProfiles); int index = 0; if (hasProfiles) { @@ -119,11 +116,11 @@ void PreviewActionGroup::slotTriggered(QAction *a) { // Device or style according to data. const QVariant data = a->data(); - switch (data.type()) { - case QVariant::String: + switch (data.metaType().id()) { + case QMetaType::QString: emit preview(data.toString(), -1); break; - case QVariant::Int: + case QMetaType::Int: emit preview(QString(), data.toInt()); break; default: diff --git a/src/designer/src/components/formeditor/previewactiongroup.h b/src/designer/src/components/formeditor/previewactiongroup.h index 2e5d77dca4..dae1abbe1c 100644 --- a/src/designer/src/components/formeditor/previewactiongroup.h +++ b/src/designer/src/components/formeditor/previewactiongroup.h @@ -40,7 +40,7 @@ #ifndef PREVIEWACTIONGROUP_H #define PREVIEWACTIONGROUP_H -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/formeditor/qdesigner_resource.cpp b/src/designer/src/components/formeditor/qdesigner_resource.cpp index 4b747d04c4..e46a01bfa9 100644 --- a/src/designer/src/components/formeditor/qdesigner_resource.cpp +++ b/src/designer/src/components/formeditor/qdesigner_resource.cpp @@ -81,8 +81,6 @@ #include #include #include -#include -#include #include #include #include @@ -94,6 +92,9 @@ #include #include +#include +#include + #include #include #include @@ -483,7 +484,7 @@ void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) const QVariant classVar = sheet->property(sheet->indexOf(QStringLiteral("objectName"))); QString classStr; - if (classVar.canConvert(QVariant::String)) + if (classVar.canConvert()) classStr = classVar.toString(); else classStr = qvariant_cast(classVar).value(); @@ -512,16 +513,18 @@ void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) if (m_formWindow->useIdBasedTranslations()) ui->setAttributeIdbasedtr(true); + if (!m_formWindow->connectSlotsByName()) // Don't write out if true (default) + ui->setAttributeConnectslotsbyname(false); const QVariantMap designerFormData = m_formWindow->formData(); - if (!designerFormData.empty()) { + if (!designerFormData.isEmpty()) { DomPropertyList domPropertyList; const QVariantMap::const_iterator cend = designerFormData.constEnd(); for (QVariantMap::const_iterator it = designerFormData.constBegin(); it != cend; ++it) { if (DomProperty *prop = variantToDomProperty(this, widget->metaObject(), it.key(), it.value())) domPropertyList += prop; } - if (!domPropertyList.empty()) { + if (!domPropertyList.isEmpty()) { DomDesignerData* domDesignerFormData = new DomDesignerData; domDesignerFormData->setElementProperty(domPropertyList); ui->setElementDesignerdata(domDesignerFormData); @@ -531,7 +534,7 @@ void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) if (!m_formWindow->includeHints().isEmpty()) { const QString local = QStringLiteral("local"); const QString global = QStringLiteral("global"); - QVector ui_includes; + QList ui_includes; const QStringList &includeHints = m_formWindow->includeHints(); ui_includes.reserve(includeHints.size()); for (QString includeHint : includeHints) { @@ -588,7 +591,7 @@ void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(m_formWindow->mainContainer()); const QStringList fakeSlots = item->fakeSlots(); const QStringList fakeSignals =item->fakeSignals(); - if (!fakeSlots.empty() || !fakeSignals.empty()) { + if (!fakeSlots.isEmpty() || !fakeSignals.isEmpty()) { DomSlots *domSlots = new DomSlots(); domSlots->setElementSlot(fakeSlots); domSlots->setElementSignal(fakeSignals); @@ -646,8 +649,12 @@ QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. QWidget *mainWidget = QAbstractFormBuilder::create(ui, parentWidget); - if (m_formWindow) + if (m_formWindow) { m_formWindow->setUseIdBasedTranslations(ui->attributeIdbasedtr()); + // Default to true unless set. + const bool connectSlotsByName = !ui->hasAttributeConnectslotsbyname() || ui->attributeConnectslotsbyname(); + m_formWindow->setConnectSlotsByName(connectSlotsByName); + } if (mainWidget && m_formWindow) { m_formWindow->setAuthor(ui->elementAuthor()); @@ -661,7 +668,7 @@ QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) const DomPropertyList::const_iterator cend = domPropertyList.constEnd(); for (DomPropertyList::const_iterator it = domPropertyList.constBegin(); it != cend; ++it) { const QVariant vprop = domPropertyToVariant(this, mainWidget->metaObject(), *it); - if (vprop.type() != QVariant::Invalid) + if (vprop.metaType().id() != QMetaType::UnknownType) designerFormData.insert((*it)->attributeName(), vprop); } } @@ -702,7 +709,7 @@ QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) // Register all button groups the form builder adds as children of the main container for them to be found // in the signal slot editor const QObjectList mchildren = mainWidget->children(); - if (!mchildren.empty()) { + if (!mchildren.isEmpty()) { QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase(); const QObjectList::const_iterator cend = mchildren.constEnd(); for (QObjectList::const_iterator it = mchildren.constBegin(); it != cend; ++it) @@ -734,7 +741,7 @@ QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) // Initialize the mainwindow geometry. Has it been explicitly specified? bool hasExplicitGeometry = false; const auto &properties = ui->elementWidget()->elementProperty(); - if (!properties.empty()) { + if (!properties.isEmpty()) { const QString geometry = QStringLiteral("geometry"); for (const DomProperty *p : properties) { if (p->attributeName() == geometry) { @@ -794,7 +801,7 @@ QWidget *QDesignerResource::create(DomWidget *ui_widget, QWidget *parentWidget) // save the actions const auto &actionRefs = ui_widget->elementAddAction(); - ui_widget->setElementAddAction(QVector()); + ui_widget->setElementAddAction(QList()); QWidget *w = QAbstractFormBuilder::create(ui_widget, parentWidget); @@ -933,9 +940,32 @@ static bool readDomEnumerationValue(const DomProperty *p, return false; } +// ### fixme Qt 7 remove this: Exclude deprecated properties of Qt 5. +static bool isDeprecatedQt5Property(const QObject *o, const DomProperty *p) +{ + const QString &propertyName = p->attributeName(); + switch (p->kind()) { + case DomProperty::Set: + if (propertyName == u"features" && o->inherits("QDockWidget") + && p->elementSet() == u"QDockWidget::AllDockWidgetFeatures") { + return true; + } + break; + case DomProperty::Enum: + if (propertyName == u"sizeAdjustPolicy" && o->inherits("QComboBox") + && p->elementEnum() == u"QComboBox::AdjustToMinimumContentsLength") { + return true; + } + break; + default: + break; + } + return false; +} + void QDesignerResource::applyProperties(QObject *o, const QList &properties) { - if (properties.empty()) + if (properties.isEmpty()) return; QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), o); @@ -947,6 +977,8 @@ void QDesignerResource::applyProperties(QObject *o, const QList &p const QString objectNameProperty = QStringLiteral("objectName"); for (DomProperty *p : properties) { + if (isDeprecatedQt5Property(o, p)) // ### fixme Qt 7 remove this + continue; // ### fixme Qt 7 remove this: Exclude deprecated value of Qt 5. QString propertyName = p->attributeName(); if (propertyName == QLatin1String("numDigits") && o->inherits("QLCDNumber")) // Deprecated in Qt 4, removed in Qt 5. propertyName = QLatin1String("digitCount"); @@ -985,25 +1017,25 @@ void QDesignerResource::applyProperties(QObject *o, const QList &p sheet->setProperty(index, v); sheet->setChanged(index, true); } else if (dynamicPropertiesAllowed) { - QVariant defaultValue = QVariant(v.type()); + QVariant defaultValue = QVariant(v.metaType()); bool isDefault = (v == defaultValue); if (v.canConvert()) { - defaultValue = QVariant(QVariant::Icon); + defaultValue = QVariant(QMetaType(QMetaType::QIcon)); isDefault = (qvariant_cast(v) == PropertySheetIconValue()); } else if (v.canConvert()) { - defaultValue = QVariant(QVariant::Pixmap); + defaultValue = QVariant(QMetaType(QMetaType::QPixmap)); isDefault = (qvariant_cast(v) == PropertySheetPixmapValue()); } else if (v.canConvert()) { - defaultValue = QVariant(QVariant::String); + defaultValue = QVariant(QMetaType(QMetaType::QString)); isDefault = (qvariant_cast(v) == PropertySheetStringValue()); } else if (v.canConvert()) { - defaultValue = QVariant(QVariant::StringList); + defaultValue = QVariant(QMetaType(QMetaType::QStringList)); isDefault = (qvariant_cast(v) == PropertySheetStringListValue()); } else if (v.canConvert()) { - defaultValue = QVariant(QVariant::KeySequence); + defaultValue = QVariant(QMetaType(QMetaType::QKeySequence)); isDefault = (qvariant_cast(v) == PropertySheetKeySequenceValue()); } - if (defaultValue.type() != QVariant::UserType) { + if (defaultValue.metaType().id() != QMetaType::User) { const int idx = dynamicSheet->addDynamicProperty(p->attributeName(), defaultValue); if (idx != -1) { sheet->setProperty(idx, v); @@ -1137,12 +1169,9 @@ DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWid if (m_internal_to_qt.contains(className)) w->setAttributeClass(m_internal_to_qt.value(className)); - w->setAttributeName(widget->objectName()); - if (isPromoted( core(), widget)) { // is promoted? Q_ASSERT(widgetInfo != nullptr); - w->setAttributeName(widget->objectName()); w->setAttributeClass(widgetInfo->name()); const auto &prop_list = w->elementProperty(); @@ -1255,7 +1284,7 @@ DomTabStops *QDesignerResource::saveTabStops() void QDesignerResource::applyTabStops(QWidget *widget, DomTabStops *tabStops) { - if (!tabStops) + if (tabStops == nullptr || widget == nullptr) return; QWidgetList tabOrder; @@ -1288,7 +1317,7 @@ inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core, DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget) { DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); - QVector ui_widget_list; + QList ui_widget_list; for (int i=0; icount(); ++i) { QWidget *page = container->widget(i); @@ -1309,7 +1338,7 @@ DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExte DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget) { DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); - QVector ui_widget_list; + QList ui_widget_list; if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { for (int i=0; icount(); ++i) { QWidget *page = container->widget(i); @@ -1368,7 +1397,7 @@ DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWid DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget) { DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); - QVector ui_widget_list; + QList ui_widget_list; if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { const int current = widget->currentIndex(); @@ -1435,7 +1464,7 @@ DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_paren DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget) { DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); - QVector ui_widget_list; + QList ui_widget_list; if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { const int current = widget->currentIndex(); @@ -1528,7 +1557,7 @@ bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj); const int pindex = meta->indexOfProperty(prop); - if (pindex != -1 && !(meta->property(pindex)->attributes(obj) & QDesignerMetaPropertyInterface::StoredAttribute)) + if (pindex != -1 && !meta->property(pindex)->attributes().testFlag(QDesignerMetaPropertyInterface::StoredAttribute)) return false; if (prop == QStringLiteral("objectName") || prop == QStringLiteral("spacerName")) // ### don't store the property objectName @@ -1686,8 +1715,8 @@ DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection) ui_widget->setAttributeName(QLatin1String(clipboardObjectName)); bool hasItems = false; // Widgets - if (!selection.m_widgets.empty()) { - QVector ui_widget_list; + if (!selection.m_widgets.isEmpty()) { + QList ui_widget_list; const int size = selection.m_widgets.size(); for (int i=0; i< size; ++i) { QWidget *w = selection.m_widgets.at(i); @@ -1697,19 +1726,19 @@ DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection) if (ui_child) ui_widget_list.append(ui_child); } - if (!ui_widget_list.empty()) { + if (!ui_widget_list.isEmpty()) { ui_widget->setElementWidget(ui_widget_list); hasItems = true; } } // actions - if (!selection.m_actions.empty()) { - QVector domActions; + if (!selection.m_actions.isEmpty()) { + QList domActions; for (QAction* action : qAsConst(selection.m_actions)) { if (DomAction *domAction = createDom(action)) domActions += domAction; } - if (!domActions.empty()) { + if (!domActions.isEmpty()) { ui_widget-> setElementAction(domActions); hasItems = true; } @@ -1744,7 +1773,7 @@ FormBuilderClipboard QDesignerResource::paste(DomUI *ui, QWidget *widgetParent, const DomWidget *topLevel = ui->elementWidget(); initialize(ui); const auto &domWidgets = topLevel->elementWidget(); - if (!domWidgets.empty()) { + if (!domWidgets.isEmpty()) { const QPoint offset = m_formWindow->grid(); for (DomWidget* domWidget : domWidgets) { if (QWidget *w = create(domWidget, widgetParent)) { @@ -1851,7 +1880,7 @@ DomCustomWidgets *QDesignerResource::saveCustomWidgets() WidgetDataBaseItem *internalItem = static_cast(item); const QStringList fakeSlots = internalItem->fakeSlots(); const QStringList fakeSignals = internalItem->fakeSignals(); - if (!fakeSlots.empty() || !fakeSignals.empty()) { + if (!fakeSlots.isEmpty() || !fakeSignals.isEmpty()) { DomSlots *domSlots = new DomSlots(); domSlots->setElementSlot(fakeSlots); domSlots->setElementSignal(fakeSignals); @@ -2109,7 +2138,7 @@ DomResources *QDesignerResource::saveResources() DomResources *QDesignerResource::saveResources(const QStringList &qrcPaths) { QtResourceSet *resourceSet = m_formWindow->resourceSet(); - QVector dom_include; + QList dom_include; if (resourceSet) { const QStringList activePaths = resourceSet->activeResourceFilePaths(); for (const QString &path : activePaths) { @@ -2206,7 +2235,7 @@ QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QStrin void QDesignerResource::applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget) { const DomPropertyList attributes = ui_widget->elementAttribute(); - if (attributes.empty()) + if (attributes.isEmpty()) return; QDesignerPropertySheetExtension *sheet = qt_extension(m_formWindow->core()->extensionManager(), widget); const DomPropertyList::const_iterator acend = attributes.constEnd(); diff --git a/src/designer/src/components/formeditor/qmainwindow_container.cpp b/src/designer/src/components/formeditor/qmainwindow_container.cpp index 180c38e79d..8bed2911b0 100644 --- a/src/designer/src/components/formeditor/qmainwindow_container.cpp +++ b/src/designer/src/components/formeditor/qmainwindow_container.cpp @@ -106,6 +106,10 @@ Qt::DockWidgetArea dockWidgetArea(QDockWidget *me) } } +// In QMainWindowContainer::remove(), remember the dock area in a dynamic +// property so that it can used in addWidget() if that is called by undo(). +static const char dockAreaPropertyName[] = "_q_dockArea"; + void QMainWindowContainer::addWidget(QWidget *widget) { // remove all the occurrences of widget @@ -138,7 +142,17 @@ void QMainWindowContainer::addWidget(QWidget *widget) else if (QDockWidget *dockWidget = qobject_cast(widget)) { m_widgets.append(widget); - m_mainWindow->addDockWidget(dockWidgetArea(dockWidget), dockWidget); + + Qt::DockWidgetArea area = Qt::LeftDockWidgetArea; + const auto areaProperty = widget->property(dockAreaPropertyName); + if (areaProperty.canConvert()) { + area = areaProperty.value(); + widget->setProperty(dockAreaPropertyName, {}); + } else { + area = dockWidgetArea(dockWidget); + } + + m_mainWindow->addDockWidget(area, dockWidget); dockWidget->show(); if (FormWindow *fw = FormWindow::findFormWindow(m_mainWindow)) { @@ -181,6 +195,8 @@ void QMainWindowContainer::remove(int index) statusBar->setParent(nullptr); m_mainWindow->setStatusBar(nullptr); } else if (QDockWidget *dockWidget = qobject_cast(widget)) { + const auto area = m_mainWindow->dockWidgetArea(dockWidget); + dockWidget->setProperty(dockAreaPropertyName, QVariant::fromValue(area)); m_mainWindow->removeDockWidget(dockWidget); } m_widgets.removeAt(index); diff --git a/src/designer/src/components/formeditor/qmainwindow_container.h b/src/designer/src/components/formeditor/qmainwindow_container.h index 9551d8ffa3..bdd0a3a874 100644 --- a/src/designer/src/components/formeditor/qmainwindow_container.h +++ b/src/designer/src/components/formeditor/qmainwindow_container.h @@ -51,8 +51,10 @@ class QMainWindowContainer: public QObject, public QDesignerContainerExtension QWidget *widget(int index) const override; int currentIndex() const override; void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; private: diff --git a/src/designer/src/components/formeditor/qmdiarea_container.cpp b/src/designer/src/components/formeditor/qmdiarea_container.cpp index e33c993676..03fe667a32 100644 --- a/src/designer/src/components/formeditor/qmdiarea_container.cpp +++ b/src/designer/src/components/formeditor/qmdiarea_container.cpp @@ -117,7 +117,7 @@ void QMdiAreaContainer::insertWidget(int, QWidget *widget) void QMdiAreaContainer::remove(int index) { - QList subWins = m_mdiArea->subWindowList(QMdiArea::CreationOrder); + auto subWins = m_mdiArea->subWindowList(QMdiArea::CreationOrder); if (index >= 0 && index < subWins.size()) { QMdiSubWindow *f = subWins.at(index); m_mdiArea->removeSubWindow(f->widget()); @@ -144,7 +144,7 @@ QMdiAreaPropertySheet::MdiAreaProperty QMdiAreaPropertySheet::mdiAreaProperty(co { using MdiAreaPropertyHash = QHash; static MdiAreaPropertyHash mdiAreaPropertyHash; - if (mdiAreaPropertyHash.empty()) { + if (mdiAreaPropertyHash.isEmpty()) { mdiAreaPropertyHash.insert(QLatin1String(subWindowNameC), MdiAreaSubWindowName); mdiAreaPropertyHash.insert(QLatin1String(subWindowTitleC), MdiAreaSubWindowTitle); } diff --git a/src/designer/src/components/formeditor/qmdiarea_container.h b/src/designer/src/components/formeditor/qmdiarea_container.h index 6bca448405..5134757d7a 100644 --- a/src/designer/src/components/formeditor/qmdiarea_container.h +++ b/src/designer/src/components/formeditor/qmdiarea_container.h @@ -53,8 +53,10 @@ class QMdiAreaContainer: public QObject, public QDesignerContainerExtension QWidget *widget(int index) const override; int currentIndex() const override; void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; // Semismart positioning of a new MDI child after cascading diff --git a/src/designer/src/components/formeditor/qwizard_container.cpp b/src/designer/src/components/formeditor/qwizard_container.cpp index dbc7084eb7..c2b8408d30 100644 --- a/src/designer/src/components/formeditor/qwizard_container.cpp +++ b/src/designer/src/components/formeditor/qwizard_container.cpp @@ -33,10 +33,10 @@ #include #include +#include QT_BEGIN_NAMESPACE -using IdList = QList; using WizardPageList = QList; namespace qdesigner_internal { @@ -56,7 +56,7 @@ QWidget *QWizardContainer::widget(int index) const { QWidget *rc = nullptr; if (index >= 0) { - const IdList idList = m_wizard->pageIds(); + const auto idList = m_wizard->pageIds(); if (index < idList.size()) rc = m_wizard->page(idList.at(index)); } @@ -65,15 +65,12 @@ QWidget *QWizardContainer::widget(int index) const int QWizardContainer::currentIndex() const { - const IdList idList = m_wizard->pageIds(); - const int currentId = m_wizard->currentId(); - const int rc = idList.empty() ? -1 : idList.indexOf(currentId); - return rc; + return m_wizard->pageIds().indexOf(m_wizard->currentId()); } void QWizardContainer::setCurrentIndex(int index) { - if (index < 0 || m_wizard->pageIds().empty()) + if (index < 0 || m_wizard->pageIds().isEmpty()) return; int currentIdx = currentIndex(); @@ -120,7 +117,7 @@ void QWizardContainer::insertWidget(int index, QWidget *widget) return; } - const IdList idList = m_wizard->pageIds(); + const auto idList = m_wizard->pageIds(); const int pageCount = idList.size(); if (index >= pageCount) { addWidget(widget); @@ -142,9 +139,8 @@ void QWizardContainer::insertWidget(int index, QWidget *widget) m_wizard->removePage(idList.at(i)); } int newId = idBefore + delta; - const WizardPageList::const_iterator wcend = pageList.constEnd(); - for (WizardPageList::const_iterator it = pageList.constBegin(); it != wcend; ++it) { - m_wizard->setPage(newId, *it); + for (QWizardPage *page : qAsConst(pageList)) { + m_wizard->setPage(newId, page); newId += delta; } } else { @@ -160,7 +156,7 @@ void QWizardContainer::remove(int index) if (index < 0) return; - const IdList idList = m_wizard->pageIds(); + const auto idList = m_wizard->pageIds(); if (index >= idList.size()) return; diff --git a/src/designer/src/components/formeditor/qwizard_container.h b/src/designer/src/components/formeditor/qwizard_container.h index 0c4241ea0b..23dc63b4f5 100644 --- a/src/designer/src/components/formeditor/qwizard_container.h +++ b/src/designer/src/components/formeditor/qwizard_container.h @@ -56,8 +56,10 @@ class QWizardContainer: public QObject, public QDesignerContainerExtension QWidget *widget(int index) const override; int currentIndex() const override; void setCurrentIndex(int index) override; + bool canAddWidget() const override { return true; } void addWidget(QWidget *widget) override; void insertWidget(int index, QWidget *widget) override; + bool canRemove(int) const override { return true; } void remove(int index) override; private: diff --git a/src/designer/src/components/formeditor/templateoptionspage.cpp b/src/designer/src/components/formeditor/templateoptionspage.cpp index b1c0dc2d4b..4e638c9137 100644 --- a/src/designer/src/components/formeditor/templateoptionspage.cpp +++ b/src/designer/src/components/formeditor/templateoptionspage.cpp @@ -79,7 +79,7 @@ void TemplateOptionsWidget::setTemplatePaths(const QStringList &l) { // add paths and select 0 m_ui->m_templatePathListWidget->clear(); - if (l.empty()) { + if (l.isEmpty()) { // disable button templatePathSelectionChanged(); } else { @@ -96,9 +96,9 @@ void TemplateOptionsWidget::addTemplatePath() if (templatePath.isEmpty()) return; - const QList existing + const auto existing = m_ui->m_templatePathListWidget->findItems(templatePath, Qt::MatchExactly); - if (!existing.empty()) + if (!existing.isEmpty()) return; QListWidgetItem *newItem = new QListWidgetItem(templatePath); @@ -108,17 +108,16 @@ void TemplateOptionsWidget::addTemplatePath() void TemplateOptionsWidget::removeTemplatePath() { - const QList selectedPaths - = m_ui->m_templatePathListWidget->selectedItems(); - if (selectedPaths.empty()) + const auto selectedPaths = m_ui->m_templatePathListWidget->selectedItems(); + if (selectedPaths.isEmpty()) return; - delete selectedPaths.front(); + delete selectedPaths.constFirst(); } void TemplateOptionsWidget::templatePathSelectionChanged() { - const QList selectedPaths = m_ui->m_templatePathListWidget->selectedItems(); - m_ui->m_removeTemplatePathButton->setEnabled(!selectedPaths.empty()); + const auto selectedPaths = m_ui->m_templatePathListWidget->selectedItems(); + m_ui->m_removeTemplatePathButton->setEnabled(!selectedPaths.isEmpty()); } QString TemplateOptionsWidget::chooseTemplatePath(QDesignerFormEditorInterface *core, QWidget *parent) diff --git a/src/designer/src/components/formeditor/tool_widgeteditor.cpp b/src/designer/src/components/formeditor/tool_widgeteditor.cpp index d3ecf80876..8b27d54aa7 100644 --- a/src/designer/src/components/formeditor/tool_widgeteditor.cpp +++ b/src/designer/src/components/formeditor/tool_widgeteditor.cpp @@ -38,10 +38,12 @@ #include #include -#include -#include #include + +#include #include +#include + #include QT_BEGIN_NAMESPACE @@ -87,7 +89,7 @@ bool WidgetEditorTool::mainWindowSeparatorEvent(QWidget *widget, QEvent *event) QMouseEvent *e = static_cast(event); if (event->type() == QEvent::MouseButtonPress) { - if (mw->isSeparator(e->pos())) { + if (mw->isSeparator(e->position().toPoint())) { m_separator_drag_mw = mw; return true; } @@ -222,7 +224,7 @@ void WidgetEditorTool::detectDockDrag(const QDesignerMimeData *mimeData) if (!mw) return; - const QList item_list = mimeData->items(); + const auto item_list = mimeData->items(); for (QDesignerDnDItemInterface *item : item_list) { if (item->decoration() && item->decoration()->property("_q_dockDrag").toBool()) @@ -254,7 +256,7 @@ bool WidgetEditorTool::handleDragEnterMoveEvent(QWidget *widget, QWidget * /*man m_lastDropTarget = mw->centralWidget(); } else { // If custom widgets have acceptDrops=true, the event occurs for them - const QPoint formPos = widget != m_formWindow ? widget->mapTo(m_formWindow, e->pos()) : e->pos(); + const QPoint formPos = widget != m_formWindow ? widget->mapTo(m_formWindow, e->position().toPoint()) : e->position().toPoint(); globalPos = m_formWindow->mapToGlobal(formPos); const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; QWidget *dropTarget = m_formWindow->widgetUnderMouse(formPos, wum); @@ -285,7 +287,7 @@ bool WidgetEditorTool::handleDropEvent(QWidget *widget, QWidget *, QDropEvent *e return true; } // FormWindow determines the position from the decoration. - const QPoint globalPos = widget->mapToGlobal(e->pos()); + const QPoint globalPos = widget->mapToGlobal(e->position().toPoint()); mimeData->moveDecoration(globalPos); if (m_specialDockDrag) { if (!m_formWindow->dropDockWidget(mimeData->items().at(0), globalPos)) { diff --git a/src/designer/src/components/formeditor/widgetselection.cpp b/src/designer/src/components/formeditor/widgetselection.cpp index c871063b58..36f9eec1f4 100644 --- a/src/designer/src/components/formeditor/widgetselection.cpp +++ b/src/designer/src/components/formeditor/widgetselection.cpp @@ -176,7 +176,7 @@ void WidgetHandle::mousePressEvent(QMouseEvent *e) QWidget *container = m_widget->parentWidget(); - m_origPressPos = container->mapFromGlobal(e->globalPos()); + m_origPressPos = container->mapFromGlobal(e->globalPosition().toPoint()); m_geom = m_origGeom = m_widget->geometry(); switch (WidgetSelection::widgetState(m_formWindow->core(), m_widget)) { @@ -200,7 +200,7 @@ void WidgetHandle::mouseMoveEvent(QMouseEvent *e) QWidget *container = m_widget->parentWidget(); - const QPoint rp = container->mapFromGlobal(e->globalPos()); + const QPoint rp = container->mapFromGlobal(e->globalPosition().toPoint()); const QPoint d = rp - m_origPressPos; const QRect pr = container->rect(); diff --git a/src/designer/src/components/lib/CMakeLists.txt b/src/designer/src/components/lib/CMakeLists.txt new file mode 100644 index 0000000000..99a10546b3 --- /dev/null +++ b/src/designer/src/components/lib/CMakeLists.txt @@ -0,0 +1,436 @@ +# Generated from lib.pro. + +##################################################################### +## DesignerComponentsPrivate Module: +##################################################################### + +qt_internal_add_module(DesignerComponentsPrivate + INTERNAL_MODULE + SOURCES + ../buddyeditor/buddyeditor.cpp ../buddyeditor/buddyeditor.h + ../buddyeditor/buddyeditor_global.h + ../buddyeditor/buddyeditor_plugin.cpp ../buddyeditor/buddyeditor_plugin.h + ../buddyeditor/buddyeditor_tool.cpp ../buddyeditor/buddyeditor_tool.h + ../formeditor/default_actionprovider.cpp ../formeditor/default_actionprovider.h + ../formeditor/default_container.cpp ../formeditor/default_container.h + ../formeditor/default_layoutdecoration.cpp ../formeditor/default_layoutdecoration.h + ../formeditor/deviceprofiledialog.cpp ../formeditor/deviceprofiledialog.h ../formeditor/deviceprofiledialog.ui + ../formeditor/dpi_chooser.cpp ../formeditor/dpi_chooser.h + ../formeditor/embeddedoptionspage.cpp ../formeditor/embeddedoptionspage.h + ../formeditor/formeditor.cpp ../formeditor/formeditor.h + ../formeditor/formeditor_global.h + ../formeditor/formeditor_optionspage.cpp ../formeditor/formeditor_optionspage.h + ../formeditor/formwindow.cpp ../formeditor/formwindow.h + ../formeditor/formwindow_dnditem.cpp ../formeditor/formwindow_dnditem.h + ../formeditor/formwindow_widgetstack.cpp ../formeditor/formwindow_widgetstack.h + ../formeditor/formwindowcursor.cpp ../formeditor/formwindowcursor.h + ../formeditor/formwindowmanager.cpp ../formeditor/formwindowmanager.h + ../formeditor/formwindowsettings.cpp ../formeditor/formwindowsettings.h ../formeditor/formwindowsettings.ui + ../formeditor/itemview_propertysheet.cpp ../formeditor/itemview_propertysheet.h + ../formeditor/layout_propertysheet.cpp ../formeditor/layout_propertysheet.h + ../formeditor/line_propertysheet.cpp ../formeditor/line_propertysheet.h + ../formeditor/previewactiongroup.cpp ../formeditor/previewactiongroup.h + ../formeditor/qdesigner_resource.cpp ../formeditor/qdesigner_resource.h + ../formeditor/qlayoutwidget_propertysheet.cpp ../formeditor/qlayoutwidget_propertysheet.h + ../formeditor/qmainwindow_container.cpp ../formeditor/qmainwindow_container.h + ../formeditor/qmdiarea_container.cpp ../formeditor/qmdiarea_container.h + ../formeditor/qwizard_container.cpp ../formeditor/qwizard_container.h + ../formeditor/spacer_propertysheet.cpp ../formeditor/spacer_propertysheet.h + ../formeditor/templateoptionspage.cpp ../formeditor/templateoptionspage.h ../formeditor/templateoptionspage.ui + ../formeditor/tool_widgeteditor.cpp ../formeditor/tool_widgeteditor.h + ../formeditor/widgetselection.cpp ../formeditor/widgetselection.h + ../objectinspector/objectinspector.cpp ../objectinspector/objectinspector.h + ../objectinspector/objectinspector_global.h + ../objectinspector/objectinspectormodel.cpp ../objectinspector/objectinspectormodel_p.h + ../propertyeditor/brushpropertymanager.cpp ../propertyeditor/brushpropertymanager.h + ../propertyeditor/designerpropertymanager.cpp ../propertyeditor/designerpropertymanager.h + ../propertyeditor/fontpropertymanager.cpp ../propertyeditor/fontpropertymanager.h + ../propertyeditor/newdynamicpropertydialog.cpp ../propertyeditor/newdynamicpropertydialog.h ../propertyeditor/newdynamicpropertydialog.ui + ../propertyeditor/paletteeditor.cpp ../propertyeditor/paletteeditor.h ../propertyeditor/paletteeditor.ui + ../propertyeditor/paletteeditorbutton.cpp ../propertyeditor/paletteeditorbutton.h + ../propertyeditor/previewframe.cpp ../propertyeditor/previewframe.h + ../propertyeditor/previewwidget.cpp ../propertyeditor/previewwidget.h ../propertyeditor/previewwidget.ui + ../propertyeditor/propertyeditor.cpp ../propertyeditor/propertyeditor.h + ../propertyeditor/propertyeditor_global.h + ../propertyeditor/qlonglongvalidator.cpp ../propertyeditor/qlonglongvalidator.h + ../propertyeditor/stringlisteditor.cpp ../propertyeditor/stringlisteditor.h ../propertyeditor/stringlisteditor.ui + ../propertyeditor/stringlisteditorbutton.cpp ../propertyeditor/stringlisteditorbutton.h + ../signalsloteditor/connectdialog.cpp ../signalsloteditor/connectdialog.ui ../signalsloteditor/connectdialog_p.h + ../signalsloteditor/signalslot_utils.cpp ../signalsloteditor/signalslot_utils_p.h + ../signalsloteditor/signalsloteditor.cpp ../signalsloteditor/signalsloteditor.h ../signalsloteditor/signalsloteditor_p.h + ../signalsloteditor/signalsloteditor_global.h + ../signalsloteditor/signalsloteditor_plugin.cpp ../signalsloteditor/signalsloteditor_plugin.h + ../signalsloteditor/signalsloteditor_tool.cpp ../signalsloteditor/signalsloteditor_tool.h + ../signalsloteditor/signalsloteditorwindow.cpp ../signalsloteditor/signalsloteditorwindow.h + ../tabordereditor/tabordereditor.cpp ../tabordereditor/tabordereditor.h + ../tabordereditor/tabordereditor_global.h + ../tabordereditor/tabordereditor_plugin.cpp ../tabordereditor/tabordereditor_plugin.h + ../tabordereditor/tabordereditor_tool.cpp ../tabordereditor/tabordereditor_tool.h + ../taskmenu/button_taskmenu.cpp ../taskmenu/button_taskmenu.h + ../taskmenu/combobox_taskmenu.cpp ../taskmenu/combobox_taskmenu.h + ../taskmenu/containerwidget_taskmenu.cpp ../taskmenu/containerwidget_taskmenu.h + ../taskmenu/groupbox_taskmenu.cpp ../taskmenu/groupbox_taskmenu.h + ../taskmenu/inplace_editor.cpp ../taskmenu/inplace_editor.h + ../taskmenu/inplace_widget_helper.cpp ../taskmenu/inplace_widget_helper.h + ../taskmenu/itemlisteditor.cpp ../taskmenu/itemlisteditor.h ../taskmenu/itemlisteditor.ui + ../taskmenu/label_taskmenu.cpp ../taskmenu/label_taskmenu.h + ../taskmenu/layouttaskmenu.cpp ../taskmenu/layouttaskmenu.h + ../taskmenu/lineedit_taskmenu.cpp ../taskmenu/lineedit_taskmenu.h + ../taskmenu/listwidget_taskmenu.cpp ../taskmenu/listwidget_taskmenu.h + ../taskmenu/listwidgeteditor.cpp ../taskmenu/listwidgeteditor.h + ../taskmenu/menutaskmenu.cpp ../taskmenu/menutaskmenu.h + ../taskmenu/tablewidget_taskmenu.cpp ../taskmenu/tablewidget_taskmenu.h + ../taskmenu/tablewidgeteditor.cpp ../taskmenu/tablewidgeteditor.h ../taskmenu/tablewidgeteditor.ui + ../taskmenu/taskmenu_component.cpp ../taskmenu/taskmenu_component.h + ../taskmenu/textedit_taskmenu.cpp ../taskmenu/textedit_taskmenu.h + ../taskmenu/toolbar_taskmenu.cpp ../taskmenu/toolbar_taskmenu.h + ../taskmenu/treewidget_taskmenu.cpp ../taskmenu/treewidget_taskmenu.h + ../taskmenu/treewidgeteditor.cpp ../taskmenu/treewidgeteditor.h ../taskmenu/treewidgeteditor.ui + ../widgetbox/widgetbox.cpp ../widgetbox/widgetbox.h + ../widgetbox/widgetbox_dnditem.cpp ../widgetbox/widgetbox_dnditem.h + ../widgetbox/widgetbox_global.h + ../widgetbox/widgetboxcategorylistview.cpp ../widgetbox/widgetboxcategorylistview.h + ../widgetbox/widgetboxtreewidget.cpp ../widgetbox/widgetboxtreewidget.h + qdesigner_components.cpp + DEFINES + QDESIGNER_COMPONENTS_LIBRARY + QT_STATICPLUGIN + INCLUDE_DIRECTORIES + . + .. + ../../../../shared/tools/shared/qtpropertybrowser + ../../lib/components + ../../lib/extension + ../../lib/sdk + ../../lib/shared + ../buddyeditor + ../formeditor + ../objectinspector + ../propertyeditor ../propertyeditor + ../signalsloteditor + ../tabordereditor + ../taskmenu + ../widgetbox + LIBRARIES + Qt::Xml + PUBLIC_LIBRARIES + Qt::Core + Qt::DesignerPrivate + Qt::GuiPrivate + Qt::WidgetsPrivate + Qt::Xml + ENABLE_AUTOGEN_TOOLS + uic + PRECOMPILED_HEADER + "lib_pch.h" +) + +# Resources: +set(propertyeditor_resource_files + "../propertyeditor/fontmapping.xml" +) + +qt_internal_add_resource(DesignerComponentsPrivate "propertyeditor" + PREFIX + "/qt-project.org/propertyeditor" + BASE + "../propertyeditor" + FILES + ${propertyeditor_resource_files} +) +set(formeditor_resource_files + "../formeditor/images/cleartext.png" + "../formeditor/images/color.png" + "../formeditor/images/configure.png" + "../formeditor/images/cursors/arrow.png" + "../formeditor/images/cursors/busy.png" + "../formeditor/images/cursors/closedhand.png" + "../formeditor/images/cursors/cross.png" + "../formeditor/images/cursors/hand.png" + "../formeditor/images/cursors/hsplit.png" + "../formeditor/images/cursors/ibeam.png" + "../formeditor/images/cursors/no.png" + "../formeditor/images/cursors/openhand.png" + "../formeditor/images/cursors/sizeall.png" + "../formeditor/images/cursors/sizeb.png" + "../formeditor/images/cursors/sizef.png" + "../formeditor/images/cursors/sizeh.png" + "../formeditor/images/cursors/sizev.png" + "../formeditor/images/cursors/uparrow.png" + "../formeditor/images/cursors/vsplit.png" + "../formeditor/images/cursors/wait.png" + "../formeditor/images/cursors/whatsthis.png" + "../formeditor/images/downplus.png" + "../formeditor/images/dropdownbutton.png" + "../formeditor/images/edit.png" + "../formeditor/images/editdelete-16.png" + "../formeditor/images/emptyicon.png" + "../formeditor/images/filenew-16.png" + "../formeditor/images/fileopen-16.png" + "../formeditor/images/leveldown.png" + "../formeditor/images/levelup.png" + "../formeditor/images/mac/adjustsize.png" + "../formeditor/images/mac/back.png" + "../formeditor/images/mac/buddytool.png" + "../formeditor/images/mac/down.png" + "../formeditor/images/mac/editbreaklayout.png" + "../formeditor/images/mac/editcopy.png" + "../formeditor/images/mac/editcut.png" + "../formeditor/images/mac/editdelete.png" + "../formeditor/images/mac/editform.png" + "../formeditor/images/mac/editgrid.png" + "../formeditor/images/mac/edithlayout.png" + "../formeditor/images/mac/edithlayoutsplit.png" + "../formeditor/images/mac/editlower.png" + "../formeditor/images/mac/editpaste.png" + "../formeditor/images/mac/editraise.png" + "../formeditor/images/mac/editvlayout.png" + "../formeditor/images/mac/editvlayoutsplit.png" + "../formeditor/images/mac/filenew.png" + "../formeditor/images/mac/fileopen.png" + "../formeditor/images/mac/filesave.png" + "../formeditor/images/mac/forward.png" + "../formeditor/images/mac/insertimage.png" + "../formeditor/images/mac/minus.png" + "../formeditor/images/mac/plus.png" + "../formeditor/images/mac/redo.png" + "../formeditor/images/mac/resourceeditortool.png" + "../formeditor/images/mac/signalslottool.png" + "../formeditor/images/mac/simplifyrichtext.png" + "../formeditor/images/mac/tabordertool.png" + "../formeditor/images/mac/textanchor.png" + "../formeditor/images/mac/textbold.png" + "../formeditor/images/mac/textcenter.png" + "../formeditor/images/mac/textitalic.png" + "../formeditor/images/mac/textjustify.png" + "../formeditor/images/mac/textleft.png" + "../formeditor/images/mac/textright.png" + "../formeditor/images/mac/textsubscript.png" + "../formeditor/images/mac/textsuperscript.png" + "../formeditor/images/mac/textunder.png" + "../formeditor/images/mac/undo.png" + "../formeditor/images/mac/up.png" + "../formeditor/images/mac/widgettool.png" + "../formeditor/images/minus-16.png" + "../formeditor/images/plus-16.png" + "../formeditor/images/prefix-add.png" + "../formeditor/images/qt3logo.png" + "../formeditor/images/qtlogo16x16.png" + "../formeditor/images/qtlogo24x24.png" + "../formeditor/images/qtlogo32x32.png" + "../formeditor/images/qtlogo64x64.png" + "../formeditor/images/reload.png" + "../formeditor/images/resetproperty.png" + "../formeditor/images/righttoleft.png" + "../formeditor/images/sort.png" + "../formeditor/images/submenu.png" + "../formeditor/images/widgets/calendarwidget.png" + "../formeditor/images/widgets/checkbox.png" + "../formeditor/images/widgets/columnview.png" + "../formeditor/images/widgets/combobox.png" + "../formeditor/images/widgets/commandlinkbutton.png" + "../formeditor/images/widgets/dateedit.png" + "../formeditor/images/widgets/datetimeedit.png" + "../formeditor/images/widgets/dial.png" + "../formeditor/images/widgets/dialogbuttonbox.png" + "../formeditor/images/widgets/dockwidget.png" + "../formeditor/images/widgets/doublespinbox.png" + "../formeditor/images/widgets/fontcombobox.png" + "../formeditor/images/widgets/frame.png" + "../formeditor/images/widgets/graphicsview.png" + "../formeditor/images/widgets/groupbox.png" + "../formeditor/images/widgets/hscrollbar.png" + "../formeditor/images/widgets/hslider.png" + "../formeditor/images/widgets/hsplit.png" + "../formeditor/images/widgets/label.png" + "../formeditor/images/widgets/lcdnumber.png" + "../formeditor/images/widgets/line.png" + "../formeditor/images/widgets/lineedit.png" + "../formeditor/images/widgets/listbox.png" + "../formeditor/images/widgets/listview.png" + "../formeditor/images/widgets/mdiarea.png" + "../formeditor/images/widgets/plaintextedit.png" + "../formeditor/images/widgets/progress.png" + "../formeditor/images/widgets/pushbutton.png" + "../formeditor/images/widgets/radiobutton.png" + "../formeditor/images/widgets/scrollarea.png" + "../formeditor/images/widgets/spacer.png" + "../formeditor/images/widgets/spinbox.png" + "../formeditor/images/widgets/table.png" + "../formeditor/images/widgets/tabwidget.png" + "../formeditor/images/widgets/textedit.png" + "../formeditor/images/widgets/timeedit.png" + "../formeditor/images/widgets/toolbox.png" + "../formeditor/images/widgets/toolbutton.png" + "../formeditor/images/widgets/vline.png" + "../formeditor/images/widgets/vscrollbar.png" + "../formeditor/images/widgets/vslider.png" + "../formeditor/images/widgets/vspacer.png" + "../formeditor/images/widgets/widget.png" + "../formeditor/images/widgets/widgetstack.png" + "../formeditor/images/widgets/wizard.png" + "../formeditor/images/win/adjustsize.png" + "../formeditor/images/win/back.png" + "../formeditor/images/win/buddytool.png" + "../formeditor/images/win/down.png" + "../formeditor/images/win/editbreaklayout.png" + "../formeditor/images/win/editcopy.png" + "../formeditor/images/win/editcut.png" + "../formeditor/images/win/editdelete.png" + "../formeditor/images/win/editform.png" + "../formeditor/images/win/editgrid.png" + "../formeditor/images/win/edithlayout.png" + "../formeditor/images/win/edithlayoutsplit.png" + "../formeditor/images/win/editlower.png" + "../formeditor/images/win/editpaste.png" + "../formeditor/images/win/editraise.png" + "../formeditor/images/win/editvlayout.png" + "../formeditor/images/win/editvlayoutsplit.png" + "../formeditor/images/win/filenew.png" + "../formeditor/images/win/fileopen.png" + "../formeditor/images/win/filesave.png" + "../formeditor/images/win/forward.png" + "../formeditor/images/win/insertimage.png" + "../formeditor/images/win/minus.png" + "../formeditor/images/win/plus.png" + "../formeditor/images/win/redo.png" + "../formeditor/images/win/resourceeditortool.png" + "../formeditor/images/win/signalslottool.png" + "../formeditor/images/win/simplifyrichtext.png" + "../formeditor/images/win/tabordertool.png" + "../formeditor/images/win/textanchor.png" + "../formeditor/images/win/textbold.png" + "../formeditor/images/win/textcenter.png" + "../formeditor/images/win/textitalic.png" + "../formeditor/images/win/textjustify.png" + "../formeditor/images/win/textleft.png" + "../formeditor/images/win/textright.png" + "../formeditor/images/win/textsubscript.png" + "../formeditor/images/win/textsuperscript.png" + "../formeditor/images/win/textunder.png" + "../formeditor/images/win/undo.png" + "../formeditor/images/win/up.png" + "../formeditor/images/win/widgettool.png" +) + +qt_internal_add_resource(DesignerComponentsPrivate "formeditor" + PREFIX + "/qt-project.org/formeditor" + BASE + "../formeditor" + FILES + ${formeditor_resource_files} +) +set(formeditor1_resource_files + "../formeditor/defaultbrushes.xml" +) + +qt_internal_add_resource(DesignerComponentsPrivate "formeditor1" + PREFIX + "/qt-project.org/brushes" + BASE + "../formeditor" + FILES + ${formeditor1_resource_files} +) +set(widgetbox_resource_files + "../widgetbox/widgetbox.xml" +) + +qt_internal_add_resource(DesignerComponentsPrivate "widgetbox" + PREFIX + "/qt-project.org/widgetbox" + BASE + "../widgetbox" + FILES + ${widgetbox_resource_files} +) + + +#### Keys ignored in scope 1:.:.:lib.pro:: +# MODULE = "DesignerComponentsPrivate" + +## Scopes: +##################################################################### + +qt_internal_extend_target(DesignerComponentsPrivate CONDITION NOT QT_BUILD_SHARED_LIBS + DEFINES + QT_DESIGNER_STATIC + INCLUDE_DIRECTORIES + ../../../../shared/findwidget + ../../../../shared/qtgradienteditor + ../../../../shared/qtpropertybrowser +) + +qt_internal_extend_target(DesignerComponentsPrivate CONDITION QT_BUILD_SHARED_LIBS + SOURCES + ../../../../shared/findwidget/abstractfindwidget.cpp ../../../../shared/findwidget/abstractfindwidget.h + ../../../../shared/findwidget/itemviewfindwidget.cpp ../../../../shared/findwidget/itemviewfindwidget.h + ../../../../shared/findwidget/texteditfindwidget.cpp ../../../../shared/findwidget/texteditfindwidget.h + ../../../../shared/qtgradienteditor/qtcolorbutton.cpp ../../../../shared/qtgradienteditor/qtcolorbutton.h + ../../../../shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp ../../../../shared/qtpropertybrowser/qtbuttonpropertybrowser.h + ../../../../shared/qtpropertybrowser/qteditorfactory.cpp ../../../../shared/qtpropertybrowser/qteditorfactory.h + ../../../../shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp ../../../../shared/qtpropertybrowser/qtgroupboxpropertybrowser.h + ../../../../shared/qtpropertybrowser/qtpropertybrowser.cpp ../../../../shared/qtpropertybrowser/qtpropertybrowser.h + ../../../../shared/qtpropertybrowser/qtpropertybrowserutils.cpp ../../../../shared/qtpropertybrowser/qtpropertybrowserutils_p.h + ../../../../shared/qtpropertybrowser/qtpropertymanager.cpp ../../../../shared/qtpropertybrowser/qtpropertymanager.h + ../../../../shared/qtpropertybrowser/qttreepropertybrowser.cpp ../../../../shared/qtpropertybrowser/qttreepropertybrowser.h + ../../../../shared/qtpropertybrowser/qtvariantproperty.cpp ../../../../shared/qtpropertybrowser/qtvariantproperty.h + INCLUDE_DIRECTORIES + ../../../../shared/findwidget + ../../../../shared/qtgradienteditor + ../../../../shared/qtpropertybrowser +) + +if(QT_BUILD_SHARED_LIBS) + # Resources: + set(findwidget_resource_files + "../../../../shared/findwidget/images/mac/closetab.png" + "../../../../shared/findwidget/images/mac/next.png" + "../../../../shared/findwidget/images/mac/previous.png" + "../../../../shared/findwidget/images/mac/searchfind.png" + "../../../../shared/findwidget/images/win/closetab.png" + "../../../../shared/findwidget/images/win/next.png" + "../../../../shared/findwidget/images/win/previous.png" + "../../../../shared/findwidget/images/win/searchfind.png" + "../../../../shared/findwidget/images/wrap.png" + ) + + qt_internal_add_resource(DesignerComponentsPrivate "findwidget" + PREFIX + "/qt-project.org/shared" + BASE + "../../../../shared/findwidget" + FILES + ${findwidget_resource_files} + ) + set(qtpropertybrowser_resource_files + "../../../../shared/qtpropertybrowser/images/cursor-arrow.png" + "../../../../shared/qtpropertybrowser/images/cursor-busy.png" + "../../../../shared/qtpropertybrowser/images/cursor-closedhand.png" + "../../../../shared/qtpropertybrowser/images/cursor-cross.png" + "../../../../shared/qtpropertybrowser/images/cursor-forbidden.png" + "../../../../shared/qtpropertybrowser/images/cursor-hand.png" + "../../../../shared/qtpropertybrowser/images/cursor-hsplit.png" + "../../../../shared/qtpropertybrowser/images/cursor-ibeam.png" + "../../../../shared/qtpropertybrowser/images/cursor-openhand.png" + "../../../../shared/qtpropertybrowser/images/cursor-sizeall.png" + "../../../../shared/qtpropertybrowser/images/cursor-sizeb.png" + "../../../../shared/qtpropertybrowser/images/cursor-sizef.png" + "../../../../shared/qtpropertybrowser/images/cursor-sizeh.png" + "../../../../shared/qtpropertybrowser/images/cursor-sizev.png" + "../../../../shared/qtpropertybrowser/images/cursor-uparrow.png" + "../../../../shared/qtpropertybrowser/images/cursor-vsplit.png" + "../../../../shared/qtpropertybrowser/images/cursor-wait.png" + "../../../../shared/qtpropertybrowser/images/cursor-whatsthis.png" + ) + + qt_internal_add_resource(DesignerComponentsPrivate "qtpropertybrowser" + PREFIX + "/qt-project.org/qtpropertybrowser" + BASE + "../../../../shared/qtpropertybrowser" + FILES + ${qtpropertybrowser_resource_files} + ) +endif() diff --git a/src/designer/src/components/lib/lib.pro b/src/designer/src/components/lib/lib.pro deleted file mode 100644 index 3f6fae950d..0000000000 --- a/src/designer/src/components/lib/lib.pro +++ /dev/null @@ -1,42 +0,0 @@ -TARGET = QtDesignerComponents -MODULE = designercomponents - -QT = core gui-private widgets-private designer-private -QT_PRIVATE = xml -CONFIG += internal_module create_cmake - -# QtDesignerComponents uses -DEFINES += QT_STATICPLUGIN -DEFINES += QDESIGNER_COMPONENTS_LIBRARY - -static:DEFINES += QT_DESIGNER_STATIC - -SOURCES += qdesigner_components.cpp - -INCLUDEPATH += . .. \ - $$PWD/../../lib/components \ - $$PWD/../../lib/sdk \ - $$PWD/../../lib/extension \ - $$PWD/../../lib/shared - -include(../propertyeditor/propertyeditor.pri) -include(../objectinspector/objectinspector.pri) -include(../signalsloteditor/signalsloteditor.pri) -include(../formeditor/formeditor.pri) -include(../widgetbox/widgetbox.pri) -include(../buddyeditor/buddyeditor.pri) -include(../taskmenu/taskmenu.pri) -include(../tabordereditor/tabordereditor.pri) - -PRECOMPILED_HEADER= lib_pch.h - -# MinGW GCC cc1plus crashes when using precompiled header -# Date Checked: 3rd September 2012 -# -# Compilers known to be affected: -# * MinGW-builds GCC 4.6.3 64-bit -# * MinGW-builds GCC 4.7.1 64-bit -# * MinGW-w64 GCC 4.7.1 64-bit (rubenvb) -mingw:CONFIG -= precompile_header - -load(qt_module) diff --git a/src/designer/src/components/objectinspector/objectinspector.cpp b/src/designer/src/components/objectinspector/objectinspector.cpp index 4267fea22d..c34df34f9b 100644 --- a/src/designer/src/components/objectinspector/objectinspector.cpp +++ b/src/designer/src/components/objectinspector/objectinspector.cpp @@ -61,9 +61,9 @@ #include #include -#include -#include #include +#include +#include QT_BEGIN_NAMESPACE @@ -90,7 +90,7 @@ namespace { // A widget managed by the form window cursor ManagedWidgetSelection }; - using QObjectVector = QVector; + using QObjectVector = QList; } static inline SelectionType selectionType(const QDesignerFormWindowInterface *fw, QObject *o) @@ -357,7 +357,7 @@ void ObjectInspector::ObjectInspectorPrivate::handleDragEnterMoveEvent(const QWi QWidget *dropTarget = nullptr; QPoint fakeDropTargetOffset = QPoint(0, 0); - if (QWidget *managedWidget = managedWidgetAt(objectInspectorWidget->mapToGlobal(event->pos()))) { + if (QWidget *managedWidget = managedWidgetAt(objectInspectorWidget->mapToGlobal(event->position().toPoint()))) { fakeDropTargetOffset = dropPointOffset(m_formWindow, managedWidget); // pretend we drag over the managed widget on the form const QPoint fakeFormPos = m_formWindow->mapFromGlobal(managedWidget->mapToGlobal(fakeDropTargetOffset)); @@ -424,7 +424,7 @@ bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) using ModelIndexSet = QSet; const QModelIndexList objectIndexes = indexesOf(o); - if (objectIndexes.empty()) + if (objectIndexes.isEmpty()) return false; QItemSelectionModel *selectionModel = m_treeView->selectionModel(); @@ -432,8 +432,10 @@ bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) const ModelIndexSet currentSelectedItems(currentSelectedItemList.cbegin(), currentSelectedItemList.cend()); // Change in selection? - if (!currentSelectedItems.empty() && currentSelectedItems == ModelIndexSet(objectIndexes.cbegin(), objectIndexes.cend())) + if (!currentSelectedItems.isEmpty() + && currentSelectedItems == ModelIndexSet(objectIndexes.cbegin(), objectIndexes.cend())) { return true; + } // do select and update selectIndexRange(objectIndexes, MakeCurrent); @@ -442,7 +444,7 @@ bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndexList &indexes, unsigned flags) { - if (indexes.empty()) + if (indexes.isEmpty()) return; QItemSelectionModel::SelectionFlags selectFlags = QItemSelectionModel::Select|QItemSelectionModel::Rows; @@ -459,7 +461,7 @@ void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndex selectFlags &= ~(QItemSelectionModel::Clear|QItemSelectionModel::Current); } if (flags & MakeCurrent) - m_treeView->scrollTo(indexes.front(), QAbstractItemView::EnsureVisible); + m_treeView->scrollTo(indexes.constFirst(), QAbstractItemView::EnsureVisible); } void ObjectInspector::ObjectInspectorPrivate::clear() @@ -528,10 +530,10 @@ void ObjectInspector::ObjectInspectorPrivate::setFormWindowBlocked(QDesignerForm bool applySelection = !mainContainerIsCurrent(m_formWindow); if (!applySelection) { const QModelIndexList currentIndexes = m_treeView->selectionModel()->selectedRows(0); - if (currentIndexes.empty()) { + if (currentIndexes.isEmpty()) { applySelection = true; } else { - applySelection = selectionType(m_formWindow, objectAt(currentIndexes.front())) == ManagedWidgetSelection; + applySelection = selectionType(m_formWindow, objectAt(currentIndexes.constFirst())) == ManagedWidgetSelection; } } if (applySelection) @@ -590,7 +592,7 @@ void ObjectInspector::ObjectInspectorPrivate::slotSelectionChanged(const QItemSe // some index lists are multicolumn ranges QObjectVector ObjectInspector::ObjectInspectorPrivate::indexesToObjects(const QModelIndexList &indexes) const { - if (indexes.empty()) + if (indexes.isEmpty()) return QObjectVector(); QObjectVector rc; rc.reserve(indexes.size()); @@ -638,11 +640,11 @@ void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSe const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); int deselectedManagedWidgetCount = 0; - if (!deselected.empty()) + if (!deselected.isEmpty()) deselectedManagedWidgetCount = selectInCursor(m_formWindow, deselected, false); - if (newlySelected.empty()) { // Nothing selected - if (currentSelectedIndexes.empty()) // Do not allow a null-selection, reset to main container + if (newlySelected.isEmpty()) { // Nothing selected + if (currentSelectedIndexes.isEmpty()) // Do not allow a null-selection, reset to main container m_formWindow->clearSelection(!m_withinClearSelection); return; } @@ -660,7 +662,7 @@ void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSe } // And now for the unmanaged selection m_formWindow->clearSelection(false); - QObject *unmanagedObject = newlySelected.front(); + QObject *unmanagedObject = newlySelected.constFirst(); m_core->propertyEditor()->setObject(unmanagedObject); m_core->propertyEditor()->setEnabled(true); // open container page if it is a single widget @@ -670,7 +672,7 @@ void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSe } // Open container page if it is a single widget if (newlySelected.size() == 1) { - QObject *object = newlySelected.back(); + QObject *object = newlySelected.constFirst(); if (object->isWidgetType()) showContainersCurrentPage(static_cast(object)); } @@ -693,7 +695,7 @@ void ObjectInspector::ObjectInspectorPrivate::getSelection(Selection &s) const return; const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); - if (currentSelectedIndexes.empty()) + if (currentSelectedIndexes.isEmpty()) return; // sort objects diff --git a/src/designer/src/components/objectinspector/objectinspector.pri b/src/designer/src/components/objectinspector/objectinspector.pri deleted file mode 100644 index ee666acb05..0000000000 --- a/src/designer/src/components/objectinspector/objectinspector.pri +++ /dev/null @@ -1,16 +0,0 @@ -# --- The Find widget is also linked into the designer_shared library. -# Avoid conflict when linking statically -contains(CONFIG, static) { - INCLUDEPATH *= ../../../../shared/findwidget -} else { - include(../../../../shared/findwidget/findwidget.pri) -} - -INCLUDEPATH += $$PWD - -HEADERS += $$PWD/objectinspector.h \ - $$PWD/objectinspectormodel_p.h \ - $$PWD/objectinspector_global.h - -SOURCES += $$PWD/objectinspector.cpp \ - $$PWD/objectinspectormodel.cpp diff --git a/src/designer/src/components/objectinspector/objectinspectormodel.cpp b/src/designer/src/components/objectinspector/objectinspectormodel.cpp index 6baf4bcdc5..3f8c6a6656 100644 --- a/src/designer/src/components/objectinspector/objectinspectormodel.cpp +++ b/src/designer/src/components/objectinspector/objectinspectormodel.cpp @@ -41,10 +41,12 @@ #include #include #include -#include #include #include #include + +#include + #include #include #include @@ -260,8 +262,6 @@ namespace qdesigner_internal { setItemsDisplayData(row, icons, ClassNameChanged|ObjectNameChanged|ClassIconChanged|TypeChanged|LayoutTypeChanged); } - using ObjectModel = QList; - // Recursive routine that creates the model by traversing the form window object tree. void createModelRecursion(const QDesignerFormWindowInterface *fwi, QObject *parent, @@ -270,8 +270,6 @@ namespace qdesigner_internal { const ModelRecursionContext &ctx) { using ButtonGroupList = QList; - using ActionList = QList; - // 1) Create entry const ObjectData entry(parent, object, ctx); model.push_back(entry); @@ -289,46 +287,41 @@ namespace qdesigner_internal { } } - QObjectList children = object->children(); - if (!children.empty()) { + if (!object->children().isEmpty()) { ButtonGroupList buttonGroups; + QObjectList children = object->children(); std::sort(children.begin(), children.end(), sortEntry); - const QObjectList::const_iterator cend = children.constEnd(); - for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + for (QObject *childObject : qAsConst(children)) { // Managed child widgets unless we had a container extension - if ((*it)->isWidgetType()) { + if (childObject->isWidgetType()) { if (!containerExtension) { - QWidget *widget = qobject_cast(*it); + QWidget *widget = qobject_cast(childObject); if (fwi->isManaged(widget)) createModelRecursion(fwi, object, widget, model, ctx); } } else { - if (ctx.mdb->item(*it)) { - if (QButtonGroup *bg = qobject_cast(*it)) + if (ctx.mdb->item(childObject)) { + if (auto bg = qobject_cast(childObject)) buttonGroups.push_back(bg); } // Has MetaDataBase entry } } // Add button groups - if (!buttonGroups.empty()) { - const ButtonGroupList::const_iterator bgcend = buttonGroups.constEnd(); - for (ButtonGroupList::const_iterator bgit = buttonGroups.constBegin(); bgit != bgcend; ++bgit) - createModelRecursion(fwi, object, *bgit, model, ctx); + if (!buttonGroups.isEmpty()) { + for (QButtonGroup *group : qAsConst(buttonGroups)) + createModelRecursion(fwi, object, group, model, ctx); } } // has children if (object->isWidgetType()) { // Add actions - const ActionList actions = static_cast(object)->actions(); - if (!actions.empty()) { - const ActionList::const_iterator cend = actions.constEnd(); - for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) - if (ctx.mdb->item(*it)) { - QAction *action = *it; - QObject *obj = action; - if (action->menu()) - obj = action->menu(); - createModelRecursion(fwi, object, obj, model, ctx); - } + const auto actions = static_cast(object)->actions(); + for (QAction *action : actions) { + if (ctx.mdb->item(action)) { + QObject *childObject = action; + if (auto menu = action->menu()) + childObject = menu; + createModelRecursion(fwi, object, childObject, model, ctx); + } } } } @@ -415,7 +408,7 @@ namespace qdesigner_internal { void ObjectInspectorModel::rebuild(const ObjectModel &newModel) { clearItems(); - if (newModel.empty()) + if (newModel.isEmpty()) return; const ObjectModel::const_iterator mcend = newModel.constEnd(); @@ -424,7 +417,7 @@ namespace qdesigner_internal { StandardItemList rootRow = createModelRow(it->object()); it->setItems(rootRow, m_icons); appendRow(rootRow); - m_objectIndexMultiMap.insert(it->object(), indexFromItem(rootRow.front())); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(rootRow.constFirst())); for (++it; it != mcend; ++it) { // Add to parent item, found via map const QModelIndex parentIndex = m_objectIndexMultiMap.value(it->parent(), QModelIndex()); @@ -433,7 +426,7 @@ namespace qdesigner_internal { StandardItemList row = createModelRow(it->object()); it->setItems(row, m_icons); parentItem->appendRow(row); - m_objectIndexMultiMap.insert(it->object(), indexFromItem(row.front())); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(row.constFirst())); } } @@ -470,7 +463,7 @@ namespace qdesigner_internal { const QVariant rc = QStandardItemModel::data(index, role); // Return if the string is empty for the display role // only (else, editing starts with ). - if (role == Qt::DisplayRole && rc.type() == QVariant::String) { + if (role == Qt::DisplayRole && rc.metaType().id() == QMetaType::QString) { const QString s = rc.toString(); if (s.isEmpty()) { static const QString noName = QCoreApplication::translate("ObjectInspectorModel", ""); diff --git a/src/designer/src/components/propertyeditor/brushpropertymanager.cpp b/src/designer/src/components/propertyeditor/brushpropertymanager.cpp index 41887cda2d..aa94e17f36 100644 --- a/src/designer/src/components/propertyeditor/brushpropertymanager.cpp +++ b/src/designer/src/components/propertyeditor/brushpropertymanager.cpp @@ -159,7 +159,8 @@ void BrushPropertyManager::initializeProperty(QtVariantPropertyManager *vm, QtPr m_brushPropertyToStyleSubProperty.insert(property, styleSubProperty); m_brushStyleSubPropertyToProperty.insert(styleSubProperty, property); // color - QtVariantProperty *colorSubProperty = vm->addProperty(QVariant::Color, QCoreApplication::translate("BrushPropertyManager", "Color")); + QtVariantProperty *colorSubProperty = + vm->addProperty(QMetaType::QColor, QCoreApplication::translate("BrushPropertyManager", "Color")); property->addSubProperty(colorSubProperty); m_brushPropertyToColorSubProperty.insert(property, colorSubProperty); m_brushColorSubPropertyToProperty.insert(colorSubProperty, property); @@ -207,8 +208,8 @@ void BrushPropertyManager::slotPropertyDestroyed(QtProperty *property) int BrushPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) { - switch (value.type()) { - case QVariant::Int: // Style subproperty? + switch (value.metaType().id()) { + case QMetaType::Int: // Style subproperty? if (QtProperty *brushProperty = m_brushStyleSubPropertyToProperty.value(property, 0)) { const QBrush oldValue = m_brushValues.value(brushProperty); QBrush newBrush = oldValue; @@ -220,7 +221,7 @@ int BrushPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty return DesignerPropertyManager::Changed; } break; - case QVariant::Color: // Color subproperty? + case QMetaType::QColor: // Color subproperty? if (QtProperty *brushProperty = m_brushColorSubPropertyToProperty.value(property, 0)) { const QBrush oldValue = m_brushValues.value(brushProperty); QBrush newBrush = oldValue; @@ -239,7 +240,7 @@ int BrushPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty int BrushPropertyManager::setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) { - if (value.type() != QVariant::Brush) + if (value.metaType().id() != QMetaType::QBrush) return DesignerPropertyManager::NoMatch; const PropertyBrushMap::iterator brit = m_brushValues.find(property); if (brit == m_brushValues.end()) diff --git a/src/designer/src/components/propertyeditor/designerpropertymanager.cpp b/src/designer/src/components/propertyeditor/designerpropertymanager.cpp index 2f1a65940c..7ec0eb5613 100644 --- a/src/designer/src/components/propertyeditor/designerpropertymanager.cpp +++ b/src/designer/src/components/propertyeditor/designerpropertymanager.cpp @@ -48,25 +48,26 @@ #include #include +#include #include #include #include -#include -#if QT_CONFIG(clipboard) -#include -#endif #include #include #include #include -#include #include #include + +#include +#if QT_CONFIG(clipboard) +#include +#endif #include -#include -#include #include +#include +#include QT_BEGIN_NAMESPACE @@ -103,28 +104,29 @@ void TranslatablePropertyManager::initialize(QtVariantProper { m_values.insert(property, value); - QtVariantProperty *translatable = m->addProperty(QVariant::Bool, DesignerPropertyManager::tr("translatable")); + QtVariantProperty *translatable = m->addProperty(QMetaType::Bool, DesignerPropertyManager::tr("translatable")); translatable->setValue(value.translatable()); m_valueToTranslatable.insert(property, translatable); m_translatableToValue.insert(translatable, property); property->addSubProperty(translatable); if (!DesignerPropertyManager::useIdBasedTranslations()) { - QtVariantProperty *disambiguation = m->addProperty(QVariant::String, DesignerPropertyManager::tr("disambiguation")); + QtVariantProperty *disambiguation = + m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("disambiguation")); disambiguation->setValue(value.disambiguation()); m_valueToDisambiguation.insert(property, disambiguation); m_disambiguationToValue.insert(disambiguation, property); property->addSubProperty(disambiguation); } - QtVariantProperty *comment = m->addProperty(QVariant::String, DesignerPropertyManager::tr("comment")); + QtVariantProperty *comment = m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("comment")); comment->setValue(value.comment()); m_valueToComment.insert(property, comment); m_commentToValue.insert(comment, property); property->addSubProperty(comment); if (DesignerPropertyManager::useIdBasedTranslations()) { - QtVariantProperty *id = m->addProperty(QVariant::String, DesignerPropertyManager::tr("id")); + QtVariantProperty *id = m->addProperty(QMetaType::QString, DesignerPropertyManager::tr("id")); id->setValue(value.id()); m_valueToId.insert(property, id); m_idToValue.insert(id, property); @@ -1012,7 +1014,7 @@ void DesignerPropertyManager::slotValueChanged(QtProperty *property, const QVari } if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { - const QList subFlags = m_propertyToFlags.value(flagProperty); + const auto subFlags = m_propertyToFlags.value(flagProperty); const int subFlagCount = subFlags.count(); // flag changed const bool subValue = variantProperty(property)->value().toBool(); @@ -1025,7 +1027,7 @@ void DesignerPropertyManager::slotValueChanged(QtProperty *property, const QVari m_changingSubValue = true; FlagData data = m_flagValues.value(flagProperty); - const QList values = data.values; + const auto values = data.values; // Compute new value, without including (additional) supermasks if (values.at(subIndex) == 0) { for (int i = 0; i < subFlagCount; ++i) { @@ -1123,7 +1125,7 @@ void DesignerPropertyManager::slotPropertyDestroyed(QtProperty *property) { if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { PropertyToPropertyListMap::iterator it = m_propertyToFlags.find(flagProperty); - QList &propertyList = it.value(); + auto &propertyList = it.value(); propertyList.replace(propertyList.indexOf(property), 0); m_flagToProperty.remove(property); } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) { @@ -1165,11 +1167,11 @@ QStringList DesignerPropertyManager::attributes(int propertyType) const list.append(QLatin1String(defaultResourceAttributeC)); } else if (propertyType == designerIconTypeId()) { list.append(QLatin1String(defaultResourceAttributeC)); - } else if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + } else if (propertyType == designerStringTypeId() || propertyType == QMetaType::QString) { list.append(QLatin1String(validationModesAttributeC)); list.append(QLatin1String(fontAttributeC)); list.append(QLatin1String(themeAttributeC)); - } else if (propertyType == QVariant::Palette) { + } else if (propertyType == QMetaType::QPalette) { list.append(QLatin1String(superPaletteAttributeC)); } list.append(QLatin1String(resettableAttributeC)); @@ -1184,21 +1186,21 @@ int DesignerPropertyManager::attributeType(int propertyType, const QString &attr if (propertyType == designerFlagTypeId() && attribute == QLatin1String(flagsAttributeC)) return designerFlagListTypeId(); if (propertyType == designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) - return QVariant::Pixmap; + return QMetaType::QPixmap; if (propertyType == designerIconTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) - return QVariant::Icon; + return QMetaType::QIcon; if (attribute == QLatin1String(resettableAttributeC)) - return QVariant::Bool; - if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + return QMetaType::Bool; + if (propertyType == designerStringTypeId() || propertyType == QMetaType::QString) { if (attribute == QLatin1String(validationModesAttributeC)) - return QVariant::Int; + return QMetaType::Int; if (attribute == QLatin1String(fontAttributeC)) - return QVariant::Font; + return QMetaType::QFont; if (attribute == QLatin1String(themeAttributeC)) - return QVariant::Bool; + return QMetaType::Bool; } - if (propertyType == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) - return QVariant::Palette; + if (propertyType == QMetaType::QPalette && attribute == QLatin1String(superPaletteAttributeC)) + return QMetaType::QPalette; return QtVariantPropertyManager::attributeType(propertyType, attribute); } @@ -1262,7 +1264,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, const QString &attribute, const QVariant &value) { if (attribute == QLatin1String(resettableAttributeC) && m_resetMap.contains(property)) { - if (value.userType() != QVariant::Bool) + if (value.userType() != QMetaType::Bool) return; const bool val = value.toBool(); const PropertyBoolMap::iterator it = m_resetMap.find(property); @@ -1295,7 +1297,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, for (const QPair &pair : flags) { const QString flagName = pair.first; - QtProperty *prop = addProperty(QVariant::Bool); + QtProperty *prop = addProperty(QMetaType::Bool); prop->setPropertyName(flagName); property->addSubProperty(prop); m_propertyToFlags[property].append(prop); @@ -1316,7 +1318,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit propertyChanged(property); emit QtVariantPropertyManager::valueChanged(property, data.val); } else if (attribute == QLatin1String(validationModesAttributeC) && m_stringAttributes.contains(property)) { - if (value.userType() != QVariant::Int) + if (value.userType() != QMetaType::Int) return; const PropertyIntMap::iterator it = m_stringAttributes.find(property); @@ -1331,7 +1333,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit attributeChanged(property, attribute, newValue); } else if (attribute == QLatin1String(fontAttributeC) && m_stringFontAttributes.contains(property)) { - if (value.userType() != QVariant::Font) + if (value.userType() != QMetaType::QFont) return; const PropertyFontMap::iterator it = m_stringFontAttributes.find(property); @@ -1346,7 +1348,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit attributeChanged(property, attribute, newValue); } else if (attribute == QLatin1String(themeAttributeC) && m_stringThemeAttributes.contains(property)) { - if (value.userType() != QVariant::Bool) + if (value.userType() != QMetaType::Bool) return; const PropertyBoolMap::iterator it = m_stringThemeAttributes.find(property); @@ -1361,7 +1363,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit attributeChanged(property, attribute, newValue); } else if (attribute == QLatin1String(superPaletteAttributeC) && m_paletteValues.contains(property)) { - if (value.userType() != QVariant::Palette) + if (value.userType() != QMetaType::QPalette) return; QPalette superPalette = qvariant_cast(value); @@ -1373,9 +1375,9 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, data.superPalette = superPalette; // resolve here - const uint mask = data.val.resolve(); + const uint mask = data.val.resolveMask(); data.val = data.val.resolve(superPalette); - data.val.resolve(mask); + data.val.setResolveMask(mask); it.value() = data; @@ -1386,7 +1388,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit propertyChanged(property); emit QtVariantPropertyManager::valueChanged(property, data.val); // if resolve was done, this is also for consistency } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultPixmaps.contains(property)) { - if (value.userType() != QVariant::Pixmap) + if (value.userType() != QMetaType::QPixmap) return; QPixmap defaultPixmap = qvariant_cast(value); @@ -1403,7 +1405,7 @@ void DesignerPropertyManager::setAttribute(QtProperty *property, emit propertyChanged(property); } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultIcons.contains(property)) { - if (value.userType() != QVariant::Icon) + if (value.userType() != QMetaType::QIcon) return; QIcon defaultIcon = qvariant_cast(value); @@ -1480,14 +1482,14 @@ int DesignerPropertyManager::designerKeySequenceTypeId() bool DesignerPropertyManager::isPropertyTypeSupported(int propertyType) const { switch (propertyType) { - case QVariant::Palette: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Url: - case QVariant::ByteArray: - case QVariant::StringList: - case QVariant::Brush: + case QMetaType::QPalette: + case QMetaType::UInt: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::QUrl: + case QMetaType::QByteArray: + case QMetaType::QStringList: + case QMetaType::QBrush: return true; default: break; @@ -1516,15 +1518,13 @@ QString DesignerPropertyManager::valueText(const QtProperty *property) const const uint v = data.val; const QChar bar = QLatin1Char('|'); QString valueStr; - const QList > flags = data.flags; - const QList >::const_iterator fcend = flags.constEnd(); - for (QList >::const_iterator it = flags.constBegin(); it != fcend; ++it) { - const uint val = it->second; + for (const DesignerIntPair &p : data.flags) { + const uint val = p.second; const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); if (checked) { if (!valueStr.isEmpty()) valueStr += bar; - valueStr += it->first; + valueStr += p.first; } } return valueStr; @@ -1536,7 +1536,7 @@ QString DesignerPropertyManager::valueText(const QtProperty *property) const } if (m_paletteValues.contains(const_cast(property))) { const PaletteData data = m_paletteValues.value(const_cast(property)); - const uint mask = data.val.resolve(); + const uint mask = data.val.resolveMask(); if (mask) return tr("Customized (%n roles)", nullptr, bitCount(mask)); static const QString inherited = tr("Inherited"); @@ -1575,20 +1575,22 @@ QString DesignerPropertyManager::valueText(const QtProperty *property) const return QString::fromUtf8(m_byteArrayValues.value(const_cast(property))); } const int vType = QtVariantPropertyManager::valueType(property); - if (vType == QVariant::String || vType == designerStringTypeId()) { - const QString str = (QtVariantPropertyManager::valueType(property) == QVariant::String) ? value(property).toString() : qvariant_cast(value(property)).value(); + if (vType == QMetaType::QString || vType == designerStringTypeId()) { + const QString str = (QtVariantPropertyManager::valueType(property) == QMetaType::QString) + ? value(property).toString() : qvariant_cast(value(property)).value(); const int validationMode = attributeValue(property, QLatin1String(validationModesAttributeC)).toInt(); return TextPropertyEditor::stringToEditorString(str, static_cast(validationMode)); } - if (vType == QVariant::StringList || vType == designerStringListTypeId()) { + if (vType == QMetaType::QStringList || vType == designerStringListTypeId()) { QVariant v = value(property); - const QStringList list = v.type() == QVariant::StringList ? v.toStringList() : qvariant_cast(v).value(); + const QStringList list = v.metaType().id() == QMetaType::QStringList + ? v.toStringList() : qvariant_cast(v).value(); return list.join(QLatin1String("; ")); } if (vType == designerKeySequenceTypeId()) { return qvariant_cast(value(property)).value().toString(QKeySequence::NativeText); } - if (vType == QVariant::Bool) { + if (vType == QMetaType::Bool) { return QString(); } @@ -1696,22 +1698,22 @@ QVariant DesignerPropertyManager::value(const QtProperty *property) const int DesignerPropertyManager::valueType(int propertyType) const { switch (propertyType) { - case QVariant::Palette: - case QVariant::UInt: - case QVariant::LongLong: - case QVariant::ULongLong: - case QVariant::Url: - case QVariant::ByteArray: - case QVariant::StringList: - case QVariant::Brush: + case QMetaType::QPalette: + case QMetaType::UInt: + case QMetaType::LongLong: + case QMetaType::ULongLong: + case QMetaType::QUrl: + case QMetaType::QByteArray: + case QMetaType::QStringList: + case QMetaType::QBrush: return propertyType; default: break; } if (propertyType == designerFlagTypeId()) - return QVariant::UInt; + return QMetaType::UInt; if (propertyType == designerAlignmentTypeId()) - return QVariant::UInt; + return QMetaType::UInt; if (propertyType == designerPixmapTypeId()) return propertyType; if (propertyType == designerIconTypeId()) @@ -1743,7 +1745,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val const PropertyFlagDataMap::iterator fit = m_flagValues.find(property); if (fit != m_flagValues.end()) { - if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + if (value.metaType().id() != QMetaType::UInt && !value.canConvert()) return; const uint v = value.toUInt(); @@ -1754,8 +1756,8 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val // set Value - const QList values = data.values; - const QList subFlags = m_propertyToFlags.value(property); + const auto values = data.values; + const auto subFlags = m_propertyToFlags.value(property); const int subFlagCount = subFlags.count(); for (int i = 0; i < subFlagCount; ++i) { QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); @@ -1795,7 +1797,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_alignValues.contains(property)) { - if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + if (value.metaType().id() != QMetaType::UInt && !value.canConvert()) return; const uint v = value.toUInt(); @@ -1821,18 +1823,18 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_paletteValues.contains(property)) { - if (value.type() != QVariant::Palette && !value.canConvert(QVariant::Palette)) + if (value.metaType().id() != QMetaType::QPalette && !value.canConvert()) return; QPalette p = qvariant_cast(value); PaletteData data = m_paletteValues.value(property); - const uint mask = p.resolve(); + const uint mask = p.resolveMask(); p = p.resolve(data.superPalette); - p.resolve(mask); + p.setResolveMask(mask); - if (data.val == p && data.val.resolve() == p.resolve()) + if (data.val == p && data.val.resolveMask() == p.resolveMask()) return; data.val = p; @@ -1916,7 +1918,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_uintValues.contains(property)) { - if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + if (value.metaType().id() != QMetaType::UInt && !value.canConvert()) return; const uint v = value.toUInt(nullptr); @@ -1933,7 +1935,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_longLongValues.contains(property)) { - if (value.type() != QVariant::LongLong && !value.canConvert(QVariant::LongLong)) + if (value.metaType().id() != QMetaType::LongLong && !value.canConvert()) return; const qlonglong v = value.toLongLong(nullptr); @@ -1950,7 +1952,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_uLongLongValues.contains(property)) { - if (value.type() != QVariant::ULongLong && !value.canConvert(QVariant::ULongLong)) + if (value.metaType().id() != QMetaType::ULongLong && !value.canConvert()) return; qulonglong v = value.toULongLong(nullptr); @@ -1967,7 +1969,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_urlValues.contains(property)) { - if (value.type() != QVariant::Url && !value.canConvert(QVariant::Url)) + if (value.metaType().id() != QMetaType::QUrl && !value.canConvert()) return; const QUrl v = value.toUrl(); @@ -1984,7 +1986,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val return; } if (m_byteArrayValues.contains(property)) { - if (value.type() != QVariant::ByteArray && !value.canConvert(QVariant::ByteArray)) + if (value.metaType().id() != QMetaType::QByteArray && !value.canConvert()) return; const QByteArray v = value.toByteArray(); @@ -2002,7 +2004,7 @@ void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &val } m_fontManager.setValue(this, property, value); QtVariantPropertyManager::setValue(property, value); - if (QtVariantPropertyManager::valueType(property) == QVariant::Bool) + if (QtVariantPropertyManager::valueType(property) == QMetaType::Bool) property->setToolTip(QtVariantPropertyManager::valueText(property)); } @@ -2013,30 +2015,30 @@ void DesignerPropertyManager::initializeProperty(QtProperty *property) const int type = propertyType(property); m_fontManager.preInitializeProperty(property, type, m_resetMap); switch (type) { - case QVariant::Palette: + case QMetaType::QPalette: m_paletteValues[property] = PaletteData(); break; - case QVariant::String: + case QMetaType::QString: m_stringAttributes[property] = ValidationSingleLine; m_stringFontAttributes[property] = QApplication::font(); m_stringThemeAttributes[property] = false; break; - case QVariant::UInt: + case QMetaType::UInt: m_uintValues[property] = 0; break; - case QVariant::LongLong: + case QMetaType::LongLong: m_longLongValues[property] = 0; break; - case QVariant::ULongLong: + case QMetaType::ULongLong: m_uLongLongValues[property] = 0; break; - case QVariant::Url: + case QMetaType::QUrl: m_urlValues[property] = QUrl(); break; - case QVariant::ByteArray: - m_byteArrayValues[property] = nullptr; + case QMetaType::QByteArray: + m_byteArrayValues[property] = QByteArray(); break; - case QVariant::Brush: + case QMetaType::QBrush: m_brushManager.initializeProperty(this, property, enumTypeId()); break; default: @@ -2071,7 +2073,7 @@ void DesignerPropertyManager::initializeProperty(QtProperty *property) m_iconValues[property] = PropertySheetIconValue(); m_defaultIcons[property] = QIcon(); - QtVariantProperty *themeProp = addProperty(QVariant::String, tr("Theme")); + QtVariantProperty *themeProp = addProperty(QMetaType::QString, tr("Theme")); themeProp->setAttribute(QLatin1String(themeAttributeC), true); m_iconSubPropertyToProperty[themeProp] = property; m_propertyToTheme[property] = themeProp; @@ -2100,7 +2102,7 @@ void DesignerPropertyManager::initializeProperty(QtProperty *property) QtVariantPropertyManager::initializeProperty(property); m_fontManager.postInitializeProperty(this, property, type, DesignerPropertyManager::enumTypeId()); - if (type == QVariant::Double) + if (type == QMetaType::Double) setAttribute(property, QStringLiteral("decimals"), 6); } @@ -2272,7 +2274,7 @@ void DesignerEditorFactory::disconnectPropertyManager(QtVariantPropertyManager * template static inline void applyToEditors(const EditorContainer &list, void (Editor::*setter)(SetterParameter), const Value &value) { - if (list.empty()) { + if (list.isEmpty()) { return; } for (auto it = list.constBegin(), end = list.constEnd(); it != end; ++it) { @@ -2288,7 +2290,7 @@ void DesignerEditorFactory::slotAttributeChanged(QtProperty *property, const QSt if (type == DesignerPropertyManager::designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) { const QPixmap pixmap = qvariant_cast(value); applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setDefaultPixmap, pixmap); - } else if (type == DesignerPropertyManager::designerStringTypeId() || type == QVariant::String) { + } else if (type == DesignerPropertyManager::designerStringTypeId() || type == QMetaType::QString) { if (attribute == QLatin1String(validationModesAttributeC)) { const TextPropertyValidationMode validationMode = static_cast(value.toInt()); applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setTextPropertyValidationMode, validationMode); @@ -2301,7 +2303,7 @@ void DesignerEditorFactory::slotAttributeChanged(QtProperty *property, const QSt const bool themeEnabled = value.toBool(); applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setIconThemeModeEnabled, themeEnabled); } - } else if (type == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) { + } else if (type == QMetaType::QPalette && attribute == QLatin1String(superPaletteAttributeC)) { const QPalette palette = qvariant_cast(value); applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setSuperPalette, palette); } @@ -2317,7 +2319,7 @@ void DesignerEditorFactory::slotPropertyChanged(QtProperty *property) defaultPixmap = qvariant_cast(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC))).pixmap(16, 16); else if (m_fwb) defaultPixmap = m_fwb->iconCache()->icon(qvariant_cast(manager->value(property))).pixmap(16, 16); - const QList editors = m_iconPropertyToEditors.value(property); + const auto editors = m_iconPropertyToEditors.value(property); for (PixmapEditor *editor : editors) editor->setDefaultPixmap(defaultPixmap); } @@ -2331,28 +2333,28 @@ void DesignerEditorFactory::slotValueChanged(QtProperty *property, const QVarian QtVariantPropertyManager *manager = propertyManager(property); const int type = manager->propertyType(property); switch (type) { - case QVariant::String: + case QMetaType::QString: applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, value.toString()); break; - case QVariant::Palette: + case QMetaType::QPalette: applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setPalette, qvariant_cast(value)); break; - case QVariant::UInt: + case QMetaType::UInt: applyToEditors(m_uintPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toUInt())); break; - case QVariant::LongLong: + case QMetaType::LongLong: applyToEditors(m_longLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toLongLong())); break; - case QVariant::ULongLong: + case QMetaType::ULongLong: applyToEditors(m_uLongLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toULongLong())); break; - case QVariant::Url: + case QMetaType::QUrl: applyToEditors(m_urlPropertyToEditors.value(property), &TextEditor::setText, value.toUrl().toString()); break; - case QVariant::ByteArray: + case QMetaType::QByteArray: applyToEditors(m_byteArrayPropertyToEditors.value(property), &TextEditor::setText, QString::fromUtf8(value.toByteArray())); break; - case QVariant::StringList: + case QMetaType::QStringList: applyToEditors(m_stringListPropertyToEditors.value(property), &StringListEditorButton::setStringList, value.toStringList()); break; default: @@ -2389,18 +2391,18 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, QWidget *editor = nullptr; const int type = manager->propertyType(property); switch (type) { - case QVariant::Bool: { + case QMetaType::Bool: { editor = QtVariantEditorFactory::createEditor(manager, property, parent); QtBoolEdit *boolEdit = qobject_cast(editor); if (boolEdit) boolEdit->setTextVisible(false); } break; - case QVariant::String: { + case QMetaType::QString: { const TextPropertyValidationMode tvm = static_cast(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); TextEditor *ed = createTextEditor(parent, tvm, manager->value(property).toString()); const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); - if (richTextDefaultFont.type() == QVariant::Font) + if (richTextDefaultFont.metaType().id() == QMetaType::QFont) ed->setRichTextDefaultFont(qvariant_cast(richTextDefaultFont)); const bool themeEnabled = manager->attributeValue(property, QLatin1String(themeAttributeC)).toBool(); ed->setIconThemeModeEnabled(themeEnabled); @@ -2411,7 +2413,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::Palette: { + case QMetaType::QPalette: { PaletteEditorButton *ed = new PaletteEditorButton(m_core, qvariant_cast(manager->value(property)), parent); ed->setSuperPalette(qvariant_cast(manager->attributeValue(property, QLatin1String(superPaletteAttributeC)))); m_palettePropertyToEditors[property].append(ed); @@ -2421,7 +2423,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::UInt: { + case QMetaType::UInt: { QLineEdit *ed = new QLineEdit(parent); ed->setValidator(new QULongLongValidator(0, UINT_MAX, ed)); ed->setText(QString::number(manager->value(property).toUInt())); @@ -2432,7 +2434,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::LongLong: { + case QMetaType::LongLong: { QLineEdit *ed = new QLineEdit(parent); ed->setValidator(new QLongLongValidator(ed)); ed->setText(QString::number(manager->value(property).toLongLong())); @@ -2443,7 +2445,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::ULongLong: { + case QMetaType::ULongLong: { QLineEdit *ed = new QLineEdit(parent); ed->setValidator(new QULongLongValidator(ed)); ed->setText(QString::number(manager->value(property).toULongLong())); @@ -2454,7 +2456,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::Url: { + case QMetaType::QUrl: { TextEditor *ed = createTextEditor(parent, ValidationURL, manager->value(property).toUrl().toString()); ed->setUpdateMode(TextPropertyEditor::UpdateOnFinished); m_urlPropertyToEditors[property].append(ed); @@ -2464,7 +2466,7 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, editor = ed; } break; - case QVariant::ByteArray: { + case QMetaType::QByteArray: { TextEditor *ed = createTextEditor(parent, ValidationMultiLine, QString::fromUtf8(manager->value(property).toByteArray())); m_byteArrayPropertyToEditors[property].append(ed); m_editorToByteArrayProperty[ed] = property; @@ -2509,17 +2511,17 @@ QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, const TextPropertyValidationMode tvm = static_cast(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); TextEditor *ed = createTextEditor(parent, tvm, qvariant_cast(manager->value(property)).value()); const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); - if (richTextDefaultFont.type() == QVariant::Font) + if (richTextDefaultFont.metaType().id() == QMetaType::QFont) ed->setRichTextDefaultFont(qvariant_cast(richTextDefaultFont)); m_stringPropertyToEditors[property].append(ed); m_editorToStringProperty[ed] = property; connect(ed, &QObject::destroyed, this, &DesignerEditorFactory::slotEditorDestroyed); connect(ed, &TextEditor::textChanged, this, &DesignerEditorFactory::slotStringTextChanged); editor = ed; - } else if (type == DesignerPropertyManager::designerStringListTypeId() || type == QVariant::StringList) { + } else if (type == DesignerPropertyManager::designerStringListTypeId() || type == QMetaType::QStringList) { const QVariant variantValue = manager->value(property); - const QStringList value = type == QVariant::StringList ? variantValue.toStringList() : - qvariant_cast(variantValue).value(); + const QStringList value = type == QMetaType::QStringList + ? variantValue.toStringList() : qvariant_cast(variantValue).value(); StringListEditorButton *ed = new StringListEditorButton(value, parent); m_stringListPropertyToEditors[property].append(ed); m_editorToStringListProperty.insert(ed, property); @@ -2659,7 +2661,7 @@ void DesignerEditorFactory::slotStringTextChanged(const QString &value) PropertySheetStringValue strVal = qvariant_cast(val); strVal.setValue(value); // Disable translation if no translation subproperties exist. - if (varProp->subProperties().empty()) + if (varProp->subProperties().isEmpty()) strVal.setTranslatable(false); val = QVariant::fromValue(strVal); } else { @@ -2725,7 +2727,7 @@ void DesignerEditorFactory::slotStringListChanged(const QStringList &value) PropertySheetStringListValue listValue = qvariant_cast(val); listValue.setValue(value); // Disable translation if no translation subproperties exist. - if (varProp->subProperties().empty()) + if (varProp->subProperties().isEmpty()) listValue.setTranslatable(false); val = QVariant::fromValue(listValue); } else { @@ -2746,7 +2748,7 @@ ResetDecorator::ResetDecorator(const QDesignerFormEditorInterface *core, QObject ResetDecorator::~ResetDecorator() { - const QList editors = m_resetWidgetToProperty.keys(); + const auto editors = m_resetWidgetToProperty.keys(); qDeleteAll(editors); } @@ -2819,7 +2821,7 @@ QWidget *ResetDecorator::editor(QWidget *subEditor, bool resettable, QtAbstractP void ResetDecorator::slotPropertyChanged(QtProperty *property) { - QMap >::ConstIterator prIt = m_createdResetWidgets.constFind(property); + const auto prIt = m_createdResetWidgets.constFind(property); if (prIt == m_createdResetWidgets.constEnd()) return; diff --git a/src/designer/src/components/propertyeditor/fontpropertymanager.cpp b/src/designer/src/components/propertyeditor/fontpropertymanager.cpp index a29867011b..4974e7975a 100644 --- a/src/designer/src/components/propertyeditor/fontpropertymanager.cpp +++ b/src/designer/src/components/propertyeditor/fontpropertymanager.cpp @@ -79,14 +79,14 @@ namespace qdesigner_internal { resetMap[property] = true; } - if (type == QVariant::Font) + if (type == QMetaType::QFont) m_createdFontProperty = property; } // Map the font family names to display names retrieved from the XML configuration static QStringList designerFamilyNames(QStringList families, const FontPropertyManager::NameMap &nm) { - if (nm.empty()) + if (nm.isEmpty()) return families; const auto ncend = nm.constEnd(); @@ -103,7 +103,7 @@ namespace qdesigner_internal { int type, int enumTypeId) { - if (type != QVariant::Font) + if (type != QMetaType::QFont) return; // This will cause a recursion @@ -117,9 +117,9 @@ namespace qdesigner_internal { m_propertyToAntialiasing[property] = antialiasing; m_antialiasingToProperty[antialiasing] = property; // Fiddle family names - if (!m_familyMappings.empty()) { + if (!m_familyMappings.isEmpty()) { const PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(m_createdFontProperty); - QtVariantProperty *familyProperty = vm->variantProperty(it.value().front()); + QtVariantProperty *familyProperty = vm->variantProperty(it.value().constFirst()); const QString enumNamesAttribute = QStringLiteral("enumNames"); QStringList plainFamilyNames = familyProperty->attributeValue(enumNamesAttribute).toStringList(); // Did someone load fonts or something? @@ -176,11 +176,11 @@ namespace qdesigner_internal { QVariant v = fontProperty->value(); QFont font = qvariant_cast(v); - unsigned mask = font.resolve(); + unsigned mask = font.resolveMask(); const unsigned flag = fontFlag(m_fontSubPropertyToFlag.value(property)); mask &= ~flag; - font.resolve(mask); + font.setResolveMask(mask); v.setValue(font); fontProperty->setValue(v); return true; @@ -254,7 +254,7 @@ namespace qdesigner_internal { const PropertyList &subProperties = it.value(); QFont font = qvariant_cast(value); - const unsigned mask = font.resolve(); + const unsigned mask = font.resolveMask(); const int count = subProperties.size(); for (int index = 0; index < count; index++) { @@ -295,7 +295,7 @@ namespace qdesigner_internal { enum ParseStage { ParseBeginning, ParseWithinRoot, ParseWithinMapping, ParseWithinFamily, ParseWithinDisplay, ParseError }; - static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) + static ParseStage nextStage(ParseStage currentStage, QStringView startElement) { switch (currentStage) { case ParseBeginning: diff --git a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp index 0a0046c9c6..91d554c8b6 100644 --- a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp +++ b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp @@ -48,34 +48,62 @@ NewDynamicPropertyDialog::NewDynamicPropertyDialog(QDesignerDialogGuiInterface * setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - m_ui->m_comboBox->addItem(QStringLiteral("String"), QVariant(QVariant::String)); - m_ui->m_comboBox->addItem(QStringLiteral("StringList"), QVariant(QVariant::StringList)); - m_ui->m_comboBox->addItem(QStringLiteral("Char"), QVariant(QVariant::Char)); - m_ui->m_comboBox->addItem(QStringLiteral("ByteArray"), QVariant(QVariant::ByteArray)); - m_ui->m_comboBox->addItem(QStringLiteral("Url"), QVariant(QVariant::Url)); - m_ui->m_comboBox->addItem(QStringLiteral("Bool"), QVariant(QVariant::Bool)); - m_ui->m_comboBox->addItem(QStringLiteral("Int"), QVariant(QVariant::Int)); - m_ui->m_comboBox->addItem(QStringLiteral("UInt"), QVariant(QVariant::UInt)); - m_ui->m_comboBox->addItem(QStringLiteral("LongLong"), QVariant(QVariant::LongLong)); - m_ui->m_comboBox->addItem(QStringLiteral("ULongLong"), QVariant(QVariant::ULongLong)); - m_ui->m_comboBox->addItem(QStringLiteral("Double"), QVariant(QVariant::Double)); - m_ui->m_comboBox->addItem(QStringLiteral("Size"), QVariant(QVariant::Size)); - m_ui->m_comboBox->addItem(QStringLiteral("SizeF"), QVariant(QVariant::SizeF)); - m_ui->m_comboBox->addItem(QStringLiteral("Point"), QVariant(QVariant::Point)); - m_ui->m_comboBox->addItem(QStringLiteral("PointF"), QVariant(QVariant::PointF)); - m_ui->m_comboBox->addItem(QStringLiteral("Rect"), QVariant(QVariant::Rect)); - m_ui->m_comboBox->addItem(QStringLiteral("RectF"), QVariant(QVariant::RectF)); - m_ui->m_comboBox->addItem(QStringLiteral("Date"), QVariant(QVariant::Date)); - m_ui->m_comboBox->addItem(QStringLiteral("Time"), QVariant(QVariant::Time)); - m_ui->m_comboBox->addItem(QStringLiteral("DateTime"), QVariant(QVariant::DateTime)); - m_ui->m_comboBox->addItem(QStringLiteral("Font"), QVariant(QVariant::Font)); - m_ui->m_comboBox->addItem(QStringLiteral("Palette"), QVariant(QVariant::Palette)); - m_ui->m_comboBox->addItem(QStringLiteral("Color"), QVariant(QVariant::Color)); - m_ui->m_comboBox->addItem(QStringLiteral("Pixmap"), QVariant(QVariant::Pixmap)); - m_ui->m_comboBox->addItem(QStringLiteral("Icon"), QVariant(QVariant::Icon)); - m_ui->m_comboBox->addItem(QStringLiteral("Cursor"), QVariant(QVariant::Cursor)); - m_ui->m_comboBox->addItem(QStringLiteral("SizePolicy"), QVariant(QVariant::SizePolicy)); - m_ui->m_comboBox->addItem(QStringLiteral("KeySequence"), QVariant(QVariant::KeySequence)); + m_ui->m_comboBox->addItem(QStringLiteral("String"), + QVariant(QMetaType(QMetaType::QString))); + m_ui->m_comboBox->addItem(QStringLiteral("StringList"), + QVariant(QMetaType(QMetaType::QStringList))); + m_ui->m_comboBox->addItem(QStringLiteral("Char"), + QVariant(QMetaType(QMetaType::QChar))); + m_ui->m_comboBox->addItem(QStringLiteral("ByteArray"), + QVariant(QMetaType(QMetaType::QByteArray))); + m_ui->m_comboBox->addItem(QStringLiteral("Url"), + QVariant(QMetaType(QMetaType::QUrl))); + m_ui->m_comboBox->addItem(QStringLiteral("Bool"), + QVariant(QMetaType(QMetaType::Bool))); + m_ui->m_comboBox->addItem(QStringLiteral("Int"), + QVariant(QMetaType(QMetaType::Int))); + m_ui->m_comboBox->addItem(QStringLiteral("UInt"), + QVariant(QMetaType(QMetaType::UInt))); + m_ui->m_comboBox->addItem(QStringLiteral("LongLong"), + QVariant(QMetaType(QMetaType::LongLong))); + m_ui->m_comboBox->addItem(QStringLiteral("ULongLong"), + QVariant(QMetaType(QMetaType::ULongLong))); + m_ui->m_comboBox->addItem(QStringLiteral("Double"), + QVariant(QMetaType(QMetaType::Double))); + m_ui->m_comboBox->addItem(QStringLiteral("Size"), + QVariant(QMetaType(QMetaType::QSize))); + m_ui->m_comboBox->addItem(QStringLiteral("SizeF"), + QVariant(QMetaType(QMetaType::QSizeF))); + m_ui->m_comboBox->addItem(QStringLiteral("Point"), + QVariant(QMetaType(QMetaType::QPoint))); + m_ui->m_comboBox->addItem(QStringLiteral("PointF"), + QVariant(QMetaType(QMetaType::QPointF))); + m_ui->m_comboBox->addItem(QStringLiteral("Rect"), + QVariant(QMetaType(QMetaType::QRect))); + m_ui->m_comboBox->addItem(QStringLiteral("RectF"), + QVariant(QMetaType(QMetaType::QRectF))); + m_ui->m_comboBox->addItem(QStringLiteral("Date"), + QVariant(QMetaType(QMetaType::QDate))); + m_ui->m_comboBox->addItem(QStringLiteral("Time"), + QVariant(QMetaType(QMetaType::QTime))); + m_ui->m_comboBox->addItem(QStringLiteral("DateTime"), + QVariant(QMetaType(QMetaType::QDateTime))); + m_ui->m_comboBox->addItem(QStringLiteral("Font"), + QVariant(QMetaType(QMetaType::QFont))); + m_ui->m_comboBox->addItem(QStringLiteral("Palette"), + QVariant(QMetaType(QMetaType::QPalette))); + m_ui->m_comboBox->addItem(QStringLiteral("Color"), + QVariant(QMetaType(QMetaType::QColor))); + m_ui->m_comboBox->addItem(QStringLiteral("Pixmap"), + QVariant(QMetaType(QMetaType::QPixmap))); + m_ui->m_comboBox->addItem(QStringLiteral("Icon"), + QVariant(QMetaType(QMetaType::QIcon))); + m_ui->m_comboBox->addItem(QStringLiteral("Cursor"), + QVariant(QMetaType(QMetaType::QCursor))); + m_ui->m_comboBox->addItem(QStringLiteral("SizePolicy"), + QVariant(QMetaType(QMetaType::QSizePolicy))); + m_ui->m_comboBox->addItem(QStringLiteral("KeySequence"), + QVariant(QMetaType(QMetaType::QKeySequence))); m_ui->m_comboBox->setCurrentIndex(0); // String setOkButtonEnabled(false); @@ -96,9 +124,9 @@ void NewDynamicPropertyDialog::setReservedNames(const QStringList &names) m_reservedNames = names; } -void NewDynamicPropertyDialog::setPropertyType(QVariant::Type t) +void NewDynamicPropertyDialog::setPropertyType(int t) { - const int index = m_ui->m_comboBox->findData(QVariant(t)); + const int index = m_ui->m_comboBox->findData(QVariant(QMetaType(t))); if (index != -1) m_ui->m_comboBox->setCurrentIndex(index); } diff --git a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h index 17daee4c38..0c3e245705 100644 --- a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h +++ b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h @@ -64,7 +64,7 @@ class QT_PROPERTYEDITOR_EXPORT NewDynamicPropertyDialog: public QDialog ~NewDynamicPropertyDialog(); void setReservedNames(const QStringList &names); - void setPropertyType(QVariant::Type t); + void setPropertyType(int t); QString propertyName() const; QVariant propertyValue() const; diff --git a/src/designer/src/components/propertyeditor/paletteeditor.cpp b/src/designer/src/components/propertyeditor/paletteeditor.cpp index 4bb1bf4501..228213ee62 100644 --- a/src/designer/src/components/propertyeditor/paletteeditor.cpp +++ b/src/designer/src/components/propertyeditor/paletteeditor.cpp @@ -31,15 +31,33 @@ #include #include +#include +#include + #include #include -#include -#include +#include +#include +#include #include #include +#include #include +#include +#if QT_CONFIG(clipboard) +# include +#endif +#include +#include +#include + +#include +#include +#include +#include + QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -48,14 +66,15 @@ enum { BrushRole = 33 }; PaletteEditor::PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent) : QDialog(parent), - m_currentColorGroup(QPalette::Active), m_paletteModel(new PaletteModel(this)), - m_modelUpdated(false), - m_paletteUpdated(false), - m_compute(true), m_core(core) { ui.setupUi(this); + auto saveButton = ui.buttonBox->addButton(tr("Save..."), QDialogButtonBox::ActionRole); + connect(saveButton, &QPushButton::clicked, this, &PaletteEditor::save); + auto loadButton = ui.buttonBox->addButton(tr("Load..."), QDialogButtonBox::ActionRole); + connect(loadButton, &QPushButton::clicked, this, &PaletteEditor::load); + ui.paletteView->setModel(m_paletteModel); updatePreviewPalette(); updateStyledButton(); @@ -71,6 +90,14 @@ PaletteEditor::PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent ui.paletteView->setRootIsDecorated(false); ui.paletteView->setColumnHidden(2, true); ui.paletteView->setColumnHidden(3, true); + ui.paletteView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.paletteView, &QWidget::customContextMenuRequested, + this, &PaletteEditor::viewContextMenuRequested); + + const auto itemRect = ui.paletteView->visualRect(m_paletteModel->index(0, 0)); + const int minHeight = qMin(itemRect.height() * QPalette::NColorRoles, + (screen()->geometry().height() * 2) / 3); + ui.paletteView->setMinimumSize({itemRect.width() * 4, minHeight}); } PaletteEditor::~PaletteEditor() = default; @@ -83,7 +110,7 @@ QPalette PaletteEditor::palette() const void PaletteEditor::setPalette(const QPalette &palette) { m_editPalette = palette; - const uint mask = palette.resolve(); + const uint mask = palette.resolveMask(); for (int i = 0; i < static_cast(QPalette::NColorRoles); ++i) { if (!(mask & (1 << i))) { m_editPalette.setBrush(QPalette::Active, static_cast(i), @@ -94,7 +121,7 @@ void PaletteEditor::setPalette(const QPalette &palette) m_parentPalette.brush(QPalette::Disabled, static_cast(i))); } } - m_editPalette.resolve(mask); + m_editPalette.setResolveMask(mask); updatePreviewPalette(); updateStyledButton(); m_paletteUpdated = true; @@ -202,7 +229,7 @@ QPalette PaletteEditor::getPalette(QDesignerFormEditorInterface *core, QWidget* { PaletteEditor dlg(core, parent); QPalette parentPalette(parentPal); - uint mask = init.resolve(); + uint mask = init.resolveMask(); for (int i = 0; i < static_cast(QPalette::NColorRoles); ++i) { if (!(mask & (1 << i))) { parentPalette.setBrush(QPalette::Active, static_cast(i), @@ -221,6 +248,145 @@ QPalette PaletteEditor::getPalette(QDesignerFormEditorInterface *core, QWidget* return result == QDialog::Accepted ? dlg.palette() : init; } +void PaletteEditor::viewContextMenuRequested(const QPoint &pos) +{ + const auto index = ui.paletteView->indexAt(pos); + if (!index.isValid()) + return; + auto brush = m_paletteModel->brushAt(index); + const auto color = brush.color(); + if (!m_contextMenu) { + m_contextMenu = new QMenu(this); + m_lighterAction = m_contextMenu->addAction(tr("Lighter")); + m_darkerAction = m_contextMenu->addAction(tr("Darker")); + m_copyColorAction = m_contextMenu->addAction(QString()); + } + const auto rgb = color.rgb() & 0xffffffu; + const bool isBlack = rgb == 0u; + m_lighterAction->setEnabled(rgb != 0xffffffu); + m_darkerAction->setDisabled(isBlack); + m_copyColorAction->setText(tr("Copy color %1").arg(color.name())); + auto action = m_contextMenu->exec(ui.paletteView->viewport()->mapToGlobal(pos)); + if (!action) + return; + if (action == m_copyColorAction) { +#if QT_CONFIG(clipboard) + QGuiApplication::clipboard()->setText(color.name()); +#endif + return; + } + // Fall through to darker/lighter. Note: black cannot be made lighter due + // to QTBUG-9343. + enum : int { factor = 120 }; + const QColor newColor = action == m_darkerAction + ? color.darker(factor) + : (isBlack ? QColor(0x404040u) : color.lighter(factor)); + brush.setColor(newColor); + m_paletteModel->setData(index, QVariant(brush), BrushRole); +} + +static inline QString paletteSuffix() { return QStringLiteral("xml"); } + +static inline QString paletteFilter() +{ + return PaletteEditor::tr("QPalette UI file (*.xml)"); +} + +static bool savePalette(const QString &fileName, const QPalette &pal, QString *errorMessage) +{ + QSaveFile file; + file.setFileName(fileName); + if (!file.open(QIODevice::WriteOnly)) { + *errorMessage = PaletteEditor::tr("Cannot open %1 for writing: %2") + .arg(QDir::toNativeSeparators(fileName), file.errorString()); + return false; + } + { + QScopedPointer domPalette(QFormBuilderExtra::savePalette(pal)); + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + domPalette->write(writer); + writer.writeEndDocument(); + } + const bool result = file.commit(); + if (!result) { + *errorMessage = PaletteEditor::tr("Cannot write %1: %2") + .arg(QDir::toNativeSeparators(fileName), file.errorString()); + } + return result; +} + +static QString msgCannotReadPalette(const QString &fileName, const QXmlStreamReader &reader, + const QString &why) +{ + return PaletteEditor::tr("Cannot read palette from %1:%2:%3") + .arg(QDir::toNativeSeparators(fileName)).arg(reader.lineNumber()).arg(why); +} + +static inline QString msgCannotReadPalette(const QString &fileName, const QXmlStreamReader &reader) +{ + return msgCannotReadPalette(fileName, reader, reader.errorString()); +} + +static bool loadPalette(const QString &fileName, QPalette *pal, QString *errorMessage) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + *errorMessage = PaletteEditor::tr("Cannot open %1 for reading: %2") + .arg(QDir::toNativeSeparators(fileName), file.errorString()); + return false; + } + QXmlStreamReader reader(&file); + if (!reader.readNextStartElement()) { + *errorMessage = msgCannotReadPalette(fileName, reader); + return false; + } + if (reader.name() != QLatin1String("palette")) { + const auto why = PaletteEditor::tr("Invalid element \"%1\", expected \"palette\".") + .arg(reader.name().toString()); + *errorMessage = msgCannotReadPalette(fileName, reader, why); + return false; + } + QScopedPointer domPalette(new DomPalette); + domPalette->read(reader); + if (reader.hasError()) { + *errorMessage = msgCannotReadPalette(fileName, reader); + return false; + } + *pal = QFormBuilderExtra::loadPalette(domPalette.data()); + return true; +} + +void PaletteEditor::save() +{ + QFileDialog dialog(this, tr("Save Palette"), QString(), paletteFilter()); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setDefaultSuffix(paletteSuffix()); + while (dialog.exec() == QDialog::Accepted) { + QString errorMessage; + if (savePalette(dialog.selectedFiles().constFirst(), palette(), &errorMessage)) + break; + QMessageBox::warning(this, tr("Error Writing Palette"), errorMessage); + } +} + +void PaletteEditor::load() +{ + QFileDialog dialog(this, tr("Load Palette"), QString(), paletteFilter()); + dialog.setAcceptMode(QFileDialog::AcceptOpen); + while (dialog.exec() == QDialog::Accepted) { + QPalette pal; + QString errorMessage; + if (loadPalette(dialog.selectedFiles().constFirst(), &pal, &errorMessage)) { + setPalette(pal); + break; + } + QMessageBox::warning(this, tr("Error Reading Palette"), errorMessage); + } +} + ////////////////////// PaletteModel::PaletteModel(QObject *parent) : @@ -230,14 +396,17 @@ PaletteModel::PaletteModel(QObject *parent) : const int index = meta->indexOfProperty("colorRole"); const QMetaProperty p = meta->property(index); const QMetaEnum e = p.enumerator(); + m_roleEntries.reserve(QPalette::NColorRoles); for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) { - m_roleNames[static_cast(r)] = QLatin1String(e.key(r)); + const auto role = static_cast(r); + if (role != QPalette::NoRole) + m_roleEntries.append({QLatin1String(e.key(r)), role}); } } int PaletteModel::rowCount(const QModelIndex &) const { - return m_roleNames.count(); + return m_roleEntries.size(); } int PaletteModel::columnCount(const QModelIndex &) const @@ -245,29 +414,35 @@ int PaletteModel::columnCount(const QModelIndex &) const return 4; } +QBrush PaletteModel::brushAt(const QModelIndex &index) const +{ + return m_palette.brush(columnToGroup(index.column()), roleAt(index.row())); +} + QVariant PaletteModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - if (index.row() < 0 || index.row() >= QPalette::NColorRoles) + if (index.row() < 0 || index.row() >= m_roleEntries.size()) return QVariant(); if (index.column() < 0 || index.column() >= 4) return QVariant(); if (index.column() == 0) { if (role == Qt::DisplayRole) - return m_roleNames[static_cast(index.row())]; + return m_roleEntries.at(index.row()).name; if (role == Qt::EditRole) { - const uint mask = m_palette.resolve(); - if (mask & (1 << index.row())) + const uint mask = m_palette.resolveMask(); + if (mask & (1 << int(roleAt(index.row())))) return true; return false; } return QVariant(); } + if (role == Qt::ToolTipRole) + return brushAt(index).color().name(); if (role == BrushRole) - return m_palette.brush(columnToGroup(index.column()), - static_cast(index.row())); + return brushAt(index); return QVariant(); } @@ -276,17 +451,19 @@ bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int if (!index.isValid()) return false; + const int row = index.row(); + const auto colorRole = roleAt(row); + if (index.column() != 0 && role == BrushRole) { const QBrush br = qvariant_cast(value); - const QPalette::ColorRole r = static_cast(index.row()); const QPalette::ColorGroup g = columnToGroup(index.column()); - m_palette.setBrush(g, r, br); + m_palette.setBrush(g, colorRole, br); - QModelIndex idxBegin = PaletteModel::index(r, 0); - QModelIndex idxEnd = PaletteModel::index(r, 3); + QModelIndex idxBegin = PaletteModel::index(row, 0); + QModelIndex idxEnd = PaletteModel::index(row, 3); if (m_compute) { - m_palette.setBrush(QPalette::Inactive, r, br); - switch (r) { + m_palette.setBrush(QPalette::Inactive, colorRole, br); + switch (colorRole) { case QPalette::WindowText: case QPalette::Text: case QPalette::ButtonText: @@ -298,18 +475,18 @@ bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int m_palette.setBrush(QPalette::Disabled, QPalette::Text, br); m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br); idxBegin = PaletteModel::index(0, 0); - idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3); + idxEnd = PaletteModel::index(m_roleEntries.size() - 1, 3); break; case QPalette::Window: m_palette.setBrush(QPalette::Disabled, QPalette::Base, br); m_palette.setBrush(QPalette::Disabled, QPalette::Window, br); - idxBegin = PaletteModel::index(QPalette::Base, 0); + idxBegin = PaletteModel::index(rowOf(QPalette::Base), 0); break; case QPalette::Highlight: //m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120)); break; default: - m_palette.setBrush(QPalette::Disabled, r, br); + m_palette.setBrush(QPalette::Disabled, colorRole, br); break; } } @@ -318,24 +495,23 @@ bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int return true; } if (index.column() == 0 && role == Qt::EditRole) { - uint mask = m_palette.resolve(); + uint mask = m_palette.resolveMask(); const bool isMask = qvariant_cast(value); - const int r = index.row(); if (isMask) - mask |= (1 << r); + mask |= (1 << int(colorRole)); else { - m_palette.setBrush(QPalette::Active, static_cast(r), - m_parentPalette.brush(QPalette::Active, static_cast(r))); - m_palette.setBrush(QPalette::Inactive, static_cast(r), - m_parentPalette.brush(QPalette::Inactive, static_cast(r))); - m_palette.setBrush(QPalette::Disabled, static_cast(r), - m_parentPalette.brush(QPalette::Disabled, static_cast(r))); - - mask &= ~(1 << index.row()); + m_palette.setBrush(QPalette::Active, colorRole, + m_parentPalette.brush(QPalette::Active, colorRole)); + m_palette.setBrush(QPalette::Inactive, colorRole, + m_parentPalette.brush(QPalette::Inactive, colorRole)); + m_palette.setBrush(QPalette::Disabled, colorRole, + m_parentPalette.brush(QPalette::Disabled, colorRole)); + + mask &= ~(1 << int(colorRole)); } - m_palette.resolve(mask); + m_palette.setResolveMask(mask); emit paletteChanged(m_palette); - const QModelIndex idxEnd = PaletteModel::index(r, 3); + const QModelIndex idxEnd = PaletteModel::index(row, 3); emit dataChanged(index, idxEnd); return true; } @@ -375,7 +551,7 @@ void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPal m_parentPalette = parentPalette; m_palette = palette; const QModelIndex idxBegin = index(0, 0); - const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3); + const QModelIndex idxEnd = index(m_roleEntries.size() - 1, 3); emit dataChanged(idxBegin, idxEnd); } @@ -397,6 +573,15 @@ int PaletteModel::groupToColumn(QPalette::ColorGroup group) const return 3; } +int PaletteModel::rowOf(QPalette::ColorRole role) const +{ + for (int row = 0, size = m_roleEntries.size(); row < size; ++row) { + if (m_roleEntries.at(row).role == role) + return row; + } + return -1; +} + ////////////////////////// BrushEditor::BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent) : diff --git a/src/designer/src/components/propertyeditor/paletteeditor.h b/src/designer/src/components/propertyeditor/paletteeditor.h index 6124340dc5..8ff10c5917 100644 --- a/src/designer/src/components/propertyeditor/paletteeditor.h +++ b/src/designer/src/components/propertyeditor/paletteeditor.h @@ -34,7 +34,9 @@ QT_BEGIN_NAMESPACE +class QAction; class QListView; +class QMenu; class QLabel; class QtColorButton; class QDesignerFormEditorInterface; @@ -65,6 +67,9 @@ private slots: void on_detailsRadio_clicked(); void paletteChanged(const QPalette &palette); + void viewContextMenuRequested(const QPoint &pos); + void save(); + void load(); protected: @@ -81,12 +86,16 @@ private slots: Ui::PaletteEditor ui; QPalette m_editPalette; QPalette m_parentPalette; - QPalette::ColorGroup m_currentColorGroup; class PaletteModel *m_paletteModel; - bool m_modelUpdated; - bool m_paletteUpdated; - bool m_compute; QDesignerFormEditorInterface *m_core; + QAction *m_lighterAction = nullptr; + QAction *m_darkerAction = nullptr; + QAction *m_copyColorAction = nullptr; + QMenu *m_contextMenu = nullptr; + QPalette::ColorGroup m_currentColorGroup = QPalette::Active; + bool m_modelUpdated = false; + bool m_paletteUpdated = false; + bool m_compute = true; }; @@ -108,18 +117,27 @@ class PaletteModel : public QAbstractTableModel QPalette getPalette() const; void setPalette(const QPalette &palette, const QPalette &parentPalette); + QBrush brushAt(const QModelIndex &index) const; + QPalette::ColorRole colorRole() const { return QPalette::NoRole; } void setCompute(bool on) { m_compute = on; } signals: void paletteChanged(const QPalette &palette); private: + struct RoleEntry + { + QString name; + QPalette::ColorRole role; + }; QPalette::ColorGroup columnToGroup(int index) const; int groupToColumn(QPalette::ColorGroup group) const; + QPalette::ColorRole roleAt(int row) const { return m_roleEntries.at(row).role; } + int rowOf(QPalette::ColorRole role) const; QPalette m_palette; QPalette m_parentPalette; - QMap m_roleNames; + QList m_roleEntries; bool m_compute = true; }; diff --git a/src/designer/src/components/propertyeditor/paletteeditor.ui b/src/designer/src/components/propertyeditor/paletteeditor.ui index aa5965d791..2bb8cfedc8 100644 --- a/src/designer/src/components/propertyeditor/paletteeditor.ui +++ b/src/designer/src/components/propertyeditor/paletteeditor.ui @@ -1,4 +1,5 @@ - + + ********************************************************************* ** ** Copyright (C) 2016 The Qt Company Ltd. @@ -27,175 +28,183 @@ ** ********************************************************************* qdesigner_internal::PaletteEditor - - + + 0 0 - 365 - 409 + 918 + 599 - - - 7 - 7 + + 0 0 - + Edit Palette - - - 9 - - - 6 - + - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - Tune Palette - - - - 9 - - - 6 - - - - - - 7 - 13 - 0 - 0 - + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Tune Palette + + + + 9 - - + + 9 - - - - - - - 0 - 200 - + + 9 - - - - - - Show Details + + 9 - - - - - - Compute Details + + 6 - - true + + + + + 0 + 0 + + + + + + + + + + + + 0 + 200 + + + + + + + + Show Details + + + + + + + Compute Details + + + true + + + + + + + Quick + + + + + + + + + + + 0 + 0 + + + + Preview + + + + 8 - - - - - - Quick + + 8 - - - - - - - - - - 5 - 7 - 0 - 0 - - - - Preview - - - - 8 - - - 6 - - - - - Disabled - - - - - - - Inactive + + 8 - - - - - - Active + + 8 - - true + + 6 - - - - - - - 7 - 7 - 0 - 0 - - - - - - + + + + Disabled + + + + + + + Inactive + + + + + + + Active + + + true + + + + + + + + 0 + 0 + + + + + + + + - - + + Qt::Horizontal - - QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -221,11 +230,11 @@ qdesigner_internal::PaletteEditor accept() - + 180 331 - + 134 341 @@ -237,11 +246,11 @@ qdesigner_internal::PaletteEditor reject() - + 287 329 - + 302 342 diff --git a/src/designer/src/components/propertyeditor/previewframe.cpp b/src/designer/src/components/propertyeditor/previewframe.cpp index a97e468775..c093663e22 100644 --- a/src/designer/src/components/propertyeditor/previewframe.cpp +++ b/src/designer/src/components/propertyeditor/previewframe.cpp @@ -78,7 +78,7 @@ PreviewFrame::PreviewFrame(QWidget *parent) : void PreviewFrame::setPreviewPalette(const QPalette &pal) { - ensureMdiSubWindow()->widget()->setPalette(pal); + ensureMdiSubWindow()->setPalette(pal); } void PreviewFrame::setSubWindowActive(bool active) diff --git a/src/designer/src/components/propertyeditor/previewwidget.cpp b/src/designer/src/components/propertyeditor/previewwidget.cpp index cc5a3af315..c489fc09aa 100644 --- a/src/designer/src/components/propertyeditor/previewwidget.cpp +++ b/src/designer/src/components/propertyeditor/previewwidget.cpp @@ -28,6 +28,12 @@ #include "previewwidget.h" +#include + +#include + +#include + QT_BEGIN_NAMESPACE using namespace qdesigner_internal; @@ -36,6 +42,16 @@ PreviewWidget::PreviewWidget(QWidget *parent) : QWidget(parent) { ui.setupUi(this); + ui.treeWidget->expandAll(); + auto model = ui.treeWidget->model(); + ui.treeWidget->setCurrentIndex(model->index(0, 0, model->index(0, 0))); + auto toolButtonMenu = new QMenu(ui.menuToolButton); + toolButtonMenu->addAction(tr("Option 1")); + toolButtonMenu->addSeparator(); + auto checkable = toolButtonMenu->addAction(tr("Checkable")); + checkable->setCheckable(true); + ui.menuToolButton->setMenu(toolButtonMenu); + ui.menuToolButton->setPopupMode(QToolButton::InstantPopup); } PreviewWidget::~PreviewWidget() = default; diff --git a/src/designer/src/components/propertyeditor/previewwidget.ui b/src/designer/src/components/propertyeditor/previewwidget.ui index fc81c8b85e..077ff24b4b 100644 --- a/src/designer/src/components/propertyeditor/previewwidget.ui +++ b/src/designer/src/components/propertyeditor/previewwidget.ui @@ -1,4 +1,5 @@ - + + ********************************************************************* ** ** Copyright (C) 2016 The Qt Company Ltd. @@ -27,191 +28,296 @@ ** ********************************************************************* qdesigner_internal::PreviewWidget - - + + 0 0 - 471 - 251 + 608 + 367 - - - 1 - 1 + + 0 0 - + Preview Window - - - 9 - - - 6 - - - - - 0 + + + + + Buttons - - 6 - - - - - LineEdit - - - - - - - - ComboBox - - - - - - - - 0 - - - 6 - - - - - - - - PushButton - - - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - - - - - - 32767 - 50 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 20 - - - - - - - - Qt::Horizontal + + true + + + + + + + RadioButton1 + + + true + + + + + + + RadioButton2 + + + + + + + RadioButton3 + + + + + + + CheckBox1 + + + true + + + + + + + Tristate CheckBox + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + PushButton + + + + + + + ToggleButton + + + true + + + true + + + false + + + + + + + + + ToolButton + + + + + + + Menu + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + - - - - ButtonGroup2 + + + + Item Views + + + true - - - 9 - - - 6 - + - - - CheckBox1 - - + + true + + + Column 1 + + + + + Top Level 1 + + + + Nested Item 1 + + + + + Nested Item 2 + + + + + Nested Item 3 + + + + + + + + + + Simple Input Widgets + + + true + + + + + + + + LineEdit + + + true + + + + + + + + ComboBox + + + + + Item1 + + + + + Item2 + + + + + + - - - CheckBox2 - - + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + - - - - ButtonGroup + + + + Display Widgets - - - 9 - - - 6 - + - - - RadioButton1 + + + 50 - - true + + Qt::Horizontal - - - RadioButton2 + + + QLabel - - - RadioButton3 + + + QFrame::StyledPanel + + + QLabel with frame diff --git a/src/designer/src/components/propertyeditor/propertyeditor.cpp b/src/designer/src/components/propertyeditor/propertyeditor.cpp index af590a7d57..3d06471901 100644 --- a/src/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/src/designer/src/components/propertyeditor/propertyeditor.cpp @@ -53,7 +53,7 @@ #include #include -#include +#include #include #include #include @@ -62,8 +62,9 @@ #include #include #include -#include -#include + +#include +#include #include #include @@ -213,7 +214,7 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare m_buttonAction(new QAction(tr("Drop Down Button View"), this)), m_classLabel(new ElidingLabel) { - QVector colors; + QList colors; colors.reserve(6); colors.push_back(QColor(255, 230, 191)); colors.push_back(QColor(255, 255, 191)); @@ -255,14 +256,14 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare m_addDynamicAction->setMenu(addDynamicActionMenu); m_addDynamicAction->setEnabled(false); QAction *addDynamicAction = addDynamicActionGroup->addAction(tr("String...")); - addDynamicAction->setData(static_cast(QVariant::String)); + addDynamicAction->setData(static_cast(QMetaType::QString)); addDynamicActionMenu->addAction(addDynamicAction); addDynamicAction = addDynamicActionGroup->addAction(tr("Bool...")); - addDynamicAction->setData(static_cast(QVariant::Bool)); + addDynamicAction->setData(static_cast(QMetaType::Bool)); addDynamicActionMenu->addAction(addDynamicAction); addDynamicActionMenu->addSeparator(); addDynamicAction = addDynamicActionGroup->addAction(tr("Other...")); - addDynamicAction->setData(static_cast(QVariant::Invalid)); + addDynamicAction->setData(static_cast(QMetaType::UnknownType)); addDynamicActionMenu->addAction(addDynamicAction); // remove m_removeDynamicAction->setEnabled(false); @@ -363,7 +364,7 @@ PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *pare break; } // Restore expansionState from QVariant map - if (!expansionState.empty()) { + if (!expansionState.isEmpty()) { const QVariantMap::const_iterator cend = expansionState.constEnd(); for (QVariantMap::const_iterator it = expansionState.constBegin(); it != cend; ++it) m_expansionState.insert(it.key(), it.value().toBool()); @@ -386,7 +387,7 @@ void PropertyEditor::saveSettings() const settings->setValue(QLatin1String(SortedKeyC), QVariant(m_sorting)); // Save last expansionState as QVariant map QVariantMap expansionState; - if (!m_expansionState.empty()) { + if (!m_expansionState.isEmpty()) { const QMap::const_iterator cend = m_expansionState.constEnd(); for (QMap::const_iterator it = m_expansionState.constBegin(); it != cend; ++it) expansionState.insert(it.key(), QVariant(it.value())); @@ -436,7 +437,7 @@ void PropertyEditor::storePropertiesExpansionState(const QList { const QChar bar = QLatin1Char('|'); for (QtBrowserItem *propertyItem : items) { - if (!propertyItem->children().empty()) { + if (!propertyItem->children().isEmpty()) { QtProperty *property = propertyItem->property(); const QString propertyName = property->propertyName(); const QMap::const_iterator itGroup = m_propertyToGroup.constFind(property); @@ -452,14 +453,14 @@ void PropertyEditor::storePropertiesExpansionState(const QList void PropertyEditor::storeExpansionState() { - const QList items = m_currentBrowser->topLevelItems(); + const auto items = m_currentBrowser->topLevelItems(); if (m_sorting) { storePropertiesExpansionState(items); } else { for (QtBrowserItem *item : items) { const QString groupName = item->property()->propertyName(); - QList propertyItems = item->children(); - if (!propertyItems.empty()) + auto propertyItems = item->children(); + if (!propertyItems.isEmpty()) m_expansionState[groupName] = isExpanded(item); // properties stuff here @@ -470,7 +471,7 @@ void PropertyEditor::storeExpansionState() void PropertyEditor::collapseAll() { - const QList items = m_currentBrowser->topLevelItems(); + const auto items = m_currentBrowser->topLevelItems(); for (QtBrowserItem *group : items) setExpanded(group, false); } @@ -498,7 +499,7 @@ void PropertyEditor::applyPropertiesExpansionState(const QList void PropertyEditor::applyExpansionState() { - const QList items = m_currentBrowser->topLevelItems(); + const auto items = m_currentBrowser->topLevelItems(); if (m_sorting) { applyPropertiesExpansionState(items); } else { @@ -533,7 +534,7 @@ int PropertyEditor::applyPropertiesFilter(const QList &items) void PropertyEditor::applyFilter() { - const QList items = m_currentBrowser->topLevelItems(); + const auto items = m_currentBrowser->topLevelItems(); if (m_sorting) { applyPropertiesFilter(items); } else { @@ -664,7 +665,7 @@ void PropertyEditor::slotSorting(bool sort) void PropertyEditor::updateColors() { if (m_treeBrowser && m_currentBrowser == m_treeBrowser) { - const QList items = m_treeBrowser->topLevelItems(); + const auto items = m_treeBrowser->topLevelItems(); for (QtBrowserItem *item : items) m_treeBrowser->setBackgroundColor(item, propertyColor(item->property())); } @@ -694,9 +695,9 @@ void PropertyEditor::slotAddDynamicProperty(QAction *action) QString newName; QVariant newValue; { // Make sure the dialog is closed before the signal is emitted. - const QVariant::Type type = static_cast(action->data().toInt()); + const int type = action->data().toInt(); NewDynamicPropertyDialog dlg(core()->dialogGui(), m_currentBrowser); - if (type != QVariant::Invalid) + if (type != QMetaType::UnknownType) dlg.setPropertyType(type); QStringList reservedNames; @@ -814,7 +815,7 @@ void PropertyEditor::updateBrowserValue(QtVariantProperty *property, const QVari } // Rich text string property with comment: Store/Update the font the rich text editor dialog starts out with - if (type == QVariant::String && !property->subProperties().empty()) { + if (type == QMetaType::QString && !property->subProperties().isEmpty()) { const int fontIndex = m_propertySheet->indexOf(m_strings.m_fontProperty); if (fontIndex != -1) property->setAttribute(m_strings.m_fontAttribute, m_propertySheet->property(fontIndex)); @@ -865,9 +866,9 @@ QString PropertyEditor::realClassName(QObject *object) const static const char *typeName(int type) { if (type == qMetaTypeId()) - type = QVariant::String; - if (type < int(QVariant::UserType)) - return QVariant::typeToName(static_cast(type)); + type = QMetaType::QString; + if (type < int(QMetaType::User)) + return QMetaType(type).name(); if (type == qMetaTypeId()) return "QIcon"; if (type == qMetaTypeId()) @@ -878,9 +879,9 @@ static const char *typeName(int type) return "QFlags"; if (type == qMetaTypeId()) return "enum"; - if (type == QVariant::Invalid) + if (type == QMetaType::UnknownType) return "invalid"; - if (type == QVariant::UserType) + if (type == QMetaType::User) return "user type"; return nullptr; } @@ -1040,16 +1041,16 @@ void PropertyEditor::setObject(QObject *object) if (!descriptionToolTip.isEmpty()) property->setDescriptionToolTip(descriptionToolTip); switch (type) { - case QVariant::Palette: + case QMetaType::QPalette: setupPaletteProperty(property); break; - case QVariant::KeySequence: + case QMetaType::QKeySequence: //addCommentProperty(property, propertyName); break; default: break; } - if (type == QVariant::String || type == qMetaTypeId()) + if (type == QMetaType::QString || type == qMetaTypeId()) setupStringProperty(property, isMainContainer); property->setAttribute(m_strings.m_resettableAttribute, m_propertySheet->hasReset(i)); @@ -1092,9 +1093,9 @@ void PropertyEditor::setObject(QObject *object) if (lastGroup != groupProperty) { lastGroup = groupProperty; lastProperty = nullptr; // Append at end - const QList subProperties = lastGroup->subProperties(); - if (!subProperties.empty()) - lastProperty = subProperties.back(); + const auto subProperties = lastGroup->subProperties(); + if (!subProperties.isEmpty()) + lastProperty = subProperties.constLast(); lastGroup = groupProperty; } if (!m_groups.contains(groupProperty)) @@ -1107,8 +1108,8 @@ void PropertyEditor::setObject(QObject *object) updateBrowserValue(property, value); property->setModified(m_propertySheet->isChanged(i)); - if (propertyName == QStringLiteral("geometry") && type == QVariant::Rect) { - const QList &subProperties = property->subProperties(); + if (propertyName == QStringLiteral("geometry") && type == QMetaType::QRect) { + const auto &subProperties = property->subProperties(); for (QtProperty *subProperty : subProperties) { const QString subPropertyName = subProperty->propertyName(); if (subPropertyName == QStringLiteral("X") || subPropertyName == QStringLiteral("Y")) @@ -1123,7 +1124,7 @@ void PropertyEditor::setObject(QObject *object) QMap groups = m_nameToGroup; for (auto itGroup = groups.cbegin(), end = groups.cend(); itGroup != end; ++itGroup) { QtVariantProperty *groupProperty = itGroup.value(); - if (groupProperty->subProperties().empty()) { + if (groupProperty->subProperties().isEmpty()) { if (groupProperty == m_dynamicGroup) m_dynamicGroup = nullptr; delete groupProperty; @@ -1157,7 +1158,7 @@ QtBrowserItem *PropertyEditor::nonFakePropertyBrowserItem(QtBrowserItem *item) c { // Top-level properties are QObject/QWidget groups, etc. Find first item property below // which should be nonfake - const QList topLevelItems = m_currentBrowser->topLevelItems(); + const auto topLevelItems = m_currentBrowser->topLevelItems(); do { if (topLevelItems.contains(item->parent())) return item; @@ -1245,9 +1246,9 @@ void PropertyEditor::editProperty(const QString &name) // find the browser item belonging to the property, make it current and edit it QtBrowserItem *browserItem = nullptr; if (QtVariantProperty *property = m_nameToProperty.value(name, 0)) { - const QList items = m_currentBrowser->items(property); + const auto items = m_currentBrowser->items(property); if (items.size() == 1) - browserItem = items.front(); + browserItem = items.constFirst(); } if (browserItem == nullptr) return; diff --git a/src/designer/src/components/propertyeditor/propertyeditor.h b/src/designer/src/components/propertyeditor/propertyeditor.h index 993c4418d2..331a72303b 100644 --- a/src/designer/src/components/propertyeditor/propertyeditor.h +++ b/src/designer/src/components/propertyeditor/propertyeditor.h @@ -32,9 +32,9 @@ #include "propertyeditor_global.h" #include -#include +#include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -180,7 +180,7 @@ private slots: QMap m_expansionState; QString m_filterPattern; - QVector > m_colors; + QList > m_colors; QPair m_dynamicColor; QPair m_layoutColor; diff --git a/src/designer/src/components/propertyeditor/propertyeditor.pri b/src/designer/src/components/propertyeditor/propertyeditor.pri deleted file mode 100644 index 6b095632ba..0000000000 --- a/src/designer/src/components/propertyeditor/propertyeditor.pri +++ /dev/null @@ -1,48 +0,0 @@ -INCLUDEPATH += $$PWD - -# --- Property browser is also linked into the designer_shared library. -# Avoid conflict when linking statically -contains(CONFIG, static) { - INCLUDEPATH *= ../../../../shared/qtpropertybrowser - INCLUDEPATH *= ../../../../shared/qtgradienteditor -} else { - include(../../../../shared/qtpropertybrowser/qtpropertybrowser.pri) - include(../../../../shared/qtgradienteditor/qtcolorbutton.pri) -} - -FORMS += $$PWD/paletteeditor.ui \ - $$PWD/stringlisteditor.ui \ - $$PWD/previewwidget.ui \ - $$PWD/newdynamicpropertydialog.ui - -HEADERS += $$PWD/propertyeditor.h \ - $$PWD/designerpropertymanager.h \ - $$PWD/paletteeditor.h \ - $$PWD/paletteeditorbutton.h \ - $$PWD/stringlisteditor.h \ - $$PWD/stringlisteditorbutton.h \ - $$PWD/previewwidget.h \ - $$PWD/previewframe.h \ - $$PWD/newdynamicpropertydialog.h \ - $$PWD/brushpropertymanager.h \ - $$PWD/fontpropertymanager.h - -SOURCES += $$PWD/propertyeditor.cpp \ - $$PWD/designerpropertymanager.cpp \ - $$PWD/paletteeditor.cpp \ - $$PWD/paletteeditorbutton.cpp \ - $$PWD/stringlisteditor.cpp \ - $$PWD/stringlisteditorbutton.cpp \ - $$PWD/previewwidget.cpp \ - $$PWD/previewframe.cpp \ - $$PWD/newdynamicpropertydialog.cpp \ - $$PWD/brushpropertymanager.cpp \ - $$PWD/fontpropertymanager.cpp - -HEADERS += \ - $$PWD/propertyeditor_global.h \ - $$PWD/qlonglongvalidator.h - -SOURCES += $$PWD/qlonglongvalidator.cpp - -RESOURCES += $$PWD/propertyeditor.qrc diff --git a/src/designer/src/components/propertyeditor/qlonglongvalidator.h b/src/designer/src/components/propertyeditor/qlonglongvalidator.h index ccc28b42eb..3f16694481 100644 --- a/src/designer/src/components/propertyeditor/qlonglongvalidator.h +++ b/src/designer/src/components/propertyeditor/qlonglongvalidator.h @@ -46,7 +46,7 @@ class QLongLongValidator : public QValidator QLongLongValidator(qlonglong bottom, qlonglong top, QObject * parent); ~QLongLongValidator(); - QValidator::State validate(QString &, int &) const; + QValidator::State validate(QString &, int &) const override; void setBottom(qlonglong); void setTop(qlonglong); @@ -74,7 +74,7 @@ class QULongLongValidator : public QValidator QULongLongValidator(qulonglong bottom, qulonglong top, QObject * parent); ~QULongLongValidator(); - QValidator::State validate(QString &, int &) const; + QValidator::State validate(QString &, int &) const override; void setBottom(qulonglong); void setTop(qulonglong); diff --git a/src/designer/src/components/signalsloteditor/connectdialog.cpp b/src/designer/src/components/signalsloteditor/connectdialog.cpp index 571ddba128..bb59e0c1c4 100644 --- a/src/designer/src/components/signalsloteditor/connectdialog.cpp +++ b/src/designer/src/components/signalsloteditor/connectdialog.cpp @@ -42,10 +42,6 @@ QT_BEGIN_NAMESPACE -namespace { - using ListWidgetItems = QList; -} - static QString realClassName(QDesignerFormEditorInterface *core, QWidget *widget) { QString class_name = QLatin1String(widget->metaObject()->className()); @@ -138,22 +134,22 @@ void ConnectDialog::populateLists() void ConnectDialog::setSignalSlot(const QString &signal, const QString &slot) { - ListWidgetItems sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + auto sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); - if (sigItems.empty()) { + if (sigItems.isEmpty()) { m_ui.showAllCheckBox->setChecked(true); sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); } - if (!sigItems.empty()) { - selectSignal(sigItems.front()); - ListWidgetItems slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); - if (slotItems.empty()) { + if (!sigItems.isEmpty()) { + selectSignal(sigItems.constFirst()); + auto slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + if (slotItems.isEmpty()) { m_ui.showAllCheckBox->setChecked(true); slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); } - if (!slotItems.empty()) - selectSlot(slotItems.front()); + if (!slotItems.isEmpty()) + selectSlot(slotItems.constFirst()); } } @@ -194,7 +190,7 @@ void ConnectDialog::selectSlot(QListWidgetItem *item) QString ConnectDialog::signal() const { - const ListWidgetItems item_list = m_ui.signalList->selectedItems(); + const auto item_list = m_ui.signalList->selectedItems(); if (item_list.size() != 1) return QString(); return item_list.at(0)->text(); @@ -202,7 +198,7 @@ QString ConnectDialog::signal() const QString ConnectDialog::slot() const { - const ListWidgetItems item_list = m_ui.slotList->selectedItems(); + const auto item_list = m_ui.slotList->selectedItems(); if (item_list.size() != 1) return QString(); return item_list.at(0)->text(); @@ -326,3 +322,6 @@ void ConnectDialog::editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlot } QT_END_NAMESPACE + +#include "moc_connectdialog_p.cpp" + diff --git a/src/designer/src/components/signalsloteditor/signalslot_utils.cpp b/src/designer/src/components/signalsloteditor/signalslot_utils.cpp index f913b5bdf9..c7a960ef31 100644 --- a/src/designer/src/components/signalsloteditor/signalslot_utils.cpp +++ b/src/designer/src/components/signalsloteditor/signalslot_utils.cpp @@ -93,7 +93,7 @@ static void memberList(QDesignerFormEditorInterface *core, const QString className = wdbItem->name(); const QStringList wdbFakeMethods = member_type == qdesigner_internal::SlotMember ? wdbItem->fakeSlots() : wdbItem->fakeSignals(); - if (!wdbFakeMethods.empty()) + if (!wdbFakeMethods.isEmpty()) for (const QString &fakeMethod : wdbFakeMethods) if (predicate(fakeMethod)) { *it = ClassNameSignaturePair(className, fakeMethod); @@ -106,7 +106,7 @@ static void memberList(QDesignerFormEditorInterface *core, if (const qdesigner_internal::MetaDataBaseItem *mdbItem = metaDataBase->metaDataBaseItem(object)) { const QStringList mdbFakeMethods = member_type == qdesigner_internal::SlotMember ? mdbItem->fakeSlots() : mdbItem->fakeSignals(); - if (!mdbFakeMethods.empty()) + if (!mdbFakeMethods.isEmpty()) for (const QString &fakeMethod : mdbFakeMethods) if (predicate(fakeMethod)) { *it = ClassNameSignaturePair(className, fakeMethod); @@ -266,7 +266,7 @@ namespace qdesigner_internal { { QMap rc; memberList(core, object, type, true, EqualsPredicate(signature), SignatureIterator(&rc)); - return !rc.empty(); + return !rc.isEmpty(); } // ### deprecated diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor.cpp index a510acdb5a..28bb2c7361 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditor.cpp +++ b/src/designer/src/components/signalsloteditor/signalsloteditor.cpp @@ -40,9 +40,10 @@ #include #include -#include #include +#include + #include #include @@ -69,7 +70,7 @@ DomConnection *SignalSlotConnection::toUi() const result->setElementSlot(slot()); DomConnectionHints *hints = new DomConnectionHints; - QVector list; + QList list; QPoint sp = endPointPos(EndPoint::Source); QPoint tp = endPointPos(EndPoint::Target); @@ -321,7 +322,7 @@ Connection *SignalSlotEditor::createConnection(QWidget *source, QWidget *destina DomConnections *SignalSlotEditor::toUi() const { DomConnections *result = new DomConnections; - QVector list; + QList list; const int count = connectionCount(); list.reserve(count); diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor.pri b/src/designer/src/components/signalsloteditor/signalsloteditor.pri deleted file mode 100644 index f8d9d359cc..0000000000 --- a/src/designer/src/components/signalsloteditor/signalsloteditor.pri +++ /dev/null @@ -1,22 +0,0 @@ - -INCLUDEPATH += $$PWD - -HEADERS += $$PWD/signalslot_utils_p.h \ - $$PWD/connectdialog_p.h \ - $$PWD/signalsloteditor.h \ - $$PWD/signalsloteditor_tool.h \ - $$PWD/signalsloteditor_plugin.h \ - $$PWD/signalsloteditor_global.h \ - $$PWD/signalsloteditor_p.h \ - $$PWD/signalsloteditorwindow.h - -SOURCES += $$PWD/signalslot_utils.cpp \ - $$PWD/connectdialog.cpp \ - $$PWD/signalsloteditor.cpp \ - $$PWD/signalsloteditor_tool.cpp \ - $$PWD/signalsloteditor_plugin.cpp \ - $$PWD/signalsloteditorwindow.cpp - -FORMS += $$PWD/connectdialog.ui - -OTHER_FILES += $$PWD/signalsloteditor.json diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_p.h b/src/designer/src/components/signalsloteditor/signalsloteditor_p.h index 15d0563cfa..1a44c101a5 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditor_p.h +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_p.h @@ -105,6 +105,9 @@ class ConnectionModel : public QAbstractItemModel Connection *indexToConnection(const QModelIndex &index) const; void updateAll(); + const SignalSlotConnection *connectionAt(const QModelIndex &index) const; + static QString columnText(const SignalSlotConnection *con, int column); + private slots: void connectionAdded(Connection *con); void connectionRemoved(int idx); diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp index 95aad3f0b4..60cfdfa6a9 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include QT_BEGIN_NAMESPACE @@ -113,3 +113,5 @@ void SignalSlotEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterfac } QT_END_NAMESPACE + +#include "moc_signalsloteditor_plugin.cpp" diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp index f322c90cbc..ec828b017e 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp @@ -32,7 +32,8 @@ #include #include -#include +#include + #include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp index f44c3cd5a9..1ed2e9da28 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp +++ b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp @@ -45,13 +45,8 @@ #include #include -#include -#include -#include #include #include -#include -#include #include #include #include @@ -63,6 +58,13 @@ #include #include +#include +#include + +#include +#include +#include + QT_BEGIN_NAMESPACE // Add suitable form widgets to a list of objects for the signal slot @@ -79,9 +81,6 @@ static void addWidgetToObjectList(const QWidget *w, QStringList &r) static QStringList objectNameList(QDesignerFormWindowInterface *form) { - using ActionList = QList; - using ButtonGroupList = QList; - QStringList result; QWidget *mainContainer = form->mainContainer(); @@ -104,30 +103,24 @@ static QStringList objectNameList(QDesignerFormWindowInterface *form) const QDesignerMetaDataBaseInterface *mdb = form->core()->metaDataBase(); // Add managed actions and actions with managed menus - const ActionList actions = mainContainer->findChildren(); - if (!actions.empty()) { - const ActionList::const_iterator cend = actions.constEnd(); - for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { - QAction *a = *it; - if (!a->isSeparator()) { - if (QMenu *menu = a->menu()) { - if (mdb->item(menu)) - result.push_back(menu->objectName()); - } else { - if (mdb->item(a)) - result.push_back(a->objectName()); - } + const auto actions = mainContainer->findChildren(); + for (QAction *a : actions) { + if (!a->isSeparator()) { + if (QMenu *menu = a->menu()) { + if (mdb->item(menu)) + result.push_back(menu->objectName()); + } else { + if (mdb->item(a)) + result.push_back(a->objectName()); } } } // Add managed buttons groups - const ButtonGroupList buttonGroups = mainContainer->findChildren(); - if (!buttonGroups.empty()) { - const ButtonGroupList::const_iterator cend = buttonGroups.constEnd(); - for (ButtonGroupList::const_iterator it = buttonGroups.constBegin(); it != cend; ++it) - if (mdb->item(*it)) - result.append((*it)->objectName()); + const auto buttonGroups = mainContainer->findChildren(); + for (QButtonGroup * b : buttonGroups) { + if (mdb->item(b)) + result.append(b->objectName()); } result.sort(); @@ -245,69 +238,77 @@ int ConnectionModel::columnCount(const QModelIndex &parent) const return 4; } +const SignalSlotConnection *ConnectionModel::connectionAt(const QModelIndex &index) const +{ + const int row = index.row(); + return m_editor != nullptr && row >= 0 && row < m_editor->connectionCount() + ? static_cast(m_editor->connection(row)) + : nullptr; +} + QVariant ConnectionModel::data(const QModelIndex &index, int role) const { enum { deprecatedMember = 0 }; - if ((role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole && role != Qt::ForegroundRole) || !m_editor) - return QVariant(); - - if (index.row() < 0 || index.row() >= m_editor->connectionCount()) { + const SignalSlotConnection *con = connectionAt(index); + if (con == nullptr) return QVariant(); - } - - const SignalSlotConnection *con = static_cast(m_editor->connection(index.row())); - Q_ASSERT(con != nullptr); // Mark deprecated slots red/italic. Not currently in use (historically for Qt 3 slots in Qt 4), // but may be used again in the future. - if (deprecatedMember && role == Qt::ForegroundRole) - return QColor(Qt::red); - if (deprecatedMember && role == Qt::FontRole) { - QFont font = QApplication::font(); - font.setItalic(true); - return font; + switch (role) { + case Qt::ForegroundRole: + return deprecatedMember ? QColor(Qt::red) : QVariant(); + case Qt::FontRole: + if (deprecatedMember) { + QFont font = QApplication::font(); + font.setItalic(true); + return font; + } + return QVariant(); + case Qt::DisplayRole: + case Qt::EditRole: + return ConnectionModel::columnText(con, index.column()); + default: + break; } - static const QVariant senderDefault = tr(""); - static const QVariant signalDefault = tr(""); - static const QVariant receiverDefault = tr(""); - static const QVariant slotDefault = tr(""); + return QVariant(); +} - switch (index.column()) { +QString ConnectionModel::columnText(const SignalSlotConnection *con, int column) +{ + static const QString senderDefault = tr(""); + static const QString signalDefault = tr(""); + static const QString receiverDefault = tr(""); + static const QString slotDefault = tr(""); + + switch (column) { case 0: { const QString sender = con->sender(); - if (sender.isEmpty()) - return senderDefault; - return sender; + return sender.isEmpty() ? senderDefault : sender; } case 1: { - const QString signal = con->signal(); - if (signal.isEmpty()) - return signalDefault; - return signal; + const QString signalName = con->signal(); + return signalName.isEmpty() ? signalDefault : signalName; } case 2: { const QString receiver = con->receiver(); - if (receiver.isEmpty()) - return receiverDefault; - return receiver; + return receiver.isEmpty() ? receiverDefault : receiver; } case 3: { - const QString slot = con->slot(); - if (slot.isEmpty()) - return slotDefault; - return slot; + const QString slotName = con->slot(); + return slotName.isEmpty() ? slotDefault : slotName; } } - return QVariant(); + return QString(); } bool ConnectionModel::setData(const QModelIndex &index, const QVariant &data, int) { if (!index.isValid() || !m_editor) return false; - if (data.type() != QVariant::String) + if (data.metaType().id() != QMetaType::QString) return false; SignalSlotConnection *con = static_cast(m_editor->connection(index.row())); @@ -391,7 +392,7 @@ void ConnectionModel::connectionChanged(Connection *con) void ConnectionModel::updateAll() { - emit dataChanged(index(0, 0), index(rowCount(), columnCount())); + emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } } @@ -517,7 +518,7 @@ InlineEditor::InlineEditor(QWidget *parent) : setModel(m_model = new InlineEditorModel(0, 4, this)); setFrame(false); m_idx = -1; - connect(this, QOverload::of(&QComboBox::activated), + connect(this, &QComboBox::activated, this, &InlineEditor::checkSelection); } @@ -591,7 +592,7 @@ ConnectionDelegate::ConnectionDelegate(QWidget *parent) factory = new QItemEditorFactory; QItemEditorCreatorBase *creator = new QItemEditorCreator("text"); - factory->registerEditor(QVariant::String, creator); + factory->registerEditor(QMetaType::QString, creator); } setItemEditorFactory(factory); @@ -655,7 +656,7 @@ QWidget *ConnectionDelegate::createEditor(QWidget *parent, break; } - connect(inline_editor, QOverload::of(&QComboBox::activated), + connect(inline_editor, &QComboBox::activated, this, &ConnectionDelegate::emitCommitData); return inline_editor; @@ -734,13 +735,15 @@ void SignalSlotEditorWindow::setActiveFormWindow(QDesignerFormWindowInterface *f this, &SignalSlotEditorWindow::updateEditorSelection); disconnect(m_editor.data(), &SignalSlotEditor::connectionSelected, this, &SignalSlotEditorWindow::updateDialogSelection); + disconnect(m_editor.data(), &SignalSlotEditor::connectionAdded, + this, &SignalSlotEditorWindow::resizeColumns); if (integration) { disconnect(integration, &QDesignerIntegrationInterface::objectNameChanged, this, &SignalSlotEditorWindow::objectNameChanged); } } - m_editor = form->findChild(); + m_editor = form ? form->findChild() : nullptr; m_model->setEditor(m_editor); if (!m_editor.isNull()) { ConnectionDelegate *delegate @@ -753,12 +756,15 @@ void SignalSlotEditorWindow::setActiveFormWindow(QDesignerFormWindowInterface *f this, &SignalSlotEditorWindow::updateEditorSelection); connect(m_editor.data(), &SignalSlotEditor::connectionSelected, this, &SignalSlotEditorWindow::updateDialogSelection); + connect(m_editor.data(), &SignalSlotEditor::connectionAdded, + this, &SignalSlotEditorWindow::resizeColumns); if (integration) { connect(integration, &QDesignerIntegrationInterface::objectNameChanged, this, &SignalSlotEditorWindow::objectNameChanged); } } + resizeColumns(); updateUi(); } @@ -768,9 +774,10 @@ void SignalSlotEditorWindow::updateDialogSelection(Connection *con) return; QModelIndex index = m_proxy_model->mapFromSource(m_model->connectionToIndex(con)); - if (index == m_view->currentIndex()) + if (!index.isValid() || index == m_view->currentIndex()) return; m_handling_selection_change = true; + m_view->scrollTo(index, QTreeView::EnsureVisible); m_view->setCurrentIndex(index); m_handling_selection_change = false; @@ -826,6 +833,12 @@ void SignalSlotEditorWindow::updateUi() m_remove_button->setEnabled(!m_editor.isNull() && m_view->currentIndex().isValid()); } +void SignalSlotEditorWindow::resizeColumns() +{ + for (int c = 0, count = m_model->columnCount(); c < count; ++c) + m_view->resizeColumnToContents(c); +} + } // namespace qdesigner_internal QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h index 8a51a8ca06..4d7af91f84 100644 --- a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h +++ b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h @@ -65,6 +65,7 @@ private slots: void addConnection(); void removeConnection(); void updateUi(); + void resizeColumns(); private: QTreeView *m_view; diff --git a/src/designer/src/components/tabordereditor/tabordereditor.cpp b/src/designer/src/components/tabordereditor/tabordereditor.cpp index bb8a01137c..fbebc89dcc 100644 --- a/src/designer/src/components/tabordereditor/tabordereditor.cpp +++ b/src/designer/src/components/tabordereditor/tabordereditor.cpp @@ -262,7 +262,7 @@ void TabOrderEditor::mouseMoveEvent(QMouseEvent *e) { e->accept(); #if QT_CONFIG(cursor) - if (m_indicator_region.contains(e->pos())) + if (m_indicator_region.contains(e->position().toPoint())) setCursor(Qt::PointingHandCursor); else setCursor(QCursor()); @@ -288,19 +288,19 @@ void TabOrderEditor::mousePressEvent(QMouseEvent *e) { e->accept(); - if (!m_indicator_region.contains(e->pos())) { - if (QWidget *child = m_bg_widget->childAt(e->pos())) { + if (!m_indicator_region.contains(e->position().toPoint())) { + if (QWidget *child = m_bg_widget->childAt(e->position().toPoint())) { QDesignerFormEditorInterface *core = m_form_window->core(); if (core->widgetFactory()->isPassiveInteractor(child)) { QMouseEvent event(QEvent::MouseButtonPress, - child->mapFromGlobal(e->globalPos()), + child->mapFromGlobal(e->globalPosition().toPoint()), e->button(), e->buttons(), e->modifiers()); qApp->sendEvent(child, &event); QMouseEvent event2(QEvent::MouseButtonRelease, - child->mapFromGlobal(e->globalPos()), + child->mapFromGlobal(e->globalPosition().toPoint()), e->button(), e->buttons(), e->modifiers()); qApp->sendEvent(child, &event2); @@ -314,7 +314,7 @@ void TabOrderEditor::mousePressEvent(QMouseEvent *e) if (e->button() != Qt::LeftButton) return; - const int target_index = widgetIndexAt(e->pos()); + const int target_index = widgetIndexAt(e->position().toPoint()); if (target_index == -1) return; @@ -375,7 +375,7 @@ void TabOrderEditor::mouseDoubleClickEvent(QMouseEvent *e) if (e->button() != Qt::LeftButton) return; - const int target_index = widgetIndexAt(e->pos()); + const int target_index = widgetIndexAt(e->position().toPoint()); if (target_index >= 0) return; diff --git a/src/designer/src/components/tabordereditor/tabordereditor.pri b/src/designer/src/components/tabordereditor/tabordereditor.pri deleted file mode 100644 index da1ecfbaee..0000000000 --- a/src/designer/src/components/tabordereditor/tabordereditor.pri +++ /dev/null @@ -1,17 +0,0 @@ - -QT += xml - -INCLUDEPATH += $$PWD - -HEADERS += \ - $$PWD/tabordereditor.h \ - $$PWD/tabordereditor_plugin.h \ - $$PWD/tabordereditor_tool.h \ - $$PWD/tabordereditor_global.h - -SOURCES += \ - $$PWD/tabordereditor.cpp \ - $$PWD/tabordereditor_tool.cpp \ - $$PWD/tabordereditor_plugin.cpp - -OTHER_FILES += $$PWD/tabordereditor.json diff --git a/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp b/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp index 0927bc870c..a95d1fe160 100644 --- a/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp +++ b/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ -#include +#include #include "tabordereditor_plugin.h" #include "tabordereditor_tool.h" @@ -113,3 +113,5 @@ QAction *TabOrderEditorPlugin::action() const } QT_END_NAMESPACE + +#include "moc_tabordereditor_plugin.cpp" diff --git a/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp b/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp index c70f3032cd..64da969371 100644 --- a/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp +++ b/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp @@ -31,8 +31,9 @@ #include +#include + #include -#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/taskmenu/button_taskmenu.cpp b/src/designer/src/components/taskmenu/button_taskmenu.cpp index 5791c69914..5facfdad3e 100644 --- a/src/designer/src/components/taskmenu/button_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/button_taskmenu.cpp @@ -38,14 +38,16 @@ #include #include -#include -#include #include #include #include #include #include #include + +#include +#include + #include Q_DECLARE_METATYPE(QButtonGroup*) @@ -211,7 +213,7 @@ CreateButtonGroupCommand::CreateButtonGroupCommand(QDesignerFormWindowInterface bool CreateButtonGroupCommand::init(const ButtonList &bl) { - if (bl.empty()) + if (bl.isEmpty()) return false; QDesignerFormWindowInterface *fw = formWindow(); QButtonGroup *buttonGroup = new QButtonGroup(fw->mainContainer()); @@ -286,9 +288,9 @@ RemoveButtonsFromGroupCommand::RemoveButtonsFromGroupCommand(QDesignerFormWindow bool RemoveButtonsFromGroupCommand::init(const ButtonList &bl) { - if (bl.empty()) + if (bl.isEmpty()) return false; - QButtonGroup *group = bl.front()->group(); + QButtonGroup *group = bl.constFirst()->group(); if (!group) return false; if (bl.size() >= group->buttons().size()) @@ -388,7 +390,7 @@ QRect ButtonTextTaskMenuInlineEditor::editRectangle() const { QWidget *w = widget(); QStyleOptionButton opt; - opt.init(w); + opt.initFrom(w); return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); } @@ -411,7 +413,7 @@ QRect LinkDescriptionTaskMenuInlineEditor::editRectangle() const { QWidget *w = widget(); // TODO: What is the exact description area? QStyleOptionButton opt; - opt.init(w); + opt.initFrom(w); return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); } @@ -560,7 +562,7 @@ static ButtonList buttonList(const QDesignerFormWindowCursorInterface *cursor) static QUndoCommand *createRemoveButtonsCommand(QDesignerFormWindowInterface *fw, const ButtonList &bl) { - QButtonGroup *bg = bl.front()->group(); + QButtonGroup *bg = bl.constFirst()->group(); // Complete group or 1-member group? if (bl.size() >= bg->buttons().size() - 1) { BreakButtonGroupCommand *breakCmd = new BreakButtonGroupCommand(fw); @@ -588,7 +590,7 @@ void ButtonTaskMenu::createGroup() const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = nullptr; - if (bl.front()->group()) { + if (bl.constFirst()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; @@ -651,7 +653,7 @@ void ButtonTaskMenu::addToGroup(QAction *a) const ButtonList bl = buttonList(fw->cursor()); // Do we need to remove the buttons from an existing group? QUndoCommand *removeCmd = nullptr; - if (bl.front()->group()) { + if (bl.constFirst()->group()) { removeCmd = createRemoveButtonsCommand(fw, bl); if (!removeCmd) return; diff --git a/src/designer/src/components/taskmenu/combobox_taskmenu.cpp b/src/designer/src/components/taskmenu/combobox_taskmenu.cpp index 6d96e97957..6613b03d2e 100644 --- a/src/designer/src/components/taskmenu/combobox_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/combobox_taskmenu.cpp @@ -33,12 +33,13 @@ #include -#include #include #include #include #include +#include + #include #include #include diff --git a/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp b/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp index 1df9e4bbbe..1bbca9d103 100644 --- a/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp @@ -38,7 +38,6 @@ #include #include -#include #include #include #include @@ -48,6 +47,8 @@ #include #include +#include + #include QT_BEGIN_NAMESPACE @@ -150,7 +151,7 @@ QList ContainerWidgetTaskMenu::taskActions() const const QDesignerContainerExtension *ce = containerExtension(); const int index = ce->currentIndex(); - QList actions = QDesignerTaskMenu::taskActions(); + auto actions = QDesignerTaskMenu::taskActions(); actions += m_taskActions; // Update the page submenu, deletion and promotion. Updated on demand due to promotion state. m_pageMenu->clear(); @@ -224,7 +225,7 @@ WizardContainerWidgetTaskMenu::WizardContainerWidgetTaskMenu(QWizard *w, QObject { connect(m_nextAction, &QAction::triggered, w, &QWizard::next); connect(m_previousAction, &QAction::triggered, w, &QWizard::back); - QList &l = containerActions(); + auto &l = containerActions(); l.push_front(createSeparator()); l.push_front(m_nextAction); l.push_front(m_previousAction); @@ -260,7 +261,7 @@ void MdiContainerWidgetTaskMenu::initializeActions() m_tileAction = new QAction(tr("Tile"), this); m_cascadeAction = new QAction(tr("Cascade"), this); - QList &l = containerActions(); + auto &l = containerActions(); l.push_front(createSeparator()); l.push_front(m_tileAction); l.push_front(m_cascadeAction); @@ -271,7 +272,7 @@ void MdiContainerWidgetTaskMenu::initializeActions() QList MdiContainerWidgetTaskMenu::taskActions() const { - const QList rc = ContainerWidgetTaskMenu::taskActions(); + const auto rc = ContainerWidgetTaskMenu::taskActions(); // Enable const int count = pageCount(); m_nextAction->setEnabled(count > 1); diff --git a/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp b/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp index 3b76299080..bc6cb55245 100644 --- a/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp @@ -31,10 +31,11 @@ #include -#include #include #include +#include + QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -58,7 +59,7 @@ QRect GroupBoxTaskMenuInlineEditor::editRectangle() const { QWidget *w = widget(); QStyleOption opt; // ## QStyleOptionGroupBox - opt.init(w); + opt.initFrom(w); return QRect(QPoint(), QSize(w->width(),20)); } diff --git a/src/designer/src/components/taskmenu/inplace_widget_helper.cpp b/src/designer/src/components/taskmenu/inplace_widget_helper.cpp index 44145bdba8..5b38e832f1 100644 --- a/src/designer/src/components/taskmenu/inplace_widget_helper.cpp +++ b/src/designer/src/components/taskmenu/inplace_widget_helper.cpp @@ -29,10 +29,12 @@ #include "abstractformwindow.h" #include "inplace_widget_helper.h" -#include + #include #include -#include + +#include +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/taskmenu/itemlisteditor.cpp b/src/designer/src/components/taskmenu/itemlisteditor.cpp index 8aca0916d7..7d8514bd3e 100644 --- a/src/designer/src/components/taskmenu/itemlisteditor.cpp +++ b/src/designer/src/components/taskmenu/itemlisteditor.cpp @@ -169,7 +169,7 @@ void AbstractItemEditor::propertyChanged(QtProperty *property) if ((role == ItemFlagsShadowRole && prop->value().toInt() == defaultItemFlags()) || (role == Qt::DecorationPropertyRole && !qvariant_cast(prop->value()).mask()) - || (role == Qt::FontRole && !qvariant_cast(prop->value()).resolve())) { + || (role == Qt::FontRole && !qvariant_cast(prop->value()).resolveMask())) { prop->setModified(false); setItemData(role, QVariant()); } else { @@ -215,7 +215,7 @@ void AbstractItemEditor::resetProperty(QtProperty *property) if (role == ItemFlagsShadowRole) prop->setValue(QVariant::fromValue(defaultItemFlags())); else - prop->setValue(QVariant(prop->valueType(), nullptr)); + prop->setValue(QVariant(QMetaType(prop->valueType()), nullptr)); prop->setModified(false); setItemData(role, QVariant()); @@ -247,7 +247,7 @@ void AbstractItemEditor::updateBrowser() if (role == ItemFlagsShadowRole) val = QVariant::fromValue(defaultItemFlags()); else - val = QVariant(int(prop->value().userType()), nullptr); + val = QVariant(QMetaType(prop->value().userType()), nullptr); prop->setModified(false); } else { prop->setModified(true); @@ -412,7 +412,7 @@ void ItemListEditor::setItemData(int role, const QVariant &v) || role == Qt::FontRole) reLayout = true; QVariant newValue = v; - if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + if (role == Qt::FontRole && newValue.metaType().id() == QMetaType::QFont) { QFont oldFont = ui.listWidget->font(); QFont newFont = qvariant_cast(newValue).resolve(oldFont); newValue = QVariant::fromValue(newFont); diff --git a/src/designer/src/components/taskmenu/label_taskmenu.cpp b/src/designer/src/components/taskmenu/label_taskmenu.cpp index b46a2a64e8..aaaa619a6d 100644 --- a/src/designer/src/components/taskmenu/label_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/label_taskmenu.cpp @@ -31,9 +31,10 @@ #include -#include #include #include + +#include #include static const char *textPropertyC = "text"; @@ -60,7 +61,7 @@ LabelTaskMenuInlineEditor::LabelTaskMenuInlineEditor(QLabel *w, QObject *parent) QRect LabelTaskMenuInlineEditor::editRectangle() const { QStyleOptionButton opt; - opt.init(widget()); + opt.initFrom(widget()); return opt.rect; } diff --git a/src/designer/src/components/taskmenu/layouttaskmenu.cpp b/src/designer/src/components/taskmenu/layouttaskmenu.cpp index 94c2095c45..39ea6df2ee 100644 --- a/src/designer/src/components/taskmenu/layouttaskmenu.cpp +++ b/src/designer/src/components/taskmenu/layouttaskmenu.cpp @@ -32,7 +32,8 @@ #include -#include +#include + #include QT_BEGIN_NAMESPACE @@ -73,7 +74,7 @@ QAction *SpacerTaskMenu::preferredEditAction() const QList SpacerTaskMenu::taskActions() const { - return QList(); + return {}; } QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp b/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp index cbe2f3e2fe..f52a060e62 100644 --- a/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp @@ -31,10 +31,11 @@ #include -#include #include #include +#include + QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -57,7 +58,7 @@ LineEditTaskMenuInlineEditor::LineEditTaskMenuInlineEditor(QLineEdit *w, QObject QRect LineEditTaskMenuInlineEditor::editRectangle() const { QStyleOption opt; - opt.init(widget()); + opt.initFrom(widget()); return opt.rect; } diff --git a/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp b/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp index 74bff711db..d4b2cb71ab 100644 --- a/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp @@ -33,11 +33,12 @@ #include -#include #include #include #include +#include + #include #include #include diff --git a/src/designer/src/components/taskmenu/listwidgeteditor.cpp b/src/designer/src/components/taskmenu/listwidgeteditor.cpp index 098dac2cd4..668978c0d4 100644 --- a/src/designer/src/components/taskmenu/listwidgeteditor.cpp +++ b/src/designer/src/components/taskmenu/listwidgeteditor.cpp @@ -74,10 +74,10 @@ static AbstractItemEditor::PropertyDefinition listBoxPropList[] = { { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, - { Qt::FontRole, QVariant::Font, nullptr, "font" }, + { Qt::FontRole, QMetaType::QFont, nullptr, "font" }, { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, - { Qt::BackgroundRole, QVariant::Brush, nullptr, "background" }, - { Qt::ForegroundRole, QVariant::Brush, nullptr, "foreground" }, + { Qt::BackgroundRole, QMetaType::QBrush, nullptr, "background" }, + { Qt::ForegroundRole, QMetaType::QBrush, nullptr, "foreground" }, { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, { 0, 0, nullptr, nullptr } diff --git a/src/designer/src/components/taskmenu/menutaskmenu.cpp b/src/designer/src/components/taskmenu/menutaskmenu.cpp index 105c3eabd8..87cd4bee5b 100644 --- a/src/designer/src/components/taskmenu/menutaskmenu.cpp +++ b/src/designer/src/components/taskmenu/menutaskmenu.cpp @@ -30,7 +30,8 @@ #include -#include +#include + #include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp b/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp index 25bc6ce405..e0d8d5c948 100644 --- a/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp @@ -32,11 +32,12 @@ #include #include -#include #include #include #include +#include + #include #include #include diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.cpp b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp index b5f41626cf..5c37106c92 100644 --- a/src/designer/src/components/taskmenu/tablewidgeteditor.cpp +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp @@ -108,10 +108,10 @@ static AbstractItemEditor::PropertyDefinition tableHeaderPropList[] = { { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, // { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, - { Qt::FontRole, QVariant::Font, nullptr, "font" }, + { Qt::FontRole, QMetaType::QFont, nullptr, "font" }, { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, - { Qt::BackgroundRole, QVariant::Color, nullptr, "background" }, - { Qt::ForegroundRole, QVariant::Brush, nullptr, "foreground" }, + { Qt::BackgroundRole, QMetaType::QColor, nullptr, "background" }, + { Qt::ForegroundRole, QMetaType::QBrush, nullptr, "foreground" }, { 0, 0, nullptr, nullptr } }; @@ -121,10 +121,10 @@ static AbstractItemEditor::PropertyDefinition tableItemPropList[] = { { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, // { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, - { Qt::FontRole, QVariant::Font, nullptr, "font" }, + { Qt::FontRole, QMetaType::QFont, nullptr, "font" }, { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, - { Qt::BackgroundRole, QVariant::Brush, nullptr, "background" }, - { Qt::ForegroundRole, QVariant::Brush, nullptr, "foreground" }, + { Qt::BackgroundRole, QMetaType::QBrush, nullptr, "background" }, + { Qt::ForegroundRole, QMetaType::QBrush, nullptr, "foreground" }, { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, { 0, 0, nullptr, nullptr } @@ -167,7 +167,7 @@ void TableWidgetEditor::setItemData(int role, const QVariant &v) ui.tableWidget->setItem(ui.tableWidget->currentRow(), ui.tableWidget->currentColumn(), item); } QVariant newValue = v; - if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + if (role == Qt::FontRole && newValue.metaType().id() == QMetaType::QFont) { QFont oldFont = ui.tableWidget->font(); QFont newFont = qvariant_cast(newValue).resolve(oldFont); newValue = QVariant::fromValue(newFont); diff --git a/src/designer/src/components/taskmenu/taskmenu.pri b/src/designer/src/components/taskmenu/taskmenu.pri deleted file mode 100644 index 7f8ceca960..0000000000 --- a/src/designer/src/components/taskmenu/taskmenu.pri +++ /dev/null @@ -1,49 +0,0 @@ -INCLUDEPATH += $$PWD \ - ../propertyeditor \ - ../../../../shared/tools/shared/qtpropertybrowser - -FORMS += $$PWD/itemlisteditor.ui \ - $$PWD/treewidgeteditor.ui \ - $$PWD/tablewidgeteditor.ui - -HEADERS += $$PWD/button_taskmenu.h \ - $$PWD/groupbox_taskmenu.h \ - $$PWD/label_taskmenu.h \ - $$PWD/lineedit_taskmenu.h \ - $$PWD/listwidget_taskmenu.h \ - $$PWD/treewidget_taskmenu.h \ - $$PWD/tablewidget_taskmenu.h \ - $$PWD/combobox_taskmenu.h \ - $$PWD/textedit_taskmenu.h \ - $$PWD/toolbar_taskmenu.h \ - $$PWD/containerwidget_taskmenu.h \ - $$PWD/inplace_editor.h \ - $$PWD/taskmenu_component.h \ - $$PWD/itemlisteditor.h \ - $$PWD/listwidgeteditor.h \ - $$PWD/treewidgeteditor.h \ - $$PWD/tablewidgeteditor.h \ - $$PWD/inplace_widget_helper.h \ - $$PWD/menutaskmenu.h \ - $$PWD/layouttaskmenu.h - -SOURCES += $$PWD/button_taskmenu.cpp \ - $$PWD/groupbox_taskmenu.cpp \ - $$PWD/label_taskmenu.cpp \ - $$PWD/lineedit_taskmenu.cpp \ - $$PWD/listwidget_taskmenu.cpp \ - $$PWD/treewidget_taskmenu.cpp \ - $$PWD/tablewidget_taskmenu.cpp \ - $$PWD/combobox_taskmenu.cpp \ - $$PWD/textedit_taskmenu.cpp \ - $$PWD/toolbar_taskmenu.cpp \ - $$PWD/containerwidget_taskmenu.cpp \ - $$PWD/inplace_editor.cpp \ - $$PWD/taskmenu_component.cpp \ - $$PWD/itemlisteditor.cpp \ - $$PWD/listwidgeteditor.cpp \ - $$PWD/treewidgeteditor.cpp \ - $$PWD/tablewidgeteditor.cpp \ - $$PWD/inplace_widget_helper.cpp \ - $$PWD/menutaskmenu.cpp \ - $$PWD/layouttaskmenu.cpp diff --git a/src/designer/src/components/taskmenu/textedit_taskmenu.cpp b/src/designer/src/components/taskmenu/textedit_taskmenu.cpp index ca5d5d5263..9894583924 100644 --- a/src/designer/src/components/taskmenu/textedit_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/textedit_taskmenu.cpp @@ -30,7 +30,8 @@ #include -#include +#include + #include #include diff --git a/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp b/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp index 158917e24c..3fc1b8b4d8 100644 --- a/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp @@ -34,8 +34,8 @@ #include #include -#include -#include +#include +#include #include @@ -58,7 +58,7 @@ namespace qdesigner_internal { { if (ToolBarEventFilter *ef = ToolBarEventFilter::eventFilterOf(m_toolBar)) return ef->contextMenuActions(); - return QList(); + return {}; } // ------------ StatusBarTaskMenu diff --git a/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp b/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp index c4ffd4ca58..6b4969c526 100644 --- a/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp +++ b/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp @@ -31,11 +31,12 @@ #include -#include #include #include #include +#include + #include #include #include diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.cpp b/src/designer/src/components/taskmenu/treewidgeteditor.cpp index 5e77939e5b..a7117beb53 100644 --- a/src/designer/src/components/taskmenu/treewidgeteditor.cpp +++ b/src/designer/src/components/taskmenu/treewidgeteditor.cpp @@ -108,10 +108,10 @@ static AbstractItemEditor::PropertyDefinition treeHeaderPropList[] = { { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, - { Qt::FontRole, QVariant::Font, nullptr, "font" }, + { Qt::FontRole, QMetaType::QFont, nullptr, "font" }, { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, - { Qt::BackgroundRole, QVariant::Color, nullptr, "background" }, - { Qt::ForegroundRole, QVariant::Brush, nullptr, "foreground" }, + { Qt::BackgroundRole, QMetaType::QColor, nullptr, "background" }, + { Qt::ForegroundRole, QMetaType::QBrush, nullptr, "foreground" }, { 0, 0, nullptr, nullptr } }; @@ -121,10 +121,10 @@ static AbstractItemEditor::PropertyDefinition treeItemColumnPropList[] = { { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, - { Qt::FontRole, QVariant::Font, nullptr, "font" }, + { Qt::FontRole, QMetaType::QFont, nullptr, "font" }, { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, - { Qt::BackgroundRole, QVariant::Brush, nullptr, "background" }, - { Qt::ForegroundRole, QVariant::Brush, nullptr, "foreground" }, + { Qt::BackgroundRole, QMetaType::QBrush, nullptr, "background" }, + { Qt::ForegroundRole, QMetaType::QBrush, nullptr, "foreground" }, { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, { 0, 0, nullptr, nullptr } }; @@ -181,7 +181,7 @@ void TreeWidgetEditor::setItemData(int role, const QVariant &v) const int col = (role == ItemFlagsShadowRole) ? 0 : ui.treeWidget->currentColumn(); QVariant newValue = v; BoolBlocker block(m_updatingBrowser); - if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + if (role == Qt::FontRole && newValue.metaType().id() == QMetaType::QFont) { QFont oldFont = ui.treeWidget->font(); QFont newFont = qvariant_cast(newValue).resolve(oldFont); newValue = QVariant::fromValue(newFont); diff --git a/src/designer/src/components/widgetbox/widgetbox.cpp b/src/designer/src/components/widgetbox/widgetbox.cpp index 4415c4dbe7..bf42f20481 100644 --- a/src/designer/src/components/widgetbox/widgetbox.cpp +++ b/src/designer/src/components/widgetbox/widgetbox.cpp @@ -246,7 +246,7 @@ void WidgetBox::dropEvent(QDropEvent * event) if (!mimeData) return; - dropWidgets(mimeData->items(), event->pos()); + dropWidgets(mimeData->items(), event->position().toPoint()); QDesignerMimeData::removeMovedWidgetsFromSourceForm(mimeData->items()); } diff --git a/src/designer/src/components/widgetbox/widgetbox.pri b/src/designer/src/components/widgetbox/widgetbox.pri deleted file mode 100644 index dd8ad002ec..0000000000 --- a/src/designer/src/components/widgetbox/widgetbox.pri +++ /dev/null @@ -1,14 +0,0 @@ - -INCLUDEPATH += $$PWD - -SOURCES += $$PWD/widgetboxcategorylistview.cpp \ - $$PWD/widgetboxtreewidget.cpp \ - $$PWD/widgetbox.cpp \ - $$PWD/widgetbox_dnditem.cpp -HEADERS += $$PWD/widgetboxcategorylistview.h \ - $$PWD/widgetboxtreewidget.h \ - $$PWD/widgetbox.h \ - $$PWD/widgetbox_global.h \ - $$PWD/widgetbox_dnditem.h - -RESOURCES += $$PWD/widgetbox.qrc diff --git a/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp b/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp index 30fbc23376..c44fa41695 100644 --- a/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp +++ b/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp @@ -174,7 +174,7 @@ static QWidget *decorationFromDomWidget(DomUI *dom_ui, QDesignerFormEditorInterf QWidget *fakeTopLevel = builder.createUI(dom_ui, nullptr); fakeTopLevel->setParent(nullptr, Qt::ToolTip); // Container // Actual widget - const DomWidget *domW = dom_ui->elementWidget()->elementWidget().front(); + const DomWidget *domW = dom_ui->elementWidget()->elementWidget().constFirst(); QWidget *w = fakeTopLevel->findChildren().constFirst(); Q_ASSERT(w); // hack begin; diff --git a/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp b/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp index 5b00ea68f7..2f5b7f536b 100644 --- a/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp +++ b/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -268,8 +269,10 @@ QVariant WidgetBoxCategoryModel::data(const QModelIndex &index, int role) const bool WidgetBoxCategoryModel::setData(const QModelIndex &index, const QVariant &value, int role) { const int row = index.row(); - if (role != Qt::EditRole || row < 0 || row >= m_items.size() || value.type() != QVariant::String) + if (role != Qt::EditRole || row < 0 || row >= m_items.size() + || value.metaType().id() != QMetaType::QString) { return false; + } // Set name and adapt Xml WidgetBoxCategoryEntry &item = m_items[row]; const QString newName = value.toString(); @@ -482,9 +485,10 @@ QString WidgetBoxCategoryListView::widgetDomXml(const QDesignerWidgetBoxInterfac return domXml; } -void WidgetBoxCategoryListView::filter(const QRegExp &re) +void WidgetBoxCategoryListView::filter(const QString &needle, Qt::CaseSensitivity caseSensitivity) { - m_proxyModel->setFilterRegExp(re); + m_proxyModel->setFilterFixedString(needle); + m_proxyModel->setFilterCaseSensitivity(caseSensitivity); } QDesignerWidgetBoxInterface::Category WidgetBoxCategoryListView::category() const diff --git a/src/designer/src/components/widgetbox/widgetboxcategorylistview.h b/src/designer/src/components/widgetbox/widgetboxcategorylistview.h index 657dad148c..28db852f66 100644 --- a/src/designer/src/components/widgetbox/widgetboxcategorylistview.h +++ b/src/designer/src/components/widgetbox/widgetboxcategorylistview.h @@ -40,7 +40,6 @@ class QDesignerFormEditorInterface; class QDesignerDnDItemInterface; class QSortFilterProxyModel; -class QRegExp; namespace qdesigner_internal { @@ -85,7 +84,7 @@ class WidgetBoxCategoryListView : public QListView void lastItemRemoved(); public slots: - void filter(const QRegExp &re); + void filter(const QString &needle, Qt::CaseSensitivity caseSensitivity); void removeCurrentItem(); void editCurrentItem(); diff --git a/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp b/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp index dd17b3a4e5..1fef65ffb4 100644 --- a/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp +++ b/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp @@ -43,13 +43,15 @@ #include -#include #include +#include +#include +#include #include + +#include +#include #include -#include -#include -#include #include #include @@ -160,7 +162,7 @@ void WidgetBoxTreeWidget::restoreExpandedState() const auto &closedCategoryList = settings->value(groupKey + QLatin1String(widgetBoxExpandedKeyC), QStringList()).toStringList(); const StringSet closedCategories(closedCategoryList.cbegin(), closedCategoryList.cend()); expandAll(); - if (closedCategories.empty()) + if (closedCategories.isEmpty()) return; if (const int numCategories = categoryCount()) { @@ -303,7 +305,15 @@ bool WidgetBoxTreeWidget::load(QDesignerWidgetBox::LoadMode loadMode) return false; const QString contents = QString::fromUtf8(f.readAll()); - return loadContents(contents); + if (!loadContents(contents)) + return false; + if (topLevelItemCount() > 0) { + // QTBUG-93099: Set the single step to the item height to have some + // size-related value. + const auto itemHeight = visualItemRect(topLevelItem(0)).height(); + verticalScrollBar()->setSingleStep(itemHeight); + } + return true; } bool WidgetBoxTreeWidget::loadContents(const QString &contents) @@ -366,7 +376,7 @@ bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString while (!reader.atEnd()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement: { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (tag == QLatin1String(widgetBoxRootElementC)) { // continue; @@ -411,7 +421,7 @@ bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString break; } case QXmlStreamReader::EndElement: { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (tag == QLatin1String(widgetBoxRootElementC)) { continue; } @@ -472,7 +482,7 @@ bool WidgetBoxTreeWidget::readWidget(Widget *w, const QString &xml, QXmlStreamRe case QXmlStreamReader::StartElement: if (nesting++ == 0) { // First element must be or (legacy) - const QStringRef name = r.name(); + const auto name = r.name(); if (name == QLatin1String(uiElementC)) { startTagPosition = currentPosition; } else { @@ -593,9 +603,8 @@ static int findCategory(const QString &name, const WidgetBoxTreeWidget::Category static inline bool isValidIcon(const QIcon &icon) { if (!icon.isNull()) { - const QList availableSizes = icon.availableSizes(); - if (!availableSizes.empty()) - return !availableSizes.front().isEmpty(); + const auto availableSizes = icon.availableSizes(); + return !availableSizes.isEmpty() && !availableSizes.constFirst().isEmpty(); } return false; } @@ -606,7 +615,7 @@ WidgetBoxTreeWidget::CategoryList WidgetBoxTreeWidget::loadCustomCategoryList() const QDesignerPluginManager *pm = m_core->pluginManager(); const QDesignerPluginManager::CustomWidgetList customWidgets = pm->registeredCustomWidgets(); - if (customWidgets.empty()) + if (customWidgets.isEmpty()) return result; static const QString customCatName = tr("Custom Widgets"); @@ -967,7 +976,6 @@ void WidgetBoxTreeWidget::dropWidgets(const QList &i void WidgetBoxTreeWidget::filter(const QString &f) { const bool empty = f.isEmpty(); - QRegExp re = empty ? QRegExp() : QRegExp(f, Qt::CaseInsensitive, QRegExp::FixedString); const int numTopLevels = topLevelItemCount(); bool changed = false; for (int i = 0; i < numTopLevels; i++) { @@ -975,7 +983,7 @@ void WidgetBoxTreeWidget::filter(const QString &f) WidgetBoxCategoryListView *categoryView = categoryViewAt(i); // Anything changed? -> Enable the category const int oldCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); - categoryView->filter(re); + categoryView->filter(f, Qt::CaseInsensitive); const int newCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); if (oldCount != newCount) { changed = true; diff --git a/src/designer/src/designer/CMakeLists.txt b/src/designer/src/designer/CMakeLists.txt new file mode 100644 index 0000000000..1ecaa40200 --- /dev/null +++ b/src/designer/src/designer/CMakeLists.txt @@ -0,0 +1,147 @@ +# Generated from designer.pro. + +##################################################################### +## designer App: +##################################################################### + +qt_internal_add_app(designer + SOURCES + ../../../shared/fontpanel/fontpanel.cpp ../../../shared/fontpanel/fontpanel.h + ../../../shared/qttoolbardialog/qttoolbardialog.cpp ../../../shared/qttoolbardialog/qttoolbardialog.h ../../../shared/qttoolbardialog/qttoolbardialog.ui + appfontdialog.cpp appfontdialog.h + assistantclient.cpp assistantclient.h + designer_enums.h + main.cpp + mainwindow.cpp mainwindow.h + newform.cpp newform.h + preferencesdialog.cpp preferencesdialog.h preferencesdialog.ui + qdesigner.cpp qdesigner.h + qdesigner_actions.cpp qdesigner_actions.h + qdesigner_appearanceoptions.cpp qdesigner_appearanceoptions.h qdesigner_appearanceoptions.ui + qdesigner_formwindow.cpp qdesigner_formwindow.h + qdesigner_server.cpp qdesigner_server.h + qdesigner_settings.cpp qdesigner_settings.h + qdesigner_toolwindow.cpp qdesigner_toolwindow.h + qdesigner_workbench.cpp qdesigner_workbench.h + saveformastemplate.cpp saveformastemplate.h saveformastemplate.ui + versiondialog.cpp versiondialog.h + INCLUDE_DIRECTORIES + ../../../shared/fontpanel + ../../../shared/qttoolbardialog + ../lib/extension + ../lib/sdk + ../lib/shared + extra + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::DesignerComponentsPrivate + Qt::DesignerPrivate + Qt::Gui + Qt::Network + Qt::Widgets + Qt::Xml + ENABLE_AUTOGEN_TOOLS + uic + PRECOMPILED_HEADER + "qdesigner_pch.h" +) + +# Resources: +set(designer_resource_files + "images/designer.png" +) + +qt_internal_add_resource(designer "designer" + PREFIX + "/qt-project.org/designer" + FILES + ${designer_resource_files} +) +set(qttoolbardialog_resource_files + "../../../shared/qttoolbardialog/images/back.png" + "../../../shared/qttoolbardialog/images/down.png" + "../../../shared/qttoolbardialog/images/forward.png" + "../../../shared/qttoolbardialog/images/minus.png" + "../../../shared/qttoolbardialog/images/plus.png" + "../../../shared/qttoolbardialog/images/up.png" +) + +qt_internal_add_resource(designer "qttoolbardialog" + PREFIX + "/qt-project.org/qttoolbardialog" + BASE + "../../../shared/qttoolbardialog" + FILES + ${qttoolbardialog_resource_files} +) + +set_target_properties(designer PROPERTIES + QT_TARGET_DESCRIPTION "Qt Designer" +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(designer CONDITION TARGET Qt::PrintSupport + PUBLIC_LIBRARIES + Qt::PrintSupport +) + +qt_internal_extend_target(designer CONDITION NOT QT_BUILD_SHARED_LIBS + DEFINES + QT_DESIGNER_STATIC +) + +if(WIN32) + set_target_properties(designer PROPERTIES + QT_TARGET_RC_ICONS "${CMAKE_CURRENT_SOURCE_DIR}/designer.ico" + ) +endif() + +if(WIN32) + set_target_properties(designer PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}.0" + ) +endif() + +if(UNIX) + set_target_properties(designer PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}" + ) +endif() + +if(APPLE) + set_target_properties(designer PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist" + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "designer.icns" + OUTPUT_NAME "Designer" + ) + set_source_files_properties(designer.icns PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + target_sources(designer PRIVATE + designer.icns + ) + # special case end + # Set values to be replaced in the custom Info_mac.plist. + # Also package the uifile.icns. + set(ICON "designer.icns") + set(EXECUTABLE "Designer") + set_source_files_properties(uifile.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + target_sources(designer PRIVATE uifile.icns) + # special case end +endif() + +#### Keys ignored in scope 6:.:.:designer.pro:APPLE: +# FILETYPES.files = "uifile.icns" +# FILETYPES.path = "Contents/Resources" +# QMAKE_BUNDLE_DATA = "FILETYPES" + +qt_internal_extend_target(designer CONDITION UNIX AND NOT HAIKU AND NOT MACOS + PUBLIC_LIBRARIES + m +) +qt_internal_add_docs(designer + doc/qtdesigner.qdocconf +) diff --git a/src/designer/src/designer/appfontdialog.cpp b/src/designer/src/designer/appfontdialog.cpp index b1a3942df3..7b40fb5b33 100644 --- a/src/designer/src/designer/appfontdialog.cpp +++ b/src/designer/src/designer/appfontdialog.cpp @@ -32,23 +32,24 @@ #include -#include -#include +#include +#include + #include -#include +#include #include -#include +#include #include -#include -#include +#include +#include -#include -#include -#include -#include #include -#include +#include #include +#include +#include +#include +#include #include @@ -122,7 +123,7 @@ void AppFontManager::restore(const QDesignerSettingsInterface *s, const QString if (debugAppFontWidget) qDebug() << "AppFontManager::restoring" << fontFiles.size() << "fonts from " << prefix; - if (!fontFiles.empty()) { + if (!fontFiles.isEmpty()) { QString errorMessage; const QStringList::const_iterator cend = fontFiles.constEnd(); for (QStringList::const_iterator it = fontFiles.constBegin(); it != cend; ++it) @@ -311,7 +312,7 @@ void AppFontWidget::addFiles() const QStringList files = QFileDialog::getOpenFileNames(this, tr("Add Font Files"), QString(), tr("Font files (*.ttf)")); - if (files.empty()) + if (files.isEmpty()) return; QString errorMessage; @@ -331,12 +332,12 @@ void AppFontWidget::addFiles() static void removeFonts(const QModelIndexList &selectedIndexes, AppFontModel *model, QWidget *dialogParent) { - if (selectedIndexes.empty()) + if (selectedIndexes.isEmpty()) return; // Reverse sort top level rows and remove AppFontManager &fmgr = AppFontManager::instance(); - QVector rows; + QList rows; rows.reserve(selectedIndexes.size()); QString errorMessage; @@ -382,7 +383,7 @@ void AppFontWidget::slotRemoveAll() void AppFontWidget::selectionChanged(const QItemSelection &selected, const QItemSelection & /*deselected*/) { - m_removeButton->setEnabled(!selected.indexes().empty()); + m_removeButton->setEnabled(!selected.indexes().isEmpty()); } void AppFontWidget::save(QDesignerSettingsInterface *s, const QString &prefix) diff --git a/src/designer/src/designer/assistantclient.cpp b/src/designer/src/designer/assistantclient.cpp index bf8026c3cf..45fee43932 100644 --- a/src/designer/src/designer/assistantclient.cpp +++ b/src/designer/src/designer/assistantclient.cpp @@ -85,7 +85,7 @@ bool AssistantClient::sendCommand(const QString &cmd, QString *errorMessage) return false; } QTextStream str(m_process); - str << cmd << QLatin1Char('\n') << endl; + str << cmd << QLatin1Char('\n') << Qt::endl; return true; } @@ -96,7 +96,7 @@ bool AssistantClient::isRunning() const QString AssistantClient::binary() { - QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); + QString app = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QDir::separator(); #if !defined(Q_OS_MACOS) app += QStringLiteral("assistant"); #else diff --git a/src/designer/src/designer/designer.pro b/src/designer/src/designer/designer.pro deleted file mode 100644 index 6a925202af..0000000000 --- a/src/designer/src/designer/designer.pro +++ /dev/null @@ -1,82 +0,0 @@ -QT += core-private widgets xml network designer-private designercomponents-private -qtHaveModule(printsupport): QT += printsupport - -INCLUDEPATH += \ - ../lib/sdk \ - ../lib/extension \ - ../lib/shared \ - extra - -RESOURCES += designer.qrc - -contains(QT_CONFIG, static) { - DEFINES += QT_DESIGNER_STATIC -} - -include(../../../shared/fontpanel/fontpanel.pri) -include(../../../shared/qttoolbardialog/qttoolbardialog.pri) - -QMAKE_DOCS = $$PWD/doc/qtdesigner.qdocconf - -HEADERS += \ - qdesigner.h \ - qdesigner_toolwindow.h \ - qdesigner_formwindow.h \ - qdesigner_workbench.h \ - qdesigner_settings.h \ - qdesigner_actions.h \ - qdesigner_server.h \ - qdesigner_appearanceoptions.h \ - saveformastemplate.h \ - newform.h \ - versiondialog.h \ - designer_enums.h \ - appfontdialog.h \ - preferencesdialog.h \ - assistantclient.h \ - mainwindow.h - -SOURCES += main.cpp \ - qdesigner.cpp \ - qdesigner_toolwindow.cpp \ - qdesigner_formwindow.cpp \ - qdesigner_workbench.cpp \ - qdesigner_settings.cpp \ - qdesigner_server.cpp \ - qdesigner_actions.cpp \ - qdesigner_appearanceoptions.cpp \ - saveformastemplate.cpp \ - newform.cpp \ - versiondialog.cpp \ - appfontdialog.cpp \ - preferencesdialog.cpp \ - assistantclient.cpp \ - mainwindow.cpp - -PRECOMPILED_HEADER=qdesigner_pch.h - -FORMS += saveformastemplate.ui \ - preferencesdialog.ui \ - qdesigner_appearanceoptions.ui - -QMAKE_TARGET_DESCRIPTION = Qt Designer - -win32 { - RC_ICONS = designer.ico - VERSION = $${QT_VERSION}.0 -} else { - VERSION = $${QT_VERSION} -} - -mac { - ICON = designer.icns - QMAKE_INFO_PLIST = Info_mac.plist - TARGET = Designer - FILETYPES.files = uifile.icns - FILETYPES.path = Contents/Resources - QMAKE_BUNDLE_DATA += FILETYPES -} - -unix:!osx:!haiku:LIBS += -lm - -load(qt_app) diff --git a/src/designer/src/designer/doc/qtdesigner.qdocconf b/src/designer/src/designer/doc/qtdesigner.qdocconf index cc0d881aa6..d265c7ea68 100644 --- a/src/designer/src/designer/doc/qtdesigner.qdocconf +++ b/src/designer/src/designer/doc/qtdesigner.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtDesigner description = Qt Designer Manual @@ -42,7 +43,9 @@ exampledirs = ../../../../../examples/designer \ imagedirs = images -depends += qtdoc qtwidgets qtcore qtuitools qtquick qmake +depends += qtdoc qtgui qtwidgets qtcore qtuitools qtquick qmake navigation.landingpage = "Qt Designer Manual" navigation.cppclassespage = "Qt Designer C++ Classes" + +warninglimit = 0 diff --git a/src/designer/src/designer/doc/src/designer-manual.qdoc b/src/designer/src/designer/doc/src/designer-manual.qdoc index 99f45ecdd3..82f81d98b0 100644 --- a/src/designer/src/designer/doc/src/designer-manual.qdoc +++ b/src/designer/src/designer/doc/src/designer-manual.qdoc @@ -75,7 +75,8 @@ \li \l{Creating Main Windows in Qt Designer} \li \l{Editing Resources with Qt Designer} \li \l{Using Stylesheets with Qt Designer} - \li \l{Using a Designer UI File in Your Application} + \li \l{Using a Designer UI File in Your C++ Application} + \li \l{Using a Designer UI File in Your Qt for Python Application} \li Advanced Use \list \li \l{Customizing Qt Designer Forms} @@ -90,7 +91,6 @@ /*! \page designer-to-know.html - \contentspage {Qt Designer Manual}{Contents} \title Getting to Know Qt Designer @@ -258,7 +258,6 @@ /*! \page designer-quick-start.html - \contentspage {Qt Designer Manual}{Contents} \title A Quick Start to Qt Designer @@ -398,7 +397,6 @@ /*! \page designer-editing-mode.html \previouspage Getting to Know Qt Designer - \contentspage {Qt Designer Manual}{Contents} \nextpage Using Layouts in Qt Designer \title Qt Designer's Editing Modes @@ -447,7 +445,6 @@ /*! \page designer-widget-mode.html \previouspage Qt Designer's Editing Modes - \contentspage {Qt Designer Manual}{Contents} \nextpage Qt Designer's Signals and Slots Editing Mode \title Qt Designer's Widget Editing Mode @@ -687,7 +684,6 @@ /*! \page designer-layouts.html \previouspage Qt Designer's Widget Editing Mode - \contentspage \nextpage Qt Designer's Signals and Slots Editing Mode \title Using Layouts in Qt Designer @@ -890,7 +886,6 @@ /*! \page designer-preview.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Using Layouts in Qt Designer \nextpage Qt Designer's Buddy Editing Mode \title Saving, Previewing and Printing Forms in Qt Designer @@ -971,7 +966,6 @@ /*! \page designer-connection-mode.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Using Layouts in Qt Designer \nextpage Qt Designer's Buddy Editing Mode @@ -1105,7 +1099,6 @@ /*! \page designer-buddy-mode.html - \contentspage{Qt Designer Manual}{Contents} \previouspage Qt Designer's Signals and Slots Editing Mode \nextpage Qt Designer's Tab Order Editing Mode @@ -1159,7 +1152,6 @@ /*! \page designer-tab-order.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Qt Designer's Buddy Editing Mode \nextpage Using Containers in Qt Designer @@ -1208,7 +1200,6 @@ /*! \page designer-using-containers.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Qt Designer's Tab Order Editing Mode \nextpage Creating Main Windows in Qt Designer @@ -1346,7 +1337,6 @@ /*! \page designer-creating-mainwindows.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Using Containers in Qt Designer \nextpage Editing Resources with Qt Designer @@ -1565,11 +1555,9 @@ \section1 Dock Widgets - Since dock widgets are \l{Using Containers in Qt Designer} - {container widgets}, they can be added to a form in the usual way. Once - added to a form, dock widgets are not placed in any particular dock area by - default; you need to set the \gui{docked} property to true for each widget - and choose an appropriate value for its \gui{dockWidgetArea} property. + Dock widgets are \l{Using Containers in Qt Designer}{container widgets} + as well. They can be added to a form by dropping them onto the desired + dock area. \target AddingADockWidget @@ -1601,7 +1589,6 @@ /*! \page designer-resources.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Creating Main Windows in Qt Designer \nextpage Using Stylesheets with Qt Designer @@ -1706,9 +1693,8 @@ pixmap property in the property editor. /*! \page designer-stylesheet.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Editing Resources with Qt Designer - \nextpage Using a Designer UI File in Your Application + \nextpage Using a Designer UI File in Your C++ Application \title Using Stylesheets with Qt Designer @@ -1734,10 +1720,10 @@ pixmap property in the property editor. /*! \page designer-using-a-ui-file.html \previouspage Using Stylesheets with Qt Designer - \contentspage {Qt Designer Manual}{Contents} - \nextpage Using Custom Widgets with Qt Designer + \nextpage Using a Designer UI File in Your Qt for Python Application - \title Using a Designer UI File in Your Application + \keyword Using a Designer UI File in Your Application + \title Using a Designer UI File in Your C++ Application Qt Designer UI files represent the widget tree of the form in XML format. The forms can be processed: @@ -2125,11 +2111,96 @@ pixmap property in the property editor. write code themselves. */ +/*! + \page designer-using-a-ui-file-python.html + \previouspage Using a Designer UI File in Your C++ Application + \nextpage Using Custom Widgets with Qt Designer + + \title Using a Designer UI File in Your Qt for Python Application + + \section1 Converting the Form to Python Code + + To demonstrate, we use the Qt Widgets animation easing example. + + The application consists of one source file, \c easing.py, a UI + file \c form.ui, a resource file \c easing.qrc and the project + file, \c{easing.pyproject} file in the YAML format: + + \code + { + "files": ["easing.qrc", "ui_form.py", "easing.py", "easing_rc.py", + "form.ui"] + } + \endcode + + The UI file is converted to Python code building the form using the + \l{User Interface Compiler (uic)}: + + \code + uic -g python form.ui > ui_form.py + \endcode + + Since the top level widget is named \c Form, this results in a Python + class named \c Ui_Form being generated. It provides a function + \c setupUi(), taking the widget as parameter, which is called to + create the UI elements: + + \code + from ui_form import Ui_Form + ... + class Window(QtWidgets.QWidget): + def __init__(self, parent=None): + super(Window, self).__init__(parent) + + self.m_ui = Ui_Form() + self.m_ui.setupUi(self) + \endcode + + Later on, the widgets can be accessed via the \c Ui_Form class: + + \code + self.m_ui.graphicsView.setScene(self.m_scene) + \endcode + + Besides \c setupUi(), \c Ui_Form provides another method + \c retranslateUi(), which can be called in reaction to + a QEvent of type QEvent.LanguageChange, which indicates + a change in the application language. + + \section2 The UiTools Approach + + The QUiLoader class provides a form loader object to construct the user + interface at runtime. This user interface can be retrieved from any + QIODevice, e.g., a QFile object. The QUiLoader::load() function + constructs the form widget using the user interface description + contained in the file. + + It is demonstrated by the uiloader example: + + \code + from PySide2.QtUiTools import QUiLoader + + if __name__ == '__main__': + # Some code to obtain the form file name, ui_file_name + app = QApplication(sys.argv) + ui_file = QFile(ui_file_name) + if not ui_file.open(QIODevice.ReadOnly): + print("Cannot open {}: {}".format(ui_file_name, ui_file.errorString())) + sys.exit(-1) + loader = QUiLoader() + widget = loader.load(ui_file, None) + ui_file.close() + if not widget: + print(loader.errorString()) + sys.exit(-1) + widget.show() + sys.exit(app.exec_()) + \endcode +*/ /*! \page designer-customizing-forms.html - \contentspage {Qt Designer Manual}{Contents} - \previouspage Using Stylesheets with Qt Designer + \previouspage Using a Designer UI File in Your Qt for Python Application \nextpage Using Custom Widgets with Qt Designer \title Customizing Qt Designer Forms @@ -2141,7 +2212,7 @@ pixmap property in the property editor. default layout, are stored along with the form's components. These settings are used when the \l uic generates the form's C++ code. For more information on how to use forms in your application, see the - \l{Using a Designer UI File in Your Application} section. + \l{Using a Designer UI File in Your C++ Application} section. \section1 Modifying the Form Settings @@ -2185,7 +2256,6 @@ pixmap property in the property editor. /*! \page designer-using-custom-widgets.html - \contentspage {Qt Designer Manual}{Contents} \previouspage Customizing Qt Designer Forms \nextpage Creating Custom Widgets for Qt Designer @@ -2281,7 +2351,6 @@ pixmap property in the property editor. /*! \page designer-creating-custom-widgets.html \previouspage Using Custom Widgets with Qt Designer - \contentspage {Qt Designer Manual}{Contents} \nextpage Creating Custom Widget Extensions \title Creating Custom Widgets for Qt Designer @@ -2642,7 +2711,6 @@ pixmap property in the property editor. \page designer-creating-custom-widgets-extensions.html \previouspage Creating Custom Widgets for Qt Designer \nextpage Qt Designer's UI File Format - \contentspage {Qt Designer Manual}{Contents} \title Creating Custom Widget Extensions @@ -2812,7 +2880,6 @@ pixmap property in the property editor. /*! \page designer-ui-file-format.html \previouspage Creating Custom Widget Extensions - \contentspage {Qt Designer Manual}{Contents} \title Qt Designer's UI File Format diff --git a/src/designer/src/designer/doc/src/qtdesigner-module.qdoc b/src/designer/src/designer/doc/src/qtdesigner-module.qdoc index eaf816f42a..814c651957 100644 --- a/src/designer/src/designer/doc/src/qtdesigner-module.qdoc +++ b/src/designer/src/designer/doc/src/qtdesigner-module.qdoc @@ -29,6 +29,7 @@ \module QtDesigner \title Qt Designer C++ Classes \ingroup modules + \qtcmakepackage Designer \qtvariable designer \brief Provides classes to create your own custom widget plugins for @@ -46,3 +47,8 @@ \snippet plugins/doc_src_qtdesigner.pro 1 */ + +/*! + \namespace qdesigner_internal + \internal +*/ diff --git a/src/designer/src/designer/main.cpp b/src/designer/src/designer/main.cpp index e5e31ca16f..50c586ccc3 100644 --- a/src/designer/src/designer/main.cpp +++ b/src/designer/src/designer/main.cpp @@ -38,9 +38,6 @@ int main(int argc, char *argv[]) { Q_INIT_RESOURCE(designer); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - // required for QWebEngineView QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); diff --git a/src/designer/src/designer/mainwindow.cpp b/src/designer/src/designer/mainwindow.cpp index 3a1ae3ce9e..317deec8cb 100644 --- a/src/designer/src/designer/mainwindow.cpp +++ b/src/designer/src/designer/mainwindow.cpp @@ -37,8 +37,6 @@ #include -#include -#include #include #include #include @@ -46,6 +44,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -98,11 +100,11 @@ void MainWindowBase::closeEvent(QCloseEvent *e) } } -QVector MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar) +QList MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar) { // Note that whenever you want to add a new tool bar here, you also have to update the default // action groups added to the toolbar manager in the mainwindow constructor - QVector rc; + QList rc; if (singleToolBar) { //: Not currently used (main tool bar) QToolBar *main = createToolBar(tr("Main"), QStringLiteral("mainToolBar"), actions->fileActions()->actions()); @@ -150,12 +152,11 @@ QStringList DockedMdiArea::uiFiles(const QMimeData *d) const QStringList rc; if (!d->hasFormat(QLatin1String(uriListMimeFormatC))) return rc; - const QList urls = d->urls(); - if (urls.empty()) + const auto urls = d->urls(); + if (urls.isEmpty()) return rc; - const QList::const_iterator cend = urls.constEnd(); - for (QList::const_iterator it = urls.constBegin(); it != cend; ++it) { - const QString fileName = it->toLocalFile(); + for (const auto &url : urls) { + const QString fileName = url.toLocalFile(); if (!fileName.isEmpty() && fileName.endsWith(m_extension)) rc.push_back(fileName); } @@ -169,7 +170,7 @@ bool DockedMdiArea::event(QEvent *event) switch (event->type()) { case QEvent::DragEnter: { QDragEnterEvent *e = static_cast(event); - if (!uiFiles(e->mimeData()).empty()) { + if (!uiFiles(e->mimeData()).isEmpty()) { e->acceptProposedAction(); return true; } @@ -204,8 +205,8 @@ ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow, QWidget *parent, QMenu *toolBarMenu, const QDesignerActions *actions, - const QVector &toolbars, - const QVector &toolWindows) : + const QList &toolbars, + const QList &toolWindows) : QObject(parent), m_configureableMainWindow(configureableMainWindow), m_parent(parent), @@ -232,7 +233,7 @@ ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow, // Filter out the device profile preview actions which have int data(). ActionList previewActions = actions->styleActions()->actions(); ActionList::iterator it = previewActions.begin(); - for ( ; (*it)->isSeparator() || (*it)->data().type() == QVariant::Int; ++it) ; + for ( ; (*it)->isSeparator() || (*it)->data().metaType().id() == QMetaType::Int; ++it) ; previewActions.erase(previewActions.begin(), it); addActionsToToolBarManager(previewActions, tr("Style"), m_manager); @@ -292,13 +293,13 @@ bool ToolBarManager::restoreState(const QByteArray &state, int version) DockedMainWindow::DockedMainWindow(QDesignerWorkbench *wb, QMenu *toolBarMenu, - const QVector &toolWindows) : + const QList &toolWindows) : m_toolBarManager(nullptr) { setObjectName(QStringLiteral("MDIWindow")); setWindowTitle(mainWindowTitle()); - const QVector toolbars = createToolBars(wb->actionManager(), false); + const QList toolbars = createToolBars(wb->actionManager(), false); for (QToolBar *tb : toolbars) addToolBar(tb); DockedMdiArea *dma = new DockedMdiArea(wb->actionManager()->uiExtension()); @@ -338,7 +339,7 @@ QMdiSubWindow *DockedMainWindow::createMdiSubWindow(QWidget *fw, Qt::WindowFlags // designer menu actions if (designerCloseActionShortCut == QKeySequence(QKeySequence::Close)) { const ActionList systemMenuActions = rc->systemMenu()->actions(); - if (!systemMenuActions.empty()) { + if (!systemMenuActions.isEmpty()) { const ActionList::const_iterator cend = systemMenuActions.constEnd(); for (ActionList::const_iterator it = systemMenuActions.constBegin(); it != cend; ++it) { if ( (*it)->shortcut() == designerCloseActionShortCut) { diff --git a/src/designer/src/designer/mainwindow.h b/src/designer/src/designer/mainwindow.h index 3bbfbb7fd2..756afd2565 100644 --- a/src/designer/src/designer/mainwindow.h +++ b/src/designer/src/designer/mainwindow.h @@ -29,8 +29,9 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include + #include -#include #include QT_BEGIN_NAMESPACE @@ -70,7 +71,7 @@ class MainWindowBase: public QMainWindow CloseEventPolicy closeEventPolicy() const { return m_policy; } void setCloseEventPolicy(CloseEventPolicy pol) { m_policy = pol; } - static QVector createToolBars(const QDesignerActions *actions, bool singleToolBar); + static QList createToolBars(const QDesignerActions *actions, bool singleToolBar); static QString mainWindowTitle(); // Use the minor Qt version as settings versions to avoid conflicts @@ -98,7 +99,7 @@ class DockedMdiArea : public QMdiArea void fileDropped(const QString &); protected: - bool event (QEvent *event); + bool event (QEvent *event) override; private: QStringList uiFiles(const QMimeData *d) const; @@ -117,8 +118,8 @@ class ToolBarManager : public QObject QWidget *parent, QMenu *toolBarMenu, const QDesignerActions *actions, - const QVector &toolbars, - const QVector &toolWindows); + const QList &toolbars, + const QList &toolWindows); QByteArray saveState(int version = 0) const; bool restoreState(const QByteArray &state, int version = 0); @@ -133,7 +134,7 @@ private slots: QMenu *m_toolBarMenu; QtToolBarManager *m_manager; QAction *m_configureAction; - QVector m_toolbars; + QList m_toolbars; }; /* Main window to be used for docked mode */ @@ -141,8 +142,8 @@ class DockedMainWindow : public MainWindowBase { Q_OBJECT Q_DISABLE_COPY_MOVE(DockedMainWindow) public: - using DesignerToolWindowList = QVector; - using DockWidgetList = QVector; + using DesignerToolWindowList = QList; + using DockWidgetList = QList; explicit DockedMainWindow(QDesignerWorkbench *wb, QMenu *toolBarMenu, diff --git a/src/designer/src/designer/newform.cpp b/src/designer/src/designer/newform.cpp index 797e601499..eea8c78139 100644 --- a/src/designer/src/designer/newform.cpp +++ b/src/designer/src/designer/newform.cpp @@ -36,12 +36,6 @@ #include -#include -#include -#include -#include -#include - #include #include #include @@ -51,6 +45,15 @@ #include #include +#include +#include + +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE NewForm::NewForm(QDesignerWorkbench *workbench, QWidget *parentWidget, const QString &fileName) @@ -103,13 +106,10 @@ QDialogButtonBox *NewForm::createButtonBox() QDesignerActions *da = m_workbench->actionManager(); QMenu *recentFilesMenu = new QMenu(tr("&Recent Forms"), m_recentButton); // Pop the "Recent Files" stuff in here. - const QList recentActions = da->recentFilesActions()->actions(); - if (!recentActions.empty()) { - const QList::const_iterator acend = recentActions.constEnd(); - for (QList::const_iterator it = recentActions.constBegin(); it != acend; ++it) { - recentFilesMenu->addAction(*it); - connect(*it, &QAction::triggered, this, &NewForm::recentFileChosen); - } + const auto recentActions = da->recentFilesActions()->actions(); + for (auto action : recentActions) { + recentFilesMenu->addAction(action); + connect(action, &QAction::triggered, this, &NewForm::recentFileChosen); } m_recentButton->setMenu(recentFilesMenu); connect(buttonBox, &QDialogButtonBox::clicked, this, &NewForm::slotButtonBoxClicked); @@ -144,7 +144,7 @@ void NewForm::slotCurrentTemplateChanged(bool templateSelected) void NewForm::slotTemplateActivated() { - m_createButton->animateClick(0); + m_createButton->animateClick(); } void NewForm::slotButtonBoxClicked(QAbstractButton *btn) diff --git a/src/designer/src/designer/qdesigner.cpp b/src/designer/src/designer/qdesigner.cpp index ff244ec29c..ed88039fb8 100644 --- a/src/designer/src/designer/qdesigner.cpp +++ b/src/designer/src/designer/qdesigner.cpp @@ -68,7 +68,7 @@ static void designerMessageHandler(QtMsgType type, const QMessageLogContext &con previousMessageHandler(type, context, msg); return; } - designerApp->showErrorMessage(qPrintable(msg)); + designerApp->showErrorMessage(msg); } QDesigner::QDesigner(int &argc, char **argv) @@ -94,10 +94,11 @@ QDesigner::~QDesigner() delete m_client; } -void QDesigner::showErrorMessage(const char *message) +void QDesigner::showErrorMessage(const QString &message) { // strip the prefix - const QString qMessage = QString::fromUtf8(message + qstrlen(designerWarningPrefix)); + const QString qMessage = + message.right(message.size() - int(qstrlen(designerWarningPrefix))); // If there is no main window yet, just store the message. // The QErrorMessage would otherwise be hidden by the main window. if (m_mainWindow) { @@ -159,7 +160,7 @@ static void showHelp(QCommandLineParser &parser, const QString &errorMessage = Q struct Options { QStringList files; - QString resourceDir{QLibraryInfo::location(QLibraryInfo::TranslationsPath)}; + QString resourceDir{QLibraryInfo::path(QLibraryInfo::TranslationsPath)}; bool server{false}; quint16 clientPort{0}; bool enableInternalDynamicProperties{false}; @@ -188,6 +189,7 @@ static inline QDesigner::ParseArgumentsResult const QCommandLineOption internalDynamicPropertyOption(QStringLiteral("enableinternaldynamicproperties"), QStringLiteral("Enable internal dynamic properties")); parser.addOption(internalDynamicPropertyOption); + parser.addPositionalArgument(QStringLiteral("files"), QStringLiteral("The UI files to open.")); @@ -235,13 +237,12 @@ QDesigner::ParseArgumentsResult QDesigner::parseCommandLineArguments() if (options.enableInternalDynamicProperties) QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(true); - const QString localSysName = QLocale::system().name(); - QScopedPointer designerTranslator(new QTranslator(this)); - if (designerTranslator->load(QStringLiteral("designer_") + localSysName, options.resourceDir)) { - installTranslator(designerTranslator.take()); - QScopedPointer qtTranslator(new QTranslator(this)); - if (qtTranslator->load(QStringLiteral("qt_") + localSysName, options.resourceDir)) - installTranslator(qtTranslator.take()); + std::unique_ptr designerTranslator(new QTranslator(this)); + if (designerTranslator->load(QLocale(), QStringLiteral("designer"), QStringLiteral("_"), options.resourceDir)) { + installTranslator(designerTranslator.release()); + std::unique_ptr qtTranslator(new QTranslator(this)); + if (qtTranslator->load(QLocale(), QStringLiteral("qt"), QStringLiteral("_"), options.resourceDir)) + installTranslator(qtTranslator.release()); } m_workbench = new QDesignerWorkbench(); @@ -252,7 +253,7 @@ QDesigner::ParseArgumentsResult QDesigner::parseCommandLineArguments() m_suppressNewFormShow = m_workbench->readInBackup(); - if (!options.files.empty()) { + if (!options.files.isEmpty()) { const QStringList::const_iterator cend = options.files.constEnd(); for (QStringList::const_iterator it = options.files.constBegin(); it != cend; ++it) { // Ensure absolute paths for recent file list to be unique diff --git a/src/designer/src/designer/qdesigner.h b/src/designer/src/designer/qdesigner.h index 7d58db26b9..91f36c5381 100644 --- a/src/designer/src/designer/qdesigner.h +++ b/src/designer/src/designer/qdesigner.h @@ -73,7 +73,7 @@ class QDesigner: public QApplication void initialized(); public slots: - void showErrorMessage(const char *message); + void showErrorMessage(const QString &message); private slots: void callCreateForm(); diff --git a/src/designer/src/designer/qdesigner_actions.cpp b/src/designer/src/designer/qdesigner_actions.cpp index 970599f14a..4b98d6493e 100644 --- a/src/designer/src/designer/qdesigner_actions.cpp +++ b/src/designer/src/designer/qdesigner_actions.cpp @@ -60,18 +60,21 @@ #include #include -#include -#include #include #include #include #include #include #include +#include + +#include +#include #include #include #include #include +#include #if defined(QT_PRINTSUPPORT_LIB) // Some platforms may not build QtPrintSupport # include # if QT_CONFIG(printer) && QT_CONFIG(printdialog) @@ -83,8 +86,8 @@ #include #include #include -#include +#include #include #include #include @@ -92,8 +95,8 @@ #include #include #include -#include -#include +#include +#include #include QT_BEGIN_NAMESPACE @@ -129,36 +132,18 @@ static inline QString savedMessage(const QString &fileName) return QDesignerActions::tr("Saved %1.").arg(fileName); } -// Prompt for a file and make sure an extension is added -// unless the user explicitly specifies another one. - -static QString getSaveFileNameWithExtension(QWidget *parent, const QString &title, QString dir, const QString &filter, const QString &extension) +static QString fileDialogFilters(const QString &extension) { - const QChar dot = QLatin1Char('.'); - - QString saveFile; - while (true) { - saveFile = QFileDialog::getSaveFileName(parent, title, dir, filter, nullptr, QFileDialog::DontConfirmOverwrite); - if (saveFile.isEmpty()) - return saveFile; - - const QFileInfo fInfo(saveFile); - if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) { - saveFile += dot; - saveFile += extension; - } - - const QFileInfo fi(saveFile); - if (!fi.exists()) - break; - - const QString prompt = QDesignerActions::tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()); - if (QMessageBox::warning(parent, title, prompt, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) - break; + return QDesignerActions::tr("Designer UI files (*.%1);;All Files (*)").arg(extension); +} - dir = saveFile; - } - return saveFile; +QFileDialog *createSaveAsDialog(QWidget *parent, const QString &dir, const QString &extension) +{ + auto result = new QFileDialog(parent, QDesignerActions::tr("Save Form As"), + dir, fileDialogFilters(extension)); + result->setAcceptMode(QFileDialog::AcceptSave); + result->setDefaultSuffix(extension); + return result; } QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) @@ -311,9 +296,11 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) m_editActions->addAction(createSeparator(this)); +#if QT_CONFIG(clipboard) m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::CutAction)); m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::CopyAction)); m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::PasteAction)); +#endif m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::DeleteAction)); m_editActions->addAction(formWindowManager->action(QDesignerFormWindowManagerInterface::SelectAllAction)); @@ -336,7 +323,8 @@ QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) shortcuts.append(QKeySequence(Qt::Key_Escape)); m_editWidgetsAction->setShortcuts(shortcuts); QIcon fallback(m_core->resourceLocation() + QStringLiteral("/widgettool.png")); - m_editWidgetsAction->setIcon(QIcon::fromTheme("designer-edit-widget", fallback)); + m_editWidgetsAction->setIcon(QIcon::fromTheme(QStringLiteral("designer-edit-widget"), + fallback)); connect(m_editWidgetsAction, &QAction::triggered, this, &QDesignerActions::editWidgetsSlot); m_editWidgetsAction->setChecked(true); m_editWidgetsAction->setEnabled(false); @@ -456,7 +444,7 @@ QActionGroup *QDesignerActions::createHelpActions() QAction *mainHelpAction = new QAction(tr("Qt Designer &Help"), this); mainHelpAction->setObjectName(QStringLiteral("__qt_designer_help_action")); connect(mainHelpAction, &QAction::triggered, this, &QDesignerActions::showDesignerHelp); - mainHelpAction->setShortcut(Qt::CTRL + Qt::Key_Question); + mainHelpAction->setShortcut(Qt::CTRL | Qt::Key_Question); helpActions->addAction(mainHelpAction); helpActions->addAction(createSeparator(this)); @@ -520,13 +508,15 @@ QAction *QDesignerActions::createRecentFilesMenu() } updateRecentFileActions(); menu->addSeparator(); - act = new QAction(QIcon::fromTheme("edit-clear"), tr("Clear &Menu"), this); + act = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear")), + tr("Clear &Menu"), this); act->setObjectName(QStringLiteral("__qt_action_clear_menu_")); connect(act, &QAction::triggered, this, &QDesignerActions::clearRecentFiles); m_recentFilesActions->addAction(act); menu->addAction(act); - act = new QAction(QIcon::fromTheme("document-open-recent"), tr("&Recent Forms"), this); + act = new QAction(QIcon::fromTheme(QStringLiteral("document-open-recent")), + tr("&Recent Forms"), this); act->setMenu(menu); return act; } @@ -604,7 +594,7 @@ bool QDesignerActions::openForm(QWidget *parent) closePreview(); const QString extension = uiExtension(); const QStringList fileNames = QFileDialog::getOpenFileNames(parent, tr("Open Form"), - m_openDirectory, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), nullptr); + m_openDirectory, fileDialogFilters(extension), nullptr); if (fileNames.isEmpty()) return false; @@ -641,10 +631,13 @@ bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw) dir += extension; } - const QString saveFile = getSaveFileNameWithExtension(fw, tr("Save Form As"), dir, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), extension); - if (saveFile.isEmpty()) + QScopedPointer saveAsDialog(createSaveAsDialog(fw, dir, extension)); + if (saveAsDialog->exec() != QDialog::Accepted) return false; + const QString saveFile = saveAsDialog->selectedFiles().constFirst(); + saveAsDialog.reset(); // writeOutForm potentially shows other dialogs + fw->setFileName(saveFile); return writeOutForm(fw, saveFile); } @@ -786,7 +779,7 @@ bool QDesignerActions::readInForm(const QString &fileName) const QString extension = uiExtension(); fn = QFileDialog::getOpenFileName(core()->topLevel(), tr("Open Form"), m_openDirectory, - tr("Designer UI files (*.%1);;All Files (*)").arg(extension), nullptr); + fileDialogFilters(extension), nullptr); if (fn.isEmpty()) return false; @@ -812,37 +805,10 @@ bool QDesignerActions::readInForm(const QString &fileName) return true; } -static QString createBackup(const QString &fileName) -{ - const QString suffix = QStringLiteral(".bak"); - QString backupFile = fileName + suffix; - QFileInfo fi(backupFile); - int i = 0; - while (fi.exists()) { - backupFile = fileName + suffix + QString::number(++i); - fi.setFile(backupFile); - } - - if (QFile::copy(fileName, backupFile)) - return backupFile; - return QString(); -} - -static void removeBackup(const QString &backupFile) -{ - if (!backupFile.isEmpty()) - QFile::remove(backupFile); -} - bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile, bool check) { Q_ASSERT(fw && !saveFile.isEmpty()); - QString backupFile; - QFileInfo fi(saveFile); - if (fi.exists()) - backupFile = createBackup(saveFile); - if (check) { const QStringList problems = fw->checkContents(); if (!problems.isEmpty()) @@ -854,10 +820,9 @@ bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QStr if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator) contents.replace(QLatin1Char('\n'), QStringLiteral("\r\n")); } - const QByteArray utf8Array = contents.toUtf8(); m_workbench->updateBackup(fw); - QFile f(saveFile); + QSaveFile f(saveFile); while (!f.open(QFile::WriteOnly)) { QMessageBox box(QMessageBox::Warning, tr("Save Form?"), @@ -875,52 +840,33 @@ bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QStr QPushButton *cancelButton = box.addButton(QMessageBox::Cancel); box.exec(); - if (box.clickedButton() == cancelButton) { - removeBackup(backupFile); + if (box.clickedButton() == cancelButton) return false; - } if (box.clickedButton() == switchButton) { - QString extension = uiExtension(); - const QString fileName = QFileDialog::getSaveFileName(fw, tr("Save Form As"), - QDir::current().absolutePath(), - QStringLiteral("*.") + extension); - if (fileName.isEmpty()) { - removeBackup(backupFile); + QScopedPointer saveAsDialog(createSaveAsDialog(fw, QDir::currentPath(), uiExtension())); + if (saveAsDialog->exec() != QDialog::Accepted) return false; - } - if (f.fileName() != fileName) { - removeBackup(backupFile); - fi.setFile(fileName); - backupFile.clear(); - if (fi.exists()) - backupFile = createBackup(fileName); - } + + const QString fileName = saveAsDialog->selectedFiles().constFirst(); f.setFileName(fileName); fw->setFileName(fileName); } // loop back around... } - while (f.write(utf8Array, utf8Array.size()) != utf8Array.size()) { - QMessageBox box(QMessageBox::Warning, tr("Save Form?"), + f.write(contents.toUtf8()); + if (!f.commit()) { + QMessageBox box(QMessageBox::Warning, tr("Save Form"), tr("Could not write file"), - QMessageBox::Retry|QMessageBox::Cancel, fw); + QMessageBox::Cancel, fw); box.setWindowModality(Qt::WindowModal); - box.setInformativeText(tr("It was not possible to write the entire file %1 to disk." - "\nReason:%2\nWould you like to retry?") + box.setInformativeText(tr("It was not possible to write the file %1 to disk." + "\nReason: %2") .arg(f.fileName(), f.errorString())); - box.setDefaultButton(QMessageBox::Retry); - switch (box.exec()) { - case QMessageBox::Retry: - f.resize(0); - break; - default: - return false; - } + box.exec(); + return false; } - f.close(); - removeBackup(backupFile); addRecentFile(saveFile); - m_saveDirectory = QFileInfo(f).absolutePath(); + m_saveDirectory = QFileInfo(f.fileName()).absolutePath(); fw->setDirty(false); fw->parentWidget()->setWindowModified(false); @@ -967,7 +913,7 @@ void QDesignerActions::updateRecentFileActions() QStringList files = m_settings.recentFilesList(); const int originalSize = files.size(); int numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); - const QList recentFilesActs = m_recentFilesActions->actions(); + const auto recentFilesActs = m_recentFilesActions->actions(); for (int i = 0; i < numRecentFiles; ++i) { const QFileInfo fi(files[i]); @@ -1197,7 +1143,7 @@ QString QDesignerActions::fixResourceFileBackupPath(QDesignerFormWindowInterface QRect QDesignerActions::fixDialogRect(const QRect &rect) const { QRect frameGeometry; - const QRect availableGeometry = QApplication::desktop()->availableGeometry(core()->topLevel()); + const QRect availableGeometry = core()->topLevel()->screen()->geometry(); if (workbench()->mode() == DockedMode) { frameGeometry = core()->topLevel()->frameGeometry(); @@ -1330,10 +1276,15 @@ void QDesignerActions::savePreviewImage() suggestion += QLatin1Char('.'); suggestion += extension; } + + QFileDialog dialog(fw, tr("Save Image"), suggestion, filter); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setDefaultSuffix(extension); + do { - const QString fileName = getSaveFileNameWithExtension(fw, tr("Save Image"), suggestion, filter, extension); - if (fileName.isEmpty()) + if (dialog.exec() != QDialog::Accepted) break; + const QString fileName = dialog.selectedFiles().constFirst(); if (image.isNull()) { const QPixmap pixmap = createPreviewPixmap(fw); @@ -1385,7 +1336,9 @@ void QDesignerActions::printPreviewImage() return; const QSizeF pixmapSize = pixmap.size(); - m_printer->setOrientation( pixmapSize.width() > pixmapSize.height() ? QPrinter::Landscape : QPrinter::Portrait); + + m_printer->setPageOrientation(pixmapSize.width() > pixmapSize.height() ? + QPageLayout::Landscape : QPageLayout::Portrait); // Printer parameters QPrintDialog dialog(m_printer, fw); diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.cpp b/src/designer/src/designer/qdesigner_appearanceoptions.cpp index 66eb49c9f9..2c44377777 100644 --- a/src/designer/src/designer/qdesigner_appearanceoptions.cpp +++ b/src/designer/src/designer/qdesigner_appearanceoptions.cpp @@ -65,7 +65,7 @@ QDesignerAppearanceOptionsWidget::QDesignerAppearanceOptionsWidget(QWidget *pare m_ui->m_uiModeCombo->addItem(tr("Docked Window"), QVariant(DockedMode)); m_ui->m_uiModeCombo->addItem(tr("Multiple Top-Level Windows"), QVariant(TopLevelMode)); - connect(m_ui->m_uiModeCombo, QOverload::of(&QComboBox::currentIndexChanged), + connect(m_ui->m_uiModeCombo, &QComboBox::currentIndexChanged, this, &QDesignerAppearanceOptionsWidget::slotUiModeComboChanged); m_ui->m_fontPanel->setCheckable(true); diff --git a/src/designer/src/designer/qdesigner_formwindow.cpp b/src/designer/src/designer/qdesigner_formwindow.cpp index 77223e416d..4ac1044501 100644 --- a/src/designer/src/designer/qdesigner_formwindow.cpp +++ b/src/designer/src/designer/qdesigner_formwindow.cpp @@ -39,17 +39,18 @@ #include #include -#include -#include - -#include #include #include #include #include -#include +#include #include +#include + +#include +#include + QT_BEGIN_NAMESPACE QDesignerFormWindow::QDesignerFormWindow(QDesignerFormWindowInterface *editor, QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags) @@ -173,7 +174,7 @@ int QDesignerFormWindow::getNumberOfUntitledWindows() const if (maxUntitled == 0) ++maxUntitled; if (match.lastCapturedIndex() >= 2) { - const QStringRef numberCapture = match.capturedRef(2); + const auto numberCapture = match.capturedView(2); if (!numberCapture.isEmpty()) maxUntitled = qMax(numberCapture.toInt(), maxUntitled); } diff --git a/src/designer/src/designer/qdesigner_settings.cpp b/src/designer/src/designer/qdesigner_settings.cpp index 8ac61c52af..e8ac4be543 100644 --- a/src/designer/src/designer/qdesigner_settings.cpp +++ b/src/designer/src/designer/qdesigner_settings.cpp @@ -40,7 +40,6 @@ #include #include -#include #include #include diff --git a/src/designer/src/designer/qdesigner_toolwindow.cpp b/src/designer/src/designer/qdesigner_toolwindow.cpp index e71edcb0c1..2a003bb25b 100644 --- a/src/designer/src/designer/qdesigner_toolwindow.cpp +++ b/src/designer/src/designer/qdesigner_toolwindow.cpp @@ -38,10 +38,11 @@ #include #include -#include -#include +#include #include +#include + enum { debugToolWindow = 0 }; QT_BEGIN_NAMESPACE @@ -171,7 +172,7 @@ PropertyEditorToolWindow::PropertyEditorToolWindow(QDesignerWorkbench *workbench QStringLiteral("__qt_property_editor_action"), Qt::RightDockWidgetArea) { - action()->setShortcut(Qt::CTRL + Qt::Key_I); + action()->setShortcut(Qt::CTRL | Qt::Key_I); } diff --git a/src/designer/src/designer/qdesigner_workbench.cpp b/src/designer/src/designer/qdesigner_workbench.cpp index f2a8b5d1cb..f94aa98bde 100644 --- a/src/designer/src/designer/qdesigner_workbench.cpp +++ b/src/designer/src/designer/qdesigner_workbench.cpp @@ -48,17 +48,6 @@ #include #include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include #include #include #include @@ -69,6 +58,17 @@ #include #include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE static const char *appFontPrefixC = "AppFonts"; @@ -236,7 +236,7 @@ QDesignerWorkbench::QDesignerWorkbench() : { // Add application specific options pages QDesignerAppearanceOptionsPage *appearanceOptions = new QDesignerAppearanceOptionsPage(m_core); connect(appearanceOptions, &QDesignerAppearanceOptionsPage::settingsChanged, this, &QDesignerWorkbench::notifyUISettingsChanged); - QList optionsPages = m_core->optionsPages(); + auto optionsPages = m_core->optionsPages(); optionsPages.push_front(appearanceOptions); m_core->setOptionsPages(optionsPages); } @@ -330,7 +330,7 @@ Qt::WindowFlags QDesignerWorkbench::magicalWindowFlags(const QWidget *widgetForF return Qt::Window; default: Q_ASSERT(0); - return nullptr; + return {}; } } @@ -569,9 +569,9 @@ QRect QDesignerWorkbench::desktopGeometry() const case NeutralMode: break; } - const int screenNumber = widget ? QApplication::desktop()->screenNumber(widget) : 0; - auto screen = QGuiApplication::screens().value(screenNumber, QGuiApplication::primaryScreen()); - return screen->availableGeometry(); + const auto screen = widget ? widget->screen() : QGuiApplication::primaryScreen(); + return screen ? screen->availableGeometry() + : QGuiApplication::primaryScreen()->availableGeometry(); } QRect QDesignerWorkbench::availableGeometry() const @@ -579,9 +579,8 @@ QRect QDesignerWorkbench::availableGeometry() const if (m_mode == DockedMode) return m_dockedMainWindow->mdiArea()->geometry(); - const int screenNumber = QApplication::desktop()->screenNumber(widgetBoxToolWindow()); - auto screen = QGuiApplication::screens().value(screenNumber, QGuiApplication::primaryScreen()); - return screen->availableGeometry(); + const auto screen = widgetBoxToolWindow()->screen(); + return screen ? screen->availableGeometry() : QGuiApplication::primaryScreen()->availableGeometry() ; } int QDesignerWorkbench::marginHint() const @@ -608,7 +607,7 @@ void QDesignerWorkbench::removeFormWindow(QDesignerFormWindow *formWindow) m_windowMenu->removeAction(action); } - if (m_formWindows.empty()) { + if (m_formWindows.isEmpty()) { m_actionManager->setWindowListSeparatorVisible(false); // Show up new form dialog unless closing if (loadOk && m_state == StateUp @@ -1079,7 +1078,7 @@ void QDesignerWorkbench::restoreUISettings() ToolWindowFontSettings fontSettings = QDesignerSettings(m_core).toolWindowFont(); const QFont &font = fontSettings.m_useFont ? fontSettings.m_font : qApp->font(); - if (font == m_toolWindows.front()->font()) + if (font == m_toolWindows.constFirst()->font()) return; for (QDesignerToolWindow *tw : qAsConst(m_toolWindows)) diff --git a/src/designer/src/designer/qdesigner_workbench.h b/src/designer/src/designer/qdesigner_workbench.h index fea02d59f1..e3435b9152 100644 --- a/src/designer/src/designer/qdesigner_workbench.h +++ b/src/designer/src/designer/qdesigner_workbench.h @@ -33,9 +33,9 @@ #include #include +#include #include #include -#include QT_BEGIN_NAMESPACE @@ -158,15 +158,15 @@ private slots: struct TopLevelData { ToolBarManager *toolbarManager; - QVector toolbars; + QList toolbars; }; TopLevelData m_topLevelData; UIMode m_mode = NeutralMode; DockedMainWindow *m_dockedMainWindow = nullptr; - QVector m_toolWindows; - QVector m_formWindows; + QList m_toolWindows; + QList m_formWindows; QMenu *m_toolbarMenu; diff --git a/src/designer/src/designer/saveformastemplate.cpp b/src/designer/src/designer/saveformastemplate.cpp index 4b338308e5..15930aa639 100644 --- a/src/designer/src/designer/saveformastemplate.cpp +++ b/src/designer/src/designer/saveformastemplate.cpp @@ -60,7 +60,7 @@ SaveFormAsTemplate::SaveFormAsTemplate(QDesignerFormEditorInterface *core, m_addPathIndex = ui.categoryCombo->count() - 1; connect(ui.templateNameEdit, &QLineEdit::textChanged, this, &SaveFormAsTemplate::updateOKButton); - connect(ui.categoryCombo, QOverload::of(&QComboBox::activated), + connect(ui.categoryCombo, &QComboBox::activated, this, &SaveFormAsTemplate::checkToAddPath); } diff --git a/src/designer/src/designer/versiondialog.cpp b/src/designer/src/designer/versiondialog.cpp index 767d251718..d5df285639 100644 --- a/src/designer/src/designer/versiondialog.cpp +++ b/src/designer/src/designer/versiondialog.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. @@ -26,15 +26,18 @@ ** ****************************************************************************/ -#include +#include + #include +#include +#include + +#include #include #include #include -#include -#include -#include #include + #include "versiondialog.h" QT_BEGIN_NAMESPACE @@ -54,8 +57,8 @@ class VersionLabel : public QLabel void mouseReleaseEvent(QMouseEvent *me) override; void paintEvent(QPaintEvent *pe) override; private: - QVector hitPoints; - QVector missPoints; + QList hitPoints; + QList missPoints; QPainterPath m_path; bool secondStage = false; bool m_pushed = false; @@ -132,7 +135,7 @@ void VersionLabel::paintEvent(QPaintEvent *pe) if (secondStage) { QPainter p(this); QStyleOptionButton opt; - opt.init(this); + opt.initFrom(this); if (!m_pushed) opt.state |= QStyle::State_Raised; else @@ -160,7 +163,7 @@ VersionDialog::VersionDialog(QWidget *parent) lbl->setText(tr("%1" "
Copyright (C) %2 The Qt Company Ltd." - ).arg(version, QStringLiteral("2019"))); + ).arg(version, QStringLiteral("2021"))); lbl->setWordWrap(true); lbl->setOpenExternalLinks(true); diff --git a/src/designer/src/lib/CMakeLists.txt b/src/designer/src/lib/CMakeLists.txt new file mode 100644 index 0000000000..d64b399988 --- /dev/null +++ b/src/designer/src/lib/CMakeLists.txt @@ -0,0 +1,422 @@ +# Generated from lib.pro. + +##################################################################### +## Designer Module: +##################################################################### + +qt_internal_add_module(Designer + PLUGIN_TYPES designer + SOURCES + ../../../shared/deviceskin/deviceskin.cpp ../../../shared/deviceskin/deviceskin.h + ../../../shared/findwidget/abstractfindwidget.cpp ../../../shared/findwidget/abstractfindwidget.h + ../../../shared/findwidget/itemviewfindwidget.cpp ../../../shared/findwidget/itemviewfindwidget.h + ../../../shared/findwidget/texteditfindwidget.cpp ../../../shared/findwidget/texteditfindwidget.h + ../../../shared/qtgradienteditor/qtcolorbutton.cpp ../../../shared/qtgradienteditor/qtcolorbutton.h + ../../../shared/qtgradienteditor/qtcolorline.cpp ../../../shared/qtgradienteditor/qtcolorline.h + ../../../shared/qtgradienteditor/qtgradientdialog.cpp ../../../shared/qtgradienteditor/qtgradientdialog.h ../../../shared/qtgradienteditor/qtgradientdialog.ui + ../../../shared/qtgradienteditor/qtgradienteditor.cpp ../../../shared/qtgradienteditor/qtgradienteditor.h ../../../shared/qtgradienteditor/qtgradienteditor.ui + ../../../shared/qtgradienteditor/qtgradientmanager.cpp ../../../shared/qtgradienteditor/qtgradientmanager.h + ../../../shared/qtgradienteditor/qtgradientstopscontroller.cpp ../../../shared/qtgradienteditor/qtgradientstopscontroller.h + ../../../shared/qtgradienteditor/qtgradientstopsmodel.cpp ../../../shared/qtgradienteditor/qtgradientstopsmodel.h + ../../../shared/qtgradienteditor/qtgradientstopswidget.cpp ../../../shared/qtgradienteditor/qtgradientstopswidget.h + ../../../shared/qtgradienteditor/qtgradientutils.cpp ../../../shared/qtgradienteditor/qtgradientutils.h + ../../../shared/qtgradienteditor/qtgradientview.cpp ../../../shared/qtgradienteditor/qtgradientview.h ../../../shared/qtgradienteditor/qtgradientview.ui + ../../../shared/qtgradienteditor/qtgradientviewdialog.cpp ../../../shared/qtgradienteditor/qtgradientviewdialog.h ../../../shared/qtgradienteditor/qtgradientviewdialog.ui + ../../../shared/qtgradienteditor/qtgradientwidget.cpp ../../../shared/qtgradienteditor/qtgradientwidget.h + extension/default_extensionfactory.cpp extension/default_extensionfactory.h + extension/extension.cpp extension/extension.h + extension/qextensionmanager.cpp extension/qextensionmanager.h + sdk/abstractactioneditor.cpp sdk/abstractactioneditor.h + sdk/abstractdialoggui.cpp sdk/abstractdialoggui_p.h + sdk/abstractdnditem.h + sdk/abstractformeditor.cpp sdk/abstractformeditor.h + sdk/abstractformeditorplugin.cpp sdk/abstractformeditorplugin.h + sdk/abstractformwindow.cpp sdk/abstractformwindow.h + sdk/abstractformwindowcursor.cpp sdk/abstractformwindowcursor.h + sdk/abstractformwindowmanager.cpp sdk/abstractformwindowmanager.h + sdk/abstractformwindowtool.cpp sdk/abstractformwindowtool.h + sdk/abstractintegration.cpp sdk/abstractintegration.h + sdk/abstractintrospection.cpp sdk/abstractintrospection_p.h + sdk/abstractlanguage.h + sdk/abstractmetadatabase.cpp sdk/abstractmetadatabase.h + sdk/abstractnewformwidget.cpp sdk/abstractnewformwidget.h + sdk/abstractobjectinspector.cpp sdk/abstractobjectinspector.h + sdk/abstractoptionspage.h + sdk/abstractpromotioninterface.cpp sdk/abstractpromotioninterface.h + sdk/abstractpropertyeditor.cpp sdk/abstractpropertyeditor.h + sdk/abstractresourcebrowser.cpp sdk/abstractresourcebrowser.h + sdk/abstractsettings.h + sdk/abstractwidgetbox.cpp sdk/abstractwidgetbox.h + sdk/abstractwidgetdatabase.cpp sdk/abstractwidgetdatabase.h + sdk/abstractwidgetfactory.cpp sdk/abstractwidgetfactory.h + sdk/container.h + sdk/dynamicpropertysheet.h + sdk/extrainfo.cpp sdk/extrainfo.h + sdk/layoutdecoration.h + sdk/membersheet.h + sdk/propertysheet.h + sdk/taskmenu.h + shared/actioneditor.cpp shared/actioneditor_p.h + shared/actionprovider_p.h + shared/actionrepository.cpp shared/actionrepository_p.h + shared/addlinkdialog.ui + shared/codedialog.cpp shared/codedialog_p.h + shared/connectionedit.cpp shared/connectionedit_p.h + shared/csshighlighter.cpp shared/csshighlighter_p.h + shared/deviceprofile.cpp shared/deviceprofile_p.h + shared/dialoggui.cpp shared/dialoggui_p.h + shared/extensionfactory_p.h + shared/formlayoutmenu.cpp shared/formlayoutmenu_p.h + shared/formlayoutrowdialog.ui + shared/formwindowbase.cpp shared/formwindowbase_p.h + shared/grid.cpp shared/grid_p.h + shared/gridpanel.cpp shared/gridpanel.ui shared/gridpanel_p.h + shared/htmlhighlighter.cpp shared/htmlhighlighter_p.h + shared/iconloader.cpp shared/iconloader_p.h + shared/iconselector.cpp shared/iconselector_p.h + shared/invisible_widget.cpp shared/invisible_widget_p.h + shared/layout.cpp shared/layout_p.h + shared/layoutinfo.cpp shared/layoutinfo_p.h + shared/metadatabase.cpp shared/metadatabase_p.h + shared/morphmenu.cpp shared/morphmenu_p.h + shared/newactiondialog.cpp shared/newactiondialog.ui shared/newactiondialog_p.h + shared/newformwidget.cpp shared/newformwidget.ui shared/newformwidget_p.h + shared/orderdialog.cpp shared/orderdialog.ui shared/orderdialog_p.h + shared/plaintexteditor.cpp shared/plaintexteditor_p.h + shared/plugindialog.cpp shared/plugindialog.ui shared/plugindialog_p.h + shared/pluginmanager.cpp shared/pluginmanager_p.h + shared/previewconfigurationwidget.cpp shared/previewconfigurationwidget.ui shared/previewconfigurationwidget_p.h + shared/previewmanager.cpp shared/previewmanager_p.h + shared/promotionmodel.cpp shared/promotionmodel_p.h + shared/promotiontaskmenu.cpp shared/promotiontaskmenu_p.h + shared/propertylineedit.cpp shared/propertylineedit_p.h + shared/qdesigner_command.cpp shared/qdesigner_command_p.h + shared/qdesigner_command2.cpp shared/qdesigner_command2_p.h + shared/qdesigner_dnditem.cpp shared/qdesigner_dnditem_p.h + shared/qdesigner_dockwidget.cpp shared/qdesigner_dockwidget_p.h + shared/qdesigner_formbuilder.cpp shared/qdesigner_formbuilder_p.h + shared/qdesigner_formeditorcommand.cpp shared/qdesigner_formeditorcommand_p.h + shared/qdesigner_formwindowcommand.cpp shared/qdesigner_formwindowcommand_p.h + shared/qdesigner_formwindowmanager.cpp shared/qdesigner_formwindowmanager_p.h + shared/qdesigner_introspection.cpp shared/qdesigner_introspection_p.h + shared/qdesigner_membersheet.cpp shared/qdesigner_membersheet_p.h + shared/qdesigner_menu.cpp shared/qdesigner_menu_p.h + shared/qdesigner_menubar.cpp shared/qdesigner_menubar_p.h + shared/qdesigner_objectinspector.cpp shared/qdesigner_objectinspector_p.h + shared/qdesigner_promotion.cpp shared/qdesigner_promotion_p.h + shared/qdesigner_promotiondialog.cpp shared/qdesigner_promotiondialog_p.h + shared/qdesigner_propertycommand.cpp + shared/qdesigner_propertyeditor.cpp shared/qdesigner_propertyeditor_p.h + shared/qdesigner_propertysheet.cpp shared/qdesigner_propertysheet_p.h + shared/qdesigner_qsettings.cpp shared/qdesigner_qsettings_p.h + shared/qdesigner_stackedbox.cpp shared/qdesigner_stackedbox_p.h + shared/qdesigner_tabwidget.cpp shared/qdesigner_tabwidget_p.h + shared/qdesigner_taskmenu.cpp shared/qdesigner_taskmenu_p.h + shared/qdesigner_toolbar.cpp shared/qdesigner_toolbar_p.h + shared/qdesigner_toolbox.cpp shared/qdesigner_toolbox_p.h + shared/qdesigner_utils.cpp shared/qdesigner_utils_p.h + shared/qdesigner_widget.cpp shared/qdesigner_widget_p.h + shared/qdesigner_widgetbox.cpp shared/qdesigner_widgetbox_p.h + shared/qdesigner_widgetitem.cpp shared/qdesigner_widgetitem_p.h + shared/qlayout_widget.cpp shared/qlayout_widget_p.h + shared/qsimpleresource.cpp shared/qsimpleresource_p.h + shared/qtresourceeditordialog.cpp shared/qtresourceeditordialog.ui shared/qtresourceeditordialog_p.h + shared/qtresourcemodel.cpp shared/qtresourcemodel_p.h + shared/qtresourceview.cpp shared/qtresourceview_p.h + shared/rcc.cpp shared/rcc_p.h + shared/richtexteditor.cpp shared/richtexteditor_p.h + shared/selectsignaldialog.cpp shared/selectsignaldialog.ui shared/selectsignaldialog_p.h + shared/shared_enums_p.h + shared/shared_global_p.h + shared/shared_settings.cpp shared/shared_settings_p.h + shared/sheet_delegate.cpp shared/sheet_delegate_p.h + shared/signalslotdialog.cpp shared/signalslotdialog.ui shared/signalslotdialog_p.h + shared/spacer_widget.cpp shared/spacer_widget_p.h + shared/stylesheeteditor.cpp shared/stylesheeteditor_p.h + shared/textpropertyeditor.cpp shared/textpropertyeditor_p.h + shared/widgetdatabase.cpp shared/widgetdatabase_p.h + shared/widgetfactory.cpp shared/widgetfactory_p.h + shared/zoomwidget.cpp shared/zoomwidget_p.h + uilib/abstractformbuilder.cpp uilib/abstractformbuilder.h + uilib/formbuilder.cpp uilib/formbuilder.h + uilib/formbuilderextra.cpp uilib/formbuilderextra_p.h + uilib/properties.cpp uilib/properties_p.h + uilib/resourcebuilder.cpp uilib/resourcebuilder_p.h + uilib/textbuilder.cpp uilib/textbuilder_p.h + uilib/ui4.cpp uilib/ui4_p.h + DEFINES + QDESIGNER_EXTENSION_LIBRARY + QDESIGNER_SDK_LIBRARY + QDESIGNER_SHARED_LIBRARY + QDESIGNER_UILIB_LIBRARY + QT_DESIGNER + QT_USE_QSTRINGBUILDER + INCLUDE_DIRECTORIES + ../../../shared/deviceskin + ../../../shared/findwidget + ../../../shared/qtgradienteditor + extension + sdk + shared + uilib + LIBRARIES + Qt::CorePrivate + Qt::GuiPrivate + Qt::UiPlugin + Qt::WidgetsPrivate + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::UiPlugin + Qt::Widgets + Qt::Xml + PRIVATE_MODULE_INTERFACE + Qt::CorePrivate + Qt::GuiPrivate + Qt::WidgetsPrivate + ENABLE_AUTOGEN_TOOLS + uic + PRECOMPILED_HEADER + "lib_pch.h" +) + +# Resources: +set(ClamshellPhone_resource_files + "../../../shared/deviceskin/skins/ClamshellPhone.skin" +) + +qt_internal_add_resource(Designer "ClamshellPhone" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${ClamshellPhone_resource_files} +) +set(SmartPhone2_resource_files + "../../../shared/deviceskin/skins/SmartPhone2.skin" +) + +qt_internal_add_resource(Designer "SmartPhone2" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${SmartPhone2_resource_files} +) +set(SmartPhone_resource_files + "../../../shared/deviceskin/skins/SmartPhone.skin" +) + +qt_internal_add_resource(Designer "SmartPhone" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${SmartPhone_resource_files} +) +set(SmartPhoneWithButtons_resource_files + "../../../shared/deviceskin/skins/SmartPhoneWithButtons.skin" +) + +qt_internal_add_resource(Designer "SmartPhoneWithButtons" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${SmartPhoneWithButtons_resource_files} +) +set(TouchscreenPhone_resource_files + "../../../shared/deviceskin/skins/TouchscreenPhone.skin" +) + +qt_internal_add_resource(Designer "TouchscreenPhone" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${TouchscreenPhone_resource_files} +) +set(PortableMedia_resource_files + "../../../shared/deviceskin/skins/PortableMedia.skin" +) + +qt_internal_add_resource(Designer "PortableMedia" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${PortableMedia_resource_files} +) +set(S60-QVGA-Candybar_resource_files + "../../../shared/deviceskin/skins/S60-QVGA-Candybar.skin" +) + +qt_internal_add_resource(Designer "S60-QVGA-Candybar" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${S60-QVGA-Candybar_resource_files} +) +set(S60-nHD-Touchscreen_resource_files + "../../../shared/deviceskin/skins/S60-nHD-Touchscreen.skin" +) + +qt_internal_add_resource(Designer "S60-nHD-Touchscreen" + PREFIX + "/skins" + BASE + "../../../shared/deviceskin/skins" + FILES + ${S60-nHD-Touchscreen_resource_files} +) +set(findwidget_resource_files + "../../../shared/findwidget/images/mac/closetab.png" + "../../../shared/findwidget/images/mac/next.png" + "../../../shared/findwidget/images/mac/previous.png" + "../../../shared/findwidget/images/mac/searchfind.png" + "../../../shared/findwidget/images/win/closetab.png" + "../../../shared/findwidget/images/win/next.png" + "../../../shared/findwidget/images/win/previous.png" + "../../../shared/findwidget/images/win/searchfind.png" + "../../../shared/findwidget/images/wrap.png" +) + +qt_internal_add_resource(Designer "findwidget" + PREFIX + "/qt-project.org/shared" + BASE + "../../../shared/findwidget" + FILES + ${findwidget_resource_files} +) +set(qtgradienteditor_resource_files + "../../../shared/qtgradienteditor/images/down.png" + "../../../shared/qtgradienteditor/images/edit.png" + "../../../shared/qtgradienteditor/images/editdelete.png" + "../../../shared/qtgradienteditor/images/minus.png" + "../../../shared/qtgradienteditor/images/plus.png" + "../../../shared/qtgradienteditor/images/spreadpad.png" + "../../../shared/qtgradienteditor/images/spreadreflect.png" + "../../../shared/qtgradienteditor/images/spreadrepeat.png" + "../../../shared/qtgradienteditor/images/typeconical.png" + "../../../shared/qtgradienteditor/images/typelinear.png" + "../../../shared/qtgradienteditor/images/typeradial.png" + "../../../shared/qtgradienteditor/images/up.png" + "../../../shared/qtgradienteditor/images/zoomin.png" + "../../../shared/qtgradienteditor/images/zoomout.png" +) + +qt_internal_add_resource(Designer "qtgradienteditor" + PREFIX + "/qt-project.org/qtgradienteditor" + BASE + "../../../shared/qtgradienteditor" + FILES + ${qtgradienteditor_resource_files} +) +set(shared_resource_files + "shared/defaultgradients.xml" + "shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui" + "shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui" + "shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui" + "shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui" + "shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui" + "shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui" + "shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui" + "shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui" + "shared/templates/forms/Dialog_with_Buttons_Bottom.ui" + "shared/templates/forms/Dialog_with_Buttons_Right.ui" + "shared/templates/forms/Dialog_without_Buttons.ui" + "shared/templates/forms/Main_Window.ui" + "shared/templates/forms/Widget.ui" +) + +qt_internal_add_resource(Designer "shared" + PREFIX + "/qt-project.org/designer" + BASE + "shared" + FILES + ${shared_resource_files} +) + + +#### Keys ignored in scope 1:.:.:lib.pro:: +# MODULE = "designer" + +## Scopes: +##################################################################### + +qt_internal_extend_target(Designer CONDITION TARGET Qt::OpenGLWidgets + PUBLIC_LIBRARIES + Qt::OpenGLWidgets +) + +qt_internal_extend_target(Designer CONDITION NOT QT_BUILD_SHARED_LIBS + DEFINES + QT_DESIGNER_STATIC + SOURCES + ../../../shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp ../../../shared/qtpropertybrowser/qtbuttonpropertybrowser.h + ../../../shared/qtpropertybrowser/qteditorfactory.cpp ../../../shared/qtpropertybrowser/qteditorfactory.h + ../../../shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp ../../../shared/qtpropertybrowser/qtgroupboxpropertybrowser.h + ../../../shared/qtpropertybrowser/qtpropertybrowser.cpp ../../../shared/qtpropertybrowser/qtpropertybrowser.h + ../../../shared/qtpropertybrowser/qtpropertybrowserutils.cpp ../../../shared/qtpropertybrowser/qtpropertybrowserutils_p.h + ../../../shared/qtpropertybrowser/qtpropertymanager.cpp ../../../shared/qtpropertybrowser/qtpropertymanager.h + ../../../shared/qtpropertybrowser/qttreepropertybrowser.cpp ../../../shared/qtpropertybrowser/qttreepropertybrowser.h + ../../../shared/qtpropertybrowser/qtvariantproperty.cpp ../../../shared/qtpropertybrowser/qtvariantproperty.h + INCLUDE_DIRECTORIES + ../../../shared/qtpropertybrowser +) + +if(NOT QT_BUILD_SHARED_LIBS) + # Resources: + set(qtpropertybrowser_resource_files + "../../../shared/qtpropertybrowser/images/cursor-arrow.png" + "../../../shared/qtpropertybrowser/images/cursor-busy.png" + "../../../shared/qtpropertybrowser/images/cursor-closedhand.png" + "../../../shared/qtpropertybrowser/images/cursor-cross.png" + "../../../shared/qtpropertybrowser/images/cursor-forbidden.png" + "../../../shared/qtpropertybrowser/images/cursor-hand.png" + "../../../shared/qtpropertybrowser/images/cursor-hsplit.png" + "../../../shared/qtpropertybrowser/images/cursor-ibeam.png" + "../../../shared/qtpropertybrowser/images/cursor-openhand.png" + "../../../shared/qtpropertybrowser/images/cursor-sizeall.png" + "../../../shared/qtpropertybrowser/images/cursor-sizeb.png" + "../../../shared/qtpropertybrowser/images/cursor-sizef.png" + "../../../shared/qtpropertybrowser/images/cursor-sizeh.png" + "../../../shared/qtpropertybrowser/images/cursor-sizev.png" + "../../../shared/qtpropertybrowser/images/cursor-uparrow.png" + "../../../shared/qtpropertybrowser/images/cursor-vsplit.png" + "../../../shared/qtpropertybrowser/images/cursor-wait.png" + "../../../shared/qtpropertybrowser/images/cursor-whatsthis.png" + ) + + qt_internal_add_resource(Designer "qtpropertybrowser" + PREFIX + "/qt-project.org/qtpropertybrowser" + BASE + "../../../shared/qtpropertybrowser" + FILES + ${qtpropertybrowser_resource_files} + ) +endif() + +qt_internal_extend_target(Designer CONDITION QT_BUILD_SHARED_LIBS + SOURCES + ../../../shared/qtpropertybrowser/qtpropertybrowserutils.cpp ../../../shared/qtpropertybrowser/qtpropertybrowserutils_p.h + INCLUDE_DIRECTORIES + ../../../shared/qtpropertybrowser +) + +qt_internal_extend_target(Designer CONDITION QT_FEATURE_opengl + LIBRARIES + Qt::OpenGL +) diff --git a/src/designer/src/lib/extension/extension.pri b/src/designer/src/lib/extension/extension.pri deleted file mode 100644 index d8ef658f25..0000000000 --- a/src/designer/src/lib/extension/extension.pri +++ /dev/null @@ -1,12 +0,0 @@ -# Input - -INCLUDEPATH += $$PWD - -HEADERS += $$PWD/default_extensionfactory.h \ - $$PWD/extension.h \ - $$PWD/qextensionmanager.h - -SOURCES += $$PWD/default_extensionfactory.cpp \ - $$PWD/extension.cpp \ - $$PWD/qextensionmanager.cpp - diff --git a/src/designer/src/lib/lib.pro b/src/designer/src/lib/lib.pro deleted file mode 100644 index de0dc7389f..0000000000 --- a/src/designer/src/lib/lib.pro +++ /dev/null @@ -1,21 +0,0 @@ -TARGET = QtDesigner -MODULE = designer - -QT = core-private gui-private widgets-private xml uiplugin - -DEFINES += \ - QDESIGNER_SDK_LIBRARY \ - QDESIGNER_EXTENSION_LIBRARY \ - QDESIGNER_UILIB_LIBRARY \ - QDESIGNER_SHARED_LIBRARY - -static:DEFINES += QT_DESIGNER_STATIC - -include(extension/extension.pri) -include(sdk/sdk.pri) -include(shared/shared.pri) -include(uilib/uilib.pri) -PRECOMPILED_HEADER=lib_pch.h - -MODULE_PLUGIN_TYPES = designer -load(qt_module) diff --git a/src/designer/src/lib/sdk/abstractactioneditor.h b/src/designer/src/lib/sdk/abstractactioneditor.h index 51bcce4a0e..abdc2397a6 100644 --- a/src/designer/src/lib/sdk/abstractactioneditor.h +++ b/src/designer/src/lib/sdk/abstractactioneditor.h @@ -42,7 +42,7 @@ class QDESIGNER_SDK_EXPORT QDesignerActionEditorInterface: public QWidget { Q_OBJECT public: - explicit QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); + explicit QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags = {}); virtual ~QDesignerActionEditorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractdialoggui_p.h b/src/designer/src/lib/sdk/abstractdialoggui_p.h index b9c1814fd7..d8f47dc8b2 100644 --- a/src/designer/src/lib/sdk/abstractdialoggui_p.h +++ b/src/designer/src/lib/sdk/abstractdialoggui_p.h @@ -50,8 +50,9 @@ class QWidget; class QDESIGNER_SDK_EXPORT QDesignerDialogGuiInterface { - Q_DISABLE_COPY_MOVE(QDesignerDialogGuiInterface) public: + Q_DISABLE_COPY_MOVE(QDesignerDialogGuiInterface) + QDesignerDialogGuiInterface(); virtual ~QDesignerDialogGuiInterface(); @@ -78,11 +79,11 @@ class QDESIGNER_SDK_EXPORT QDesignerDialogGuiInterface QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) = 0; virtual QString getExistingDirectory(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly)= 0; - virtual QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr)= 0; - virtual QString getOpenImageFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr); - virtual QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr)= 0; - virtual QStringList getOpenImageFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr); - virtual QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr)= 0; + virtual QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {})= 0; + virtual QString getOpenImageFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}); + virtual QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {})= 0; + virtual QStringList getOpenImageFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}); + virtual QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {})= 0; }; QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractdnditem.h b/src/designer/src/lib/sdk/abstractdnditem.h index 944134e5be..24fc3a9771 100644 --- a/src/designer/src/lib/sdk/abstractdnditem.h +++ b/src/designer/src/lib/sdk/abstractdnditem.h @@ -40,10 +40,12 @@ class QPoint; class QDESIGNER_SDK_EXPORT QDesignerDnDItemInterface { public: + Q_DISABLE_COPY_MOVE(QDesignerDnDItemInterface) + enum DropType { MoveDrop, CopyDrop }; - QDesignerDnDItemInterface() {} - virtual ~QDesignerDnDItemInterface() {} + QDesignerDnDItemInterface() = default; + virtual ~QDesignerDnDItemInterface() = default; virtual DomUI *domUi() const = 0; virtual QWidget *widget() const = 0; diff --git a/src/designer/src/lib/sdk/abstractformeditor.h b/src/designer/src/lib/sdk/abstractformeditor.h index 60dc35c95a..39f5054cc1 100644 --- a/src/designer/src/lib/sdk/abstractformeditor.h +++ b/src/designer/src/lib/sdk/abstractformeditor.h @@ -118,10 +118,6 @@ class QDESIGNER_SDK_EXPORT QDesignerFormEditorInterface : public QObject private: QScopedPointer d; - -private: - QDesignerFormEditorInterface(const QDesignerFormEditorInterface &other); - void operator = (const QDesignerFormEditorInterface &other); }; QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformeditorplugin.h b/src/designer/src/lib/sdk/abstractformeditorplugin.h index 2cd8c7a2e2..008270f562 100644 --- a/src/designer/src/lib/sdk/abstractformeditorplugin.h +++ b/src/designer/src/lib/sdk/abstractformeditorplugin.h @@ -41,7 +41,10 @@ class QAction; class QDESIGNER_SDK_EXPORT QDesignerFormEditorPluginInterface { public: - virtual ~QDesignerFormEditorPluginInterface() {} + Q_DISABLE_COPY_MOVE(QDesignerFormEditorPluginInterface) + + QDesignerFormEditorPluginInterface() = default; + virtual ~QDesignerFormEditorPluginInterface() = default; virtual bool isInitialized() const = 0; virtual void initialize(QDesignerFormEditorInterface *core) = 0; diff --git a/src/designer/src/lib/sdk/abstractformwindow.h b/src/designer/src/lib/sdk/abstractformwindow.h index 6437eecc79..63aeaada85 100644 --- a/src/designer/src/lib/sdk/abstractformwindow.h +++ b/src/designer/src/lib/sdk/abstractformwindow.h @@ -61,9 +61,9 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowInterface: public QWidget SaveOnlyUsedResourceFiles, DontSaveResourceFiles }; + Q_ENUM(ResourceFileSaveMode) -public: - explicit QDesignerFormWindowInterface(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); + explicit QDesignerFormWindowInterface(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); virtual ~QDesignerFormWindowInterface(); virtual QString fileName() const = 0; diff --git a/src/designer/src/lib/sdk/abstractformwindowcursor.h b/src/designer/src/lib/sdk/abstractformwindowcursor.h index 861d07918a..0ef900db1f 100644 --- a/src/designer/src/lib/sdk/abstractformwindowcursor.h +++ b/src/designer/src/lib/sdk/abstractformwindowcursor.h @@ -41,6 +41,8 @@ class QString; class QDESIGNER_SDK_EXPORT QDesignerFormWindowCursorInterface { public: + Q_DISABLE_COPY_MOVE(QDesignerFormWindowCursorInterface) + enum MoveOperation { NoMove, @@ -61,8 +63,8 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowCursorInterface KeepAnchor }; -public: - virtual ~QDesignerFormWindowCursorInterface() {} + QDesignerFormWindowCursorInterface() = default; + virtual ~QDesignerFormWindowCursorInterface() = default; virtual QDesignerFormWindowInterface *formWindow() const = 0; diff --git a/src/designer/src/lib/sdk/abstractformwindowmanager.cpp b/src/designer/src/lib/sdk/abstractformwindowmanager.cpp index 387f0665c8..b94e046721 100644 --- a/src/designer/src/lib/sdk/abstractformwindowmanager.cpp +++ b/src/designer/src/lib/sdk/abstractformwindowmanager.cpp @@ -147,10 +147,12 @@ QDesignerFormWindowManagerInterface::~QDesignerFormWindowManagerInterface() = de Use action() instead. */ +#if QT_CONFIG(clipboard) QAction *QDesignerFormWindowManagerInterface::actionCut() const { return action(CutAction); } +#endif /*! Allows you to intervene and control \QD's "copy" action. The @@ -161,10 +163,12 @@ QAction *QDesignerFormWindowManagerInterface::actionCut() const Use action() instead. */ +#if QT_CONFIG(clipboard) QAction *QDesignerFormWindowManagerInterface::actionCopy() const { return action(CopyAction); } +#endif /*! Allows you to intervene and control \QD's "paste" action. The @@ -175,10 +179,12 @@ QAction *QDesignerFormWindowManagerInterface::actionCopy() const Use action() instead. */ +#if QT_CONFIG(clipboard) QAction *QDesignerFormWindowManagerInterface::actionPaste() const { return action(PasteAction); } +#endif /*! Allows you to intervene and control \QD's "delete" action. The function diff --git a/src/designer/src/lib/sdk/abstractformwindowmanager.h b/src/designer/src/lib/sdk/abstractformwindowmanager.h index 4f826660fc..2f93fbde87 100644 --- a/src/designer/src/lib/sdk/abstractformwindowmanager.h +++ b/src/designer/src/lib/sdk/abstractformwindowmanager.h @@ -54,16 +54,18 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowManagerInterface: public QObject enum Action { +#if QT_CONFIG(clipboard) CutAction = 100, CopyAction, PasteAction, - DeleteAction, +#endif + DeleteAction = 103, SelectAllAction, LowerAction = 200, RaiseAction, - UndoAction = 300, + UndoAction = 300, RedoAction, HorizontalLayoutAction = 400, @@ -78,20 +80,24 @@ class QDESIGNER_SDK_EXPORT QDesignerFormWindowManagerInterface: public QObject DefaultPreviewAction = 500, - FormWindowSettingsDialogAction = 600 + FormWindowSettingsDialogAction = 600 }; + Q_ENUM(Action) enum ActionGroup { StyledPreviewActionGroup = 100 }; + Q_ENUM(ActionGroup) virtual QAction *action(Action action) const = 0; virtual QActionGroup *actionGroup(ActionGroup actionGroup) const = 0; +#if QT_CONFIG(clipboard) QAction *actionCut() const; QAction *actionCopy() const; QAction *actionPaste() const; +#endif QAction *actionDelete() const; QAction *actionSelectAll() const; QAction *actionLower() const; @@ -135,9 +141,6 @@ public Q_SLOTS: virtual void showPreview() = 0; virtual void closeAllPreviews() = 0; virtual void showPluginDialog() = 0; - -private: - QScopedPointer d; }; QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractintegration.h b/src/designer/src/lib/sdk/abstractintegration.h index f2572a7aba..c47e1f8cf0 100644 --- a/src/designer/src/lib/sdk/abstractintegration.h +++ b/src/designer/src/lib/sdk/abstractintegration.h @@ -62,6 +62,7 @@ class QDESIGNER_SDK_EXPORT QDesignerIntegrationInterface: public QObject ReloadResourceFileSilently, PromptToReloadResourceFile // Default }; + Q_ENUM(ResourceFileWatcherBehaviour) enum FeatureFlag { diff --git a/src/designer/src/lib/sdk/abstractintrospection.cpp b/src/designer/src/lib/sdk/abstractintrospection.cpp index c4e12635a7..14bc2a5f26 100644 --- a/src/designer/src/lib/sdk/abstractintrospection.cpp +++ b/src/designer/src/lib/sdk/abstractintrospection.cpp @@ -197,15 +197,17 @@ QDesignerMetaPropertyInterface::~QDesignerMetaPropertyInterface() = default; */ /*! - \fn Attributes QDesignerMetaPropertyInterface::attributes(const QObject *object) const + \fn Attributes QDesignerMetaPropertyInterface::attributes() const - Returns the attributes of the property for the gives \a object. + Returns the attributes of the property. */ /*! - \fn QVariant::Type QDesignerMetaPropertyInterface::type() const + \fn int QDesignerMetaPropertyInterface::type() const Returns the type of the property. + + \sa QMetaType::Type */ /*! diff --git a/src/designer/src/lib/sdk/abstractintrospection_p.h b/src/designer/src/lib/sdk/abstractintrospection_p.h index 9163fc6b0e..fedf5538c8 100644 --- a/src/designer/src/lib/sdk/abstractintrospection_p.h +++ b/src/designer/src/lib/sdk/abstractintrospection_p.h @@ -30,8 +30,8 @@ // W A R N I N G // ------------- // -// This file is not part of the Qt API. It exists for the convenience -// of Qt Designer. This header +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header // file may change from version to version without notice, or even be removed. // // We mean it. @@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE class QDESIGNER_SDK_EXPORT QDesignerMetaEnumInterface { public: + Q_DISABLE_COPY_MOVE(QDesignerMetaEnumInterface) + QDesignerMetaEnumInterface(); virtual ~QDesignerMetaEnumInterface(); virtual bool isFlag() const = 0; @@ -67,6 +69,8 @@ class QDESIGNER_SDK_EXPORT QDesignerMetaEnumInterface class QDESIGNER_SDK_EXPORT QDesignerMetaPropertyInterface { public: + Q_DISABLE_COPY_MOVE(QDesignerMetaPropertyInterface) + enum Kind { EnumKind, FlagKind, OtherKind }; enum AccessFlag { ReadAccess = 0x0001, WriteAccess = 0x0002, ResetAccess = 0x0004 }; enum Attribute { DesignableAttribute = 0x0001, ScriptableAttribute = 0x0002, StoredAttribute = 0x0004, UserAttribute = 0x0008}; @@ -80,9 +84,9 @@ class QDESIGNER_SDK_EXPORT QDesignerMetaPropertyInterface virtual Kind kind() const = 0; virtual AccessFlags accessFlags() const = 0; - virtual Attributes attributes(const QObject *object = nullptr) const = 0; + virtual Attributes attributes() const = 0; - virtual QVariant::Type type() const = 0; + virtual int type() const = 0; virtual QString name() const = 0; virtual QString typeName() const = 0; virtual int userType() const = 0; @@ -99,6 +103,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QDesignerMetaPropertyInterface::Attributes) class QDESIGNER_SDK_EXPORT QDesignerMetaMethodInterface { public: + Q_DISABLE_COPY_MOVE(QDesignerMetaMethodInterface) + QDesignerMetaMethodInterface(); virtual ~QDesignerMetaMethodInterface(); @@ -115,8 +121,11 @@ class QDESIGNER_SDK_EXPORT QDesignerMetaMethodInterface virtual QString typeName() const = 0; }; -class QDESIGNER_SDK_EXPORT QDesignerMetaObjectInterface { +class QDESIGNER_SDK_EXPORT QDesignerMetaObjectInterface +{ public: + Q_DISABLE_COPY_MOVE(QDesignerMetaObjectInterface) + QDesignerMetaObjectInterface(); virtual ~QDesignerMetaObjectInterface(); @@ -144,8 +153,11 @@ class QDESIGNER_SDK_EXPORT QDesignerMetaObjectInterface { }; // To be obtained from core -class QDESIGNER_SDK_EXPORT QDesignerIntrospectionInterface { +class QDESIGNER_SDK_EXPORT QDesignerIntrospectionInterface +{ public: + Q_DISABLE_COPY_MOVE(QDesignerIntrospectionInterface) + QDesignerIntrospectionInterface(); virtual ~QDesignerIntrospectionInterface(); diff --git a/src/designer/src/lib/sdk/abstractlanguage.h b/src/designer/src/lib/sdk/abstractlanguage.h index e31dfa78d0..1ac58261f3 100644 --- a/src/designer/src/lib/sdk/abstractlanguage.h +++ b/src/designer/src/lib/sdk/abstractlanguage.h @@ -53,7 +53,10 @@ class QDesignerResourceBrowserInterface; class QDesignerLanguageExtension { public: - virtual ~QDesignerLanguageExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerLanguageExtension) + + QDesignerLanguageExtension() = default; + virtual ~QDesignerLanguageExtension() = default; /*! Returns the name to be matched against the "language" attribute of the element. diff --git a/src/designer/src/lib/sdk/abstractmetadatabase.h b/src/designer/src/lib/sdk/abstractmetadatabase.h index d3d729429f..adeb6c7eed 100644 --- a/src/designer/src/lib/sdk/abstractmetadatabase.h +++ b/src/designer/src/lib/sdk/abstractmetadatabase.h @@ -45,7 +45,10 @@ class QDesignerFormEditorInterface; class QDesignerMetaDataBaseItemInterface { public: - virtual ~QDesignerMetaDataBaseItemInterface() {} + Q_DISABLE_COPY_MOVE(QDesignerMetaDataBaseItemInterface) + + QDesignerMetaDataBaseItemInterface() = default; + virtual ~QDesignerMetaDataBaseItemInterface() = default; virtual QString name() const = 0; virtual void setName(const QString &name) = 0; diff --git a/src/designer/src/lib/sdk/abstractnewformwidget.h b/src/designer/src/lib/sdk/abstractnewformwidget.h index 35d8efe003..b34d5ff0a7 100644 --- a/src/designer/src/lib/sdk/abstractnewformwidget.h +++ b/src/designer/src/lib/sdk/abstractnewformwidget.h @@ -39,7 +39,6 @@ class QDesignerFormEditorInterface; class QDESIGNER_SDK_EXPORT QDesignerNewFormWidgetInterface : public QWidget { - Q_DISABLE_COPY_MOVE(QDesignerNewFormWidgetInterface) Q_OBJECT public: explicit QDesignerNewFormWidgetInterface(QWidget *parent = nullptr); diff --git a/src/designer/src/lib/sdk/abstractobjectinspector.h b/src/designer/src/lib/sdk/abstractobjectinspector.h index 5f4790de92..a71c2bfdd1 100644 --- a/src/designer/src/lib/sdk/abstractobjectinspector.h +++ b/src/designer/src/lib/sdk/abstractobjectinspector.h @@ -42,7 +42,7 @@ class QDESIGNER_SDK_EXPORT QDesignerObjectInspectorInterface: public QWidget { Q_OBJECT public: - explicit QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); + explicit QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags = {}); virtual ~QDesignerObjectInspectorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractoptionspage.h b/src/designer/src/lib/sdk/abstractoptionspage.h index 6e9e2cc22e..80607ffd0e 100644 --- a/src/designer/src/lib/sdk/abstractoptionspage.h +++ b/src/designer/src/lib/sdk/abstractoptionspage.h @@ -39,7 +39,11 @@ class QWidget; class QDESIGNER_SDK_EXPORT QDesignerOptionsPageInterface { public: - virtual ~QDesignerOptionsPageInterface() {} + Q_DISABLE_COPY_MOVE(QDesignerOptionsPageInterface) + + QDesignerOptionsPageInterface() = default; + virtual ~QDesignerOptionsPageInterface() = default; + virtual QString name() const = 0; virtual QWidget *createPage(QWidget *parent) = 0; virtual void apply() = 0; diff --git a/src/designer/src/lib/sdk/abstractpromotioninterface.cpp b/src/designer/src/lib/sdk/abstractpromotioninterface.cpp index 90f8203307..a8e8ecdb6e 100644 --- a/src/designer/src/lib/sdk/abstractpromotioninterface.cpp +++ b/src/designer/src/lib/sdk/abstractpromotioninterface.cpp @@ -29,11 +29,6 @@ #include "abstractpromotioninterface.h" QT_BEGIN_NAMESPACE - -QDesignerPromotionInterface::~QDesignerPromotionInterface() -{ -} - /*! \class QDesignerPromotionInterface @@ -56,7 +51,7 @@ QDesignerPromotionInterface::~QDesignerPromotionInterface() */ /*! - \fn virtual QDesignerPromotionInterface::PromotedClasses promotedClasses() const + \fn QDesignerPromotionInterface::PromotedClasses QDesignerPromotionInterface::promotedClasses() const Returns a list of promoted classes along with their base classes in alphabetical order. It can be used to populate tree models for editing promoted widgets. diff --git a/src/designer/src/lib/sdk/abstractpromotioninterface.h b/src/designer/src/lib/sdk/abstractpromotioninterface.h index 94c863116b..3ec2a3038a 100644 --- a/src/designer/src/lib/sdk/abstractpromotioninterface.h +++ b/src/designer/src/lib/sdk/abstractpromotioninterface.h @@ -42,9 +42,13 @@ class QDesignerWidgetDataBaseItemInterface; class QDESIGNER_SDK_EXPORT QDesignerPromotionInterface { public: - virtual ~QDesignerPromotionInterface(); + Q_DISABLE_COPY_MOVE(QDesignerPromotionInterface) - struct PromotedClass { + QDesignerPromotionInterface() = default; + virtual ~QDesignerPromotionInterface() = default; + + struct PromotedClass + { QDesignerWidgetDataBaseItemInterface *baseItem; QDesignerWidgetDataBaseItemInterface *promotedItem; }; diff --git a/src/designer/src/lib/sdk/abstractpropertyeditor.h b/src/designer/src/lib/sdk/abstractpropertyeditor.h index 0d8a367ab4..1da6227d59 100644 --- a/src/designer/src/lib/sdk/abstractpropertyeditor.h +++ b/src/designer/src/lib/sdk/abstractpropertyeditor.h @@ -43,7 +43,7 @@ class QDESIGNER_SDK_EXPORT QDesignerPropertyEditorInterface: public QWidget { Q_OBJECT public: - explicit QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags = Qt::WindowFlags()); + explicit QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags = {}); virtual ~QDesignerPropertyEditorInterface(); virtual QDesignerFormEditorInterface *core() const; diff --git a/src/designer/src/lib/sdk/abstractresourcebrowser.h b/src/designer/src/lib/sdk/abstractresourcebrowser.h index cc49a38ea3..d3b97e5ad8 100644 --- a/src/designer/src/lib/sdk/abstractresourcebrowser.h +++ b/src/designer/src/lib/sdk/abstractresourcebrowser.h @@ -37,7 +37,7 @@ QT_BEGIN_NAMESPACE class QWidget; // FIXME: fool syncqt -class QDESIGNER_SDK_EXPORT QDesignerResourceBrowserInterface: public QWidget +class QDESIGNER_SDK_EXPORT QDesignerResourceBrowserInterface : public QWidget { Q_OBJECT public: diff --git a/src/designer/src/lib/sdk/abstractsettings.h b/src/designer/src/lib/sdk/abstractsettings.h index 8be23fc3a1..4540ef1451 100644 --- a/src/designer/src/lib/sdk/abstractsettings.h +++ b/src/designer/src/lib/sdk/abstractsettings.h @@ -40,7 +40,10 @@ class QString; class QDESIGNER_SDK_EXPORT QDesignerSettingsInterface { public: - virtual ~QDesignerSettingsInterface() {} + Q_DISABLE_COPY_MOVE(QDesignerSettingsInterface) + + QDesignerSettingsInterface() = default; + virtual ~QDesignerSettingsInterface() = default; virtual void beginGroup(const QString &prefix) = 0; virtual void endGroup() = 0; diff --git a/src/designer/src/lib/sdk/abstractwidgetbox.cpp b/src/designer/src/lib/sdk/abstractwidgetbox.cpp index e16c274762..9bdef3c5bb 100644 --- a/src/designer/src/lib/sdk/abstractwidgetbox.cpp +++ b/src/designer/src/lib/sdk/abstractwidgetbox.cpp @@ -98,9 +98,7 @@ QDesignerWidgetBoxInterface::QDesignerWidgetBoxInterface(QWidget *parent, Qt::Wi /*! Destroys the widget box interface. */ -QDesignerWidgetBoxInterface::~QDesignerWidgetBoxInterface() -{ -} +QDesignerWidgetBoxInterface::~QDesignerWidgetBoxInterface() = default; /*! \internal diff --git a/src/designer/src/lib/sdk/abstractwidgetbox.h b/src/designer/src/lib/sdk/abstractwidgetbox.h index 7d7600e5b3..6d038fc6a2 100644 --- a/src/designer/src/lib/sdk/abstractwidgetbox.h +++ b/src/designer/src/lib/sdk/abstractwidgetbox.h @@ -47,7 +47,8 @@ class QDESIGNER_SDK_EXPORT QDesignerWidgetBoxInterface : public QWidget { Q_OBJECT public: - class QDESIGNER_SDK_EXPORT Widget { + class QDESIGNER_SDK_EXPORT Widget + { public: enum Type { Default, Custom }; Widget(const QString &aname = QString(), const QString &xml = QString(), @@ -71,7 +72,10 @@ class QDESIGNER_SDK_EXPORT QDesignerWidgetBoxInterface : public QWidget QSharedDataPointer m_data; }; - class Category { + using WidgetList = QList; + + class Category + { public: enum Type { Default, Scratchpad }; @@ -92,8 +96,9 @@ class QDESIGNER_SDK_EXPORT QDesignerWidgetBoxInterface : public QWidget private: QString m_name; Type m_type; - QList m_widget_list; + WidgetList m_widget_list; }; + using CategoryList = QList; explicit QDesignerWidgetBoxInterface(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags()); diff --git a/src/designer/src/lib/sdk/abstractwidgetdatabase.h b/src/designer/src/lib/sdk/abstractwidgetdatabase.h index 725846cafc..c162039fc7 100644 --- a/src/designer/src/lib/sdk/abstractwidgetdatabase.h +++ b/src/designer/src/lib/sdk/abstractwidgetdatabase.h @@ -44,7 +44,10 @@ class QDebug; class QDesignerWidgetDataBaseItemInterface { public: - virtual ~QDesignerWidgetDataBaseItemInterface() {} + Q_DISABLE_COPY_MOVE(QDesignerWidgetDataBaseItemInterface) + + QDesignerWidgetDataBaseItemInterface() = default; + virtual ~QDesignerWidgetDataBaseItemInterface() = default; virtual QString name() const = 0; virtual void setName(const QString &name) = 0; diff --git a/src/designer/src/lib/sdk/container.h b/src/designer/src/lib/sdk/container.h index d661a610f4..f1100c8b10 100644 --- a/src/designer/src/lib/sdk/container.h +++ b/src/designer/src/lib/sdk/container.h @@ -39,7 +39,10 @@ class QWidget; class QDesignerContainerExtension { public: - virtual ~QDesignerContainerExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerContainerExtension) + + QDesignerContainerExtension() = default; + virtual ~QDesignerContainerExtension() = default; virtual int count() const = 0; virtual QWidget *widget(int index) const = 0; @@ -47,17 +50,13 @@ class QDesignerContainerExtension virtual int currentIndex() const = 0; virtual void setCurrentIndex(int index) = 0; + virtual bool canAddWidget() const = 0; virtual void addWidget(QWidget *widget) = 0; virtual void insertWidget(int index, QWidget *widget) = 0; + virtual bool canRemove(int index) const = 0; virtual void remove(int index) = 0; - - virtual bool canAddWidget() const - // ### Qt6 remove body, provided in Qt5 for source compatibility to Qt4. - { return true; } - virtual bool canRemove(int index) const - // ### Qt6 remove body, provided in Qt5 for source compatibility to Qt4. - { Q_UNUSED(index); return true; } }; + Q_DECLARE_EXTENSION_INTERFACE(QDesignerContainerExtension, "org.qt-project.Qt.Designer.Container") QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/dynamicpropertysheet.h b/src/designer/src/lib/sdk/dynamicpropertysheet.h index 57ff043324..9c8cebf1aa 100644 --- a/src/designer/src/lib/sdk/dynamicpropertysheet.h +++ b/src/designer/src/lib/sdk/dynamicpropertysheet.h @@ -49,7 +49,10 @@ class QString; // FIXME: fool syncqt class QDesignerDynamicPropertySheetExtension { public: - virtual ~QDesignerDynamicPropertySheetExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerDynamicPropertySheetExtension) + + QDesignerDynamicPropertySheetExtension() = default; + virtual ~QDesignerDynamicPropertySheetExtension() = default; virtual bool dynamicPropertiesAllowed() const = 0; virtual int addDynamicProperty(const QString &propertyName, const QVariant &value) = 0; diff --git a/src/designer/src/lib/sdk/extrainfo.h b/src/designer/src/lib/sdk/extrainfo.h index aa34979d6e..1b06c03474 100644 --- a/src/designer/src/lib/sdk/extrainfo.h +++ b/src/designer/src/lib/sdk/extrainfo.h @@ -43,7 +43,10 @@ class QDesignerFormEditorInterface; class QDESIGNER_SDK_EXPORT QDesignerExtraInfoExtension { public: - virtual ~QDesignerExtraInfoExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerExtraInfoExtension) + + QDesignerExtraInfoExtension() = default; + virtual ~QDesignerExtraInfoExtension() = default; virtual QDesignerFormEditorInterface *core() const = 0; virtual QWidget *widget() const = 0; diff --git a/src/designer/src/lib/sdk/layoutdecoration.h b/src/designer/src/lib/sdk/layoutdecoration.h index 6318b3466b..e893d19471 100644 --- a/src/designer/src/lib/sdk/layoutdecoration.h +++ b/src/designer/src/lib/sdk/layoutdecoration.h @@ -45,6 +45,8 @@ class QLayout; class QDesignerLayoutDecorationExtension { public: + Q_DISABLE_COPY_MOVE(QDesignerLayoutDecorationExtension) + enum InsertMode { InsertWidgetMode, @@ -52,7 +54,8 @@ class QDesignerLayoutDecorationExtension InsertColumnMode }; - virtual ~QDesignerLayoutDecorationExtension() {} + QDesignerLayoutDecorationExtension() = default; + virtual ~QDesignerLayoutDecorationExtension() = default; virtual QList widgets(QLayout *layout) const = 0; diff --git a/src/designer/src/lib/sdk/membersheet.h b/src/designer/src/lib/sdk/membersheet.h index 185706aef5..a3a9275384 100644 --- a/src/designer/src/lib/sdk/membersheet.h +++ b/src/designer/src/lib/sdk/membersheet.h @@ -41,7 +41,10 @@ class QString; // FIXME: fool syncqt class QDesignerMemberSheetExtension { public: - virtual ~QDesignerMemberSheetExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerMemberSheetExtension) + + QDesignerMemberSheetExtension() = default; + virtual ~QDesignerMemberSheetExtension() = default; virtual int count() const = 0; diff --git a/src/designer/src/lib/sdk/propertysheet.h b/src/designer/src/lib/sdk/propertysheet.h index a59c896a94..1f3a78d056 100644 --- a/src/designer/src/lib/sdk/propertysheet.h +++ b/src/designer/src/lib/sdk/propertysheet.h @@ -38,7 +38,10 @@ class QVariant; class QDesignerPropertySheetExtension { public: - virtual ~QDesignerPropertySheetExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerPropertySheetExtension) + + QDesignerPropertySheetExtension() = default; + virtual ~QDesignerPropertySheetExtension() = default; virtual int count() const = 0; @@ -63,9 +66,7 @@ class QDesignerPropertySheetExtension virtual bool isChanged(int index) const = 0; virtual void setChanged(int index, bool changed) = 0; - virtual bool isEnabled(int index) const - // ### Qt6 remove body, provided in Qt5 for source compatibility to Qt4. - { Q_UNUSED(index); return true; } + virtual bool isEnabled(int index) const = 0; }; Q_DECLARE_EXTENSION_INTERFACE(QDesignerPropertySheetExtension, diff --git a/src/designer/src/lib/sdk/propertysheet.qdoc b/src/designer/src/lib/sdk/propertysheet.qdoc index 4e0ccddf23..e5ab420f4d 100644 --- a/src/designer/src/lib/sdk/propertysheet.qdoc +++ b/src/designer/src/lib/sdk/propertysheet.qdoc @@ -68,17 +68,24 @@ also provides an interface for creating custom property sheet extensions. - \warning \QD uses the QDesignerPropertySheetExtension to feed its - property editor. Whenever a widget is selected in its workspace, - \QD will query for the widget's property sheet extension. If the - selected widget has an implemented property sheet extension, this - extension will override the default property sheet. - - \warning The data types used by the property sheet for some properties - are opaque custom QVariant types containing additional information - instead of plain Qt data types. - For example, this is the case for enumerations, flags, - icons, pixmaps and strings. + Keep the following limitations in mind: + + \list + \li \QD uses the QDesignerPropertySheetExtension to feed its + property editor. Whenever a widget is selected in its workspace, + \QD will query for the widget's property sheet extension. If the + selected widget has an implemented property sheet extension, this + extension will override the default property sheet. + + \li The data types used by the property sheet for some properties + are opaque custom QVariant types containing additional information + instead of plain Qt data types. For example, this is the case for + enumerations, flags, icons, pixmaps and strings. + + \li \QD's property editor has no implementation for handling + Q_PROPERTY types for custom types that have been declared + with Q_DECLARE_METATYPE(). + \endlist To create a property sheet extension, your extension class must inherit from both QObject and diff --git a/src/designer/src/lib/sdk/sdk.pri b/src/designer/src/lib/sdk/sdk.pri deleted file mode 100644 index 4a72dd7d75..0000000000 --- a/src/designer/src/lib/sdk/sdk.pri +++ /dev/null @@ -1,55 +0,0 @@ -# Input - -INCLUDEPATH += $$PWD - -HEADERS += $$PWD/abstractformeditor.h \ - $$PWD/abstractintrospection_p.h \ - $$PWD/abstractsettings.h \ - $$PWD/abstractformeditorplugin.h \ - $$PWD/abstractresourcebrowser.h \ - $$PWD/abstractintegration.h \ - $$PWD/abstractpropertyeditor.h \ - $$PWD/abstractformwindow.h \ - $$PWD/abstractformwindowtool.h \ - $$PWD/abstractformwindowcursor.h \ - $$PWD/abstractformwindowmanager.h \ - $$PWD/abstractwidgetdatabase.h \ - $$PWD/abstractmetadatabase.h \ - $$PWD/abstractwidgetfactory.h \ - $$PWD/abstractobjectinspector.h \ - $$PWD/abstractactioneditor.h \ - $$PWD/abstractlanguage.h \ - $$PWD/abstractoptionspage.h \ - $$PWD/propertysheet.h \ - $$PWD/container.h \ - $$PWD/dynamicpropertysheet.h \ - $$PWD/membersheet.h \ - $$PWD/taskmenu.h \ - $$PWD/extrainfo.h \ - $$PWD/abstractwidgetbox.h \ - $$PWD/layoutdecoration.h \ - $$PWD/abstractdnditem.h \ - $$PWD/abstractpromotioninterface.h \ - $$PWD/abstractdialoggui_p.h \ - $$PWD/abstractnewformwidget.h - -SOURCES += $$PWD/abstractformeditor.cpp \ - $$PWD/abstractintrospection.cpp \ - $$PWD/abstractformeditorplugin.cpp \ - $$PWD/abstractresourcebrowser.cpp \ - $$PWD/abstractintegration.cpp \ - $$PWD/abstractpropertyeditor.cpp \ - $$PWD/abstractformwindow.cpp \ - $$PWD/abstractformwindowtool.cpp \ - $$PWD/abstractformwindowcursor.cpp \ - $$PWD/abstractformwindowmanager.cpp \ - $$PWD/abstractwidgetdatabase.cpp \ - $$PWD/abstractmetadatabase.cpp \ - $$PWD/abstractwidgetfactory.cpp \ - $$PWD/abstractobjectinspector.cpp \ - $$PWD/abstractactioneditor.cpp \ - $$PWD/abstractwidgetbox.cpp \ - $$PWD/extrainfo.cpp \ - $$PWD/abstractpromotioninterface.cpp \ - $$PWD/abstractdialoggui.cpp \ - $$PWD/abstractnewformwidget.cpp diff --git a/src/designer/src/lib/sdk/taskmenu.h b/src/designer/src/lib/sdk/taskmenu.h index 68203e7057..fd588baf13 100644 --- a/src/designer/src/lib/sdk/taskmenu.h +++ b/src/designer/src/lib/sdk/taskmenu.h @@ -38,7 +38,10 @@ class QAction; class QDesignerTaskMenuExtension { public: - virtual ~QDesignerTaskMenuExtension() {} + Q_DISABLE_COPY_MOVE(QDesignerTaskMenuExtension) + + QDesignerTaskMenuExtension() = default; + virtual ~QDesignerTaskMenuExtension() = default; virtual QAction *preferredEditAction() const; diff --git a/src/designer/src/lib/shared/actioneditor.cpp b/src/designer/src/lib/shared/actioneditor.cpp index 86cbb49596..d1ce9804e1 100644 --- a/src/designer/src/lib/shared/actioneditor.cpp +++ b/src/designer/src/lib/shared/actioneditor.cpp @@ -49,21 +49,23 @@ #include #include #include -#include #include #if QT_CONFIG(clipboard) #include #endif #include -#include #include #include #include #include #include + +#include +#include #include -#include +#include +#include #include #include #include @@ -101,7 +103,7 @@ class ActionGroupDelegate: public QItemDelegate }; //-------- ActionEditor -ObjectNamingMode ActionEditor::m_objectNamingMode = Underscore; // fixme Qt 6: CamelCase +ObjectNamingMode ActionEditor::m_objectNamingMode = CamelCase; ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) : QDesignerActionEditorInterface(parent, flags), @@ -325,7 +327,7 @@ void ActionEditor::setFormWindow(QDesignerFormWindowInterface *formWindow) void ActionEditor::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/) { - const bool hasSelection = !selected.indexes().empty(); + const bool hasSelection = !selected.indexes().isEmpty(); #if QT_CONFIG(clipboard) m_actionCopy->setEnabled(hasSelection); m_actionCut->setEnabled(hasSelection); @@ -336,7 +338,7 @@ void ActionEditor::slotSelectionChanged(const QItemSelection& selected, const Q void ActionEditor::slotCurrentItemChanged(QAction *action) { QDesignerFormWindowInterface *fw = formWindow(); - if (!fw) + if (m_withinSelectAction || fw == nullptr) return; const bool hasCurrentAction = action != nullptr; @@ -349,7 +351,7 @@ void ActionEditor::slotCurrentItemChanged(QAction *action) QDesignerObjectInspector *oi = qobject_cast(core()->objectInspector()); - if (action->associatedWidgets().empty()) { + if (action->associatedWidgets().isEmpty()) { // Special case: action not in object tree. Deselect all and set in property editor fw->clearSelection(false); if (oi) @@ -528,7 +530,7 @@ static inline QString textPropertyValue(const QDesignerPropertySheetExtension *s return ps.value(); } -void ActionEditor::editAction(QAction *action) +void ActionEditor::editAction(QAction *action, int column) { if (!action) return; @@ -546,6 +548,24 @@ void ActionEditor::editAction(QAction *action) oldActionData.checkable = action->isCheckable(); dlg.setActionData(oldActionData); + switch (column) { + case qdesigner_internal::ActionModel::NameColumn: + dlg.focusName(); + break; + case qdesigner_internal::ActionModel::TextColumn: + dlg.focusText(); + break; + case qdesigner_internal::ActionModel::ShortCutColumn: + dlg.focusShortcut(); + break; + case qdesigner_internal::ActionModel::CheckedColumn: + dlg.focusCheckable(); + break; + case qdesigner_internal::ActionModel::ToolTipColumn: + dlg.focusTooltip(); + break; + } + if (!dlg.exec()) return; @@ -602,8 +622,9 @@ void ActionEditor::deleteActions(QDesignerFormWindowInterface *fw, const ActionL { // We need a macro even in the case of single action because the commands might cause the // scheduling of other commands (signal slots connections) - const QString description = actions.size() == 1 ? - tr("Remove action '%1'").arg(actions.front()->objectName()) : tr("Remove actions"); + const QString description = actions.size() == 1 + ? tr("Remove action '%1'").arg(actions.constFirst()->objectName()) + : tr("Remove actions"); fw->beginCommand(description); for (QAction *action : actions) { RemoveActionCommand *cmd = new RemoveActionCommand(fw); @@ -644,7 +665,7 @@ void ActionEditor::slotDelete() return; const ActionView::ActionList selection = m_actionView->selectedActions(); - if (selection.empty()) + if (selection.isEmpty()) return; deleteActions(fw, selection); @@ -731,6 +752,24 @@ void ActionEditor::mainContainerChanged() setFormWindow(nullptr); } +void ActionEditor::clearSelection() +{ + // For use by the menu editor; block the syncing of the object inspector + // in slotCurrentItemChanged() since the menu editor updates it itself. + m_withinSelectAction = true; + m_actionView->clearSelection(); + m_withinSelectAction = false; +} + +void ActionEditor::selectAction(QAction *a) +{ + // For use by the menu editor; block the syncing of the object inspector + // in slotCurrentItemChanged() since the menu editor updates it itself. + m_withinSelectAction = true; + m_actionView->selectAction(a); + m_withinSelectAction = false; +} + void ActionEditor::slotViewMode(QAction *a) { m_actionView->setViewMode(a->data().toInt()); @@ -784,7 +823,7 @@ void ActionEditor::slotCopy() return; const ActionView::ActionList selection = m_actionView->selectedActions(); - if (selection.empty()) + if (selection.isEmpty()) return; copyActions(fw, selection); @@ -797,7 +836,7 @@ void ActionEditor::slotCut() return; const ActionView::ActionList selection = m_actionView->selectedActions(); - if (selection.empty()) + if (selection.isEmpty()) return; copyActions(fw, selection); @@ -826,7 +865,7 @@ void ActionEditor::slotContextMenuRequested(QContextMenuEvent *e, QAction *item) // Associated Widgets if (QAction *action = m_actionView->currentAction()) { const QWidgetList associatedWidgets = ActionModel::associatedWidgets(action); - if (!associatedWidgets.empty()) { + if (!associatedWidgets.isEmpty()) { QMenu *associatedWidgetsSubMenu = menu.addMenu(tr("Used In")); for (QWidget *w : associatedWidgets) { associatedWidgetsSubMenu->addAction(w->objectName(), diff --git a/src/designer/src/lib/shared/actioneditor_p.h b/src/designer/src/lib/shared/actioneditor_p.h index 321dbfb32d..911289c8f3 100644 --- a/src/designer/src/lib/shared/actioneditor_p.h +++ b/src/designer/src/lib/shared/actioneditor_p.h @@ -96,11 +96,13 @@ class QDESIGNER_SHARED_EXPORT ActionEditor: public QDesignerActionEditorInterfac public slots: void setFilter(const QString &filter); void mainContainerChanged(); + void clearSelection(); + void selectAction(QAction *a); // For use by the menu editor private slots: void slotCurrentItemChanged(QAction *item); void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); - void editAction(QAction *item); + void editAction(QAction *item, int column = -1); void editCurrentAction(); void navigateToSlotCurrentAction(); void slotActionChanged(); @@ -117,7 +119,7 @@ private slots: #endif signals: - void itemActivated(QAction *item); + void itemActivated(QAction *item, int column); // Context menu for item or global menu if item == 0. void contextMenuRequested(QMenu *menu, QAction *item); @@ -158,6 +160,7 @@ private slots: QString m_filter; QWidget *m_filterWidget; + bool m_withinSelectAction = false; }; } // namespace qdesigner_internal diff --git a/src/designer/src/lib/shared/actionprovider_p.h b/src/designer/src/lib/shared/actionprovider_p.h index 085162a8e0..63d9029512 100644 --- a/src/designer/src/lib/shared/actionprovider_p.h +++ b/src/designer/src/lib/shared/actionprovider_p.h @@ -66,7 +66,7 @@ class QDesignerActionProviderExtension template int actionIndexAt(const Widget *w, const QPoint &pos, Qt::Orientation orientation) { - const QList actions = w->actions(); + const auto actions = w->actions(); const int actionCount = actions.count(); if (actionCount == 0) return -1; diff --git a/src/designer/src/lib/shared/actionrepository.cpp b/src/designer/src/lib/shared/actionrepository.cpp index 2d91a5f001..b9f60cdb6e 100644 --- a/src/designer/src/lib/shared/actionrepository.cpp +++ b/src/designer/src/lib/shared/actionrepository.cpp @@ -35,16 +35,17 @@ #include #include -#include -#include -#include #include -#include -#include #include #include #include + +#include +#include +#include #include +#include + #include #include @@ -107,7 +108,7 @@ void ActionModel::update(int row) for (int i = 0; i < NumColumns; i++) list += item(row, i); - setItems(m_core, actionOfItem(list.front()), m_emptyIcon, list); + setItems(m_core, actionOfItem(list.constFirst()), m_emptyIcon, list); } void ActionModel::remove(int row) @@ -132,7 +133,7 @@ QModelIndex ActionModel::addAction(QAction *action) } setItems(m_core, action, m_emptyIcon, items); appendRow(items); - return indexFromItem(items.front()); + return indexFromItem(items.constFirst()); } // Find the associated menus and toolbars, ignore toolbuttons @@ -190,7 +191,7 @@ void ActionModel::setItems(QDesignerFormEditorInterface *core, QAction *action, item->setWhatsThis(firstTooltip); // Used const QWidgetList associatedDesignerWidgets = associatedWidgets(action); - const bool used = !associatedDesignerWidgets.empty(); + const bool used = !associatedDesignerWidgets.isEmpty(); item = sl[UsedColumn]; item->setCheckState(used ? Qt::Checked : Qt::Unchecked); if (used) { @@ -276,6 +277,16 @@ QAction *ActionModel::actionAt(const QModelIndex &index) const return actionOfItem(i); } +QModelIndex ActionModel::indexOf(QAction *a) const +{ + for (int r = rowCount() - 1; r >= 0; --r) { + QStandardItem *stdItem = item(r, 0); + if (actionOfItem(stdItem) == a) + return indexFromItem(stdItem); + } + return {}; +} + // helpers static bool handleImageDragEnterMoveEvent(QDropEvent *event) @@ -291,7 +302,7 @@ static bool handleImageDragEnterMoveEvent(QDropEvent *event) static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, ActionModel *am) { - const QModelIndex index = iv->indexAt(event->pos()); + const QModelIndex index = iv->indexAt(event->position().toPoint()); if (!index.isValid()) { event->ignore(); return; @@ -308,14 +319,14 @@ static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, void startActionDrag(QWidget *dragParent, ActionModel *model, const QModelIndexList &indexes, Qt::DropActions supportedActions) { - if (indexes.empty()) + if (indexes.isEmpty()) return; QDrag *drag = new QDrag(dragParent); QMimeData *data = model->mimeData(indexes); drag->setMimeData(data); if (ActionRepositoryMimeData *actionMimeData = qobject_cast(data)) - drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(actionMimeData->actionList().front())); + drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(actionMimeData->actionList().constFirst())); drag->exec(supportedActions); } @@ -392,7 +403,7 @@ void ActionTreeView::currentChanged(const QModelIndex ¤t, const QModelInde void ActionTreeView::slotActivated(const QModelIndex &index) { - emit actionActivated(m_model->actionAt(index)); + emit actionActivated(m_model->actionAt(index), index.column()); } void ActionTreeView::startDrag(Qt::DropActions supportedActions) @@ -499,7 +510,8 @@ ActionView::ActionView(QWidget *parent) : // make it possible for vs integration to reimplement edit action dialog // [which it shouldn't do actually] - connect(m_actionListView, &ActionListView::actionActivated, this, &ActionView::activated); + connect(m_actionListView, &ActionListView::actionActivated, + this, [this](QAction *a) { this->activated(a, -1); }); connect(m_actionTreeView, &ActionTreeView::actionActivated, this, &ActionView::activated); connect(m_actionListView, &ActionListView::currentActionChanged, @@ -562,6 +574,13 @@ void ActionView::clearSelection() m_actionTreeView->selectionModel()->clearSelection(); } +void ActionView::selectAction(QAction *a) +{ + const QModelIndex index = m_model->indexOf(a); + if (index.isValid()) + setCurrentIndex(index); +} + void ActionView::setCurrentIndex(const QModelIndex &index) { m_actionTreeView->setCurrentIndex(index); diff --git a/src/designer/src/lib/shared/actionrepository_p.h b/src/designer/src/lib/shared/actionrepository_p.h index a68b3371fc..e84dd8acf0 100644 --- a/src/designer/src/lib/shared/actionrepository_p.h +++ b/src/designer/src/lib/shared/actionrepository_p.h @@ -82,6 +82,7 @@ class QDESIGNER_SHARED_EXPORT ActionModel: public QStandardItemModel QString actionName(int row) const; QAction *actionAt(const QModelIndex &index) const; + QModelIndex indexOf(QAction *a) const; QMimeData *mimeData(const QModelIndexList &indexes) const override; QStringList mimeTypes() const override; @@ -124,7 +125,7 @@ public slots: signals: void actionContextMenuRequested(QContextMenuEvent *event, QAction *); void currentActionChanged(QAction *action); - void actionActivated(QAction *action); + void actionActivated(QAction *action, int column); protected slots: void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) override; @@ -211,11 +212,12 @@ public slots: void filter(const QString &text); void selectAll(); void clearSelection(); + void selectAction(QAction *a); signals: void contextMenuRequested(QContextMenuEvent *event, QAction *); void currentChanged(QAction *action); - void activated(QAction *action); + void activated(QAction *action, int column); void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void resourceImageDropped(const QString &data, QAction *action); diff --git a/src/designer/src/lib/shared/codedialog.cpp b/src/designer/src/lib/shared/codedialog.cpp index e3b3f0d747..34bc561965 100644 --- a/src/designer/src/lib/shared/codedialog.cpp +++ b/src/designer/src/lib/shared/codedialog.cpp @@ -32,21 +32,22 @@ #include -#include #include #if QT_CONFIG(clipboard) #include #endif #include #include -#include -#include #include #include #include #include #include +#include +#include +#include + #include #include #include diff --git a/src/designer/src/lib/shared/connectionedit.cpp b/src/designer/src/lib/shared/connectionedit.cpp index e9064dced5..2382e154a2 100644 --- a/src/designer/src/lib/shared/connectionedit.cpp +++ b/src/designer/src/lib/shared/connectionedit.cpp @@ -31,14 +31,15 @@ #include +#include +#include + +#include #include #include #include #include -#include -#include -#include -#include +#include #include @@ -135,8 +136,8 @@ void AddConnectionCommand::redo() emit edit()->aboutToAddConnection(edit()->m_con_list.size()); edit()->m_con_list.append(m_con); m_con->inserted(); - edit()->setSelected(m_con, true); emit edit()->connectionAdded(m_con); + edit()->setSelected(m_con, true); } void AddConnectionCommand::undo() @@ -222,10 +223,11 @@ void DeleteConnectionsCommand::undo() Q_ASSERT(!edit()->m_con_list.contains(con)); emit edit()->aboutToAddConnection(edit()->m_con_list.size()); edit()->m_con_list.append(con); - edit()->setSelected(con, true); + edit()->selectNone(); con->update(); con->inserted(); emit edit()->connectionAdded(con); + edit()->setSelected(con, true); } } @@ -880,7 +882,7 @@ void Connection::updatePixmap(EndPoint::Type type) const LineDir dir = labelDir(type); if (dir == DownDir) - *pm = pm->transformed(QMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); + *pm = pm->transformed(QTransform(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); } void Connection::checkWidgets() @@ -1142,9 +1144,10 @@ void ConnectionEdit::mousePressEvent(QMouseEvent *e) // otherwise, widgets covered by the connection labels cannot be accessed Connection *con_under_mouse = nullptr; if (!m_widget_under_mouse || m_widget_under_mouse == m_bg_widget) - con_under_mouse = connectionAt(e->pos()); + con_under_mouse = connectionAt(e->position().toPoint()); m_start_connection_on_drag = false; + const bool toggleSelection = e->modifiers().testFlag(Qt::ControlModifier); switch (cstate) { case Connecting: if (button == Qt::RightButton) @@ -1154,18 +1157,17 @@ void ConnectionEdit::mousePressEvent(QMouseEvent *e) break; case Editing: if (!m_end_point_under_mouse.isNull()) { - if (!(e->modifiers() & Qt::ShiftModifier)) { - startDrag(m_end_point_under_mouse, e->pos()); - } + if (!toggleSelection) + startDrag(m_end_point_under_mouse, e->position().toPoint()); } else if (con_under_mouse != nullptr) { - if (!(e->modifiers() & Qt::ShiftModifier)) { + if (toggleSelection) { + setSelected(con_under_mouse, !selected(con_under_mouse)); + } else { selectNone(); setSelected(con_under_mouse, true); - } else { - setSelected(con_under_mouse, !selected(con_under_mouse)); } } else { - if (!(e->modifiers() & Qt::ShiftModifier)) { + if (!toggleSelection) { selectNone(); if (!m_widget_under_mouse.isNull()) m_start_connection_on_drag = true; @@ -1212,7 +1214,7 @@ void ConnectionEdit::mouseReleaseEvent(QMouseEvent *e) if (m_widget_under_mouse.isNull()) abortConnection(); else - endConnection(m_widget_under_mouse, e->pos()); + endConnection(m_widget_under_mouse, e->position().toPoint()); #if QT_CONFIG(cursor) setCursor(QCursor()); #endif @@ -1220,7 +1222,7 @@ void ConnectionEdit::mouseReleaseEvent(QMouseEvent *e) case Editing: break; case Dragging: - endDrag(e->pos()); + endDrag(e->position().toPoint()); break; } } @@ -1260,24 +1262,24 @@ void ConnectionEdit::findObjectsUnderMouse(const QPoint &pos) void ConnectionEdit::mouseMoveEvent(QMouseEvent *e) { - findObjectsUnderMouse(e->pos()); + findObjectsUnderMouse(e->position().toPoint()); switch (state()) { case Connecting: - continueConnection(m_widget_under_mouse, e->pos()); + continueConnection(m_widget_under_mouse, e->position().toPoint()); break; case Editing: if ((e->buttons() & Qt::LeftButton) && m_start_connection_on_drag && !m_widget_under_mouse.isNull()) { m_start_connection_on_drag = false; - startConnection(m_widget_under_mouse, e->pos()); + startConnection(m_widget_under_mouse, e->position().toPoint()); #if QT_CONFIG(cursor) setCursor(Qt::CrossCursor); #endif } break; case Dragging: - continueDrag(e->pos()); + continueDrag(e->position().toPoint()); break; } @@ -1370,7 +1372,7 @@ static ConnectionEdit::ConnectionSet findConnectionsOf(const ConnectionEdit::Con void ConnectionEdit::widgetRemoved(QWidget *widget) { // Remove all connections of that widget and its children. - if (m_con_list.empty()) + if (m_con_list.isEmpty()) return; QWidgetList child_list = widget->findChildren(); @@ -1378,8 +1380,10 @@ void ConnectionEdit::widgetRemoved(QWidget *widget) const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd()); - if (!remove_set.isEmpty()) - m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys())); + if (!remove_set.isEmpty()) { + auto cmd = new DeleteConnectionsCommand(this, ConnectionList(remove_set.cbegin(), remove_set.cend())); + m_undo_stack->push(cmd); + } updateBackground(); } @@ -1387,14 +1391,16 @@ void ConnectionEdit::widgetRemoved(QWidget *widget) void ConnectionEdit::objectRemoved(QObject *o) { // Remove all connections of that object and its children (in case of action groups). - if (m_con_list.empty()) + if (m_con_list.isEmpty()) return; QObjectList child_list = o->children(); child_list.prepend(o); const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd()); - if (!remove_set.isEmpty()) - m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys())); + if (!remove_set.isEmpty()) { + auto cmd = new DeleteConnectionsCommand(this, ConnectionList(remove_set.cbegin(), remove_set.cend())); + m_undo_stack->push(cmd); + } updateBackground(); } @@ -1499,7 +1505,8 @@ void ConnectionEdit::deleteSelected() { if (m_sel_con_set.isEmpty()) return; - m_undo_stack->push(new DeleteConnectionsCommand(this, m_sel_con_set.keys())); + auto cmd = new DeleteConnectionsCommand(this, ConnectionList(m_sel_con_set.cbegin(), m_sel_con_set.cend())); + m_undo_stack->push(cmd); } void ConnectionEdit::addConnection(Connection *con) diff --git a/src/designer/src/lib/shared/connectionedit_p.h b/src/designer/src/lib/shared/connectionedit_p.h index 6fd623457c..ca4560fdab 100644 --- a/src/designer/src/lib/shared/connectionedit_p.h +++ b/src/designer/src/lib/shared/connectionedit_p.h @@ -50,8 +50,7 @@ #include #include #include - -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/deviceprofile.cpp b/src/designer/src/lib/shared/deviceprofile.cpp index c2df77ffdf..fbe65abafc 100644 --- a/src/designer/src/lib/shared/deviceprofile.cpp +++ b/src/designer/src/lib/shared/deviceprofile.cpp @@ -34,11 +34,12 @@ #include #include -#include #include #include #include +#include + #include #include @@ -202,9 +203,9 @@ void DeviceProfile::setName(const QString &n) void DeviceProfile::systemResolution(int *dpiX, int *dpiY) { - const QDesktopWidget *dw = qApp->desktop(); - *dpiX = dw->logicalDpiX(); - *dpiY = dw->logicalDpiY(); + auto s = qApp->primaryScreen(); + *dpiX = s->logicalDotsPerInchX(); + *dpiY = s->logicalDotsPerInchY(); } class FriendlyWidget : public QWidget { @@ -241,7 +242,7 @@ static void applyFont(const QString &family, int size, DeviceProfile::ApplyMode case DeviceProfile::ApplyPreview: { // Preview: Apply only subproperties that have not been changed by designer properties bool apply = false; - const uint resolve = currentFont.resolve(); + const uint resolve = currentFont.resolveMask(); if (!(resolve & QFont::FamilyResolved)) { currentFont.setFamily(family); apply = true; @@ -331,7 +332,7 @@ enum ParseStage { ParseBeginning, ParseWithinRoot, ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle, ParseError }; -static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) +static ParseStage nextStage(ParseStage currentStage, QStringView startElement) { switch (currentStage) { case ParseBeginning: diff --git a/src/designer/src/lib/shared/dialoggui.cpp b/src/designer/src/lib/shared/dialoggui.cpp index 8c537ab342..613a421432 100644 --- a/src/designer/src/lib/shared/dialoggui.cpp +++ b/src/designer/src/lib/shared/dialoggui.cpp @@ -211,13 +211,13 @@ QString DialogGui::getOpenImageFileName(QWidget *parent, const QString &caption, return QString(); const QStringList selectedFiles = fileDialog.selectedFiles(); - if (selectedFiles.empty()) + if (selectedFiles.isEmpty()) return QString(); if (selectedFilter) *selectedFilter = fileDialog.selectedNameFilter(); - return selectedFiles.front(); + return selectedFiles.constFirst(); #else return getOpenFileName(parent, caption, dir, filter, selectedFilter, options); #endif @@ -232,7 +232,7 @@ QStringList DialogGui::getOpenImageFileNames(QWidget *parent, const QString &cap return QStringList(); const QStringList selectedFiles = fileDialog.selectedFiles(); - if (!selectedFiles.empty() && selectedFilter) + if (!selectedFiles.isEmpty() && selectedFilter) *selectedFilter = fileDialog.selectedNameFilter(); return selectedFiles; diff --git a/src/designer/src/lib/shared/dialoggui_p.h b/src/designer/src/lib/shared/dialoggui_p.h index 0dde0b34ee..4b5f2829f5 100644 --- a/src/designer/src/lib/shared/dialoggui_p.h +++ b/src/designer/src/lib/shared/dialoggui_p.h @@ -73,12 +73,12 @@ class QDESIGNER_SHARED_EXPORT DialogGui : public QDesignerDialogGuiInterface QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) override; QString getExistingDirectory(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly) override; - QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr) override; - QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr) override; - QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr) override; + QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}) override; + QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}) override; + QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}) override; - QString getOpenImageFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr) override; - QStringList getOpenImageFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = nullptr) override; + QString getOpenImageFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}) override; + QStringList getOpenImageFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = {}) override; private: QFileIconProvider *ensureIconProvider(); diff --git a/src/designer/src/lib/shared/formlayoutmenu.cpp b/src/designer/src/lib/shared/formlayoutmenu.cpp index 8d4bab6c7a..f4b9255ffa 100644 --- a/src/designer/src/lib/shared/formlayoutmenu.cpp +++ b/src/designer/src/lib/shared/formlayoutmenu.cpp @@ -41,13 +41,14 @@ #include #include -#include #include #include -#include #include #include + +#include #include +#include #include #include @@ -154,7 +155,7 @@ FormLayoutRowDialog::FormLayoutRowDialog(QDesignerFormEditorInterface *core, m_ui.fieldClassComboBox->addItems(fieldWidgetClasses(core)); m_ui.fieldClassComboBox->setCurrentIndex(0); connect(m_ui.fieldClassComboBox, - QOverload::of(&QComboBox::currentIndexChanged), + &QComboBox::currentIndexChanged, this, &FormLayoutRowDialog::fieldClassChanged); updateOkButton(); @@ -476,7 +477,7 @@ void FormLayoutMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, Acti { switch (LayoutInfo::managedLayoutType(fw->core(), w)) { case LayoutInfo::Form: - if (!actions.empty() && !actions.back()->isSeparator()) + if (!actions.isEmpty() && !actions.constLast()->isSeparator()) actions.push_back(m_separator1); actions.push_back(m_populateFormAction); actions.push_back(m_separator2); diff --git a/src/designer/src/lib/shared/formwindowbase.cpp b/src/designer/src/lib/shared/formwindowbase.cpp index ab3fcfbb07..8a126c1a14 100644 --- a/src/designer/src/lib/shared/formwindowbase.cpp +++ b/src/designer/src/lib/shared/formwindowbase.cpp @@ -45,10 +45,6 @@ #include #include -#include -#include -#include -#include #include #include #include @@ -59,9 +55,15 @@ #include #include #include -#include #include +#include + +#include +#include +#include +#include + QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -84,6 +86,7 @@ class FormWindowBasePrivate { FormWindowBase::LineTerminatorMode m_lineTerminatorMode; FormWindowBase::ResourceFileSaveMode m_saveResourcesBehaviour; bool m_useIdBasedTranslations; + bool m_connectSlotsByName; }; FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) : @@ -96,7 +99,8 @@ FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) m_deviceProfile(QDesignerSharedSettings(core).currentDeviceProfile()), m_lineTerminatorMode(FormWindowBase::NativeLineTerminator), m_saveResourcesBehaviour(FormWindowBase::SaveAllResourceFiles), - m_useIdBasedTranslations(false) + m_useIdBasedTranslations(false), + m_connectSlotsByName(true) { } @@ -444,7 +448,7 @@ void FormWindowBase::deleteWidgetList(const QWidgetList &widget_list) // the signal slot editor are connected to widgetRemoved() and add their // own commands (for example, to delete w's connections) const QString description = widget_list.size() == 1 ? - tr("Delete '%1'").arg(widget_list.front()->objectName()) : tr("Delete"); + tr("Delete '%1'").arg(widget_list.constFirst()->objectName()) : tr("Delete"); commandHistory()->beginMacro(description); for (QWidget *w : qAsConst(widget_list)) { @@ -465,16 +469,16 @@ QMenu *FormWindowBase::createExtensionTaskMenu(QDesignerFormWindowInterface *fw, if (const QDesignerTaskMenuExtension *extTaskMenu = qt_extension(em, o)) actions += extTaskMenu->taskActions(); if (const QDesignerTaskMenuExtension *intTaskMenu = qobject_cast(em->extension(o, QStringLiteral("QDesignerInternalTaskMenuExtension")))) { - if (!actions.empty()) { + if (!actions.isEmpty()) { QAction *a = new QAction(fw); a->setSeparator(true); actions.push_back(a); } actions += intTaskMenu->taskActions(); } - if (actions.empty()) + if (actions.isEmpty()) return nullptr; - if (trailingSeparator && !actions.back()->isSeparator()) { + if (trailingSeparator && !actions.constLast()->isSeparator()) { QAction *a = new QAction(fw); a->setSeparator(true); actions.push_back(a); @@ -537,6 +541,16 @@ void FormWindowBase::setUseIdBasedTranslations(bool v) m_d->m_useIdBasedTranslations = v; } +bool FormWindowBase::connectSlotsByName() const +{ + return m_d->m_connectSlotsByName; +} + +void FormWindowBase::setConnectSlotsByName(bool v) +{ + m_d->m_connectSlotsByName = v; +} + QStringList FormWindowBase::checkContents() const { if (!mainContainer()) diff --git a/src/designer/src/lib/shared/formwindowbase_p.h b/src/designer/src/lib/shared/formwindowbase_p.h index b1e8a2f403..b240aa5215 100644 --- a/src/designer/src/lib/shared/formwindowbase_p.h +++ b/src/designer/src/lib/shared/formwindowbase_p.h @@ -165,6 +165,9 @@ class QDESIGNER_SHARED_EXPORT FormWindowBase: public QDesignerFormWindowInterfac bool useIdBasedTranslations() const; void setUseIdBasedTranslations(bool v); + bool connectSlotsByName() const; + void setConnectSlotsByName(bool v); + public slots: void resourceSetActivated(QtResourceSet *resourceSet, bool resourceSetChanged); diff --git a/src/designer/src/lib/shared/grid.cpp b/src/designer/src/lib/shared/grid.cpp index d1298d1f02..9f9ff7d650 100644 --- a/src/designer/src/lib/shared/grid.cpp +++ b/src/designer/src/lib/shared/grid.cpp @@ -28,11 +28,13 @@ #include "grid_p.h" +#include #include -#include + +#include #include + #include -#include QT_BEGIN_NAMESPACE @@ -125,7 +127,7 @@ void Grid::paint(QPainter &p, const QWidget *widget, QPaintEvent *e) const const int xend = e->rect().right(); const int yend = e->rect().bottom(); - using Points = QVector; + using Points = QList; static Points points; points.clear(); diff --git a/src/designer/src/lib/shared/iconselector.cpp b/src/designer/src/lib/shared/iconselector.cpp index d9d50e7828..7b3c7a6b03 100644 --- a/src/designer/src/lib/shared/iconselector.cpp +++ b/src/designer/src/lib/shared/iconselector.cpp @@ -42,7 +42,6 @@ #include #include -#include #include #include #include @@ -53,9 +52,12 @@ #include #include #include + +#include #include -#include +#include +#include QT_BEGIN_NAMESPACE @@ -329,7 +331,7 @@ bool IconSelector::checkPixmap(const QString &fileName, CheckMode cm, QString *e static QString imageFilter() { QString filter = QApplication::translate("IconSelector", "All Pixmaps ("); - const QList supportedImageFormats = QImageReader::supportedImageFormats(); + const auto supportedImageFormats = QImageReader::supportedImageFormats(); const QString jpeg = QStringLiteral("JPEG"); const int count = supportedImageFormats.count(); for (int i = 0; i< count; ++i) { @@ -590,8 +592,7 @@ void IconThemeEditor::updatePreview(const QString &t) { // Update preview label with icon. if (t.isEmpty() || !QIcon::hasThemeIcon(t)) { // Empty - const QPixmap *currentPixmap = d->m_themeLabel->pixmap(); - if (currentPixmap == nullptr || currentPixmap->cacheKey() != d->m_emptyPixmap.cacheKey()) + if (d->m_themeLabel->pixmap(Qt::ReturnByValue).cacheKey() != d->m_emptyPixmap.cacheKey()) d->m_themeLabel->setPixmap(d->m_emptyPixmap); } else { const QIcon icon = QIcon::fromTheme(t); diff --git a/src/designer/src/lib/shared/layout.cpp b/src/designer/src/lib/shared/layout.cpp index 436d5223b5..ce2351d656 100644 --- a/src/designer/src/lib/shared/layout.cpp +++ b/src/designer/src/lib/shared/layout.cpp @@ -27,37 +27,37 @@ ****************************************************************************/ #include "layout_p.h" +#include "layoutdecoration.h" #include "qdesigner_utils_p.h" +#include "qdesigner_widgetitem_p.h" #include "qlayout_widget_p.h" #include "spacer_widget_p.h" -#include "layoutdecoration.h" #include "widgetfactory_p.h" -#include "qdesigner_widgetitem_p.h" #include #include +#include +#include #include -#include #include -#include -#include +#include #include -#include +#include +#include +#include #include -#include #include -#include -#include -#include + #include -#include #include +#include #include +#include +#include +#include #include -#include -#include #include @@ -392,7 +392,7 @@ void Layout::breakLayout() for (auto it = rects.cbegin(), end = rects.cend(); it != end; ++it) { QWidget *w = it.key(); if (needReparent) { - w->setParent(m_layoutBase->parentWidget(), nullptr); + w->setParent(m_layoutBase->parentWidget(), {}); w->move(m_layoutBasePos + it.value().topLeft()); w->show(); } @@ -456,7 +456,7 @@ QLayout *Layout::createLayout(int type) void Layout::reparentToLayoutBase(QWidget *w) { if (w->parent() != m_layoutBase) { - w->setParent(m_layoutBase, nullptr); + w->setParent(m_layoutBase, {}); w->move(QPoint(0,0)); } } @@ -895,8 +895,8 @@ void Grid::simplify() void Grid::shrink() { // tick off the occupied cols/rows (bordering on widget edges) - QVector columns(m_ncols, false); - QVector rows(m_nrows, false); + QList columns(m_ncols, false); + QList rows(m_nrows, false); for (int c = 0; c < m_ncols; c++) for (int r = 0; r < m_nrows; r++) @@ -1104,7 +1104,7 @@ void GridLayout::doLayout() if (needReparent) reparentToLayoutBase(w); - Qt::Alignment alignment = Qt::Alignment(nullptr); + Qt::Alignment alignment; if (const Spacer *spacer = qobject_cast(w)) alignment = spacer->alignment(); @@ -1122,12 +1122,12 @@ void GridLayout::doLayout() } // Remove duplicate entries (Remove next, if equal to current) -void removeIntVecDuplicates(QVector &v) +void removeIntVecDuplicates(QList &v) { if (v.size() < 2) return; - for (QVector::iterator current = v.begin() ; (current != v.end()) && ((current+1) != v.end()) ; ) + for (QList::iterator current = v.begin() ; (current != v.end()) && ((current+1) != v.end()) ; ) if ( *current == *(current+1) ) v.erase(current+1); else @@ -1143,7 +1143,7 @@ inline QRect expandGeometry(const QRect &rect) template QWidgetList GridLayout::buildGrid(const QWidgetList &widgetList) { - if (widgetList.empty()) + if (widgetList.isEmpty()) return QWidgetList(); // Pixel to cell conversion: @@ -1154,8 +1154,8 @@ QWidgetList GridLayout::buildGrid(const QW // We need a list of both start and stop values for x- & y-axis const int widgetCount = widgetList.size(); - QVector x( widgetCount * 2 ); - QVector y( widgetCount * 2 ); + QList x( widgetCount * 2 ); + QList y( widgetCount * 2 ); // Using push_back would look nicer, but operator[] is much faster int index = 0; diff --git a/src/designer/src/lib/shared/layoutinfo.cpp b/src/designer/src/lib/shared/layoutinfo.cpp index 30cfabfda1..0374de582e 100644 --- a/src/designer/src/lib/shared/layoutinfo.cpp +++ b/src/designer/src/lib/shared/layoutinfo.cpp @@ -65,7 +65,7 @@ LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core static const QHash &layoutNameTypeMap() { static QHash nameTypeMap; - if (nameTypeMap.empty()) { + if (nameTypeMap.isEmpty()) { nameTypeMap.insert(QStringLiteral("QVBoxLayout"), LayoutInfo::VBox); nameTypeMap.insert(QStringLiteral("QHBoxLayout"), LayoutInfo::HBox); nameTypeMap.insert(QStringLiteral("QGridLayout"), LayoutInfo::Grid); @@ -177,12 +177,10 @@ LayoutInfo::Type LayoutInfo::laidoutWidgetType(const QDesignerFormEditorInterfac } // 3) Some child layout (see below comment about Q3GroupBox) - const QList childLayouts = parentLayout->findChildren(); - if (childLayouts.empty()) + const auto childLayouts = parentLayout->findChildren(); + if (childLayouts.isEmpty()) return NoLayout; - const QList::const_iterator lcend = childLayouts.constEnd(); - for (QList::const_iterator it = childLayouts.constBegin(); it != lcend; ++it) { - QLayout *layout = *it; + for (QLayout *layout : childLayouts) { if (layout->indexOf(widget) != -1) { if (isManaged) *isManaged = core->metaDataBase()->item(layout); @@ -215,6 +213,9 @@ QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, con QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout) { + if (!layout) + return nullptr; + QDesignerMetaDataBaseInterface *metaDataBase = core->metaDataBase(); if (!metaDataBase) diff --git a/src/designer/src/lib/shared/morphmenu.cpp b/src/designer/src/lib/shared/morphmenu.cpp index ee09dfafd8..976a27dedc 100644 --- a/src/designer/src/lib/shared/morphmenu.cpp +++ b/src/designer/src/lib/shared/morphmenu.cpp @@ -44,11 +44,10 @@ #include #include -#include #include #include #include -#include +#include #include #include @@ -63,6 +62,8 @@ #include #include +#include + #include #include #include @@ -226,14 +227,10 @@ static QString suggestObjectName(const QString &oldClassName, const QString &new // Find the label whose buddy the widget is. QLabel *buddyLabelOf(QDesignerFormWindowInterface *fw, QWidget *w) { - using LabelList = QList; - const LabelList labelList = fw->findChildren(); - if (labelList.empty()) - return nullptr; - const LabelList::const_iterator cend = labelList.constEnd(); - for (LabelList::const_iterator it = labelList.constBegin(); it != cend; ++it ) - if ( (*it)->buddy() == w) - return *it; + const auto labelList = fw->findChildren(); + for (QLabel *label : labelList) + if (label->buddy() == w) + return label; return nullptr; } @@ -586,7 +583,7 @@ bool MorphMenu::populateMenu(QWidget *w, QDesignerFormWindowInterface *fw) return false; const QStringList c = MorphWidgetCommand::candidateClasses(fw, w); - if (c.empty()) + if (c.isEmpty()) return false; // Pull up diff --git a/src/designer/src/lib/shared/newactiondialog.cpp b/src/designer/src/lib/shared/newactiondialog.cpp index 676d4a80ae..d5380bfcbd 100644 --- a/src/designer/src/lib/shared/newactiondialog.cpp +++ b/src/designer/src/lib/shared/newactiondialog.cpp @@ -78,7 +78,7 @@ NewActionDialog::NewActionDialog(ActionEditor *parent) : this, &NewActionDialog::slotResetKeySequence); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - m_ui->editActionText->setFocus(); + focusText(); updateButtons(); QDesignerFormWindowInterface *form = parent->formWindow(); @@ -96,6 +96,31 @@ NewActionDialog::~NewActionDialog() delete m_ui; } +void NewActionDialog::focusName() +{ + m_ui->editObjectName->setFocus(); +} + +void NewActionDialog::focusText() +{ + m_ui->editActionText->setFocus(); +} + +void NewActionDialog::focusTooltip() +{ + m_ui->tooltipEditor->setFocus(); +} + +void NewActionDialog::focusShortcut() +{ + m_ui->keySequenceEdit->setFocus(); +} + +void NewActionDialog::focusCheckable() +{ + m_ui->checkableCheckBox->setFocus(); +} + QString NewActionDialog::actionText() const { return m_ui->editActionText->text(); diff --git a/src/designer/src/lib/shared/newactiondialog_p.h b/src/designer/src/lib/shared/newactiondialog_p.h index 8eddcbe720..f6e3b1dd7f 100644 --- a/src/designer/src/lib/shared/newactiondialog_p.h +++ b/src/designer/src/lib/shared/newactiondialog_p.h @@ -89,6 +89,13 @@ class NewActionDialog: public QDialog QString actionText() const; QString actionName() const; +public slots: + void focusName(); + void focusText(); + void focusTooltip(); + void focusShortcut(); + void focusCheckable(); + private slots: void on_editActionText_textEdited(const QString &text); void on_editObjectName_textEdited(const QString &text); diff --git a/src/designer/src/lib/shared/newformwidget.cpp b/src/designer/src/lib/shared/newformwidget.cpp index b3853ae211..e049a06603 100644 --- a/src/designer/src/lib/shared/newformwidget.cpp +++ b/src/designer/src/lib/shared/newformwidget.cpp @@ -49,10 +49,10 @@ #include #include -#include #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -129,8 +129,6 @@ NewFormWidget::NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent m_currentItem(nullptr), m_acceptedItem(nullptr) { - using DeviceProfileList = QList; - m_ui->setupUi(this); m_ui->treeWidget->setItemDelegate(new qdesigner_internal::SheetDelegate(m_ui->treeWidget, this)); m_ui->treeWidget->header()->hide(); @@ -181,14 +179,13 @@ NewFormWidget::NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent m_deviceProfiles = settings.deviceProfiles(); m_ui->profileComboBox->addItem(tr("None")); connect(m_ui->profileComboBox, - QOverload::of(&QComboBox::currentIndexChanged), + &QComboBox::currentIndexChanged, this, &NewFormWidget::slotDeviceProfileIndexChanged); - if (m_deviceProfiles.empty()) { + if (m_deviceProfiles.isEmpty()) { m_ui->profileComboBox->setEnabled(false); } else { - const DeviceProfileList::const_iterator dcend = m_deviceProfiles.constEnd(); - for (DeviceProfileList::const_iterator it = m_deviceProfiles.constBegin(); it != dcend; ++it) - m_ui->profileComboBox->addItem(it->name()); + for (const auto &deviceProfile : qAsConst(m_deviceProfiles)) + m_ui->profileComboBox->addItem(deviceProfile.name()); const int ci = settings.currentDeviceProfileIndex(); if (ci >= 0) m_ui->profileComboBox->setCurrentIndex(ci + profileComboIndexOffset); @@ -262,11 +259,11 @@ QPixmap NewFormWidget::formPreviewPixmap(const QTreeWidgetItem *item) // file or string? const QVariant fileName = item->data(0, TemplateNameRole); QPixmap rc; - if (fileName.type() == QVariant::String) { + if (fileName.metaType().id() == QMetaType::QString) { rc = formPreviewPixmap(fileName.toString()); } else { const QVariant classNameV = item->data(0, ClassNameRole); - Q_ASSERT(classNameV.type() == QVariant::String); + Q_ASSERT(classNameV.metaType().id() == QMetaType::QString); const QString className = classNameV.toString(); QByteArray data = qdesigner_internal::WidgetDataBase::formTemplate(m_core, className, formName(className)).toUtf8(); QBuffer buffer(&data); @@ -314,7 +311,7 @@ QImage NewFormWidget::grabForm(QDesignerFormEditorInterface *core, QPixmap NewFormWidget::formPreviewPixmap(QIODevice &file, const QString &workingDir) const { - const QSizeF screenSize(QApplication::desktop()->screenGeometry(this).size()); + const QSizeF screenSize(screen()->geometry().size()); const int previewSize = qRound(screenSize.width() / 7.5); // 256 on 1920px screens. const int margin = previewSize / 32 - 1; // 7 on 1920px screens. const int shadow = margin; @@ -446,7 +443,7 @@ void NewFormWidget::loadFrom(const QString &path, bool resourceFile, const QStri void NewFormWidget::loadFrom(const QString &title, const QStringList &nameList, const QString &selectedItem, QTreeWidgetItem *&selectedItemFound) { - if (nameList.empty()) + if (nameList.isEmpty()) return; QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget); root->setFlags(root->flags() & ~Qt::ItemIsSelectable); @@ -495,7 +492,7 @@ QString NewFormWidget::itemToTemplate(const QTreeWidgetItem *item, QString *erro const QSize size = templateSize(); // file name or string contents? const QVariant templateFileName = item->data(0, TemplateNameRole); - if (templateFileName.type() == QVariant::String) { + if (templateFileName.metaType().id() == QMetaType::QString) { const QString fileName = templateFileName.toString(); // No fixed size: just open. if (size.isNull()) diff --git a/src/designer/src/lib/shared/newformwidget_p.h b/src/designer/src/lib/shared/newformwidget_p.h index f6daae1229..c7a5e2a084 100644 --- a/src/designer/src/lib/shared/newformwidget_p.h +++ b/src/designer/src/lib/shared/newformwidget_p.h @@ -46,11 +46,13 @@ #include #include + #include -#include -#include +#include #include +#include +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/plugindialog.cpp b/src/designer/src/lib/shared/plugindialog.cpp index 8f73099e76..de96d55d20 100644 --- a/src/designer/src/lib/shared/plugindialog.cpp +++ b/src/designer/src/lib/shared/plugindialog.cpp @@ -37,14 +37,23 @@ #include +#include #include #include +#include #include + +#if QT_CONFIG(clipboard) +# include +#endif + #include #include QT_BEGIN_NAMESPACE +enum { ErrorItemRole = Qt::UserRole + 1 }; + namespace qdesigner_internal { PluginDialog::PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent) @@ -64,6 +73,9 @@ PluginDialog::PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent) ui.treeWidget->setSelectionMode(QAbstractItemView::NoSelection); ui.treeWidget->setHeaderLabels(headerLabels); ui.treeWidget->header()->hide(); + ui.treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui.treeWidget, &QWidget::customContextMenuRequested, + this, &PluginDialog::treeWidgetContextMenu); interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On); @@ -101,7 +113,7 @@ void PluginDialog::populateTreeWidget() if (QObject *plugin = loader.instance()) { if (const QDesignerCustomWidgetCollectionInterface *c = qobject_cast(plugin)) { - const QList &collCustomWidgets = c->customWidgets(); + const auto &collCustomWidgets = c->customWidgets(); for (const QDesignerCustomWidgetInterface *p : collCustomWidgets) setItem(pluginItem, p->name(), p->toolTip(), p->whatsThis(), p->icon()); } else { @@ -118,8 +130,13 @@ void PluginDialog::populateTreeWidget() const QFont boldFont = topLevelItem->font(0); for (const QString &plugin : notLoadedPlugins) { const QString failureReason = pluginManager->failureReason(plugin); + const QString htmlFailureReason = QLatin1String("

") + + failureReason.toHtmlEscaped() + + QLatin1String("

"); QTreeWidgetItem *pluginItem = setPluginItem(topLevelItem, plugin, boldFont); - setItem(pluginItem, failureReason, failureReason, QString(), QIcon()); + auto errorItem = setItem(pluginItem, failureReason, + htmlFailureReason, QString(), QIcon()); + errorItem->setData(0, ErrorItemRole, QVariant(true)); } } @@ -157,14 +174,16 @@ QTreeWidgetItem* PluginDialog::setPluginItem(QTreeWidgetItem *topLevelItem, return pluginItem; } -void PluginDialog::setItem(QTreeWidgetItem *pluginItem, const QString &name, - const QString &toolTip, const QString &whatsThis, const QIcon &icon) +QTreeWidgetItem *PluginDialog::setItem(QTreeWidgetItem *pluginItem, const QString &name, + const QString &toolTip, const QString &whatsThis, + const QIcon &icon) { QTreeWidgetItem *item = new QTreeWidgetItem(pluginItem); item->setText(0, name); item->setToolTip(0, toolTip); item->setWhatsThis(0, whatsThis); item->setIcon(0, icon.isNull() ? qtLogoIcon() : icon); + return item; } void PluginDialog::updateCustomWidgetPlugins() @@ -181,6 +200,27 @@ void PluginDialog::updateCustomWidgetPlugins() populateTreeWidget(); } +void PluginDialog::treeWidgetContextMenu(const QPoint &pos) +{ +#if QT_CONFIG(clipboard) + const QTreeWidgetItem *item = ui.treeWidget->itemAt(pos); + if (item == nullptr || !item->data(0, ErrorItemRole).toBool()) + return; + QMenu menu; + //: Copy error text + auto copyAction = menu.addAction(tr("Copy")); + auto chosenAction = menu.exec(ui.treeWidget->mapToGlobal(pos)); + if (chosenAction == nullptr) + return; + if (chosenAction == copyAction) + QGuiApplication::clipboard()->setText(item->text(0)); +#else + Q_UNUSED(pos); +#endif } +} // namespace qdesigner_internal + QT_END_NAMESPACE + +#include "moc_plugindialog_p.cpp" diff --git a/src/designer/src/lib/shared/plugindialog_p.h b/src/designer/src/lib/shared/plugindialog_p.h index f51d044f87..939ce68b16 100644 --- a/src/designer/src/lib/shared/plugindialog_p.h +++ b/src/designer/src/lib/shared/plugindialog_p.h @@ -56,14 +56,16 @@ class PluginDialog : public QDialog private slots: void updateCustomWidgetPlugins(); + void treeWidgetContextMenu(const QPoint &pos); private: void populateTreeWidget(); QTreeWidgetItem* setTopLevelItem(const QString &itemName); QTreeWidgetItem* setPluginItem(QTreeWidgetItem *topLevelItem, const QString &itemName, const QFont &font); - void setItem(QTreeWidgetItem *pluginItem, const QString &name, - const QString &toolTip, const QString &whatsThis, const QIcon &icon); + QTreeWidgetItem *setItem(QTreeWidgetItem *pluginItem, const QString &name, + const QString &toolTip, const QString &whatsThis, + const QIcon &icon); QDesignerFormEditorInterface *m_core; Ui::PluginDialog ui; diff --git a/src/designer/src/lib/shared/pluginmanager.cpp b/src/designer/src/lib/shared/pluginmanager.cpp index ddc8cd611f..88b581862e 100644 --- a/src/designer/src/lib/shared/pluginmanager.cpp +++ b/src/designer/src/lib/shared/pluginmanager.cpp @@ -544,7 +544,7 @@ void QDesignerPluginManagerPrivate::addCustomWidgets(const QObject *o, return; } if (const QDesignerCustomWidgetCollectionInterface *coll = qobject_cast(o)) { - const QList &collCustomWidgets = coll->customWidgets(); + const auto &collCustomWidgets = coll->customWidgets(); for (QDesignerCustomWidgetInterface *c : collCustomWidgets) addCustomWidget(c, pluginPath, designerLanguage); } @@ -589,7 +589,7 @@ QStringList QDesignerPluginManager::findPlugins(const QString &path) return QStringList(); const QFileInfoList infoList = dir.entryInfoList(QDir::Files); - if (infoList.empty()) + if (infoList.isEmpty()) return QStringList(); // Load symbolic links but make sure all file names are unique as not @@ -738,7 +738,7 @@ void QDesignerPluginManager::ensureInitialized() m_d->clearCustomWidgets(); // Add the static custom widgets const QObjectList staticPluginObjects = QPluginLoader::staticInstances(); - if (!staticPluginObjects.empty()) { + if (!staticPluginObjects.isEmpty()) { const QString staticPluginPath = QCoreApplication::applicationFilePath(); for (QObject *o : staticPluginObjects) m_d->addCustomWidgets(o, staticPluginPath, designerLanguage); diff --git a/src/designer/src/lib/shared/previewconfigurationwidget.cpp b/src/designer/src/lib/shared/previewconfigurationwidget.cpp index f9ddb4b5e2..bf8d0b60e0 100644 --- a/src/designer/src/lib/shared/previewconfigurationwidget.cpp +++ b/src/designer/src/lib/shared/previewconfigurationwidget.cpp @@ -63,13 +63,13 @@ enum { SkinComboNoneIndex = 0 }; // find default skins (resources) static const Skins &defaultSkins() { static Skins rc; - if (rc.empty()) { + if (rc.isEmpty()) { const QString skinPath = QLatin1String(skinResourcePathC); QString pattern = QStringLiteral("*."); pattern += QLatin1String(skinExtensionC); const QDir dir(skinPath, pattern); const QFileInfoList list = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name); - if (list.empty()) + if (list.isEmpty()) return rc; const QFileInfoList::const_iterator lcend = list.constEnd(); for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it) @@ -144,9 +144,8 @@ PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::PreviewConfigurat Skins skins = defaultSkins(); skins.push_front(SkinNamePath(PreviewConfigurationWidget::tr("None"), QString())); - const Skins::const_iterator scend = skins.constEnd(); - for (Skins::const_iterator it = skins.constBegin(); it != scend; ++it) - m_ui.m_skinCombo->addItem (it->first, QVariant(it->second)); + for (const auto &skin : qAsConst(skins)) + m_ui.m_skinCombo->addItem(skin.first, QVariant(skin.second)); m_browseSkinIndex = m_firstUserSkinIndex = skins.size(); m_ui.m_skinCombo->addItem(PreviewConfigurationWidget::tr("Browse..."), QString()); @@ -171,7 +170,7 @@ QStringList PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::userS void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::addUserSkins(const QStringList &files) { - if (files.empty()) + if (files.isEmpty()) return; const QStringList ::const_iterator fcend = files.constEnd(); for (QStringList::const_iterator it = files.constBegin(); it != fcend; ++it) { @@ -281,7 +280,7 @@ int PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::browseSkin() break; // check: 1) name already there - const QString directory = directories.front(); + const QString directory = directories.constFirst(); const QString name = QFileInfo(directory).baseName(); const int existingIndex = m_ui.m_skinCombo->findText(name); if (existingIndex != -1 && existingIndex != SkinComboNoneIndex && existingIndex != m_browseSkinIndex) { @@ -318,7 +317,7 @@ PreviewConfigurationWidget::PreviewConfigurationWidget(QDesignerFormEditorInterf this, &PreviewConfigurationWidget::slotEditAppStyleSheet); connect(m_impl->skinRemoveButton(), &QAbstractButton::clicked, this, &PreviewConfigurationWidget::slotDeleteSkinEntry); - connect(m_impl->skinCombo(), QOverload::of(&QComboBox::currentIndexChanged), + connect(m_impl->skinCombo(), &QComboBox::currentIndexChanged, this, &PreviewConfigurationWidget::slotSkinChanged); m_impl->retrieveSettings(); diff --git a/src/designer/src/lib/shared/previewmanager.cpp b/src/designer/src/lib/shared/previewmanager.cpp index 741fe455a2..3d04346f30 100644 --- a/src/designer/src/lib/shared/previewmanager.cpp +++ b/src/designer/src/lib/shared/previewmanager.cpp @@ -26,38 +26,38 @@ ** ****************************************************************************/ +#include "formwindowbase_p.h" #include "previewmanager_p.h" #include "qdesigner_formbuilder_p.h" #include "shared_settings_p.h" -#include "shared_settings_p.h" -#include "zoomwidget_p.h" -#include "formwindowbase_p.h" #include "widgetfactory_p.h" +#include "zoomwidget_p.h" #include -#include #include +#include #include #include -#include -#include -#include -#include -#include #include -#include #include #include +#include +#include #include -#include -#include + +#include +#include #include -#include +#include +#include +#include +#include -#include #include +#include +#include #include QT_BEGIN_NAMESPACE @@ -168,7 +168,7 @@ private slots: virtual void fitWidget(const QSize &size); // Calculate the complete transformation for the skin // (base class implementation provides rotation). - virtual QMatrix skinTransform() const; + virtual QTransform skinTransform() const; private: const QSize m_screenSize; @@ -207,7 +207,7 @@ void PreviewDeviceSkin::setPreview(QWidget *formWidget) void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep) { if (QWidget *focusWidget = QApplication::focusWidget()) { - QKeyEvent e(QEvent::KeyPress, code, nullptr, text, autorep); + QKeyEvent e(QEvent::KeyPress, code, {}, text, autorep); QApplication::sendEvent(focusWidget, &e); } } @@ -215,7 +215,7 @@ void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, boo void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) { if (QWidget *focusWidget = QApplication::focusWidget()) { - QKeyEvent e(QEvent::KeyRelease, code, nullptr, text, autorep); + QKeyEvent e(QEvent::KeyRelease, code, {}, text, autorep); QApplication::sendEvent(focusWidget, &e); } } @@ -285,9 +285,9 @@ void PreviewDeviceSkin::fitWidget(const QSize &size) view()->setFixedSize(size); } -QMatrix PreviewDeviceSkin::skinTransform() const +QTransform PreviewDeviceSkin::skinTransform() const { - QMatrix newTransform; + QTransform newTransform; switch (m_direction) { case DirectionUp: break; @@ -341,7 +341,7 @@ public slots: protected: void populateContextMenu(QMenu *m) override; - QMatrix skinTransform() const override; + QTransform skinTransform() const override; void fitWidget(const QSize &size) override; private: @@ -414,10 +414,10 @@ void ZoomablePreviewDeviceSkin::populateContextMenu(QMenu *menu) menu->addSeparator(); } -QMatrix ZoomablePreviewDeviceSkin::skinTransform() const +QTransform ZoomablePreviewDeviceSkin::skinTransform() const { // Complete transformation consisting of base class rotation and zoom. - QMatrix rc = PreviewDeviceSkin::skinTransform(); + QTransform rc = PreviewDeviceSkin::skinTransform(); const int zp = zoomPercent(); if (zp != 100) { const qreal factor = zoomFactor(zp); @@ -622,10 +622,9 @@ static QWidget *fakeContainer(QWidget *w) dock->setFeatures(dock->features() & ~(QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetClosable)); dock->setAllowedAreas(Qt::LeftDockWidgetArea); QMainWindow *mw = new QMainWindow; - int leftMargin, topMargin, rightMargin, bottomMargin; - mw->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + const QMargins cm = mw->contentsMargins(); mw->addDockWidget(Qt::LeftDockWidgetArea, dock); - mw->resize(size + QSize(leftMargin + rightMargin, topMargin + bottomMargin)); + mw->resize(size + QSize(cm.left() + cm.right(), cm.top() + cm.bottom())); return mw; } return w; @@ -773,14 +772,13 @@ QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, // If its the first one, position relative to form. // 2nd, attempt to tile right (for comparing styles) or cascade const QSize size = widget->size(); - const bool firstPreview = d->m_previews.empty(); + const bool firstPreview = d->m_previews.isEmpty(); if (firstPreview) { widget->move(fw->mapToGlobal(QPoint(Spacing, Spacing))); } else { - if (QWidget *lastPreview = d->m_previews.back().m_widget) { - QDesktopWidget *desktop = qApp->desktop(); + if (QWidget *lastPreview = d->m_previews.constLast().m_widget) { const QRect lastPreviewGeometry = lastPreview->frameGeometry(); - const QRect availGeometry = desktop->availableGeometry(lastPreview); + const QRect availGeometry = lastPreview->screen()->availableGeometry(); const QPoint newPos = lastPreviewGeometry.topRight() + QPoint(Spacing, 0); if (newPos.x() + size.width() < availGeometry.right()) widget->move(newPos); @@ -799,7 +797,7 @@ QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, QWidget *PreviewManager::raise(const QDesignerFormWindowInterface *fw, const PreviewConfiguration &pc) { using PreviewDataList = PreviewManagerPrivate::PreviewDataList; - if (d->m_previews.empty()) + if (d->m_previews.isEmpty()) return nullptr; // find matching window @@ -817,7 +815,7 @@ QWidget *PreviewManager::raise(const QDesignerFormWindowInterface *fw, const Pre void PreviewManager::closeAllPreviews() { - if (!d->m_previews.empty()) { + if (!d->m_previews.isEmpty()) { d->m_updateBlocked = true; d->m_activePreview = nullptr; for (auto it = d->m_previews.constBegin(), cend = d->m_previews.constEnd(); it != cend ;++it) { @@ -844,7 +842,7 @@ void PreviewManager::updatePreviewClosed(QWidget *w) ++it; } } - if (d->m_previews.empty()) + if (d->m_previews.isEmpty()) emit lastPreviewClosed(); } diff --git a/src/designer/src/lib/shared/promotionmodel.cpp b/src/designer/src/lib/shared/promotionmodel.cpp index c2dd255236..37136ced65 100644 --- a/src/designer/src/lib/shared/promotionmodel.cpp +++ b/src/designer/src/lib/shared/promotionmodel.cpp @@ -129,7 +129,7 @@ namespace qdesigner_internal { // Set the item index as user data on the item. const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses(); - if (promotedClasses.empty()) + if (promotedClasses.isEmpty()) return; const QSet usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames(); @@ -143,7 +143,7 @@ namespace qdesigner_internal { if (baseClass != it->baseItem) { baseClass = it->baseItem; const StandardItemList baseRow = baseModelRow(it->baseItem); - baseItem = baseRow.front(); + baseItem = baseRow.constFirst(); appendRow(baseRow); } Q_ASSERT(baseItem); @@ -187,7 +187,7 @@ namespace qdesigner_internal { QModelIndex PromotionModel::indexOfClass(const QString &className) const { const StandardItemList matches = findItems (className, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive); - return matches.empty() ? QModelIndex() : indexFromItem (matches.front()); + return matches.isEmpty() ? QModelIndex() : indexFromItem (matches.constFirst()); } } // namespace qdesigner_internal diff --git a/src/designer/src/lib/shared/promotiontaskmenu.cpp b/src/designer/src/lib/shared/promotiontaskmenu.cpp index bb5631d322..c458d2604a 100644 --- a/src/designer/src/lib/shared/promotiontaskmenu.cpp +++ b/src/designer/src/lib/shared/promotiontaskmenu.cpp @@ -42,9 +42,11 @@ #include #include -#include #include #include + +#include + #include QT_BEGIN_NAMESPACE @@ -111,7 +113,7 @@ void PromotionTaskMenu::setDemoteLabel(const QString &demoteLabel) PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDesignerFormWindowInterface *formWindow) { // clear out old - if (!m_promotionActions.empty()) { + if (!m_promotionActions.isEmpty()) { qDeleteAll(m_promotionActions); m_promotionActions.clear(); } @@ -122,7 +124,7 @@ PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDe // Check for a homogenous selection const PromotionSelectionList promotionSelection = promotionSelectionList(formWindow); - if (promotionSelection.empty()) + if (promotionSelection.isEmpty()) return NoHomogenousSelection; QDesignerFormEditorInterface *core = formWindow->core(); @@ -137,7 +139,7 @@ PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDe // figure out candidates const QString baseClassName = WidgetFactory::classNameOf(core, m_widget); const WidgetDataBaseItemList candidates = promotionCandidates(core->widgetDataBase(), baseClassName ); - if (candidates.empty()) { + if (candidates.isEmpty()) { // Is this thing promotable at all? return QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(baseClassName) ? CanPromote : NotApplicable; } @@ -230,7 +232,7 @@ void PromotionTaskMenu::slotDemoteFromCustomWidget() { QDesignerFormWindowInterface *fw = formWindow(); const PromotionSelectionList promotedWidgets = promotionSelectionList(fw); - Q_ASSERT(!promotedWidgets.empty() && isPromoted(fw->core(), promotedWidgets.front())); + Q_ASSERT(!promotedWidgets.isEmpty() && isPromoted(fw->core(), promotedWidgets.constFirst())); // ### use the undo stack DemoteFromCustomWidgetCommand *cmd = new DemoteFromCustomWidgetCommand(fw); diff --git a/src/designer/src/lib/shared/promotiontaskmenu_p.h b/src/designer/src/lib/shared/promotiontaskmenu_p.h index 8309869681..ee9f53db03 100644 --- a/src/designer/src/lib/shared/promotiontaskmenu_p.h +++ b/src/designer/src/lib/shared/promotiontaskmenu_p.h @@ -42,9 +42,9 @@ #include "shared_global_p.h" +#include #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_command.cpp b/src/designer/src/lib/shared/qdesigner_command.cpp index 7346b98f36..04cbfeff34 100644 --- a/src/designer/src/lib/shared/qdesigner_command.cpp +++ b/src/designer/src/lib/shared/qdesigner_command.cpp @@ -232,18 +232,15 @@ void InsertWidgetCommand::undo() void InsertWidgetCommand::refreshBuddyLabels() { - using LabelList = QList; - - const LabelList label_list = formWindow()->findChildren(); - if (label_list.empty()) + const auto label_list = formWindow()->findChildren(); + if (label_list.isEmpty()) return; const QString buddyProperty = QStringLiteral("buddy"); const QByteArray objectNameU8 = m_widget->objectName().toUtf8(); // Re-set the buddy (The sheet locates the object by name and sets it) - const LabelList::const_iterator cend = label_list.constEnd(); - for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) { - if (QDesignerPropertySheetExtension* sheet = propertySheet(*it)) { + for (QLabel *label : label_list) { + if (QDesignerPropertySheetExtension* sheet = propertySheet(label)) { const int idx = sheet->indexOf(buddyProperty); if (idx != -1) { const QVariant value = sheet->property(idx); @@ -350,7 +347,7 @@ void ManageWidgetCommandHelper::init(const QDesignerFormWindowInterface *fw, QWi m_managedChildren.clear(); const QWidgetList children = m_widget->findChildren(); - if (children.empty()) + if (children.isEmpty()) return; m_managedChildren.reserve(children.size()); @@ -370,7 +367,7 @@ void ManageWidgetCommandHelper::manage(QDesignerFormWindowInterface *fw) { // Manage the managed children after parent fw->manageWidget(m_widget); - if (!m_managedChildren.empty()) { + if (!m_managedChildren.isEmpty()) { const WidgetVector::const_iterator lcend = m_managedChildren.constEnd(); for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it) fw->manageWidget(*it); @@ -380,7 +377,7 @@ void ManageWidgetCommandHelper::manage(QDesignerFormWindowInterface *fw) void ManageWidgetCommandHelper::unmanage(QDesignerFormWindowInterface *fw) { // Unmanage the managed children first - if (!m_managedChildren.empty()) { + if (!m_managedChildren.isEmpty()) { const WidgetVector::const_iterator lcend = m_managedChildren.constEnd(); for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it) fw->unmanageWidget(*it); @@ -665,7 +662,7 @@ DemoteFromCustomWidgetCommand::DemoteFromCustomWidgetCommand void DemoteFromCustomWidgetCommand::init(const WidgetList &promoted) { - m_promote_cmd.init(promoted, promotedCustomClassName(core(), promoted.front())); + m_promote_cmd.init(promoted, promotedCustomClassName(core(), promoted.constFirst())); } void DemoteFromCustomWidgetCommand::redo() @@ -695,7 +692,7 @@ void CursorSelectionState::save(const QDesignerFormWindowInterface *formWindow) void CursorSelectionState::restore(QDesignerFormWindowInterface *formWindow) const { - if (m_selection.empty()) { + if (m_selection.isEmpty()) { formWindow->clearSelection(true); } else { // Select current as last @@ -2656,7 +2653,7 @@ static RemoveActionCommand::ActionData findActionIn(QAction *action) const QWidgetList &associatedWidgets = action->associatedWidgets(); for (QWidget *widget : associatedWidgets) { if (qobject_cast(widget) || qobject_cast(widget)) { - const QList actionList = widget->actions(); + const auto actionList = widget->actions(); const int size = actionList.size(); for (int i = 0; i < size; ++i) { if (actionList.at(i) == action) { @@ -2692,7 +2689,7 @@ void RemoveActionCommand::redo() core()->actionEditor()->setFormWindow(fw); core()->actionEditor()->unmanageAction(m_action); - if (!m_actionData.empty()) + if (!m_actionData.isEmpty()) core()->objectInspector()->setFormWindow(fw); } @@ -2702,7 +2699,7 @@ void RemoveActionCommand::undo() core()->actionEditor()->manageAction(m_action); for (const ActionDataItem &item : qAsConst(m_actionData)) item.widget->insertAction(item.before, m_action); - if (!m_actionData.empty()) + if (!m_actionData.isEmpty()) core()->objectInspector()->setFormWindow(formWindow()); } diff --git a/src/designer/src/lib/shared/qdesigner_command2.cpp b/src/designer/src/lib/shared/qdesigner_command2.cpp index e956e7d92d..ac035f6ecf 100644 --- a/src/designer/src/lib/shared/qdesigner_command2.cpp +++ b/src/designer/src/lib/shared/qdesigner_command2.cpp @@ -143,7 +143,7 @@ QString MorphLayoutCommand::formatDescription(QDesignerFormEditorInterface * /* LayoutAlignmentCommand::LayoutAlignmentCommand(QDesignerFormWindowInterface *formWindow) : QDesignerFormWindowCommand(QApplication::translate("Command", "Change layout alignment"), formWindow), - m_newAlignment(nullptr), m_oldAlignment(nullptr), m_widget(nullptr) + m_widget(nullptr) { } @@ -180,7 +180,7 @@ Qt::Alignment LayoutAlignmentCommand::alignmentOf(const QDesignerFormEditorInter (type == LayoutInfo::HBox || type == LayoutInfo::VBox || type == LayoutInfo::Grid); if (!enabled) - return Qt::Alignment(nullptr); + return {}; // Get alignment const int index = layout->indexOf(w); Q_ASSERT(index >= 0); diff --git a/src/designer/src/lib/shared/qdesigner_command_p.h b/src/designer/src/lib/shared/qdesigner_command_p.h index 8053c8918c..578c001ba0 100644 --- a/src/designer/src/lib/shared/qdesigner_command_p.h +++ b/src/designer/src/lib/shared/qdesigner_command_p.h @@ -40,20 +40,22 @@ #ifndef QDESIGNER_COMMAND_H #define QDESIGNER_COMMAND_H -#include "shared_global_p.h" -#include "shared_enums_p.h" #include "layoutinfo_p.h" -#include "qdesigner_utils_p.h" -#include "qdesigner_formwindowcommand_p.h" #include "qdesigner_formeditorcommand_p.h" +#include "qdesigner_formwindowcommand_p.h" +#include "qdesigner_utils_p.h" +#include "shared_enums_p.h" +#include "shared_global_p.h" #include #include + +#include +#include +#include #include #include -#include -#include #include #include @@ -179,7 +181,7 @@ class QDESIGNER_SHARED_EXPORT AdjustWidgetSizeCommand: public QDesignerFormWindo // Helper to correctly unmanage a widget and its children for delete operations class QDESIGNER_SHARED_EXPORT ManageWidgetCommandHelper { public: - using WidgetVector = QVector; + using WidgetVector = QList; ManageWidgetCommandHelper(); void init(const QDesignerFormWindowInterface *fw, QWidget *widget); @@ -752,7 +754,7 @@ class DockWidgetCommand: public QDesignerFormWindowCommand QPointer m_dockWidget; }; -class AddDockWidgetCommand: public QDesignerFormWindowCommand +class QDESIGNER_SHARED_EXPORT AddDockWidgetCommand: public QDesignerFormWindowCommand { public: diff --git a/src/designer/src/lib/shared/qdesigner_dnditem.cpp b/src/designer/src/lib/shared/qdesigner_dnditem.cpp index db714d9501..4a7864372f 100644 --- a/src/designer/src/lib/shared/qdesigner_dnditem.cpp +++ b/src/designer/src/lib/shared/qdesigner_dnditem.cpp @@ -206,7 +206,7 @@ Qt::DropAction QDesignerMimeData::proposedDropAction() const Qt::DropAction QDesignerMimeData::execDrag(const QDesignerDnDItems &items, QWidget * dragSource) { - if (items.empty()) + if (items.isEmpty()) return Qt::IgnoreAction; QDrag *drag = new QDrag(dragSource); @@ -253,7 +253,7 @@ void QDesignerMimeData::removeMovedWidgetsFromSourceForm(const QDesignerDnDItems if (FormWindowBase *fb = qobject_cast((*it)->source())) formWidgetMap.insert(fb, w); - const QList &formWindows = formWidgetMap.uniqueKeys(); + const auto &formWindows = formWidgetMap.uniqueKeys(); for (FormWindowBase *fb : formWindows) fb->deleteWidgetList(formWidgetMap.values(fb)); } diff --git a/src/designer/src/lib/shared/qdesigner_dockwidget.cpp b/src/designer/src/lib/shared/qdesigner_dockwidget.cpp index 278f9b8293..d29fcaba25 100644 --- a/src/designer/src/lib/shared/qdesigner_dockwidget.cpp +++ b/src/designer/src/lib/shared/qdesigner_dockwidget.cpp @@ -35,11 +35,23 @@ #include #include +#include + #include #include QT_BEGIN_NAMESPACE +bool QDockWidgetPropertySheet::isEnabled(int index) const +{ + const QString &name = propertyName(index); + if (name == QLatin1String("dockWidgetArea")) + return static_cast(object())->docked(); + if (name == QLatin1String("docked")) + return static_cast(object())->inMainWindow(); + return QDesignerPropertySheet::isEnabled(index); +} + QDesignerDockWidget::QDesignerDockWidget(QWidget *parent) : QDockWidget(parent) { diff --git a/src/designer/src/lib/shared/qdesigner_dockwidget_p.h b/src/designer/src/lib/shared/qdesigner_dockwidget_p.h index 7db3324958..a39ece90d9 100644 --- a/src/designer/src/lib/shared/qdesigner_dockwidget_p.h +++ b/src/designer/src/lib/shared/qdesigner_dockwidget_p.h @@ -41,6 +41,9 @@ #define QDESIGNER_DOCKWIDGET_H #include "shared_global_p.h" + +#include + #include QT_BEGIN_NAMESPACE @@ -50,8 +53,8 @@ class QDesignerFormWindowInterface; class QDESIGNER_SHARED_EXPORT QDesignerDockWidget: public QDockWidget { Q_OBJECT - Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea DESIGNABLE docked STORED false) - Q_PROPERTY(bool docked READ docked WRITE setDocked DESIGNABLE inMainWindow STORED false) + Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea DESIGNABLE true STORED false) + Q_PROPERTY(bool docked READ docked WRITE setDocked DESIGNABLE true STORED false) public: QDesignerDockWidget(QWidget *parent = nullptr); ~QDesignerDockWidget() override; @@ -69,6 +72,18 @@ class QDESIGNER_SHARED_EXPORT QDesignerDockWidget: public QDockWidget QMainWindow *findMainWindow() const; }; +class QDESIGNER_SHARED_EXPORT QDockWidgetPropertySheet : public QDesignerPropertySheet +{ + Q_OBJECT +public: + using QDesignerPropertySheet::QDesignerPropertySheet; + + bool isEnabled(int index) const override; +}; + +using QDockWidgetPropertySheetFactory = + QDesignerPropertySheetFactory; + QT_END_NAMESPACE #endif // QDESIGNER_DOCKWIDGET_H diff --git a/src/designer/src/lib/shared/qdesigner_formbuilder.cpp b/src/designer/src/lib/shared/qdesigner_formbuilder.cpp index 260316381a..3b25125afa 100644 --- a/src/designer/src/lib/shared/qdesigner_formbuilder.cpp +++ b/src/designer/src/lib/shared/qdesigner_formbuilder.cpp @@ -226,7 +226,7 @@ static bool readDomEnumerationValue(const DomProperty *p, void QDesignerFormBuilder::applyProperties(QObject *o, const QList &properties) { - if (properties.empty()) + if (properties.isEmpty()) return; const QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), o); diff --git a/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h b/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h index e6ee083018..071c090c69 100644 --- a/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h +++ b/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h @@ -41,8 +41,11 @@ #define QDESIGNER_FORMEDITORCOMMAND_H #include "shared_global_p.h" + +#include + #include -#include + QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp b/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp index 7c44ec4f78..190540db25 100644 --- a/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp +++ b/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp @@ -100,19 +100,17 @@ void QDesignerFormWindowCommand::updateBuddies(QDesignerFormWindowInterface *for { QExtensionManager* extensionManager = form->core()->extensionManager(); - using LabelList = QList; - - const LabelList label_list = form->findChildren(); - if (label_list.empty()) + const auto label_list = form->findChildren(); + if (label_list.isEmpty()) return; const QString buddyProperty = QStringLiteral("buddy"); const QByteArray oldNameU8 = old_name.toUtf8(); const QByteArray newNameU8 = new_name.toUtf8(); - const LabelList::const_iterator cend = label_list.constEnd(); - for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) { - if (QDesignerPropertySheetExtension* sheet = qt_extension(extensionManager, *it)) { + for (QLabel *label : label_list) { + if (QDesignerPropertySheetExtension* sheet = + qt_extension(extensionManager, label)) { const int idx = sheet->indexOf(buddyProperty); if (idx != -1) { const QByteArray oldBuddy = sheet->property(idx).toByteArray(); diff --git a/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h b/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h index bccc11d1b6..ff53287928 100644 --- a/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h +++ b/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h @@ -42,8 +42,9 @@ #include "shared_global_p.h" +#include + #include -#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp b/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp index 91332b0ecf..243a2cac7c 100644 --- a/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp +++ b/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp @@ -38,6 +38,7 @@ using namespace qdesigner_internal; /*! \class qdesigner_internal::QDesignerFormWindowManager \inmodule QtDesigner + \internal Extends QDesignerFormWindowManagerInterface with methods to control the preview and printing of forms. It provides a facade that simplifies diff --git a/src/designer/src/lib/shared/qdesigner_introspection.cpp b/src/designer/src/lib/shared/qdesigner_introspection.cpp index 3001d6b767..89dc6350e5 100644 --- a/src/designer/src/lib/shared/qdesigner_introspection.cpp +++ b/src/designer/src/lib/shared/qdesigner_introspection.cpp @@ -28,16 +28,16 @@ #include "qdesigner_introspection_p.h" +#include #include #include -#include QT_BEGIN_NAMESPACE // Qt Implementation static QStringList byteArrayListToStringList(const QByteArrayList &l) { - if (l.empty()) + if (l.isEmpty()) return QStringList(); QStringList rc; for (const QByteArray &b : l) @@ -99,9 +99,9 @@ namespace { Kind kind() const override { return m_kind; } AccessFlags accessFlags() const override { return m_access; } - Attributes attributes(const QObject *object = nullptr) const override; + Attributes attributes() const override; - QVariant::Type type() const override { return m_property.type(); } + int type() const override { return m_property.metaType().id(); } QString name() const override { return m_name; } QString typeName() const override { return m_typeName; } int userType() const override { return m_property.userType(); } @@ -162,20 +162,9 @@ namespace { delete m_enumerator; } - QDesignerMetaProperty::Attributes QDesignerMetaProperty::attributes(const QObject *object) const + QDesignerMetaProperty::Attributes QDesignerMetaProperty::attributes() const { - if (!object) - return m_defaultAttributes; - Attributes rc; - if (m_property.isDesignable(object)) - rc |= DesignableAttribute; - if (m_property.isScriptable(object)) - rc |= ScriptableAttribute; - if (m_property.isStored(object)) - rc |= StoredAttribute; - if (m_property.isUser(object)) - rc |= UserAttribute; - return rc; + return m_defaultAttributes; } // -------------- QDesignerMetaMethod @@ -283,13 +272,13 @@ namespace { const qdesigner_internal::QDesignerIntrospection *m_introspection; const QMetaObject *m_metaObject; - using Enumerators = QVector; + using Enumerators = QList; Enumerators m_enumerators; - using Methods = QVector; + using Methods = QList; Methods m_methods; - using Properties = QVector; + using Properties = QList; Properties m_properties; QDesignerMetaPropertyInterface *m_userProperty; diff --git a/src/designer/src/lib/shared/qdesigner_membersheet.cpp b/src/designer/src/lib/shared/qdesigner_membersheet.cpp index 93371ac068..2e62aab7f1 100644 --- a/src/designer/src/lib/shared/qdesigner_membersheet.cpp +++ b/src/designer/src/lib/shared/qdesigner_membersheet.cpp @@ -36,7 +36,7 @@ QT_BEGIN_NAMESPACE static QList stringListToByteArray(const QStringList &l) { - if (l.empty()) + if (l.isEmpty()) return QList(); QList rc; const QStringList::const_iterator cend = l.constEnd(); diff --git a/src/designer/src/lib/shared/qdesigner_menu.cpp b/src/designer/src/lib/shared/qdesigner_menu.cpp index 88668ea453..35a116bae0 100644 --- a/src/designer/src/lib/shared/qdesigner_menu.cpp +++ b/src/designer/src/lib/shared/qdesigner_menu.cpp @@ -37,23 +37,24 @@ #include "qdesigner_utils_p.h" #include "qdesigner_objectinspector_p.h" -#include -#include - #include #include #include #include -#include #include #include -#include -#include #include #include #include + +#include +#include #include +#include + +#include +#include Q_DECLARE_METATYPE(QAction*) @@ -295,7 +296,7 @@ bool QDesignerMenu::handleKeyPressEvent(QWidget * /*widget*/, QKeyEvent *e) static void sendMouseEventTo(QWidget *target, const QPoint &targetPoint, const QMouseEvent *event) { - QMouseEvent e(event->type(), targetPoint, event->globalPos(), event->button(), event->buttons(), event->modifiers()); + QMouseEvent e(event->type(), targetPoint, event->globalPosition().toPoint(), event->button(), event->buttons(), event->modifiers()); QApplication::sendEvent(target, &e); } @@ -307,13 +308,13 @@ bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) return true; - if (!rect().contains(event->pos())) { + if (!rect().contains(event->position().toPoint())) { // special case for menubar - QWidget *target = QApplication::widgetAt(event->globalPos()); + QWidget *target = QApplication::widgetAt(event->globalPosition().toPoint()); QMenuBar *mb = qobject_cast(target); QDesignerMenu *menu = qobject_cast(target); if (mb != nullptr || menu != nullptr) { - const QPoint pt = target->mapFromGlobal(event->globalPos()); + const QPoint pt = target->mapFromGlobal(event->globalPosition().toPoint()); QAction *action = mb == nullptr ? menu->actionAt(pt) : mb->actionAt(pt); if (action) sendMouseEventTo(target, pt, event); @@ -321,7 +322,7 @@ bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) return true; } - m_currentIndex = findAction(event->pos()); + m_currentIndex = findAction(event->position().toPoint()); QAction *action = safeActionAt(m_currentIndex); QRect pm_rect; @@ -330,7 +331,7 @@ bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) extendClickableArea(&pm_rect, layoutDirection()); } - if (!pm_rect.contains(event->pos()) && m_currentIndex != -1) + if (!pm_rect.contains(event->position().toPoint()) && m_currentIndex != -1) enterEditMode(); return true; @@ -338,10 +339,10 @@ bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *event) { - if (!rect().contains(event->pos())) { - QWidget *clickedWidget = QApplication::widgetAt(event->globalPos()); + if (!rect().contains(event->position().toPoint())) { + QWidget *clickedWidget = QApplication::widgetAt(event->globalPosition().toPoint()); if (QMenuBar *mb = qobject_cast(clickedWidget)) { - const QPoint pt = mb->mapFromGlobal(event->globalPos()); + const QPoint pt = mb->mapFromGlobal(event->globalPosition().toPoint()); if (QAction *action = mb->actionAt(pt)) { QMenu * menu = action->menu(); if (menu == findRootMenu()) { @@ -354,7 +355,7 @@ bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *eve if (QDesignerMenu *m = qobject_cast(clickedWidget)) { m->hideSubMenu(); - sendMouseEventTo(m, m->mapFromGlobal(event->globalPos()), event); + sendMouseEventTo(m, m->mapFromGlobal(event->globalPosition().toPoint()), event); } else { QDesignerMenu *root = findRootMenu(); root->hide(); @@ -376,7 +377,7 @@ bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *eve if (event->button() != Qt::LeftButton) return true; - m_startPosition = mapFromGlobal(event->globalPos()); + m_startPosition = mapFromGlobal(event->globalPosition().toPoint()); const int index = findAction(m_startPosition); @@ -421,10 +422,10 @@ bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event) if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) return true; - if (!rect().contains(event->pos())) { + if (!rect().contains(event->position().toPoint())) { - if (QMenuBar *mb = qobject_cast(QApplication::widgetAt(event->globalPos()))) { - const QPoint pt = mb->mapFromGlobal(event->globalPos()); + if (QMenuBar *mb = qobject_cast(QApplication::widgetAt(event->globalPosition().toPoint()))) { + const QPoint pt = mb->mapFromGlobal(event->globalPosition().toPoint()); QAction *action = mb->actionAt(pt); if (action && action->menu() == findRootMenu()) { // propagate the mouse press event (but don't close the popup) @@ -442,7 +443,7 @@ bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event) event->accept(); - const QPoint pos = mapFromGlobal(event->globalPos()); + const QPoint pos = mapFromGlobal(event->globalPosition().toPoint()); if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance()) return true; @@ -568,7 +569,7 @@ void QDesignerMenu::paintEvent(QPaintEvent *event) QAction *current = currentAction(); - const QList &actionList = actions(); + const auto &actionList = actions(); for (QAction *a : actionList) { const QRect g = actionGeometry(a); @@ -708,7 +709,7 @@ QDesignerMenu::ActionDragCheck QDesignerMenu::checkAction(QAction *action) const void QDesignerMenu::dragEnterEvent(QDragEnterEvent *event) { const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); - if (!d || d->actionList().empty()) { + if (!d || d->actionList().isEmpty()) { event->ignore(); return; } @@ -726,21 +727,21 @@ void QDesignerMenu::dragEnterEvent(QDragEnterEvent *event) case AcceptActionDrag: d->accept(event); m_dragging = true; - adjustIndicator(event->pos()); + adjustIndicator(event->position().toPoint()); break; } } void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event) { - if (actionGeometry(m_addSeparator).contains(event->pos())) { + if (actionGeometry(m_addSeparator).contains(event->position().toPoint())) { event->ignore(); adjustIndicator(QPoint(-1, -1)); return; } const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); - if (!d || d->actionList().empty()) { + if (!d || d->actionList().isEmpty()) { event->ignore(); return; } @@ -753,14 +754,14 @@ void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event) break; case ActionDragOnSubMenu: case AcceptActionDrag: { // Do not pop up submenu of action being dragged - const int newIndex = findAction(event->pos()); + const int newIndex = findAction(event->position().toPoint()); if (safeActionAt(newIndex) != action) { m_currentIndex = newIndex; if (m_lastSubMenuIndex != m_currentIndex) m_showSubMenuTimer->start(300); } if (dc == AcceptActionDrag) { - adjustIndicator(event->pos()); + adjustIndicator(event->position().toPoint()); d->accept(event); } else { event->ignore(); @@ -785,14 +786,14 @@ void QDesignerMenu::dropEvent(QDropEvent *event) QDesignerFormWindowInterface *fw = formWindow(); const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); - if (!d || d->actionList().empty()) { + if (!d || d->actionList().isEmpty()) { event->ignore(); return; } QAction *action = d->actionList().first(); if (action && checkAction(action) == AcceptActionDrag) { event->acceptProposedAction(); - int index = findAction(event->pos()); + int index = findAction(event->position().toPoint()); index = qMin(index, actions().count() - 1); fw->beginCommand(tr("Insert action")); @@ -851,7 +852,7 @@ void QDesignerMenu::closeMenuChain() w = w->parentWidget(); if (w) { - const QList &menus = w->findChildren(); + const auto &menus = w->findChildren(); for (QMenu *subMenu : menus) subMenu->hide(); } @@ -957,17 +958,26 @@ void QDesignerMenu::selectCurrentAction() return; QDesignerObjectInspector *oi = nullptr; - if (QDesignerFormWindowInterface *fw = formWindow()) - oi = qobject_cast(fw->core()->objectInspector()); + ActionEditor *ae = nullptr; + if (QDesignerFormWindowInterface *fw = formWindow()) { + auto core = fw->core(); + oi = qobject_cast(core->objectInspector()); + ae = qobject_cast(core->actionEditor()); + } if (!oi) return; oi->clearSelection(); - if (QMenu *menu = action->menu()) + if (QMenu *menu = action->menu()) { oi->selectObject(menu); - else + if (ae) + ae->clearSelection(); + } else { oi->selectObject(action); + if (ae) + ae->selectAction(action); + } } void QDesignerMenu::createRealMenuAction(QAction *action) @@ -1298,7 +1308,7 @@ QAction *QDesignerMenu::safeActionAt(int index) const void QDesignerMenu::hideSubMenu() { m_lastSubMenuIndex = -1; - const QList &menus = findChildren(); + const auto &menus = findChildren(); for (QMenu *subMenu : menus) subMenu->hide(); } diff --git a/src/designer/src/lib/shared/qdesigner_menu_p.h b/src/designer/src/lib/shared/qdesigner_menu_p.h index 5fc8f3c8e0..1093961eba 100644 --- a/src/designer/src/lib/shared/qdesigner_menu_p.h +++ b/src/designer/src/lib/shared/qdesigner_menu_p.h @@ -42,9 +42,11 @@ #include "shared_global_p.h" -#include #include + +#include #include + #include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_menubar.cpp b/src/designer/src/lib/shared/qdesigner_menubar.cpp index e212eff829..51bab619ed 100644 --- a/src/designer/src/lib/shared/qdesigner_menubar.cpp +++ b/src/designer/src/lib/shared/qdesigner_menubar.cpp @@ -168,7 +168,7 @@ bool QDesignerMenuBar::handleEvent(QWidget *widget, QEvent *event) bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) { - if (!rect().contains(event->pos())) + if (!rect().contains(event->position().toPoint())) return true; if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) @@ -178,7 +178,7 @@ bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event m_startPosition = QPoint(); - m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal); + m_currentIndex = actionIndexAt(this, event->position().toPoint(), Qt::Horizontal); if (m_currentIndex != -1) { showLineEdit(); } @@ -327,7 +327,7 @@ bool QDesignerMenuBar::handleMousePressEvent(QWidget *, QMouseEvent *event) if (event->button() != Qt::LeftButton) return true; - m_startPosition = event->pos(); + m_startPosition = event->position().toPoint(); const int newIndex = actionIndexAt(this, m_startPosition, Qt::Horizontal); const bool changed = newIndex != m_currentIndex; m_currentIndex = newIndex; @@ -344,7 +344,7 @@ bool QDesignerMenuBar::handleMouseReleaseEvent(QWidget *, QMouseEvent *event) return true; event->accept(); - m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal); + m_currentIndex = actionIndexAt(this, event->position().toPoint(), Qt::Horizontal); if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount()) showMenu(); @@ -359,7 +359,7 @@ bool QDesignerMenuBar::handleMouseMoveEvent(QWidget *, QMouseEvent *event) if (m_startPosition.isNull()) return true; - const QPoint pos = mapFromGlobal(event->globalPos()); + const QPoint pos = mapFromGlobal(event->globalPosition().toPoint()); if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance()) return true; @@ -604,7 +604,7 @@ QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action) void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event) { const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); - if (!d || d->actionList().empty()) { + if (!d || d->actionList().isEmpty()) { event->ignore(); return; } @@ -621,7 +621,7 @@ void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event) case AcceptActionDrag: m_dragging = true; d->accept(event); - adjustIndicator(event->pos()); + adjustIndicator(event->position().toPoint()); break; } } @@ -629,7 +629,7 @@ void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event) void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event) { const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); - if (!d || d->actionList().empty()) { + if (!d || d->actionList().isEmpty()) { event->ignore(); return; } @@ -641,11 +641,11 @@ void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event) break; case ActionDragOnSubMenu: event->ignore(); - showMenu(findAction(event->pos())); + showMenu(findAction(event->position().toPoint())); break; case AcceptActionDrag: d->accept(event); - adjustIndicator(event->pos()); + adjustIndicator(event->position().toPoint()); break; } } @@ -666,7 +666,7 @@ void QDesignerMenuBar::dropEvent(QDropEvent *event) QAction *action = d->actionList().first(); if (checkAction(action) == AcceptActionDrag) { event->acceptProposedAction(); - int index = findAction(event->pos()); + int index = findAction(event->position().toPoint()); index = qMin(index, actions().count() - 1); QDesignerFormWindowInterface *fw = formWindow(); diff --git a/src/designer/src/lib/shared/qdesigner_menubar_p.h b/src/designer/src/lib/shared/qdesigner_menubar_p.h index 5ec5132ab5..8b6e5383e5 100644 --- a/src/designer/src/lib/shared/qdesigner_menubar_p.h +++ b/src/designer/src/lib/shared/qdesigner_menubar_p.h @@ -42,9 +42,10 @@ #include "shared_global_p.h" -#include #include +#include + #include #include diff --git a/src/designer/src/lib/shared/qdesigner_objectinspector.cpp b/src/designer/src/lib/shared/qdesigner_objectinspector.cpp index e075042594..c672dca70c 100644 --- a/src/designer/src/lib/shared/qdesigner_objectinspector.cpp +++ b/src/designer/src/lib/shared/qdesigner_objectinspector.cpp @@ -50,7 +50,7 @@ void Selection::clear() bool Selection::empty() const { - return managed.empty() && unmanaged.empty() && objects.empty(); + return managed.isEmpty() && unmanaged.isEmpty() && objects.isEmpty(); } QObjectList Selection::selection() const diff --git a/src/designer/src/lib/shared/qdesigner_promotion.cpp b/src/designer/src/lib/shared/qdesigner_promotion.cpp index 2d8169960b..08b2848fd7 100644 --- a/src/designer/src/lib/shared/qdesigner_promotion.cpp +++ b/src/designer/src/lib/shared/qdesigner_promotion.cpp @@ -48,7 +48,7 @@ namespace { // Return a set of on-promotable classes const QSet &nonPromotableClasses() { static QSet rc; - if (rc.empty()) { + if (rc.isEmpty()) { rc.insert(QStringLiteral("Line")); rc.insert(QStringLiteral("QAction")); rc.insert(QStringLiteral("Spacer")); @@ -225,7 +225,7 @@ namespace qdesigner_internal { // convert map into list. PromotedClasses rc; - if (baseClassPromotedMap.empty()) + if (baseClassPromotedMap.isEmpty()) return rc; const BaseClassPromotedMap::const_iterator bcend = baseClassPromotedMap.constEnd(); @@ -262,7 +262,7 @@ namespace qdesigner_internal { // check the scratchpad of the widget box if (QDesignerWidgetBoxInterface *widgetBox = m_core->widgetBox()) { const QStringList scratchPadClasses = getScratchPadClasses(widgetBox); - if (!scratchPadClasses.empty()) { + if (!scratchPadClasses.isEmpty()) { // Check whether these are actually promoted QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); QStringList::const_iterator cend = scratchPadClasses.constEnd(); diff --git a/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp b/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp index 7058b0c817..18261f640a 100644 --- a/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp +++ b/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp @@ -39,22 +39,24 @@ #include #include -#include #include #include #include #include #include #include -#include #include #include #include -#include #include #include #include -#include + +#include +#include + +#include +#include QT_BEGIN_NAMESPACE @@ -290,7 +292,7 @@ namespace qdesigner_internal { const QStringList &QDesignerPromotionDialog::baseClassNames(const QDesignerPromotionInterface *promotion) { using WidgetDataBaseItemList = QList; static QStringList rc; - if (rc.empty()) { + if (rc.isEmpty()) { // Convert the item list into a string list. const WidgetDataBaseItemList dbItems = promotion->promotionBaseClasses(); const WidgetDataBaseItemList::const_iterator cend = dbItems.constEnd(); @@ -351,7 +353,7 @@ namespace qdesigner_internal { QDesignerWidgetDataBaseItemInterface *QDesignerPromotionDialog::databaseItemAt(const QItemSelection &selected, unsigned &flags) const { flags = 0; const QModelIndexList indexes = selected.indexes(); - if (indexes.empty()) + if (indexes.isEmpty()) return nullptr; const PromotionModel::ModelData data = m_model->modelData(indexes.constFirst()); QDesignerWidgetDataBaseItemInterface *dbItem = data.promotedItem; diff --git a/src/designer/src/lib/shared/qdesigner_propertycommand.cpp b/src/designer/src/lib/shared/qdesigner_propertycommand.cpp index 8b564ab6fc..223fd76aef 100644 --- a/src/designer/src/lib/shared/qdesigner_propertycommand.cpp +++ b/src/designer/src/lib/shared/qdesigner_propertycommand.cpp @@ -45,26 +45,30 @@ #include #include -#include -#include #include #include -#include #include #include #include -#include + +#include + +#include +#include +#include QT_BEGIN_NAMESPACE namespace { enum { debugPropertyCommands = 0 }; +const unsigned QFontFamiliesResolved = (QFont::FamilyResolved | QFont::FamiliesResolved); + // Debug resolve mask of font QString fontMask(unsigned m) { QString rc; - if (m & QFont::FamilyResolved) + if (m & QFontFamiliesResolved) rc += QStringLiteral("Family"); if (m & QFont::SizeResolved) rc += QStringLiteral("Size "); @@ -102,7 +106,7 @@ QString fontString(const QFont &f) if (f.kerning()) str << comma << QStringLiteral("kerning"); str << comma << f.styleStrategy() << QStringLiteral(" resolve: ") - << fontMask(f.resolve()) << QLatin1Char(')'); + << fontMask(f.resolveMask()) << QLatin1Char(')'); } return rc; } @@ -244,8 +248,8 @@ void compareFontSubProperty(const QFont & f1, unsigned maskBit, unsigned &mask) { - const bool f1Changed = f1.resolve() & maskBit; - const bool f2Changed = f2.resolve() & maskBit; + const bool f1Changed = f1.resolveMask() & maskBit; + const bool f2Changed = f2.resolveMask() & maskBit; // Role has been set/reset in editor if (f1Changed != f2Changed) { mask |= maskBit; @@ -259,7 +263,7 @@ void compareFontSubProperty(const QFont & f1, unsigned compareSubProperties(const QFont & f1, const QFont & f2) { unsigned rc = 0; - compareFontSubProperty(f1, f2, &QFont::family, QFont::FamilyResolved, rc); + compareFontSubProperty(f1, f2, &QFont::family, QFontFamiliesResolved, rc); compareFontSubProperty(f1, f2, &QFont::pointSize, QFont::SizeResolved, rc); compareFontSubProperty(f1, f2, &QFont::bold, QFont::WeightResolved, rc); compareFontSubProperty(f1, f2, &QFont::italic, QFont::StyleResolved, rc); @@ -288,8 +292,8 @@ unsigned compareSubProperties(const QPalette & p1, const QPalette & p2) unsigned rc = 0; unsigned maskBit = 1u; // generate a mask for each role - const unsigned p1Changed = p1.resolve(); - const unsigned p2Changed = p2.resolve(); + const unsigned p1Changed = p1.resolveMask(); + const unsigned p2Changed = p2.resolveMask(); for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) { const bool p1RoleChanged = p1Changed & maskBit; const bool p2RoleChanged = p2Changed & maskBit; @@ -326,18 +330,20 @@ unsigned compareSubProperties(const QVariant & q1, const QVariant & q2, qdesigne { // Do not clobber new value in the comparison function in // case someone sets a QString on a PropertySheetStringValue. - if (q1.type() != q2.type()) + const int t1 = q1.metaType().id(); + const int t2 = q2.metaType().id(); + if (t1 != t2) return SubPropertyAll; - switch (q1.type()) { - case QVariant::Rect: + switch (t1) { + case QMetaType::QRect: return compareSubProperties(q1.toRect(), q2.toRect()); - case QVariant::Size: + case QMetaType::QSize: return compareSubProperties(q1.toSize(), q2.toSize()); - case QVariant::SizePolicy: + case QMetaType::QSizePolicy: return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); - case QVariant::Font: + case QMetaType::QFont: return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); - case QVariant::Palette: + case QMetaType::QPalette: return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); default: if (q1.userType() == qMetaTypeId()) @@ -449,13 +455,13 @@ inline void setFontSubProperty(unsigned mask, if (mask & maskBit) { (value.*setter)((newValue.*getter)()); // Set the resolve bit from NewValue in return value - uint r = value.resolve(); - const bool origFlag = newValue.resolve() & maskBit; + uint r = value.resolveMask(); + const bool origFlag = newValue.resolveMask() & maskBit; if (origFlag) r |= maskBit; else r &= ~maskBit; - value.resolve(r); + value.setResolveMask(r); if (debugPropertyCommands) qDebug() << "setFontSubProperty " << fontMask(maskBit) << " resolve=" << origFlag; } @@ -464,7 +470,7 @@ inline void setFontSubProperty(unsigned mask, QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigned mask) { QFont rc = oldValue; - setFontSubProperty(mask, newValue, QFont::FamilyResolved, &QFont::family, &QFont::setFamily, rc); + setFontSubProperty(mask, newValue, QFontFamiliesResolved, &QFont::family, &QFont::setFamily, rc); setFontSubProperty(mask, newValue, QFont::SizeResolved, &QFont::pointSize, &QFont::setPointSize, rc); setFontSubProperty(mask, newValue, QFont::WeightResolved, &QFont::bold, &QFont::setBold, rc); setFontSubProperty(mask, newValue, QFont::StyleResolved, &QFont::italic, &QFont::setItalic, rc); @@ -473,7 +479,7 @@ QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigne setFontSubProperty(mask, newValue, QFont::KerningResolved, &QFont::kerning, &QFont::setKerning, rc); setFontSubProperty(mask, newValue, QFont::StyleStrategyResolved, &QFont::styleStrategy, &QFont::setStyleStrategy, rc); if (debugPropertyCommands) - qDebug() << "applyFontSubProperty old " << fontMask(oldValue.resolve()) << " new " << fontMask(newValue.resolve()) << " return: " << fontMask(rc.resolve()); + qDebug() << "applyFontSubProperty old " << fontMask(oldValue.resolveMask()) << " new " << fontMask(newValue.resolveMask()) << " return: " << fontMask(rc.resolveMask()); return rc; } @@ -491,13 +497,13 @@ QPalette applyPaletteSubProperty(const QPalette &oldValue, const QPalette &newVa rc.setColor(pgroup, prole, newValue.color(pgroup, prole)); } // Set the resolve bit from NewValue in return value - uint r = rc.resolve(); - const bool origFlag = newValue.resolve() & maskBit; + uint r = rc.resolveMask(); + const bool origFlag = newValue.resolveMask() & maskBit; if (origFlag) r |= maskBit; else r &= ~maskBit; - rc.resolve(r); + rc.setResolveMask(r); } } return rc; @@ -525,14 +531,14 @@ PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant if (mask == SubPropertyAll) return PropertyHelper::Value(newValue, changed); - switch (oldValue.type()) { - case QVariant::Rect: + switch (oldValue.metaType().id()) { + case QMetaType::QRect: return PropertyHelper::Value(applyRectSubProperty(oldValue.toRect(), newValue.toRect(), mask), changed); - case QVariant::Size: + case QMetaType::QSize: return PropertyHelper::Value(applySizeSubProperty(oldValue.toSize(), newValue.toSize(), mask), changed); - case QVariant::SizePolicy: + case QMetaType::QSizePolicy: return PropertyHelper::Value(QVariant::fromValue(applySizePolicySubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask)), changed); - case QVariant::Font: { + case QMetaType::QFont: { // Changed flag in case of font and palette depends on resolve mask only, not on the passed "changed" value. // The first case: the user changed bold subproperty and then pressed reset button for this subproperty (not for @@ -550,11 +556,11 @@ PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant // He press reset button for the whole font property. In result whole font properties for both // widgets should be marked as unchanged. QFont font = applyFontSubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask); - return PropertyHelper::Value(QVariant::fromValue(font), font.resolve()); + return PropertyHelper::Value(QVariant::fromValue(font), font.resolveMask()); } - case QVariant::Palette: { + case QMetaType::QPalette: { QPalette palette = applyPaletteSubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask); - return PropertyHelper::Value(QVariant::fromValue(palette), palette.resolve()); + return PropertyHelper::Value(QVariant::fromValue(palette), palette.resolveMask()); } default: if (oldValue.userType() == qMetaTypeId()) { @@ -646,7 +652,7 @@ PropertyHelper::PropertyHelper(QObject* object, m_objectType = OT_Widget; } else { if (const QAction *action = qobject_cast(m_object)) - m_objectType = action->associatedWidgets().empty() ? OT_FreeAction : OT_AssociatedAction; + m_objectType = action->associatedWidgets().isEmpty() ? OT_FreeAction : OT_AssociatedAction; } if(debugPropertyCommands) @@ -881,11 +887,11 @@ QVariant PropertyHelper::findDefaultValue(QDesignerFormWindowInterface *fw) cons return m_oldValue.first; // We simply don't know the value in this case const QDesignerWidgetDataBaseItemInterface *item = fw->core()->widgetDataBase()->item(item_idx); - const QList default_prop_values = item->defaultPropertyValues(); + const auto default_prop_values = item->defaultPropertyValues(); if (m_index < default_prop_values.size()) return default_prop_values.at(m_index); - if (m_oldValue.first.type() == QVariant::Color) + if (m_oldValue.first.metaType().id() == QMetaType::QColor) return QColor(); return m_oldValue.first; // Again, we just don't know @@ -933,7 +939,7 @@ PropertyListCommand::PropertyDescription::PropertyDescription(const QString &pro int index) : m_propertyName(propertyName), m_propertyGroup(propertySheet->propertyGroup(index)), - m_propertyType(propertySheet->property(index).type()), + m_propertyType(propertySheet->property(index).metaType().id()), m_specialProperty(getSpecialProperty(propertyName)) { } @@ -982,7 +988,7 @@ bool PropertyListCommand::add(QObject *object, const QString &propertyName) const PropertyDescription description(propertyName, sheet, index); - if (m_propertyHelperList.empty()) { + if (m_propertyHelperList.isEmpty()) { // first entry m_propertyDescription = description; } else { @@ -1018,7 +1024,7 @@ bool PropertyListCommand::initList(const QObjectList &list, const QString &aprop add(o, apropertyName); } - return !propertyHelperList().empty(); + return !propertyHelperList().isEmpty(); } diff --git a/src/designer/src/lib/shared/qdesigner_propertycommand_p.h b/src/designer/src/lib/shared/qdesigner_propertycommand_p.h index 2ee57ad2c6..7afd7b55aa 100644 --- a/src/designer/src/lib/shared/qdesigner_propertycommand_p.h +++ b/src/designer/src/lib/shared/qdesigner_propertycommand_p.h @@ -187,7 +187,7 @@ class QDESIGNER_SHARED_EXPORT PropertyListCommand : public QDesignerFormWindowCo QString m_propertyName; QString m_propertyGroup; - QVariant::Type m_propertyType = QVariant::Invalid; + int m_propertyType = QMetaType::UnknownType; SpecialProperty m_specialProperty = SP_None; }; const PropertyDescription &propertyDescription() const { return m_propertyDescription; } @@ -242,10 +242,10 @@ class QDESIGNER_SHARED_EXPORT ResetPropertyCommand: public PropertyListCommand bool init(QObject *object, const QString &propertyName); bool init(const QObjectList &list, const QString &propertyName, QObject *referenceObject = nullptr); - virtual void redo(); + void redo() override; protected: - virtual bool mergeWith(const QUndoCommand *) { return false; } + bool mergeWith(const QUndoCommand *) override { return false; } private: void setDescription(); @@ -261,8 +261,8 @@ class QDESIGNER_SHARED_EXPORT AddDynamicPropertyCommand: public QDesignerFormWin bool init(const QList &selection, QObject *current, const QString &propertyName, const QVariant &value); - virtual void redo(); - virtual void undo(); + void redo() override; + void undo() override; private: void setDescription(); QString m_propertyName; @@ -278,8 +278,8 @@ class QDESIGNER_SHARED_EXPORT RemoveDynamicPropertyCommand: public QDesignerForm bool init(const QList &selection, QObject *current, const QString &propertyName); - virtual void redo(); - virtual void undo(); + void redo() override; + void undo() override; private: void setDescription(); QString m_propertyName; diff --git a/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp b/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp index 3a26553fd8..a31b6ab08e 100644 --- a/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp +++ b/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp @@ -34,10 +34,12 @@ #include #include #include -#include + #include #include +#include + QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -49,7 +51,7 @@ using PropertyNameTypeMap = QHash; static const PropertyNameTypeMap &stringPropertyTypes() { static PropertyNameTypeMap propertyNameTypeMap; - if (propertyNameTypeMap.empty()) { + if (propertyNameTypeMap.isEmpty()) { const StringPropertyParameters richtext(ValidationRichText, true); // Accessibility. Both are texts the narrator reads propertyNameTypeMap.insert(QStringLiteral("accessibleDescription"), richtext); diff --git a/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h b/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h index dbb116f653..5995cd21ea 100644 --- a/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h +++ b/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h @@ -56,7 +56,7 @@ class QDESIGNER_SHARED_EXPORT QDesignerPropertyEditor: public QDesignerPropertyE { Q_OBJECT public: - explicit QDesignerPropertyEditor(QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr); + explicit QDesignerPropertyEditor(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); // A pair . using StringPropertyParameters = QPair; diff --git a/src/designer/src/lib/shared/qdesigner_propertysheet.cpp b/src/designer/src/lib/shared/qdesigner_propertysheet.cpp index 1293b689c2..209582b1e5 100644 --- a/src/designer/src/lib/shared/qdesigner_propertysheet.cpp +++ b/src/designer/src/lib/shared/qdesigner_propertysheet.cpp @@ -39,18 +39,23 @@ #include #include -#include - #include #include #include +#include #include #include #include +#include #include #include #include #include +#include + +#include + +#include QT_BEGIN_NAMESPACE @@ -173,6 +178,7 @@ class QDesignerPropertySheetPrivate { public: using PropertyType = QDesignerPropertySheet::PropertyType; using ObjectType = QDesignerPropertySheet::ObjectType; + using ObjectFlags = QDesignerPropertySheet::ObjectFlags; explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent); @@ -186,7 +192,7 @@ class QDesignerPropertySheetPrivate { bool isReloadableProperty(int index) const; bool isResourceProperty(int index) const; - void addResourceProperty(int index, QVariant::Type type); + void addResourceProperty(int index, int type); QVariant resourceProperty(int index) const; void setResourceProperty(int index, const QVariant &value); QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue @@ -227,6 +233,7 @@ class QDesignerPropertySheetPrivate { QDesignerFormEditorInterface *m_core; const QDesignerMetaObjectInterface *m_meta; const ObjectType m_objectType; + const ObjectFlags m_objectFlags; using InfoHash = QHash; InfoHash m_info; @@ -264,7 +271,7 @@ bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const return isResourceProperty(index) || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet || propertyType(index) == QDesignerPropertySheet::PropertyText - || q->property(index).type() == QVariant::Url; + || q->property(index).metaType().id() == QMetaType::QUrl; } /* @@ -279,11 +286,11 @@ bool QDesignerPropertySheetPrivate::isResourceProperty(int index) const return m_resourceProperties.contains(index); } -void QDesignerPropertySheetPrivate::addResourceProperty(int index, QVariant::Type type) +void QDesignerPropertySheetPrivate::addResourceProperty(int index, int type) { - if (type == QVariant::Pixmap) + if (type == QMetaType::QPixmap) m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue())); - else if (type == QVariant::Icon) + else if (type == QMetaType::QIcon) m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetIconValue())); } @@ -388,6 +395,7 @@ QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySh m_core(formEditorForObject(sheetParent)), m_meta(m_core->introspection()->metaObject(object)), m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)), + m_objectFlags(QDesignerPropertySheet::objectFlagsFromObject(object)), m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)), m_object(object), m_lastLayout(nullptr), @@ -470,7 +478,7 @@ QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) co { using TypeNameMap = QMap; static TypeNameMap typeNameMap; - if (typeNameMap.empty()) { + if (typeNameMap.isEmpty()) { typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QStringLiteral("objectName")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QStringLiteral("leftMargin")); typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QStringLiteral("topMargin")); @@ -515,11 +523,22 @@ QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject( return ObjectNone; } +QDesignerPropertySheet::ObjectFlags QDesignerPropertySheet::objectFlagsFromObject(const QObject *o) +{ + ObjectFlags result; + if ((o->isWidgetType() && (qobject_cast(o) + || qobject_cast(o))) + || qobject_cast(o)) { + result |= CheckableProperty; + } + return result; +} + QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name) { typedef QHash PropertyTypeHash; static PropertyTypeHash propertyTypeHash; - if (propertyTypeHash.empty()) { + if (propertyTypeHash.isEmpty()) { propertyTypeHash.insert(QLatin1String(layoutObjectNameC), PropertyLayoutObjectName); propertyTypeHash.insert(QLatin1String(layoutLeftMarginC), PropertyLayoutLeftMargin); propertyTypeHash.insert(QLatin1String(layoutTopMarginC), PropertyLayoutTopMargin); @@ -540,9 +559,11 @@ QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromNam propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC), PropertyLayoutGridColumnMinimumWidth); propertyTypeHash.insert(QStringLiteral("buddy"), PropertyBuddy); propertyTypeHash.insert(QStringLiteral("geometry"), PropertyGeometry); + propertyTypeHash.insert(QStringLiteral("checked"), PropertyChecked); propertyTypeHash.insert(QStringLiteral("checkable"), PropertyCheckable); propertyTypeHash.insert(QStringLiteral("accessibleName"), PropertyAccessibility); propertyTypeHash.insert(QStringLiteral("accessibleDescription"), PropertyAccessibility); + propertyTypeHash.insert(QStringLiteral("visible"), PropertyVisible); propertyTypeHash.insert(QStringLiteral("windowTitle"), PropertyWindowTitle); propertyTypeHash.insert(QStringLiteral("windowIcon"), PropertyWindowIcon); propertyTypeHash.insert(QStringLiteral("windowFilePath"), PropertyWindowFilePath); @@ -579,7 +600,7 @@ QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) for (int index=0; indexm_meta->property(index); const QString name = p->name(); - if (p->type() == QVariant::KeySequence) { + if (p->type() == QMetaType::QKeySequence) { createFakeProperty(name); } else { setVisible(index, false); // use the default for `real' properties @@ -595,22 +616,22 @@ QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) info.group = pgroup; info.propertyType = propertyTypeFromName(name); - const QVariant::Type type = p->type(); + const int type = p->type(); switch (type) { - case QVariant::Cursor: - case QVariant::Icon: - case QVariant::Pixmap: + case QMetaType::QCursor: + case QMetaType::QIcon: + case QMetaType::QPixmap: info.defaultValue = p->read(d->m_object); - if (type == QVariant::Icon || type == QVariant::Pixmap) + if (type == QMetaType::QIcon || type == QMetaType::QPixmap) d->addResourceProperty(index, type); break; - case QVariant::String: + case QMetaType::QString: d->addStringProperty(index); break; - case QVariant::StringList: + case QMetaType::QStringList: d->addStringListProperty(index); break; - case QVariant::KeySequence: + case QMetaType::QKeySequence: d->addKeySequenceProperty(index); break; default: @@ -676,7 +697,7 @@ QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) using ByteArrayList = QList; const ByteArrayList names = object->dynamicPropertyNames(); - if (!names.empty()) { + if (!names.isEmpty()) { const ByteArrayList::const_iterator cend = names.constEnd(); for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) { const char* cName = it->constData(); @@ -729,18 +750,25 @@ int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QV return -1; QVariant v = value; - if (value.type() == QVariant::Icon) + switch (value.metaType().id()) { + case QMetaType::QIcon: v = QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); - else if (value.type() == QVariant::Pixmap) + break; + case QMetaType::QPixmap: v = QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()); - else if (value.type() == QVariant::String) + break; + case QMetaType::QString: v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(value.toString())); - else if (value.type() == QVariant::StringList) + break; + case QMetaType::QStringList: v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue(value.toStringList())); - else if (value.type() == QVariant::KeySequence) { + break; + case QMetaType::QKeySequence: { const QKeySequence keySequence = qvariant_cast(value); v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); } + break; + } if (d->m_addIndex.contains(propName)) { const int idx = d->m_addIndex.value(propName); @@ -752,12 +780,18 @@ int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QV Info &info = d->ensureInfo(index); info.defaultValue = value; info.kind = QDesignerPropertySheetPrivate::DynamicProperty; - if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap) - d->addResourceProperty(idx, value.type()); - else if (value.type() == QVariant::String) + switch (value.metaType().id()) { + case QMetaType::QIcon: + case QMetaType::QPixmap: + d->addResourceProperty(idx, value.metaType().id()); + break; + case QMetaType::QString: d->addStringProperty(idx); - else if (value.type() == QVariant::KeySequence) + break; + case QMetaType::QKeySequence: d->addKeySequenceProperty(idx); + break; + } return idx; } @@ -770,18 +804,18 @@ int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QV info.defaultValue = value; info.kind = QDesignerPropertySheetPrivate::DynamicProperty; setPropertyGroup(index, tr("Dynamic Properties")); - switch (value.type()) { - case QVariant::Icon: - case QVariant::Pixmap: - d->addResourceProperty(index, value.type()); + switch (value.metaType().id()) { + case QMetaType::QIcon: + case QMetaType::QPixmap: + d->addResourceProperty(index, value.metaType().id()); break; - case QVariant::String: + case QMetaType::QString: d->addStringProperty(index); break; - case QVariant::StringList: + case QMetaType::QStringList: d->addStringListProperty(index); break; - case QVariant::KeySequence: + case QMetaType::QKeySequence: d->addKeySequenceProperty(index); break; default: @@ -893,12 +927,17 @@ int QDesignerPropertySheet::createFakeProperty(const QString &propertyName, cons info.visible = false; info.kind = QDesignerPropertySheetPrivate::FakeProperty; QVariant v = value.isValid() ? value : metaProperty(index); - if (v.type() == QVariant::String) + switch (v.metaType().id()) { + case QMetaType::QString: v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); - if (v.type() == QVariant::StringList) + break; + case QMetaType::QStringList: v = QVariant::fromValue(qdesigner_internal::PropertySheetStringListValue()); - if (v.type() == QVariant::KeySequence) + break; + case QMetaType::QKeySequence: v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue()); + break; + } d->m_fakeProperties.insert(index, v); return index; } @@ -1048,7 +1087,22 @@ QVariant QDesignerPropertySheet::property(int index) const return QVariant::fromValue(value); } - return metaProperty(index); + QVariant result = metaProperty(index); + // QTBUG-49591: "visible" is only exposed for QHeaderView as a fake + // property ("headerVisible") for the item view. If the item view is not + // visible (on a page based container), check the WA_WState_Hidden instead, + // since otherwise false is returned when saving. + if (result.typeId() == QMetaType::Bool && !result.toBool() + && d->m_object->isWidgetType() + && propertyType(index) == PropertyVisible) { + if (auto *hv = qobject_cast(d->m_object)) { + if (auto *parent = hv->parentWidget()) { + if (!parent->isVisible()) + result = QVariant(!hv->testAttribute(Qt::WA_WState_Hidden)); + } + } + } + return result; } QVariant QDesignerPropertySheet::metaProperty(int index) const @@ -1124,12 +1178,12 @@ void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value) qdesigner_internal::PropertySheetFlagValue f = qvariant_cast(v); f.value = value.toInt(); v.setValue(f); - Q_ASSERT(value.type() == QVariant::Int); + Q_ASSERT(value.metaType().id() == QMetaType::Int); } else if (v.canConvert()) { qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(v); e.value = value.toInt(); v.setValue(e); - Q_ASSERT(value.type() == QVariant::Int); + Q_ASSERT(value.metaType().id() == QMetaType::Int); } else { v = value; } @@ -1142,7 +1196,7 @@ void QDesignerPropertySheet::clearFakeProperties() // Buddy needs to be byte array, else uic won't work static QVariant toByteArray(const QVariant &value) { - if (value.type() == QVariant::ByteArray) + if (value.metaType().id() == QMetaType::QByteArray) return value; const QByteArray ba = value.toString().toUtf8(); return QVariant(ba); @@ -1440,23 +1494,13 @@ bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const return false; } -// Determine the "designable" state of a property. Properties, which have -// a per-object boolean test function that returns false are shown in -// disabled state ("checked" depending on "checkable", etc.) -// Properties, which are generally not designable independent -// of the object are not shown at all. -enum DesignableState { PropertyIsDesignable, - // Object has a Designable test function that returns false. - PropertyOfObjectNotDesignable, - PropertyNotDesignable }; - -static inline DesignableState designableState(const QDesignerMetaPropertyInterface *p, const QObject *object) -{ - if (p->attributes(object) & QDesignerMetaPropertyInterface::DesignableAttribute) - return PropertyIsDesignable; - return (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute) ? - PropertyOfObjectNotDesignable : PropertyNotDesignable; -} +// Visible vs. Enabled: In Qt 5, it was possible to define a boolean function +// for the DESIGNABLE attribute of Q_PROPERTY. Qt Designer would use that to +// determine isEnabled() for the property and return isVisible() = false +// for properties that specified 'false' for DESIGNABLE. +// This was used for example for the "checked" property of QAbstractButton, +// QGroupBox and QAction, where "checkable" would determine isEnabled(). +// This is now implemented by querying the property directly. bool QDesignerPropertySheet::isVisible(int index) const { @@ -1532,8 +1576,7 @@ bool QDesignerPropertySheet::isVisible(int index) const if (!(p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess)) return false; - // Enabled handling: Hide only statically not designable properties - return designableState(p, d->m_object) != PropertyNotDesignable; + return p->attributes().testFlag(QDesignerMetaPropertyInterface::DesignableAttribute); } void QDesignerPropertySheet::setVisible(int index, bool visible) @@ -1567,8 +1610,16 @@ bool QDesignerPropertySheet::isEnabled(int index) const // as this might be done via TaskMenu/Cursor::setProperty. Note that those // properties are not visible. const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); - return (p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess) && - designableState(p, d->m_object) != PropertyOfObjectNotDesignable; + if (!p->accessFlags().testFlag(QDesignerMetaPropertyInterface::WriteAccess)) + return false; + + if (!p->attributes().testFlag(QDesignerMetaPropertyInterface::DesignableAttribute)) + return false; + + const PropertyType type = propertyType(index); + if (type == PropertyChecked && d->m_objectFlags.testFlag(CheckableProperty)) + return d->m_object->property("checkable").toBool(); + return true; } bool QDesignerPropertySheet::isAttribute(int index) const @@ -1657,16 +1708,16 @@ QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object) { - QMutableMapIterator it(m_impl->m_extensions); - while (it.hasNext()) { - it.next(); + for (auto it = m_impl->m_extensions.begin(), end = m_impl->m_extensions.end(); it != end; /*erasing*/) { if (it.key() == object || it.value() == object) { if (it.key() == object) { QObject *ext = it.value(); disconnect(ext, &QObject::destroyed, this, &QDesignerAbstractPropertySheetFactory::objectDestroyed); delete ext; } - it.remove(); + it = m_impl->m_extensions.erase(it); + } else { + ++it; } } } diff --git a/src/designer/src/lib/shared/qdesigner_propertysheet_p.h b/src/designer/src/lib/shared/qdesigner_propertysheet_p.h index 4da33b5254..e066d0c4fa 100644 --- a/src/designer/src/lib/shared/qdesigner_propertysheet_p.h +++ b/src/designer/src/lib/shared/qdesigner_propertysheet_p.h @@ -155,7 +155,9 @@ class QDESIGNER_SHARED_EXPORT QDesignerPropertySheet: public QObject, public QDe PropertyBuddy, PropertyAccessibility, PropertyGeometry, + PropertyChecked, PropertyCheckable, + PropertyVisible, PropertyWindowTitle, PropertyWindowIcon, PropertyWindowFilePath, @@ -168,8 +170,14 @@ class QDESIGNER_SHARED_EXPORT QDesignerPropertySheet: public QObject, public QDe }; enum ObjectType { ObjectNone, ObjectLabel, ObjectLayout, ObjectLayoutWidget }; + enum ObjectFlag + { + CheckableProperty = 0x1 // Has a "checked" property depending on "checkable" + }; + Q_DECLARE_FLAGS(ObjectFlags, ObjectFlag) static ObjectType objectTypeFromObject(const QObject *o); + static ObjectFlags objectFlagsFromObject(const QObject *o); static PropertyType propertyTypeFromName(const QString &name); protected: @@ -248,6 +256,8 @@ void QDesignerPropertySheetFactory::registerExtension(QEx // Standard property sheet typedef QDesignerPropertySheetFactory QDesignerDefaultPropertySheetFactory; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDesignerPropertySheet::ObjectFlags) + QT_END_NAMESPACE #endif // QDESIGNER_PROPERTYSHEET_H diff --git a/src/designer/src/lib/shared/qdesigner_stackedbox.cpp b/src/designer/src/lib/shared/qdesigner_stackedbox.cpp index a85df26939..c62b12972c 100644 --- a/src/designer/src/lib/shared/qdesigner_stackedbox.cpp +++ b/src/designer/src/lib/shared/qdesigner_stackedbox.cpp @@ -36,10 +36,12 @@ #include #include -#include -#include #include #include + +#include +#include + #include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_tabwidget.cpp b/src/designer/src/lib/shared/qdesigner_tabwidget.cpp index 2f003cf6ca..9325e386d4 100644 --- a/src/designer/src/lib/shared/qdesigner_tabwidget.cpp +++ b/src/designer/src/lib/shared/qdesigner_tabwidget.cpp @@ -36,13 +36,14 @@ #include #include -#include -#include -#include #include #include #include +#include +#include +#include + #include #include @@ -118,9 +119,9 @@ QTabBar *QTabWidgetEventFilter::tabBar() const { // QTabWidget::tabBar() accessor is protected, grmbl... if (!m_cachedTabBar) { - const QList tabBars = m_tabWidget->findChildren(); + const auto tabBars = m_tabWidget->findChildren(); Q_ASSERT(tabBars.size() == 1); - m_cachedTabBar = tabBars.front(); + m_cachedTabBar = tabBars.constFirst(); } return m_cachedTabBar; @@ -128,7 +129,7 @@ QTabBar *QTabWidgetEventFilter::tabBar() const static bool canMove(const QPoint &pressPoint, const QMouseEvent *e) { - const QPoint pt = pressPoint - e->pos(); + const QPoint pt = pressPoint - e->position().toPoint(); return pt.manhattanLength() > QApplication::startDragDistance(); } @@ -170,7 +171,7 @@ bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e) } if (mev->button() & Qt::LeftButton) { m_mousePressed = true; - m_pressPoint = mev->pos(); + m_pressPoint = mev->position().toPoint(); QTabBar *tabbar = tabBar(); const int count = tabbar->count(); @@ -249,7 +250,7 @@ bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e) } QRect rect; - const int index = pageFromPosition(de->pos(), rect); + const int index = pageFromPosition(de->position().toPoint(), rect); if (!m_dropIndicator) { m_dropIndicator = new QWidget(m_tabWidget); @@ -276,7 +277,7 @@ bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e) de->accept(); QRect rect; - const int newIndex = pageFromPosition(de->pos(), rect); + const int newIndex = pageFromPosition(de->position().toPoint(), rect); qdesigner_internal::MoveTabPageCommand *cmd = new qdesigner_internal::MoveTabPageCommand(fw); m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel); @@ -406,7 +407,7 @@ QTabWidgetPropertySheet::TabWidgetProperty QTabWidgetPropertySheet::tabWidgetPro { using TabWidgetPropertyHash = QHash; static TabWidgetPropertyHash tabWidgetPropertyHash; - if (tabWidgetPropertyHash.empty()) { + if (tabWidgetPropertyHash.isEmpty()) { tabWidgetPropertyHash.insert(QLatin1String(currentTabTextKey), PropertyCurrentTabText); tabWidgetPropertyHash.insert(QLatin1String(currentTabNameKey), PropertyCurrentTabName); tabWidgetPropertyHash.insert(QLatin1String(currentTabIconKey), PropertyCurrentTabIcon); diff --git a/src/designer/src/lib/shared/qdesigner_taskmenu.cpp b/src/designer/src/lib/shared/qdesigner_taskmenu.cpp index f1783587fd..e51cd3a73b 100644 --- a/src/designer/src/lib/shared/qdesigner_taskmenu.cpp +++ b/src/designer/src/lib/shared/qdesigner_taskmenu.cpp @@ -60,8 +60,6 @@ #include #include -#include -#include #include #include #include @@ -69,7 +67,11 @@ #include #include #include -#include + +#include +#include +#include + #include #include @@ -250,7 +252,7 @@ bool LayoutAlignmentMenu::setAlignment(const QDesignerFormEditorInterface *core, Qt::Alignment LayoutAlignmentMenu::alignment() const { - Qt::Alignment alignment = nullptr; + Qt::Alignment alignment; if (const QAction *horizAction = m_horizGroup->checkedAction()) if (const int horizAlign = horizAction->data().toInt()) alignment |= static_cast(horizAlign); diff --git a/src/designer/src/lib/shared/qdesigner_toolbar.cpp b/src/designer/src/lib/shared/qdesigner_toolbar.cpp index 28c2ca2855..5e8eeccddb 100644 --- a/src/designer/src/lib/shared/qdesigner_toolbar.cpp +++ b/src/designer/src/lib/shared/qdesigner_toolbar.cpp @@ -41,14 +41,15 @@ #include #include -#include #include #include #include #include + +#include #include #include -#include + #include Q_DECLARE_METATYPE(QAction*) @@ -124,7 +125,7 @@ ActionList ToolBarEventFilter::contextMenuActions(const QPoint &globalPos) { ActionList rc; const int index = actionIndexAt(m_toolBar, m_toolBar->mapFromGlobal(globalPos), m_toolBar->orientation()); - const ActionList actions = m_toolBar->actions(); + const auto actions = m_toolBar->actions(); QAction *action = index != -1 ?actions.at(index) : 0; QVariant itemData; @@ -138,7 +139,7 @@ ActionList ToolBarEventFilter::contextMenuActions(const QPoint &globalPos) } // Append separator - if (actions.empty() || !actions.back()->isSeparator()) { + if (actions.isEmpty() || !actions.constLast()->isSeparator()) { QAction *newSeperatorAct = new QAction(tr("Append Separator"), nullptr); itemData.setValue(static_cast(nullptr)); newSeperatorAct->setData(itemData); @@ -262,7 +263,7 @@ void ToolBarEventFilter::hideDragIndicator() bool ToolBarEventFilter::handleMousePressEvent(QMouseEvent *event) { - if (event->button() != Qt::LeftButton || withinHandleArea(m_toolBar, event->pos())) + if (event->button() != Qt::LeftButton || withinHandleArea(m_toolBar, event->position().toPoint())) return false; if (QDesignerFormWindowInterface *fw = formWindow()) { @@ -275,14 +276,14 @@ bool ToolBarEventFilter::handleMousePressEvent(QMouseEvent *event) } core->propertyEditor()->setObject(m_toolBar); } - m_startPosition = m_toolBar->mapFromGlobal(event->globalPos()); + m_startPosition = m_toolBar->mapFromGlobal(event->globalPosition().toPoint()); event->accept(); return true; } bool ToolBarEventFilter::handleMouseReleaseEvent(QMouseEvent *event) { - if (event->button() != Qt::LeftButton || m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos())) + if (event->button() != Qt::LeftButton || m_startPosition.isNull() || withinHandleArea(m_toolBar, event->position().toPoint())) return false; // Accept the event, otherwise, form window selection will trigger @@ -293,10 +294,10 @@ bool ToolBarEventFilter::handleMouseReleaseEvent(QMouseEvent *event) bool ToolBarEventFilter::handleMouseMoveEvent(QMouseEvent *event) { - if (m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos())) + if (m_startPosition.isNull() || withinHandleArea(m_toolBar, event->position().toPoint())) return false; - const QPoint pos = m_toolBar->mapFromGlobal(event->globalPos()); + const QPoint pos = m_toolBar->mapFromGlobal(event->globalPosition().toPoint()); if ((pos - m_startPosition).manhattanLength() > qApp->startDragDistance()) { startDrag(m_startPosition, event->modifiers()); m_startPosition = QPoint(); @@ -326,7 +327,7 @@ bool ToolBarEventFilter::handleDragEnterMoveEvent(QDragMoveEvent *event) } d->accept(event); - adjustDragIndicator(event->pos()); + adjustDragIndicator(event->position().toPoint()); return true; } @@ -359,7 +360,7 @@ bool ToolBarEventFilter::handleDropEvent(QDropEvent *event) // Try to find action to 'insert before'. Click on action or in free area, else ignore. QAction *beforeAction = nullptr; - const QPoint pos = event->pos(); + const QPoint pos = event->position().toPoint(); const int index = actionIndexAt(m_toolBar, pos, m_toolBar->orientation()); if (index != -1) { beforeAction = actions.at(index); @@ -448,7 +449,8 @@ QRect ToolBarEventFilter::freeArea(const QToolBar *tb) { QRect rc = QRect(QPoint(0, 0), tb->size()); const ActionList actionList = tb->actions(); - QRect exclusionRectangle = actionList.empty() ? handleArea(tb) : tb->actionGeometry(actionList.back()); + QRect exclusionRectangle = actionList.isEmpty() + ? handleArea(tb) : tb->actionGeometry(actionList.constLast()); switch (tb->orientation()) { case Qt::Horizontal: switch (tb->layoutDirection()) { diff --git a/src/designer/src/lib/shared/qdesigner_toolbar_p.h b/src/designer/src/lib/shared/qdesigner_toolbar_p.h index 97d957c0c6..a3fa2c2ade 100644 --- a/src/designer/src/lib/shared/qdesigner_toolbar_p.h +++ b/src/designer/src/lib/shared/qdesigner_toolbar_p.h @@ -42,9 +42,10 @@ #include "shared_global_p.h" -#include #include +#include + #include #include diff --git a/src/designer/src/lib/shared/qdesigner_toolbox.cpp b/src/designer/src/lib/shared/qdesigner_toolbox.cpp index f0c0dc7263..26b36c8f9e 100644 --- a/src/designer/src/lib/shared/qdesigner_toolbox.cpp +++ b/src/designer/src/lib/shared/qdesigner_toolbox.cpp @@ -34,12 +34,14 @@ #include -#include #include #include #include #include + +#include #include + #include QT_BEGIN_NAMESPACE @@ -256,7 +258,7 @@ QToolBoxWidgetPropertySheet::ToolBoxProperty QToolBoxWidgetPropertySheet::toolBo { using ToolBoxPropertyHash = QHash; static ToolBoxPropertyHash toolBoxPropertyHash; - if (toolBoxPropertyHash.empty()) { + if (toolBoxPropertyHash.isEmpty()) { toolBoxPropertyHash.insert(QLatin1String(currentItemTextKey), PropertyCurrentItemText); toolBoxPropertyHash.insert(QLatin1String(currentItemNameKey), PropertyCurrentItemName); toolBoxPropertyHash.insert(QLatin1String(currentItemIconKey), PropertyCurrentItemIcon); diff --git a/src/designer/src/lib/shared/qdesigner_utils.cpp b/src/designer/src/lib/shared/qdesigner_utils.cpp index a7c4fdd727..dcc627a22e 100644 --- a/src/designer/src/lib/shared/qdesigner_utils.cpp +++ b/src/designer/src/lib/shared/qdesigner_utils.cpp @@ -198,7 +198,7 @@ namespace qdesigner_internal QString DesignerMetaFlags::toString(int value, SerializationMode sm) const { const QStringList flagIds = flags(value); - if (flagIds.empty()) + if (flagIds.isEmpty()) return QString(); const QChar delimiter = QLatin1Char('|'); @@ -695,7 +695,7 @@ namespace qdesigner_internal if (const QDesignerTaskMenuExtension *taskMenu = qt_extension(core->extensionManager(), managedWidget)) { action = taskMenu->preferredEditAction(); if (!action) { - const QList actions = taskMenu->taskActions(); + const auto actions = taskMenu->taskActions(); if (!actions.isEmpty()) action = actions.first(); } @@ -705,7 +705,7 @@ namespace qdesigner_internal core->extensionManager()->extension(managedWidget, QStringLiteral("QDesignerInternalTaskMenuExtension")))) { action = taskMenu->preferredEditAction(); if (!action) { - const QList actions = taskMenu->taskActions(); + const auto actions = taskMenu->taskActions(); if (!actions.isEmpty()) action = actions.first(); } @@ -719,7 +719,7 @@ namespace qdesigner_internal { QProcess uic; QStringList arguments; - QString binary = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QStringLiteral("/uic"); + QString binary = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + QStringLiteral("/uic"); switch (language) { case UicLanguage::Cpp: break; diff --git a/src/designer/src/lib/shared/qdesigner_widgetbox.cpp b/src/designer/src/lib/shared/qdesigner_widgetbox.cpp index 1ca79d777f..03cd9a3adc 100644 --- a/src/designer/src/lib/shared/qdesigner_widgetbox.cpp +++ b/src/designer/src/lib/shared/qdesigner_widgetbox.cpp @@ -190,7 +190,7 @@ DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement) { - const QStringRef name = reader.name(); + const auto name = reader.name(); if (ui) { reader.raiseError(tr("Unexpected element <%1>").arg(name.toString())); continue; @@ -229,7 +229,7 @@ DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool if (insertFakeTopLevel) { DomWidget *fakeTopLevel = new DomWidget; fakeTopLevel->setAttributeClass(QStringLiteral("QWidget")); - QVector children; + QList children; children.push_back(ui->takeElementWidget()); fakeTopLevel->setElementWidget(children); ui->setElementWidget(fakeTopLevel); diff --git a/src/designer/src/lib/shared/qdesigner_widgetbox_p.h b/src/designer/src/lib/shared/qdesigner_widgetbox_p.h index efedb34b28..cad8e04da8 100644 --- a/src/designer/src/lib/shared/qdesigner_widgetbox_p.h +++ b/src/designer/src/lib/shared/qdesigner_widgetbox_p.h @@ -57,7 +57,7 @@ class QDESIGNER_SHARED_EXPORT QDesignerWidgetBox : public QDesignerWidgetBoxInte public: enum LoadMode { LoadMerge, LoadReplace, LoadCustomWidgetsOnly }; - explicit QDesignerWidgetBox(QWidget *parent = nullptr, Qt::WindowFlags flags = nullptr); + explicit QDesignerWidgetBox(QWidget *parent = nullptr, Qt::WindowFlags flags = {}); LoadMode loadMode() const; void setLoadMode(LoadMode lm); diff --git a/src/designer/src/lib/shared/qdesigner_widgetitem.cpp b/src/designer/src/lib/shared/qdesigner_widgetitem.cpp index 93dd2112e5..e6e6cd00ae 100644 --- a/src/designer/src/lib/shared/qdesigner_widgetitem.cpp +++ b/src/designer/src/lib/shared/qdesigner_widgetitem.cpp @@ -224,7 +224,7 @@ bool QDesignerWidgetItem::check(const QLayout *layout, QWidget *w, Qt::Orientati // well. Avoid nested layouts (as the effective stretch cannot be easily // computed and may mess things up). if (ptrToOrientations) - *ptrToOrientations = nullptr; + *ptrToOrientations = {}; const QObject *layoutParent = layout->parent(); if (!layoutParent || !layoutParent->isWidgetType() || !WidgetFactory::isFormEditorObject(layoutParent)) diff --git a/src/designer/src/lib/shared/qlayout_widget.cpp b/src/designer/src/lib/shared/qlayout_widget.cpp index 8520028387..aa05020769 100644 --- a/src/designer/src/lib/shared/qlayout_widget.cpp +++ b/src/designer/src/lib/shared/qlayout_widget.cpp @@ -199,7 +199,7 @@ static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area) { // check if there are any items in the way. Should be only spacers // Unique out items that span rows/columns. - QVector indexesToBeRemoved; + QList indexesToBeRemoved; indexesToBeRemoved.reserve(grid->count()); const int rightColumn = area.x() + area.width(); const int bottomRow = area.y() + area.height(); @@ -217,7 +217,7 @@ static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area) } } // remove, starting from last - if (!indexesToBeRemoved.empty()) { + if (!indexesToBeRemoved.isEmpty()) { std::stable_sort(indexesToBeRemoved.begin(), indexesToBeRemoved.end()); for (int i = indexesToBeRemoved.size() - 1; i >= 0; i--) delete grid->takeAt(indexesToBeRemoved[i]); @@ -460,12 +460,12 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) override {} // Helper for restoring layout states - using LayoutItemVector = QVector; + using LayoutItemVector = QList; static LayoutItemVector disassembleLayout(QLayout *lt); static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w); private: - using BoxLayoutState = QVector; + using BoxLayoutState = QList; static BoxLayoutState state(const QBoxLayout*lt); @@ -604,7 +604,7 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const }; // Horiontal, Vertical pair of state typedef QPair CellState; - using CellStates = QVector; + using CellStates = QList; // Figure out states of a cell and return as a flat vector of // [column1, column2,...] (address as row * columnCount + col) @@ -638,12 +638,11 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const GridLayoutState::CellStates GridLayoutState::cellStates(const QList &rects, int numRows, int numColumns) { CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free)); - const QList::const_iterator rcend = rects.constEnd(); - for (QList::const_iterator it = rects.constBegin(); it != rcend; ++it) { - const int leftColumn = it->x(); - const int topRow = it->y(); - const int rightColumn = leftColumn + it->width() - 1; - const int bottomRow = topRow + it->height() - 1; + for (const auto &rect : rects) { + const int leftColumn = rect.x(); + const int topRow = rect.y(); + const int rightColumn = leftColumn + rect.width() - 1; + const int bottomRow = topRow + rect.height() - 1; for (int r = topRow; r <= bottomRow; r++) for (int c = leftColumn; c <= rightColumn; c++) { const int flatIndex = r * numColumns + c; @@ -773,8 +772,8 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const bool GridLayoutState::simplify(const QRect &r, bool testOnly) { // figure out free rows/columns. - QVector occupiedRows(rowCount, false); - QVector occupiedColumns(colCount, false); + QList occupiedRows(rowCount, false); + QList occupiedColumns(colCount, false); // Mark everything outside restriction rectangle as occupied const int restrictionLeftColumn = r.x(); const int restrictionRightColumn = restrictionLeftColumn + r.width(); @@ -979,7 +978,7 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) { - Q_ASSERT(!m_states.empty()); + Q_ASSERT(!m_states.isEmpty()); const GridLayoutState state = m_states.pop(); state.applyToLayout(core, widgetWithManagedLayout); } @@ -1011,7 +1010,7 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const class FormLayoutHelper : public LayoutHelper { public: typedef QPair WidgetPair; - using FormLayoutState = QVector; + using FormLayoutState = QList; FormLayoutHelper() = default; @@ -1137,7 +1136,7 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) { QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); - Q_ASSERT(!m_states.empty() && formLayout); + Q_ASSERT(!m_states.isEmpty() && formLayout); const FormLayoutState storedState = m_states.pop(); const FormLayoutState currentState = state(formLayout); @@ -1176,7 +1175,7 @@ QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) { using LayoutItemPair = QPair; - using LayoutItemPairs = QVector; + using LayoutItemPairs = QList; QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); Q_ASSERT(formLayout); @@ -1916,11 +1915,11 @@ void QLayoutWidget::paintEvent(QPaintEvent*) columns[column + i - 2] = true; while (rowSpan > 0) { - excludedColumnsForRow[row + rowSpan - 1].unite(columns); + excludedColumnsForRow[row + rowSpan - 1].insert(columns); rowSpan--; } while (columnSpan > 0) { - excludedRowsForColumn[column + columnSpan - 1].unite(rows); + excludedRowsForColumn[column + columnSpan - 1].insert(rows); columnSpan--; } } diff --git a/src/designer/src/lib/shared/qsimpleresource.cpp b/src/designer/src/lib/shared/qsimpleresource.cpp index 705d7b608d..eca53c2168 100644 --- a/src/designer/src/lib/shared/qsimpleresource.cpp +++ b/src/designer/src/lib/shared/qsimpleresource.cpp @@ -40,13 +40,14 @@ #include -#include #include -#include + +#include +#include + #include #include - QT_BEGIN_NAMESPACE namespace qdesigner_internal { @@ -156,7 +157,7 @@ void QSimpleResource::addFakeMethodsToWidgetDataBase(const DomCustomWidget *domC // Classes whose base class could not be found are left in the list. void QSimpleResource::addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, - QVector &custom_widget_list) + QList &custom_widget_list) { QDesignerWidgetDataBaseInterface *db = core->widgetDataBase(); for (int i=0; i < custom_widget_list.size(); ) { @@ -224,7 +225,7 @@ void QSimpleResource::handleDomCustomWidgets(const QDesignerFormEditorInterface // (derived first, max depth: promoted custom plugin = 2) for (int iteration = 0; iteration < 2; iteration++) { addCustomWidgetsToWidgetDatabase(core, custom_widget_list); - if (custom_widget_list.empty()) + if (custom_widget_list.isEmpty()) return; } // Oops, there are classes left whose base class could not be found. @@ -250,7 +251,7 @@ FormBuilderClipboard::FormBuilderClipboard(QWidget *w) bool FormBuilderClipboard::empty() const { - return m_widgets.empty() && m_actions.empty(); + return m_widgets.isEmpty() && m_actions.isEmpty(); } } diff --git a/src/designer/src/lib/shared/qsimpleresource_p.h b/src/designer/src/lib/shared/qsimpleresource_p.h index e2dccaa530..2c8ae1456a 100644 --- a/src/designer/src/lib/shared/qsimpleresource_p.h +++ b/src/designer/src/lib/shared/qsimpleresource_p.h @@ -40,10 +40,11 @@ #ifndef QSIMPLERESOURCE_H #define QSIMPLERESOURCE_H -#include "shared_global_p.h" #include "abstractformbuilder.h" +#include "shared_global_p.h" + +#include #include -#include QT_BEGIN_NAMESPACE @@ -91,7 +92,7 @@ class QDESIGNER_SHARED_EXPORT QSimpleResource : public QAbstractFormBuilder private: static void addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, - QVector &custom_widget_list); + QList &custom_widget_list); static void addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item); static bool m_warningsEnabled; diff --git a/src/designer/src/lib/shared/qtresourceeditordialog.cpp b/src/designer/src/lib/shared/qtresourceeditordialog.cpp index f2275d0b9e..613c5d0c9a 100644 --- a/src/designer/src/lib/shared/qtresourceeditordialog.cpp +++ b/src/designer/src/lib/shared/qtresourceeditordialog.cpp @@ -399,10 +399,10 @@ void QtQrcManager::exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) QList resourceList; - const QList resourcePrefixes = qrcFile->resourcePrefixList(); + const auto resourcePrefixes = qrcFile->resourcePrefixList(); for (const QtResourcePrefix *prefix : resourcePrefixes) { QList resourceFileList; - const QList resourceFiles = prefix->resourceFiles(); + const auto resourceFiles = prefix->resourceFiles(); for (QtResourceFile *file : resourceFiles) { QtResourceFileData fileData; fileData.path = file->path(); @@ -460,7 +460,7 @@ QtResourcePrefix *QtQrcManager::prevResourcePrefix(QtResourcePrefix *resourcePre { if (!resourcePrefix) return nullptr; - QList prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); + const auto prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); const int idx = prefixes.indexOf(resourcePrefix); if (idx <= 0) return nullptr; @@ -471,7 +471,7 @@ QtResourcePrefix *QtQrcManager::nextResourcePrefix(QtResourcePrefix *resourcePre { if (!resourcePrefix) return nullptr; - QList prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); + const auto prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); const int idx = prefixes.indexOf(resourcePrefix); if (idx < 0 || idx == prefixes.size() - 1) return nullptr; @@ -482,7 +482,7 @@ QtResourceFile *QtQrcManager::prevResourceFile(QtResourceFile *resourceFile) con { if (!resourceFile) return nullptr; - QList files = resourcePrefixOf(resourceFile)->resourceFiles(); + const auto files = resourcePrefixOf(resourceFile)->resourceFiles(); const int idx = files.indexOf(resourceFile); if (idx <= 0) return nullptr; @@ -493,7 +493,7 @@ QtResourceFile *QtQrcManager::nextResourceFile(QtResourceFile *resourceFile) con { if (!resourceFile) return nullptr; - QList files = resourcePrefixOf(resourceFile)->resourceFiles(); + const auto files = resourcePrefixOf(resourceFile)->resourceFiles(); const int idx = files.indexOf(resourceFile); if (idx < 0 || idx == files.size() - 1) return nullptr; @@ -502,7 +502,7 @@ QtResourceFile *QtQrcManager::nextResourceFile(QtResourceFile *resourceFile) con void QtQrcManager::clear() { - const QList oldQrcFiles = qrcFiles(); + const auto oldQrcFiles = qrcFiles(); for (QtQrcFile *qf : oldQrcFiles) removeQrcFile(qf); } @@ -569,7 +569,7 @@ void QtQrcManager::removeQrcFile(QtQrcFile *qrcFile) if (idx < 0) return; - const QList resourcePrefixes = qrcFile->resourcePrefixList(); + const auto resourcePrefixes = qrcFile->resourcePrefixList(); for (QtResourcePrefix *rp : resourcePrefixes) removeResourcePrefix(rp); @@ -672,7 +672,7 @@ void QtQrcManager::removeResourcePrefix(QtResourcePrefix *resourcePrefix) const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix); - const QList resourceFiles = resourcePrefix->resourceFiles(); + const auto resourceFiles = resourcePrefix->resourceFiles(); for (QtResourceFile *rf : resourceFiles) removeResourceFile(rf); @@ -1013,7 +1013,7 @@ void QtResourceEditorDialogPrivate::slotResourcePrefixMoved(QtResourcePrefix *re const QModelIndex index = m_treeModel->indexFromItem(prefixItem); const bool expanded = m_ui.resourceTreeView->isExpanded(index); m_ignoreCurrentChanged = true; - const QList items = m_treeModel->takeRow(index.row()); + const auto items = m_treeModel->takeRow(index.row()); int row = m_treeModel->rowCount(); QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(resourcePrefix); @@ -1126,7 +1126,7 @@ void QtResourceEditorDialogPrivate::slotResourceFileMoved(QtResourceFile *resour QStandardItem *parentItem = pathItem->parent(); m_ignoreCurrentChanged = true; - const QList items = parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row()); + const auto items = parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row()); int row = parentItem->rowCount(); QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(resourceFile); @@ -1189,7 +1189,7 @@ void QtResourceEditorDialogPrivate::slotCurrentQrcFileChanged(QListWidgetItem *i QMap currentPrefixList = m_resourcePrefixToPrefixItem; for (auto it = currentPrefixList.cbegin(), end = currentPrefixList.cend(); it != end; ++it) { QtResourcePrefix *resourcePrefix = it.key(); - const QList currentResourceFiles = resourcePrefix->resourceFiles(); + const auto currentResourceFiles = resourcePrefix->resourceFiles(); for (QtResourceFile *rf : currentResourceFiles) slotResourceFileRemoved(rf); slotResourcePrefixRemoved(resourcePrefix); @@ -1200,12 +1200,12 @@ void QtResourceEditorDialogPrivate::slotCurrentQrcFileChanged(QListWidgetItem *i slotCurrentTreeViewItemChanged(QModelIndex()); QStandardItem *firstPrefix = nullptr; // select first prefix if (m_currentQrcFile) { - const QList newPrefixList = m_currentQrcFile->resourcePrefixList(); + const auto newPrefixList = m_currentQrcFile->resourcePrefixList(); for (QtResourcePrefix *resourcePrefix : newPrefixList) { if (QStandardItem *newPrefixItem = insertResourcePrefix(resourcePrefix)) if (!firstPrefix) firstPrefix = newPrefixItem; - const QList newResourceFiles = resourcePrefix->resourceFiles(); + const auto newResourceFiles = resourcePrefix->resourceFiles(); for (QtResourceFile *rf : newResourceFiles) slotResourceFileInserted(rf); } @@ -1542,7 +1542,7 @@ void QtResourceEditorDialogPrivate::slotAddFiles() QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(currentResourceFile); if (!currentResourceFile) { - QList resourceFiles = currentResourcePrefix->resourceFiles(); + const auto resourceFiles = currentResourcePrefix->resourceFiles(); if (resourceFiles.count() > 0) nextResourceFile = resourceFiles.first(); } @@ -1660,7 +1660,7 @@ void QtResourceEditorDialogPrivate::slotClonePrefix() QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile, currentResourcePrefix->prefix(), currentResourcePrefix->language(), m_qrcManager->nextResourcePrefix(currentResourcePrefix)); if (newResourcePrefix) { - const QList files = currentResourcePrefix->resourceFiles(); + const auto files = currentResourcePrefix->resourceFiles(); for (QtResourceFile *resourceFile : files) { QString path = resourceFile->path(); QFileInfo fi(path); @@ -1996,7 +1996,7 @@ QtResourceEditorDialog::QtResourceEditorDialog(QDesignerFormEditorInterface *cor d_ptr->m_ui.splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray()); const QVariant geometry = settings->value(QLatin1String(Geometry)); - if (geometry.type() == QVariant::ByteArray) // Used to be a QRect up until 5.4.0, QTBUG-43374 + if (geometry.metaType().id() == QMetaType::QByteArray) // Used to be a QRect up until 5.4.0, QTBUG-43374 restoreGeometry(geometry.toByteArray()); settings->endGroup(); @@ -2096,7 +2096,7 @@ void QtResourceEditorDialog::accept() QStringList newQrcPaths; QList currentState; - const QList qrcFiles = d_ptr->m_qrcManager->qrcFiles(); + const auto qrcFiles = d_ptr->m_qrcManager->qrcFiles(); for (QtQrcFile *qrcFile : qrcFiles) { QtQrcFileData qrcFileData; d_ptr->m_qrcManager->exportQrcFile(qrcFile, &qrcFileData); diff --git a/src/designer/src/lib/shared/qtresourcemodel.cpp b/src/designer/src/lib/shared/qtresourcemodel.cpp index 1586fcf448..391cf49a38 100644 --- a/src/designer/src/lib/shared/qtresourcemodel.cpp +++ b/src/designer/src/lib/shared/qtresourcemodel.cpp @@ -169,7 +169,7 @@ const QByteArray *QtResourceModelPrivate::createResource(const QString &path, QS *errorCount = library.failedResources().size(); *contents = resMap.keys(); - if (resMap.empty()) + if (resMap.isEmpty()) break; buffer.close(); @@ -279,9 +279,9 @@ void QtResourceModelPrivate::activate(QtResourceSet *resourceSet, const QStringL m_pathToModified.insert(path, false); m_pathToContents.insert(path, contents); newResourceSetChanged = true; - const QMap >::iterator itReload = m_pathToResourceSet.find(path); + const auto itReload = m_pathToResourceSet.find(path); if (itReload != m_pathToResourceSet.end()) { - const QList resources = itReload.value(); + const auto resources = itReload.value(); for (QtResourceSet *res : resources) { if (res != resourceSet) { m_resourceSetToReload[res] = true; @@ -292,8 +292,8 @@ void QtResourceModelPrivate::activate(QtResourceSet *resourceSet, const QStringL } } - const QList oldData = m_pathToData.values(); - const QList newData = newPathToData.values(); + const auto oldData = m_pathToData.values(); + const auto newData = newPathToData.values(); QList toDelete; for (const QByteArray *array : oldData) { @@ -373,7 +373,7 @@ void QtResourceModelPrivate::removeOldPaths(QtResourceSet *resourceSet, const QS // remove old for (const QString &oldPath : oldPaths) { if (!newPaths.contains(oldPath)) { - const QMap >::iterator itRemove = m_pathToResourceSet.find(oldPath); + const auto itRemove = m_pathToResourceSet.find(oldPath); if (itRemove != m_pathToResourceSet.end()) { const int idx = itRemove.value().indexOf(resourceSet); if (idx >= 0) @@ -452,7 +452,7 @@ QtResourceModel::QtResourceModel(QObject *parent) : QtResourceModel::~QtResourceModel() { blockSignals(true); - const QList resourceList = resourceSets(); + const auto resourceList = resourceSets(); for (QtResourceSet *rs : resourceList) removeResourceSet(rs); blockSignals(false); @@ -478,11 +478,11 @@ void QtResourceModel::setModified(const QString &path) return; d_ptr->m_pathToModified[path] = true; - QMap >::const_iterator it = d_ptr->m_pathToResourceSet.constFind(path); + const auto it = d_ptr->m_pathToResourceSet.constFind(path); if (it == d_ptr->m_pathToResourceSet.constEnd()) return; - const QList resourceList = it.value(); + const auto resourceList = it.value(); for (QtResourceSet *rs : resourceList) d_ptr->m_resourceSetToReload.insert(rs, true); } diff --git a/src/designer/src/lib/shared/qtresourceview.cpp b/src/designer/src/lib/shared/qtresourceview.cpp index 61f00a53dc..fa40394b59 100644 --- a/src/designer/src/lib/shared/qtresourceview.cpp +++ b/src/designer/src/lib/shared/qtresourceview.cpp @@ -35,28 +35,30 @@ #include #include -#include #include #include #include #include #include -#include -#include -#include -#include -#include #include #include #include #include -#if QT_CONFIG(clipboard) -#include -#endif #include #include + +#include +#if QT_CONFIG(clipboard) +# include +#endif #include +#include + #include +#include +#include +#include + #include #include @@ -845,7 +847,7 @@ QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, Q settings->beginGroup(QLatin1String(ResourceViewDialogC)); const QVariant geometry = settings->value(QLatin1String(Geometry)); - if (geometry.type() == QVariant::ByteArray) // Used to be a QRect up until 5.4.0, QTBUG-43374. + if (geometry.metaType().id() == QMetaType::QByteArray) // Used to be a QRect up until 5.4.0, QTBUG-43374. restoreGeometry(geometry.toByteArray()); settings->endGroup(); diff --git a/src/designer/src/lib/shared/rcc.cpp b/src/designer/src/lib/shared/rcc.cpp index b98f17e07c..6d271bd8ad 100644 --- a/src/designer/src/lib/shared/rcc.cpp +++ b/src/designer/src/lib/shared/rcc.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -589,7 +588,7 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) parent->m_children.insert(node, s); parent = s; } else { - parent = parent->m_children[node]; + parent = *parent->m_children.constFind(node); } } @@ -602,7 +601,7 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) qPrintable(fileName), qPrintable(filename)); } } - parent->m_children.insertMulti(filename, s); + parent->m_children.insert(filename, s); return true; } @@ -895,12 +894,11 @@ bool RCCResourceLibrary::writeDataStructure() file->m_childOffset = offset; //sort by hash value for binary lookup - QList m_children = file->m_children.values(); - std::sort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); + auto children = file->m_children.values(); + std::sort(children.begin(), children.end(), qt_rcc_compare_hash); //write out the actual data now - for (int i = 0; i < m_children.size(); ++i) { - RCCFileInfo *child = m_children.at(i); + for (RCCFileInfo *child : children) { ++offset; if (child->m_flags & RCCFileInfo::Directory) pending.push(child); @@ -914,12 +912,11 @@ bool RCCResourceLibrary::writeDataStructure() RCCFileInfo *file = pending.pop(); //sort by hash value for binary lookup - QList m_children = file->m_children.values(); - std::sort(m_children.begin(), m_children.end(), qt_rcc_compare_hash); + auto children = file->m_children.values(); + std::sort(children.begin(), children.end(), qt_rcc_compare_hash); //write out the actual data now - for (int i = 0; i < m_children.size(); ++i) { - RCCFileInfo *child = m_children.at(i); + for (RCCFileInfo *child : children) { child->writeDataInfo(*this); if (child->m_flags & RCCFileInfo::Directory) pending.push(child); @@ -953,6 +950,16 @@ void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name) } } +static bool unacceptableChar(QChar qc) +{ + if (qc.isDigit()) + return false; + if (!qc.isLetter()) + return true; + auto c = qc.toLower().toLatin1(); + return c < 'a' || c > 'z'; +} + bool RCCResourceLibrary::writeInitializer() { if (m_format == C_Code) { @@ -960,7 +967,8 @@ bool RCCResourceLibrary::writeInitializer() QString initName = m_initName; if (!initName.isEmpty()) { initName.prepend(QLatin1Char('_')); - initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_")); + std::replace_if(initName.begin(), initName.end(), + unacceptableChar, QLatin1Char('_')); } //init diff --git a/src/designer/src/lib/shared/richtexteditor.cpp b/src/designer/src/lib/shared/richtexteditor.cpp index ca2a82b090..3818de6f72 100644 --- a/src/designer/src/lib/shared/richtexteditor.cpp +++ b/src/designer/src/lib/shared/richtexteditor.cpp @@ -36,29 +36,31 @@ #include #include -#include -#include -#include -#include - -#include #include #include -#include -#include -#include -#include #include -#include #include -#include -#include #include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + QT_BEGIN_NAMESPACE static const char RichTextDialogGroupC[] = "RichTextDialog"; @@ -70,13 +72,13 @@ const bool simplifyRichTextDefault = true; namespace qdesigner_internal { // Richtext simplification filter helpers: Elements to be discarded -static inline bool filterElement(const QStringRef &name) +static inline bool filterElement(QStringView name) { return name != QStringLiteral("meta") && name != QStringLiteral("style"); } // Richtext simplification filter helpers: Filter attributes of elements -static inline void filterAttributes(const QStringRef &name, +static inline void filterAttributes(QStringView name, QXmlStreamAttributes *atts, bool *paragraphAlignmentFound) { @@ -103,8 +105,8 @@ static inline void filterAttributes(const QStringRef &name, } } -// Richtext simplification filter helpers: Check for blank QStringRef. -static inline bool isWhiteSpace(const QStringRef &in) +// Richtext simplification filter helpers: Check for blank QStringView. +static inline bool isWhiteSpace(QStringView in) { const int count = in.size(); for (int i = 0; i < count; i++) @@ -131,7 +133,7 @@ QString simplifyRichTextFilter(const QString &in, bool *isPlainTextPtr = nullptr case QXmlStreamReader::StartElement: elementCount++; if (filterElement(reader.name())) { - const QStringRef name = reader.name(); + const auto name = reader.name(); QXmlStreamAttributes attributes = reader.attributes(); filterAttributes(name, &attributes, ¶graphAlignmentFound); writer.writeStartElement(name.toString()); @@ -425,7 +427,7 @@ RichTextEditorToolBar::RichTextEditorToolBar(QDesignerFormEditorInterface *core, { // Font size combo box m_font_size_input->setEditable(false); - const QList font_sizes = QFontDatabase::standardSizes(); + const auto font_sizes = QFontDatabase::standardSizes(); for (int font_size : font_sizes) m_font_size_input->addItem(QString::number(font_size)); diff --git a/src/designer/src/lib/shared/selectsignaldialog.cpp b/src/designer/src/lib/shared/selectsignaldialog.cpp index 67b988a56d..576dd0bdb8 100644 --- a/src/designer/src/lib/shared/selectsignaldialog.cpp +++ b/src/designer/src/lib/shared/selectsignaldialog.cpp @@ -38,12 +38,14 @@ #include "widgetdatabase_p.h" #include -#include #include + +#include #include + #include +#include #include -#include #include @@ -53,7 +55,7 @@ namespace qdesigner_internal { enum { MethodRole = Qt::UserRole + 1 }; -using Methods = QVector; +using Methods = QList; SelectSignalDialog::SelectSignalDialog(QWidget *parent) : QDialog(parent) @@ -69,7 +71,7 @@ SelectSignalDialog::SelectSignalDialog(QWidget *parent) this, &SelectSignalDialog::currentChanged); connect(m_ui->signalList, &QTreeView::activated, this, &SelectSignalDialog::activated); - const QRect availableGeometry = QApplication::desktop()->availableGeometry(this); + const QRect availableGeometry = screen()->geometry(); resize(availableGeometry.width() / 5, availableGeometry.height() / 2); } @@ -162,7 +164,7 @@ void SelectSignalDialog::populate(QDesignerFormEditorInterface *core, QObject *o if (defaultSignal.isEmpty()) { selectedIndex = m_model->index(0, 0, m_model->index(0, 0, QModelIndex())); // first method } else { - const QList items = m_model->findItems(defaultSignal, Qt::MatchExactly | Qt::MatchRecursive, 0); + const auto items = m_model->findItems(defaultSignal, Qt::MatchExactly | Qt::MatchRecursive, 0); if (!items.isEmpty()) selectedIndex = m_model->indexFromItem(items.constFirst()); } @@ -240,3 +242,5 @@ void SelectSignalDialog::currentChanged(const QModelIndex ¤t, const QModel } // namespace qdesigner_internal QT_END_NAMESPACE + +#include "moc_selectsignaldialog_p.cpp" diff --git a/src/designer/src/lib/shared/shared.pri b/src/designer/src/lib/shared/shared.pri deleted file mode 100644 index 99d52a4bf8..0000000000 --- a/src/designer/src/lib/shared/shared.pri +++ /dev/null @@ -1,192 +0,0 @@ - -INCLUDEPATH += $$PWD - -# When linking dynamically, use only the QKeySequenceEdit widget of -# the property browser solution as the other symbols of the property -# browser solution must not be duplicated (see e7762b60d51). When linking -# statically, add the property browser solution to make the library self-contained -# and use only the include path in the property editor (see propertyeditor.pri) - -contains(CONFIG, static) { - include(../../../../shared/qtpropertybrowser/qtpropertybrowser.pri) -} else { - include(../../../../shared/qtpropertybrowser/qtpropertybrowserutils.pri) -} - -include(../../../../shared/deviceskin/deviceskin.pri) -include(../../../../shared/findwidget/findwidget.pri) -include(../../../../shared/qtgradienteditor/qtgradienteditor.pri) - -# Input -FORMS += $$PWD/addlinkdialog.ui \ - $$PWD/orderdialog.ui \ - $$PWD/newactiondialog.ui \ - $$PWD/gridpanel.ui \ - $$PWD/signalslotdialog.ui \ - $$PWD/previewconfigurationwidget.ui \ - $$PWD/qtresourceeditordialog.ui \ - $$PWD/newformwidget.ui \ - $$PWD/selectsignaldialog.ui \ - $$PWD/formlayoutrowdialog.ui \ - $$PWD/plugindialog.ui - -HEADERS += \ - $$PWD/shared_global_p.h \ - $$PWD/spacer_widget_p.h \ - $$PWD/layoutinfo_p.h \ - $$PWD/layout_p.h \ - $$PWD/connectionedit_p.h \ - $$PWD/pluginmanager_p.h \ - $$PWD/metadatabase_p.h \ - $$PWD/qdesigner_formeditorcommand_p.h \ - $$PWD/qdesigner_formwindowcommand_p.h \ - $$PWD/qdesigner_command_p.h \ - $$PWD/morphmenu_p.h \ - $$PWD/qdesigner_command2_p.h \ - $$PWD/qdesigner_formbuilder_p.h \ - $$PWD/qdesigner_taskmenu_p.h \ - $$PWD/formlayoutmenu_p.h \ - $$PWD/qdesigner_widget_p.h \ - $$PWD/qdesigner_propertysheet_p.h \ - $$PWD/qdesigner_membersheet_p.h \ - $$PWD/qdesigner_propertyeditor_p.h \ - $$PWD/qdesigner_objectinspector_p.h \ - $$PWD/invisible_widget_p.h \ - $$PWD/qlayout_widget_p.h \ - $$PWD/sheet_delegate_p.h \ - $$PWD/qdesigner_stackedbox_p.h \ - $$PWD/qdesigner_tabwidget_p.h \ - $$PWD/qdesigner_dockwidget_p.h \ - $$PWD/qdesigner_toolbox_p.h \ - $$PWD/qdesigner_dnditem_p.h \ - $$PWD/qsimpleresource_p.h \ - $$PWD/widgetfactory_p.h \ - $$PWD/widgetdatabase_p.h \ - $$PWD/qdesigner_promotion_p.h \ - $$PWD/qdesigner_introspection_p.h \ - $$PWD/promotionmodel_p.h \ - $$PWD/qdesigner_promotiondialog_p.h \ - $$PWD/iconloader_p.h \ - $$PWD/richtexteditor_p.h \ - $$PWD/plaintexteditor_p.h \ - $$PWD/actioneditor_p.h \ - $$PWD/actionrepository_p.h \ - $$PWD/qdesigner_toolbar_p.h \ - $$PWD/qdesigner_menubar_p.h \ - $$PWD/qdesigner_menu_p.h \ - $$PWD/actionprovider_p.h \ - $$PWD/orderdialog_p.h \ - $$PWD/newactiondialog_p.h \ - $$PWD/stylesheeteditor_p.h \ - $$PWD/csshighlighter_p.h \ - $$PWD/shared_enums_p.h \ - $$PWD/textpropertyeditor_p.h \ - $$PWD/propertylineedit_p.h \ - $$PWD/promotiontaskmenu_p.h \ - $$PWD/gridpanel_p.h \ - $$PWD/grid_p.h \ - $$PWD/formwindowbase_p.h \ - $$PWD/qdesigner_utils_p.h \ - $$PWD/qdesigner_widgetbox_p.h \ - $$PWD/signalslotdialog_p.h \ - $$PWD/extensionfactory_p.h \ - $$PWD/dialoggui_p.h \ - $$PWD/deviceprofile_p.h \ - $$PWD/zoomwidget_p.h \ - $$PWD/previewmanager_p.h \ - $$PWD/previewconfigurationwidget_p.h \ - $$PWD/codedialog_p.h \ - $$PWD/qtresourceeditordialog_p.h \ - $$PWD/qtresourcemodel_p.h \ - $$PWD/qtresourceview_p.h \ - $$PWD/iconselector_p.h \ - $$PWD/htmlhighlighter_p.h \ - $$PWD/qdesigner_widgetitem_p.h \ - $$PWD/qdesigner_qsettings_p.h \ - $$PWD/qdesigner_formwindowmanager_p.h \ - $$PWD/shared_settings_p.h \ - $$PWD/newformwidget_p.h \ - $$PWD/plugindialog_p.h \ - $$PWD/rcc_p.h \ - $$PWD/selectsignaldialog_p.h - -SOURCES += \ - $$PWD/spacer_widget.cpp \ - $$PWD/layoutinfo.cpp \ - $$PWD/layout.cpp \ - $$PWD/connectionedit.cpp \ - $$PWD/pluginmanager.cpp \ - $$PWD/qdesigner_formwindowcommand.cpp \ - $$PWD/qdesigner_formeditorcommand.cpp \ - $$PWD/qdesigner_command.cpp \ - $$PWD/morphmenu.cpp \ - $$PWD/qdesigner_command2.cpp \ - $$PWD/qdesigner_propertycommand.cpp \ - $$PWD/qdesigner_formbuilder.cpp \ - $$PWD/qdesigner_taskmenu.cpp \ - $$PWD/formlayoutmenu.cpp \ - $$PWD/qdesigner_widget.cpp \ - $$PWD/qdesigner_dockwidget.cpp \ - $$PWD/qdesigner_propertysheet.cpp \ - $$PWD/qdesigner_membersheet.cpp \ - $$PWD/qdesigner_propertyeditor.cpp \ - $$PWD/qdesigner_objectinspector.cpp \ - $$PWD/qdesigner_dnditem.cpp \ - $$PWD/qsimpleresource.cpp \ - $$PWD/invisible_widget.cpp \ - $$PWD/qlayout_widget.cpp \ - $$PWD/sheet_delegate.cpp \ - $$PWD/metadatabase.cpp \ - $$PWD/qdesigner_stackedbox.cpp \ - $$PWD/qdesigner_tabwidget.cpp \ - $$PWD/qdesigner_toolbox.cpp \ - $$PWD/widgetfactory.cpp \ - $$PWD/widgetdatabase.cpp \ - $$PWD/qdesigner_promotion.cpp \ - $$PWD/qdesigner_introspection.cpp \ - $$PWD/promotionmodel.cpp \ - $$PWD/qdesigner_promotiondialog.cpp \ - $$PWD/richtexteditor.cpp \ - $$PWD/plaintexteditor.cpp \ - $$PWD/actioneditor.cpp \ - $$PWD/actionrepository.cpp \ - $$PWD/qdesigner_toolbar.cpp \ - $$PWD/qdesigner_menubar.cpp \ - $$PWD/qdesigner_menu.cpp \ - $$PWD/orderdialog.cpp \ - $$PWD/newactiondialog.cpp \ - $$PWD/stylesheeteditor.cpp \ - $$PWD/csshighlighter.cpp \ - $$PWD/textpropertyeditor.cpp \ - $$PWD/propertylineedit.cpp \ - $$PWD/promotiontaskmenu.cpp \ - $$PWD/gridpanel.cpp \ - $$PWD/grid.cpp \ - $$PWD/formwindowbase.cpp \ - $$PWD/qdesigner_utils.cpp \ - $$PWD/qdesigner_widgetbox.cpp \ - $$PWD/iconloader.cpp \ - $$PWD/signalslotdialog.cpp \ - $$PWD/dialoggui.cpp \ - $$PWD/deviceprofile.cpp \ - $$PWD/zoomwidget.cpp \ - $$PWD/previewmanager.cpp \ - $$PWD/previewconfigurationwidget.cpp \ - $$PWD/codedialog.cpp \ - $$PWD/qtresourceeditordialog.cpp \ - $$PWD/qtresourcemodel.cpp \ - $$PWD/qtresourceview.cpp \ - $$PWD/iconselector.cpp \ - $$PWD/htmlhighlighter.cpp \ - $$PWD/qdesigner_widgetitem.cpp \ - $$PWD/qdesigner_qsettings.cpp \ - $$PWD/qdesigner_formwindowmanager.cpp \ - $$PWD/shared_settings.cpp \ - $$PWD/newformwidget.cpp \ - $$PWD/plugindialog.cpp \ - $$PWD/rcc.cpp \ - $$PWD/selectsignaldialog.cpp - -RESOURCES += $$PWD/shared.qrc - -TR_EXCLUDE += $$PWD/templates/* diff --git a/src/designer/src/lib/shared/shared_settings.cpp b/src/designer/src/lib/shared/shared_settings.cpp index b759555bd3..2800e89c5a 100644 --- a/src/designer/src/lib/shared/shared_settings.cpp +++ b/src/designer/src/lib/shared/shared_settings.cpp @@ -90,7 +90,7 @@ Grid QDesignerSharedSettings::defaultGrid() const Grid grid; const QVariantMap defaultGridMap = m_settings->value(QLatin1String(defaultGridKey), QVariantMap()).toMap(); - if (!defaultGridMap.empty()) + if (!defaultGridMap.isEmpty()) grid.fromVariantMap(defaultGridMap); return grid; } @@ -103,7 +103,7 @@ void QDesignerSharedSettings::setDefaultGrid(const Grid &grid) const QStringList &QDesignerSharedSettings::defaultFormTemplatePaths() { static QStringList rc; - if (rc.empty()) { + if (rc.isEmpty()) { // Ensure default form template paths const QString templatePath = QStringLiteral("/templates"); // home @@ -300,7 +300,7 @@ QDesignerSharedSettings::DeviceProfileList QDesignerSharedSettings::deviceProfil { DeviceProfileList rc; const QStringList xmls = deviceProfileXml(); - if (xmls.empty()) + if (xmls.isEmpty()) return rc; // De-serialize QString errorMessage; diff --git a/src/designer/src/lib/shared/shared_settings_p.h b/src/designer/src/lib/shared/shared_settings_p.h index 65dcf29bc5..7fded12180 100644 --- a/src/designer/src/lib/shared/shared_settings_p.h +++ b/src/designer/src/lib/shared/shared_settings_p.h @@ -52,7 +52,6 @@ QT_BEGIN_NAMESPACE class QDesignerFormEditorInterface; class QDesignerSettingsInterface; -class QStringList; class QSize; namespace qdesigner_internal { diff --git a/src/designer/src/lib/shared/signalslotdialog.cpp b/src/designer/src/lib/shared/signalslotdialog.cpp index 5c0d9e1fef..65297030de 100644 --- a/src/designer/src/lib/shared/signalslotdialog.cpp +++ b/src/designer/src/lib/shared/signalslotdialog.cpp @@ -270,7 +270,7 @@ void SignaturePanel::slotAdd() newSlot += QString::number(i); // Always add number, Avoid setting 'slot' for first entry newSlot += QLatin1Char('('); // check for function name independent of parameters - if (m_model->findItems(newSlot, Qt::MatchStartsWith, 0).empty()) { + if (m_model->findItems(newSlot, Qt::MatchStartsWith, 0).isEmpty()) { newSlot += QLatin1Char(')'); QStandardItem * item = createEditableItem(newSlot); m_model->appendRow(item); @@ -290,13 +290,13 @@ int SignaturePanel::count(const QString &signature) const void SignaturePanel::slotRemove() { const QModelIndexList selectedIndexes = m_listView->selectionModel()->selectedIndexes (); - if (selectedIndexes.empty()) + if (selectedIndexes.isEmpty()) return; closeEditor(); // scroll to previous - if (const int row = selectedIndexes.front().row()) - m_listView->setCurrentIndex (selectedIndexes.front().sibling(row - 1, 0)); + if (const int row = selectedIndexes.constFirst().row()) + m_listView->setCurrentIndex (selectedIndexes.constFirst().sibling(row - 1, 0)); for (int i = selectedIndexes.size() - 1; i >= 0; i--) qDeleteAll(m_model->takeRow(selectedIndexes[i].row())); @@ -304,7 +304,7 @@ void SignaturePanel::slotRemove() void SignaturePanel::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &) { - m_removeButton->setEnabled(!selected.indexes().empty()); + m_removeButton->setEnabled(!selected.indexes().isEmpty()); } void SignaturePanel::setData(const SignalSlotDialogData &d) @@ -515,3 +515,5 @@ bool SignalSlotDialog::editPromotedClass(QDesignerFormEditorInterface *core, con } QT_END_NAMESPACE + +#include "moc_signalslotdialog_p.cpp" diff --git a/src/designer/src/lib/shared/stylesheeteditor.cpp b/src/designer/src/lib/shared/stylesheeteditor.cpp index c7b36c4222..2956d1abc9 100644 --- a/src/designer/src/lib/shared/stylesheeteditor.cpp +++ b/src/designer/src/lib/shared/stylesheeteditor.cpp @@ -44,18 +44,19 @@ #include -#include #include #include #include #include #include -#include #include #include -#include +#include #include +#include + +#include QT_BEGIN_NAMESPACE diff --git a/src/designer/src/lib/shared/textpropertyeditor.cpp b/src/designer/src/lib/shared/textpropertyeditor.cpp index 88e8841b6e..e78cb81b40 100644 --- a/src/designer/src/lib/shared/textpropertyeditor.cpp +++ b/src/designer/src/lib/shared/textpropertyeditor.cpp @@ -259,7 +259,7 @@ namespace qdesigner_internal { break; case ValidationURL: { static QStringList urlCompletions; - if (urlCompletions.empty()) { + if (urlCompletions.isEmpty()) { urlCompletions.push_back(QStringLiteral("about:blank")); urlCompletions.push_back(QStringLiteral("http://")); urlCompletions.push_back(QStringLiteral("http://www.")); diff --git a/src/designer/src/lib/shared/widgetdatabase.cpp b/src/designer/src/lib/shared/widgetdatabase.cpp index 1a9297e73e..8621f28408 100644 --- a/src/designer/src/lib/shared/widgetdatabase.cpp +++ b/src/designer/src/lib/shared/widgetdatabase.cpp @@ -373,10 +373,8 @@ void WidgetDataBase::loadPlugins() unsigned replacedPlugins = 0; unsigned addedPlugins = 0; unsigned removedPlugins = 0; - if (!pluginList.empty()) { - ItemList::const_iterator cend = pluginList.constEnd(); - for (ItemList::const_iterator it = pluginList.constBegin();it != cend; ++it ) { - QDesignerWidgetDataBaseItemInterface* pluginItem = *it; + if (!pluginList.isEmpty()) { + for (QDesignerWidgetDataBaseItemInterface *pluginItem : qAsConst(pluginList)) { const QString pluginName = pluginItem->name(); NameIndexMap::iterator existingIt = existingCustomClasses.find(pluginName); if (existingIt == existingCustomClasses.end()) { @@ -399,7 +397,7 @@ void WidgetDataBase::loadPlugins() } } // 4) remove classes that have not been matched. The stored indexes become invalid while deleting. - if (!existingCustomClasses.empty()) { + if (!existingCustomClasses.isEmpty()) { NameIndexMap::const_iterator cend = existingCustomClasses.constEnd(); for (NameIndexMap::const_iterator it = existingCustomClasses.constBegin();it != cend; ++it ) { const int index = indexOfClassName(it.key()); @@ -429,10 +427,10 @@ QList WidgetDataBase::defaultPropertyValues(const QString &name) object = factory->createWidget(name, nullptr); if (!object) { qDebug() << "** WARNING Factory failed to create " << name; - return QList(); + return {}; } // Get properties from sheet. - QList result; + QVariantList result; if (const QDesignerPropertySheetExtension *sheet = qt_extension(m_core->extensionManager(), object)) { const int propertyCount = sheet->count(); for (int i = 0; i < propertyCount; ++i) { @@ -448,7 +446,7 @@ void WidgetDataBase::grabDefaultPropertyValues() const int itemCount = count(); for (int i = 0; i < itemCount; ++i) { QDesignerWidgetDataBaseItemInterface *dbItem = item(i); - const QList default_prop_values = defaultPropertyValues(dbItem->name()); + const auto default_prop_values = defaultPropertyValues(dbItem->name()); dbItem->setDefaultPropertyValues(default_prop_values); } } @@ -503,7 +501,7 @@ static inline bool suitableForNewForm(const QString &className) QStringList WidgetDataBase::formWidgetClasses(const QDesignerFormEditorInterface *core) { static QStringList rc; - if (rc.empty()) { + if (rc.isEmpty()) { const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); const int widgetCount = wdb->count(); for (int i = 0; i < widgetCount; i++) { @@ -601,22 +599,22 @@ static QString xmlFromWidgetBox(const QDesignerFormEditorInterface *core, const // Generate default standard ui new form xml based on the class passed on as similarClassName. static QString generateNewFormXML(const QString &className, const QString &similarClassName, const QString &name) { - QString rc; { - QTextStream str(&rc); - str << QStringLiteral("\n") << name << QStringLiteral("\n") - << QStringLiteral("\n") - << QStringLiteral("\n00") - << NewFormWidth << QStringLiteral("") << NewFormHeight << QStringLiteral("\n\n"); - str << QStringLiteral("\n") << name << QStringLiteral("\n\n"); - - if (similarClassName == QStringLiteral("QMainWindow")) { - str << QStringLiteral("\n"); - } else { - if (similarClassName == QStringLiteral("QWizard")) - str << QStringLiteral("\n"); - } - str << QStringLiteral("\n\n"); + QString rc; + QTextStream str(&rc); + str << R"()" << name << "" + << R"()" + << R"(00)" + << NewFormWidth << "" << NewFormHeight << "" + << R"()" << name << "\n"; + + if (similarClassName == QLatin1String("QMainWindow")) { + str << R"()"; + } else if (similarClassName == QLatin1String("QWizard")) { + str << R"()"; + } else if (similarClassName == QLatin1String("QDockWidget")) { + str << R"()"; } + str << "\n"; return rc; } @@ -645,7 +643,7 @@ QString WidgetDataBase::formTemplate(const QDesignerFormEditorInterface *core, c // Set a fixed size on a XML template QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, bool fixed) { - DomUI *domUI = QDesignerWidgetBox::xmlToUi(QStringLiteral("Form"), xml, false); + QScopedPointer domUI(QDesignerWidgetBox::xmlToUi(QStringLiteral("Form"), xml, false)); if (!domUI) return QString(); DomWidget *domWidget = domUI->elementWidget(); @@ -723,7 +721,6 @@ QString WidgetDataBase::scaleFormTemplate(const QString &xml, const QSize &size, writer.writeEndDocument(); } - delete domUI; return rc; } diff --git a/src/designer/src/lib/shared/widgetfactory.cpp b/src/designer/src/lib/shared/widgetfactory.cpp index 14cd721247..34253b32ba 100644 --- a/src/designer/src/lib/shared/widgetfactory.cpp +++ b/src/designer/src/lib/shared/widgetfactory.cpp @@ -71,6 +71,10 @@ #include #include +#ifdef QT_OPENGLWIDGETS_LIB +# include +#endif + QT_BEGIN_NAMESPACE #ifdef Q_OS_WIN @@ -78,7 +82,7 @@ static inline bool isAxWidget(const QObject *o) { // Is it one of QDesignerAxWidget/QDesignerAxPluginWidget? static const char *axWidgetName = "QDesignerAx"; - static const unsigned axWidgetNameLen = qstrlen(axWidgetName); + static const size_t axWidgetNameLen = qstrlen(axWidgetName); return qstrncmp(o->metaObject()->className(), axWidgetName, axWidgetNameLen) == 0; } #endif @@ -212,8 +216,7 @@ void WidgetFactory::loadPlugins() { m_customFactory.clear(); - const QList &lst = - m_core->pluginManager()->registeredCustomWidgets(); + const auto &lst = m_core->pluginManager()->registeredCustomWidgets(); for (QDesignerCustomWidgetInterface *c : lst) m_customFactory.insert(c->name(), c); } diff --git a/src/designer/src/lib/shared/zoomwidget.cpp b/src/designer/src/lib/shared/zoomwidget.cpp index fef509a39b..6c947f4acb 100644 --- a/src/designer/src/lib/shared/zoomwidget.cpp +++ b/src/designer/src/lib/shared/zoomwidget.cpp @@ -31,11 +31,12 @@ #include #include #include -#include -#include -#include #include +#include +#include +#include + #include #include #include @@ -43,9 +44,6 @@ QT_BEGIN_NAMESPACE -using ActionList = QList; -using GraphicsItemList = QList; - enum { debugZoomWidget = 0 }; static const int menuZoomList[] = { 100, 25, 50, 75, 125, 150 , 175, 200 }; @@ -77,11 +75,10 @@ int ZoomMenu::zoomOf(const QAction *a) void ZoomMenu::addActions(QMenu *m) { - const ActionList za = m_menuActions->actions(); - const ActionList::const_iterator cend = za.constEnd(); - for (ActionList::const_iterator it = za.constBegin(); it != cend; ++it) { - m->addAction(*it); - if (zoomOf(*it) == 100) + const auto za = m_menuActions->actions(); + for (QAction *a : za) { + m->addAction(a); + if (zoomOf(a) == 100) m->addSeparator(); } } @@ -93,13 +90,13 @@ int ZoomMenu::zoom() const void ZoomMenu::setZoom(int percent) { - const ActionList za = m_menuActions->actions(); - const ActionList::const_iterator cend = za.constEnd(); - for (ActionList::const_iterator it = za.constBegin(); it != cend; ++it) - if (zoomOf(*it) == percent) { - (*it)->setChecked(true); + const auto za = m_menuActions->actions(); + for (QAction *a : za) { + if (zoomOf(a) == percent) { + a->setChecked(true); return; } + } } void ZoomMenu::slotZoomMenu(QAction *a) @@ -107,9 +104,9 @@ void ZoomMenu::slotZoomMenu(QAction *a) emit zoomChanged(zoomOf(a)); } -QVector ZoomMenu::zoomValues() +QList ZoomMenu::zoomValues() { - QVector rc; + QList rc; const int nz = sizeof(menuZoomList)/sizeof(int); rc.reserve(nz); for (int i = 0; i < nz; i++) @@ -290,7 +287,7 @@ ZoomWidget::ZoomWidget(QWidget *parent) : void ZoomWidget::setWidget(QWidget *w, Qt::WindowFlags wFlags) { if (debugZoomWidget) - qDebug() << "ZoomWidget::setWidget" << w << bin << wFlags; + qDebug() << "ZoomWidget::setWidget" << w << Qt::bin << wFlags; if (m_proxy) { scene().removeItem(m_proxy); @@ -520,7 +517,7 @@ void ZoomWidget::dump() const { qDebug() << "ZoomWidget::dump " << geometry() << " Viewport " << viewport()->geometry() - << "Scroll: " << scrollPosition() << "Matrix: " << matrix() << " SceneRect: " << sceneRect(); + << "Scroll: " << scrollPosition() << "Transform: " << transform() << " SceneRect: " << sceneRect(); if (m_proxy) { qDebug() << "Proxy Pos: " << m_proxy->pos() << "Proxy " << m_proxy->size() << "\nProxy size hint" diff --git a/src/designer/src/lib/shared/zoomwidget_p.h b/src/designer/src/lib/shared/zoomwidget_p.h index 7745280698..1830be4be2 100644 --- a/src/designer/src/lib/shared/zoomwidget_p.h +++ b/src/designer/src/lib/shared/zoomwidget_p.h @@ -44,7 +44,8 @@ #include #include -#include + +#include QT_BEGIN_NAMESPACE @@ -68,7 +69,7 @@ class QDESIGNER_SHARED_EXPORT ZoomMenu : public QObject { int zoom() const; // Return a list of available zoom values. - static QVector zoomValues(); + static QList zoomValues(); public slots: void setZoom(int percent); diff --git a/src/designer/src/lib/uilib/abstractformbuilder.cpp b/src/designer/src/lib/uilib/abstractformbuilder.cpp index bc7ba02bfc..cbe53f3927 100644 --- a/src/designer/src/lib/uilib/abstractformbuilder.cpp +++ b/src/designer/src/lib/uilib/abstractformbuilder.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -55,17 +44,6 @@ #include "ui4_p.h" #include "properties_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include #include #include #include @@ -93,7 +71,18 @@ # include // Compiling within Designer #endif +#include +#include + +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -219,7 +208,7 @@ QWidget *QAbstractFormBuilder::create(DomUI *ui, QWidget *parentWidget) if (QWidget *widget = create(ui_widget, parentWidget)) { // Reparent button groups that were actually created to main container for them to be found in the signal/slot part const ButtonGroupHash &buttonGroups = d->buttonGroups(); - if (!buttonGroups.empty()) { + if (!buttonGroups.isEmpty()) { const ButtonGroupHash::const_iterator cend = buttonGroups.constEnd(); for (ButtonGroupHash::const_iterator it = buttonGroups.constBegin(); it != cend; ++it) if (it.value().second) @@ -297,7 +286,7 @@ QWidget *QAbstractFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidge } const auto &addActions = ui_widget->elementAddAction(); - if (!addActions.empty()) { + if (!addActions.isEmpty()) { const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); for (DomActionRef *ui_action_ref : addActions) { const QString name = ui_action_ref->attributeName(); @@ -794,10 +783,10 @@ static inline QString alignmentValue(Qt::Alignment a) static inline Qt::Alignment alignmentFromDom(const QString &in) { - Qt::Alignment rc = nullptr; + Qt::Alignment rc; if (!in.isEmpty()) { - const QVector flags = in.splitRef(QLatin1Char('|')); - for (const QStringRef &f : flags) { + const auto flags = QStringView{in}.split(QLatin1Char('|')); + for (const auto &f : flags) { if (f == QStringLiteral("Qt::AlignLeft")) { rc |= Qt::AlignLeft; } else if (f == QStringLiteral("Qt::AlignRight")) { @@ -881,7 +870,7 @@ QLayoutItem *QAbstractFormBuilder::create(DomLayoutItem *ui_layoutItem, QLayout const DomSpacer *ui_spacer = ui_layoutItem->elementSpacer(); const auto &spacerProperties = ui_spacer->elementProperty(); - if (!spacerProperties.empty()) { + if (!spacerProperties.isEmpty()) { const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); for (DomProperty *p : spacerProperties) { const QVariant v = toVariant(&QAbstractFormBuilderGadget::staticMetaObject, p); // ### remove me @@ -959,27 +948,7 @@ QVariant QAbstractFormBuilder::toVariant(const QMetaObject *meta, DomProperty *p void QAbstractFormBuilder::setupColorGroup(QPalette &palette, QPalette::ColorGroup colorGroup, DomColorGroup *group) { - // old format - const auto &colors = group->elementColor(); - for (int role = 0; role < colors.size(); ++role) { - const DomColor *color = colors.at(role); - const QColor c(color->elementRed(), color->elementGreen(), color->elementBlue()); - palette.setColor(colorGroup, QPalette::ColorRole(role), c); - } - - // new format - const QMetaEnum colorRole_enum = metaEnum("colorRole"); - - const auto colorRoles = group->elementColorRole(); - for (const DomColorRole *colorRole : colorRoles) { - if (colorRole->hasAttributeRole()) { - const int r = colorRole_enum.keyToValue(colorRole->attributeRole().toLatin1()); - if (r != -1) { - const QBrush br = setupBrush(colorRole->elementBrush()); - palette.setBrush(colorGroup, static_cast(r), br); - } - } - } + QFormBuilderExtra::setupColorGroup(&palette, colorGroup, group); } /*! @@ -987,26 +956,8 @@ void QAbstractFormBuilder::setupColorGroup(QPalette &palette, QPalette::ColorGro */ DomColorGroup *QAbstractFormBuilder::saveColorGroup(const QPalette &palette) { - - const QMetaEnum colorRole_enum = metaEnum("colorRole"); - - DomColorGroup *group = new DomColorGroup(); - QVector colorRoles; - - const uint mask = palette.resolve(); - for (int role = QPalette::WindowText; role < QPalette::NColorRoles; ++role) { - if (mask & (1 << role)) { - const QBrush &br = palette.brush(QPalette::ColorRole(role)); - - DomColorRole *colorRole = new DomColorRole(); - colorRole->setElementBrush(saveBrush(br)); - colorRole->setAttributeRole(QLatin1String(colorRole_enum.valueToKey(role))); - colorRoles.append(colorRole); - } - } - - group->setElementColorRole(colorRoles); - return group; + return QFormBuilderExtra::saveColorGroup(palette, + palette.currentColorGroup()); } /*! @@ -1014,143 +965,12 @@ DomColorGroup *QAbstractFormBuilder::saveColorGroup(const QPalette &palette) */ QBrush QAbstractFormBuilder::setupBrush(DomBrush *brush) { - QBrush br; - if (!brush->hasAttributeBrushStyle()) - return br; - - const Qt::BrushStyle style = enumKeyOfObjectToValue("brushStyle", - brush->attributeBrushStyle().toLatin1().constData()); - - if (style == Qt::LinearGradientPattern || - style == Qt::RadialGradientPattern || - style == Qt::ConicalGradientPattern) { - const QMetaEnum gradientType_enum = metaEnum("gradientType"); - const QMetaEnum gradientSpread_enum = metaEnum("gradientSpread"); - const QMetaEnum gradientCoordinate_enum = metaEnum("gradientCoordinate"); - - const DomGradient *gradient = brush->elementGradient(); - const QGradient::Type type = enumKeyToValue(gradientType_enum, gradient->attributeType().toLatin1()); - - - QGradient *gr = nullptr; - - if (type == QGradient::LinearGradient) { - gr = new QLinearGradient(QPointF(gradient->attributeStartX(), gradient->attributeStartY()), - QPointF(gradient->attributeEndX(), gradient->attributeEndY())); - } else if (type == QGradient::RadialGradient) { - gr = new QRadialGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()), - gradient->attributeRadius(), - QPointF(gradient->attributeFocalX(), gradient->attributeFocalY())); - } else if (type == QGradient::ConicalGradient) { - gr = new QConicalGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()), - gradient->attributeAngle()); - } - if (!gr) - return br; - - const QGradient::Spread spread = enumKeyToValue(gradientSpread_enum, gradient->attributeSpread().toLatin1()); - gr->setSpread(spread); - - const QGradient::CoordinateMode coord = enumKeyToValue(gradientCoordinate_enum, gradient->attributeCoordinateMode().toLatin1()); - gr->setCoordinateMode(coord); - - const auto &stops = gradient->elementGradientStop(); - for (const DomGradientStop *stop : stops) { - const DomColor *color = stop->elementColor(); - gr->setColorAt(stop->attributePosition(), QColor::fromRgb(color->elementRed(), - color->elementGreen(), color->elementBlue(), color->attributeAlpha())); - } - br = QBrush(*gr); - delete gr; - } else if (style == Qt::TexturePattern) { - const DomProperty *texture = brush->elementTexture(); - if (texture && texture->kind() == DomProperty::Pixmap) { - br.setTexture(domPropertyToPixmap(texture)); - } - } else { - const DomColor *color = brush->elementColor(); - br.setColor(QColor::fromRgb(color->elementRed(), - color->elementGreen(), color->elementBlue(), color->attributeAlpha())); - br.setStyle((Qt::BrushStyle)style); - } - return br; + return QFormBuilderExtra::setupBrush(brush); } -/*! - \internal -*/ DomBrush *QAbstractFormBuilder::saveBrush(const QBrush &br) { - const QMetaEnum brushStyle_enum = metaEnum("brushStyle"); - - DomBrush *brush = new DomBrush(); - const Qt::BrushStyle style = br.style(); - brush->setAttributeBrushStyle(QLatin1String(brushStyle_enum.valueToKey(style))); - if (style == Qt::LinearGradientPattern || - style == Qt::RadialGradientPattern || - style == Qt::ConicalGradientPattern) { - const QMetaEnum gradientType_enum = metaEnum("gradientType"); - const QMetaEnum gradientSpread_enum = metaEnum("gradientSpread"); - const QMetaEnum gradientCoordinate_enum = metaEnum("gradientCoordinate"); - - DomGradient *gradient = new DomGradient(); - const QGradient *gr = br.gradient(); - const QGradient::Type type = gr->type(); - gradient->setAttributeType(QLatin1String(gradientType_enum.valueToKey(type))); - gradient->setAttributeSpread(QLatin1String(gradientSpread_enum.valueToKey(gr->spread()))); - gradient->setAttributeCoordinateMode(QLatin1String(gradientCoordinate_enum.valueToKey(gr->coordinateMode()))); - QVector stops; - const QGradientStops st = gr->stops(); - for (const QGradientStop &pair : st) { - DomGradientStop *stop = new DomGradientStop(); - stop->setAttributePosition(pair.first); - DomColor *color = new DomColor(); - color->setElementRed(pair.second.red()); - color->setElementGreen(pair.second.green()); - color->setElementBlue(pair.second.blue()); - color->setAttributeAlpha(pair.second.alpha()); - stop->setElementColor(color); - stops.append(stop); - } - gradient->setElementGradientStop(stops); - if (type == QGradient::LinearGradient) { - auto lgr = static_cast(gr); - gradient->setAttributeStartX(lgr->start().x()); - gradient->setAttributeStartY(lgr->start().y()); - gradient->setAttributeEndX(lgr->finalStop().x()); - gradient->setAttributeEndY(lgr->finalStop().y()); - } else if (type == QGradient::RadialGradient) { - auto rgr = static_cast(gr); - gradient->setAttributeCentralX(rgr->center().x()); - gradient->setAttributeCentralY(rgr->center().y()); - gradient->setAttributeFocalX(rgr->focalPoint().x()); - gradient->setAttributeFocalY(rgr->focalPoint().y()); - gradient->setAttributeRadius(rgr->radius()); - } else if (type == QGradient::ConicalGradient) { - auto cgr = static_cast(gr); - gradient->setAttributeCentralX(cgr->center().x()); - gradient->setAttributeCentralY(cgr->center().y()); - gradient->setAttributeAngle(cgr->angle()); - } - - brush->setElementGradient(gradient); - } else if (style == Qt::TexturePattern) { - const QPixmap pixmap = br.texture(); - if (!pixmap.isNull()) { - DomProperty *p = new DomProperty; - setPixmapProperty(*p, pixmapPaths(pixmap)); - brush->setElementTexture(p); - } - } else { - const QColor &c = br.color(); - DomColor *color = new DomColor(); - color->setElementRed(c.red()); - color->setElementGreen(c.green()); - color->setElementBlue(c.blue()); - color->setAttributeAlpha(c.alpha()); - brush->setElementColor(color); - } - return brush; + return QFormBuilderExtra::saveBrush(br); } /*! @@ -1201,6 +1021,21 @@ QActionGroup *QAbstractFormBuilder::createActionGroup(QObject *parent, const QSt Saves an XML representation of the given \a widget to the specified \a device in the standard UI file format. + \note Unlike when saving a form in Qt Designer, all property values are + written. This is because, the state of whether a property value was + modified or not isn't stored in the Qt property system. The widget that + is being saved, could have been created dynamically, not loaded via + \l load(), so in this case the form builder isn't aware of the list of + changed properties. Also, there's no generic way to do this for widgets + that were created dynamically. + + Therefore, you should remove properties that are not required from your + resulting XML files, before loading them. Alternatively, if you already + know which properties you want to save when you call this method, + you can overload \c computeProperties() and return a filtered list of + required properties. Otherwise, unexpected behavior may occur as some + of these properties may depend on each other. + \sa load() */ void QAbstractFormBuilder::save(QIODevice *dev, QWidget *widget) @@ -1268,12 +1103,14 @@ DomWidget *QAbstractFormBuilder::createDom(QWidget *widget, DomWidget *ui_parent { DomWidget *ui_widget = new DomWidget(); ui_widget->setAttributeClass(QLatin1String(widget->metaObject()->className())); + ui_widget->setAttributeName(widget->objectName()); + ui_widget->setElementProperty(computeProperties(widget)); if (recursive) { if (QLayout *layout = widget->layout()) { if (DomLayout *ui_layout = createDom(layout, nullptr, ui_parentWidget)) { - QVector ui_layouts; + QList ui_layouts; ui_layouts.append(ui_layout); ui_widget->setElementLayout(ui_layouts); @@ -1282,9 +1119,9 @@ DomWidget *QAbstractFormBuilder::createDom(QWidget *widget, DomWidget *ui_parent } // widgets, actions and action groups - QVector ui_widgets; - QVector ui_actions; - QVector ui_action_groups; + QList ui_widgets; + QList ui_actions; + QList ui_action_groups; QObjectList children; @@ -1326,7 +1163,7 @@ DomWidget *QAbstractFormBuilder::createDom(QWidget *widget, DomWidget *ui_parent continue; if (QMenu *menu = qobject_cast(childWidget)) { - const QList actions = menu->parentWidget()->actions(); + const auto actions = menu->parentWidget()->actions(); const bool found = std::any_of(actions.cbegin(), actions.cend(), [menu] (const QAction *a) { return a->menu() == menu; }); @@ -1354,8 +1191,8 @@ DomWidget *QAbstractFormBuilder::createDom(QWidget *widget, DomWidget *ui_parent } // add-action - QVector ui_action_refs; - const QList &actions = widget->actions(); + QList ui_action_refs; + const auto &actions = widget->actions(); ui_action_refs.reserve(actions.size()); for (QAction *action : actions) { if (DomActionRef *ui_action_ref = createActionRefDom(action)) { @@ -1508,7 +1345,7 @@ DomLayout *QAbstractFormBuilder::createDom(QLayout *layout, DomLayout *ui_layout newList = saveLayoutEntries(layout); } - QVector ui_items; + QList ui_items; ui_items.reserve(newList.size()); for (const FormBuilderSaveLayoutEntry &item : qAsConst(newList)) { if (DomLayoutItem *ui_item = createDom(item.item, lay, ui_parentWidget)) { @@ -1606,7 +1443,7 @@ QList QAbstractFormBuilder::computeProperties(QObject *obj) for(int i=0; i < propertyCount; ++i) properties.insert(meta->property(i).name(), true); - const QList propertyNames = properties.keys(); + const auto propertyNames = properties.keys(); const int propertyNamesCount = propertyNames.size(); for(int i=0; i QAbstractFormBuilder::computeProperties(QObject *obj) const QVariant v = prop.read(obj); DomProperty *dom_prop = nullptr; - if (v.type() == QVariant::Int) { + if (v.metaType().id() == QMetaType::Int) { dom_prop = new DomProperty(); if (prop.isFlagType()) @@ -1746,15 +1583,15 @@ DomButtonGroups *QAbstractFormBuilder::saveButtonGroups(const QWidget *mainConta { // Save fst order buttongroup children of maincontainer const QObjectList &mchildren = mainContainer->children(); - if (mchildren.empty()) + if (mchildren.isEmpty()) return nullptr; - QVector domGroups; + QList domGroups; for (QObject *o : mchildren) { if (auto bg = qobject_cast(o)) if (DomButtonGroup* dg = createDom(bg)) domGroups.push_back(dg); } - if (domGroups.empty()) + if (domGroups.isEmpty()) return nullptr; DomButtonGroups *rc = new DomButtonGroups; rc->setElementButtonGroup(domGroups); @@ -1871,7 +1708,7 @@ void QAbstractFormBuilder::saveTreeWidgetExtraInfo(QTreeWidget *treeWidget, DomW { Q_UNUSED(ui_parentWidget); - QVector columns; + QList columns; DomProperty *p; QVariant v; const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); @@ -1962,7 +1799,7 @@ void QAbstractFormBuilder::saveTableWidgetExtraInfo(QTableWidget *tableWidget, D Q_UNUSED(ui_parentWidget); // save the horizontal header - QVector columns; + QList columns; for (int c = 0; c < tableWidget->columnCount(); c++) { QList properties; QTableWidgetItem *item = tableWidget->horizontalHeaderItem(c); @@ -1976,7 +1813,7 @@ void QAbstractFormBuilder::saveTableWidgetExtraInfo(QTableWidget *tableWidget, D ui_widget->setElementColumn(columns); // save the vertical header - QVector rows; + QList rows; for (int r = 0; r < tableWidget->rowCount(); r++) { QList properties; QTableWidgetItem *item = tableWidget->verticalHeaderItem(r); @@ -2103,7 +1940,7 @@ void QAbstractFormBuilder::saveItemViewExtraInfo(const QAbstractItemView *itemVi if (const QTreeView *treeView = qobject_cast(itemView)) { auto viewProperties = ui_widget->elementAttribute(); const auto &headerProperties = computeProperties(treeView->header()); - for (const QString &realPropertyName : realPropertyNames) { + for (QString realPropertyName : realPropertyNames) { const QString upperPropertyName = realPropertyName.at(0).toUpper() + realPropertyName.mid(1); const QString fakePropertyName = QStringLiteral("header") + upperPropertyName; @@ -2125,7 +1962,7 @@ void QAbstractFormBuilder::saveItemViewExtraInfo(const QAbstractItemView *itemVi const auto &headerProperties = headerPrefix == QStringLiteral("horizontalHeader") ? computeProperties(tableView->horizontalHeader()) : computeProperties(tableView->verticalHeader()); - for (const QString &realPropertyName : realPropertyNames) { + for (QString realPropertyName : realPropertyNames) { const QString upperPropertyName = realPropertyName.at(0).toUpper() + realPropertyName.mid(1); const QString fakePropertyName = headerPrefix + upperPropertyName; @@ -2417,7 +2254,7 @@ void QAbstractFormBuilder::loadComboBoxExtraInfo(DomWidget *ui_widget, QComboBox static QString buttonGroupName(const DomWidget *ui_widget) { const auto &attributes = ui_widget->elementAttribute(); - if (attributes.empty()) + if (attributes.isEmpty()) return QString(); const QString buttonGroupProperty = QLatin1String(buttonGroupPropertyC); for (const DomProperty *p : attributes) { @@ -2481,7 +2318,7 @@ void QAbstractFormBuilder::loadItemViewExtraInfo(DomWidget *ui_widget, QAbstract if (QTreeView *treeView = qobject_cast(itemView)) { const auto &allAttributes = ui_widget->elementAttribute(); QList headerProperties; - for (const QString &realPropertyName : realPropertyNames) { + for (QString realPropertyName : realPropertyNames) { const QString upperPropertyName = realPropertyName.at(0).toUpper() + realPropertyName.mid(1); const QString fakePropertyName = QStringLiteral("header") + upperPropertyName; @@ -2501,7 +2338,7 @@ void QAbstractFormBuilder::loadItemViewExtraInfo(DomWidget *ui_widget, QAbstract const auto &allAttributes = ui_widget->elementAttribute(); for (const QString &headerPrefix : headerPrefixes) { QList headerProperties; - for (const QString &realPropertyName : realPropertyNames) { + for (QString realPropertyName : realPropertyNames) { const QString upperPropertyName = realPropertyName.at(0).toUpper() + realPropertyName.mid(1); const QString fakePropertyName = headerPrefix + upperPropertyName; @@ -2636,9 +2473,9 @@ DomActionGroup *QAbstractFormBuilder::createDom(QActionGroup *actionGroup) ui_action_group->setElementProperty(computeProperties(actionGroup)); - QVector ui_actions; + QList ui_actions; - const QList &actions = actionGroup->actions(); + const auto &actions = actionGroup->actions(); ui_actions.reserve(actions.size()); for (QAction *action : actions) { if (DomAction *ui_action = createDom(action)) { @@ -2681,6 +2518,8 @@ QMetaEnum QAbstractFormBuilder::toolBarAreaMetaEnum() return metaEnum("toolBarArea"); } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + /*! \internal Return paths of an icon. @@ -2705,6 +2544,8 @@ QAbstractFormBuilder::IconPaths QAbstractFormBuilder::pixmapPaths(const QPixmap return IconPaths(); } +#endif // < Qt 6 + /*! \internal Set up a DOM property with icon. @@ -2731,16 +2572,11 @@ void QAbstractFormBuilder::setIconProperty(DomProperty &p, const IconPaths &ip) void QAbstractFormBuilder::setPixmapProperty(DomProperty &p, const IconPaths &ip) const { - DomResourcePixmap *pix = new DomResourcePixmap; - if (!ip.second.isEmpty()) - pix->setAttributeResource(ip.second); - - pix->setText(ip.first); - - p.setAttributeName(QFormBuilderStrings::instance().pixmapAttribute); - p.setElementPixmap(pix); + QFormBuilderExtra::setPixmapProperty(&p, ip); } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + /*! \internal Convenience. Return DOM property for icon; 0 if icon.isNull(). @@ -2753,6 +2589,8 @@ DomProperty* QAbstractFormBuilder::iconToDomProperty(const QIcon &icon) const return nullptr; } +#endif // < Qt 6 + /*! \internal \since 4.4 @@ -2804,6 +2642,8 @@ const DomResourcePixmap *QAbstractFormBuilder::domPixmap(const DomProperty* p) { return nullptr; } +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + /*! \internal Create icon from DOM. @@ -2858,6 +2698,8 @@ QPixmap QAbstractFormBuilder::domPropertyToPixmap(const DomProperty* p) return QPixmap(); } +#endif // < Qt 6 + /*! \fn void QAbstractFormBuilder::createConnections ( DomConnections *, QWidget * ) \internal diff --git a/src/designer/src/lib/uilib/abstractformbuilder.h b/src/designer/src/lib/uilib/abstractformbuilder.h index 4863590999..d33ceb76c1 100644 --- a/src/designer/src/lib/uilib/abstractformbuilder.h +++ b/src/designer/src/lib/uilib/abstractformbuilder.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -118,7 +107,7 @@ class QFormBuilderExtra; class QDESIGNER_UILIB_EXPORT QAbstractFormBuilder { public: - Q_DISABLE_COPY(QAbstractFormBuilder) + Q_DISABLE_COPY_MOVE(QAbstractFormBuilder) QAbstractFormBuilder(); virtual ~QAbstractFormBuilder(); @@ -243,17 +232,20 @@ class QDESIGNER_UILIB_EXPORT QAbstractFormBuilder // A Pair of icon path/qrc path. using IconPaths = QPair; - IconPaths iconPaths(const QIcon &) const; - IconPaths pixmapPaths(const QPixmap &) const; void setIconProperty(DomProperty &, const IconPaths &) const; void setPixmapProperty(DomProperty &, const IconPaths &) const; - DomProperty* iconToDomProperty(const QIcon &) const; static const DomResourcePixmap *domPixmap(const DomProperty* p); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + IconPaths iconPaths(const QIcon &) const; + IconPaths pixmapPaths(const QPixmap &) const; + DomProperty* iconToDomProperty(const QIcon &) const; QIcon domPropertyToIcon(const DomResourcePixmap *); QIcon domPropertyToIcon(const DomProperty* p); QPixmap domPropertyToPixmap(const DomResourcePixmap* p); QPixmap domPropertyToPixmap(const DomProperty* p); +#endif private: // diff --git a/src/designer/src/lib/uilib/formbuilder.cpp b/src/designer/src/lib/uilib/formbuilder.cpp index 31bfdfde46..4b5e99c697 100644 --- a/src/designer/src/lib/uilib/formbuilder.cpp +++ b/src/designer/src/lib/uilib/formbuilder.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -55,6 +44,10 @@ #include #include +#ifdef QT_OPENGLWIDGETS_LIB +# include +#endif + QT_BEGIN_NAMESPACE #ifdef QFORMINTERNAL_NAMESPACE @@ -517,7 +510,7 @@ QList QFormBuilder::customWidgets() const void QFormBuilder::applyProperties(QObject *o, const QList &properties) { - if (properties.empty()) + if (properties.isEmpty()) return; const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); diff --git a/src/designer/src/lib/uilib/formbuilder.h b/src/designer/src/lib/uilib/formbuilder.h index 522c6df78b..79013d2216 100644 --- a/src/designer/src/lib/uilib/formbuilder.h +++ b/src/designer/src/lib/uilib/formbuilder.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/formbuilderextra.cpp b/src/designer/src/lib/uilib/formbuilderextra.cpp index 01d79c5576..1dbed53480 100644 --- a/src/designer/src/lib/uilib/formbuilderextra.cpp +++ b/src/designer/src/lib/uilib/formbuilderextra.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -50,6 +39,7 @@ #include "formbuilderextra_p.h" #include "abstractformbuilder.h" +#include "properties_p.h" #include "resourcebuilder_p.h" #include "textbuilder_p.h" #include "ui4_p.h" @@ -206,7 +196,7 @@ bool QFormBuilderExtra::applyPropertyInternally(QObject *o, const QString &prope void QFormBuilderExtra::applyInternalProperties() const { - if (m_buddies.empty()) + if (m_buddies.isEmpty()) return; const BuddyHash::const_iterator cend = m_buddies.constEnd(); @@ -222,7 +212,7 @@ bool QFormBuilderExtra::applyBuddy(const QString &buddyName, BuddyMode applyMode } const QWidgetList widgets = label->topLevelWidget()->findChildren(buddyName); - if (widgets.empty()) { + if (widgets.isEmpty()) { label->setBuddy(nullptr); return false; } @@ -385,8 +375,8 @@ inline bool parsePerCellProperty(Layout *l, int count, void (Layout::*setter)(in clearPerCellValue(l, count, setter, defaultValue); return true; } - const QVector list = s.splitRef(QLatin1Char(',')); - if (list.empty()) { + const auto list = QStringView{s}.split(QLatin1Char(',')); + if (list.isEmpty()) { clearPerCellValue(l, count, setter, defaultValue); return true; } @@ -511,6 +501,234 @@ void QFormBuilderExtra::clearGridLayoutColumnMinimumWidth(QGridLayout *grid) clearPerCellValue(grid, grid->columnCount(), &QGridLayout::setColumnMinimumWidth); } +void QFormBuilderExtra::setPixmapProperty(DomProperty *p, const QPair &ip) +{ + DomResourcePixmap *pix = new DomResourcePixmap; + if (!ip.second.isEmpty()) + pix->setAttributeResource(ip.second); + + pix->setText(ip.first); + + p->setAttributeName(QFormBuilderStrings::instance().pixmapAttribute); + p->setElementPixmap(pix); +} + +void QFormBuilderExtra::setupColorGroup(QPalette *palette, QPalette::ColorGroup colorGroup, + const DomColorGroup *group) +{ + // old format + const auto &colors = group->elementColor(); + for (int role = 0; role < colors.size(); ++role) { + const DomColor *color = colors.at(role); + const QColor c(color->elementRed(), color->elementGreen(), color->elementBlue()); + palette->setColor(colorGroup, QPalette::ColorRole(role), c); + } + + // new format + const QMetaEnum colorRole_enum = metaEnum("colorRole"); + + const auto colorRoles = group->elementColorRole(); + for (const DomColorRole *colorRole : colorRoles) { + if (colorRole->hasAttributeRole()) { + const int r = colorRole_enum.keyToValue(colorRole->attributeRole().toLatin1()); + if (r != -1) { + const QBrush br = setupBrush(colorRole->elementBrush()); + palette->setBrush(colorGroup, static_cast(r), br); + } + } + } +} + +DomColorGroup *QFormBuilderExtra::saveColorGroup(const QPalette &palette, + QPalette::ColorGroup colorGroup) +{ + + const QMetaEnum colorRole_enum = metaEnum("colorRole"); + + DomColorGroup *group = new DomColorGroup(); + QList colorRoles; + + const uint mask = palette.resolveMask(); + for (int role = QPalette::WindowText; role < QPalette::NColorRoles; ++role) { + if (mask & (1 << role)) { + const QBrush &br = palette.brush(colorGroup, QPalette::ColorRole(role)); + + DomColorRole *colorRole = new DomColorRole(); + colorRole->setElementBrush(saveBrush(br)); + colorRole->setAttributeRole(QLatin1String(colorRole_enum.valueToKey(role))); + colorRoles.append(colorRole); + } + } + + group->setElementColorRole(colorRoles); + return group; +} + +DomPalette *QFormBuilderExtra::savePalette(const QPalette &palette) +{ + DomPalette *dom = new DomPalette(); + dom->setElementActive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Active)); + dom->setElementInactive(QFormBuilderExtra::saveColorGroup(palette, QPalette::Inactive)); + dom->setElementDisabled(QFormBuilderExtra::saveColorGroup(palette, QPalette::Disabled)); + + return dom; +} + +QPalette QFormBuilderExtra::loadPalette(const DomPalette *dom) +{ + QPalette palette; + + if (dom->elementActive()) + QFormBuilderExtra::setupColorGroup(&palette, QPalette::Active, dom->elementActive()); + + if (dom->elementInactive()) + QFormBuilderExtra::setupColorGroup(&palette, QPalette::Inactive, dom->elementInactive()); + + if (dom->elementDisabled()) + QFormBuilderExtra::setupColorGroup(&palette, QPalette::Disabled, dom->elementDisabled()); + + palette.setCurrentColorGroup(QPalette::Active); + return palette; +} + +QBrush QFormBuilderExtra::setupBrush(const DomBrush *brush) +{ + QBrush br; + if (!brush->hasAttributeBrushStyle()) + return br; + + const Qt::BrushStyle style = enumKeyOfObjectToValue("brushStyle", + brush->attributeBrushStyle().toLatin1().constData()); + + if (style == Qt::LinearGradientPattern || + style == Qt::RadialGradientPattern || + style == Qt::ConicalGradientPattern) { + const QMetaEnum gradientType_enum = metaEnum("gradientType"); + const QMetaEnum gradientSpread_enum = metaEnum("gradientSpread"); + const QMetaEnum gradientCoordinate_enum = metaEnum("gradientCoordinate"); + + const DomGradient *gradient = brush->elementGradient(); + const QGradient::Type type = enumKeyToValue(gradientType_enum, gradient->attributeType().toLatin1()); + + + QGradient *gr = nullptr; + + if (type == QGradient::LinearGradient) { + gr = new QLinearGradient(QPointF(gradient->attributeStartX(), gradient->attributeStartY()), + QPointF(gradient->attributeEndX(), gradient->attributeEndY())); + } else if (type == QGradient::RadialGradient) { + gr = new QRadialGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()), + gradient->attributeRadius(), + QPointF(gradient->attributeFocalX(), gradient->attributeFocalY())); + } else if (type == QGradient::ConicalGradient) { + gr = new QConicalGradient(QPointF(gradient->attributeCentralX(), gradient->attributeCentralY()), + gradient->attributeAngle()); + } + if (!gr) + return br; + + const QGradient::Spread spread = enumKeyToValue(gradientSpread_enum, gradient->attributeSpread().toLatin1()); + gr->setSpread(spread); + + const QGradient::CoordinateMode coord = enumKeyToValue(gradientCoordinate_enum, gradient->attributeCoordinateMode().toLatin1()); + gr->setCoordinateMode(coord); + + const auto &stops = gradient->elementGradientStop(); + for (const DomGradientStop *stop : stops) { + const DomColor *color = stop->elementColor(); + gr->setColorAt(stop->attributePosition(), QColor::fromRgb(color->elementRed(), + color->elementGreen(), color->elementBlue(), color->attributeAlpha())); + } + br = QBrush(*gr); + delete gr; + } else if (style == Qt::TexturePattern) { + const DomProperty *texture = brush->elementTexture(); + if (texture && texture->kind() == DomProperty::Pixmap) { + br.setTexture({}); + } + } else { + const DomColor *color = brush->elementColor(); + br.setColor(QColor::fromRgb(color->elementRed(), + color->elementGreen(), color->elementBlue(), color->attributeAlpha())); + br.setStyle((Qt::BrushStyle)style); + } + return br; +} + +DomBrush *QFormBuilderExtra::saveBrush(const QBrush &br) +{ + const QMetaEnum brushStyle_enum = metaEnum("brushStyle"); + + DomBrush *brush = new DomBrush(); + const Qt::BrushStyle style = br.style(); + brush->setAttributeBrushStyle(QLatin1String(brushStyle_enum.valueToKey(style))); + if (style == Qt::LinearGradientPattern || + style == Qt::RadialGradientPattern || + style == Qt::ConicalGradientPattern) { + const QMetaEnum gradientType_enum = metaEnum("gradientType"); + const QMetaEnum gradientSpread_enum = metaEnum("gradientSpread"); + const QMetaEnum gradientCoordinate_enum = metaEnum("gradientCoordinate"); + + DomGradient *gradient = new DomGradient(); + const QGradient *gr = br.gradient(); + const QGradient::Type type = gr->type(); + gradient->setAttributeType(QLatin1String(gradientType_enum.valueToKey(type))); + gradient->setAttributeSpread(QLatin1String(gradientSpread_enum.valueToKey(gr->spread()))); + gradient->setAttributeCoordinateMode(QLatin1String(gradientCoordinate_enum.valueToKey(gr->coordinateMode()))); + QList stops; + const QGradientStops st = gr->stops(); + for (const QGradientStop &pair : st) { + DomGradientStop *stop = new DomGradientStop(); + stop->setAttributePosition(pair.first); + DomColor *color = new DomColor(); + color->setElementRed(pair.second.red()); + color->setElementGreen(pair.second.green()); + color->setElementBlue(pair.second.blue()); + color->setAttributeAlpha(pair.second.alpha()); + stop->setElementColor(color); + stops.append(stop); + } + gradient->setElementGradientStop(stops); + if (type == QGradient::LinearGradient) { + auto lgr = static_cast(gr); + gradient->setAttributeStartX(lgr->start().x()); + gradient->setAttributeStartY(lgr->start().y()); + gradient->setAttributeEndX(lgr->finalStop().x()); + gradient->setAttributeEndY(lgr->finalStop().y()); + } else if (type == QGradient::RadialGradient) { + auto rgr = static_cast(gr); + gradient->setAttributeCentralX(rgr->center().x()); + gradient->setAttributeCentralY(rgr->center().y()); + gradient->setAttributeFocalX(rgr->focalPoint().x()); + gradient->setAttributeFocalY(rgr->focalPoint().y()); + gradient->setAttributeRadius(rgr->radius()); + } else if (type == QGradient::ConicalGradient) { + auto cgr = static_cast(gr); + gradient->setAttributeCentralX(cgr->center().x()); + gradient->setAttributeCentralY(cgr->center().y()); + gradient->setAttributeAngle(cgr->angle()); + } + + brush->setElementGradient(gradient); + } else if (style == Qt::TexturePattern) { + const QPixmap pixmap = br.texture(); + if (!pixmap.isNull()) { + DomProperty *p = new DomProperty; + QFormBuilderExtra::setPixmapProperty(p, {}); + brush->setElementTexture(p); + } + } else { + const QColor &c = br.color(); + DomColor *color = new DomColor(); + color->setElementRed(c.red()); + color->setElementGreen(c.green()); + color->setElementBlue(c.blue()); + color->setAttributeAlpha(c.alpha()); + brush->setElementColor(color); + } + return brush; +} + // ------------ QFormBuilderStrings QFormBuilderStrings::QFormBuilderStrings() : @@ -575,7 +793,8 @@ QFormBuilderStrings::QFormBuilderStrings() : whatsThisAttribute)); // Note: this skips the first item! - QList::const_iterator it = itemTextRoles.constBegin(), end = itemTextRoles.constEnd(); + auto it = itemTextRoles.constBegin(); + const auto end = itemTextRoles.constEnd(); while (++it != end) treeItemTextRoleHash.insert(it->second, it->first); } diff --git a/src/designer/src/lib/uilib/formbuilderextra_p.h b/src/designer/src/lib/uilib/formbuilderextra_p.h index 54fbfbe660..94b0c22312 100644 --- a/src/designer/src/lib/uilib/formbuilderextra_p.h +++ b/src/designer/src/lib/uilib/formbuilderextra_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -69,6 +58,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -89,9 +79,13 @@ namespace QFormInternal { #endif +class DomBrush; class DomButtonGroups; class DomButtonGroup; +class DomColorGroup; class DomCustomWidget; +class DomPalette; +class DomProperty; class DomUI; class QAbstractFormBuilder; @@ -175,6 +169,16 @@ class QDESIGNER_UILIB_EXPORT QFormBuilderExtra static bool setGridLayoutColumnMinimumWidth(const QString &, QGridLayout *); static void clearGridLayoutColumnMinimumWidth(QGridLayout *); + static void setPixmapProperty(DomProperty *p, const QPair &ip); + static QPalette loadPalette(const DomPalette *dom); + static void setupColorGroup(QPalette *palette, QPalette::ColorGroup colorGroup, + const DomColorGroup *group); + static DomColorGroup *saveColorGroup(const QPalette &palette, + QPalette::ColorGroup colorGroup); + static DomPalette *savePalette(const QPalette &palette); + static QBrush setupBrush(const DomBrush *brush); + static DomBrush *saveBrush(const QBrush &br); + QStringList m_pluginPaths; QMap m_customWidgets; diff --git a/src/designer/src/lib/uilib/properties.cpp b/src/designer/src/lib/uilib/properties.cpp index 0e18d3ca99..d7ba8cef12 100644 --- a/src/designer/src/lib/uilib/properties.cpp +++ b/src/designer/src/lib/uilib/properties.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -86,7 +75,7 @@ QVariant domPropertyToVariant(QAbstractFormBuilder *afb,const QMetaObject *meta, switch(p->kind()) { case DomProperty::String: { const int index = meta->indexOfProperty(p->attributeName().toUtf8()); - if (index != -1 && meta->property(index).type() == QVariant::KeySequence) + if (index != -1 && meta->property(index).metaType().id() == QMetaType::QKeySequence) return QVariant::fromValue(QKeySequence(p->elementString()->text())); } break; @@ -239,8 +228,6 @@ QVariant domPropertyToVariant(const DomProperty *p) f.setFamily(font->elementFamily()); if (font->hasElementPointSize() && font->elementPointSize() > 0) f.setPointSize(font->elementPointSize()); - if (font->hasElementWeight() && font->elementWeight() > 0) - f.setWeight(font->elementWeight()); if (font->hasElementItalic()) f.setItalic(font->elementItalic()); if (font->hasElementBold()) @@ -338,8 +325,8 @@ QVariant domPropertyToVariant(const DomProperty *p) // Apply a simple variant type to a DOM property static bool applySimpleProperty(const QVariant &v, bool translateString, DomProperty *dom_prop) { - switch (v.type()) { - case QVariant::String: { + switch (v.metaType().id()) { + case QMetaType::QString: { DomString *str = new DomString(); str->setText(v.toString()); if (!translateString) @@ -348,35 +335,35 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::ByteArray: + case QMetaType::QByteArray: dom_prop->setElementCstring(QString::fromUtf8(v.toByteArray())); return true; - case QVariant::Int: + case QMetaType::Int: dom_prop->setElementNumber(v.toInt()); return true; - case QVariant::UInt: + case QMetaType::UInt: dom_prop->setElementUInt(v.toUInt()); return true; - case QVariant::LongLong: + case QMetaType::LongLong: dom_prop->setElementLongLong(v.toLongLong()); return true; - case QVariant::ULongLong: + case QMetaType::ULongLong: dom_prop->setElementULongLong(v.toULongLong()); return true; - case QVariant::Double: + case QMetaType::Double: dom_prop->setElementDouble(v.toDouble()); return true; - case QVariant::Bool: + case QMetaType::Bool: dom_prop->setElementBool(v.toBool() ? QFormBuilderStrings::instance().trueValue : QFormBuilderStrings::instance().falseValue); return true; - case QVariant::Char: { + case QMetaType::QChar: { DomChar *ch = new DomChar(); const QChar character = v.toChar(); ch->setElementUnicode(character.unicode()); @@ -384,7 +371,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Point: { + case QMetaType::QPoint: { DomPoint *pt = new DomPoint(); const QPoint point = v.toPoint(); pt->setElementX(point.x()); @@ -393,7 +380,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::PointF: { + case QMetaType::QPointF: { DomPointF *ptf = new DomPointF(); const QPointF pointf = v.toPointF(); ptf->setElementX(pointf.x()); @@ -402,7 +389,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Color: { + case QMetaType::QColor: { DomColor *clr = new DomColor(); const QColor color = qvariant_cast(v); clr->setElementRed(color.red()); @@ -415,7 +402,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Size: { + case QMetaType::QSize: { DomSize *sz = new DomSize(); const QSize size = v.toSize(); sz->setElementWidth(size.width()); @@ -424,7 +411,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::SizeF: { + case QMetaType::QSizeF: { DomSizeF *szf = new DomSizeF(); const QSizeF sizef = v.toSizeF(); szf->setElementWidth(sizef.width()); @@ -433,7 +420,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Rect: { + case QMetaType::QRect: { DomRect *rc = new DomRect(); const QRect rect = v.toRect(); rc->setElementX(rect.x()); @@ -444,7 +431,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::RectF: { + case QMetaType::QRectF: { DomRectF *rcf = new DomRectF(); const QRectF rectf = v.toRectF(); rcf->setElementX(rectf.x()); @@ -455,14 +442,12 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Font: { + case QMetaType::QFont: { DomFont *fnt = new DomFont(); const QFont font = qvariant_cast(v); - const uint mask = font.resolve(); - if (mask & QFont::WeightResolved) { + const uint mask = font.resolveMask(); + if (mask & QFont::WeightResolved) fnt->setElementBold(font.bold()); - fnt->setElementWeight(font.weight()); - } if (mask & QFont::FamilyResolved) fnt->setElementFamily(font.family()); if (mask & QFont::StyleResolved) @@ -484,21 +469,21 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp return true; #if QT_CONFIG(cursor) - case QVariant::Cursor: { + case QMetaType::QCursor: { const QMetaEnum cursorShape_enum = metaEnum("cursorShape"); dom_prop->setElementCursorShape(QLatin1String(cursorShape_enum.valueToKey(qvariant_cast(v).shape()))); } return true; #endif - case QVariant::KeySequence: { + case QMetaType::QKeySequence: { DomString *s = new DomString(); s->setText(qvariant_cast(v).toString(QKeySequence::PortableText)); dom_prop->setElementString(s); } return true; - case QVariant::Locale: { + case QMetaType::QLocale: { DomLocale *dom = new DomLocale(); const QLocale locale = qvariant_cast(v); @@ -512,7 +497,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::SizePolicy: { + case QMetaType::QSizePolicy: { DomSizePolicy *dom = new DomSizePolicy(); const QSizePolicy sizePolicy = qvariant_cast(v); @@ -528,7 +513,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Date: { + case QMetaType::QDate: { DomDate *dom = new DomDate(); const QDate date = qvariant_cast(v); @@ -540,7 +525,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Time: { + case QMetaType::QTime: { DomTime *dom = new DomTime(); const QTime time = qvariant_cast(v); @@ -552,7 +537,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::DateTime: { + case QMetaType::QDateTime: { DomDateTime *dom = new DomDateTime(); const QDateTime dateTime = qvariant_cast(v); @@ -567,7 +552,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::Url: { + case QMetaType::QUrl: { DomUrl *dom = new DomUrl(); const QUrl url = v.toUrl(); @@ -579,7 +564,7 @@ static bool applySimpleProperty(const QVariant &v, bool translateString, DomProp } return true; - case QVariant::StringList: { + case QMetaType::QStringList: { DomStringList *sl = new DomStringList; sl->setElementString(qvariant_cast(v)); dom_prop->setElementStringList(sl); @@ -613,8 +598,10 @@ static bool isTranslatable(const QString &pname, const QVariant &v, const QMetaO const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); if (pname == strings.objectNameProperty) return false; - if (pname == strings.styleSheetProperty && v.type() == QVariant::String && isOfType(meta, &QWidget::staticMetaObject)) + if (pname == strings.styleSheetProperty && v.metaType().id() == QMetaType::QString + && isOfType(meta, &QWidget::staticMetaObject)) { return false; + } return true; } @@ -631,7 +618,7 @@ DomProperty *variantToDomProperty(QAbstractFormBuilder *afb, const QMetaObject * const int pindex = meta->indexOfProperty(pname.toLatin1()); if (pindex != -1) { QMetaProperty meta_property = meta->property(pindex); - if ((v.type() == QVariant::Int || v.type() == QVariant::UInt) && meta_property.isEnumType()) { + if ((v.metaType().id() == QMetaType::Int || v.metaType().id() == QMetaType::UInt) && meta_property.isEnumType()) { const QMetaEnum e = meta_property.enumerator(); if (e.isFlag()) dom_prop->setElementSet(QString::fromLatin1(e.valueToKeys(v.toInt()))); @@ -648,8 +635,8 @@ DomProperty *variantToDomProperty(QAbstractFormBuilder *afb, const QMetaObject * return dom_prop; // Complex properties - switch (v.type()) { - case QVariant::Palette: { + switch (v.metaType().id()) { + case QMetaType::QPalette: { DomPalette *dom = new DomPalette(); QPalette palette = qvariant_cast(v); @@ -664,7 +651,7 @@ DomProperty *variantToDomProperty(QAbstractFormBuilder *afb, const QMetaObject * dom_prop->setElementPalette(dom); } break; - case QVariant::Brush: + case QMetaType::QBrush: dom_prop->setElementBrush(afb->saveBrush(qvariant_cast(v))); break; default: { diff --git a/src/designer/src/lib/uilib/properties_p.h b/src/designer/src/lib/uilib/properties_p.h index aa707b323a..7fa8e052f8 100644 --- a/src/designer/src/lib/uilib/properties_p.h +++ b/src/designer/src/lib/uilib/properties_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/resourcebuilder.cpp b/src/designer/src/lib/uilib/resourcebuilder.cpp index f6bdaed5e5..eb9cb27287 100644 --- a/src/designer/src/lib/uilib/resourcebuilder.cpp +++ b/src/designer/src/lib/uilib/resourcebuilder.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -166,9 +155,9 @@ bool QResourceBuilder::isResourceProperty(const DomProperty *p) const bool QResourceBuilder::isResourceType(const QVariant &value) const { - switch (value.type()) { - case QVariant::Pixmap: - case QVariant::Icon: + switch (value.metaType().id()) { + case QMetaType::QPixmap: + case QMetaType::QIcon: return true; default: break; diff --git a/src/designer/src/lib/uilib/resourcebuilder_p.h b/src/designer/src/lib/uilib/resourcebuilder_p.h index 89cb5f8feb..a5fb6b37c8 100644 --- a/src/designer/src/lib/uilib/resourcebuilder_p.h +++ b/src/designer/src/lib/uilib/resourcebuilder_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/textbuilder.cpp b/src/designer/src/lib/uilib/textbuilder.cpp index abf148a93b..96d453ee30 100644 --- a/src/designer/src/lib/uilib/textbuilder.cpp +++ b/src/designer/src/lib/uilib/textbuilder.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/textbuilder_p.h b/src/designer/src/lib/uilib/textbuilder_p.h index 3a2e75dd83..7944c6f7e2 100644 --- a/src/designer/src/lib/uilib/textbuilder_p.h +++ b/src/designer/src/lib/uilib/textbuilder_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/ui4.cpp b/src/designer/src/lib/uilib/ui4.cpp index 4afa1dce5e..1a3738ce19 100644 --- a/src/designer/src/lib/uilib/ui4.cpp +++ b/src/designer/src/lib/uilib/ui4.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -81,7 +70,7 @@ void DomUI::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("version")) { setAttributeVersion(attribute.value().toString()); continue; @@ -98,6 +87,10 @@ void DomUI::read(QXmlStreamReader &reader) setAttributeIdbasedtr(attribute.value() == QLatin1String("true")); continue; } + if (name == QLatin1String("connectslotsbyname")) { + setAttributeConnectslotsbyname(attribute.value() == QLatin1String("true")); + continue; + } if (name == QLatin1String("stdsetdef")) { setAttributeStdsetdef(attribute.value().toInt()); continue; @@ -112,7 +105,7 @@ void DomUI::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("author"), Qt::CaseInsensitive)) { setElementAuthor(reader.readElementText()); continue; @@ -231,6 +224,9 @@ void DomUI::write(QXmlStreamWriter &writer, const QString &tagName) const if (hasAttributeIdbasedtr()) writer.writeAttribute(QStringLiteral("idbasedtr"), (attributeIdbasedtr() ? QLatin1String("true") : QLatin1String("false"))); + if (hasAttributeConnectslotsbyname()) + writer.writeAttribute(QStringLiteral("connectslotsbyname"), (attributeConnectslotsbyname() ? QLatin1String("true") : QLatin1String("false"))); + if (hasAttributeStdsetdef()) writer.writeAttribute(QStringLiteral("stdsetdef"), QString::number(attributeStdsetdef())); @@ -596,7 +592,7 @@ void DomIncludes::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("include"), Qt::CaseInsensitive)) { auto *v = new DomInclude(); v->read(reader); @@ -624,7 +620,7 @@ void DomIncludes::write(QXmlStreamWriter &writer, const QString &tagName) const writer.writeEndElement(); } -void DomIncludes::setElementInclude(const QVector &a) +void DomIncludes::setElementInclude(const QList &a) { m_children |= Include; m_include = a; @@ -636,7 +632,7 @@ void DomInclude::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("location")) { setAttributeLocation(attribute.value().toString()); continue; @@ -651,7 +647,7 @@ void DomInclude::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -693,7 +689,7 @@ void DomResources::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -704,7 +700,7 @@ void DomResources::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("include"), Qt::CaseInsensitive)) { auto *v = new DomResource(); v->read(reader); @@ -735,7 +731,7 @@ void DomResources::write(QXmlStreamWriter &writer, const QString &tagName) const writer.writeEndElement(); } -void DomResources::setElementInclude(const QVector &a) +void DomResources::setElementInclude(const QList &a) { m_children |= Include; m_include = a; @@ -747,7 +743,7 @@ void DomResource::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("location")) { setAttributeLocation(attribute.value().toString()); continue; @@ -758,7 +754,7 @@ void DomResource::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -796,7 +792,7 @@ void DomActionGroup::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -807,7 +803,7 @@ void DomActionGroup::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("action"), Qt::CaseInsensitive)) { auto *v = new DomAction(); v->read(reader); @@ -865,13 +861,13 @@ void DomActionGroup::write(QXmlStreamWriter &writer, const QString &tagName) con writer.writeEndElement(); } -void DomActionGroup::setElementAction(const QVector &a) +void DomActionGroup::setElementAction(const QList &a) { m_children |= Action; m_action = a; } -void DomActionGroup::setElementActionGroup(const QVector &a) +void DomActionGroup::setElementActionGroup(const QList &a) { m_children |= ActionGroup; m_actionGroup = a; @@ -901,7 +897,7 @@ void DomAction::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -916,7 +912,7 @@ void DomAction::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -977,7 +973,7 @@ void DomActionRef::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -988,7 +984,7 @@ void DomActionRef::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -1022,7 +1018,7 @@ void DomButtonGroup::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -1033,7 +1029,7 @@ void DomButtonGroup::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -1096,7 +1092,7 @@ void DomButtonGroups::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("buttongroup"), Qt::CaseInsensitive)) { auto *v = new DomButtonGroup(); v->read(reader); @@ -1124,7 +1120,7 @@ void DomButtonGroups::write(QXmlStreamWriter &writer, const QString &tagName) co writer.writeEndElement(); } -void DomButtonGroups::setElementButtonGroup(const QVector &a) +void DomButtonGroups::setElementButtonGroup(const QList &a) { m_children |= ButtonGroup; m_buttonGroup = a; @@ -1141,7 +1137,7 @@ void DomCustomWidgets::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("customwidget"), Qt::CaseInsensitive)) { auto *v = new DomCustomWidget(); v->read(reader); @@ -1169,7 +1165,7 @@ void DomCustomWidgets::write(QXmlStreamWriter &writer, const QString &tagName) c writer.writeEndElement(); } -void DomCustomWidgets::setElementCustomWidget(const QVector &a) +void DomCustomWidgets::setElementCustomWidget(const QList &a) { m_children |= CustomWidget; m_customWidget = a; @@ -1181,7 +1177,7 @@ void DomHeader::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("location")) { setAttributeLocation(attribute.value().toString()); continue; @@ -1192,7 +1188,7 @@ void DomHeader::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -1234,7 +1230,7 @@ void DomCustomWidget::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("class"), Qt::CaseInsensitive)) { setElementClass(reader.readElementText()); continue; @@ -1488,7 +1484,7 @@ void DomLayoutDefault::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("spacing")) { setAttributeSpacing(attribute.value().toInt()); continue; @@ -1503,7 +1499,7 @@ void DomLayoutDefault::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -1534,7 +1530,7 @@ void DomLayoutFunction::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("spacing")) { setAttributeSpacing(attribute.value().toString()); continue; @@ -1549,7 +1545,7 @@ void DomLayoutFunction::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -1584,7 +1580,7 @@ void DomTabStops::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("tabstop"), Qt::CaseInsensitive)) { m_tabStop.append(reader.readElementText()); continue; @@ -1630,7 +1626,7 @@ void DomLayout::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("class")) { setAttributeClass(attribute.value().toString()); continue; @@ -1665,7 +1661,7 @@ void DomLayout::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -1744,7 +1740,7 @@ void DomLayout::setElementAttribute(const QList &a) m_attribute = a; } -void DomLayout::setElementItem(const QVector &a) +void DomLayout::setElementItem(const QList &a) { m_children |= Item; m_item = a; @@ -1774,7 +1770,7 @@ void DomLayoutItem::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("row")) { setAttributeRow(attribute.value().toInt()); continue; @@ -1801,7 +1797,7 @@ void DomLayoutItem::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("widget"), Qt::CaseInsensitive)) { auto *v = new DomWidget(); v->read(reader); @@ -1925,7 +1921,7 @@ void DomRow::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -1970,7 +1966,7 @@ void DomColumn::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -2016,7 +2012,7 @@ void DomItem::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("row")) { setAttributeRow(attribute.value().toInt()); continue; @@ -2031,7 +2027,7 @@ void DomItem::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -2080,7 +2076,7 @@ void DomItem::setElementProperty(const QList &a) m_property = a; } -void DomItem::setElementItem(const QVector &a) +void DomItem::setElementItem(const QList &a) { m_children |= Item; m_item = a; @@ -2116,7 +2112,7 @@ void DomWidget::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("class")) { setAttributeClass(attribute.value().toString()); continue; @@ -2135,7 +2131,7 @@ void DomWidget::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("class"), Qt::CaseInsensitive)) { m_class.append(reader.readElementText()); continue; @@ -2295,49 +2291,49 @@ void DomWidget::setElementAttribute(const QList &a) m_attribute = a; } -void DomWidget::setElementRow(const QVector &a) +void DomWidget::setElementRow(const QList &a) { m_children |= Row; m_row = a; } -void DomWidget::setElementColumn(const QVector &a) +void DomWidget::setElementColumn(const QList &a) { m_children |= Column; m_column = a; } -void DomWidget::setElementItem(const QVector &a) +void DomWidget::setElementItem(const QList &a) { m_children |= Item; m_item = a; } -void DomWidget::setElementLayout(const QVector &a) +void DomWidget::setElementLayout(const QList &a) { m_children |= Layout; m_layout = a; } -void DomWidget::setElementWidget(const QVector &a) +void DomWidget::setElementWidget(const QList &a) { m_children |= Widget; m_widget = a; } -void DomWidget::setElementAction(const QVector &a) +void DomWidget::setElementAction(const QList &a) { m_children |= Action; m_action = a; } -void DomWidget::setElementActionGroup(const QVector &a) +void DomWidget::setElementActionGroup(const QList &a) { m_children |= ActionGroup; m_actionGroup = a; } -void DomWidget::setElementAddAction(const QVector &a) +void DomWidget::setElementAddAction(const QList &a) { m_children |= AddAction; m_addAction = a; @@ -2359,7 +2355,7 @@ void DomSpacer::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -2370,7 +2366,7 @@ void DomSpacer::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -2413,7 +2409,7 @@ void DomColor::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("alpha")) { setAttributeAlpha(attribute.value().toInt()); continue; @@ -2424,7 +2420,7 @@ void DomColor::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("red"), Qt::CaseInsensitive)) { setElementRed(reader.readElementText().toInt()); continue; @@ -2509,7 +2505,7 @@ void DomGradientStop::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("position")) { setAttributePosition(attribute.value().toDouble()); continue; @@ -2520,7 +2516,7 @@ void DomGradientStop::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("color"), Qt::CaseInsensitive)) { auto *v = new DomColor(); v->read(reader); @@ -2583,7 +2579,7 @@ void DomGradient::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("startx")) { setAttributeStartX(attribute.value().toDouble()); continue; @@ -2642,7 +2638,7 @@ void DomGradient::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("gradientstop"), Qt::CaseInsensitive)) { auto *v = new DomGradientStop(); v->read(reader); @@ -2709,7 +2705,7 @@ void DomGradient::write(QXmlStreamWriter &writer, const QString &tagName) const writer.writeEndElement(); } -void DomGradient::setElementGradientStop(const QVector &a) +void DomGradient::setElementGradientStop(const QList &a) { m_children |= GradientStop; m_gradientStop = a; @@ -2739,7 +2735,7 @@ void DomBrush::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("brushstyle")) { setAttributeBrushStyle(attribute.value().toString()); continue; @@ -2750,7 +2746,7 @@ void DomBrush::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("color"), Qt::CaseInsensitive)) { auto *v = new DomColor(); v->read(reader); @@ -2860,7 +2856,7 @@ void DomColorRole::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("role")) { setAttributeRole(attribute.value().toString()); continue; @@ -2871,7 +2867,7 @@ void DomColorRole::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("brush"), Qt::CaseInsensitive)) { auto *v = new DomBrush(); v->read(reader); @@ -2937,7 +2933,7 @@ void DomColorGroup::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("colorrole"), Qt::CaseInsensitive)) { auto *v = new DomColorRole(); v->read(reader); @@ -2974,13 +2970,13 @@ void DomColorGroup::write(QXmlStreamWriter &writer, const QString &tagName) cons writer.writeEndElement(); } -void DomColorGroup::setElementColorRole(const QVector &a) +void DomColorGroup::setElementColorRole(const QList &a) { m_children |= ColorRole; m_colorRole = a; } -void DomColorGroup::setElementColor(const QVector &a) +void DomColorGroup::setElementColor(const QList &a) { m_children |= Color; m_color = a; @@ -2998,7 +2994,7 @@ void DomPalette::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("active"), Qt::CaseInsensitive)) { auto *v = new DomColorGroup(); v->read(reader); @@ -3117,7 +3113,7 @@ void DomFont::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("family"), Qt::CaseInsensitive)) { setElementFamily(reader.readElementText()); continue; @@ -3323,7 +3319,7 @@ void DomPoint::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("x"), Qt::CaseInsensitive)) { setElementX(reader.readElementText().toInt()); continue; @@ -3385,7 +3381,7 @@ void DomRect::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("x"), Qt::CaseInsensitive)) { setElementX(reader.readElementText().toInt()); continue; @@ -3482,7 +3478,7 @@ void DomLocale::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("language")) { setAttributeLanguage(attribute.value().toString()); continue; @@ -3497,7 +3493,7 @@ void DomLocale::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -3528,7 +3524,7 @@ void DomSizePolicy::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("hsizetype")) { setAttributeHSizeType(attribute.value().toString()); continue; @@ -3543,7 +3539,7 @@ void DomSizePolicy::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("hsizetype"), Qt::CaseInsensitive)) { setElementHSizeType(reader.readElementText().toInt()); continue; @@ -3647,7 +3643,7 @@ void DomSize::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("width"), Qt::CaseInsensitive)) { setElementWidth(reader.readElementText().toInt()); continue; @@ -3709,7 +3705,7 @@ void DomDate::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("year"), Qt::CaseInsensitive)) { setElementYear(reader.readElementText().toInt()); continue; @@ -3789,7 +3785,7 @@ void DomTime::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("hour"), Qt::CaseInsensitive)) { setElementHour(reader.readElementText().toInt()); continue; @@ -3869,7 +3865,7 @@ void DomDateTime::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("hour"), Qt::CaseInsensitive)) { setElementHour(reader.readElementText().toInt()); continue; @@ -4005,7 +4001,7 @@ void DomStringList::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("notr")) { setAttributeNotr(attribute.value().toString()); continue; @@ -4028,7 +4024,7 @@ void DomStringList::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("string"), Qt::CaseInsensitive)) { m_string.append(reader.readElementText()); continue; @@ -4078,7 +4074,7 @@ void DomResourcePixmap::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("resource")) { setAttributeResource(attribute.value().toString()); continue; @@ -4093,7 +4089,7 @@ void DomResourcePixmap::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -4141,7 +4137,7 @@ void DomResourceIcon::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("theme")) { setAttributeTheme(attribute.value().toString()); continue; @@ -4156,7 +4152,7 @@ void DomResourceIcon::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("normaloff"), Qt::CaseInsensitive)) { auto *v = new DomResourcePixmap(); v->read(reader); @@ -4442,7 +4438,7 @@ void DomString::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("notr")) { setAttributeNotr(attribute.value().toString()); continue; @@ -4465,7 +4461,7 @@ void DomString::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -4510,7 +4506,7 @@ void DomPointF::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("x"), Qt::CaseInsensitive)) { setElementX(reader.readElementText().toDouble()); continue; @@ -4572,7 +4568,7 @@ void DomRectF::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("x"), Qt::CaseInsensitive)) { setElementX(reader.readElementText().toDouble()); continue; @@ -4670,7 +4666,7 @@ void DomSizeF::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("width"), Qt::CaseInsensitive)) { setElementWidth(reader.readElementText().toDouble()); continue; @@ -4732,7 +4728,7 @@ void DomChar::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("unicode"), Qt::CaseInsensitive)) { setElementUnicode(reader.readElementText().toInt()); continue; @@ -4779,7 +4775,7 @@ void DomUrl::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("string"), Qt::CaseInsensitive)) { auto *v = new DomString(); v->read(reader); @@ -4914,7 +4910,7 @@ void DomProperty::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -4929,7 +4925,7 @@ void DomProperty::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("bool"), Qt::CaseInsensitive)) { setElementBool(reader.readElementText()); continue; @@ -5674,7 +5670,7 @@ void DomConnections::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("connection"), Qt::CaseInsensitive)) { auto *v = new DomConnection(); v->read(reader); @@ -5702,7 +5698,7 @@ void DomConnections::write(QXmlStreamWriter &writer, const QString &tagName) con writer.writeEndElement(); } -void DomConnections::setElementConnection(const QVector &a) +void DomConnections::setElementConnection(const QList &a) { m_children |= Connection; m_connection = a; @@ -5718,7 +5714,7 @@ void DomConnection::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("sender"), Qt::CaseInsensitive)) { setElementSender(reader.readElementText()); continue; @@ -5851,7 +5847,7 @@ void DomConnectionHints::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("hint"), Qt::CaseInsensitive)) { auto *v = new DomConnectionHint(); v->read(reader); @@ -5879,7 +5875,7 @@ void DomConnectionHints::write(QXmlStreamWriter &writer, const QString &tagName) writer.writeEndElement(); } -void DomConnectionHints::setElementHint(const QVector &a) +void DomConnectionHints::setElementHint(const QList &a) { m_children |= Hint; m_hint = a; @@ -5891,7 +5887,7 @@ void DomConnectionHint::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("type")) { setAttributeType(attribute.value().toString()); continue; @@ -5902,7 +5898,7 @@ void DomConnectionHint::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("x"), Qt::CaseInsensitive)) { setElementX(reader.readElementText().toInt()); continue; @@ -5971,7 +5967,7 @@ void DomDesignerData::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("property"), Qt::CaseInsensitive)) { auto *v = new DomProperty(); v->read(reader); @@ -6016,7 +6012,7 @@ void DomSlots::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("signal"), Qt::CaseInsensitive)) { m_signal.append(reader.readElementText()); continue; @@ -6074,7 +6070,7 @@ void DomPropertySpecifications::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); if (!tag.compare(QLatin1String("tooltip"), Qt::CaseInsensitive)) { auto *v = new DomPropertyToolTip(); v->read(reader); @@ -6111,13 +6107,13 @@ void DomPropertySpecifications::write(QXmlStreamWriter &writer, const QString &t writer.writeEndElement(); } -void DomPropertySpecifications::setElementTooltip(const QVector &a) +void DomPropertySpecifications::setElementTooltip(const QList &a) { m_children |= Tooltip; m_tooltip = a; } -void DomPropertySpecifications::setElementStringpropertyspecification(const QVector &a) +void DomPropertySpecifications::setElementStringpropertyspecification(const QList &a) { m_children |= Stringpropertyspecification; m_stringpropertyspecification = a; @@ -6129,7 +6125,7 @@ void DomPropertyToolTip::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -6140,7 +6136,7 @@ void DomPropertyToolTip::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; @@ -6168,7 +6164,7 @@ void DomStringPropertySpecification::read(QXmlStreamReader &reader) { const QXmlStreamAttributes &attributes = reader.attributes(); for (const QXmlStreamAttribute &attribute : attributes) { - const QStringRef name = attribute.name(); + const auto name = attribute.name(); if (name == QLatin1String("name")) { setAttributeName(attribute.value().toString()); continue; @@ -6187,7 +6183,7 @@ void DomStringPropertySpecification::read(QXmlStreamReader &reader) while (!reader.hasError()) { switch (reader.readNext()) { case QXmlStreamReader::StartElement : { - const QStringRef tag = reader.name(); + const auto tag = reader.name(); reader.raiseError(QLatin1String("Unexpected element ") + tag); } break; diff --git a/src/designer/src/lib/uilib/ui4_p.h b/src/designer/src/lib/uilib/ui4_p.h index d1ed64b610..531f53abdc 100644 --- a/src/designer/src/lib/uilib/ui4_p.h +++ b/src/designer/src/lib/uilib/ui4_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -67,7 +56,6 @@ #include #include #include -#include #include #include @@ -191,6 +179,11 @@ class QDESIGNER_UILIB_EXPORT DomUI { inline void setAttributeIdbasedtr(bool a) { m_attr_idbasedtr = a; m_has_attr_idbasedtr = true; } inline void clearAttributeIdbasedtr() { m_has_attr_idbasedtr = false; } + inline bool hasAttributeConnectslotsbyname() const { return m_has_attr_connectslotsbyname; } + inline bool attributeConnectslotsbyname() const { return m_attr_connectslotsbyname; } + inline void setAttributeConnectslotsbyname(bool a) { m_attr_connectslotsbyname = a; m_has_attr_connectslotsbyname = true; } + inline void clearAttributeConnectslotsbyname() { m_has_attr_connectslotsbyname = false; } + inline bool hasAttributeStdsetdef() const { return m_has_attr_stdsetdef; } inline int attributeStdsetdef() const { return m_attr_stdsetdef; } inline void setAttributeStdsetdef(int a) { m_attr_stdsetdef = a; m_has_attr_stdsetdef = true; } @@ -307,6 +300,9 @@ class QDESIGNER_UILIB_EXPORT DomUI { bool m_attr_idbasedtr = false; bool m_has_attr_idbasedtr = false; + bool m_attr_connectslotsbyname = false; + bool m_has_attr_connectslotsbyname = false; + int m_attr_stdsetdef = 0; bool m_has_attr_stdsetdef = false; @@ -362,14 +358,14 @@ class QDESIGNER_UILIB_EXPORT DomIncludes { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementInclude() const { return m_include; } - void setElementInclude(const QVector &a); + inline QList elementInclude() const { return m_include; } + void setElementInclude(const QList &a); private: // child element data uint m_children = 0; - QVector m_include; + QList m_include; enum Child { Include = 1 @@ -426,8 +422,8 @@ class QDESIGNER_UILIB_EXPORT DomResources { inline void clearAttributeName() { m_has_attr_name = false; } // child element accessors - inline QVector elementInclude() const { return m_include; } - void setElementInclude(const QVector &a); + inline QList elementInclude() const { return m_include; } + void setElementInclude(const QList &a); private: // attribute data @@ -436,7 +432,7 @@ class QDESIGNER_UILIB_EXPORT DomResources { // child element data uint m_children = 0; - QVector m_include; + QList m_include; enum Child { Include = 1 @@ -480,16 +476,16 @@ class QDESIGNER_UILIB_EXPORT DomActionGroup { inline void clearAttributeName() { m_has_attr_name = false; } // child element accessors - inline QVector elementAction() const { return m_action; } - void setElementAction(const QVector &a); + inline QList elementAction() const { return m_action; } + void setElementAction(const QList &a); - inline QVector elementActionGroup() const { return m_actionGroup; } - void setElementActionGroup(const QVector &a); + inline QList elementActionGroup() const { return m_actionGroup; } + void setElementActionGroup(const QList &a); - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QList elementAttribute() const { return m_attribute; } + inline QList elementAttribute() const { return m_attribute; } void setElementAttribute(const QList &a); private: @@ -499,10 +495,10 @@ class QDESIGNER_UILIB_EXPORT DomActionGroup { // child element data uint m_children = 0; - QVector m_action; - QVector m_actionGroup; - QList m_property; - QList m_attribute; + QList m_action; + QList m_actionGroup; + QList m_property; + QList m_attribute; enum Child { Action = 1, @@ -533,10 +529,10 @@ class QDESIGNER_UILIB_EXPORT DomAction { inline void clearAttributeMenu() { m_has_attr_menu = false; } // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QList elementAttribute() const { return m_attribute; } + inline QList elementAttribute() const { return m_attribute; } void setElementAttribute(const QList &a); private: @@ -549,8 +545,8 @@ class QDESIGNER_UILIB_EXPORT DomAction { // child element data uint m_children = 0; - QList m_property; - QList m_attribute; + QList m_property; + QList m_attribute; enum Child { Property = 1, @@ -595,10 +591,10 @@ class QDESIGNER_UILIB_EXPORT DomButtonGroup { inline void clearAttributeName() { m_has_attr_name = false; } // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QList elementAttribute() const { return m_attribute; } + inline QList elementAttribute() const { return m_attribute; } void setElementAttribute(const QList &a); private: @@ -608,8 +604,8 @@ class QDESIGNER_UILIB_EXPORT DomButtonGroup { // child element data uint m_children = 0; - QList m_property; - QList m_attribute; + QList m_property; + QList m_attribute; enum Child { Property = 1, @@ -627,14 +623,14 @@ class QDESIGNER_UILIB_EXPORT DomButtonGroups { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementButtonGroup() const { return m_buttonGroup; } - void setElementButtonGroup(const QVector &a); + inline QList elementButtonGroup() const { return m_buttonGroup; } + void setElementButtonGroup(const QList &a); private: // child element data uint m_children = 0; - QVector m_buttonGroup; + QList m_buttonGroup; enum Child { ButtonGroup = 1 @@ -651,14 +647,14 @@ class QDESIGNER_UILIB_EXPORT DomCustomWidgets { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementCustomWidget() const { return m_customWidget; } - void setElementCustomWidget(const QVector &a); + inline QList elementCustomWidget() const { return m_customWidget; } + void setElementCustomWidget(const QList &a); private: // child element data uint m_children = 0; - QVector m_customWidget; + QList m_customWidget; enum Child { CustomWidget = 1 @@ -905,14 +901,14 @@ class QDESIGNER_UILIB_EXPORT DomLayout { inline void clearAttributeColumnMinimumWidth() { m_has_attr_columnMinimumWidth = false; } // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QList elementAttribute() const { return m_attribute; } + inline QList elementAttribute() const { return m_attribute; } void setElementAttribute(const QList &a); - inline QVector elementItem() const { return m_item; } - void setElementItem(const QVector &a); + inline QList elementItem() const { return m_item; } + void setElementItem(const QList &a); private: // attribute data @@ -939,9 +935,9 @@ class QDESIGNER_UILIB_EXPORT DomLayout { // child element data uint m_children = 0; - QList m_property; - QList m_attribute; - QVector m_item; + QList m_property; + QList m_attribute; + QList m_item; enum Child { Property = 1, @@ -1037,14 +1033,14 @@ class QDESIGNER_UILIB_EXPORT DomRow { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); private: // child element data uint m_children = 0; - QList m_property; + QList m_property; enum Child { Property = 1 @@ -1061,14 +1057,14 @@ class QDESIGNER_UILIB_EXPORT DomColumn { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); private: // child element data uint m_children = 0; - QList m_property; + QList m_property; enum Child { Property = 1 @@ -1096,11 +1092,11 @@ class QDESIGNER_UILIB_EXPORT DomItem { inline void clearAttributeColumn() { m_has_attr_column = false; } // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QVector elementItem() const { return m_item; } - void setElementItem(const QVector &a); + inline QList elementItem() const { return m_item; } + void setElementItem(const QList &a); private: // attribute data @@ -1112,8 +1108,8 @@ class QDESIGNER_UILIB_EXPORT DomItem { // child element data uint m_children = 0; - QList m_property; - QVector m_item; + QList m_property; + QList m_item; enum Child { Property = 1, @@ -1150,35 +1146,35 @@ class QDESIGNER_UILIB_EXPORT DomWidget { inline QStringList elementClass() const { return m_class; } void setElementClass(const QStringList &a); - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); - inline QList elementAttribute() const { return m_attribute; } + inline QList elementAttribute() const { return m_attribute; } void setElementAttribute(const QList &a); - inline QVector elementRow() const { return m_row; } - void setElementRow(const QVector &a); + inline QList elementRow() const { return m_row; } + void setElementRow(const QList &a); - inline QVector elementColumn() const { return m_column; } - void setElementColumn(const QVector &a); + inline QList elementColumn() const { return m_column; } + void setElementColumn(const QList &a); - inline QVector elementItem() const { return m_item; } - void setElementItem(const QVector &a); + inline QList elementItem() const { return m_item; } + void setElementItem(const QList &a); - inline QVector elementLayout() const { return m_layout; } - void setElementLayout(const QVector &a); + inline QList elementLayout() const { return m_layout; } + void setElementLayout(const QList &a); - inline QVector elementWidget() const { return m_widget; } - void setElementWidget(const QVector &a); + inline QList elementWidget() const { return m_widget; } + void setElementWidget(const QList &a); - inline QVector elementAction() const { return m_action; } - void setElementAction(const QVector &a); + inline QList elementAction() const { return m_action; } + void setElementAction(const QList &a); - inline QVector elementActionGroup() const { return m_actionGroup; } - void setElementActionGroup(const QVector &a); + inline QList elementActionGroup() const { return m_actionGroup; } + void setElementActionGroup(const QList &a); - inline QVector elementAddAction() const { return m_addAction; } - void setElementAddAction(const QVector &a); + inline QList elementAddAction() const { return m_addAction; } + void setElementAddAction(const QList &a); inline QStringList elementZOrder() const { return m_zOrder; } void setElementZOrder(const QStringList &a); @@ -1197,16 +1193,16 @@ class QDESIGNER_UILIB_EXPORT DomWidget { // child element data uint m_children = 0; QStringList m_class; - QList m_property; - QList m_attribute; - QVector m_row; - QVector m_column; - QVector m_item; - QVector m_layout; - QVector m_widget; - QVector m_action; - QVector m_actionGroup; - QVector m_addAction; + QList m_property; + QList m_attribute; + QList m_row; + QList m_column; + QList m_item; + QList m_layout; + QList m_widget; + QList m_action; + QList m_actionGroup; + QList m_addAction; QStringList m_zOrder; enum Child { @@ -1241,7 +1237,7 @@ class QDESIGNER_UILIB_EXPORT DomSpacer { inline void clearAttributeName() { m_has_attr_name = false; } // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); private: @@ -1251,7 +1247,7 @@ class QDESIGNER_UILIB_EXPORT DomSpacer { // child element data uint m_children = 0; - QList m_property; + QList m_property; enum Child { Property = 1 @@ -1419,8 +1415,8 @@ class QDESIGNER_UILIB_EXPORT DomGradient { inline void clearAttributeCoordinateMode() { m_has_attr_coordinateMode = false; } // child element accessors - inline QVector elementGradientStop() const { return m_gradientStop; } - void setElementGradientStop(const QVector &a); + inline QList elementGradientStop() const { return m_gradientStop; } + void setElementGradientStop(const QList &a); private: // attribute data @@ -1465,7 +1461,7 @@ class QDESIGNER_UILIB_EXPORT DomGradient { // child element data uint m_children = 0; - QVector m_gradientStop; + QList m_gradientStop; enum Child { GradientStop = 1 @@ -1563,18 +1559,18 @@ class QDESIGNER_UILIB_EXPORT DomColorGroup { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementColorRole() const { return m_colorRole; } - void setElementColorRole(const QVector &a); + inline QList elementColorRole() const { return m_colorRole; } + void setElementColorRole(const QList &a); - inline QVector elementColor() const { return m_color; } - void setElementColor(const QVector &a); + inline QList elementColor() const { return m_color; } + void setElementColor(const QList &a); private: // child element data uint m_children = 0; - QVector m_colorRole; - QVector m_color; + QList m_colorRole; + QList m_color; enum Child { ColorRole = 1, @@ -2674,14 +2670,14 @@ class QDESIGNER_UILIB_EXPORT DomConnections { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementConnection() const { return m_connection; } - void setElementConnection(const QVector &a); + inline QList elementConnection() const { return m_connection; } + void setElementConnection(const QList &a); private: // child element data uint m_children = 0; - QVector m_connection; + QList m_connection; enum Child { Connection = 1 @@ -2753,14 +2749,14 @@ class QDESIGNER_UILIB_EXPORT DomConnectionHints { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementHint() const { return m_hint; } - void setElementHint(const QVector &a); + inline QList elementHint() const { return m_hint; } + void setElementHint(const QList &a); private: // child element data uint m_children = 0; - QVector m_hint; + QList m_hint; enum Child { Hint = 1 @@ -2819,14 +2815,14 @@ class QDESIGNER_UILIB_EXPORT DomDesignerData { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QList elementProperty() const { return m_property; } + inline QList elementProperty() const { return m_property; } void setElementProperty(const QList &a); private: // child element data uint m_children = 0; - QList m_property; + QList m_property; enum Child { Property = 1 @@ -2872,18 +2868,18 @@ class QDESIGNER_UILIB_EXPORT DomPropertySpecifications { void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const; // child element accessors - inline QVector elementTooltip() const { return m_tooltip; } - void setElementTooltip(const QVector &a); + inline QList elementTooltip() const { return m_tooltip; } + void setElementTooltip(const QList &a); - inline QVector elementStringpropertyspecification() const { return m_stringpropertyspecification; } - void setElementStringpropertyspecification(const QVector &a); + inline QList elementStringpropertyspecification() const { return m_stringpropertyspecification; } + void setElementStringpropertyspecification(const QList &a); private: // child element data uint m_children = 0; - QVector m_tooltip; - QVector m_stringpropertyspecification; + QList m_tooltip; + QList m_stringpropertyspecification; enum Child { Tooltip = 1, diff --git a/src/designer/src/lib/uilib/uilib.pri b/src/designer/src/lib/uilib/uilib.pri deleted file mode 100644 index 386414b67d..0000000000 --- a/src/designer/src/lib/uilib/uilib.pri +++ /dev/null @@ -1,28 +0,0 @@ - -INCLUDEPATH += $$PWD - -DEFINES += QT_DESIGNER QT_USE_QSTRINGBUILDER - -QT += widgets -QT_PRIVATE += uiplugin - -# Input -HEADERS += \ - $$PWD/ui4_p.h \ - $$PWD/abstractformbuilder.h \ - $$PWD/formbuilder.h \ - $$PWD/properties_p.h \ - $$PWD/formbuilderextra_p.h \ - $$PWD/resourcebuilder_p.h \ - $$PWD/textbuilder_p.h - -SOURCES += \ - $$PWD/abstractformbuilder.cpp \ - $$PWD/formbuilder.cpp \ - $$PWD/ui4.cpp \ - $$PWD/properties.cpp \ - $$PWD/formbuilderextra.cpp \ - $$PWD/resourcebuilder.cpp \ - $$PWD/textbuilder.cpp - -OTHER_FILES += $$PWD/widgets.table diff --git a/src/designer/src/lib/uilib/uilib_global.h b/src/designer/src/lib/uilib/uilib_global.h index 3f4944bc81..8630b0af04 100644 --- a/src/designer/src/lib/uilib/uilib_global.h +++ b/src/designer/src/lib/uilib/uilib_global.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/designer/src/lib/uilib/widgets.table b/src/designer/src/lib/uilib/widgets.table index 3dbb7aff24..546197ebca 100644 --- a/src/designer/src/lib/uilib/widgets.table +++ b/src/designer/src/lib/uilib/widgets.table @@ -111,7 +111,7 @@ DECLARE_WIDGET(QWidget, "") #if QT_CONFIG(keysequenceedit) DECLARE_WIDGET(QKeySequenceEdit, "") #endif -#if QT_CONFIG(opengl) +#ifdef QT_OPENGLWIDGETS_LIB DECLARE_WIDGET(QOpenGLWidget, "") #endif #if QT_CONFIG(splitter) diff --git a/src/designer/src/plugins/CMakeLists.txt b/src/designer/src/plugins/CMakeLists.txt new file mode 100644 index 0000000000..9534009be3 --- /dev/null +++ b/src/designer/src/plugins/CMakeLists.txt @@ -0,0 +1,11 @@ +# Generated from plugins.pro. + +if(TARGET Qt::WebKitWidgets) + add_subdirectory(qwebview) +endif() +if(TARGET Qt::AxContainer AND WIN32) + add_subdirectory(activeqt) +endif() +if(TARGET Qt::QuickWidgets) + add_subdirectory(qquickwidget) +endif() diff --git a/src/designer/src/plugins/activeqt/CMakeLists.txt b/src/designer/src/plugins/activeqt/CMakeLists.txt new file mode 100644 index 0000000000..0ac285f188 --- /dev/null +++ b/src/designer/src/plugins/activeqt/CMakeLists.txt @@ -0,0 +1,26 @@ +# Generated from activeqt.pro. + +##################################################################### +## QAxWidgetPlugin Plugin: +##################################################################### + +qt_internal_add_plugin(QAxWidgetPlugin + OUTPUT_NAME qaxwidget + TYPE designer + SOURCES + qaxwidgetextrainfo.cpp qaxwidgetextrainfo.h + qaxwidgetplugin.cpp qaxwidgetplugin.h + qaxwidgetpropertysheet.cpp qaxwidgetpropertysheet.h + qaxwidgettaskmenu.cpp qaxwidgettaskmenu.h + qdesigneraxwidget.cpp qdesigneraxwidget.h + PUBLIC_LIBRARIES + Qt::AxContainer + Qt::Core + Qt::Designer + Qt::DesignerPrivate + Qt::Gui + Qt::Widgets +) + +#### Keys ignored in scope 1:.:.:activeqt.pro:: +# OTHER_FILES = "activeqt.json" diff --git a/src/designer/src/plugins/activeqt/activeqt.pro b/src/designer/src/plugins/activeqt/activeqt.pro deleted file mode 100644 index fb0928246c..0000000000 --- a/src/designer/src/plugins/activeqt/activeqt.pro +++ /dev/null @@ -1,19 +0,0 @@ -TARGET = qaxwidget -QT += widgets designer-private axcontainer - -PLUGIN_CLASS_NAME = QAxWidgetPlugin -include(../plugins.pri) - -SOURCES += qaxwidgetextrainfo.cpp \ -qaxwidgetplugin.cpp \ -qdesigneraxwidget.cpp \ -qaxwidgetpropertysheet.cpp \ -qaxwidgettaskmenu.cpp - -HEADERS += qaxwidgetextrainfo.h \ -qaxwidgetplugin.h \ -qdesigneraxwidget.h \ -qaxwidgetpropertysheet.h \ -qaxwidgettaskmenu.h - -OTHER_FILES += activeqt.json diff --git a/src/designer/src/plugins/activeqt/qaxwidgetplugin.cpp b/src/designer/src/plugins/activeqt/qaxwidgetplugin.cpp index a29ba2f77c..9d28392c9a 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgetplugin.cpp +++ b/src/designer/src/plugins/activeqt/qaxwidgetplugin.cpp @@ -37,13 +37,12 @@ #include #include -#include +#include QT_BEGIN_NAMESPACE QAxWidgetPlugin::QAxWidgetPlugin(QObject *parent) : - QObject(parent), - m_core(0) + QObject(parent) { } @@ -85,8 +84,9 @@ bool QAxWidgetPlugin::isContainer() const QWidget *QAxWidgetPlugin::createWidget(QWidget *parent) { // Construction from Widget box or on a form? - const bool isFormEditor = parent != 0 && QDesignerFormWindowInterface::findFormWindow(parent) != 0; - QDesignerAxWidget *rc = new QDesignerAxPluginWidget(parent); + const bool isFormEditor = parent != nullptr + && QDesignerFormWindowInterface::findFormWindow(parent) != nullptr; + auto rc = new QDesignerAxPluginWidget(parent); if (!isFormEditor) rc->setDrawFlags(QDesignerAxWidget::DrawFrame|QDesignerAxWidget::DrawControl); return rc; @@ -94,12 +94,12 @@ QWidget *QAxWidgetPlugin::createWidget(QWidget *parent) bool QAxWidgetPlugin::isInitialized() const { - return m_core != 0; + return m_core != nullptr; } void QAxWidgetPlugin::initialize(QDesignerFormEditorInterface *core) { - if (m_core != 0) + if (m_core != nullptr) return; m_core = core; @@ -113,19 +113,18 @@ void QAxWidgetPlugin::initialize(QDesignerFormEditorInterface *core) QString QAxWidgetPlugin::domXml() const { - return QStringLiteral("\ -\ - \ - \ - \ - 0\ - 0\ - 80\ - 70\ - \ - \ - \ -"); + return QStringLiteral(R"( + + + + 0 + 0 + 80 + 70 + + + +)"); } QT_END_NAMESPACE diff --git a/src/designer/src/plugins/activeqt/qaxwidgetplugin.h b/src/designer/src/plugins/activeqt/qaxwidgetplugin.h index 23311e90b6..2d0cef2496 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgetplugin.h +++ b/src/designer/src/plugins/activeqt/qaxwidgetplugin.h @@ -42,7 +42,7 @@ class QAxWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDesignerCustomWidget" FILE "activeqt.json") Q_INTERFACES(QDesignerCustomWidgetInterface) public: - explicit QAxWidgetPlugin(QObject *parent = 0); + explicit QAxWidgetPlugin(QObject *parent = nullptr); QString name() const override; QString group() const override; @@ -57,7 +57,7 @@ class QAxWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface QString domXml() const override; private: - QDesignerFormEditorInterface *m_core; + QDesignerFormEditorInterface *m_core = nullptr; }; QT_END_NAMESPACE diff --git a/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.cpp b/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.cpp index 960316cf2b..f6e2e26399 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.cpp +++ b/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.cpp @@ -70,6 +70,12 @@ bool QAxWidgetPropertySheet::isEnabled(int index) const return QDesignerPropertySheet::isEnabled(index); } +bool QAxWidgetPropertySheet::isVisible(int index) const +{ + // classContext is ulong, which the property editor does not support + return propertyName(index) != QLatin1String("classContext"); +} + bool QAxWidgetPropertySheet::dynamicPropertiesAllowed() const { return false; @@ -130,7 +136,7 @@ int QAxWidgetPropertySheet::indexOf(const QString &name) const return index; // Loading before recreation of sheet in timer slot: Add a fake property to store the value const QVariant dummValue(0); - QAxWidgetPropertySheet *that = const_cast(this); + auto that = const_cast(this); const int newIndex = that->createFakeProperty(name, dummValue); that->setPropertyGroup(newIndex, m_propertyGroup); return newIndex; @@ -142,7 +148,7 @@ void QAxWidgetPropertySheet::updatePropertySheet() struct SavedProperties tmp = m_currentProperties; QDesignerAxWidget *axw = axWidget(); QDesignerFormWindowInterface *formWin = QDesignerFormWindowInterface::findFormWindow(axw); - Q_ASSERT(formWin != 0); + Q_ASSERT(formWin != nullptr); tmp.widget = axw; tmp.clsid = axw->control(); // Delete the sheets as they cache the meta object and other information @@ -151,16 +157,18 @@ void QAxWidgetPropertySheet::updatePropertySheet() reloadPropertySheet(tmp, formWin); } -void QAxWidgetPropertySheet::reloadPropertySheet(const struct SavedProperties &properties, QDesignerFormWindowInterface *formWin) +void QAxWidgetPropertySheet::reloadPropertySheet(const struct SavedProperties &properties, + QDesignerFormWindowInterface *formWin) { QDesignerFormEditorInterface *core = formWin->core(); //Recreation of the property sheet - QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), properties.widget); + auto sheet = qt_extension(core->extensionManager(), + properties.widget); bool foundGeometry = false; const QString geometryProperty = QLatin1String(geometryPropertyC); - const SavedProperties::NamePropertyMap::const_iterator cend = properties.changedProperties.constEnd(); - for (SavedProperties::NamePropertyMap::const_iterator i = properties.changedProperties.constBegin(); i != cend; ++i) { + for (auto i = properties.changedProperties.cbegin(), cend = properties.changedProperties.cend(); + i != cend; ++i) { const QString name = i.key(); const int index = sheet->indexOf(name); if (index == -1) diff --git a/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.h b/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.h index 93ff577aae..8bea29a4ec 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.h +++ b/src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.h @@ -53,6 +53,7 @@ class QAxWidgetPropertySheet: public QDesignerPropertySheet explicit QAxWidgetPropertySheet(QDesignerAxWidget *object, QObject *parent = 0); bool isEnabled(int index) const override; + bool isVisible(int index) const override; QVariant property(int index) const override; void setProperty(int index, const QVariant &value) override; bool reset(int index) override; diff --git a/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp b/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp index 4e34f38729..97594473b3 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp +++ b/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp @@ -35,15 +35,17 @@ #include #include +#include + #include -#include -#include +#include + +#include + +#include #include -#include -#include #include -#include QT_BEGIN_NAMESPACE @@ -86,8 +88,9 @@ bool SetControlCommand::apply(const QString &clsid) if (m_oldClsid == m_newClsid) return true; - QObject *ext = m_formWindow->core()->extensionManager()->extension(m_axWidget, Q_TYPEID(QDesignerPropertySheetExtension)); - QAxWidgetPropertySheet *sheet = qobject_cast(ext); + QObject *ext = m_formWindow->core()->extensionManager()->extension( + m_axWidget, Q_TYPEID(QDesignerPropertySheetExtension)); + auto sheet = qobject_cast(ext); if (!sheet) return false; @@ -113,9 +116,7 @@ QAxWidgetTaskMenu::QAxWidgetTaskMenu(QDesignerAxWidget *object, QObject *parent) m_taskActions.push_back(m_resetAction); } -QAxWidgetTaskMenu::~QAxWidgetTaskMenu() -{ -} +QAxWidgetTaskMenu::~QAxWidgetTaskMenu() = default; QList QAxWidgetTaskMenu::taskActions() const { @@ -127,48 +128,46 @@ QList QAxWidgetTaskMenu::taskActions() const void QAxWidgetTaskMenu::resetActiveXControl() { - QDesignerFormWindowInterface *formWin = QDesignerFormWindowInterface::findFormWindow(m_axwidget); - Q_ASSERT(formWin != 0); + auto formWin = QDesignerFormWindowInterface::findFormWindow(m_axwidget); + Q_ASSERT(formWin != nullptr); formWin->commandHistory()->push(new SetControlCommand(m_axwidget, formWin)); } void QAxWidgetTaskMenu::setActiveXControl() { - QAxSelect *dialog = new QAxSelect(m_axwidget->topLevelWidget()); - if (dialog->exec()) { - QUuid clsid = dialog->clsid(); - QString key; - - IClassFactory2 *cf2 = 0; - CoGetClassObject(clsid, CLSCTX_SERVER, 0, IID_IClassFactory2, (void**)&cf2); - - if (cf2) { - BSTR bKey; - HRESULT hres = cf2->RequestLicKey(0, &bKey); - if (hres == CLASS_E_NOTLICENSED) { - QMessageBox::warning(m_axwidget->topLevelWidget(), tr("Licensed Control"), - tr("The control requires a design-time license")); - clsid = QUuid(); - } else { - key = QString::fromWCharArray(bKey); - } - + QAxSelect dialog(m_axwidget->topLevelWidget()); + if (dialog.exec() != QDialog::Accepted) + return; + + const auto clsid = QUuid::fromString(dialog.clsid()); + QString key; + + IClassFactory2 *cf2 = nullptr; + CoGetClassObject(clsid, CLSCTX_SERVER, 0, IID_IClassFactory2, reinterpret_cast(&cf2)); + + if (cf2) { + BSTR bKey; + HRESULT hres = cf2->RequestLicKey(0, &bKey); + if (hres == CLASS_E_NOTLICENSED) { + QMessageBox::warning(m_axwidget->topLevelWidget(), tr("Licensed Control"), + tr("The control requires a design-time license")); cf2->Release(); + return; } - if (!clsid.isNull()) { - QDesignerFormWindowInterface *formWin = QDesignerFormWindowInterface::findFormWindow(m_axwidget); + key = QString::fromWCharArray(bKey); + cf2->Release(); + } + + auto formWin = QDesignerFormWindowInterface::findFormWindow(m_axwidget); - Q_ASSERT(formWin != 0); - QString value = clsid.toString(); - if (!key.isEmpty()) { - value += QLatin1Char(':'); - value += key; - } - formWin->commandHistory()->push(new SetControlCommand(m_axwidget, formWin, value)); - } + Q_ASSERT(formWin != nullptr); + QString value = clsid.toString(); + if (!key.isEmpty()) { + value += QLatin1Char(':'); + value += key; } - delete dialog; + formWin->commandHistory()->push(new SetControlCommand(m_axwidget, formWin, value)); } QT_END_NAMESPACE diff --git a/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.h b/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.h index e1cf40af65..ea76dcd5a8 100644 --- a/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.h +++ b/src/designer/src/plugins/activeqt/qaxwidgettaskmenu.h @@ -41,7 +41,7 @@ class QAxWidgetTaskMenu: public QObject, public QDesignerTaskMenuExtension Q_OBJECT Q_INTERFACES(QDesignerTaskMenuExtension) public: - explicit QAxWidgetTaskMenu(QDesignerAxWidget *object, QObject *parent = 0); + explicit QAxWidgetTaskMenu(QDesignerAxWidget *object, QObject *parent = nullptr); virtual ~QAxWidgetTaskMenu(); QList taskActions() const override; diff --git a/src/designer/src/plugins/activeqt/qdesigneraxwidget.cpp b/src/designer/src/plugins/activeqt/qdesigneraxwidget.cpp index 9ce14ed817..a787c08525 100644 --- a/src/designer/src/plugins/activeqt/qdesigneraxwidget.cpp +++ b/src/designer/src/plugins/activeqt/qdesigneraxwidget.cpp @@ -34,11 +34,10 @@ #include #include -#include +#include #include #include -#include enum { debugAxWidget = 0 }; @@ -78,9 +77,6 @@ const char *widgetIconXPM[]={ QDesignerAxWidget::QDesignerAxWidget(QWidget *parent) : QWidget(parent), - m_defaultSize(80, 70), - m_drawFlags(DrawIndicator|DrawFrame|DrawControl), - m_axobject(0), m_axImage(widgetIcon()) { } @@ -117,7 +113,7 @@ void QDesignerAxWidget::resetControl() if (!m_axobject) return; delete m_axobject; - m_axobject = 0; + m_axobject = nullptr; update(); } @@ -131,7 +127,7 @@ bool QDesignerAxWidget::loadControl(const QString &clsid) if (!m_axobject->setControl(clsid)) { delete m_axobject; - m_axobject = 0; + m_axobject = nullptr; return false; } update(); @@ -190,9 +186,7 @@ QDesignerAxPluginWidget::QDesignerAxPluginWidget(QWidget *parent) : { } -QDesignerAxPluginWidget::~QDesignerAxPluginWidget() -{ -} +QDesignerAxPluginWidget::~QDesignerAxPluginWidget() = default; const QMetaObject *QDesignerAxPluginWidget::metaObject() const { @@ -212,6 +206,12 @@ static QString msgComException(const QObject *o, const QMetaObject::Call call, i #endif // QT_NO_EXCEPTIONS +static bool isInheritedCall(const QMetaObject *mo, QMetaObject::Call call, int id) +{ + return call == QMetaObject::InvokeMetaMethod + ? (id < mo->methodOffset()) : (id < mo->propertyOffset()); +} + int QDesignerAxPluginWidget::qt_metacall(QMetaObject::Call call, int signal, void **argv) { QAxWidget *aw = axobject(); @@ -221,10 +221,11 @@ int QDesignerAxPluginWidget::qt_metacall(QMetaObject::Call call, int signal, voi const QMetaObject *mo = metaObject(); // Have base class handle inherited stuff (geometry, enabled...) - const bool inherited = call == QMetaObject::InvokeMetaMethod ? - (signal < mo->methodOffset()) : (signal < mo->propertyOffset()); - if (inherited) - return QDesignerAxWidget::qt_metacall(call, signal, argv); + if (isInheritedCall(mo, call, signal)) { + // Skip over QAxBaseWidget + return isInheritedCall(mo->superClass(), call, signal) + ? QDesignerAxWidget::qt_metacall(call, signal, argv) : -1; + } int rc = -1; #ifndef QT_NO_EXCEPTIONS @@ -234,11 +235,6 @@ int QDesignerAxPluginWidget::qt_metacall(QMetaObject::Call call, int signal, voi if (call != QMetaObject::InvokeMetaMethod) qDebug() << objectName() << call << signal << mo->property(signal).name(); switch (call) { - case QMetaObject::QueryPropertyStored: // Pretend all changed properties are stored for them to be saved - if (m_propValues.contains(signal)) - if (argv[0]) - *reinterpret_cast< bool*>(argv[0]) = true; - break; case QMetaObject::ResetProperty: rc = aw->qt_metacall(call, signal, argv); update(); diff --git a/src/designer/src/plugins/activeqt/qdesigneraxwidget.h b/src/designer/src/plugins/activeqt/qdesigneraxwidget.h index 3c15763da3..8f74bfaea1 100644 --- a/src/designer/src/plugins/activeqt/qdesigneraxwidget.h +++ b/src/designer/src/plugins/activeqt/qdesigneraxwidget.h @@ -84,9 +84,9 @@ class QDesignerAxWidget : public QWidget QAxWidget *axobject() const { return m_axobject; } private: - const QSize m_defaultSize; - unsigned m_drawFlags; - QAxWidget *m_axobject; + const QSize m_defaultSize { 80, 70 }; + unsigned m_drawFlags = DrawIndicator | DrawFrame | DrawControl; + QAxWidget *m_axobject = nullptr; QPixmap m_axImage; }; diff --git a/src/designer/src/plugins/plugins.pri b/src/designer/src/plugins/plugins.pri deleted file mode 100644 index c4613d1a69..0000000000 --- a/src/designer/src/plugins/plugins.pri +++ /dev/null @@ -1,5 +0,0 @@ -QT += designer - -PLUGIN_TYPE = designer -CONFIG += tool_plugin -load(qt_plugin) diff --git a/src/designer/src/plugins/plugins.pro b/src/designer/src/plugins/plugins.pro deleted file mode 100644 index 500a15345f..0000000000 --- a/src/designer/src/plugins/plugins.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = subdirs - -# qtHaveModule(opengl): SUBDIRS += tools/view3d -qtHaveModule(webkitwidgets): SUBDIRS += qwebview -win32: qtHaveModule(axcontainer): SUBDIRS += activeqt -qtHaveModule(quickwidgets): SUBDIRS += qquickwidget diff --git a/src/designer/src/plugins/qquickwidget/CMakeLists.txt b/src/designer/src/plugins/qquickwidget/CMakeLists.txt new file mode 100644 index 0000000000..b755e3b2dd --- /dev/null +++ b/src/designer/src/plugins/qquickwidget/CMakeLists.txt @@ -0,0 +1,31 @@ +# Generated from qquickwidget.pro. + +##################################################################### +## QQuickWidgetPlugin Plugin: +##################################################################### + +qt_internal_add_plugin(QQuickWidgetPlugin + OUTPUT_NAME qquickwidget + TYPE designer + SOURCES + qquickwidget_plugin.cpp qquickwidget_plugin.h + PUBLIC_LIBRARIES + Qt::Core + Qt::Designer + Qt::Gui + Qt::QuickWidgets + Qt::Widgets +) + +# Resources: +set(qquickwidget_plugin_resource_files + "images/qquickwidget.png" +) + +qt_internal_add_resource(QQuickWidgetPlugin "qquickwidget_plugin" + PREFIX + "/qt-project.org/qquickwidget" + FILES + ${qquickwidget_plugin_resource_files} +) + diff --git a/src/designer/src/plugins/qquickwidget/qquickwidget.pro b/src/designer/src/plugins/qquickwidget/qquickwidget.pro deleted file mode 100644 index bfdade7de1..0000000000 --- a/src/designer/src/plugins/qquickwidget/qquickwidget.pro +++ /dev/null @@ -1,9 +0,0 @@ -TARGET = qquickwidget -QT += widgets quickwidgets - -PLUGIN_CLASS_NAME = QQuickWidgetPlugin -include(../plugins.pri) - -SOURCES += qquickwidget_plugin.cpp -HEADERS += qquickwidget_plugin.h -RESOURCES += qquickwidget_plugin.qrc diff --git a/src/designer/src/plugins/qquickwidget/qquickwidget_plugin.cpp b/src/designer/src/plugins/qquickwidget/qquickwidget_plugin.cpp index 8e1721a939..cce05023ab 100644 --- a/src/designer/src/plugins/qquickwidget/qquickwidget_plugin.cpp +++ b/src/designer/src/plugins/qquickwidget/qquickwidget_plugin.cpp @@ -35,6 +35,9 @@ #include #include +#include + + QT_BEGIN_NAMESPACE QQuickWidgetPlugin::QQuickWidgetPlugin(QObject *parent) @@ -100,22 +103,29 @@ void QQuickWidgetPlugin::initialize(QDesignerFormEditorInterface * /*core*/) QString QQuickWidgetPlugin::domXml() const { - return QStringLiteral("\ - \ - \ - \ - QQuickWidget::SizeRootObjectToView\ - \ - \ - \ - 0\ - 0\ - 300\ - 200\ - \ - \ - \ - "); + const auto graphicsApi = QQuickWindow::graphicsApi(); + if (graphicsApi != QSGRendererInterface::OpenGLRhi) { + qWarning("Qt Designer: The QQuickWidget custom widget plugin is disabled because it requires OpenGL RHI (current: %d).", + int(graphicsApi)); + return {}; + } + return QStringLiteral(R"( + + + + QQuickWidget::SizeRootObjectToView + + + + 0 + 0 + 300 + 200 + + + + +)"); } void QQuickWidgetPlugin::sceneGraphError(QQuickWindow::SceneGraphError, const QString &message) diff --git a/src/designer/src/plugins/qwebview/CMakeLists.txt b/src/designer/src/plugins/qwebview/CMakeLists.txt new file mode 100644 index 0000000000..98a603f4c1 --- /dev/null +++ b/src/designer/src/plugins/qwebview/CMakeLists.txt @@ -0,0 +1,34 @@ +# Generated from qwebview.pro. + +##################################################################### +## QWebViewPlugin Plugin: +##################################################################### + +qt_internal_add_plugin(QWebViewPlugin + OUTPUT_NAME qwebview + TYPE designer + SOURCES + qwebview_plugin.cpp qwebview_plugin.h + PUBLIC_LIBRARIES + Qt::Core + Qt::Designer + Qt::Gui + Qt::WebKitWidgets + Qt::Widgets +) + +# Resources: +set(qwebview_plugin_resource_files + "images/qwebview.png" +) + +qt_internal_add_resource(QWebViewPlugin "qwebview_plugin" + PREFIX + "/qt-project.org/qwebview" + FILES + ${qwebview_plugin_resource_files} +) + + +#### Keys ignored in scope 1:.:.:qwebview.pro:: +# OTHER_FILES = "qwebview.json" diff --git a/src/designer/src/plugins/qwebview/qwebview.pro b/src/designer/src/plugins/qwebview/qwebview.pro deleted file mode 100644 index e9268b559b..0000000000 --- a/src/designer/src/plugins/qwebview/qwebview.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = qwebview -QT += widgets webkitwidgets - -PLUGIN_CLASS_NAME = QWebViewPlugin -include(../plugins.pri) - -SOURCES += qwebview_plugin.cpp -HEADERS += qwebview_plugin.h -RESOURCES += qwebview_plugin.qrc -OTHER_FILES += qwebview.json diff --git a/src/designer/src/plugins/qwebview/qwebview_plugin.cpp b/src/designer/src/plugins/qwebview/qwebview_plugin.cpp index 5f72a6185b..6583ddf8b3 100644 --- a/src/designer/src/plugins/qwebview/qwebview_plugin.cpp +++ b/src/designer/src/plugins/qwebview/qwebview_plugin.cpp @@ -96,24 +96,25 @@ void QWebViewPlugin::initialize(QDesignerFormEditorInterface * /*core*/) QString QWebViewPlugin::domXml() const { - return QStringLiteral("\ - \ - \ - \ - \ - about:blank\ - \ - \ - \ - \ - 0\ - 0\ - 300\ - 200\ - \ - \ - \ - "); + return QStringLiteral(R"( + + + + + about:blank + + + + + 0 + 0 + 300 + 200 + + + + +)"); } QT_END_NAMESPACE diff --git a/src/designer/src/plugins/tools/view3d/CMakeLists.txt b/src/designer/src/plugins/tools/view3d/CMakeLists.txt new file mode 100644 index 0000000000..d7d43a5ac3 --- /dev/null +++ b/src/designer/src/plugins/tools/view3d/CMakeLists.txt @@ -0,0 +1,21 @@ +# Generated from view3d.pro. + +##################################################################### +## QView3DPlugin Plugin: +##################################################################### + +qt_internal_add_plugin(QView3DPlugin + OUTPUT_NAME view3d + TYPE designer + SOURCES + view3d.cpp view3d.h + view3d_global.h + view3d_plugin.cpp view3d_plugin.h + view3d_tool.cpp view3d_tool.h + PUBLIC_LIBRARIES + Qt::Core + Qt::Designer + Qt::Gui + Qt::OpenGL + Qt::Widgets +) diff --git a/src/designer/src/plugins/tools/view3d/view3d.cpp b/src/designer/src/plugins/tools/view3d/view3d.cpp index 91700f6506..3ae8bdf477 100644 --- a/src/designer/src/plugins/tools/view3d/view3d.cpp +++ b/src/designer/src/plugins/tools/view3d/view3d.cpp @@ -217,7 +217,7 @@ void QView3DWidget::initializeGL() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - qglClearColor(palette().color(QPalette::Window).dark()); + qglClearColor(palette().color(QPalette::Window).darker()); glColor3f (1.0, 1.0, 1.0); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); diff --git a/src/designer/src/plugins/tools/view3d/view3d.pro b/src/designer/src/plugins/tools/view3d/view3d.pro deleted file mode 100644 index 81f6a9384a..0000000000 --- a/src/designer/src/plugins/tools/view3d/view3d.pro +++ /dev/null @@ -1,8 +0,0 @@ -QT += opengl widgets -TARGET = view3d - -PLUGIN_CLASS_NAME = QView3DPlugin -include(../../plugins.pri) - -SOURCES += view3d.cpp view3d_tool.cpp view3d_plugin.cpp -HEADERS += view3d.h view3d_tool.h view3d_plugin.h view3d_global.h diff --git a/src/designer/src/plugins/tools/view3d/view3d_plugin.cpp b/src/designer/src/plugins/tools/view3d/view3d_plugin.cpp index 5af4cc007a..3bf356e56b 100644 --- a/src/designer/src/plugins/tools/view3d/view3d_plugin.cpp +++ b/src/designer/src/plugins/tools/view3d/view3d_plugin.cpp @@ -29,12 +29,14 @@ #include "view3d_plugin.h" #include "view3d_tool.h" -#include -#include -#include #include #include +#include + +#include +#include + QView3DPlugin::QView3DPlugin() { m_core = 0; diff --git a/src/designer/src/plugins/tools/view3d/view3d_tool.cpp b/src/designer/src/plugins/tools/view3d/view3d_tool.cpp index d53e719436..fe52d6aed7 100644 --- a/src/designer/src/plugins/tools/view3d/view3d_tool.cpp +++ b/src/designer/src/plugins/tools/view3d/view3d_tool.cpp @@ -28,9 +28,10 @@ #include "view3d_tool.h" -#include #include +#include + QView3DTool::QView3DTool(QDesignerFormWindowInterface *formWindow, QObject *parent) : QDesignerFormWindowToolInterface(parent) { diff --git a/src/designer/src/src.pro b/src/designer/src/src.pro deleted file mode 100644 index 79e9e64ee8..0000000000 --- a/src/designer/src/src.pro +++ /dev/null @@ -1,28 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = \ - uiplugin \ - uitools - -qtConfig(process) { - SUBDIRS += \ - lib \ - components \ - designer - - lib.depends = uiplugin - components.depends = lib - designer.depends = components - plugins.depends = lib - - contains(QT_CONFIG, shared): SUBDIRS += plugins -} - -uitools.depends = uiplugin - -qtNomakeTools( \ - lib \ - components \ - designer \ - plugins \ -) diff --git a/src/designer/src/uiplugin/CMakeLists.txt b/src/designer/src/uiplugin/CMakeLists.txt new file mode 100644 index 0000000000..4fedf8e333 --- /dev/null +++ b/src/designer/src/uiplugin/CMakeLists.txt @@ -0,0 +1,27 @@ +# Generated from uiplugin.pro. + +##################################################################### +## UiPlugin Module: +##################################################################### + +qt_internal_add_module(UiPlugin + NO_PRIVATE_MODULE + HEADER_MODULE + QMAKE_MODULE_CONFIG designer_defines + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::Widgets +) + +# special case begin +set(is_plugin "$") +target_compile_definitions( + UiPlugin + INTERFACE + $<$:QDESIGNER_EXPORT_WIDGETS> +) +# special case end + +#### Keys ignored in scope 1:.:.:uiplugin.pro:: +# MODULE_CONFIG = "designer_defines" diff --git a/src/designer/src/uiplugin/uiplugin.pro b/src/designer/src/uiplugin/uiplugin.pro deleted file mode 100644 index 7c41ea78cb..0000000000 --- a/src/designer/src/uiplugin/uiplugin.pro +++ /dev/null @@ -1,6 +0,0 @@ -TARGET = QtUiPlugin -CONFIG += no_private_module header_module -QT += widgets - -MODULE_CONFIG = designer_defines -load(qt_module) diff --git a/src/designer/src/uitools/CMakeLists.txt b/src/designer/src/uitools/CMakeLists.txt new file mode 100644 index 0000000000..5306fcbd58 --- /dev/null +++ b/src/designer/src/uitools/CMakeLists.txt @@ -0,0 +1,47 @@ +# Generated from uitools.pro. + +##################################################################### +## UiTools Module: +##################################################################### + +qt_internal_add_module(UiTools + SOURCES + ../lib/uilib/abstractformbuilder.cpp ../lib/uilib/abstractformbuilder.h + ../lib/uilib/formbuilder.cpp ../lib/uilib/formbuilder.h + ../lib/uilib/formbuilderextra.cpp ../lib/uilib/formbuilderextra_p.h + ../lib/uilib/properties.cpp ../lib/uilib/properties_p.h + ../lib/uilib/resourcebuilder.cpp ../lib/uilib/resourcebuilder_p.h + ../lib/uilib/textbuilder.cpp ../lib/uilib/textbuilder_p.h + ../lib/uilib/ui4.cpp ../lib/uilib/ui4_p.h + quiloader.cpp quiloader.h + DEFINES + QFORMINTERNAL_NAMESPACE + QT_DESIGNER + QT_DESIGNER_STATIC + QT_USE_QSTRINGBUILDER + INCLUDE_DIRECTORIES + ../lib/uilib + LIBRARIES + Qt::UiPlugin + PUBLIC_LIBRARIES + Qt::Core + Qt::Gui + Qt::Widgets +) + +## Scopes: +##################################################################### + +qt_internal_extend_target(UiTools CONDITION TARGET Qt::OpenGLWidgets + PUBLIC_LIBRARIES + Qt::OpenGLWidgets +) + +qt_internal_extend_target(UiTools CONDITION QT_FEATURE_opengl + LIBRARIES + Qt::OpenGL +) +qt_internal_add_docs(UiTools + doc/qtuitools.qdocconf +) + diff --git a/src/designer/src/uitools/doc/qtuitools.qdocconf b/src/designer/src/uitools/doc/qtuitools.qdocconf index b3306ce595..47a86c8b61 100644 --- a/src/designer/src/uitools/doc/qtuitools.qdocconf +++ b/src/designer/src/uitools/doc/qtuitools.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtUiTools description = Qt UI Tools Reference Documentation @@ -40,3 +41,5 @@ depends += qtdoc qtdesigner qtcore qtwidgets navigation.landingpage = "Qt UI Tools" navigation.cppclassespage = "Qt UI Tools C++ Classes" + +warninglimit = 0 diff --git a/src/designer/src/uitools/doc/src/qtuitools-index.qdoc b/src/designer/src/uitools/doc/src/qtuitools-index.qdoc index db73d8ac98..a63de0e50a 100644 --- a/src/designer/src/uitools/doc/src/qtuitools-index.qdoc +++ b/src/designer/src/uitools/doc/src/qtuitools-index.qdoc @@ -57,50 +57,11 @@ \section1 Licenses and Attributions Qt UI Tools is available under commercial licenses from \l{The Qt Company}. - Since Qt 5.11, it is also available under the BSD 3-Clause - "New" or "Revised" License: - - \code -Copyright (C) 2018 The Qt Company Ltd. - -Commercial License Usage -Licensees holding valid commercial Qt licenses may use this file in -accordance with the commercial license agreement provided with the -Software or, alternatively, in accordance with the terms contained in -a written agreement between you and The Qt Company. For licensing terms -and conditions see https://www.qt.io/terms-conditions. For further -information use the contact form at https://www.qt.io/contact-us. - -BSD License Usage -Alternatively, you may use this file under the terms of the BSD license -as follows: - -"Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of The Qt Company Ltd nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." - \endcode + In addition, it is available under free software licenses. Since Qt 6.0, + these free software licenses are + \l{GNU Lesser General Public License, version 3}, or + the \l{GNU General Public License, version 2}. + See \l{Qt Licensing} for further details. \section1 API Reference These are links to the API reference materials. diff --git a/src/designer/src/uitools/doc/src/qtuitools-module.qdoc b/src/designer/src/uitools/doc/src/qtuitools-module.qdoc index 2820ac4754..b65bd918ee 100644 --- a/src/designer/src/uitools/doc/src/qtuitools-module.qdoc +++ b/src/designer/src/uitools/doc/src/qtuitools-module.qdoc @@ -30,6 +30,7 @@ \title Qt UI Tools C++ Classes \since 4.1 \ingroup modules + \qtcmakepackage UiTools \qtvariable uitools \brief Provides classes to handle forms created with Qt Designer. diff --git a/src/designer/src/uitools/qtuitoolsglobal.h b/src/designer/src/uitools/qtuitoolsglobal.h new file mode 100644 index 0000000000..40827b3ab0 --- /dev/null +++ b/src/designer/src/uitools/qtuitoolsglobal.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt UI Tools library of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTUITOOLSGLOBAL_H +#define QTUITOOLSGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_UITOOLS_LIB) +# define Q_UITOOLS_EXPORT Q_DECL_EXPORT +# else +# define Q_UITOOLS_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_UITOOLS_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QTUITOOLSGLOBAL_H + diff --git a/src/designer/src/uitools/quiloader.cpp b/src/designer/src/uitools/quiloader.cpp index e5f157fb1a..e0ba98a1e0 100644 --- a/src/designer/src/uitools/quiloader.cpp +++ b/src/designer/src/uitools/quiloader.cpp @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Qt Designer of the Qt Toolkit. +** This file is part of the Qt UI Tools library of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -59,16 +48,9 @@ #include #include -#include -#include -#include -#include #include -#include -#include #include #include -#include #include #include #include @@ -77,6 +59,15 @@ #include #include +#include +#include + +#include +#include +#include +#include +#include + QT_BEGIN_NAMESPACE typedef QMap widget_map; @@ -96,7 +87,10 @@ QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s) QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s) { - in >> s.m_qualifier >> s.m_value; + QByteArray qualifier, value; + in >> qualifier >> value; + s.setQualifier(qualifier); + s.setValue(value); return in; } #endif // QT_NO_DATASTREAM @@ -242,7 +236,7 @@ class TranslationWatcher: public QObject bool eventFilter(QObject *o, QEvent *event) override { if (event->type() == QEvent::LanguageChange) { - const QList &dynamicPropertyNames = o->dynamicPropertyNames(); + const auto &dynamicPropertyNames = o->dynamicPropertyNames(); for (const QByteArray &prop : dynamicPropertyNames) { if (prop.startsWith(PROP_GENERIC_PREFIX)) { const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); @@ -438,7 +432,7 @@ void FormBuilderPrivate::applyProperties(QObject *o, const QList & if (!m_trwatch) m_trwatch = new TranslationWatcher(o, m_class, m_idBased); - if (properties.empty()) + if (properties.isEmpty()) return; // Unlike string item roles, string properties are not loaded via the textBuilder @@ -659,7 +653,6 @@ QUiLoader::QUiLoader(QObject *parent) static int metaTypeId = 0; if (!metaTypeId) { metaTypeId = qRegisterMetaType("QUiTranslatableStringValue"); - qRegisterMetaTypeStreamOperators("QUiTranslatableStringValue"); } #endif // QT_NO_DATASTREAM d->builder.loader = this; diff --git a/src/designer/src/uitools/quiloader.h b/src/designer/src/uitools/quiloader.h index 82a01210b4..7d632ab0b8 100644 --- a/src/designer/src/uitools/quiloader.h +++ b/src/designer/src/uitools/quiloader.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Qt Designer of the Qt Toolkit. +** This file is part of the Qt UI Tools library of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -51,6 +40,7 @@ #ifndef QUILOADER_H #define QUILOADER_H +#include #include #include @@ -65,7 +55,7 @@ class QIODevice; class QDir; class QUiLoaderPrivate; -class QUiLoader : public QObject +class Q_UITOOLS_EXPORT QUiLoader : public QObject { Q_OBJECT public: diff --git a/src/designer/src/uitools/quiloader_p.h b/src/designer/src/uitools/quiloader_p.h index 0a6907a549..0febc88c2e 100644 --- a/src/designer/src/uitools/quiloader_p.h +++ b/src/designer/src/uitools/quiloader_p.h @@ -1,11 +1,11 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Qt Designer of the Qt Toolkit. +** This file is part of the Qt UI Tools library of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:BSD$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the @@ -14,35 +14,24 @@ ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -62,6 +51,7 @@ // We mean it. // +#include #include #include @@ -79,7 +69,7 @@ QT_FORWARD_DECLARE_CLASS(QDataStream) QT_BEGIN_NAMESPACE -class QUiTranslatableStringValue +class Q_UITOOLS_EXPORT QUiTranslatableStringValue { public: QByteArray value() const { return m_value; } @@ -90,12 +80,15 @@ class QUiTranslatableStringValue QString translate(const QByteArray &className, bool idBased) const; private: - friend QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); - QByteArray m_value; QByteArray m_qualifier; // Comment or ID for id-based tr(). }; +#ifndef QT_NO_DATASTREAM +Q_UITOOLS_EXPORT QDataStream &operator<<(QDataStream &out, const QUiTranslatableStringValue &s); +Q_UITOOLS_EXPORT QDataStream &operator>>(QDataStream &in, QUiTranslatableStringValue &s); +#endif // QT_NO_DATASTREAM + struct QUiItemRolePair { int realRole; int shadowRole; @@ -106,7 +99,7 @@ namespace QFormInternal { #endif -extern const QUiItemRolePair qUiItemRoles[]; +extern const Q_UITOOLS_EXPORT QUiItemRolePair qUiItemRoles[]; #ifdef QFORMINTERNAL_NAMESPACE } diff --git a/src/designer/src/uitools/uitools.pro b/src/designer/src/uitools/uitools.pro deleted file mode 100644 index 8a71fa8b1b..0000000000 --- a/src/designer/src/uitools/uitools.pro +++ /dev/null @@ -1,20 +0,0 @@ -TARGET = QtUiTools -CONFIG += static - -include(../lib/uilib/uilib.pri) - -QMAKE_DOCS = $$PWD/doc/qtuitools.qdocconf - -HEADERS += quiloader.h -SOURCES += quiloader.cpp - -DEFINES += \ - QFORMINTERNAL_NAMESPACE \ - QT_DESIGNER_STATIC - -# QtUiPlugins end up in designer for historical reasons. However, if -# designer isn't actually built, we need to claim the plugin type here. -!qtBuildPart(tools): \ - MODULE_PLUGIN_TYPES = designer - -load(qt_module) diff --git a/src/distancefieldgenerator/CMakeLists.txt b/src/distancefieldgenerator/CMakeLists.txt new file mode 100644 index 0000000000..9be21f1998 --- /dev/null +++ b/src/distancefieldgenerator/CMakeLists.txt @@ -0,0 +1,36 @@ +# Generated from distancefieldgenerator.pro. + +##################################################################### +## qdistancefieldgenerator App: +##################################################################### + +qt_internal_add_app(qdistancefieldgenerator + SOURCES + distancefieldmodel.cpp distancefieldmodel.h + distancefieldmodelworker.cpp distancefieldmodelworker.h + main.cpp + mainwindow.cpp mainwindow.h mainwindow.ui + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + QT_NO_FOREACH + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::QuickPrivate + Qt::Widgets + ENABLE_AUTOGEN_TOOLS + uic +) +set_target_properties(qdistancefieldgenerator PROPERTIES + QT_TARGET_DESCRIPTION "Qt Distance Field Generator" +) + +#### Keys ignored in scope 1:.:.:distancefieldgenerator.pro:: +# QT_FOR_CONFIG = "tools-private" +# _REQUIREMENTS = "qtConfig(distancefieldgenerator)" +qt_internal_add_docs(qdistancefieldgenerator + doc/qtdistancefieldgenerator.qdocconf +) + diff --git a/src/distancefieldgenerator/distancefieldgenerator.pro b/src/distancefieldgenerator/distancefieldgenerator.pro deleted file mode 100644 index c37ca68886..0000000000 --- a/src/distancefieldgenerator/distancefieldgenerator.pro +++ /dev/null @@ -1,26 +0,0 @@ -TARGET = qdistancefieldgenerator - -QT += gui widgets gui-private core-private quick-private - -SOURCES += \ - main.cpp \ - mainwindow.cpp \ - distancefieldmodel.cpp \ - distancefieldmodelworker.cpp - -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII -DEFINES += QT_NO_FOREACH - -FORMS += \ - mainwindow.ui - -HEADERS += \ - mainwindow.h \ - distancefieldmodel.h \ - distancefieldmodelworker.h - -QMAKE_DOCS = $$PWD/doc/qtdistancefieldgenerator.qdocconf - -QMAKE_TARGET_DESCRIPTION = "Qt Distance Field Generator" - -load(qt_app) diff --git a/src/distancefieldgenerator/distancefieldmodel.cpp b/src/distancefieldgenerator/distancefieldmodel.cpp index aebd861408..e529e65ba0 100644 --- a/src/distancefieldgenerator/distancefieldmodel.cpp +++ b/src/distancefieldgenerator/distancefieldmodel.cpp @@ -183,7 +183,7 @@ void DistanceFieldModel::addDistanceField(const QImage &distanceField, if (ucs4 != 0) { UnicodeRange range = unicodeRangeForUcs4(ucs4); - m_glyphsPerUnicodeRange.insertMulti(range, glyphId); + m_glyphsPerUnicodeRange.insert(range, glyphId); m_glyphsPerUcs4.insert(ucs4, glyphId); } diff --git a/src/distancefieldgenerator/distancefieldmodel.h b/src/distancefieldgenerator/distancefieldmodel.h index b866e5e6a2..1740213012 100644 --- a/src/distancefieldgenerator/distancefieldmodel.h +++ b/src/distancefieldgenerator/distancefieldmodel.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -223,8 +224,8 @@ private slots: DistanceFieldModelWorker *m_worker; QScopedPointer m_workerThread; quint16 m_glyphCount; - QVector m_distanceFields; - QVector m_paths; + QList m_distanceFields; + QList m_paths; QMultiHash m_glyphsPerUnicodeRange; QHash m_glyphsPerUcs4; bool m_doubleGlyphResolution; diff --git a/src/distancefieldgenerator/distancefieldmodelworker.cpp b/src/distancefieldgenerator/distancefieldmodelworker.cpp index 373cb05abb..b76f3b7071 100644 --- a/src/distancefieldgenerator/distancefieldmodelworker.cpp +++ b/src/distancefieldgenerator/distancefieldmodelworker.cpp @@ -129,7 +129,7 @@ static void readCmapSubtable(DistanceFieldModelWorker *worker, const QByteArray return; } - const void *end = cmap.constData() + tableOffset + subtable->length; + const void *end = cmap.constData() + tableOffset + length; worker->readCmapSubtable(subtable, end); } @@ -148,7 +148,7 @@ void DistanceFieldModelWorker::readCmapSubtable(const CmapSubtable4 *subtable, c const qint16 *idDeltas = reinterpret_cast(startCodes + segCount); const quint16 *idRangeOffsets = reinterpret_cast(idDeltas + segCount); const quint16 *glyphIdArray = idRangeOffsets + segCount; - if (glyphIdArray >= end) { + if (glyphIdArray > end) { emit error(tr("End of cmap table reached when parsing subtable format '4'")); return; } diff --git a/src/distancefieldgenerator/doc/qtdistancefieldgenerator.qdocconf b/src/distancefieldgenerator/doc/qtdistancefieldgenerator.qdocconf index 070d4eebb8..4e4e282a0e 100644 --- a/src/distancefieldgenerator/doc/qtdistancefieldgenerator.qdocconf +++ b/src/distancefieldgenerator/doc/qtdistancefieldgenerator.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtDistanceFieldGenerator description = Qt Distance Field Generator Manual @@ -26,3 +27,5 @@ imagedirs = images depends += qtdoc qtqml qtquick qtcore qtgui qmake navigation.landingpage = "Qt Distance Field Generator Manual" + +warninglimit = 0 diff --git a/src/distancefieldgenerator/main.cpp b/src/distancefieldgenerator/main.cpp index 53ada87ac0..8fdcaba30c 100644 --- a/src/distancefieldgenerator/main.cpp +++ b/src/distancefieldgenerator/main.cpp @@ -35,7 +35,6 @@ QT_USE_NAMESPACE int main(int argc, char **argv) { - QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); app.setOrganizationName(QStringLiteral("QtProject")); app.setApplicationName(QStringLiteral("Qt Distance Field Generator")); diff --git a/src/distancefieldgenerator/mainwindow.cpp b/src/distancefieldgenerator/mainwindow.cpp index 763aeaa6bf..41516bd495 100644 --- a/src/distancefieldgenerator/mainwindow.cpp +++ b/src/distancefieldgenerator/mainwindow.cpp @@ -52,7 +52,10 @@ QT_BEGIN_NAMESPACE static void openHelp() { - QDesktopServices::openUrl(QUrl(QLatin1String("http://doc.qt.io/qt-5/qtdistancefieldgenerator-index.html"))); + const int qtVersion = QT_VERSION; + QString url; + QTextStream(&url) << "https://doc.qt.io/qt-" << (qtVersion >> 16) << "/qtdistancefieldgenerator-index.html"; + QDesktopServices::openUrl(QUrl(url)); } MainWindow::MainWindow(QWidget *parent) @@ -417,10 +420,20 @@ QByteArray MainWindow::createSfntTable() header.minorVersion = 12; header.pixelSize = qToBigEndian(quint16(qRound(m_model->pixelSize()))); + const quint8 padding = 2; + qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); + const int radius = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) + / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); + quint32 textureSize = ui->sbMaximumTextureSize->value(); + + // Since we are using a single area allocator that spans all textures, we need + // to split the textures one row before the actual maximum size, otherwise + // glyphs that fall on the edge between two textures will expand the texture + // they are assigned to, and this will end up being larger than the max. + textureSize -= quint32(qCeil(m_model->pixelSize() * scaleFactor) + radius * 2 + padding * 2); header.textureSize = qToBigEndian(textureSize); - const quint8 padding = 2; header.padding = padding; header.flags = m_model->doubleGlyphResolution() ? 1 : 0; header.numGlyphs = qToBigEndian(quint32(list.size())); @@ -428,8 +441,7 @@ QByteArray MainWindow::createSfntTable() sizeof(QtdfHeader)); // Maximum height allocator to find optimal number of textures - QRect allocatedArea; - QVector allocatedAreaPerTexture; + QList allocatedAreaPerTexture; struct GlyphData { QSGDistanceFieldGlyphCache::TexCoord texCoord; @@ -437,19 +449,15 @@ QByteArray MainWindow::createSfntTable() QSize glyphSize; int textureIndex; }; - QVector glyphDatas; + QList glyphDatas; glyphDatas.resize(m_model->rowCount()); int textureCount = 0; { - qreal scaleFactor = qreal(1) / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); QTransform scaleDown; scaleDown.scale(scaleFactor, scaleFactor); - const int radius = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) - / QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution()); - { bool foundOptimalSize = false; while (!foundOptimalSize) { @@ -466,6 +474,7 @@ QByteArray MainWindow::createSfntTable() glyphData.boundingRect = scaleDown.mapRect(path.boundingRect()); int glyphWidth = qCeil(glyphData.boundingRect.width()) + radius * 2; int glyphHeight = qCeil(glyphData.boundingRect.height()) + radius * 2; + glyphData.glyphSize = QSize(glyphWidth + padding * 2, glyphHeight + padding * 2); if (glyphData.glyphSize.width() > qint32(textureSize) @@ -482,15 +491,14 @@ QByteArray MainWindow::createSfntTable() break; glyphData.textureIndex = rect.y() / textureSize; - if (glyphData.textureIndex >= allocatedAreaPerTexture.size()) - allocatedAreaPerTexture.resize(glyphData.textureIndex + 1); + while (glyphData.textureIndex >= allocatedAreaPerTexture.size()) + allocatedAreaPerTexture.append(QRect(0, 0, 1, 1)); + allocatedAreaPerTexture[glyphData.textureIndex] |= QRect(rect.x(), rect.y() % textureSize, rect.width(), rect.height()); - allocatedArea |= rect; - glyphData.texCoord.xMargin = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) / qreal(QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution())); glyphData.texCoord.yMargin = QT_DISTANCEFIELD_RADIUS(m_model->doubleGlyphResolution()) / qreal(QT_DISTANCEFIELD_SCALE(m_model->doubleGlyphResolution())); glyphData.texCoord.x = rect.x() + padding; @@ -508,7 +516,7 @@ QByteArray MainWindow::createSfntTable() } } - QVector textures; + QList textures; textures.resize(textureCount); for (int textureIndex = 0; textureIndex < textureCount; ++textureIndex) { @@ -546,7 +554,7 @@ QByteArray MainWindow::createSfntTable() glyphRecord.boundingRectY = qToBigEndian(TO_FIXED_POINT(glyphData.boundingRect.y())); glyphRecord.boundingRectWidth = qToBigEndian(TO_FIXED_POINT(glyphData.boundingRect.width())); glyphRecord.boundingRectHeight = qToBigEndian(TO_FIXED_POINT(glyphData.boundingRect.height())); - glyphRecord.textureIndex = qToBigEndian(glyphData.textureIndex); + glyphRecord.textureIndex = qToBigEndian(quint16(glyphData.textureIndex)); buffer.write(reinterpret_cast(&glyphRecord), sizeof(QtdfGlyphRecord)); int expectedWidth = qCeil(glyphData.texCoord.width + glyphData.texCoord.xMargin * 2); @@ -688,18 +696,25 @@ void MainWindow::updateUnicodeRanges() this, &MainWindow::updateSelection); + QItemSelection selectedItems; + for (int i = 0; i < ui->lwUnicodeRanges->count(); ++i) { QListWidgetItem *item = ui->lwUnicodeRanges->item(i); - DistanceFieldModel::UnicodeRange unicodeRange = item->data(Qt::UserRole).value(); - QList glyphIndexes = m_model->glyphIndexesForUnicodeRange(unicodeRange); - for (glyph_t glyphIndex : glyphIndexes) { - QModelIndex index = m_model->index(glyphIndex); - ui->lvGlyphs->selectionModel()->select(index, item->isSelected() - ? QItemSelectionModel::Select - : QItemSelectionModel::Deselect); + if (item->isSelected()) { + DistanceFieldModel::UnicodeRange unicodeRange = item->data(Qt::UserRole).value(); + QList glyphIndexes = m_model->glyphIndexesForUnicodeRange(unicodeRange); + + for (glyph_t glyphIndex : glyphIndexes) { + QModelIndex index = m_model->index(glyphIndex); + selectedItems.select(index, index); + } } } + ui->lvGlyphs->selectionModel()->clearSelection(); + if (!selectedItems.isEmpty()) + ui->lvGlyphs->selectionModel()->select(selectedItems, QItemSelectionModel::Select); + connect(ui->lvGlyphs->selectionModel(), &QItemSelectionModel::selectionChanged, this, @@ -734,7 +749,7 @@ void MainWindow::selectString() tr("Select glyphs for string"), tr("String to parse:")); if (!s.isEmpty()) { - QVector ucs4String = s.toUcs4(); + QList ucs4String = s.toUcs4(); for (uint ucs4 : ucs4String) { glyph_t glyph = m_model->glyphIndexForUcs4(ucs4); if (glyph != 0) { diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt new file mode 100644 index 0000000000..d96a8abb34 --- /dev/null +++ b/src/global/CMakeLists.txt @@ -0,0 +1,18 @@ +# Generated from global.pro. + +##################################################################### +## Tools Module: +##################################################################### + +qt_internal_add_module(Tools + INTERNAL_MODULE + HEADER_MODULE + # special case begin + CONFIGURE_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../configure.cmake" + # special case end + MODULE_INTERFACE_NAME Tools # Specify the 'Tools' name explicitly to avoid warning + # related to the expected name of internal module. +) + +#### Keys ignored in scope 1:.:.:global.pro:: +# MODULE = "tools" diff --git a/src/kmap2qmap/CMakeLists.txt b/src/kmap2qmap/CMakeLists.txt new file mode 100644 index 0000000000..3dcf766415 --- /dev/null +++ b/src/kmap2qmap/CMakeLists.txt @@ -0,0 +1,19 @@ +# Generated from kmap2qmap.pro. + +##################################################################### +## kmap2qmap App: +##################################################################### + +qt_internal_add_app(kmap2qmap + SOURCES + main.cpp + PUBLIC_LIBRARIES + Qt::InputSupportPrivate +) +set_target_properties(kmap2qmap PROPERTIES + WIN32_EXECUTABLE FALSE +) + +#### Keys ignored in scope 1:.:.:kmap2qmap.pro:: +# QT_FOR_CONFIG = "tools-private" +# _REQUIREMENTS = "qtConfig(kmap2qmap)" diff --git a/src/kmap2qmap/kmap2qmap.pro b/src/kmap2qmap/kmap2qmap.pro deleted file mode 100644 index d08ec6bb4f..0000000000 --- a/src/kmap2qmap/kmap2qmap.pro +++ /dev/null @@ -1,6 +0,0 @@ -QT = core input_support-private -CONFIG += console - -SOURCES += main.cpp - -load(qt_app) diff --git a/src/kmap2qmap/main.cpp b/src/kmap2qmap/main.cpp index 0cff817c58..57cfdd9ff2 100644 --- a/src/kmap2qmap/main.cpp +++ b/src/kmap2qmap/main.cpp @@ -31,10 +31,9 @@ #include #include #include -#include #include -#include #include +#include #include #include @@ -410,8 +409,8 @@ class KeymapParser { int parseWarningCount() const { return m_warning_count; } private: - bool parseSymbol(const QByteArray &str, const QTextCodec *codec, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special); - bool parseCompose(const QByteArray &str, const QTextCodec *codec, quint16 &unicode); + bool parseSymbol(const QByteArray &str, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special); + bool parseCompose(const QByteArray &str, QStringDecoder &codec, quint16 &unicode); bool parseModifier(const QByteArray &str, quint8 &modifier); void updateMapping(quint16 keycode = 0, quint8 modifiers = 0, quint16 unicode = 0xffff, quint32 qtcode = Qt::Key_unknown, quint8 flags = 0, quint16 = 0); @@ -441,7 +440,7 @@ int main(int argc, char **argv) return 1; } - QVector kmaps(argc - header - 2); + QList kmaps(argc - header - 2); for (int i = 0; i < kmaps.size(); ++i) { kmaps [i] = new QFile(QString::fromLocal8Bit(argv[i + 1 + header])); @@ -496,27 +495,27 @@ bool KeymapParser::generateHeader(QFile *f) { QTextStream ts(f); - ts << "#ifndef QEVDEVKEYBOARDHANDLER_DEFAULTMAP_H" << endl; - ts << "#define QEVDEVKEYBOARDHANDLER_DEFAULTMAP_H" << endl << endl; + ts << "#ifndef QEVDEVKEYBOARDHANDLER_DEFAULTMAP_H" << Qt::endl; + ts << "#define QEVDEVKEYBOARDHANDLER_DEFAULTMAP_H" << Qt::endl << Qt::endl; - ts << "const QEvdevKeyboardMap::Mapping QEvdevKeyboardHandler::s_keymap_default[] = {" << endl; + ts << "const QEvdevKeyboardMap::Mapping QEvdevKeyboardHandler::s_keymap_default[] = {" << Qt::endl; for (int i = 0; i < m_keymap.size(); ++i) { const QEvdevKeyboardMap::Mapping &m = m_keymap.at(i); ts << QString::asprintf(" { %3d, 0x%04x, 0x%08x, 0x%02x, 0x%02x, 0x%04x },\n", m.keycode, m.unicode, m.qtcode, m.modifiers, m.flags, m.special); } - ts << "};" << endl << endl; + ts << "};" << Qt::endl << Qt::endl; - ts << "const QEvdevKeyboardMap::Composing QEvdevKeyboardHandler::s_keycompose_default[] = {" << endl; + ts << "const QEvdevKeyboardMap::Composing QEvdevKeyboardHandler::s_keycompose_default[] = {" << Qt::endl; for (int i = 0; i < m_keycompose.size(); ++i) { const QEvdevKeyboardMap::Composing &c = m_keycompose.at(i); ts << QString::asprintf(" { 0x%04x, 0x%04x, 0x%04x },\n", c.first, c.second, c.result); } - ts << "};" << endl << endl; + ts << "};" << Qt::endl << Qt::endl; - ts << "#endif" << endl; + ts << "#endif" << Qt::endl; return (ts.status() == QTextStream::Ok); } @@ -581,7 +580,7 @@ bool KeymapParser::parseKmap(QFile *f) QByteArray line; int lineno = 0; QList keymaps; - QTextCodec *codec = QTextCodec::codecForName("iso8859-1"); + auto codec = QStringDecoder(QStringDecoder::Latin1); for (int i = 0; i <= 256; ++i) keymaps << i; @@ -659,13 +658,13 @@ bool KeymapParser::parseKmap(QFile *f) } else if (tokens[0] == "charset") { if (tokens.count() == 2) { - codec = QTextCodec::codecForName(tokens[1]); - if (!codec) { + codec = QStringDecoder(tokens[1]); + if (!codec.isValid()) { parseWarning("could not parse codec definition"); - codec = QTextCodec::codecForName("iso8859-1"); + codec = QStringDecoder(QStringDecoder::Latin1); } } else - parseWarning("codec doesn't habe exactly one argument"); + parseWarning("codec doesn't have exactly one argument"); } else if (tokens[0] == "strings") { // simply ignore those - they have no meaning for us @@ -726,7 +725,7 @@ bool KeymapParser::parseKmap(QFile *f) quint16 unicode; quint16 special; quint8 flags; - if (!parseSymbol(tokens[i + kcpos + 3], codec, unicode, qtcode, flags, special)) { + if (!parseSymbol(tokens[i + kcpos + 3], unicode, qtcode, flags, special)) { parseWarning((QByteArray("symbol could not be parsed: ") + tokens[i + kcpos + 3]).constData()); break; } @@ -830,13 +829,13 @@ bool KeymapParser::parseModifier(const QByteArray &str, quint8 &modifier) } -bool KeymapParser::parseCompose(const QByteArray &str, const QTextCodec *codec, quint16 &unicode) +bool KeymapParser::parseCompose(const QByteArray &str, QStringDecoder &codec, quint16 &unicode) { if (str == "'\\''") { unicode = '\''; return true; } else if (str.length() == 3 && str.startsWith('\'') && str.endsWith('\'')) { - QString temp = codec->toUnicode(str.constData() + 1, str.length() - 2); + QString temp = codec(str.constData() + 1, str.length() - 2); if (temp.length() != 1) return false; unicode = temp[0].unicode(); @@ -848,7 +847,7 @@ bool KeymapParser::parseCompose(const QByteArray &str, const QTextCodec *codec, char c[2]; c[0] = char(code); c[1] = 0; - QString temp = codec->toUnicode(c); + QString temp = codec(c, 2); if (temp.length() != 1) return false; unicode = temp[0].unicode(); @@ -857,7 +856,7 @@ bool KeymapParser::parseCompose(const QByteArray &str, const QTextCodec *codec, } -bool KeymapParser::parseSymbol(const QByteArray &str, const QTextCodec * /*codec*/, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special) +bool KeymapParser::parseSymbol(const QByteArray &str, quint16 &unicode, quint32 &qtcode, quint8 &flags, quint16 &special) { flags = (str[0] == '+') ? QEvdevKeyboardMap::IsLetter : 0; QByteArray sym = (flags & QEvdevKeyboardMap::IsLetter) ? str.right(str.length() - 1) : str; diff --git a/src/linguist/CMakeLists.txt b/src/linguist/CMakeLists.txt new file mode 100644 index 0000000000..16ff9f5595 --- /dev/null +++ b/src/linguist/CMakeLists.txt @@ -0,0 +1,24 @@ +# Generated from linguist.pro. + + +qt_exclude_tool_directories_from_default_target( + linguist +) + +if(NOT QT_FEATURE_linguist) + return() +endif() +add_subdirectory(lconvert) +add_subdirectory(lprodump) +add_subdirectory(lrelease) +add_subdirectory(lrelease-pro) +add_subdirectory(lupdate) +add_subdirectory(lupdate-pro) +if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png) + add_subdirectory(linguist) +endif() + +# special case begin +# Create a fake module that would emulate the Qt5::LinguistTools CMake Config package +qt_internal_add_module(Linguist NO_MODULE_HEADERS HEADER_MODULE) +# special case end diff --git a/src/linguist/Qt5LinguistToolsConfig.cmake.in b/src/linguist/Qt5LinguistToolsConfig.cmake.in deleted file mode 100644 index 4318b16fa0..0000000000 --- a/src/linguist/Qt5LinguistToolsConfig.cmake.in +++ /dev/null @@ -1,92 +0,0 @@ - -if (CMAKE_VERSION VERSION_LESS 2.8.3) - message(FATAL_ERROR \"Qt 5 requires at least CMake version 2.8.3\") -endif() - -!!IF !isEmpty(CMAKE_USR_MOVE_WORKAROUND) -!!IF !isEmpty(CMAKE_LIB_DIR_IS_ABSOLUTE) -set(_qt5_linguisttools_install_prefix \"$$[QT_INSTALL_PREFIX]\") -!!ELSE -get_filename_component(_IMPORT_PREFIX \"${CMAKE_CURRENT_LIST_FILE}\" PATH) -# Use original install prefix when loaded through a -# cross-prefix symbolic link such as /lib -> /usr/lib. -get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH) -get_filename_component(_realOrig \"$$CMAKE_INSTALL_LIBS_DIR/cmake/Qt5LinguistTools\" REALPATH) -if(_realCurr STREQUAL _realOrig) - get_filename_component(_qt5_linguisttools_install_prefix \"$$CMAKE_INSTALL_LIBS_DIR/$${CMAKE_RELATIVE_INSTALL_LIBS_DIR}\" ABSOLUTE) -else() - get_filename_component(_qt5_linguisttools_install_prefix \"${CMAKE_CURRENT_LIST_DIR}/$${CMAKE_RELATIVE_INSTALL_DIR}\" ABSOLUTE) -endif() -unset(_realOrig) -unset(_realCurr) -unset(_IMPORT_PREFIX) -!!ENDIF -!!ELIF isEmpty(CMAKE_LIB_DIR_IS_ABSOLUTE) -get_filename_component(_qt5_linguisttools_install_prefix \"${CMAKE_CURRENT_LIST_DIR}/$${CMAKE_RELATIVE_INSTALL_DIR}\" ABSOLUTE) -!!ELSE -set(_qt5_linguisttools_install_prefix \"$$[QT_INSTALL_PREFIX]\") -!!ENDIF - -macro(_qt5_LinguistTools_check_file_exists file) - if(NOT EXISTS \"${file}\" ) - message(FATAL_ERROR \"The package \\\"Qt5LinguistTools\\\" references the file - \\\"${file}\\\" -but this file does not exist. Possible reasons include: -* The file was deleted, renamed, or moved to another location. -* An install or uninstall procedure did not complete successfully. -* The installation package was faulty and contained - \\\"${CMAKE_CURRENT_LIST_FILE}\\\" -but not all the files it references. -\") - endif() -endmacro() - -if (NOT TARGET Qt5::lrelease) - add_executable(Qt5::lrelease IMPORTED) - -!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) - set(imported_location \"${_qt5_linguisttools_install_prefix}/$${CMAKE_BIN_DIR}lrelease$$CMAKE_BIN_SUFFIX\") -!!ELSE - set(imported_location \"$${CMAKE_BIN_DIR}lrelease$$CMAKE_BIN_SUFFIX\") -!!ENDIF - _qt5_LinguistTools_check_file_exists(${imported_location}) - - set_target_properties(Qt5::lrelease PROPERTIES - IMPORTED_LOCATION ${imported_location} - ) -endif() - -if (NOT TARGET Qt5::lupdate) - add_executable(Qt5::lupdate IMPORTED) - -!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) - set(imported_location \"${_qt5_linguisttools_install_prefix}/$${CMAKE_BIN_DIR}lupdate$$CMAKE_BIN_SUFFIX\") -!!ELSE - set(imported_location \"$${CMAKE_BIN_DIR}lupdate$$CMAKE_BIN_SUFFIX\") -!!ENDIF - _qt5_LinguistTools_check_file_exists(${imported_location}) - - set_target_properties(Qt5::lupdate PROPERTIES - IMPORTED_LOCATION ${imported_location} - ) -endif() - -if (NOT TARGET Qt5::lconvert) - add_executable(Qt5::lconvert IMPORTED) - -!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) - set(imported_location \"${_qt5_linguisttools_install_prefix}/$${CMAKE_BIN_DIR}lconvert$$CMAKE_BIN_SUFFIX\") -!!ELSE - set(imported_location \"$${CMAKE_BIN_DIR}lconvert$$CMAKE_BIN_SUFFIX\") -!!ENDIF - _qt5_LinguistTools_check_file_exists(${imported_location}) - - set_target_properties(Qt5::lconvert PROPERTIES - IMPORTED_LOCATION ${imported_location} - ) -endif() - -set(Qt5_LRELEASE_EXECUTABLE Qt5::lrelease) -set(Qt5_LUPDATE_EXECUTABLE Qt5::lupdate) - -include(\"${CMAKE_CURRENT_LIST_DIR}/Qt5LinguistToolsMacros.cmake\") diff --git a/src/linguist/Qt5LinguistToolsMacros.cmake b/src/linguist/Qt6LinguistToolsMacros.cmake similarity index 66% rename from src/linguist/Qt5LinguistToolsMacros.cmake rename to src/linguist/Qt6LinguistToolsMacros.cmake index 5c357a152d..ec08504ac2 100644 --- a/src/linguist/Qt5LinguistToolsMacros.cmake +++ b/src/linguist/Qt6LinguistToolsMacros.cmake @@ -1,4 +1,5 @@ #============================================================================= +# Copyright (C) 2020 The Qt Company Ltd. # Copyright 2005-2011 Kitware, Inc. # All rights reserved. # @@ -32,7 +33,7 @@ include(CMakeParseArguments) -function(QT5_CREATE_TRANSLATION _qm_files) +function(qt6_create_translation _qm_files) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) @@ -41,6 +42,17 @@ function(QT5_CREATE_TRANSLATION _qm_files) set(_lupdate_files ${_LUPDATE_UNPARSED_ARGUMENTS}) set(_lupdate_options ${_LUPDATE_OPTIONS}) + list(FIND _lupdate_options "-extensions" _extensions_index) + if(_extensions_index GREATER -1) + math(EXPR _extensions_index "${_extensions_index} + 1") + list(GET _lupdate_options ${_extensions_index} _extensions_list) + string(REPLACE "," ";" _extensions_list "${_extensions_list}") + list(TRANSFORM _extensions_list STRIP) + list(TRANSFORM _extensions_list REPLACE "^\." "") + list(TRANSFORM _extensions_list PREPEND "*.") + else() + set(_extensions_list "*.java;*.jui;*.ui;*.c;*.c++;*.cc;*.cpp;*.cxx;*.ch;*.h;*.h++;*.hh;*.hpp;*.hxx;*.js;*.qs;*.qml;*.qrc") + endif() set(_my_sources) set(_my_tsfiles) foreach(_file ${_lupdate_files}) @@ -56,11 +68,19 @@ function(QT5_CREATE_TRANSLATION _qm_files) if(_my_sources) # make a list file to call lupdate on, so we don't make our commands too # long for some systems - get_filename_component(_ts_name ${_ts_file} NAME_WE) + get_filename_component(_ts_name ${_ts_file} NAME) set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file") set(_lst_file_srcs) + set(_dependencies) foreach(_lst_file_src ${_my_sources}) set(_lst_file_srcs "${_lst_file_src}\n${_lst_file_srcs}") + if(IS_DIRECTORY ${_lst_file_src}) + list(TRANSFORM _extensions_list PREPEND "${_lst_file_src}/" OUTPUT_VARIABLE _directory_glob) + file(GLOB_RECURSE _directory_contents CONFIGURE_DEPENDS ${_directory_glob}) + list(APPEND _dependencies ${_directory_contents}) + else() + list(APPEND _dependencies "${_lst_file_src}") + endif() endforeach() get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES) @@ -72,17 +92,28 @@ function(QT5_CREATE_TRANSLATION _qm_files) file(WRITE ${_ts_lst_file} "${_lst_file_srcs}") endif() add_custom_command(OUTPUT ${_ts_file} - COMMAND ${Qt5_LUPDATE_EXECUTABLE} + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lupdate ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file} - DEPENDS ${_my_sources} - BYPRODUCTS ${_ts_lst_file} VERBATIM) + DEPENDS ${_dependencies} + VERBATIM) endforeach() - qt5_add_translation(${_qm_files} ${_my_tsfiles}) + qt6_add_translation(${_qm_files} ${_my_tsfiles}) set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() +if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) + function(qt_create_translation _qm_files) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 5) + qt5_create_translation("${_qm_files}" ${ARGN}) + elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_create_translation("${_qm_files}" ${ARGN}) + endif() + set("${_qm_files}" "${${_qm_files}}" PARENT_SCOPE) + endfunction() +endif() + -function(QT5_ADD_TRANSLATION _qm_files) +function(qt6_add_translation _qm_files) set(options) set(oneValueArgs) set(multiValueArgs OPTIONS) @@ -104,7 +135,7 @@ function(QT5_ADD_TRANSLATION _qm_files) endif() add_custom_command(OUTPUT ${qm} - COMMAND ${Qt5_LRELEASE_EXECUTABLE} + COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lrelease ARGS ${_LRELEASE_OPTIONS} ${_abs_FILE} -qm ${qm} DEPENDS ${_abs_FILE} VERBATIM ) @@ -112,3 +143,14 @@ function(QT5_ADD_TRANSLATION _qm_files) endforeach() set(${_qm_files} ${${_qm_files}} PARENT_SCOPE) endfunction() + +if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) + function(qt_add_translation _qm_files) + if(QT_DEFAULT_MAJOR_VERSION EQUAL 5) + qt5_add_translation("${_qm_files}" ${ARGN}) + elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6) + qt6_add_translation("${_qm_files}" ${ARGN}) + endif() + set("${_qm_files}" "${${_qm_files}}" PARENT_SCOPE) + endfunction() +endif() diff --git a/src/linguist/lconvert/CMakeLists.txt b/src/linguist/lconvert/CMakeLists.txt new file mode 100644 index 0000000000..aeb545bd76 --- /dev/null +++ b/src/linguist/lconvert/CMakeLists.txt @@ -0,0 +1,33 @@ +# Generated from lconvert.pro. + +##################################################################### +## lconvert Tool: +##################################################################### + +qt_get_tool_target_name(target_name lconvert) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Translation File Converter" + TOOLS_TARGET Linguist # special case + SOURCES + ../shared/numerus.cpp + ../shared/po.cpp + ../shared/qm.cpp + ../shared/qph.cpp + ../shared/translator.cpp ../shared/translator.h + ../shared/translatormessage.cpp ../shared/translatormessage.h + ../shared/ts.cpp + ../shared/xliff.cpp + ../shared/xmlparser.cpp ../shared/xmlparser.h + main.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared + PUBLIC_LIBRARIES + Qt::CorePrivate +) + +#### Keys ignored in scope 1:.:.:lconvert.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Translation File Converter" +# _OPTION = "host_build" diff --git a/src/linguist/lconvert/lconvert.pro b/src/linguist/lconvert/lconvert.pro deleted file mode 100644 index d1e49bc204..0000000000 --- a/src/linguist/lconvert/lconvert.pro +++ /dev/null @@ -1,10 +0,0 @@ -option(host_build) -QT = core-private -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - -SOURCES += main.cpp - -include(../shared/formats.pri) - -QMAKE_TARGET_DESCRIPTION = "Qt Translation File Converter" -load(qt_tool) diff --git a/src/linguist/lconvert/main.cpp b/src/linguist/lconvert/main.cpp index 2dc07db514..816453bb40 100644 --- a/src/linguist/lconvert/main.cpp +++ b/src/linguist/lconvert/main.cpp @@ -49,7 +49,7 @@ static int usage(const QStringList &args) QString loaders; QString line(QLatin1String(" %1 - %2\n")); - foreach (Translator::FileFormat format, Translator::registeredFileFormats()) + for (const Translator::FileFormat &format : qAsConst(Translator::registeredFileFormats())) loaders += line.arg(format.extension, -5).arg(format.description()); std::cout << qPrintable(LC::tr("\nUsage:\n" @@ -128,7 +128,7 @@ int main(int argc, char *argv[]) QTranslator translator; QTranslator qtTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) { app.installTranslator(&translator); diff --git a/src/linguist/linguist.pro b/src/linguist/linguist.pro deleted file mode 100644 index face6545f8..0000000000 --- a/src/linguist/linguist.pro +++ /dev/null @@ -1,58 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = \ - lconvert \ - lprodump \ - lrelease \ - lrelease-pro \ - lupdate \ - lupdate-pro -!no-png:qtHaveModule(widgets) { - QT_FOR_CONFIG += widgets - qtConfig(process):qtConfig(pushbutton):qtConfig(toolbutton) { - SUBDIRS += linguist - } -} - -qtNomakeTools( \ - linguist \ -) - -equals(QMAKE_HOST.os, Windows): CMAKE_BIN_SUFFIX = ".exe" - -load(cmake_functions) - -CMAKE_INSTALL_LIBS_DIR = $$cmakeTargetPath($$[QT_INSTALL_LIBS]) -contains(CMAKE_INSTALL_LIBS_DIR, ^(/usr)?/lib(64)?.*): CMAKE_USR_MOVE_WORKAROUND = $$CMAKE_INSTALL_LIBS_DIR - -CMAKE_LIB_DIR = $$cmakeRelativePath($$[QT_INSTALL_LIBS], $$[QT_INSTALL_PREFIX]) -!contains(CMAKE_LIB_DIR,"^\\.\\./.*") { - CMAKE_RELATIVE_INSTALL_LIBS_DIR = $$cmakeRelativePath($$[QT_INSTALL_PREFIX], $$[QT_INSTALL_LIBS]) - # We need to go up another two levels because the CMake files are - # installed in $${CMAKE_LIB_DIR}/cmake/Qt5$${CMAKE_MODULE_NAME} - CMAKE_RELATIVE_INSTALL_DIR = "$${CMAKE_RELATIVE_INSTALL_LIBS_DIR}../../" -} else { - CMAKE_LIB_DIR_IS_ABSOLUTE = True -} - -CMAKE_BIN_DIR = $$cmakeRelativePath($$[QT_HOST_BINS], $$[QT_INSTALL_PREFIX]) -contains(CMAKE_BIN_DIR, "^\\.\\./.*") { - CMAKE_BIN_DIR = $$[QT_HOST_BINS]/ - CMAKE_BIN_DIR_IS_ABSOLUTE = True -} - -load(qt_build_paths) - -cmake_linguist_config_file.input = $$PWD/Qt5LinguistToolsConfig.cmake.in -cmake_linguist_config_version_file.input = $$[QT_HOST_DATA/src]/mkspecs/features/data/cmake/Qt5ConfigVersion.cmake.in -cmake_linguist_macros_file.input = $$PWD/Qt5LinguistToolsMacros.cmake -CMAKE_PACKAGE_VERSION = $$MODULE_VERSION -cmake_linguist_config_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5LinguistTools/Qt5LinguistToolsConfig.cmake -cmake_linguist_config_version_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5LinguistTools/Qt5LinguistToolsConfigVersion.cmake -cmake_linguist_macros_file.output = $$MODULE_BASE_OUTDIR/lib/cmake/Qt5LinguistTools/Qt5LinguistToolsMacros.cmake -cmake_linguist_macros_file.CONFIG = verbatim -QMAKE_SUBSTITUTES += cmake_linguist_config_file cmake_linguist_config_version_file cmake_linguist_macros_file - -cmake_linguist_tools_files.files += $$cmake_linguist_config_file.output $$cmake_linguist_config_version_file.output $$cmake_linguist_macros_file.output -cmake_linguist_tools_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5LinguistTools -cmake_linguist_tools_files.CONFIG = no_check_exist -INSTALLS += cmake_linguist_tools_files diff --git a/src/linguist/linguist/CMakeLists.txt b/src/linguist/linguist/CMakeLists.txt new file mode 100644 index 0000000000..c6250fed8b --- /dev/null +++ b/src/linguist/linguist/CMakeLists.txt @@ -0,0 +1,177 @@ +# Generated from linguist.pro. + +##################################################################### +## linguist App: +##################################################################### + +qt_internal_add_app(linguist + SOURCES + ../shared/numerus.cpp + ../shared/po.cpp + ../shared/qm.cpp + ../shared/qph.cpp + ../shared/simtexth.cpp ../shared/simtexth.h + ../shared/translator.cpp ../shared/translator.h + ../shared/translatormessage.cpp ../shared/translatormessage.h + ../shared/ts.cpp + ../shared/xliff.cpp + ../shared/xmlparser.cpp ../shared/xmlparser.h + batchtranslation.ui + batchtranslationdialog.cpp batchtranslationdialog.h + errorsview.cpp errorsview.h + finddialog.cpp finddialog.h finddialog.ui + formpreviewview.cpp formpreviewview.h + globals.cpp globals.h + main.cpp + mainwindow.cpp mainwindow.h mainwindow.ui + messageeditor.cpp messageeditor.h + messageeditorwidgets.cpp messageeditorwidgets.h + messagehighlighter.cpp messagehighlighter.h + messagemodel.cpp messagemodel.h + phrase.cpp phrase.h + phrasebookbox.cpp phrasebookbox.h phrasebookbox.ui + phrasemodel.cpp phrasemodel.h + phraseview.cpp phraseview.h + printout.cpp printout.h + recentfiles.cpp recentfiles.h + sourcecodeview.cpp sourcecodeview.h + statistics.cpp statistics.h statistics.ui + translatedialog.cpp translatedialog.h translatedialog.ui + translationsettings.ui + translationsettingsdialog.cpp translationsettingsdialog.h + DEFINES + QFORMINTERNAL_NAMESPACE + QT_KEYWORDS + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::PrintSupport + Qt::UiToolsPrivate + Qt::Widgets + ENABLE_AUTOGEN_TOOLS + uic +) + +# Resources: +set(linguist_resource_files + "images/appicon.png" + "images/down.png" + "images/editdelete.png" + "images/icons/linguist-128-32.png" + "images/mac/accelerator.png" + "images/mac/book.png" + "images/mac/done.png" + "images/mac/doneandnext.png" + "images/mac/editcopy.png" + "images/mac/editcut.png" + "images/mac/editpaste.png" + "images/mac/fileopen.png" + "images/mac/filesave.png" + "images/mac/next.png" + "images/mac/nextunfinished.png" + "images/mac/phrase.png" + "images/mac/prev.png" + "images/mac/prevunfinished.png" + "images/mac/print.png" + "images/mac/punctuation.png" + "images/mac/redo.png" + "images/mac/searchfind.png" + "images/mac/surroundingwhitespace.png" + "images/mac/undo.png" + "images/mac/validateplacemarkers.png" + "images/mac/whatsthis.png" + "images/minus.png" + "images/plus.png" + "images/s_check_danger.png" + "images/s_check_empty.png" + "images/s_check_obsolete.png" + "images/s_check_off.png" + "images/s_check_on.png" + "images/s_check_warning.png" + "images/up.png" + "images/win/accelerator.png" + "images/win/book.png" + "images/win/done.png" + "images/win/doneandnext.png" + "images/win/editcopy.png" + "images/win/editcut.png" + "images/win/editpaste.png" + "images/win/fileopen.png" + "images/win/filesave.png" + "images/win/next.png" + "images/win/nextunfinished.png" + "images/win/phrase.png" + "images/win/prev.png" + "images/win/prevunfinished.png" + "images/win/print.png" + "images/win/punctuation.png" + "images/win/redo.png" + "images/win/searchfind.png" + "images/win/surroundingwhitespace.png" + "images/win/undo.png" + "images/win/validateplacemarkers.png" + "images/win/whatsthis.png" +) + +qt_internal_add_resource(linguist "linguist" + PREFIX + "/" + FILES + ${linguist_resource_files} +) + +set_target_properties(linguist PROPERTIES + QT_TARGET_DESCRIPTION "Qt Linguist" +) + +# special case begin +file(GLOB phrasebooks_files "${CMAKE_CURRENT_SOURCE_DIR}/../phrasebooks/*") +qt_install(FILES ${phrasebooks_files} DESTINATION "${INSTALL_DATADIR}/phrasebooks") +# special case end + +qt_internal_extend_target(linguist CONDITION QT_PRODUCT___contains___OpenSource._x_ + DEFINES + QT_OPENSOURCE +) + +if(WIN32) + set_target_properties(linguist PROPERTIES + QT_TARGET_RC_ICONS "${CMAKE_CURRENT_SOURCE_DIR}/linguist.ico" + ) +endif() + +if(WIN32) + set_target_properties(linguist PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}.0" + ) +endif() + +if(UNIX) + set_target_properties(linguist PROPERTIES + QT_TARGET_VERSION "${PROJECT_VERSION}" + ) +endif() + +if(APPLE) + set_target_properties(linguist PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist" + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "linguist.icns" + OUTPUT_NAME "Linguist" + ) + set_source_files_properties(linguist.icns PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + target_sources(linguist PRIVATE + linguist.icns + ) +endif() +qt_internal_add_docs(linguist + doc/qtlinguist.qdocconf +) + diff --git a/src/linguist/linguist/batchtranslationdialog.cpp b/src/linguist/linguist/batchtranslationdialog.cpp index 85961986b3..2543ed7362 100644 --- a/src/linguist/linguist/batchtranslationdialog.cpp +++ b/src/linguist/linguist/batchtranslationdialog.cpp @@ -50,9 +50,12 @@ BatchTranslationDialog::BatchTranslationDialog(MultiDataModel *dataModel, QWidge : QDialog(w), m_model(this), m_dataModel(dataModel) { m_ui.setupUi(this); - connect(m_ui.runButton, SIGNAL(clicked()), this, SLOT(startTranslation())); - connect(m_ui.moveUpButton, SIGNAL(clicked()), this, SLOT(movePhraseBookUp())); - connect(m_ui.moveDownButton, SIGNAL(clicked()), this, SLOT(movePhraseBookDown())); + connect(m_ui.runButton, &QAbstractButton::clicked, + this, &BatchTranslationDialog::startTranslation); + connect(m_ui.moveUpButton, &QAbstractButton::clicked, + this, &BatchTranslationDialog::movePhraseBookUp); + connect(m_ui.moveDownButton, &QAbstractButton::clicked, + this, &BatchTranslationDialog::movePhraseBookDown); m_ui.phrasebookList->setModel(&m_model); m_ui.phrasebookList->setSelectionBehavior(QAbstractItemView::SelectItems); @@ -118,7 +121,8 @@ void BatchTranslationDialog::startTranslation() QVariant checkState = m_model.data(idx, Qt::CheckStateRole); if (checkState == Qt::Checked) { PhraseBook *pb = m_phrasebooks[m_model.data(idx, Qt::UserRole).toInt()]; - foreach (const Phrase *ph, pb->phrases()) { + const auto phrases = pb->phrases(); + for (const Phrase *ph : phrases) { if (ph->source() == m->text()) { m_dataModel->setTranslation(it, ph->target()); m_dataModel->setFinished(it, m_ui.ckMarkFinished->isChecked()); diff --git a/src/linguist/linguist/batchtranslationdialog.h b/src/linguist/linguist/batchtranslationdialog.h index 63808dfbb9..3bfc000209 100644 --- a/src/linguist/linguist/batchtranslationdialog.h +++ b/src/linguist/linguist/batchtranslationdialog.h @@ -43,7 +43,7 @@ class CheckableListModel : public QStandardItemModel { public: CheckableListModel(QObject *parent = 0); - virtual Qt::ItemFlags flags(const QModelIndex &index) const; + Qt::ItemFlags flags(const QModelIndex &index) const override; }; class BatchTranslationDialog : public QDialog diff --git a/src/linguist/linguist/doc/cmake-macros.qdoc b/src/linguist/linguist/doc/cmake-macros.qdoc new file mode 100644 index 0000000000..b82739b074 --- /dev/null +++ b/src/linguist/linguist/doc/cmake-macros.qdoc @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtlinguist-cmake-qt-add-translation.html +\ingroup cmake-macros-qtlinguisttools + +\title qt_add_translation +\target qt6_add_translation + +\brief Compiles Qt Linguist .ts files into .qm files. + +\section1 Synopsis + +\badcode +qt_add_translation( file1.ts [file2.ts ...] + [OPTIONS ...]) + +qt6_add_translation( file1.ts [file2.ts ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Calls \c{lrelease} on each \c{.ts} file passed as an argument, generating +\c{.qm} files. The paths of the generated files are added to \c{}. + +\section1 Options + +You can set additional \c{OPTIONS} that should be passed when \c{lrelease} is +invoked. You can find possible options in the \l{lrelease}{lrelease documentation}. + +By default, the \c{qm} files will be placed in the root level of the build +directory. To change this, you can set \c{OUTPUT_LOCATION} as a property +of the source \c{.ts} file. + +\section1 Examples + +Generating \c{helloworld_en.qm}, \c{helloworld_de.qm} in the build +directory: + +\snippet cmake-macros/examples.cmake qt_add_translation + +Generating \c{helloworld_en.qm}, \c{helloworld_de.qm} in a \c{l10n} +sub-directory: + +\snippet cmake-macros/examples.cmake qt_add_translation_output_location +*/ + +/*! +\page qtlinguist-cmake-qt-create-translation.html +\ingroup cmake-macros-qtlinguisttools + +\title qt_create_translation +\target qt6_create_translation + +\brief Sets up the Qt Linguist translation toolchain. + +\section1 Synopsis + +\badcode +qt6_create_translation( ts-file-or-sources [ts-file-or-sources2 ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Processes given sources (directories or individual files) to generate +Qt Linguist \c{.ts} files. The \c{.ts} files are in turn compiled into \c{.qm} +files of the same base name that are stored in the build +directory. Paths to the generated \c{.qm} files are added to \c{}. + +The translation files to create or update need to have a \c{.ts} suffix. If +the given file path is not absolute it is resolved relative to the current +source directory. If no \c{.ts} file is passed as an argument, the macro +does nothing. + +Any arguments that do not have a \c{.ts} suffix are passed as input to the +\c{lupdate}. \c{lupdate} accepts directories and source files as input. +See also the \l{lupdate}{lupdate documentation} on further details. + +\section1 Options + +You can set additional \c{OPTIONS} that should be passed when \c{lupdate} is +invoked. You can find possible options in the \l{lupdate}{lupdate documentation}. + +\section1 Examples + +Recursively look up Qt translations from source files in current directory and +generate or update \c{helloworld_en.ts} and \c{helloworld_de.ts} file using +\c{lupdate}. Compile said files into \c{helloworld_en.qm} and \c{helloworld.de.qm} +files in the build directory: + +\snippet cmake-macros/examples.cmake qt_create_translation +*/ diff --git a/src/linguist/linguist/doc/qtlinguist.qdocconf b/src/linguist/linguist/doc/qtlinguist.qdocconf index 8f50d966cb..595471aa18 100644 --- a/src/linguist/linguist/doc/qtlinguist.qdocconf +++ b/src/linguist/linguist/doc/qtlinguist.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QtLinguist description = Qt Linguist Manual @@ -36,3 +37,5 @@ imagedirs = images depends += qtdoc qtqml qtquick qtcore qtgui qmake navigation.landingpage = "Qt Linguist Manual" + +warninglimit = 0 diff --git a/src/linguist/linguist/doc/snippets/cmake-macros/examples.cmake b/src/linguist/linguist/doc/snippets/cmake-macros/examples.cmake new file mode 100644 index 0000000000..c91fe5536b --- /dev/null +++ b/src/linguist/linguist/doc/snippets/cmake-macros/examples.cmake @@ -0,0 +1,13 @@ +#! [qt_add_translation] +qt_add_translation(qmFiles helloworld_en.ts helloworld_de.ts) +#! [qt_add_translation] + +#! [qt_add_translation_output_location] +set(TS_FILES helloworld_en.ts helloworld_de.ts) +set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "l10n") +qt_add_translation(qmFiles ${TS_FILES}) +#! [qt_add_translation_output_location] + +#! [qt_create_translation] +qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} helloworld_en.ts helloworld_de.ts) +#! [qt_create_translation] diff --git a/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.cpp b/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.cpp index 7ded33ade8..f2064a8bb2 100644 --- a/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.cpp +++ b/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.cpp @@ -51,3 +51,27 @@ //! [3] label->setText(tr("F\374r \310lise")); //! [3] +//! [4] +menuBar: MenuBar { + Menu { + title: qsTr("&File") + Action { text: qsTr("&New...") } + Action { text: qsTr("&Open...") } + Action { text: qsTr("&Save") } + Action { text: qsTr("Save &As...") } + MenuSeparator { } + Action { text: qsTr("&Quit") } + } + Menu { + title: qsTr("&Edit") + Action { text: qsTr("Cu&t") } + Action { text: qsTr("&Copy") } + Action { text: qsTr("&Paste") } + } + Menu { + title: qsTr("&Help") + Action { text: qsTr("&About") } + } +} + +//! [4] diff --git a/src/linguist/linguist/doc/src/linguist-manual.qdoc b/src/linguist/linguist/doc/src/linguist-manual.qdoc index 403e4652c4..5407b03ee9 100644 --- a/src/linguist/linguist/doc/src/linguist-manual.qdoc +++ b/src/linguist/linguist/doc/src/linguist-manual.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -77,14 +77,13 @@ \title Overview of the Translation Process \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Qt Linguist Manual \nextpage Qt Linguist Manual: Release Manager Most of the text that must be translated in an application consists of either single words or short phrases. These typically appear as window titles, menu items, tooltips, - and labels to buttons, check boxes and radio buttons. + and labels to buttons, check boxes, and radio buttons. The phrases are entered into the source code by the developer in their native language using a simple but special syntax to identify @@ -96,15 +95,14 @@ The release manager generates a set of translation files that are produced from the source files and passes these to the translator. The translator opens the translation files using \QL, - enters their translations and saves the results back into + enters their translations, and saves the results back into the translation files, which they pass back to the release manager. The release manager then generates fast compact versions of these translation files ready for use by the application. - The tools are - designed to be used in repeated cycles as applications change and - evolve, preserving existing translations and making it easy to - identify which new translations are required. \QL also + The tools are designed to be used in repeated cycles as applications + change and evolve, preserving existing translations and making it + easy to identify which new translations are required. \QL also provides a phrase book facility to help ensure consistent translations across multiple applications and projects. @@ -119,15 +117,16 @@ "open internet connection", in German. \li Keyboard accelerators may need to be changed but without - introducing conflicts. For example, "\&Quit" in English becomes "Avslutt" - in Norwegian which does not contain a "Q". We cannot use a letter - that is already in use - unless we change several accelerators. + introducing conflicts. For example, "\&Quit" in English becomes + "Avslutt" in Norwegian which does not contain a "Q". We cannot + use a letter that is already in use - unless we change several + accelerators. \li Phrases that contain variables, for example, "The 25 files selected will take 63 seconds to process", where the two numbers - are inserted programmatically at run-time may need to be reworded - because in a different language the word order and therefore the - placement of the variables may have to change. + are inserted programmatically at runtime, may need to be rephrased. + The word order in the other language may be different, so the + variables will have to be put in another place in the sentence. \endlist @@ -146,13 +145,12 @@ \title Qt Linguist Manual: Release Manager \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Overview of the Translation Process \nextpage Qt Linguist Manual: Translators - Two tools are provided for the release manager, lupdate and - lrelease. These tools can process \l {qmake Manual}{qmake} project files, or operate - directly on the file system. + Two tools are provided for the release manager: \c lupdate and + \c lrelease. These tools can process \l {qmake Manual}{qmake} project files, + or operate directly on the file system. \section1 Creating Translation Files @@ -178,7 +176,7 @@ \endlist - For lupdate to work successfully, it must know which translation files to + For \c lupdate to work successfully, it must know which translation files to produce. The files are listed in the application's \c .pro Qt project file. \target lupdate @@ -190,13 +188,59 @@ strings in the specified source, header and \e {Qt Designer} interface files, and produces or updates \c .ts translation files. The files to process and the files to update can be set at - the command line, or provided in a \c .pro file specified as an + the command line, or provided in a \c .pro file specified as a command line argument. The developer creates the .pro file, as described in \l{Qt Linguist Manual: Developers}. - The produced translation files are given to - the translator who uses \QL to read the files and insert the - translations. + You can generate the translation file for a single QML file in + the following way: + + \badcode + lupdate main.qml -ts main_en.ts + \endcode + + To make a translation file for another language, for example French, + you copy main_en.ts to main_fr.ts, and translate the strings in the + French TS file. + + \c lupdate processes QML files that are listed in the \c .qrc file: + + \badcode + RESOURCES += qml.qrc + \endcode + + To have all QML files processed by \c lupdate: + + \badcode + lupdate application.qrc -ts myapp_en.ts + \endcode + + You can also process all QML files without using a \c .qrc file: + + \badcode + lupdate -extensions qml -ts myapp_en.ts + \endcode + + If you are mostly processing QML files, but also have C++ code + that contains strings to be translated, you can add it in the same command: + + \badcode + lupdate qml.qrc filevalidator.cpp -ts myapp_en.ts + \endcode + + The translation files can be mentioned in the .pro file, but it + is also possible to do without it, and just specify the translation + file on the command line. + + For example, to generate .ts files that will be used for English and + French: + + \badcode + lupdate qml.qrc filevalidator.cpp -ts myapp_en.ts myapp_fr.ts + \endcode + + The produced translation files are given to the translator who + uses \QL to read the files and insert the translations. Companies that have their own translators in-house may find it useful to run lupdate regularly, perhaps monthly, as the @@ -250,6 +294,12 @@ are available the application will detect them and use them automatically. + \c lrelease can be also be run without specifying a \.pro file: + + \badcode + lrelease.exe main_en.ts languages\main_fr.ts + \endcode + \note The lrelease tool only incorporates translations that are marked as "finished". Otherwise the original text is used instead. @@ -269,7 +319,6 @@ \title Qt Linguist Manual: Translators \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Qt Linguist Manual: Release Manager \nextpage Qt Linguist Manual: Developers @@ -824,7 +873,6 @@ \title Qt Linguist Manual: Developers \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Qt Linguist Manual: Translators \nextpage Qt Linguist Manual: TS File Format @@ -995,7 +1043,6 @@ \title Qt Linguist Manual: TS File Format \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Qt Linguist Manual: Developers \nextpage Qt Linguist Manual: Text ID Based Translations @@ -1013,7 +1060,6 @@ \title Qt Linguist Manual: Text ID Based Translations \ingroup internationalization - \contentspage {Qt Linguist Manual}{Contents} \previouspage Qt Linguist Manual: TS File Format \brief Text ID based internationalization provides support for large scale diff --git a/src/linguist/linguist/finddialog.cpp b/src/linguist/linguist/finddialog.cpp index 9dd801a712..e2ca9f38ee 100644 --- a/src/linguist/linguist/finddialog.cpp +++ b/src/linguist/linguist/finddialog.cpp @@ -43,9 +43,12 @@ FindDialog::FindDialog(QWidget *parent) findNxt->setEnabled(false); - connect(findNxt, SIGNAL(clicked()), this, SLOT(emitFindNext())); - connect(useRegExp, SIGNAL(stateChanged(int)), this, SLOT(verify())); - connect(led, SIGNAL(textChanged(QString)), this, SLOT(verify())); + connect(findNxt, &QAbstractButton::clicked, + this, &FindDialog::emitFindNext); + connect(useRegExp, &QCheckBox::stateChanged, + this, &FindDialog::verify); + connect(led, &QLineEdit::textChanged, + this, &FindDialog::verify); led->setFocus(); } diff --git a/src/linguist/linguist/finddialog.h b/src/linguist/linguist/finddialog.h index 039f0b9e72..529b343fd7 100644 --- a/src/linguist/linguist/finddialog.h +++ b/src/linguist/linguist/finddialog.h @@ -48,10 +48,12 @@ class FindDialog : public QDialog, public Ui::FindDialog void findNext(const QString& text, DataModel::FindLocation where, bool matchCase, bool ignoreAccelerators, bool skipObsolete, bool useRegExp); +public slots: + void find(); + private slots: void emitFindNext(); void verify(); - void find(); private: QRegularExpression m_regExp; diff --git a/src/linguist/linguist/formpreviewview.cpp b/src/linguist/linguist/formpreviewview.cpp index 939322a462..8aed545da3 100644 --- a/src/linguist/linguist/formpreviewview.cpp +++ b/src/linguist/linguist/formpreviewview.cpp @@ -31,10 +31,6 @@ #include -#include -#include - -#include #include #include #include @@ -51,12 +47,17 @@ #include #include +#include + +#include +#include + QT_BEGIN_NAMESPACE #if defined(Q_CC_SUN) || defined(Q_CC_HPACC) || defined(Q_CC_XLC) -int qHash(const QUiTranslatableStringValue &tsv) +size_t qHash(const QUiTranslatableStringValue &tsv) #else -static int qHash(const QUiTranslatableStringValue &tsv) +static size_t qHash(const QUiTranslatableStringValue &tsv) #endif { return qHash(tsv.value()) ^ qHash(tsv.qualifier()); @@ -130,7 +131,8 @@ static void buildTargets(QObject *o, TargetsHash *targets) { TranslatableEntry target; - foreach (const QByteArray &prop, o->dynamicPropertyNames()) { + const auto propNames = o->dynamicPropertyNames(); + for (const QByteArray &prop : propNames) { if (prop.startsWith(PROP_GENERIC_PREFIX)) { const QByteArray propName = prop.mid(sizeof(PROP_GENERIC_PREFIX) - 1); INSERT_TARGET(o->property(prop), @@ -199,14 +201,14 @@ static void buildTargets(QObject *o, TargetsHash *targets) registerTreeItem(treew->topLevelItem(i), targets); #endif } - foreach (QObject *co, o->children()) + for (QObject *co : o->children()) buildTargets(co, targets); } static void destroyTargets(TargetsHash *targets) { - for (TargetsHash::Iterator it = targets->begin(), end = targets->end(); it != end; ++it) - foreach (const TranslatableEntry &target, *it) + for (const auto &targetList : qAsConst(*targets)) + for (const TranslatableEntry &target : targetList) if (target.type == TranslatableProperty) delete target.prop.name; targets->clear(); @@ -278,7 +280,7 @@ static void retranslateTargets( if (text.isEmpty() && !tsv.value().isEmpty()) text = QLatin1Char('#') + sourceText; - foreach (const TranslatableEntry &target, targets) + for (const TranslatableEntry &target : targets) retranslateTarget(target, text); } @@ -375,7 +377,7 @@ static void highlightAction(QAction *a, bool on) a->setProperty(FONT_BACKUP_PROP, QVariant()); } } - foreach (QWidget *w, a->associatedWidgets()) + for (QWidget *w : a->associatedWidgets()) highlightWidget(w, on); } @@ -385,7 +387,7 @@ static void highlightWidget(QWidget *w, bool on) if (on) { if (!bak.isValid()) { QPalette pal = qApp->palette(); - foreach (QObject *co, w->children()) + for (QObject *co : w->children()) if (QWidget *cw = qobject_cast(co)) cw->setPalette(cw->palette().resolve(pal)); w->setProperty(PALETTE_BACKUP_PROP, QVariant::fromValue(w->palette().resolve(pal))); @@ -477,7 +479,7 @@ static void highlightTarget(const TranslatableEntry &target, bool on) static void highlightTargets(const QList &targets, bool on) { - foreach (const TranslatableEntry &target, targets) + for (const TranslatableEntry &target : targets) highlightTarget(target, on); } @@ -552,7 +554,7 @@ void FormPreviewView::setSourceContext(int model, MessageItem *messageItem) tsv.setQualifier(messageItem->comment().toUtf8()); m_highlights = m_targets.value(tsv); if (m_lastModel != model) { - for (TargetsHash::Iterator it = m_targets.begin(), end = m_targets.end(); it != end; ++it) + for (auto it = m_targets.cbegin(), end = m_targets.cend(); it != end; ++it) retranslateTargets(*it, it.key(), m_dataModel->model(model), m_lastClassName); m_lastModel = model; } else { diff --git a/src/linguist/linguist/linguist.pro b/src/linguist/linguist/linguist.pro deleted file mode 100644 index af74df8ecc..0000000000 --- a/src/linguist/linguist/linguist.pro +++ /dev/null @@ -1,93 +0,0 @@ -QT += core-private gui-private widgets xml uitools-private printsupport - -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - -include(../shared/formats.pri) - -QMAKE_DOCS = $$PWD/doc/qtlinguist.qdocconf - -DEFINES += QFORMINTERNAL_NAMESPACE - -SOURCES += \ - batchtranslationdialog.cpp \ - errorsview.cpp \ - finddialog.cpp \ - formpreviewview.cpp \ - globals.cpp \ - main.cpp \ - mainwindow.cpp \ - messageeditor.cpp \ - messageeditorwidgets.cpp \ - messagehighlighter.cpp \ - messagemodel.cpp \ - phrasebookbox.cpp \ - phrase.cpp \ - phrasemodel.cpp \ - phraseview.cpp \ - printout.cpp \ - recentfiles.cpp \ - sourcecodeview.cpp \ - statistics.cpp \ - translatedialog.cpp \ - translationsettingsdialog.cpp \ - ../shared/simtexth.cpp - -HEADERS += \ - batchtranslationdialog.h \ - errorsview.h \ - finddialog.h \ - formpreviewview.h \ - globals.h \ - mainwindow.h \ - messageeditor.h \ - messageeditorwidgets.h \ - messagehighlighter.h \ - messagemodel.h \ - phrasebookbox.h \ - phrase.h \ - phrasemodel.h \ - phraseview.h \ - printout.h \ - recentfiles.h \ - sourcecodeview.h \ - statistics.h \ - translatedialog.h \ - translationsettingsdialog.h \ - ../shared/simtexth.h - -contains(QT_PRODUCT, OpenSource.*):DEFINES *= QT_OPENSOURCE -DEFINES += QT_KEYWORDS -TARGET = linguist - -QMAKE_TARGET_DESCRIPTION = Qt Linguist - -win32 { - RC_ICONS = linguist.ico - VERSION = $${QT_VERSION}.0 -} else { - VERSION = $${QT_VERSION} -} -mac { - static:CONFIG -= global_init_link_order - ICON = linguist.icns - TARGET = Linguist - QMAKE_INFO_PLIST=Info_mac.plist -} -PROJECTNAME = Qt \ - Linguist - -phrasebooks.path = $$[QT_INSTALL_DATA]/phrasebooks -# ## will this work on windows? -phrasebooks.files = $$PWD/../phrasebooks/* -INSTALLS += phrasebooks - -FORMS += statistics.ui \ - phrasebookbox.ui \ - batchtranslation.ui \ - translatedialog.ui \ - mainwindow.ui \ - translationsettings.ui \ - finddialog.ui -RESOURCES += linguist.qrc - -load(qt_app) diff --git a/src/linguist/linguist/main.cpp b/src/linguist/linguist/main.cpp index 0b549b6e02..3113443853 100644 --- a/src/linguist/linguist/main.cpp +++ b/src/linguist/linguist/main.cpp @@ -32,13 +32,10 @@ #include #include #include -#include #include #include -#include #include -#include #ifdef Q_OS_MAC #include @@ -68,7 +65,7 @@ class ApplicationEventFilter : public QObject } protected: - bool eventFilter(QObject *object, QEvent *event) + bool eventFilter(QObject *object, QEvent *event) override { if (object == qApp && event->type() == QEvent::FileOpen) { QFileOpenEvent *e = static_cast(event); @@ -92,9 +89,6 @@ int main(int argc, char **argv) { Q_INIT_RESOURCE(linguist); - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QApplication app(argc, argv); QApplication::setOverrideCursor(Qt::WaitCursor); @@ -104,7 +98,7 @@ int main(int argc, char **argv) #endif // Q_OS_MAC QStringList files; - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); QStringList args = app.arguments(); for (int i = 1; i < args.count(); ++i) { @@ -122,10 +116,9 @@ int main(int argc, char **argv) QTranslator translator; QTranslator qtTranslator; - QString sysLocale = QLocale::system().name(); - if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir)) { + if (translator.load(QLocale(), QLatin1String("linguist"), QLatin1String("_"), resourceDir)) { app.installTranslator(&translator); - if (qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) + if (qtTranslator.load(QLocale(), QLatin1String("qt"), QLatin1String("_"), resourceDir)) app.installTranslator(&qtTranslator); else app.removeTranslator(&translator); @@ -134,28 +127,11 @@ int main(int argc, char **argv) app.setOrganizationName(QLatin1String("QtProject")); app.setApplicationName(QLatin1String("Linguist")); - QSettings config; - - QWidget tmp; - tmp.restoreGeometry(config.value(settingPath("Geometry/WindowGeometry")).toByteArray()); - - QSplashScreen *splash = 0; - int screenId = QApplication::desktop()->screenNumber(tmp.geometry().center()); - splash = new QSplashScreen(QApplication::desktop()->screen(screenId), - QPixmap(QLatin1String(":/images/icons/linguist-128-32.png"))); - if (QApplication::desktop()->isVirtualDesktop()) { - QRect srect(0, 0, splash->width(), splash->height()); - splash->move(QApplication::desktop()->availableGeometry(screenId).center() - srect.center()); - } - splash->setAttribute(Qt::WA_DeleteOnClose); - splash->show(); - MainWindow mw; #ifdef Q_OS_MAC eventFilter.setMainWindow(&mw); #endif // Q_OS_MAC mw.show(); - splash->finish(&mw); QApplication::restoreOverrideCursor(); mw.openFiles(files, true); diff --git a/src/linguist/linguist/mainwindow.cpp b/src/linguist/linguist/mainwindow.cpp index f443d25eac..fb3049c014 100644 --- a/src/linguist/linguist/mainwindow.cpp +++ b/src/linguist/linguist/mainwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Linguist of the Qt Toolkit. @@ -54,7 +54,6 @@ #include #include #include -#include #include #include #include @@ -72,7 +71,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include @@ -174,7 +175,7 @@ class ContextItemDelegate : public QItemDelegate ContextItemDelegate(QObject *parent, MultiDataModel *model) : QItemDelegate(parent), m_dataModel(model) {} void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const + const QModelIndex &index) const override { const QAbstractItemModel *model = index.model(); Q_ASSERT(model); @@ -207,7 +208,7 @@ class SortedMessagesModel : public QSortFilterProxyModel public: SortedMessagesModel(QObject *parent, MultiDataModel *model) : QSortFilterProxyModel(parent), m_dataModel(model) {} - QVariant headerData(int section, Qt::Orientation orientation, int role) const + QVariant headerData(int section, Qt::Orientation orientation, int role) const override { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) switch (section - m_dataModel->modelCount()) { @@ -231,7 +232,7 @@ class SortedContextsModel : public QSortFilterProxyModel public: SortedContextsModel(QObject *parent, MultiDataModel *model) : QSortFilterProxyModel(parent), m_dataModel(model) {} - QVariant headerData(int section, Qt::Orientation orientation, int role) const + QVariant headerData(int section, Qt::Orientation orientation, int role) const override { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) switch (section - m_dataModel->modelCount()) { @@ -257,7 +258,7 @@ class FocusWatcher : public QObject FocusWatcher(MessageEditor *msgedit, QObject *parent) : QObject(parent), m_messageEditor(msgedit) {} protected: - bool eventFilter(QObject *object, QEvent *event); + bool eventFilter(QObject *object, QEvent *event) override; private: MessageEditor *m_messageEditor; @@ -266,7 +267,7 @@ class FocusWatcher : public QObject bool FocusWatcher::eventFilter(QObject *, QEvent *event) { if (event->type() == QEvent::FocusIn) - m_messageEditor->setEditorFocus(-1); + m_messageEditor->setEditorFocusForModel(-1); return false; } @@ -299,7 +300,6 @@ MainWindow::MainWindow() m_contextDock = new QDockWidget(this); m_contextDock->setObjectName(QLatin1String("ContextDockWidget")); m_contextDock->setAllowedAreas(Qt::AllDockWidgetAreas); - m_contextDock->setFeatures(QDockWidget::AllDockWidgetFeatures); m_contextDock->setWindowTitle(tr("Context")); m_contextDock->setAcceptDrops(true); m_contextDock->installEventFilter(this); @@ -329,7 +329,6 @@ MainWindow::MainWindow() m_messagesDock = new QDockWidget(this); m_messagesDock->setObjectName(QLatin1String("StringsDockWidget")); m_messagesDock->setAllowedAreas(Qt::AllDockWidgetAreas); - m_messagesDock->setFeatures(QDockWidget::AllDockWidgetFeatures); m_messagesDock->setWindowTitle(tr("Strings")); m_messagesDock->setAcceptDrops(true); m_messagesDock->installEventFilter(this); @@ -366,7 +365,6 @@ MainWindow::MainWindow() m_phrasesDock = new QDockWidget(this); m_phrasesDock->setObjectName(QLatin1String("PhrasesDockwidget")); m_phrasesDock->setAllowedAreas(Qt::AllDockWidgetAreas); - m_phrasesDock->setFeatures(QDockWidget::AllDockWidgetFeatures); m_phrasesDock->setWindowTitle(tr("Phrases and guesses")); m_phraseView = new PhraseView(m_dataModel, &m_phraseDict, this); @@ -376,12 +374,9 @@ MainWindow::MainWindow() m_sourceAndFormDock = new QDockWidget(this); m_sourceAndFormDock->setObjectName(QLatin1String("SourceAndFormDock")); m_sourceAndFormDock->setAllowedAreas(Qt::AllDockWidgetAreas); - m_sourceAndFormDock->setFeatures(QDockWidget::AllDockWidgetFeatures); m_sourceAndFormDock->setWindowTitle(tr("Sources and Forms")); m_sourceAndFormView = new QStackedWidget(this); m_sourceAndFormDock->setWidget(m_sourceAndFormView); - //connect(m_sourceAndDock, SIGNAL(visibilityChanged(bool)), - // m_sourceCodeView, SLOT(setActivated(bool))); m_formPreviewView = new FormPreviewView(0, m_dataModel); m_sourceCodeView = new SourceCodeView(0); m_sourceAndFormView->addWidget(m_sourceCodeView); @@ -391,7 +386,6 @@ MainWindow::MainWindow() m_errorsDock = new QDockWidget(this); m_errorsDock->setObjectName(QLatin1String("ErrorsDockWidget")); m_errorsDock->setAllowedAreas(Qt::AllDockWidgetAreas); - m_errorsDock->setFeatures(QDockWidget::AllDockWidgetFeatures); m_errorsDock->setWindowTitle(tr("Warnings")); m_errorsView = new ErrorsView(m_dataModel, this); m_errorsDock->setWidget(m_errorsView); @@ -415,34 +409,36 @@ MainWindow::MainWindow() // Set up shortcuts for the dock widgets QShortcut *contextShortcut = new QShortcut(QKeySequence(Qt::Key_F6), this); - connect(contextShortcut, SIGNAL(activated()), this, SLOT(showContextDock())); + connect(contextShortcut, &QShortcut::activated, + this, &MainWindow::showContextDock); QShortcut *messagesShortcut = new QShortcut(QKeySequence(Qt::Key_F7), this); - connect(messagesShortcut, SIGNAL(activated()), this, SLOT(showMessagesDock())); + connect(messagesShortcut, &QShortcut::activated, + this, &MainWindow::showMessagesDock); QShortcut *errorsShortcut = new QShortcut(QKeySequence(Qt::Key_F8), this); - connect(errorsShortcut, SIGNAL(activated()), this, SLOT(showErrorDock())); + connect(errorsShortcut, &QShortcut::activated, + this, &MainWindow::showErrorDock); QShortcut *sourceCodeShortcut = new QShortcut(QKeySequence(Qt::Key_F9), this); - connect(sourceCodeShortcut, SIGNAL(activated()), this, SLOT(showSourceCodeDock())); + connect(sourceCodeShortcut, &QShortcut::activated, + this, &MainWindow::showSourceCodeDock); QShortcut *phrasesShortcut = new QShortcut(QKeySequence(Qt::Key_F10), this); - connect(phrasesShortcut, SIGNAL(activated()), this, SLOT(showPhrasesDock())); - - connect(m_phraseView, SIGNAL(phraseSelected(int,QString)), - m_messageEditor, SLOT(setTranslation(int,QString))); - connect(m_phraseView, SIGNAL(setCurrentMessageFromGuess(int,Candidate)), - this, SLOT(setCurrentMessage(int,Candidate))); - connect(m_contextView->selectionModel(), - SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), - this, SLOT(selectedContextChanged(QModelIndex,QModelIndex))); - connect(m_messageView->selectionModel(), - SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), - this, SLOT(selectedMessageChanged(QModelIndex,QModelIndex))); - connect(m_contextView->selectionModel(), - SIGNAL(currentColumnChanged(QModelIndex,QModelIndex)), - SLOT(updateLatestModel(QModelIndex))); - connect(m_messageView->selectionModel(), - SIGNAL(currentColumnChanged(QModelIndex,QModelIndex)), - SLOT(updateLatestModel(QModelIndex))); - - connect(m_messageEditor, SIGNAL(activeModelChanged(int)), SLOT(updateActiveModel(int))); + connect(phrasesShortcut, &QShortcut::activated, + this, &MainWindow::showPhrasesDock); + + connect(m_phraseView, &PhraseView::phraseSelected, + m_messageEditor, &MessageEditor::setTranslation); + connect(m_phraseView, &PhraseView::setCurrentMessageFromGuess, + this, &MainWindow::setCurrentMessageFromGuess); + connect(m_contextView->selectionModel(), &QItemSelectionModel::currentRowChanged, + this, &MainWindow::selectedContextChanged); + connect(m_messageView->selectionModel(), &QItemSelectionModel::currentRowChanged, + this, &MainWindow::selectedMessageChanged); + connect(m_contextView->selectionModel(), &QItemSelectionModel::currentColumnChanged, + this, &MainWindow::updateLatestModel); + connect(m_messageView->selectionModel(), &QItemSelectionModel::currentColumnChanged, + this, &MainWindow::updateLatestModel); + + connect(m_messageEditor, &MessageEditor::activeModelChanged, + this, &MainWindow::updateActiveModel); m_translateDialog = new TranslateDialog(this); m_batchTranslateDialog = new BatchTranslationDialog(m_dataModel, this); @@ -460,46 +456,48 @@ MainWindow::MainWindow() initViewHeaders(); resetSorting(); - connect(m_dataModel, SIGNAL(modifiedChanged(bool)), - this, SLOT(setWindowModified(bool))); - connect(m_dataModel, SIGNAL(modifiedChanged(bool)), - m_modifiedLabel, SLOT(setVisible(bool))); - connect(m_dataModel, SIGNAL(multiContextDataChanged(MultiDataIndex)), - SLOT(updateProgress())); - connect(m_dataModel, SIGNAL(messageDataChanged(MultiDataIndex)), - SLOT(maybeUpdateStatistics(MultiDataIndex))); - connect(m_dataModel, SIGNAL(translationChanged(MultiDataIndex)), - SLOT(translationChanged(MultiDataIndex))); - connect(m_dataModel, SIGNAL(languageChanged(int)), - SLOT(updatePhraseDict(int))); + connect(m_dataModel, &MultiDataModel::modifiedChanged, + this, &QWidget::setWindowModified); + connect(m_dataModel, &MultiDataModel::modifiedChanged, + m_modifiedLabel, &QWidget::setVisible); + connect(m_dataModel, &MultiDataModel::multiContextDataChanged, + this, &MainWindow::updateProgress); + connect(m_dataModel, &MultiDataModel::messageDataChanged, + this, &MainWindow::maybeUpdateStatistics); + connect(m_dataModel, &MultiDataModel::translationChanged, + this, &MainWindow::translationChanged); + connect(m_dataModel, &MultiDataModel::languageChanged, + this, &MainWindow::updatePhraseDict); setWindowModified(m_dataModel->isModified()); m_modifiedLabel->setVisible(m_dataModel->isModified()); - connect(m_messageView, SIGNAL(clicked(QModelIndex)), - this, SLOT(toggleFinished(QModelIndex))); - connect(m_messageView, SIGNAL(activated(QModelIndex)), - m_messageEditor, SLOT(setEditorFocus())); - connect(m_contextView, SIGNAL(activated(QModelIndex)), - m_messageView, SLOT(setFocus())); - connect(m_messageEditor, SIGNAL(translationChanged(QStringList)), - this, SLOT(updateTranslation(QStringList))); - connect(m_messageEditor, SIGNAL(translatorCommentChanged(QString)), - this, SLOT(updateTranslatorComment(QString))); - connect(m_findDialog, SIGNAL(findNext(QString,DataModel::FindLocation,bool,bool,bool,bool)), - this, SLOT(findNext(QString,DataModel::FindLocation,bool,bool,bool,bool))); - connect(m_translateDialog, SIGNAL(requestMatchUpdate(bool&)), SLOT(updateTranslateHit(bool&))); - connect(m_translateDialog, SIGNAL(activated(int)), SLOT(translate(int))); - - QSize as(qApp->desktop()->size()); + connect(m_messageView, &QAbstractItemView::clicked, + this, &MainWindow::toggleFinished); + connect(m_messageView, &QAbstractItemView::activated, + m_messageEditor, &MessageEditor::setEditorFocus); + connect(m_contextView, &QAbstractItemView::activated, + m_messageView, qOverload<>(&QWidget::setFocus)); + connect(m_messageEditor, &MessageEditor::translationChanged, + this, &MainWindow::updateTranslation); + connect(m_messageEditor, &MessageEditor::translatorCommentChanged, + this, &MainWindow::updateTranslatorComment); + connect(m_findDialog, &FindDialog::findNext, + this, &MainWindow::findNext); + connect(m_translateDialog, &TranslateDialog::requestMatchUpdate, + this, &MainWindow::updateTranslateHit); + connect(m_translateDialog, &TranslateDialog::activated, + this, &MainWindow::translate); + + QSize as(screen()->size()); as -= QSize(30, 30); resize(QSize(1000, 800).boundedTo(as)); show(); readConfig(); m_statistics = 0; - connect(m_ui.actionLengthVariants, SIGNAL(toggled(bool)), - m_messageEditor, SLOT(setLengthVariants(bool))); + connect(m_ui.actionLengthVariants, &QAction::toggled, + m_messageEditor, &MessageEditor::setLengthVariants); m_messageEditor->setLengthVariants(m_ui.actionLengthVariants->isChecked()); m_messageEditor->setVisualizeWhitespace(m_ui.actionVisualizeWhitespace->isChecked()); @@ -547,7 +545,7 @@ void MainWindow::modelCountChanged() if (!mc) { selectedMessageChanged(QModelIndex(), QModelIndex()); - updateLatestModel(-1); + doUpdateLatestModel(-1); } else { if (!m_contextView->currentIndex().isValid()) { // Ensure that something is selected @@ -562,9 +560,9 @@ void MainWindow::modelCountChanged() // Field insertions/removals are automatic, but not the re-fill m_messageEditor->showMessage(m_currentIndex); if (mc == 1) - updateLatestModel(0); + doUpdateLatestModel(0); else if (m_currentIndex.model() >= mc) - updateLatestModel(mc - 1); + doUpdateLatestModel(mc - 1); } m_contextView->setUpdatesEnabled(true); @@ -598,7 +596,7 @@ bool MainWindow::openFiles(const QStringList &names, bool globalReadWrite) QList opened; bool closeOld = false; - foreach (QString name, names) { + for (QString name : names) { if (!waitCursor) { QApplication::setOverrideCursor(Qt::WaitCursor); waitCursor = true; @@ -658,7 +656,7 @@ bool MainWindow::openFiles(const QStringList &names, bool globalReadWrite) { case QMessageBox::Cancel: delete dm; - foreach (const OpenedFile &op, opened) + for (const OpenedFile &op : qAsConst(opened)) delete op.dataModel; return false; case QMessageBox::Yes: @@ -678,13 +676,13 @@ bool MainWindow::openFiles(const QStringList &names, bool globalReadWrite) waitCursor = false; } if (!closeAll()) { - foreach (const OpenedFile &op, opened) + for (const OpenedFile &op : qAsConst(opened)) delete op.dataModel; return false; } } - foreach (const OpenedFile &op, opened) { + for (const OpenedFile &op : qAsConst(opened)) { if (op.langGuessed) { if (waitCursor) { QApplication::restoreOverrideCursor(); @@ -702,7 +700,7 @@ bool MainWindow::openFiles(const QStringList &names, bool globalReadWrite) m_contextView->setUpdatesEnabled(false); m_messageView->setUpdatesEnabled(false); int totalCount = 0; - foreach (const OpenedFile &op, opened) { + for (const OpenedFile &op : qAsConst(opened)) { m_phraseDict.append(QHash >()); m_dataModel->append(op.dataModel, op.readWrite); if (op.readWrite) @@ -766,7 +764,7 @@ static QString fileFilters(bool allFirst) static const QString pattern(QLatin1String("%1 (*.%2);;")); QStringList allExtensions; QString filter; - foreach (const Translator::FileFormat &format, Translator::registeredFileFormats()) { + for (const Translator::FileFormat &format : qAsConst(Translator::registeredFileFormats())) { if (format.fileType == Translator::FileFormat::TranslationSource && format.priority >= 0) { filter.append(pattern.arg(format.description(), format.extension)); allExtensions.append(QLatin1String("*.") + format.extension); @@ -1023,7 +1021,8 @@ void MainWindow::findAgain() if (searchItem(DataModel::Comments, m->extraComment())) break; } - foreach (const QString &trans, m->translations()) + const auto translations = m->translations(); + for (const QString &trans : translations) if (searchItem(DataModel::Translations, trans)) goto didfind; if (searchItem(DataModel::Comments, m->translatorComment())) @@ -1178,7 +1177,7 @@ void MainWindow::newPhraseBook() return; m_phraseBookDir = QFileInfo(name).absolutePath(); if (savePhraseBook(&name, pb)) { - if (openPhraseBook(name)) + if (doOpenPhraseBook(name)) statusBar()->showMessage(tr("Phrase book created."), MessageMS); } } @@ -1186,7 +1185,7 @@ void MainWindow::newPhraseBook() bool MainWindow::isPhraseBookOpen(const QString &name) { - foreach(const PhraseBook *pb, m_phraseBooks) { + for (const PhraseBook *pb : qAsConst(m_phraseBooks)) { if (pb->fileName() == name) return true; } @@ -1202,7 +1201,7 @@ void MainWindow::openPhraseBook() if (!name.isEmpty()) { m_phraseBookDir = QFileInfo(name).absolutePath(); if (!isPhraseBookOpen(name)) { - if (PhraseBook *phraseBook = openPhraseBook(name)) { + if (PhraseBook *phraseBook = doOpenPhraseBook(name)) { int n = phraseBook->phrases().count(); statusBar()->showMessage(tr("%n phrase(s) loaded.", 0, n), MessageMS); } @@ -1227,7 +1226,8 @@ void MainWindow::closePhraseBook(QAction *action) m_ui.menuPrintPhraseBook->removeAction(act); m_phraseBooks.removeOne(pb); - disconnect(pb, SIGNAL(listChanged()), this, SLOT(updatePhraseDicts())); + disconnect(pb, &PhraseBook::listChanged, + this, &MainWindow::updatePhraseDicts); updatePhraseDicts(); delete pb; updatePhraseBookActions(); @@ -1254,7 +1254,8 @@ void MainWindow::printPhraseBook(QAction *action) statusBar()->showMessage(tr("Printing...")); PrintOut pout(printer()); pout.setRule(PrintOut::ThinRule); - foreach (const Phrase *p, phraseBook->phrases()) { + const auto phrases = phraseBook->phrases(); + for (const Phrase *p : phrases) { pout.setGuide(p->source()); pout.addBox(29, p->source()); pout.addBox(4); @@ -1279,12 +1280,9 @@ void MainWindow::printPhraseBook(QAction *action) void MainWindow::addToPhraseBook() { - MessageItem *currentMessage = m_dataModel->messageItem(m_currentIndex); - Phrase *phrase = new Phrase(currentMessage->text(), currentMessage->translation(), - QString(), nullptr); QStringList phraseBookList; QHash phraseBookHash; - foreach (PhraseBook *pb, m_phraseBooks) { + for (PhraseBook *pb : qAsConst(m_phraseBooks)) { if (pb->language() != QLocale::C && m_dataModel->language(m_currentIndex.model()) != QLocale::C) { if (pb->language() != m_dataModel->language(m_currentIndex.model())) continue; @@ -1300,20 +1298,31 @@ void MainWindow::addToPhraseBook() if (phraseBookList.isEmpty()) { QMessageBox::warning(this, tr("Add to phrase book"), tr("No appropriate phrasebook found.")); - } else if (phraseBookList.size() == 1) { + return; + } + + QString selectedPhraseBook; + if (phraseBookList.size() == 1) { + selectedPhraseBook = phraseBookList.at(0); if (QMessageBox::information(this, tr("Add to phrase book"), - tr("Adding entry to phrasebook %1").arg(phraseBookList.at(0)), + tr("Adding entry to phrasebook %1").arg(selectedPhraseBook), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) - == QMessageBox::Ok) - phraseBookHash.value(phraseBookList.at(0))->append(phrase); + != QMessageBox::Ok) + return; } else { bool okPressed = false; - QString selection = QInputDialog::getItem(this, tr("Add to phrase book"), - tr("Select phrase book to add to"), - phraseBookList, 0, false, &okPressed); - if (okPressed) - phraseBookHash.value(selection)->append(phrase); + selectedPhraseBook = QInputDialog::getItem(this, tr("Add to phrase book"), + tr("Select phrase book to add to"), + phraseBookList, 0, false, &okPressed); + if (!okPressed) + return; } + + MessageItem *currentMessage = m_dataModel->messageItem(m_currentIndex); + Phrase *phrase = new Phrase(currentMessage->text(), currentMessage->translation(), + QString(), nullptr); + + phraseBookHash.value(selectedPhraseBook)->append(phrase); } void MainWindow::resetSorting() @@ -1328,7 +1337,7 @@ void MainWindow::manual() m_assistantProcess = new QProcess(); if (m_assistantProcess->state() != QProcess::Running) { - QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); + QString app = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QDir::separator(); #if !defined(Q_OS_MAC) app += QLatin1String("assistant"); #else @@ -1347,7 +1356,7 @@ void MainWindow::manual() << (QT_VERSION >> 16) << ((QT_VERSION >> 8) & 0xFF) << (QT_VERSION & 0xFF) << QLatin1String("/qtlinguist/qtlinguist-index.html") - << QLatin1Char('\n') << endl; + << QLatin1Char('\n') << Qt::endl; } void MainWindow::about() @@ -1360,7 +1369,7 @@ void MainWindow::about() const QString description = tr("Qt Linguist is a tool for adding translations to Qt applications."); const QString copyright - = tr("Copyright (C) %1 The Qt Company Ltd.").arg(QStringLiteral("2019")); + = tr("Copyright (C) %1 The Qt Company Ltd.").arg(QStringLiteral("2021")); box.setText(QStringLiteral("

%1

" "

%2

" "

%3

").arg(version, description, copyright)); @@ -1719,7 +1728,7 @@ QModelIndex MainWindow::prevMessage(const QModelIndex ¤tIndex, bool checkU void MainWindow::nextUnfinished() { if (m_ui.actionNextUnfinished->isEnabled()) { - if (!next(true)) { + if (!doNext(true)) { // If no Unfinished message is left, the user has finished the job. We // congratulate on a job well done with this ringing bell. statusBar()->showMessage(tr("No untranslated translation units left."), MessageMS); @@ -1731,7 +1740,7 @@ void MainWindow::nextUnfinished() void MainWindow::prevUnfinished() { if (m_ui.actionNextUnfinished->isEnabled()) { - if (!prev(true)) { + if (!doPrev(true)) { // If no Unfinished message is left, the user has finished the job. We // congratulate on a job well done with this ringing bell. statusBar()->showMessage(tr("No untranslated translation units left."), MessageMS); @@ -1742,15 +1751,15 @@ void MainWindow::prevUnfinished() void MainWindow::prev() { - prev(false); + doPrev(false); } void MainWindow::next() { - next(false); + doNext(false); } -bool MainWindow::prev(bool checkUnfinished) +bool MainWindow::doPrev(bool checkUnfinished) { QModelIndex index = prevMessage(m_messageView->currentIndex(), checkUnfinished); if (index.isValid()) @@ -1762,7 +1771,7 @@ bool MainWindow::prev(bool checkUnfinished) return index.isValid(); } -bool MainWindow::next(bool checkUnfinished) +bool MainWindow::doNext(bool checkUnfinished) { QModelIndex index = nextMessage(m_messageView->currentIndex(), checkUnfinished); if (index.isValid()) @@ -1806,7 +1815,7 @@ void MainWindow::revalidate() QString MainWindow::friendlyString(const QString& str) { QString f = str.toLower(); - f.replace(QRegExp(QString(QLatin1String("[.,:;!?()-]"))), QString(QLatin1String(" "))); + f.replace(QRegularExpression(QString(QLatin1String("[.,:;!?()-]"))), QString(QLatin1String(" "))); f.remove(QLatin1Char('&')); return f.simplified(); } @@ -1865,89 +1874,112 @@ void MainWindow::setupMenuBar() m_ui.actionWhatsThis->setIcon(QIcon(prefix + QStringLiteral("/whatsthis.png"))); // File menu - connect(m_ui.menuFile, SIGNAL(aboutToShow()), SLOT(fileAboutToShow())); - connect(m_ui.actionOpen, SIGNAL(triggered()), this, SLOT(open())); - connect(m_ui.actionOpenAux, SIGNAL(triggered()), this, SLOT(openAux())); - connect(m_ui.actionSaveAll, SIGNAL(triggered()), this, SLOT(saveAll())); - connect(m_ui.actionSave, SIGNAL(triggered()), this, SLOT(save())); - connect(m_ui.actionSaveAs, SIGNAL(triggered()), this, SLOT(saveAs())); - connect(m_ui.actionReleaseAll, SIGNAL(triggered()), this, SLOT(releaseAll())); - connect(m_ui.actionRelease, SIGNAL(triggered()), this, SLOT(release())); - connect(m_ui.actionReleaseAs, SIGNAL(triggered()), this, SLOT(releaseAs())); - connect(m_ui.actionPrint, SIGNAL(triggered()), this, SLOT(print())); - connect(m_ui.actionClose, SIGNAL(triggered()), this, SLOT(closeFile())); - connect(m_ui.actionCloseAll, SIGNAL(triggered()), this, SLOT(closeAll())); - connect(m_ui.actionExit, SIGNAL(triggered()), this, SLOT(close())); + connect(m_ui.menuFile, &QMenu::aboutToShow, this, &MainWindow::fileAboutToShow); + connect(m_ui.actionOpen, &QAction::triggered, this, &MainWindow::open); + connect(m_ui.actionOpenAux, &QAction::triggered, this, &MainWindow::openAux); + connect(m_ui.actionSaveAll, &QAction::triggered, this, &MainWindow::saveAll); + connect(m_ui.actionSave, &QAction::triggered, this, &MainWindow::save); + connect(m_ui.actionSaveAs, &QAction::triggered, this, &MainWindow::saveAs); + connect(m_ui.actionReleaseAll, &QAction::triggered, this, &MainWindow::releaseAll); + connect(m_ui.actionRelease, &QAction::triggered, this, &MainWindow::release); + connect(m_ui.actionReleaseAs, &QAction::triggered, this, &MainWindow::releaseAs); + connect(m_ui.actionPrint, &QAction::triggered, this, &MainWindow::print); + connect(m_ui.actionClose, &QAction::triggered, this, &MainWindow::closeFile); + connect(m_ui.actionCloseAll, &QAction::triggered, this, &MainWindow::closeAll); + connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close); // Edit menu - connect(m_ui.menuEdit, SIGNAL(aboutToShow()), SLOT(editAboutToShow())); - - connect(m_ui.actionUndo, SIGNAL(triggered()), m_messageEditor, SLOT(undo())); - connect(m_messageEditor, SIGNAL(undoAvailable(bool)), m_ui.actionUndo, SLOT(setEnabled(bool))); + connect(m_ui.menuEdit, &QMenu::aboutToShow, this, &MainWindow::editAboutToShow); - connect(m_ui.actionRedo, SIGNAL(triggered()), m_messageEditor, SLOT(redo())); - connect(m_messageEditor, SIGNAL(redoAvailable(bool)), m_ui.actionRedo, SLOT(setEnabled(bool))); + connect(m_ui.actionUndo, &QAction::triggered, m_messageEditor, &MessageEditor::undo); + connect(m_messageEditor, &MessageEditor::undoAvailable, m_ui.actionUndo, &QAction::setEnabled); - connect(m_ui.actionCopy, SIGNAL(triggered()), m_messageEditor, SLOT(copy())); - connect(m_messageEditor, SIGNAL(copyAvailable(bool)), m_ui.actionCopy, SLOT(setEnabled(bool))); + connect(m_ui.actionRedo, &QAction::triggered, m_messageEditor, &MessageEditor::redo); + connect(m_messageEditor, &MessageEditor::redoAvailable, m_ui.actionRedo, &QAction::setEnabled); - connect(m_messageEditor, SIGNAL(cutAvailable(bool)), m_ui.actionCut, SLOT(setEnabled(bool))); - connect(m_ui.actionCut, SIGNAL(triggered()), m_messageEditor, SLOT(cut())); +#ifndef QT_NO_CLIPBOARD + connect(m_ui.actionCut, &QAction::triggered, m_messageEditor, &MessageEditor::cut); + connect(m_messageEditor, &MessageEditor::cutAvailable, m_ui.actionCut, &QAction::setEnabled); - connect(m_messageEditor, SIGNAL(pasteAvailable(bool)), m_ui.actionPaste, SLOT(setEnabled(bool))); - connect(m_ui.actionPaste, SIGNAL(triggered()), m_messageEditor, SLOT(paste())); + connect(m_ui.actionCopy, &QAction::triggered, m_messageEditor, &MessageEditor::copy); + connect(m_messageEditor, &MessageEditor::copyAvailable, m_ui.actionCopy, &QAction::setEnabled); - connect(m_ui.actionSelectAll, SIGNAL(triggered()), m_messageEditor, SLOT(selectAll())); - connect(m_ui.actionFind, SIGNAL(triggered()), m_findDialog, SLOT(find())); - connect(m_ui.actionFindNext, SIGNAL(triggered()), this, SLOT(findAgain())); - connect(m_ui.actionSearchAndTranslate, SIGNAL(triggered()), this, SLOT(showTranslateDialog())); - connect(m_ui.actionBatchTranslation, SIGNAL(triggered()), this, SLOT(showBatchTranslateDialog())); - connect(m_ui.actionTranslationFileSettings, SIGNAL(triggered()), this, SLOT(showTranslationSettings())); + connect(m_ui.actionPaste, &QAction::triggered, m_messageEditor, &MessageEditor::paste); + connect(m_messageEditor, &MessageEditor::pasteAvailable, m_ui.actionPaste, &QAction::setEnabled); +#endif - connect(m_batchTranslateDialog, SIGNAL(finished()), SLOT(refreshItemViews())); + connect(m_ui.actionSelectAll, &QAction::triggered, + m_messageEditor, &MessageEditor::selectAll); + connect(m_ui.actionFind, &QAction::triggered, + m_findDialog, &FindDialog::find); + connect(m_ui.actionFindNext, &QAction::triggered, + this, &MainWindow::findAgain); + connect(m_ui.actionSearchAndTranslate, &QAction::triggered, + this, &MainWindow::showTranslateDialog); + connect(m_ui.actionBatchTranslation, &QAction::triggered, + this, &MainWindow::showBatchTranslateDialog); + connect(m_ui.actionTranslationFileSettings, &QAction::triggered, + this, &MainWindow::showTranslationSettings); + + connect(m_batchTranslateDialog, &BatchTranslationDialog::finished, + this, &MainWindow::refreshItemViews); // Translation menu // when updating the accelerators, remember the status bar - connect(m_ui.actionPrevUnfinished, SIGNAL(triggered()), this, SLOT(prevUnfinished())); - connect(m_ui.actionNextUnfinished, SIGNAL(triggered()), this, SLOT(nextUnfinished())); - connect(m_ui.actionNext, SIGNAL(triggered()), this, SLOT(next())); - connect(m_ui.actionPrev, SIGNAL(triggered()), this, SLOT(prev())); - connect(m_ui.actionDone, SIGNAL(triggered()), this, SLOT(done())); - connect(m_ui.actionDoneAndNext, SIGNAL(triggered()), this, SLOT(doneAndNext())); - connect(m_ui.actionBeginFromSource, SIGNAL(triggered()), m_messageEditor, SLOT(beginFromSource())); - connect(m_messageEditor, SIGNAL(beginFromSourceAvailable(bool)), m_ui.actionBeginFromSource, SLOT(setEnabled(bool))); + connect(m_ui.actionPrevUnfinished, &QAction::triggered, this, &MainWindow::prevUnfinished); + connect(m_ui.actionNextUnfinished, &QAction::triggered, this, &MainWindow::nextUnfinished); + connect(m_ui.actionNext, &QAction::triggered, this, &MainWindow::next); + connect(m_ui.actionPrev, &QAction::triggered, this, &MainWindow::prev); + connect(m_ui.actionDone, &QAction::triggered, this, &MainWindow::done); + connect(m_ui.actionDoneAndNext, &QAction::triggered, this, &MainWindow::doneAndNext); + connect(m_ui.actionBeginFromSource, &QAction::triggered, m_messageEditor, &MessageEditor::beginFromSource); + connect(m_messageEditor, &MessageEditor::beginFromSourceAvailable, + m_ui.actionBeginFromSource, &QAction::setEnabled); // Phrasebook menu - connect(m_ui.actionNewPhraseBook, SIGNAL(triggered()), this, SLOT(newPhraseBook())); - connect(m_ui.actionOpenPhraseBook, SIGNAL(triggered()), this, SLOT(openPhraseBook())); - connect(m_ui.menuClosePhraseBook, SIGNAL(triggered(QAction*)), - this, SLOT(closePhraseBook(QAction*))); - connect(m_ui.menuEditPhraseBook, SIGNAL(triggered(QAction*)), - this, SLOT(editPhraseBook(QAction*))); - connect(m_ui.menuPrintPhraseBook, SIGNAL(triggered(QAction*)), - this, SLOT(printPhraseBook(QAction*))); - connect(m_ui.actionAddToPhraseBook, SIGNAL(triggered()), this, SLOT(addToPhraseBook())); + connect(m_ui.actionNewPhraseBook, &QAction::triggered, this, &MainWindow::newPhraseBook); + connect(m_ui.actionOpenPhraseBook, &QAction::triggered, this, &MainWindow::openPhraseBook); + connect(m_ui.menuClosePhraseBook, &QMenu::triggered, + this, &MainWindow::closePhraseBook); + connect(m_ui.menuEditPhraseBook, &QMenu::triggered, + this, &MainWindow::editPhraseBook); + connect(m_ui.menuPrintPhraseBook, &QMenu::triggered, + this, &MainWindow::printPhraseBook); + connect(m_ui.actionAddToPhraseBook, &QAction::triggered, + this, &MainWindow::addToPhraseBook); // Validation menu - connect(m_ui.actionAccelerators, SIGNAL(triggered()), this, SLOT(revalidate())); - connect(m_ui.actionSurroundingWhitespace, SIGNAL(triggered()), this, SLOT(revalidate())); - connect(m_ui.actionEndingPunctuation, SIGNAL(triggered()), this, SLOT(revalidate())); - connect(m_ui.actionPhraseMatches, SIGNAL(triggered()), this, SLOT(revalidate())); - connect(m_ui.actionPlaceMarkerMatches, SIGNAL(triggered()), this, SLOT(revalidate())); + connect(m_ui.actionAccelerators, &QAction::triggered, this, &MainWindow::revalidate); + connect(m_ui.actionSurroundingWhitespace, &QAction::triggered, this, &MainWindow::revalidate); + connect(m_ui.actionEndingPunctuation, &QAction::triggered, this, &MainWindow::revalidate); + connect(m_ui.actionPhraseMatches, &QAction::triggered, this, &MainWindow::revalidate); + connect(m_ui.actionPlaceMarkerMatches, &QAction::triggered, this, &MainWindow::revalidate); // View menu - connect(m_ui.actionResetSorting, SIGNAL(triggered()), this, SLOT(resetSorting())); - connect(m_ui.actionDisplayGuesses, SIGNAL(triggered()), m_phraseView, SLOT(toggleGuessing())); - connect(m_ui.actionStatistics, SIGNAL(triggered()), this, SLOT(toggleStatistics())); - connect(m_ui.actionVisualizeWhitespace, SIGNAL(triggered()), this, SLOT(toggleVisualizeWhitespace())); - connect(m_ui.menuView, SIGNAL(aboutToShow()), this, SLOT(updateViewMenu())); - connect(m_ui.actionIncreaseZoom, SIGNAL(triggered()), m_messageEditor, SLOT(increaseFontSize())); - connect(m_ui.actionDecreaseZoom, SIGNAL(triggered()), m_messageEditor, SLOT(decreaseFontSize())); - connect(m_ui.actionResetZoomToDefault, SIGNAL(triggered()), m_messageEditor, SLOT(resetFontSize())); - connect(m_ui.actionShowMoreGuesses, SIGNAL(triggered()), m_phraseView, SLOT(moreGuesses())); - connect(m_ui.actionShowFewerGuesses, SIGNAL(triggered()), m_phraseView, SLOT(fewerGuesses())); - connect(m_phraseView, SIGNAL(showFewerGuessesAvailable(bool)), m_ui.actionShowFewerGuesses, SLOT(setEnabled(bool))); - connect(m_ui.actionResetGuessesToDefault, SIGNAL(triggered()), m_phraseView, SLOT(resetNumGuesses())); + connect(m_ui.actionResetSorting, &QAction::triggered, + this, &MainWindow::resetSorting); + connect(m_ui.actionDisplayGuesses, &QAction::triggered, + m_phraseView, &PhraseView::toggleGuessing); + connect(m_ui.actionStatistics, &QAction::triggered, + this, &MainWindow::toggleStatistics); + connect(m_ui.actionVisualizeWhitespace, &QAction::triggered, + this, &MainWindow::toggleVisualizeWhitespace); + connect(m_ui.menuView, &QMenu::aboutToShow, + this, &MainWindow::updateViewMenu); + connect(m_ui.actionIncreaseZoom, &QAction::triggered, + m_messageEditor, &MessageEditor::increaseFontSize); + connect(m_ui.actionDecreaseZoom, &QAction::triggered, + m_messageEditor, &MessageEditor::decreaseFontSize); + connect(m_ui.actionResetZoomToDefault, &QAction::triggered, + m_messageEditor, &MessageEditor::resetFontSize); + connect(m_ui.actionShowMoreGuesses, &QAction::triggered, + m_phraseView, &PhraseView::moreGuesses); + connect(m_ui.actionShowFewerGuesses, &QAction::triggered, + m_phraseView, &PhraseView::fewerGuesses); + connect(m_phraseView, &PhraseView::showFewerGuessesAvailable, + m_ui.actionShowFewerGuesses, &QAction::setEnabled); + connect(m_ui.actionResetGuessesToDefault, &QAction::triggered, + m_phraseView, &PhraseView::resetNumGuesses); m_ui.menuViewViews->addAction(m_contextDock->toggleViewAction()); m_ui.menuViewViews->addAction(m_messagesDock->toggleViewAction()); m_ui.menuViewViews->addAction(m_phrasesDock->toggleViewAction()); @@ -1959,17 +1991,17 @@ void MainWindow::setupMenuBar() QMenu *windowMenu = new QMenu(tr("&Window"), this); menuBar()->insertMenu(m_ui.menuHelp->menuAction(), windowMenu); windowMenu->addAction(tr("Minimize"), this, - SLOT(showMinimized()), QKeySequence(tr("Ctrl+M"))); + &QWidget::showMinimized, QKeySequence(tr("Ctrl+M"))); #endif // Help - connect(m_ui.actionManual, SIGNAL(triggered()), this, SLOT(manual())); - connect(m_ui.actionAbout, SIGNAL(triggered()), this, SLOT(about())); - connect(m_ui.actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt())); - connect(m_ui.actionWhatsThis, SIGNAL(triggered()), this, SLOT(onWhatsThis())); + connect(m_ui.actionManual, &QAction::triggered, this, &MainWindow::manual); + connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::about); + connect(m_ui.actionAboutQt, &QAction::triggered, this, &MainWindow::aboutQt); + connect(m_ui.actionWhatsThis, &QAction::triggered, this, &MainWindow::onWhatsThis); - connect(m_ui.menuRecentlyOpenedFiles, SIGNAL(triggered(QAction*)), this, - SLOT(recentFileActivated(QAction*))); + connect(m_ui.menuRecentlyOpenedFiles, &QMenu::triggered, + this, &MainWindow::recentFileActivated); m_ui.actionManual->setWhatsThis(tr("Display the manual for %1.").arg(tr("Qt Linguist"))); m_ui.actionAbout->setWhatsThis(tr("Display information about %1.").arg(tr("Qt Linguist"))); @@ -1981,25 +2013,26 @@ void MainWindow::setupMenuBar() << QKeySequence(QLatin1String("Ctrl+Enter"))); // Disable the Close/Edit/Print phrasebook menuitems if they are not loaded - connect(m_ui.menuPhrases, SIGNAL(aboutToShow()), this, SLOT(setupPhrase())); + connect(m_ui.menuPhrases, &QMenu::aboutToShow, this, &MainWindow::setupPhrase); - connect(m_ui.menuRecentlyOpenedFiles, SIGNAL(aboutToShow()), SLOT(setupRecentFilesMenu())); + connect(m_ui.menuRecentlyOpenedFiles, &QMenu::aboutToShow, + this, &MainWindow::setupRecentFilesMenu); } void MainWindow::updateActiveModel(int model) { if (model >= 0) - updateLatestModel(model); + doUpdateLatestModel(model); } // Arriving here implies that the messageEditor does not have focus void MainWindow::updateLatestModel(const QModelIndex &index) { if (index.column() && (index.column() - 1 < m_dataModel->modelCount())) - updateLatestModel(index.column() - 1); + doUpdateLatestModel(index.column() - 1); } -void MainWindow::updateLatestModel(int model) +void MainWindow::doUpdateLatestModel(int model) { m_currentIndex = MultiDataIndex(model, m_currentIndex.context(), m_currentIndex.message()); bool enable = false; @@ -2251,10 +2284,10 @@ void MainWindow::setCurrentMessage(const QModelIndex &index, int model) { const QModelIndex &theIndex = m_messageModel->index(index.row(), model + 1, index.parent()); setCurrentMessage(theIndex); - m_messageEditor->setEditorFocus(model); + m_messageEditor->setEditorFocusForModel(model); } -void MainWindow::setCurrentMessage(int modelIndex, const Candidate &cand) +void MainWindow::setCurrentMessageFromGuess(int modelIndex, const Candidate &cand) { int contextIndex = m_dataModel->findContextIndex(cand.context); int messageIndex = m_dataModel->multiContextItem(contextIndex)->findMessage(cand.source, @@ -2273,7 +2306,7 @@ QModelIndex MainWindow::currentMessageIndex() const return m_sortedMessagesModel->mapToSource(m_messageView->currentIndex()); } -PhraseBook *MainWindow::openPhraseBook(const QString& name) +PhraseBook *MainWindow::doOpenPhraseBook(const QString& name) { PhraseBook *pb = new PhraseBook(); bool langGuessed; @@ -2305,7 +2338,7 @@ PhraseBook *MainWindow::openPhraseBook(const QString& name) m_phraseBookMenu[PhrasePrintMenu].insert(a, pb); a->setWhatsThis(tr("Print the entries in this phrase book.")); - connect(pb, SIGNAL(listChanged()), this, SLOT(updatePhraseDicts())); + connect(pb, &PhraseBook::listChanged, this, &MainWindow::updatePhraseDicts); updatePhraseDicts(); updatePhraseBookActions(); @@ -2348,7 +2381,7 @@ bool MainWindow::maybeSavePhraseBook(PhraseBook *pb) bool MainWindow::maybeSavePhraseBooks() { - foreach(PhraseBook *phraseBook, m_phraseBooks) + for (PhraseBook *phraseBook : qAsConst(m_phraseBooks)) if (!maybeSavePhraseBook(phraseBook)) return false; return true; @@ -2389,7 +2422,7 @@ void MainWindow::updatePhraseDictInternal(int model) QHash > &pd = m_phraseDict[model]; pd.clear(); - foreach (PhraseBook *pb, m_phraseBooks) { + for (PhraseBook *pb : qAsConst(m_phraseBooks)) { bool before; if (pb->language() != QLocale::C && m_dataModel->language(model) != QLocale::C) { if (pb->language() != m_dataModel->language(model)) @@ -2398,7 +2431,8 @@ void MainWindow::updatePhraseDictInternal(int model) } else { before = false; } - foreach (Phrase *p, pb->phrases()) { + const auto phrases = pb->phrases(); + for (Phrase *p : phrases) { QString f = friendlyString(p->source()); if (f.length() > 0) { f = f.split(QLatin1Char(' ')).first(); @@ -2536,10 +2570,11 @@ void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose) QStringList lookupWords = fsource.split(QLatin1Char(' ')); bool phraseFound; - foreach (const QString &s, lookupWords) { + for (const QString &s : qAsConst(lookupWords)) { if (m_phraseDict[mi].contains(s)) { phraseFound = true; - foreach (const Phrase *p, m_phraseDict[mi].value(s)) { + const auto phrases = m_phraseDict[mi].value(s); + for (const Phrase *p : phrases) { if (fsource == friendlyString(p->source())) { if (ftranslation.indexOf(friendlyString(p->target())) >= 0) { phraseFound = true; @@ -2595,7 +2630,7 @@ void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose) } } - foreach (int i, placeMarkerIndexes) { + for (int i : qAsConst(placeMarkerIndexes)) { if (i != 0) { if (verbose) m_errorsView->addError(mi, ErrorsView::PlaceMarkersDiffer); @@ -2659,7 +2694,7 @@ void MainWindow::readConfig() int size = config.beginReadArray(settingPath("OpenedPhraseBooks")); for (int i = 0; i < size; ++i) { config.setArrayIndex(i); - openPhraseBook(config.value(QLatin1String("FileName")).toString()); + doOpenPhraseBook(config.value(QLatin1String("FileName")).toString()); } config.endArray(); } @@ -2702,7 +2737,7 @@ void MainWindow::writeConfig() void MainWindow::setupRecentFilesMenu() { m_ui.menuRecentlyOpenedFiles->clear(); - foreach (const QStringList &strList, recentFiles().filesLists()) + for (const QStringList &strList : recentFiles().filesLists()) if (strList.size() == 1) { const QString &str = strList.first(); m_ui.menuRecentlyOpenedFiles->addAction( @@ -2712,7 +2747,7 @@ void MainWindow::setupRecentFilesMenu() MultiDataModel::condenseFileNames( MultiDataModel::prettifyFileNames(strList))); menu->addAction(tr("All"))->setData(strList); - foreach (const QString &str, strList) + for (const QString &str : strList) menu->addAction(DataModel::prettifyFileName(str))->setData(str); } } @@ -2727,8 +2762,8 @@ void MainWindow::toggleStatistics() if (m_ui.actionStatistics->isChecked()) { if (!m_statistics) { m_statistics = new Statistics(this); - connect(m_dataModel, SIGNAL(statsChanged(int,int,int,int,int,int)), - m_statistics, SLOT(updateStats(int,int,int,int,int,int))); + connect(m_dataModel, &MultiDataModel::statsChanged, + m_statistics, &Statistics::updateStats); } m_statistics->show(); updateStatistics(); @@ -2759,7 +2794,7 @@ void MainWindow::updateStatistics() m_dataModel->model(m_currentIndex.model())->updateStatistics(); } -void MainWindow::showTranslationSettings(int model) +void MainWindow::doShowTranslationSettings(int model) { if (!m_translationSettingsDialog) m_translationSettingsDialog = new TranslationSettingsDialog(this); @@ -2769,7 +2804,7 @@ void MainWindow::showTranslationSettings(int model) void MainWindow::showTranslationSettings() { - showTranslationSettings(m_currentIndex.model()); + doShowTranslationSettings(m_currentIndex.model()); } bool MainWindow::eventFilter(QObject *object, QEvent *event) @@ -2785,7 +2820,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) if (!e->mimeData()->hasFormat(QLatin1String("text/uri-list"))) return false; QStringList urls; - foreach (QUrl url, e->mimeData()->urls()) + for (const QUrl &url : e->mimeData()->urls()) if (!url.toLocalFile().isEmpty()) urls << url.toLocalFile(); if (!urls.isEmpty()) @@ -2809,7 +2844,7 @@ bool MainWindow::eventFilter(QObject *object, QEvent *event) } else if (event->type() == QEvent::Wheel) { QWheelEvent *we = static_cast(event); if (we->modifiers() & Qt::ControlModifier) { - if (we->delta() > 0) + if (we->angleDelta().y() > 0) m_messageEditor->increaseFontSize(); else m_messageEditor->decreaseFontSize(); diff --git a/src/linguist/linguist/mainwindow.h b/src/linguist/linguist/mainwindow.h index d8a99b4b47..e6313898f0 100644 --- a/src/linguist/linguist/mainwindow.h +++ b/src/linguist/linguist/mainwindow.h @@ -79,11 +79,14 @@ class MainWindow : public QMainWindow static RecentFiles &recentFiles(); static QString friendlyString(const QString &str); +public slots: + void updateViewMenu(); + protected: void readConfig(); void writeConfig(); - void closeEvent(QCloseEvent *); - bool eventFilter(QObject *object, QEvent *event); + void closeEvent(QCloseEvent *) override; + bool eventFilter(QObject *object, QEvent *event) override; private slots: void done(); @@ -120,7 +123,6 @@ private slots: void about(); void aboutQt(); - void updateViewMenu(); void fileAboutToShow(); void editAboutToShow(); @@ -140,7 +142,7 @@ private slots: void updateLatestModel(const QModelIndex &index); void selectedContextChanged(const QModelIndex &sortedIndex, const QModelIndex &oldIndex); void selectedMessageChanged(const QModelIndex &sortedIndex, const QModelIndex &oldIndex); - void setCurrentMessage(int modelIndex, const Candidate &tm); + void setCurrentMessageFromGuess(int modelIndex, const Candidate &tm); // To synchronize from the message editor to the model ... void updateTranslation(const QStringList &translations); @@ -165,8 +167,8 @@ private slots: QModelIndex prevContext(const QModelIndex &index) const; QModelIndex nextMessage(const QModelIndex ¤tIndex, bool checkUnfinished = false) const; QModelIndex prevMessage(const QModelIndex ¤tIndex, bool checkUnfinished = false) const; - bool next(bool checkUnfinished); - bool prev(bool checkUnfinished); + bool doNext(bool checkUnfinished); + bool doPrev(bool checkUnfinished); void updateStatistics(); void initViewHeaders(); @@ -178,14 +180,14 @@ private slots: QModelIndex setMessageViewRoot(const QModelIndex &index); QModelIndex currentContextIndex() const; QModelIndex currentMessageIndex() const; - PhraseBook *openPhraseBook(const QString &name); + PhraseBook *doOpenPhraseBook(const QString &name); bool isPhraseBookOpen(const QString &name); bool savePhraseBook(QString *name, PhraseBook &pb); bool maybeSavePhraseBook(PhraseBook *phraseBook); bool maybeSavePhraseBooks(); QStringList pickTranslationFiles(); - void showTranslationSettings(int model); - void updateLatestModel(int model); + void doShowTranslationSettings(int model); + void doUpdateLatestModel(int model); void updateSourceView(int model, MessageItem *item); void updatePhraseBookActions(); void updatePhraseDictInternal(int model); diff --git a/src/linguist/linguist/messageeditor.cpp b/src/linguist/linguist/messageeditor.cpp index b02aa1859c..1a126da7a4 100644 --- a/src/linguist/linguist/messageeditor.cpp +++ b/src/linguist/linguist/messageeditor.cpp @@ -82,20 +82,21 @@ MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent) // Signals #ifndef QT_NO_CLIPBOARD - connect(qApp->clipboard(), SIGNAL(dataChanged()), - SLOT(clipboardChanged())); + connect(qApp->clipboard(), &QClipboard::dataChanged, + this, &MessageEditor::clipboardChanged); #endif - connect(m_dataModel, SIGNAL(modelAppended()), - SLOT(messageModelAppended())); - connect(m_dataModel, SIGNAL(modelDeleted(int)), - SLOT(messageModelDeleted(int))); - connect(m_dataModel, SIGNAL(allModelsDeleted()), - SLOT(allModelsDeleted())); - connect(m_dataModel, SIGNAL(languageChanged(int)), - SLOT(setTargetLanguage(int))); + connect(m_dataModel, &MultiDataModel::modelAppended, + this, &MessageEditor::messageModelAppended); + connect(m_dataModel, &MultiDataModel::modelDeleted, + this, &MessageEditor::messageModelDeleted); + connect(m_dataModel, &MultiDataModel::allModelsDeleted, + this, &MessageEditor::allModelsDeleted); + connect(m_dataModel, &MultiDataModel::languageChanged, + this, &MessageEditor::setTargetLanguage); m_tabOrderTimer.setSingleShot(true); - connect(&m_tabOrderTimer, SIGNAL(timeout()), SLOT(reallyFixTabOrder())); + connect(&m_tabOrderTimer, &QTimer::timeout, + this, &MessageEditor::reallyFixTabOrder); #ifndef QT_NO_CLIPBOARD clipboardChanged(); @@ -114,14 +115,14 @@ void MessageEditor::setupEditorPage() m_source = new FormWidget(tr("Source text"), false); m_source->setHideWhenEmpty(true); m_source->setWhatsThis(tr("This area shows the source text.")); - connect(m_source, SIGNAL(selectionChanged(QTextEdit*)), - SLOT(selectionChanged(QTextEdit*))); + connect(m_source, &FormWidget::selectionChanged, + this, &MessageEditor::selectionChanged); m_pluralSource = new FormWidget(tr("Source text (Plural)"), false); m_pluralSource->setHideWhenEmpty(true); m_pluralSource->setWhatsThis(tr("This area shows the plural form of the source text.")); - connect(m_pluralSource, SIGNAL(selectionChanged(QTextEdit*)), - SLOT(selectionChanged(QTextEdit*))); + connect(m_pluralSource, &FormWidget::selectionChanged, + this, &MessageEditor::selectionChanged); m_commentText = new FormWidget(tr("Developer comments"), false); m_commentText->setHideWhenEmpty(true); @@ -129,8 +130,8 @@ void MessageEditor::setupEditorPage() m_commentText->setWhatsThis(tr("This area shows a comment that" " may guide you, and the context in which the text" " occurs.") ); - connect(m_commentText, SIGNAL(selectionChanged(QTextEdit*)), - SLOT(selectionChanged(QTextEdit*))); + connect(m_commentText, &FormWidget::selectionChanged, + this, &MessageEditor::selectionChanged); QBoxLayout *subLayout = new QVBoxLayout; @@ -191,12 +192,14 @@ void MessageEditor::messageModelAppended() " They have no effect on the translated applications.") ); ed.transCommentText->getEditor()->installEventFilter(this); ed.transCommentText->getEditor()->setVisualizeWhitespace(m_visualizeWhitespace); - connect(ed.transCommentText, SIGNAL(selectionChanged(QTextEdit*)), - SLOT(selectionChanged(QTextEdit*))); - connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)), - SLOT(emitTranslatorCommentChanged(QTextEdit*))); - connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection())); - connect(ed.transCommentText, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection())); + connect(ed.transCommentText, &FormWidget::selectionChanged, + this, &MessageEditor::selectionChanged); + connect(ed.transCommentText, &FormWidget::textChanged, + this, &MessageEditor::emitTranslatorCommentChanged); + connect(ed.transCommentText, &FormWidget::textChanged, + this, &MessageEditor::resetHoverSelection); + connect(ed.transCommentText, &FormWidget::cursorPositionChanged, + this, &MessageEditor::resetHoverSelection); fixTabOrder(); QBoxLayout *box = new QVBoxLayout(ed.container); box->setContentsMargins(5, 5, 5, 5); @@ -208,7 +211,7 @@ void MessageEditor::messageModelAppended() void MessageEditor::allModelsDeleted() { - foreach (const MessageEditorData &med, m_editors) + for (const MessageEditorData &med : qAsConst(m_editors)) med.container->deleteLater(); m_editors.clear(); m_currentModel = -1; @@ -244,7 +247,8 @@ void MessageEditor::messageModelDeleted(int model) void MessageEditor::addPluralForm(int model, const QString &label, bool writable) { FormMultiWidget *transEditor = new FormMultiWidget(label); - connect(transEditor, SIGNAL(editorCreated(QTextEdit*)), SLOT(editorCreated(QTextEdit*))); + connect(transEditor, &FormMultiWidget::editorCreated, + this, &MessageEditor::editorCreated); transEditor->setEditingEnabled(writable); transEditor->setHideWhenEmpty(!writable); if (!m_editors[model].transTexts.isEmpty()) @@ -253,12 +257,14 @@ void MessageEditor::addPluralForm(int model, const QString &label, bool writable static_cast(m_editors[model].container->layout())->insertWidget( m_editors[model].transTexts.count(), transEditor); - connect(transEditor, SIGNAL(selectionChanged(QTextEdit*)), - SLOT(selectionChanged(QTextEdit*))); - connect(transEditor, SIGNAL(textChanged(QTextEdit*)), - SLOT(emitTranslationChanged(QTextEdit*))); - connect(transEditor, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection())); - connect(transEditor, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection())); + connect(transEditor, &FormMultiWidget::selectionChanged, + this, &MessageEditor::selectionChanged); + connect(transEditor, &FormMultiWidget::textChanged, + this, &MessageEditor::emitTranslationChanged); + connect(transEditor, &FormMultiWidget::textChanged, + this, &MessageEditor::resetHoverSelection); + connect(transEditor, &FormMultiWidget::cursorPositionChanged, + this, &MessageEditor::resetHoverSelection); m_editors[model].transTexts << transEditor; } @@ -306,9 +312,9 @@ void MessageEditor::fixTabOrder() void MessageEditor::reallyFixTabOrder() { QWidget *prev = this; - foreach (const MessageEditorData &med, m_editors) { - foreach (FormMultiWidget *fmw, med.transTexts) - foreach (QTextEdit *te, fmw->getEditors()) { + for (const MessageEditorData &med : qAsConst(m_editors)) { + for (FormMultiWidget *fmw : med.transTexts) + for (QTextEdit *te : fmw->getEditors()) { setTabOrder(prev, te); prev = te; } @@ -348,11 +354,16 @@ void MessageEditor::selectionChanged(QTextEdit *te) if (te != m_selectionHolder) { if (m_selectionHolder) { clearSelection(m_selectionHolder); - disconnect(this, SLOT(editorDestroyed())); + if (FormatTextEdit *fte = qobject_cast(m_selectionHolder)) { + disconnect(fte, &FormatTextEdit::editorDestroyed, + this, &MessageEditor::editorDestroyed); + } + } + m_selectionHolder = (te->textCursor().hasSelection() ? te : nullptr); + if (FormatTextEdit *fte = qobject_cast(m_selectionHolder)) { + connect(fte, &FormatTextEdit::editorDestroyed, + this, &MessageEditor::editorDestroyed); } - m_selectionHolder = (te->textCursor().hasSelection() ? te : 0); - if (FormatTextEdit *fte = qobject_cast(m_selectionHolder)) - connect(fte, SIGNAL(editorDestroyed()), SLOT(editorDestroyed())); #ifndef QT_NO_CLIPBOARD updateCanCutCopy(); #endif @@ -371,7 +382,10 @@ void MessageEditor::resetSelection() { if (m_selectionHolder) { clearSelection(m_selectionHolder); - disconnect(this, SLOT(editorDestroyed())); + if (FormatTextEdit *fte = qobject_cast(m_selectionHolder)) { + disconnect(fte, &FormatTextEdit::editorDestroyed, + this, &MessageEditor::editorDestroyed); + } m_selectionHolder = 0; #ifndef QT_NO_CLIPBOARD updateCanCutCopy(); @@ -383,7 +397,7 @@ void MessageEditor::activeModelAndNumerus(int *model, int *numerus) const { for (int j = 0; j < m_editors.count(); ++j) { for (int i = 0; i < m_editors[j].transTexts.count(); ++i) - foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors()) + for (QTextEdit *te : m_editors[j].transTexts[i]->getEditors()) if (m_focusWidget == te) { *model = j; *numerus = i; @@ -405,7 +419,7 @@ QTextEdit *MessageEditor::activeTranslation() const return 0; const QList &editors = m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors(); - foreach (QTextEdit *te, editors) + for (QTextEdit *te : editors) if (te->hasFocus()) return te; return editors.first(); @@ -471,7 +485,7 @@ MessageEditorData *MessageEditor::modelForWidget(const QObject *o) { for (int j = 0; j < m_editors.count(); ++j) { for (int i = 0; i < m_editors[j].transTexts.count(); ++i) - foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors()) + for (QTextEdit *te : m_editors[j].transTexts[i]->getEditors()) if (te == o) return &m_editors[j]; if (m_editors[j].transCommentText->getEditor() == o) @@ -554,7 +568,7 @@ void MessageEditor::showNothing() m_commentText->clearTranslation(); for (int j = 0; j < m_editors.count(); ++j) { setEditingEnabled(j, false); - foreach (FormMultiWidget *widget, m_editors[j].transTexts) + for (FormMultiWidget *widget : qAsConst(m_editors[j].transTexts)) widget->clearTranslation(); m_editors[j].transCommentText->clearTranslation(); } @@ -626,9 +640,9 @@ void MessageEditor::showMessage(const MultiDataIndex &index) for (int i = 0; i < ed.transTexts.size(); ++i) { bool shouldShow = (i < normalizedTranslations.count()); if (shouldShow) - setTranslation(j, normalizedTranslations.at(i), i); + setNumerusTranslation(j, normalizedTranslations.at(i), i); else - setTranslation(j, QString(), i); + setNumerusTranslation(j, QString(), i); ed.transTexts.at(i)->setVisible(i == 0 || shouldShow); } } @@ -639,7 +653,7 @@ void MessageEditor::showMessage(const MultiDataIndex &index) updateUndoRedo(); } -void MessageEditor::setTranslation(int model, const QString &translation, int numerus) +void MessageEditor::setNumerusTranslation(int model, const QString &translation, int numerus) { MessageEditorData &ed = m_editors[model]; if (numerus >= ed.transTexts.count()) @@ -669,7 +683,7 @@ void MessageEditor::setTranslation(int latestModel, const QString &translation) void MessageEditor::setEditingEnabled(int model, bool enabled) { MessageEditorData &ed = m_editors[model]; - foreach (FormMultiWidget *widget, ed.transTexts) + for (FormMultiWidget *widget : qAsConst(ed.transTexts)) widget->setEditingEnabled(enabled); ed.transCommentText->setEditingEnabled(enabled); @@ -681,8 +695,8 @@ void MessageEditor::setEditingEnabled(int model, bool enabled) void MessageEditor::setLengthVariants(bool on) { m_lengthVariants = on; - foreach (const MessageEditorData &ed, m_editors) - foreach (FormMultiWidget *widget, ed.transTexts) + for (const MessageEditorData &ed : qAsConst(m_editors)) + for (FormMultiWidget *widget : ed.transTexts) widget->setMultiEnabled(on); } @@ -819,7 +833,7 @@ void MessageEditor::setEditorFocus() activeEditor->setFocus(); } -void MessageEditor::setEditorFocus(int model) +void MessageEditor::setEditorFocusForModel(int model) { if (m_currentModel != model) { if (model < 0) { @@ -868,10 +882,10 @@ void MessageEditor::setVisualizeWhitespace(bool value) m_pluralSource->getEditor()->setVisualizeWhitespace(value); m_commentText->getEditor()->setVisualizeWhitespace(value); - foreach (const MessageEditorData &med, m_editors) { + for (const MessageEditorData &med : qAsConst(m_editors)) { med.transCommentText->getEditor()->setVisualizeWhitespace(value); - foreach (FormMultiWidget *widget, med.transTexts) - foreach (FormatTextEdit *te, widget->getEditors()) + for (FormMultiWidget *widget : med.transTexts) + for (FormatTextEdit *te : widget->getEditors()) te->setVisualizeWhitespace(value); } } @@ -898,9 +912,9 @@ void MessageEditor::applyFontSize() m_pluralSource->getEditor()->setFont(font); m_commentText->getEditor()->setFont(font); - foreach (MessageEditorData med, m_editors) { - for (int i = 0; i < med.transTexts.count(); ++i) - foreach (QTextEdit *te, med.transTexts[i]->getEditors()) + for (const MessageEditorData &med : qAsConst(m_editors)) { + for (FormMultiWidget *fmw : med.transTexts) + for (QTextEdit *te : fmw->getEditors()) te->setFont(font); med.transCommentText->getEditor()->setFont(font); } diff --git a/src/linguist/linguist/messageeditor.h b/src/linguist/linguist/messageeditor.h index a4353becea..1a16ff1d5d 100644 --- a/src/linguist/linguist/messageeditor.h +++ b/src/linguist/linguist/messageeditor.h @@ -68,10 +68,10 @@ class MessageEditor : public QScrollArea void showNothing(); void showMessage(const MultiDataIndex &index); void setNumerusForms(int model, const QStringList &numerusForms); - bool eventFilter(QObject *, QEvent *); - void setTranslation(int model, const QString &translation, int numerus); + bool eventFilter(QObject *, QEvent *) override; + void setNumerusTranslation(int model, const QString &translation, int numerus); int activeModel() const { return (m_editors.count() != 1) ? m_currentModel : 0; } - void setEditorFocus(int model); + void setEditorFocusForModel(int model); void setUnfinishedEditorFocus(); bool focusNextUnfinished(); void setVisualizeWhitespace(bool value); diff --git a/src/linguist/linguist/messageeditorwidgets.cpp b/src/linguist/linguist/messageeditorwidgets.cpp index 6c16b36fd1..d869fe31ab 100644 --- a/src/linguist/linguist/messageeditorwidgets.cpp +++ b/src/linguist/linguist/messageeditorwidgets.cpp @@ -58,8 +58,10 @@ ExpandingTextEdit::ExpandingTextEdit(QWidget *parent) setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); QAbstractTextDocumentLayout *docLayout = document()->documentLayout(); - connect(docLayout, SIGNAL(documentSizeChanged(QSizeF)), SLOT(updateHeight(QSizeF))); - connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(reallyEnsureCursorVisible())); + connect(docLayout, &QAbstractTextDocumentLayout::documentSizeChanged, + this, &ExpandingTextEdit::updateHeight); + connect(this, &QTextEdit::cursorPositionChanged, + this, &ExpandingTextEdit::reallyEnsureCursorVisible); m_minimumHeight = qRound(docLayout->documentSize().height()) + frameWidth() * 2; } @@ -187,9 +189,12 @@ FormWidget::FormWidget(const QString &label, bool isEditable, QWidget *parent) setLayout(layout); - connect(m_editor, SIGNAL(textChanged()), SLOT(slotTextChanged())); - connect(m_editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged())); - connect(m_editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged())); + connect(m_editor, &QTextEdit::textChanged, + this, &FormWidget::slotTextChanged); + connect(m_editor, &QTextEdit::selectionChanged, + this, &FormWidget::slotSelectionChanged); + connect(m_editor, &QTextEdit::cursorPositionChanged, + this, &FormWidget::cursorPositionChanged); } void FormWidget::slotTextChanged() @@ -233,7 +238,7 @@ class ButtonWrapper : public QWidget } protected: - virtual bool eventFilter(QObject *object, QEvent *event) + bool eventFilter(QObject *object, QEvent *event) override { if (event->type() == QEvent::Resize) { QWidget *relator = static_cast(object); @@ -257,16 +262,15 @@ FormMultiWidget::FormMultiWidget(const QString &label, QWidget *parent) m_label->setText(label); m_plusButtons.append( - new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), 0)); + new ButtonWrapper(makeButton(m_plusIcon, &FormMultiWidget::plusButtonClicked), 0)); } -QAbstractButton *FormMultiWidget::makeButton(const QIcon &icon, const char *slot) +QAbstractButton *FormMultiWidget::makeButton(const QIcon &icon) { QAbstractButton *btn = new QToolButton(this); btn->setIcon(icon); btn->setFixedSize(icon.availableSizes().first() /* + something */); btn->setFocusPolicy(Qt::NoFocus); - connect(btn, SIGNAL(clicked()), slot); return btn; } @@ -275,13 +279,16 @@ void FormMultiWidget::addEditor(int idx) FormatTextEdit *editor = new FormatTextEdit(this); m_editors.insert(idx, editor); - m_minusButtons.insert(idx, makeButton(m_minusIcon, SLOT(minusButtonClicked()))); + m_minusButtons.insert(idx, makeButton(m_minusIcon, &FormMultiWidget::minusButtonClicked)); m_plusButtons.insert(idx + 1, - new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), editor)); - - connect(editor, SIGNAL(textChanged()), SLOT(slotTextChanged())); - connect(editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged())); - connect(editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged())); + new ButtonWrapper(makeButton(m_plusIcon, &FormMultiWidget::plusButtonClicked), editor)); + + connect(editor, &QTextEdit::textChanged, + this, &FormMultiWidget::slotTextChanged); + connect(editor, &QTextEdit::selectionChanged, + this, &FormMultiWidget::slotSelectionChanged); + connect(editor, &QTextEdit::cursorPositionChanged, + this, &FormMultiWidget::cursorPositionChanged); editor->installEventFilter(this); emit editorCreated(editor); @@ -372,7 +379,7 @@ void FormMultiWidget::slotSelectionChanged() void FormMultiWidget::setTranslation(const QString &text, bool userAction) { - QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), QString::KeepEmptyParts); + QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), Qt::KeepEmptyParts); while (m_editors.count() > texts.count()) { delete m_minusButtons.takeLast(); @@ -418,7 +425,7 @@ QString FormMultiWidget::getTranslation() const for (int i = 0; i < m_editors.count(); ++i) { if (i) ret += QChar(Translator::BinaryVariantSeparator); - ret += toPlainText(m_editors.at(i)->document()->docHandle()->plainText()); + ret += toPlainText(m_editors.at(i)->document()->toRawText()); } return ret; } diff --git a/src/linguist/linguist/messageeditorwidgets.h b/src/linguist/linguist/messageeditorwidgets.h index 0e17af518e..508021b609 100644 --- a/src/linguist/linguist/messageeditorwidgets.h +++ b/src/linguist/linguist/messageeditorwidgets.h @@ -29,6 +29,7 @@ #ifndef MESSAGEEDITORWIDGETS_H #define MESSAGEEDITORWIDGETS_H +#include #include #include #include @@ -39,7 +40,6 @@ QT_BEGIN_NAMESPACE -class QAbstractButton; class QAction; class QContextMenuEvent; class QKeyEvent; @@ -59,8 +59,8 @@ class ExpandingTextEdit : public QTextEdit public: ExpandingTextEdit(QWidget *parent = 0); - QSize sizeHint() const; - QSize minimumSizeHint() const; + QSize sizeHint() const override; + QSize minimumSizeHint() const override; private slots: void updateHeight(const QSizeF &documentSize); @@ -147,7 +147,7 @@ class FormMultiWidget : public QWidget void cursorPositionChanged(); protected: - bool eventFilter(QObject *watched, QEvent *event); + bool eventFilter(QObject *watched, QEvent *event) override; private slots: void slotTextChanged(); @@ -158,7 +158,16 @@ private slots: private: void addEditor(int idx); void updateLayout(); - QAbstractButton *makeButton(const QIcon &icon, const char *slot); + + template + QAbstractButton *makeButton(const QIcon &icon, Func slot) + { + auto *button = makeButton(icon); + connect(button, &QAbstractButton::clicked, + this, slot); + return button; + } + QAbstractButton *makeButton(const QIcon &icon); void insertEditor(int idx); void deleteEditor(int idx); diff --git a/src/linguist/linguist/messagehighlighter.h b/src/linguist/linguist/messagehighlighter.h index 5b9221939f..861ee844bd 100644 --- a/src/linguist/linguist/messagehighlighter.h +++ b/src/linguist/linguist/messagehighlighter.h @@ -44,7 +44,7 @@ class MessageHighlighter : public QSyntaxHighlighter MessageHighlighter(QTextEdit *textEdit); protected: - void highlightBlock(const QString &text); + void highlightBlock(const QString &text) override; private: enum Construct { diff --git a/src/linguist/linguist/messagemodel.cpp b/src/linguist/linguist/messagemodel.cpp index 74c49cf832..faa4b2a0a8 100644 --- a/src/linguist/linguist/messagemodel.cpp +++ b/src/linguist/linguist/messagemodel.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "messagemodel.h" +#include "statistics.h" #include #include @@ -202,18 +203,18 @@ bool DataModel::load(const QString &fileName, bool *langGuessed, QWidget *parent return false; } - Translator::Duplicates dupes = tor.resolveDuplicates(); + const Translator::Duplicates dupes = tor.resolveDuplicates(); if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) { QString err = tr("Duplicate messages found in '%1':").arg(fileName.toHtmlEscaped()); int numdups = 0; - foreach (int i, dupes.byId) { + for (int i : dupes.byId) { if (++numdups >= 5) { err += tr("

[more duplicates omitted]"); goto doWarn; } err += tr("

* ID: %1").arg(tor.message(i).id().toHtmlEscaped()); } - foreach (int j, dupes.byContents) { + for (int j : dupes.byContents) { const TranslatorMessage &msg = tor.message(j); if (++numdups >= 5) { err += tr("

[more duplicates omitted]"); @@ -240,7 +241,7 @@ bool DataModel::load(const QString &fileName, bool *langGuessed, QWidget *parent m_srcChars = 0; m_srcCharsSpc = 0; - foreach (const TranslatorMessage &msg, tor.messages()) { + for (const TranslatorMessage &msg : tor.messages()) { if (!contexts.contains(msg.context())) { contexts.insert(msg.context(), m_contextList.size()); m_contextList.append(ContextItem(msg.context())); @@ -426,20 +427,37 @@ void DataModel::setSourceLanguageAndCountry(QLocale::Language lang, QLocale::Cou void DataModel::updateStatistics() { - int trW = 0; - int trC = 0; - int trCS = 0; - + StatisticalData stats {}; for (DataModelIterator it(this); it.isValid(); ++it) { const MessageItem *mi = it.current(); - if (mi->isFinished()) { - const QStringList translations = mi->translations(); - for (const QString &trnsl : translations) - doCharCounting(trnsl, trW, trC, trCS); + if (mi->isObsolete()) { + stats.obsoleteMsg++; + } else if (mi->isFinished()) { + bool hasDanger = false; + for (const QString &trnsl : mi->translations()) { + doCharCounting(trnsl, stats.wordsFinished, stats.charsFinished, stats.charsSpacesFinished); + hasDanger |= mi->danger(); + } + if (hasDanger) + stats.translatedMsgDanger++; + else + stats.translatedMsgNoDanger++; + } else if (mi->isUnfinished()) { + bool hasDanger = false; + for (const QString &trnsl : mi->translations()) { + doCharCounting(trnsl, stats.wordsUnfinished, stats.charsUnfinished, stats.charsSpacesUnfinished); + hasDanger |= mi->danger(); + } + if (hasDanger) + stats.unfinishedMsgDanger++; + else + stats.unfinishedMsgNoDanger++; } } - - emit statsChanged(m_srcWords, m_srcChars, m_srcCharsSpc, trW, trC, trCS); + stats.wordsSource = m_srcWords; + stats.charsSource = m_srcChars; + stats.charsSpacesSource = m_srcCharsSpc; + emit statsChanged(stats); } void DataModel::setModified(bool isModified) @@ -591,7 +609,7 @@ void MultiContextItem::appendMessageItems(const QList &m) for (int i = 0; i < m_messageLists.count() - 1; ++i) m_messageLists[i] += nullItems; m_messageLists.last() += m; - foreach (MessageItem *mi, m) + for (MessageItem *mi : m) m_multiMessageList.append(MultiMessageItem(mi)); } @@ -769,9 +787,12 @@ void MultiDataModel::append(DataModel *dm, bool readWrite) } dm->setWritable(readWrite); updateCountsOnAdd(modelCount() - 1, readWrite); - connect(dm, SIGNAL(modifiedChanged()), SLOT(onModifiedChanged())); - connect(dm, SIGNAL(languageChanged()), SLOT(onLanguageChanged())); - connect(dm, SIGNAL(statsChanged(int,int,int,int,int,int)), SIGNAL(statsChanged(int,int,int,int,int,int))); + connect(dm, &DataModel::modifiedChanged, + this, &MultiDataModel::onModifiedChanged); + connect(dm, &DataModel::languageChanged, + this, &MultiDataModel::onLanguageChanged); + connect(dm, &DataModel::statsChanged, + this, &MultiDataModel::statsChanged); emit modelAppended(); } @@ -839,7 +860,7 @@ QStringList MultiDataModel::prettifyFileNames(const QStringList &names) { QStringList out; - foreach (const QString &name, names) + for (const QString &name : names) out << DataModel::prettifyFileName(name); return out; } @@ -904,7 +925,7 @@ QString MultiDataModel::condenseFileNames(const QStringList &names) QStringList MultiDataModel::srcFileNames(bool pretty) const { QStringList names; - foreach (DataModel *dm, m_dataModels) + for (DataModel *dm : m_dataModels) names << (dm->isWritable() ? QString() : QString::fromLatin1("=")) + dm->srcFileName(pretty); return names; } @@ -916,7 +937,7 @@ QString MultiDataModel::condensedSrcFileNames(bool pretty) const bool MultiDataModel::isModified() const { - foreach (const DataModel *mdl, m_dataModels) + for (const DataModel *mdl : m_dataModels) if (mdl->isModified()) return true; return false; @@ -1182,12 +1203,12 @@ MessageModel::MessageModel(QObject *parent, MultiDataModel *data) : QAbstractItemModel(parent), m_data(data) { data->m_msgModel = this; - connect(m_data, SIGNAL(multiContextDataChanged(MultiDataIndex)), - SLOT(multiContextItemChanged(MultiDataIndex))); - connect(m_data, SIGNAL(contextDataChanged(MultiDataIndex)), - SLOT(contextItemChanged(MultiDataIndex))); - connect(m_data, SIGNAL(messageDataChanged(MultiDataIndex)), - SLOT(messageItemChanged(MultiDataIndex))); + connect(m_data, &MultiDataModel::multiContextDataChanged, + this, &MessageModel::multiContextItemChanged); + connect(m_data, &MultiDataModel::contextDataChanged, + this, &MessageModel::contextItemChanged); + connect(m_data, &MultiDataModel::messageDataChanged, + this, &MessageModel::messageItemChanged); } QModelIndex MessageModel::index(int row, int column, const QModelIndex &parent) const diff --git a/src/linguist/linguist/messagemodel.h b/src/linguist/linguist/messagemodel.h index 5c2d95ec20..3eadf5193f 100644 --- a/src/linguist/linguist/messagemodel.h +++ b/src/linguist/linguist/messagemodel.h @@ -37,13 +37,12 @@ #include #include #include -#include - QT_BEGIN_NAMESPACE class DataModel; class MultiDataModel; +struct StatisticalData; class MessageItem { @@ -75,6 +74,7 @@ class MessageItem void setType(TranslatorMessage::Type type) { m_message.setType(type); } bool isFinished() const { return type() == TranslatorMessage::Finished; } + bool isUnfinished() const { return type() == TranslatorMessage::Unfinished; } bool isObsolete() const { return type() == TranslatorMessage::Obsolete || type() == TranslatorMessage::Vanished; } const TranslatorMessage &message() const { return m_message; } @@ -219,7 +219,7 @@ class DataModel : public QObject int getSrcCharsSpc() const { return m_srcCharsSpc; } signals: - void statsChanged(int words, int characters, int cs, int words2, int characters2, int cs2); + void statsChanged(const StatisticalData &newStats); void progressChanged(int finishedCount, int oldFinishedCount); void languageChanged(); void modifiedChanged(); @@ -446,7 +446,7 @@ class MultiDataModel : public QObject void modelDeleted(int model); void allModelsDeleted(); void languageChanged(int model); - void statsChanged(int words, int characters, int cs, int words2, int characters2, int cs2); + void statsChanged(const StatisticalData &newStats); void modifiedChanged(bool); void multiContextDataChanged(const MultiDataIndex &index); void contextDataChanged(const MultiDataIndex &index); @@ -496,11 +496,11 @@ class MessageModel : public QAbstractItemModel MessageModel(QObject *parent, MultiDataModel *data); // QAbstractItemModel - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex& index) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex& index) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // Convenience MultiDataIndex dataIndex(const QModelIndex &index, int model) const; diff --git a/src/linguist/linguist/phrase.cpp b/src/linguist/linguist/phrase.cpp index b7b9835f5f..1d4688d4da 100644 --- a/src/linguist/linguist/phrase.cpp +++ b/src/linguist/linguist/phrase.cpp @@ -28,17 +28,14 @@ #include "phrase.h" #include "translator.h" +#include "xmlparser.h" #include #include #include #include -#include -#include #include -#include -#include -#include +#include QT_BEGIN_NAMESPACE @@ -104,24 +101,26 @@ bool operator==(const Phrase &p, const Phrase &q) p.definition() == q.definition() && p.phraseBook() == q.phraseBook(); } -class QphHandler : public QXmlDefaultHandler +class QphHandler : public XmlParser { public: - QphHandler(PhraseBook *phraseBook) - : pb(phraseBook), ferrorCount(0) { } - - virtual bool startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, - const QXmlAttributes &atts); - virtual bool endElement(const QString &namespaceURI, - const QString &localName, const QString &qName); - virtual bool characters(const QString &ch); - virtual bool fatalError(const QXmlParseException &exception); + QphHandler(PhraseBook *phraseBook, QXmlStreamReader &reader) + : XmlParser(reader), pb(phraseBook), ferrorCount(0) + { + } + ~QphHandler() override = default; QString language() const { return m_language; } QString sourceLanguage() const { return m_sourceLanguage; } private: + bool startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) override; + bool endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) override; + bool characters(QStringView ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; + PhraseBook *pb; QString source; QString target; @@ -133,14 +132,15 @@ class QphHandler : public QXmlDefaultHandler int ferrorCount; }; -bool QphHandler::startElement(const QString & /* namespaceURI */, - const QString & /* localName */, - const QString &qName, - const QXmlAttributes &atts) +bool QphHandler::startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) { + Q_UNUSED(namespaceURI); + Q_UNUSED(localName); + if (qName == QLatin1String("QPH")) { - m_language = atts.value(QLatin1String("language")); - m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")); + m_language = atts.value(QLatin1String("language")).toString(); + m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")).toString(); } else if (qName == QLatin1String("phrase")) { source.truncate(0); target.truncate(0); @@ -150,10 +150,12 @@ bool QphHandler::startElement(const QString & /* namespaceURI */, return true; } -bool QphHandler::endElement(const QString & /* namespaceURI */, - const QString & /* localName */, - const QString &qName) +bool QphHandler::endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) { + Q_UNUSED(namespaceURI); + Q_UNUSED(localName); + if (qName == QLatin1String("source")) source = accum; else if (qName == QLatin1String("target")) @@ -165,20 +167,20 @@ bool QphHandler::endElement(const QString & /* namespaceURI */, return true; } -bool QphHandler::characters(const QString &ch) +bool QphHandler::characters(QStringView ch) { accum += ch; return true; } -bool QphHandler::fatalError(const QXmlParseException &exception) +bool QphHandler::fatalError(qint64 line, qint64 column, const QString &message) { if (ferrorCount++ == 0) { QString msg = PhraseBook::tr("Parse error at line %1, column %2 (%3).") - .arg(exception.lineNumber()).arg(exception.columnNumber()) - .arg(exception.message()); - QMessageBox::information(0, - QObject::tr("Qt Linguist"), msg); + .arg(line) + .arg(column) + .arg(message); + QMessageBox::information(nullptr, QObject::tr("Qt Linguist"), msg); } return false; } @@ -223,20 +225,10 @@ bool PhraseBook::load(const QString &fileName, bool *langGuessed) m_fileName = fileName; - QXmlInputSource in(&f); - QXmlSimpleReader reader; - // don't click on these! - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); - reader.setFeature(QLatin1String("http://trolltech.com/xml/features/report-whitespace" - "-only-CharData"), false); - QphHandler *hand = new QphHandler(this); - reader.setContentHandler(hand); - reader.setErrorHandler(hand); - - bool ok = reader.parse(in); - reader.setContentHandler(0); - reader.setErrorHandler(0); + QXmlStreamReader reader(&f); + QphHandler *hand = new QphHandler(this, reader); + reader.setNamespaceProcessing(false); + bool ok = hand->parse(); Translator::languageAndCountry(hand->language(), &m_language, &m_country); *langGuessed = false; @@ -276,7 +268,6 @@ bool PhraseBook::save(const QString &fileName) m_fileName = fileName; QTextStream t(&f); - t.setCodec( QTextCodec::codecForName("UTF-8") ); t << "\n\n"; - foreach (Phrase *p, m_phrases) { + for (Phrase *p : qAsConst(m_phrases)) { t << "\n"; t << " " << protect( p->source() ) << "\n"; t << " " << protect( p->target() ) << "\n"; diff --git a/src/linguist/linguist/phrasebookbox.cpp b/src/linguist/linguist/phrasebookbox.cpp index 035ca09ff0..60f8f25c47 100644 --- a/src/linguist/linguist/phrasebookbox.cpp +++ b/src/linguist/linguist/phrasebookbox.cpp @@ -68,25 +68,31 @@ PhraseBookBox::PhraseBookBox(PhraseBook *phraseBook, QWidget *parent) phraseList->header()->setDefaultSectionSize(150); phraseList->header()->setSectionResizeMode(QHeaderView::Interactive); - connect(sourceLed, SIGNAL(textChanged(QString)), - this, SLOT(sourceChanged(QString))); - connect(targetLed, SIGNAL(textChanged(QString)), - this, SLOT(targetChanged(QString))); - connect(definitionLed, SIGNAL(textChanged(QString)), - this, SLOT(definitionChanged(QString))); - connect(phraseList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), - this, SLOT(selectionChanged())); - connect(newBut, SIGNAL(clicked()), this, SLOT(newPhrase())); - connect(removeBut, SIGNAL(clicked()), this, SLOT(removePhrase())); - connect(settingsBut, SIGNAL(clicked()), this, SLOT(settings())); - connect(saveBut, SIGNAL(clicked()), this, SLOT(save())); - connect(m_phraseBook, SIGNAL(modifiedChanged(bool)), this, SLOT(setWindowModified(bool))); + connect(sourceLed, &QLineEdit::textChanged, + this, &PhraseBookBox::sourceChanged); + connect(targetLed, &QLineEdit::textChanged, + this, &PhraseBookBox::targetChanged); + connect(definitionLed, &QLineEdit::textChanged, + this, &PhraseBookBox::definitionChanged); + connect(phraseList->selectionModel(), &QItemSelectionModel::currentChanged, + this, &PhraseBookBox::selectionChanged); + connect(newBut, &QAbstractButton::clicked, + this, &PhraseBookBox::newPhrase); + connect(removeBut, &QAbstractButton::clicked, + this, &PhraseBookBox::removePhrase); + connect(settingsBut, &QAbstractButton::clicked, + this, &PhraseBookBox::settings); + connect(saveBut, &QAbstractButton::clicked, + this, &PhraseBookBox::save); + connect(m_phraseBook, &PhraseBook::modifiedChanged, + this, &PhraseBookBox::setWindowModified); sourceLed->installEventFilter(this); targetLed->installEventFilter(this); definitionLed->installEventFilter(this); - foreach (Phrase *p, phraseBook->phrases()) + const auto phrases = phraseBook->phrases(); + for (Phrase *p : phrases) phrMdl->addPhrase(p); phraseList->sortByColumn(0, Qt::AscendingOrder); diff --git a/src/linguist/linguist/phrasebookbox.h b/src/linguist/linguist/phrasebookbox.h index 118c90a155..85a71d8358 100644 --- a/src/linguist/linguist/phrasebookbox.h +++ b/src/linguist/linguist/phrasebookbox.h @@ -47,7 +47,7 @@ class PhraseBookBox : public QDialog, public Ui::PhraseBookBox PhraseBookBox(PhraseBook *phraseBook, QWidget *parent = 0); protected: - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; private slots: void newPhrase(); diff --git a/src/linguist/linguist/phrasemodel.cpp b/src/linguist/linguist/phrasemodel.cpp index afd880cc10..8a820e1ce6 100644 --- a/src/linguist/linguist/phrasemodel.cpp +++ b/src/linguist/linguist/phrasemodel.cpp @@ -116,7 +116,7 @@ QVariant PhraseModel::headerData(int section, Qt::Orientation orientation, int r Qt::ItemFlags PhraseModel::flags(const QModelIndex &index) const { if (!index.isValid()) - return 0; + return {}; Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; // Edit is allowed for source & translation if item is from phrasebook if (plist.at(index.row())->phraseBook() diff --git a/src/linguist/linguist/phrasemodel.h b/src/linguist/linguist/phrasemodel.h index 190ac2e024..8fc165386c 100644 --- a/src/linguist/linguist/phrasemodel.h +++ b/src/linguist/linguist/phrasemodel.h @@ -54,22 +54,22 @@ class PhraseModel : public QAbstractTableModel Phrase *phrase(const QModelIndex &index) const; void setPhrase(const QModelIndex &indx, Phrase *ph); QModelIndex index(Phrase * const phr) const; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override { return QAbstractTableModel::index(row, column, parent); } // from qabstracttablemodel - int rowCount(const QModelIndex &) const; - int columnCount(const QModelIndex &) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int rowCount(const QModelIndex &) const override; + int columnCount(const QModelIndex &) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const; - Qt::ItemFlags flags(const QModelIndex &index) const; + int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole); + int role = Qt::EditRole) override; // HACK: This model will be displayed in a _TreeView_ // which has a tendency to expand 'children' on double click - bool hasChildren(const QModelIndex &parent) const + bool hasChildren(const QModelIndex &parent) const override { return !parent.isValid(); } private: diff --git a/src/linguist/linguist/phraseview.cpp b/src/linguist/linguist/phraseview.cpp index b0199fc16d..b145b6fc98 100644 --- a/src/linguist/linguist/phraseview.cpp +++ b/src/linguist/linguist/phraseview.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -67,14 +68,19 @@ PhraseView::PhraseView(MultiDataModel *model, QList(int(Qt::Key_1) + i); + auto shortCut = new QShortcut(Qt::CTRL | key, this); + connect(shortCut, &QShortcut::activated, this, + [i, this]() { this->guessShortcut(i); }); + } header()->setSectionResizeMode(QHeaderView::Interactive); header()->setSectionsClickable(true); header()->restoreState(QSettings().value(phraseViewHeaderKey()).toByteArray()); - connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(selectPhrase(QModelIndex))); + connect(this, &QAbstractItemView::activated, + this, &PhraseView::selectPhrase); } PhraseView::~PhraseView() @@ -104,15 +110,18 @@ void PhraseView::contextMenuEvent(QContextMenuEvent *event) QMenu *contextMenu = new QMenu(this); QAction *insertAction = new QAction(tr("Insert"), contextMenu); - connect(insertAction, SIGNAL(triggered()), this, SLOT(selectPhrase())); + connect(insertAction, &QAction::triggered, + this, &PhraseView::selectCurrentPhrase); QAction *editAction = new QAction(tr("Edit"), contextMenu); - connect(editAction, SIGNAL(triggered()), this, SLOT(editPhrase())); + connect(editAction, &QAction::triggered, + this, &PhraseView::editPhrase); Qt::ItemFlags isFromPhraseBook = model()->flags(index) & Qt::ItemIsEditable; editAction->setEnabled(isFromPhraseBook); QAction *gotoAction = new QAction(tr("Go to"), contextMenu); - connect(gotoAction, SIGNAL(triggered()), this, SLOT(gotoMessageFromGuess())); + connect(gotoAction, &QAction::triggered, + this, &PhraseView::gotoMessageFromGuess); gotoAction->setEnabled(!isFromPhraseBook); contextMenu->addAction(insertAction); @@ -135,7 +144,8 @@ void PhraseView::mouseDoubleClickEvent(QMouseEvent *event) void PhraseView::guessShortcut(int key) { - foreach (const Phrase *phrase, m_phraseModel->phraseList()) + const auto phrases = m_phraseModel->phraseList(); + for (const Phrase *phrase : phrases) if (phrase->shortcut() == key) { emit phraseSelected(m_modelIndex, phrase->target()); return; @@ -147,7 +157,7 @@ void PhraseView::selectPhrase(const QModelIndex &index) emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target()); } -void PhraseView::selectPhrase() +void PhraseView::selectCurrentPhrase() { emit phraseSelected(m_modelIndex, m_phraseModel->phrase(currentIndex())->target()); } @@ -245,14 +255,15 @@ void PhraseView::setSourceText(int model, const QString &sourceText) if (model < 0) return; - foreach (Phrase *p, getPhrases(model, sourceText)) + const auto phrases = getPhrases(model, sourceText); + for (Phrase *p : phrases) m_phraseModel->addPhrase(p); if (!sourceText.isEmpty() && m_doGuesses) { - CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model, + const CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model, sourceText.toLatin1(), m_maxCandidates); int n = 0; - foreach (const Candidate &candidate, cl) { + for (const Candidate &candidate : cl) { QString def; if (n < 9) def = tr("Guess from '%1' (%2)") @@ -271,12 +282,13 @@ void PhraseView::setSourceText(int model, const QString &sourceText) QList PhraseView::getPhrases(int model, const QString &source) { QList phrases; - QString f = MainWindow::friendlyString(source); - QStringList lookupWords = f.split(QLatin1Char(' ')); + const QString f = MainWindow::friendlyString(source); + const QStringList lookupWords = f.split(QLatin1Char(' ')); - foreach (const QString &s, lookupWords) { + for (const QString &s : lookupWords) { if (m_phraseDict->at(model).contains(s)) { - foreach (Phrase *p, m_phraseDict->at(model).value(s)) { + const auto phraseList = m_phraseDict->at(model).value(s); + for (Phrase *p : phraseList) { if (f.contains(MainWindow::friendlyString(p->source()))) phrases.append(p); } diff --git a/src/linguist/linguist/phraseview.h b/src/linguist/linguist/phraseview.h index 708105db3f..b21d284102 100644 --- a/src/linguist/linguist/phraseview.h +++ b/src/linguist/linguist/phraseview.h @@ -30,7 +30,6 @@ #define PHRASEVIEW_H #include -#include #include #include "phrase.h" @@ -41,28 +40,6 @@ static const int DefaultMaxCandidates = 5; class MultiDataModel; class PhraseModel; -class GuessShortcut : public QShortcut -{ - Q_OBJECT -public: - GuessShortcut(int nkey, QWidget *parent, const char *member) - : QShortcut(parent), nrkey(nkey) - { - setKey(Qt::CTRL + (Qt::Key_1 + nrkey)); - connect(this, SIGNAL(activated()), this, SLOT(keyActivated())); - connect(this, SIGNAL(activated(int)), parent, member); - } - -private slots: - void keyActivated() { emit activated(nrkey); } - -signals: - void activated(int nkey); - -private: - int nrkey; -}; - class PhraseView : public QTreeView { Q_OBJECT @@ -78,6 +55,9 @@ public slots: int getMaxCandidates() const { return m_maxCandidates; } void setMaxCandidates(const int max); static int getDefaultMaxCandidates() { return DefaultMaxCandidates; } + void moreGuesses(); + void fewerGuesses(); + void resetNumGuesses(); signals: void phraseSelected(int latestModel, const QString &phrase); @@ -86,19 +66,16 @@ public slots: protected: // QObject - virtual void contextMenuEvent(QContextMenuEvent *event); + void contextMenuEvent(QContextMenuEvent *event) override; // QAbstractItemView - virtual void mouseDoubleClickEvent(QMouseEvent *event); + void mouseDoubleClickEvent(QMouseEvent *event) override; private slots: void guessShortcut(int nkey); void selectPhrase(const QModelIndex &index); - void selectPhrase(); + void selectCurrentPhrase(); void editPhrase(); void gotoMessageFromGuess(); - void moreGuesses(); - void fewerGuesses(); - void resetNumGuesses(); private: QList getPhrases(int model, const QString &sourceText); diff --git a/src/linguist/linguist/recentfiles.cpp b/src/linguist/linguist/recentfiles.cpp index c39e44088a..57423dc268 100644 --- a/src/linguist/linguist/recentfiles.cpp +++ b/src/linguist/linguist/recentfiles.cpp @@ -50,7 +50,8 @@ RecentFiles::RecentFiles(const int maxEntries) { m_timer.setSingleShot(true); m_timer.setInterval(3 * 60 * 1000); - connect(&m_timer, SIGNAL(timeout()), SLOT(closeGroup())); + connect(&m_timer, &QTimer::timeout, + this, &RecentFiles::closeGroup); } /* @@ -114,18 +115,17 @@ void RecentFiles::readConfig() { m_strLists.clear(); QVariant val = QSettings().value(configKey()); - if (val.type() == QVariant::StringList) // Backwards compat to Qt < 4.5 - foreach (const QString &s, val.toStringList()) - m_strLists << QStringList(QFileInfo(s).canonicalFilePath()); - else - foreach (const QVariant &v, val.toList()) + if (val.metaType().id() == QMetaType::QVariantList) { + const auto list = val.toList(); + for (const QVariant &v : list) m_strLists << v.toStringList(); + } } void RecentFiles::writeConfig() const { QList vals; - foreach (const QStringList &sl, m_strLists) + for (const QStringList &sl : m_strLists) vals << sl; QSettings().setValue(configKey(), vals); } diff --git a/src/linguist/linguist/statistics.cpp b/src/linguist/linguist/statistics.cpp index e3f42f2ece..24dfeea2e4 100644 --- a/src/linguist/linguist/statistics.cpp +++ b/src/linguist/linguist/statistics.cpp @@ -41,14 +41,31 @@ void Statistics::languageChange() retranslateUi(this); } -void Statistics::updateStats(int sW,int sC,int sCS,int trW,int trC,int trCS) +void Statistics::updateStats(const StatisticalData& newStats) { - untrWords->setText(QString::number(sW)); - untrChars->setText(QString::number(sC)); - untrCharsSpc->setText(QString::number(sCS)); - trWords->setText(QString::number(trW)); - trChars->setText(QString::number(trC)); - trCharsSpc->setText(QString::number(trCS)); + int totals = newStats.translatedMsgDanger + newStats.translatedMsgNoDanger + + newStats.unfinishedMsgNoDanger + newStats.unfinishedMsgDanger; + int totalsWithObsolete = totals + newStats.obsoleteMsg; + int unfinished = newStats.unfinishedMsgDanger + newStats.unfinishedMsgNoDanger; + int finished = newStats.translatedMsgNoDanger + newStats.translatedMsgDanger; + + wordsSourceTextbox->setText(QString::number(newStats.wordsSource)); + charsSourceTextbox->setText(QString::number(newStats.charsSource)); + charsSpacesSourceTextbox->setText(QString::number(newStats.charsSpacesSource)); + wordsFinishedTextbox->setText(QString::number(newStats.wordsFinished)); + charsFinishedTextbox->setText(QString::number(newStats.charsFinished)); + charsSpacesFinishedTextbox->setText(QString::number(newStats.charsSpacesFinished)); + wordsUnfinishedTextbox->setText(QString::number(newStats.wordsUnfinished)); + charsUnfinishedTextbox->setText(QString::number(newStats.charsUnfinished)); + charsSpacesUnfinishedTextbox->setText(QString::number(newStats.charsSpacesUnfinished)); + totalMessagesTextbox->setText(QString::number(totals)); + totalWithObsoleteTextbox->setText(QString::number(totalsWithObsolete)); + totalFinishedTextbox->setText(QString::number(finished)); + finishedWithoutWarningsTextbox->setText(QString::number(newStats.translatedMsgNoDanger)); + finishedWithWarningsTextbox->setText(QString::number(newStats.translatedMsgDanger)); + unfinishedNoObsTextbox->setText(QString::number(unfinished)); + unfinishedNoWarningsTextbox->setText(QString::number(newStats.unfinishedMsgNoDanger)); + unfinishedWithWarningsTextbox->setText(QString::number(newStats.unfinishedMsgDanger)); } QT_END_NAMESPACE diff --git a/src/linguist/linguist/statistics.h b/src/linguist/linguist/statistics.h index 632332ffd8..8f8939201f 100644 --- a/src/linguist/linguist/statistics.h +++ b/src/linguist/linguist/statistics.h @@ -34,16 +34,34 @@ QT_BEGIN_NAMESPACE +struct StatisticalData +{ + int wordsSource; + int charsSource; + int charsSpacesSource; + int wordsFinished; + int charsFinished; + int charsSpacesFinished; + int wordsUnfinished; + int charsUnfinished; + int charsSpacesUnfinished; + int translatedMsgNoDanger; + int translatedMsgDanger; + int obsoleteMsg; + int unfinishedMsgNoDanger; + int unfinishedMsgDanger; +}; + class Statistics : public QDialog, public Ui::Statistics { Q_OBJECT public: - Statistics(QWidget *parent = 0, Qt::WindowFlags fl = 0); + Statistics(QWidget *parent = 0, Qt::WindowFlags fl = {}); ~Statistics() {} public slots: - virtual void updateStats(int w1, int c1, int cs1, int w2, int c2, int cs2); + virtual void updateStats(const StatisticalData &newStats); protected slots: virtual void languageChange(); diff --git a/src/linguist/linguist/statistics.ui b/src/linguist/linguist/statistics.ui index aaf70d7ab4..68798c43a9 100644 --- a/src/linguist/linguist/statistics.ui +++ b/src/linguist/linguist/statistics.ui @@ -33,15 +33,15 @@ 0 0 - 336 - 169 + 422 + 386 Statistics - + @@ -107,64 +107,234 @@ - - + + + + Unfinished + + + + + 0 - - + + 0 - + + + + 0 + + + + Words: - - + + 0 - - + + 0 - + + + + 0 + + + + Characters: - + Characters (with spaces): - - + + + + 0 + + + + + + + 0 + + + + + + + 0 + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Total translatable messages: + + + + + + + Total finished: + + + 15 + + + + + + + Without warnings: + + + 30 + + + + + + + With warnings: + + + 30 + + + + + + + Unfinished: + + + 15 + + + + + + + Without warnings: + + + 30 + + + + + + + With warnings: + + + 30 + + + + + + + Total messages including obsolete: + + + + + + + 0 + + + + + + + 0 + + + + + 0 - + + + 0 + + + + + + + 0 + + + + + + + 0 + + + + + + + 0 + + + + + 0 diff --git a/src/linguist/linguist/translatedialog.cpp b/src/linguist/linguist/translatedialog.cpp index 2dc9552544..bb52be371d 100644 --- a/src/linguist/linguist/translatedialog.cpp +++ b/src/linguist/linguist/translatedialog.cpp @@ -34,11 +34,16 @@ TranslateDialog::TranslateDialog(QWidget *parent) : QDialog(parent) { m_ui.setupUi(this); - connect(m_ui.findNxt, SIGNAL(clicked()), this, SLOT(emitFindNext())); - connect(m_ui.translate, SIGNAL(clicked()), this, SLOT(emitTranslateAndFindNext())); - connect(m_ui.translateAll, SIGNAL(clicked()), this, SLOT(emitTranslateAll())); - connect(m_ui.ledFindWhat, SIGNAL(textChanged(QString)), SLOT(verifyText())); - connect(m_ui.ckMatchCase, SIGNAL(toggled(bool)), SLOT(verifyText())); + connect(m_ui.findNxt, &QAbstractButton::clicked, + this, &TranslateDialog::emitFindNext); + connect(m_ui.translate, &QAbstractButton::clicked, + this, &TranslateDialog::emitTranslateAndFindNext); + connect(m_ui.translateAll, &QAbstractButton::clicked, + this, &TranslateDialog::emitTranslateAll); + connect(m_ui.ledFindWhat, &QLineEdit::textChanged, + this, &TranslateDialog::verifyText); + connect(m_ui.ckMatchCase, &QAbstractButton::toggled, + this, &TranslateDialog::verifyText); } void TranslateDialog::showEvent(QShowEvent *) diff --git a/src/linguist/linguist/translatedialog.h b/src/linguist/linguist/translatedialog.h index c3887fa7ad..fb086c8a4a 100644 --- a/src/linguist/linguist/translatedialog.h +++ b/src/linguist/linguist/translatedialog.h @@ -58,7 +58,7 @@ class TranslateDialog : public QDialog void activated(int mode); protected: - virtual void showEvent(QShowEvent *event); + void showEvent(QShowEvent *event) override; private slots: void emitFindNext(); diff --git a/src/linguist/linguist/translationsettingsdialog.cpp b/src/linguist/linguist/translationsettingsdialog.cpp index 5c567e59a0..919258c6e9 100644 --- a/src/linguist/linguist/translationsettingsdialog.cpp +++ b/src/linguist/linguist/translationsettingsdialog.cpp @@ -79,7 +79,7 @@ static void fillCountryCombo(const QVariant &lng, QComboBox *combo) combo->clear(); QLocale::Language lang = QLocale::Language(lng.toInt()); if (lang != QLocale::C) { - foreach (QLocale::Country cntr, QLocale::countriesForLanguage(lang)) { + for (QLocale::Country cntr : QLocale::countriesForLanguage(lang)) { QString country = QLocale::countryToString(cntr); auto loc = QLocale(lang, cntr); if (loc.language() != QLocale::English) { diff --git a/src/linguist/linguist/translationsettingsdialog.h b/src/linguist/linguist/translationsettingsdialog.h index 7e3f2b22e7..33340ea6f3 100644 --- a/src/linguist/linguist/translationsettingsdialog.h +++ b/src/linguist/linguist/translationsettingsdialog.h @@ -49,7 +49,7 @@ class TranslationSettingsDialog : public QDialog void setPhraseBook(PhraseBook *phraseBook); private: - virtual void showEvent(QShowEvent *e); + void showEvent(QShowEvent *e) override; private slots: void on_buttonBox_accepted(); diff --git a/src/linguist/lprodump/CMakeLists.txt b/src/linguist/lprodump/CMakeLists.txt new file mode 100644 index 0000000000..93879861ab --- /dev/null +++ b/src/linguist/lprodump/CMakeLists.txt @@ -0,0 +1,56 @@ +# Generated from lprodump.pro. + +##################################################################### +## lprodump Tool: +##################################################################### + +qt_get_tool_target_name(target_name lprodump) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Linguist QMake Project Dump Tool" + TOOLS_TARGET Linguist # special case + INSTALL_DIR "${INSTALL_LIBEXECDIR}" + SOURCES + ../shared/ioutils.cpp ../shared/ioutils.h + ../shared/profileevaluator.cpp ../shared/profileevaluator.h + ../shared/proitems.cpp ../shared/proitems.h + ../shared/qmake_global.h + ../shared/qmakebuiltins.cpp + ../shared/qmakeevaluator.cpp ../shared/qmakeevaluator.h ../shared/qmakeevaluator_p.h + ../shared/qmakeglobals.cpp ../shared/qmakeglobals.h + ../shared/qmakeparser.cpp ../shared/qmakeparser.h + ../shared/qmakevfs.cpp ../shared/qmakevfs.h + ../shared/qrcreader.cpp ../shared/qrcreader.h + main.cpp + DEFINES + PROEVALUATOR_CUMULATIVE + PROEVALUATOR_DEBUG + PROEVALUATOR_INIT_PROPS + QMAKE_BUILTIN_PRFS + QMAKE_OVERRIDE_PRFS + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared +) + +# Resources: +set(proparser_resource_files + "../shared/exclusive_builds.prf" +) + +qt_internal_add_resource(${target_name} "proparser" + PREFIX + "/qmake/override_features" + BASE + "../shared" + FILES + ${proparser_resource_files} +) + + +#### Keys ignored in scope 1:.:.:lprodump.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Linguist QMake Project Dump Tool" +# QT_TOOL_ENV = "qmake" +# _OPTION = "host_build" +# qmake.name = "QMAKE" +# qmake.value = "$$shell_path($$QMAKE_QMAKE)" diff --git a/src/linguist/lprodump/lprodump.pro b/src/linguist/lprodump/lprodump.pro deleted file mode 100644 index a1bcace55d..0000000000 --- a/src/linguist/lprodump/lprodump.pro +++ /dev/null @@ -1,22 +0,0 @@ -option(host_build) -QT = core - -DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII - -include(../shared/proparser.pri) - -DEFINES += PROEVALUATOR_DEBUG - -HEADERS += \ - ../shared/qrcreader.h - -SOURCES += \ - ../shared/qrcreader.cpp \ - main.cpp - -qmake.name = QMAKE -qmake.value = $$shell_path($$QMAKE_QMAKE) -QT_TOOL_ENV += qmake - -QMAKE_TARGET_DESCRIPTION = "Qt Linguist QMake Project Dump Tool" -load(qt_tool) diff --git a/src/linguist/lprodump/main.cpp b/src/linguist/lprodump/main.cpp index 857786beb6..d1d4f60e2f 100644 --- a/src/linguist/lprodump/main.cpp +++ b/src/linguist/lprodump/main.cpp @@ -38,7 +38,8 @@ #include #include #include -#include +#include +#include #include #include @@ -121,13 +122,13 @@ static void print(const QString &fileName, int lineNo, const QString &msg) class EvalHandler : public QMakeHandler { public: - virtual void message(int type, const QString &msg, const QString &fileName, int lineNo) + void message(int type, const QString &msg, const QString &fileName, int lineNo) override { if (verbose && !(type & CumulativeEvalMessage) && (type & CategoryMask) == ErrorMessage) print(fileName, lineNo, msg); } - virtual void fileMessage(int type, const QString &msg) + void fileMessage(int type, const QString &msg) override { if (verbose && !(type & CumulativeEvalMessage) && (type & CategoryMask) == ErrorMessage) { // "Downgrade" errors, as we don't really care for them @@ -135,8 +136,8 @@ class EvalHandler : public QMakeHandler { } } - virtual void aboutToEval(ProFile *, ProFile *, EvalFileType) {} - virtual void doneWithEval(ProFile *) {} + void aboutToEval(ProFile *, ProFile *, EvalFileType) override {} + void doneWithEval(ProFile *) override {} bool verbose = true; }; @@ -195,16 +196,16 @@ static QStringList getSources(const ProFileEvaluator &visitor, const QString &pr sourceFiles += getSources("FORMS", "VPATH_FORMS", baseVPaths, projectDir, visitor); - QStringList resourceFiles = getSources("RESOURCES", "VPATH_RESOURCES", baseVPaths, projectDir, visitor); - foreach (const QString &resource, resourceFiles) + const QStringList resourceFiles = getSources("RESOURCES", "VPATH_RESOURCES", baseVPaths, projectDir, visitor); + for (const QString &resource : resourceFiles) sourceFiles += getResources(resource, vfs); QStringList installs = visitor.values(QLatin1String("INSTALLS")) + visitor.values(QLatin1String("DEPLOYMENT")); installs.removeDuplicates(); QDir baseDir(projectDir); - foreach (const QString inst, installs) { - foreach (const QString &file, visitor.values(inst + QLatin1String(".files"))) { + for (const QString &inst : qAsConst(installs)) { + for (const QString &file : visitor.values(inst + QLatin1String(".files"))) { QFileInfo info(file); if (!info.isAbsolute()) info.setFile(baseDir.absoluteFilePath(file)); @@ -233,11 +234,11 @@ static QStringList getSources(const ProFileEvaluator &visitor, const QString &pr sourceFiles.removeDuplicates(); sourceFiles.sort(); - foreach (const QString &ex, excludes) { + for (const QString &ex : excludes) { // TODO: take advantage of the file list being sorted - QRegExp rx(ex, Qt::CaseSensitive, QRegExp::Wildcard); - for (QStringList::Iterator it = sourceFiles.begin(); it != sourceFiles.end(); ) { - if (rx.exactMatch(*it)) + QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(ex)); + for (auto it = sourceFiles.begin(); it != sourceFiles.end(); ) { + if (rx.match(*it).hasMatch()) it = sourceFiles.erase(it); else ++it; @@ -260,10 +261,10 @@ QStringList getExcludes(const ProFileEvaluator &visitor, const QString &projectD static void excludeProjects(const ProFileEvaluator &visitor, QStringList *subProjects) { - foreach (const QString &ex, visitor.values(QLatin1String("TR_EXCLUDE"))) { - QRegExp rx(ex, Qt::CaseSensitive, QRegExp::Wildcard); - for (QStringList::Iterator it = subProjects->begin(); it != subProjects->end(); ) { - if (rx.exactMatch(*it)) + for (const QString &ex : visitor.values(QLatin1String("TR_EXCLUDE"))) { + QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(ex)); + for (auto it = subProjects->begin(); it != subProjects->end(); ) { + if (rx.match(*it).hasMatch()) it = subProjects->erase(it); else ++it; @@ -289,7 +290,7 @@ static QJsonObject processProject(const QString &proFile, ProFileGlobals *option excludeProjects(visitor, &subProjects); QStringList subProFiles; QDir proDir(proPath); - foreach (const QString &subdir, subProjects) { + for (const QString &subdir : qAsConst(subProjects)) { QString realdir = visitor.value(subdir + QLatin1String(".subdir")); if (realdir.isEmpty()) realdir = visitor.value(subdir + QLatin1String(".file")); @@ -325,7 +326,7 @@ static QJsonArray processProjects(bool topLevel, const QStringList &proFiles, ProFileGlobals *option, QMakeVfs *vfs, QMakeParser *parser, bool *fail) { QJsonArray result; - foreach (const QString &proFile, proFiles) { + for (const QString &proFile : proFiles) { if (!outDirMap.isEmpty()) option->setDirectories(QFileInfo(proFile).path(), outDirMap[proFile]); @@ -356,6 +357,11 @@ static QJsonArray processProjects(bool topLevel, const QStringList &proFiles, tsFiles << proDir.filePath(tsFile); setValue(prj, "translations", tsFiles); } + if (visitor.contains(QLatin1String("LUPDATE_COMPILE_COMMANDS_PATH"))) { + const QStringList thepathjson = visitor.values( + QLatin1String("LUPDATE_COMPILE_COMMANDS_PATH")); + setValue(prj, "compileCommands", thepathjson.value(0)); + } result.append(prj); pro->deref(); } @@ -437,8 +443,10 @@ int main(int argc, char **argv) bool fail = false; ProFileGlobals option; option.qmake_abslocation = QString::fromLocal8Bit(qgetenv("QMAKE")); - if (option.qmake_abslocation.isEmpty()) - option.qmake_abslocation = app.applicationDirPath() + QLatin1String("/qmake"); + if (option.qmake_abslocation.isEmpty()) { + option.qmake_abslocation = QLibraryInfo::path(QLibraryInfo::BinariesPath) + + QLatin1String("/qmake"); + } option.debugLevel = proDebug; option.initProperties(); option.setCommandLineArguments(QDir::currentPath(), diff --git a/src/linguist/lrelease-pro/CMakeLists.txt b/src/linguist/lrelease-pro/CMakeLists.txt new file mode 100644 index 0000000000..b1c314ef04 --- /dev/null +++ b/src/linguist/lrelease-pro/CMakeLists.txt @@ -0,0 +1,27 @@ +# Generated from lrelease-pro.pro. + +##################################################################### +## lrelease-pro Tool: +##################################################################### + +qt_get_tool_target_name(target_name lrelease-pro) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Translation File Compiler for QMake Projects" + TOOLS_TARGET Linguist # special case + INSTALL_DIR "${INSTALL_LIBEXECDIR}" + SOURCES + ../shared/runqttool.cpp ../shared/runqttool.h + main.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared +) + +#### Keys ignored in scope 1:.:.:lrelease-pro.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Translation File Compiler for QMake Projects" +# QT_TOOL_ENV = "qmake" +# _OPTION = "host_build" +# qmake.name = "QMAKE" +# qmake.value = "$$shell_path($$QMAKE_QMAKE)" diff --git a/src/linguist/lrelease-pro/lrelease-pro.pro b/src/linguist/lrelease-pro/lrelease-pro.pro deleted file mode 100644 index 76b896d755..0000000000 --- a/src/linguist/lrelease-pro/lrelease-pro.pro +++ /dev/null @@ -1,19 +0,0 @@ -option(host_build) -QT = core -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - -HEADERS += \ - ../shared/runqttool.h - -SOURCES += \ - ../shared/runqttool.cpp \ - main.cpp - -INCLUDEPATH += ../shared - -qmake.name = QMAKE -qmake.value = $$shell_path($$QMAKE_QMAKE) -QT_TOOL_ENV += qmake - -QMAKE_TARGET_DESCRIPTION = "Qt Translation File Compiler for QMake Projects" -load(qt_tool) diff --git a/src/linguist/lrelease-pro/main.cpp b/src/linguist/lrelease-pro/main.cpp index 9f4ca259fe..bd20eea598 100644 --- a/src/linguist/lrelease-pro/main.cpp +++ b/src/linguist/lrelease-pro/main.cpp @@ -88,7 +88,7 @@ int main(int argc, char **argv) QTranslator translator; QTranslator qtTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) { app.installTranslator(&translator); diff --git a/src/linguist/lrelease/CMakeLists.txt b/src/linguist/lrelease/CMakeLists.txt new file mode 100644 index 0000000000..cea1b515d3 --- /dev/null +++ b/src/linguist/lrelease/CMakeLists.txt @@ -0,0 +1,42 @@ +# Generated from lrelease.pro. + +##################################################################### +## lrelease Tool: +##################################################################### + +qt_get_tool_target_name(target_name lrelease) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Translation File Compiler" + TOOLS_TARGET Linguist # special case + SOURCES + ../shared/numerus.cpp + ../shared/po.cpp + ../shared/projectdescriptionreader.cpp ../shared/projectdescriptionreader.h + ../shared/qm.cpp + ../shared/qph.cpp + ../shared/runqttool.cpp ../shared/runqttool.h + ../shared/translator.cpp ../shared/translator.h + ../shared/translatormessage.cpp ../shared/translatormessage.h + ../shared/ts.cpp + ../shared/xliff.cpp + ../shared/xmlparser.cpp ../shared/xmlparser.h + main.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared + PUBLIC_LIBRARIES + Qt::CorePrivate + # special case begin + EXTRA_CMAKE_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/../${QT_CMAKE_EXPORT_NAMESPACE}LinguistToolsMacros.cmake" + # special case end +) + +#### Keys ignored in scope 1:.:.:lrelease.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Translation File Compiler" +# QT_TOOL_ENV = "qmake" +# _OPTION = "host_build" +# qmake.name = "QMAKE" +# qmake.value = "$$shell_path($$QMAKE_QMAKE)" diff --git a/src/linguist/lrelease/lrelease.pro b/src/linguist/lrelease/lrelease.pro deleted file mode 100644 index fb457ac05f..0000000000 --- a/src/linguist/lrelease/lrelease.pro +++ /dev/null @@ -1,21 +0,0 @@ -option(host_build) -QT = core-private -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII - -HEADERS += \ - ../shared/projectdescriptionreader.h \ - ../shared/runqttool.h - -SOURCES += \ - ../shared/projectdescriptionreader.cpp \ - ../shared/runqttool.cpp \ - main.cpp - -include(../shared/formats.pri) - -qmake.name = QMAKE -qmake.value = $$shell_path($$QMAKE_QMAKE) -QT_TOOL_ENV += qmake - -QMAKE_TARGET_DESCRIPTION = "Qt Translation File Compiler" -load(qt_tool) diff --git a/src/linguist/lrelease/main.cpp b/src/linguist/lrelease/main.cpp index 7ef9afe1f5..95617a8a42 100644 --- a/src/linguist/lrelease/main.cpp +++ b/src/linguist/lrelease/main.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -165,7 +164,7 @@ static bool releaseTsFile(const QString& tsFileName, return false; QString qmFileName = tsFileName; - foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { + for (const Translator::FileFormat &fmt : qAsConst(Translator::registeredFileFormats())) { if (qmFileName.endsWith(QLatin1Char('.') + fmt.extension)) { qmFileName.chop(fmt.extension.length() + 1); break; @@ -180,7 +179,9 @@ static QStringList translationsFromProjects(const Projects &projects, bool topLe static QStringList translationsFromProject(const Project &project, bool topLevel) { - QStringList result = *project.translations; + QStringList result; + if (project.translations) + result = *project.translations; result << translationsFromProjects(project.subProjects, false); if (topLevel && result.isEmpty()) { printErr(LR::tr("lrelease warning: Met no 'TRANSLATIONS' entry in project file '%1'\n") @@ -205,7 +206,7 @@ int main(int argc, char **argv) QTranslator translator; QTranslator qtTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) { app.installTranslator(&translator); @@ -287,7 +288,7 @@ int main(int argc, char **argv) QString errorString; if (!extractProFiles(&inputFiles).isEmpty()) { - runQtTool(QStringLiteral("lrelease-pro"), app.arguments().mid(1)); + runInternalQtTool(QStringLiteral("lrelease-pro"), app.arguments().mid(1)); return 0; } @@ -304,7 +305,7 @@ int main(int argc, char **argv) inputFiles = translationsFromProjects(projectDescription); } - foreach (const QString &inputFile, inputFiles) { + for (const QString &inputFile : qAsConst(inputFiles)) { if (outputFile.isEmpty()) { if (!releaseTsFile(inputFile, cd, removeIdentical)) return 1; diff --git a/src/linguist/lupdate-pro/CMakeLists.txt b/src/linguist/lupdate-pro/CMakeLists.txt new file mode 100644 index 0000000000..104f6c96f8 --- /dev/null +++ b/src/linguist/lupdate-pro/CMakeLists.txt @@ -0,0 +1,33 @@ +# Generated from lupdate-pro.pro. + +##################################################################### +## lupdate-pro Tool: +##################################################################### + +qt_get_tool_target_name(target_name lupdate-pro) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Translation File Update Tool for QMake Projects" + TOOLS_TARGET Linguist # special case + INSTALL_DIR "${INSTALL_LIBEXECDIR}" + SOURCES + ../shared/runqttool.cpp ../shared/runqttool.h + main.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared +) + +#### Keys ignored in scope 1:.:.:lupdate-pro.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Translation File Update Tool for QMake Projects" +# QT_TOOL_ENV = "qmake" +# _OPTION = "host_build" +# qmake.name = "QMAKE" +# qmake.value = "$$shell_path($$QMAKE_QMAKE)" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:lupdate-pro.pro:MINGW: +# RC_FILE = "lupdate-pro.rc" diff --git a/src/linguist/lupdate-pro/lupdate-pro.pro b/src/linguist/lupdate-pro/lupdate-pro.pro deleted file mode 100644 index 49dac11c7f..0000000000 --- a/src/linguist/lupdate-pro/lupdate-pro.pro +++ /dev/null @@ -1,23 +0,0 @@ -option(host_build) -QT = core -DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII - -INCLUDEPATH += ../shared - -HEADERS += \ - ../shared/runqttool.h - -SOURCES += \ - ../shared/runqttool.cpp \ - main.cpp - -mingw { - RC_FILE = lupdate-pro.rc -} - -qmake.name = QMAKE -qmake.value = $$shell_path($$QMAKE_QMAKE) -QT_TOOL_ENV += qmake - -QMAKE_TARGET_DESCRIPTION = "Qt Translation File Update Tool for QMake Projects" -load(qt_tool) diff --git a/src/linguist/lupdate-pro/main.cpp b/src/linguist/lupdate-pro/main.cpp index ab5b7ebf8f..1910467f4c 100644 --- a/src/linguist/lupdate-pro/main.cpp +++ b/src/linguist/lupdate-pro/main.cpp @@ -89,7 +89,7 @@ int main(int argc, char **argv) QTranslator translator; QTranslator qtTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) { app.installTranslator(&translator); diff --git a/src/linguist/lupdate/CMakeLists.txt b/src/linguist/lupdate/CMakeLists.txt new file mode 100644 index 0000000000..0ce48917e1 --- /dev/null +++ b/src/linguist/lupdate/CMakeLists.txt @@ -0,0 +1,109 @@ +# Generated from lupdate.pro. + +# special case begin +if(CMAKE_VERSION VERSION_LESS "3.19" AND MSVC AND CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + message(WARNING "lupdate will not be built in this configuration.") + return() +endif() + +if (MINGW) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY _qt_skip_separate_debug_info ON) +endif() +# special case end + +##################################################################### +## lupdate Tool: +##################################################################### + +qt_get_tool_target_name(target_name lupdate) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Translation File Update Tool" + TOOLS_TARGET Linguist # special case + SOURCES + ../shared/numerus.cpp + ../shared/po.cpp + ../shared/projectdescriptionreader.cpp ../shared/projectdescriptionreader.h + ../shared/qm.cpp + ../shared/qph.cpp + ../shared/qrcreader.cpp ../shared/qrcreader.h + ../shared/runqttool.cpp ../shared/runqttool.h + ../shared/simtexth.cpp ../shared/simtexth.h + ../shared/translator.cpp ../shared/translator.h + ../shared/translatormessage.cpp ../shared/translatormessage.h + ../shared/ts.cpp + ../shared/xliff.cpp + ../shared/xmlparser.cpp ../shared/xmlparser.h + cpp.cpp cpp.h + java.cpp + lupdate.h + main.cpp + merge.cpp + ui.cpp + DEFINES + QT_NO_CAST_FROM_ASCII + QT_NO_CAST_TO_ASCII + INCLUDE_DIRECTORIES + ../shared + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Tools +) + +#### Keys ignored in scope 1:.:.:lupdate.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Translation File Update Tool" +# QT_TOOL_ENV = "qmake" +# _OPTION = "host_build" +# qmake.name = "QMAKE" +# qmake.value = "$$shell_path($$QMAKE_QMAKE)" + +## Scopes: +##################################################################### + +qt_internal_extend_target(${target_name} CONDITION TARGET Qt::QmlDevToolsPrivate + SOURCES + qdeclarative.cpp + PUBLIC_LIBRARIES + Qt::QmlDevToolsPrivate +) + +qt_internal_extend_target(${target_name} CONDITION NOT TARGET Qt::QmlDevToolsPrivate + DEFINES + QT_NO_QML +) + +qt_internal_extend_target(${target_name} CONDITION QT_FEATURE_clangcpp + SOURCES + clangtoolastreader.cpp clangtoolastreader.h + cpp_clang.cpp cpp_clang.h + lupdatepreprocessoraction.cpp lupdatepreprocessoraction.h + synchronized.h + DEFINES + # special case begin + # remove these + #(CLANG_RESOURCE_DIR=\"/clang//include\") + #(LUPDATE_CLANG_VERSION_STR=\"\") + #LUPDATE_CLANG_VERSION_MAJOR= + #LUPDATE_CLANG_VERSION_MINOR= + #LUPDATE_CLANG_VERSION_PATCH= + # in favor of these + CLANG_RESOURCE_DIR="${QT_LIB_CLANG_LIBDIR}/clang/${QT_LIB_CLANG_VERSION}" + LUPDATE_CLANG_VERSION_STR="\"${QT_LIB_CLANG_VERSION}\"" + LUPDATE_CLANG_VERSION_MAJOR=${QT_LIB_CLANG_VERSION_MAJOR} + LUPDATE_CLANG_VERSION_MINOR=${QT_LIB_CLANG_VERSION_MINOR} + LUPDATE_CLANG_VERSION_PATCH=${QT_LIB_CLANG_VERSION_PATCH} + # special case end + LIBRARIES # special case + WrapLibClang::WrapLibClang # special case +) + +# special case begin +if(QT_FEATURE_clangcpp) + set_property(SOURCE clangtoolastreader.cpp PROPERTY SKIP_AUTOMOC ON) +endif() +# special case end + +#### Keys ignored in scope 6:.:.:lupdate.pro:NOT QMAKE_DEFAULT_LIBDIRS___contains____ss_CLANG_LIBDIR AND NOT disable_external_rpath: +# QMAKE_RPATHDIR = "$$CLANG_LIBDIR" + +#### Keys ignored in scope 9:.:.:lupdate.pro:MINGW: +# RC_FILE = "lupdate.rc" diff --git a/src/linguist/lupdate/clangtoolastreader.cpp b/src/linguist/lupdate/clangtoolastreader.cpp new file mode 100644 index 0000000000..5230608780 --- /dev/null +++ b/src/linguist/lupdate/clangtoolastreader.cpp @@ -0,0 +1,857 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "clangtoolastreader.h" +#include "translator.h" + +QT_BEGIN_NAMESPACE + +namespace LupdatePrivate +{ + void exploreChildrenForFirstStringLiteral(clang::Stmt* stmt, QString &context) + { + // only exploring the children until the context has been found. + if (!stmt || !context.isEmpty()) + return; + + for (auto it = stmt->child_begin() ; it !=stmt->child_end() ; it++) { + if (!context.isEmpty()) + break; + clang::Stmt *child = *it; + clang::StringLiteral *stringLit = llvm::dyn_cast_or_null(child); + if (stringLit) { + context = toQt(stringLit->getString()); + return; + } + exploreChildrenForFirstStringLiteral(child, context); + } + return; + } + + // Checks if the tr method is supported by the CXXRecordDecl + // Either because Q_OBJECT or Q_DECLARE_FUNCTIONS(MyContext) is declared with this CXXRecordDecl + // In case of Q_DECLARE_FUNCTIONS the context is read in the tr Method children with function exploreChildrenForFirstStringLiteral + // Q_DECLARE_FUNCTIONS trace in the AST is: + // - a public AccessSpecDecl pointing to src/corelib/kernel/qcoreapplication.h + // - a CXXMethodDecl called tr with a children that is a StringLiteral. This is the context + // Q_OBJECT trace in the AST is: + // - a public AccessSpecDecl pointing to src/corelib/kernel/qtmetamacros.h + // - a CXXMethodDecl called tr WITHOUT a StringLiteral among its children. + bool isQObjectOrQDeclareTrFunctionMacroDeclared(clang::CXXRecordDecl *recordDecl, QString &context, const clang::SourceManager &sm) + { + if (!recordDecl) + return false; + + bool tr_method_present = false; + bool access_for_qobject = false; + bool access_for_qdeclaretrfunction = false; + + for (auto decl : recordDecl->decls()) { + clang::AccessSpecDecl *accessSpec = llvm::dyn_cast(decl); + clang::CXXMethodDecl *method = llvm::dyn_cast(decl); + + if (!accessSpec && !method) + continue; + if (method) { + // Look for method with name 'tr' + std::string name = method->getNameAsString(); + if (name == "tr") { + tr_method_present = true; + // if nothing is found and the context remains empty, it's ok, it's probably a Q_OBJECT. + exploreChildrenForFirstStringLiteral(method->getBody(), context); + } + } else if (accessSpec) { + QString location = accessSpec->getBeginLoc().isValid() ? + QString::fromStdString(accessSpec->getBeginLoc().printToString(sm)) : QString(); + const QString accessForQDeclareTrFunctions = QStringLiteral("src/corelib/kernel/qcoreapplication.h"); + const QString accessForQObject = QStringLiteral("src/corelib/kernel/qtmetamacros.h"); + if (location.contains(accessForQDeclareTrFunctions)) + access_for_qdeclaretrfunction = true; + if (location.contains(accessForQObject)) + access_for_qobject = true; + } + } + + bool access_to_qtbase = false; + // if the context is still empty then it cannot be a Q_DECLARE_TR_FUNCTION. + if (context.isEmpty()) + access_to_qtbase = access_for_qobject; + else + access_to_qtbase = access_for_qdeclaretrfunction; + + return tr_method_present && access_to_qtbase; + } + + QString exploreBases(clang::CXXRecordDecl *recordDecl, const clang::SourceManager &sm); + QString lookForContext(clang::CXXRecordDecl *recordDecl, const clang::SourceManager &sm) + { + QString context; + if (isQObjectOrQDeclareTrFunctionMacroDeclared(recordDecl, context, sm)) { + return context.isEmpty() ? QString::fromStdString(recordDecl->getQualifiedNameAsString()) : context; + } else { + // explore the bases of this CXXRecordDecl + // the base class AA takes precedent over B (reproducing tr context behavior) + /* + class AA {Q_OBJECT}; + class A : public AA {}; + class B { + Q_OBJECT + class C : public A + { + QString c_tr = tr("context is AA"); + const char * c_noop = QT_TR_NOOP("context should be AA"); + } + }; + */ + // For recordDecl corresponding to class C, the following gives access to class A + return exploreBases(recordDecl, sm); + } + } + + // Gives access to the class or struct the CXXRecordDecl is inheriting from + QString exploreBases(clang::CXXRecordDecl *recordDecl, const clang::SourceManager &sm) + { + QString context; + for (auto base : recordDecl->bases()) { + const clang::Type *type = base.getType().getTypePtrOrNull(); + if (!type) continue; + clang::CXXRecordDecl *baseDecl = type->getAsCXXRecordDecl(); + if (!baseDecl) + continue; + context = lookForContext(baseDecl, sm); + if (!context.isEmpty()) + return context; + } + return context; + } + + // QT_TR_NOOP location is within the the NamedDecl range + // Look for the RecordDecl (class or struct) the NamedDecl belongs to + // and the related classes until Q_OBJECT macro declaration or Q_DECLARE_TR_FUNCTIONS is found. + // The first class where Q_OBJECT or Q_DECLARE_TR_FUNCTIONS is declared is the context. + // The goal is to reproduce the behavior exibited by the new parser for tr function. + // tr function and QT_TR_NOOP, when next to each other in code, should always have the same context! + // + // The old parser does not do this. + // If a Q_OBJECT macro cannot be found in the first class + // a warning is emitted and the class is used as context regardless. + // This is the behavior for tr function and QT_TR_NOOP + // This is not correct. + QString contextForNoopMacro(clang::NamedDecl *namedDecl, const clang::SourceManager &sm) + { + QString context; + clang::DeclContext *decl = namedDecl->getDeclContext(); + if (!decl) + return context; + while (decl) { + qCDebug(lcClang) << "--------------------- decl kind name: " << decl->getDeclKindName(); + if (clang::isa(decl)) { + clang::CXXRecordDecl *recordDecl = llvm::dyn_cast(decl); + + context = lookForContext(recordDecl, sm); + if (!context.isEmpty()) + return context; + } + decl = decl->getParent(); // Brings to the class or struct decl is nested in, if it exists. + } + + // If no context has been found: do not emit a warning here. + // because more than one NamedDecl can include the QT_TR_NOOP macro location + // in the following, class A and class B and c_noop will. + /* + class A { + class B + { + Q_OBJECT + const char * c_noop = QT_TR_NOOP("context is B"); + } + }; + */ + // calling contextForNoopMacro on NamedDecl corresponding to class A + // no context will be found, but it's ok because the context will be found + // when the function is called on c_noop. + return context; + } + + + QString contextForFunctionDecl(clang::FunctionDecl *func, const std::string &funcName) + { + std::string context; +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + { + llvm::raw_string_ostream tmp(context); + func->printQualifiedName(tmp); + } +#else + context = func->getQualifiedNameAsString(); +#endif + return QString::fromStdString(context.substr(0, context.find("::" + funcName, 0))); + } + + static bool capture(const QRegularExpression &exp, const QString &line, QString *i, QString *c) + { + i->clear(), c->clear(); + auto result = exp.match(line); + if (!result.hasMatch()) + return false; + + *i = result.captured(QLatin1String("identifier")); + *c = result.captured(QStringLiteral("comment")).trimmed(); + + if (*i == QLatin1String("%")) + *c = LupdatePrivate::cleanQuote(c->toStdString(), QuoteCompulsary::Left); + + return !c->isEmpty(); + } + + bool hasQuote(llvm::StringRef source) + { + return source.contains("\""); + } + + bool trFunctionPresent(llvm::StringRef text) + { + if (text.contains(llvm::StringRef("qtTrId("))) + return true; + if (text.contains(llvm::StringRef("tr("))) + return true; + if (text.contains(llvm::StringRef("trUtf8("))) + return true; + if (text.contains(llvm::StringRef("translate("))) + return true; + if (text.contains(llvm::StringRef("Q_DECLARE_TR_FUNCTIONS("))) + return true; + if (text.contains(llvm::StringRef("QT_TR_N_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRID_N_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_N_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_N_NOOP3("))) + return true; + if (text.contains(llvm::StringRef("QT_TR_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRID_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_NOOP("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_NOOP3("))) + return true; + if (text.contains(llvm::StringRef("QT_TR_NOOP_UTF8("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_NOOP_UTF8("))) + return true; + if (text.contains(llvm::StringRef("QT_TRANSLATE_NOOP3_UTF8("))) + return true; + return false; + } + + bool isPointWithin(const clang::SourceRange &sourceRange, const clang::SourceLocation &point, + const clang::SourceManager &sm) + { + clang::SourceLocation start = sourceRange.getBegin(); + clang::SourceLocation end = sourceRange.getEnd(); + return point == start || point == end || (sm.isBeforeInTranslationUnit(start, point) + && sm.isBeforeInTranslationUnit(point, end)); + } + + class BeforeThanCompare + { + const clang::SourceManager &SM; + + public: + explicit BeforeThanCompare(const clang::SourceManager &SM) : SM(SM) { } + + bool operator()(const clang::RawComment &LHS, const clang::RawComment &RHS) + { + return SM.isBeforeInTranslationUnit(LHS.getBeginLoc(), RHS.getBeginLoc()); + } + + bool operator()(const clang::RawComment *LHS, const clang::RawComment *RHS) + { + return operator()(*LHS, *RHS); + } + }; +} + +/* + The visit call expression function is called automatically after the + visitor TraverseAST function is called. This is the function where the + "tr", "trUtf8", "qtIdTr", "translate" functions are picked up in the AST. + Previously mentioned functions are always part of a CallExpression. +*/ +bool LupdateVisitor::VisitCallExpr(clang::CallExpr *callExpression) +{ + const auto fullLocation = m_context->getFullLoc(callExpression->getBeginLoc()); + if (fullLocation.isInvalid()) + return true; + clang::FunctionDecl *func = callExpression->getDirectCallee(); + if (!func) + return true; + clang::QualType q = callExpression->getType(); + if (!q.getTypePtrOrNull()) + return true; + + struct { + unsigned Line; + std::string Filename; + } info; + + const auto funcName = QString::fromStdString(func->getNameInfo().getAsString()); + + // Only continue if the function a translation function (TODO: deal with alias function...) + switch (trFunctionAliasManager.trFunctionByName(funcName)) { + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + case TrFunctionAliasManager::Function_translate: + case TrFunctionAliasManager::Function_qtTrId:{ + + const auto &sm = m_context->getSourceManager(); + const auto fileLoc = sm.getFileLoc(callExpression->getBeginLoc()); + if (fileLoc.isInvalid() || !fileLoc.isFileID()) + return true; + auto presumedLoc = sm.getPresumedLoc(fileLoc); + if (presumedLoc.isInvalid()) + return true; + info = { presumedLoc.getLine(), presumedLoc.getFilename() }; + } break; + default: + return true; + } + + // Checking that the CallExpression is from the input file we're interested in + if (info.Filename != m_inputFile) + return true; + + qCDebug(lcClang) << "************************** VisitCallExpr ****************"; + // Retrieving the information needed to fill the lupdate translator. + // Function independent retrieve + TranslationRelatedStore store; + store.callType = QStringLiteral("ASTRead_CallExpr"); + store.funcName = funcName; + store.lupdateLocationFile = QString::fromStdString(info.Filename); + store.lupdateLocationLine = info.Line; + store.contextRetrieved = LupdatePrivate::contextForFunctionDecl(func, funcName.toStdString()); + + qCDebug(lcClang) << "CallType : ASTRead_CallExpr"; + qCDebug(lcClang) << "Function name : " << store.funcName; + qCDebug(lcClang) << "File location : " << store.lupdateLocationFile; + qCDebug(lcClang) << "Line : " << store.lupdateLocationLine; + qCDebug(lcClang) << "Context retrieved : " << store.contextRetrieved; + + // Here we gonna need to retrieve the comments around the function call + // //: //* //~ Things like that + const std::vector rawComments = rawCommentsForCallExpr(callExpression); + for (const auto &rawComment : rawComments) { + setInfoFromRawComment(rawComment, &store); + qCDebug(lcClang) << "Raw comments :" << rawComment; + } + + clang::LangOptions langOpts; + langOpts.CPlusPlus = true; + clang::PrintingPolicy policy(langOpts); + std::vector arguments(callExpression->getNumArgs(), ""); + for (unsigned int i = 0; i < callExpression->getNumArgs(); i++) { + auto arg = callExpression->getArg(i); + llvm::raw_string_ostream temp(arguments[i]); + arg->printPretty(temp, nullptr, policy); + } + + // Function dependent retrieve! + switch (trFunctionAliasManager.trFunctionByName(funcName)) { + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + if (arguments.size() != 3 || !LupdatePrivate::hasQuote(arguments[0])) + return true; + store.lupdateSource = LupdatePrivate::cleanQuote(arguments[0]); + store.lupdateComment = LupdatePrivate::cleanQuote(arguments[1]); + store.lupdatePlural = QString::fromStdString(arguments[2]); + qCDebug(lcClang) << "Source : " << store.lupdateSource; + qCDebug(lcClang) << "Comment : " << store.lupdateComment; + qCDebug(lcClang) << "Plural : " << store.lupdatePlural; + break; + case TrFunctionAliasManager::Function_translate: + if (arguments.size() != 4 || !LupdatePrivate::hasQuote(arguments[0]) + || !LupdatePrivate::hasQuote(arguments[1])) { + return true; + } + store.contextArg = LupdatePrivate::cleanQuote(arguments[0]); + store.lupdateSource = LupdatePrivate::cleanQuote(arguments[1]); + store.lupdateComment = LupdatePrivate::cleanQuote(arguments[2]); + store.lupdatePlural = QString::fromStdString(arguments[3]); + qCDebug(lcClang) << "Context Arg : " << store.contextArg; + qCDebug(lcClang) << "Source : " << store.lupdateSource; + qCDebug(lcClang) << "Comment : " << store.lupdateComment; + qCDebug(lcClang) << "Plural : " << store.lupdatePlural; + break; + case TrFunctionAliasManager::Function_qtTrId: + if (arguments.size() != 2 || !LupdatePrivate::hasQuote(arguments[0])) + return true; + store.lupdateId = LupdatePrivate::cleanQuote(arguments[0]); + store.lupdatePlural = QString::fromStdString(arguments[1]); + qCDebug(lcClang) << "ID : " << store.lupdateId; + qCDebug(lcClang) << "Plural : " << store.lupdatePlural; + break; + } + // locationCol needs to be set for the store to be considered valid (but really only needed for PP calls, to reconstruct location) + store.locationCol = 0; + m_trCalls.emplace_back(std::move(store)); + return true; +} + +/* + Retrieve the comments not associated with tr calls. +*/ +void LupdateVisitor::processIsolatedComments() +{ + qCDebug(lcClang) << "==== processIsolatedComments ===="; + auto &sourceMgr = m_context->getSourceManager(); + +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + const clang::FileID file = sourceMgr.getMainFileID(); + const auto commentsInThisFile = m_context->Comments.getCommentsInFile(file); + if (!commentsInThisFile) + return; + + std::vector tmp; + for (const auto &commentInFile : *commentsInThisFile) + tmp.emplace_back(commentInFile.second); + clang::ArrayRef rawComments = tmp; +#else + clang::ArrayRef rawComments = m_context->getRawCommentList().getComments(); +#endif + + // If there are no comments anywhere, we won't find anything. + if (rawComments.empty()) + return; + + // Searching for the comments of the form: + // /* TRANSLATOR CONTEXT + // whatever */ + // They are not associated to any tr calls + // Each one needs its own entry in the m_stores->AST translation store + for (const auto &rawComment : rawComments) { + if (sourceMgr.getFilename(rawComment->getBeginLoc()).str() != m_inputFile) + continue; + // Comments not separated by an empty line will be part of the same Raw comments + // Each one needs to be saved with its line number. + // The store is used here only to pass this information. + TranslationRelatedStore store; + store.lupdateLocationLine = sourceMgr.getPresumedLoc(rawComment->getBeginLoc()).getLine(); + QString comment = toQt(rawComment->getRawText(sourceMgr)); + qCDebug(lcClang) << " raw Comment : \n" << comment; + setInfoFromRawComment(comment, &store); + } +} + +/* + Retrieve the comments associated with the CallExpression. +*/ +std::vector LupdateVisitor::rawCommentsForCallExpr(const clang::CallExpr *callExpr) const +{ + if (!m_context) + return {}; + return rawCommentsFromSourceLocation(m_context->getFullLoc(callExpr->getBeginLoc())); +} + +std::vector LupdateVisitor::rawCommentsFromSourceLocation( + clang::SourceLocation sourceLocation) const +{ + if (!m_context) + return {}; + if (sourceLocation.isInvalid() || !sourceLocation.isFileID()) { + qCDebug(lcClang) << "The declaration does not map directly to a location in a file," + " early return."; + return {}; + } + auto &sourceMgr = m_context->getSourceManager(); + +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + const clang::FileID file = sourceMgr.getDecomposedLoc(sourceLocation).first; + const auto commentsInThisFile = m_context->Comments.getCommentsInFile(file); + if (!commentsInThisFile) + return {}; + + std::vector tmp; + for (const auto &commentInFile : *commentsInThisFile) + tmp.emplace_back(commentInFile.second); + clang::ArrayRef rawComments = tmp; +#else + clang::ArrayRef rawComments = m_context->getRawCommentList().getComments(); +#endif + + // If there are no comments anywhere, we won't find anything. + if (rawComments.empty()) + return {}; + + // Create a dummy raw comment with the source location of the declaration. + clang::RawComment commentAtDeclarationLocation(sourceMgr, + clang::SourceRange(sourceLocation), m_context->getLangOpts().CommentOpts, false); + + // Create a functor object to compare the source location of the comment and the declaration. + const LupdatePrivate::BeforeThanCompare compareSourceLocation(sourceMgr); + // Find the comment that occurs just after or within this declaration. Possible findings: + // QObject::tr(/* comment 1 */ "test"); //: comment 2 -> finds "//: comment 1" + // QObject::tr("test"); //: comment 1 -> finds "//: comment 1" + // QObject::tr("test"); + // //: comment 1 -> finds "//: comment 1" + // /*: comment 1 */ QObject::tr("test"); -> finds no trailing comment + auto comment = std::lower_bound(rawComments.begin(), rawComments.end(), + &commentAtDeclarationLocation, compareSourceLocation); + + // We did not find any comment before the declaration. + if (comment == rawComments.begin()) + return {}; + + // Decompose the location for the declaration and find the beginning of the file buffer. + std::pair declLocDecomp = sourceMgr.getDecomposedLoc(sourceLocation); + + // Get the text buffer from the beginning of the file up through the declaration's begin. + bool invalid = false; + const char *buffer = sourceMgr.getBufferData(declLocDecomp.first, &invalid).data(); + if (invalid) { + qCDebug(lcClang).nospace() << "An error occurred fetching the source buffer of file: " + << toQt(sourceMgr.getFilename(sourceLocation)); + return {}; + } + + std::vector retrievedRawComments; + auto lastDecompLoc = declLocDecomp.second; + const auto declLineNum = sourceMgr.getLineNumber(declLocDecomp.first, declLocDecomp.second); + do { + std::advance(comment, -1); + + // Decompose the end of the comment. + std::pair commentEndDecomp + = sourceMgr.getDecomposedLoc((*comment)->getSourceRange().getEnd()); + + // If the comment and the declaration aren't in the same file, then they aren't related. + if (declLocDecomp.first != commentEndDecomp.first) { + qCDebug(lcClang) << "Comment and the declaration aren't in the same file. Comment '" + << toQt((*comment)->getRawText(sourceMgr)) << "' is ignored, return."; + return retrievedRawComments; + } + + // Current lupdate ignores comments on the same line before the declaration. + // void Class42::hello(int something /*= 17 */, QString str = Class42::tr("eyo")) + bool sameLineComment = false; + if (declLineNum == sourceMgr.getLineNumber(commentEndDecomp.first, commentEndDecomp.second)) + sameLineComment = true; + + // Extract text between the comment and declaration. + llvm::StringRef text(buffer + commentEndDecomp.second, + lastDecompLoc - commentEndDecomp.second); + + // There should be no other declarations or preprocessor directives between + // comment and declaration. + if (text.find_first_of(";}#@") != llvm::StringRef::npos) { + qCDebug(lcClang) << "Found another declaration or preprocessor directive between" + " comment and declaration, break."; + break; + } + if (sameLineComment && text.find_first_of(",") != llvm::StringRef::npos) { + qCDebug(lcClang) << "Comment ends on same line as the declaration and is separated " + "from the tr call by a ','. Comment '" + << toQt((*comment)->getRawText(sourceMgr)) + << "' is ignored, continue."; + continue; // if there is a comment on the previous line it should be picked up + } + + // There should be no other translation function between comment and declaration. + if (LupdatePrivate::trFunctionPresent(text)) { + qCDebug(lcClang) << "Found another translation function between comment and " + "declaration, break."; + break; + } + + retrievedRawComments.emplace(retrievedRawComments.begin(), + toQt((*comment)->getRawText(sourceMgr))); + lastDecompLoc = sourceMgr.getDecomposedLoc((*comment)->getSourceRange().getBegin()).second; + } while (comment != rawComments.begin()); + + return retrievedRawComments; +} + +/* + Read the raw comments and split them according to the prefix. + Fill the corresponding variables in the TranslationRelatedStore. +*/ +void LupdateVisitor::setInfoFromRawComment(const QString &commentString, + TranslationRelatedStore *store) +{ + const QStringList commentLines = commentString.split(QLatin1Char('\n')); + + static const QRegularExpression + cppStyle( + QStringLiteral("^\\/\\/(?[:=~%]|(\\s*?TRANSLATOR))\\s+(?.+)$")); + static const QRegularExpression + cStyleSingle( + QStringLiteral("^\\/\\*(?[:=~%]|(\\s*?TRANSLATOR))\\s+(?.+)\\*\\/$")); + static const QRegularExpression + cStyleMultiBegin( + QStringLiteral("^\\/\\*(?[:=~%]|(\\s*?TRANSLATOR))\\s+(?.*)$")); + + static const QRegularExpression isSpace(QStringLiteral("\\s+")); + static const QRegularExpression idefix( + QStringLiteral("^\\/\\*(?[:=~%]|(\\s*?TRANSLATOR))")); + + bool save = false; + bool sawStarPrefix = false; + bool sourceIdentifier = false; + + int storeLine = store->lupdateLocationLine; + int lineExtra = storeLine - 1; + + QString comment, identifier; + for (auto line : commentLines) { + line = line.trimmed(); + lineExtra++; + if (!sawStarPrefix) { + if (line.startsWith(QStringLiteral("//"))) { + // Process C++ style comment. + save = LupdatePrivate::capture(cppStyle, line, &identifier, &comment); + storeLine = lineExtra; + } else if (line.startsWith(QLatin1String("/*")) && line.endsWith(QLatin1String("*/"))) { + // Process C style comment on a single line. + storeLine = lineExtra; + save = LupdatePrivate::capture(cStyleSingle, line, &identifier, &comment); + } else if (line.startsWith(QLatin1String("/*"))) { + storeLine = lineExtra; + sawStarPrefix = true; // Start processing a multi line C style comment. + + auto result = idefix.match(line); + if (!result.hasMatch()) + continue; // No identifier found. + identifier = result.captured(QLatin1String("identifier")); + + // The line is not just opening, try grab the comment. + if (line.size() > (identifier.size() + 3)) + LupdatePrivate::capture(cStyleMultiBegin, line, &identifier, &comment); + sourceIdentifier = (identifier == QLatin1String("%")); + } + } else { + if (line.endsWith(QLatin1String("*/"))) { + sawStarPrefix = false; // Finished processing a multi line C style comment. + line = line.remove(QLatin1String("*/")).trimmed(); // Still there can be something. + } + + if (sourceIdentifier) { + line = LupdatePrivate::cleanQuote(line.toStdString(), + LupdatePrivate::QuoteCompulsary::Left); + } + + if (!line.isEmpty() && !comment.isEmpty() && !sourceIdentifier) + comment.append(QLatin1Char(' ')); + + comment += line; + save = !sawStarPrefix && !comment.isEmpty(); + } + if (!save) + continue; + + // To avoid processing the non TRANSLATOR comments when setInfoFromRawComment in called + // from processIsolatedComments + if (!store->funcName.isEmpty()) { + if (identifier == QStringLiteral(":")) { + if (!store->lupdateExtraComment.isEmpty()) + store->lupdateExtraComment.append(QLatin1Char(' ')); + store->lupdateExtraComment += comment; + } else if (identifier == QStringLiteral("=")) { + if (!store->lupdateIdMetaData.isEmpty()) + store->lupdateIdMetaData.append(QLatin1Char(' ')); + store->lupdateIdMetaData = comment; // Only the last one is to be picked up. + } else if (identifier == QStringLiteral("~")) { + auto first = comment.section(isSpace, 0, 0); + auto second = comment.mid(first.size()).trimmed(); + if (!second.isEmpty()) + store->lupdateAllMagicMetaData.insert(first, second); + } else if (identifier == QLatin1String("%")) { + store->lupdateSourceWhenId += comment; + } + } else if (identifier.trimmed() == QStringLiteral("TRANSLATOR")) { + // separate the comment in two in order to get the context + // then save it as a new entry in m_stores. + // reminder: TRANSLATOR comments are isolated comments not linked to any tr call + qCDebug(lcClang) << "Comment = " << comment; + TranslationRelatedStore newStore; + // need a funcName name in order to get handeled in fillTranslator + newStore.funcName = QStringLiteral("TRANSLATOR"); + auto index = comment.indexOf(QStringLiteral(" ")); + if (index >= 0) { + newStore.contextArg = comment.left(index).trimmed(); + newStore.lupdateComment = comment.mid(index).trimmed(); + } + newStore.lupdateLocationFile = QString::fromStdString(m_inputFile); + newStore.lupdateLocationLine = storeLine; + newStore.locationCol = 0; + newStore.printStore(); + m_trCalls.emplace_back(std::move(newStore)); + } + + save = false; + comment.clear(); + identifier.clear(); + } +} + +void LupdateVisitor::processPreprocessorCalls() +{ + m_macro = (m_stores->Preprocessor.size() > 0); + for (const auto &store : m_stores->Preprocessor) + processPreprocessorCall(store); +} + +void LupdateVisitor::processPreprocessorCall(TranslationRelatedStore store) +{ + const std::vector rawComments = rawCommentsFromSourceLocation(store + .callLocation(m_context->getSourceManager())); + for (const auto &rawComment : rawComments) + setInfoFromRawComment(rawComment, &store); + + if (store.isValid()) { + if (store.funcName.contains(QStringLiteral("Q_DECLARE_TR_FUNCTIONS"))) + m_qDeclareTrMacroAll.emplace_back(std::move(store)); + else + m_noopTranslationMacroAll.emplace_back(std::move(store)); + store.printStore(); + } +} + +bool LupdateVisitor::VisitNamedDecl(clang::NamedDecl *namedDeclaration) +{ + if (!m_macro) + return true; + auto fullLocation = m_context->getFullLoc(namedDeclaration->getBeginLoc()); + if (!fullLocation.isValid() || !fullLocation.getFileEntry()) + return true; + + if (fullLocation.getFileEntry()->getName() != m_inputFile) + return true; + + qCDebug(lcClang) << "NamedDecl Name: " << namedDeclaration->getQualifiedNameAsString(); + qCDebug(lcClang) << "NamedDecl source: " << namedDeclaration->getSourceRange().printToString( + m_context->getSourceManager()); + // Checks if there is a macro located within the range of this NamedDeclaration + // in order to find a context for the macro + findContextForTranslationStoresFromPP(namedDeclaration); + return true; +} + +void LupdateVisitor::findContextForTranslationStoresFromPP(clang::NamedDecl *namedDeclaration) +{ + qCDebug(lcClang) << "=================findContextForTranslationStoresFromPP==================="; + qCDebug(lcClang) << "m_noopTranslationMacroAll " << m_noopTranslationMacroAll.size(); + qCDebug(lcClang) << "m_qDeclareTrMacroAll " << m_qDeclareTrMacroAll.size(); + clang::SourceManager &sm = m_context->getSourceManager(); + + // Looking for NOOP context only in the input file + // because we are not interested in the NOOP from all related file + // Once QT_TR_NOOP are gone this step can be removes because the only + // QT_...NOOP left will have an context as argument + for (TranslationRelatedStore &store : m_noopTranslationMacroAll) { + if (!store.contextArg.isEmpty()) + continue; + clang::SourceLocation sourceLoc = store.callLocation(sm); + if (!sourceLoc.isValid()) + continue; + if (LupdatePrivate::isPointWithin(namedDeclaration->getSourceRange(), sourceLoc, sm)) { + + store.contextRetrieved = LupdatePrivate::contextForNoopMacro(namedDeclaration, sm); + qCDebug(lcClang) << "------------------------------------------NOOP Macro in range ---"; + qCDebug(lcClang) << "Range " << namedDeclaration->getSourceRange().printToString(sm); + qCDebug(lcClang) << "Point " << sourceLoc.printToString(sm); + qCDebug(lcClang) << "=========== Visit Named Declaration ============================="; + qCDebug(lcClang) << " Declaration Location " << + namedDeclaration->getSourceRange().printToString(sm); + qCDebug(lcClang) << " Macro Location " + << sourceLoc.printToString(sm); + qCDebug(lcClang) << " Context namedDeclaration->getQualifiedNameAsString() " + << namedDeclaration->getQualifiedNameAsString(); + qCDebug(lcClang) << " Context LupdatePrivate::contextForNoopMacro " + << store.contextRetrieved; + qCDebug(lcClang) << " Context Retrieved " << store.contextRetrieved; + qCDebug(lcClang) << "================================================================="; + store.printStore(); + } + } + + for (TranslationRelatedStore &store : m_qDeclareTrMacroAll) { + clang::SourceLocation sourceLoc = store.callLocation(sm); + if (!sourceLoc.isValid()) + continue; + if (LupdatePrivate::isPointWithin(namedDeclaration->getSourceRange(), sourceLoc, sm)) { + store.contextRetrieved = QString::fromStdString( + namedDeclaration->getQualifiedNameAsString()); + qCDebug(lcClang) << "------------------------------------------DECL Macro in range ---"; + qCDebug(lcClang) << "Range " << namedDeclaration->getSourceRange().printToString(sm); + qCDebug(lcClang) << "Point " << sourceLoc.printToString(sm); + qCDebug(lcClang) << "=========== Visit Named Declaration ============================="; + qCDebug(lcClang) << " Declaration Location " << + namedDeclaration->getSourceRange().printToString(sm); + qCDebug(lcClang) << " Macro Location " + << sourceLoc.printToString(sm); + qCDebug(lcClang) << " Context namedDeclaration->getQualifiedNameAsString() " + << store.contextRetrieved; + qCDebug(lcClang) << " Context Retrieved " << store.contextRetrieved; + qCDebug(lcClang) << "================================================================="; + store.printStore(); + } + } +} + +void LupdateVisitor::generateOuput() +{ + qCDebug(lcClang) << "=================m_trCallserateOuput============================"; + m_noopTranslationMacroAll.erase(std::remove_if(m_noopTranslationMacroAll.begin(), + m_noopTranslationMacroAll.end(), [](const TranslationRelatedStore &store) { + // only fill if a context has been retrieved in the file we're currently visiting + // emit warning if both context are empty + if (store.contextRetrieved.isEmpty() && store.contextArg.isEmpty()) { + std::cerr << qPrintable(store.lupdateLocationFile) << ":"; + std::cerr << store.lupdateLocationLine << ":"; + std::cerr << store.locationCol << ": "; + std::cerr << " \'" << qPrintable(store.funcName) << "\' cannot be called without context."; + std::cerr << " The call is ignored (missing Q_OBJECT maybe?)\n"; + } + return store.contextRetrieved.isEmpty() && store.contextArg.isEmpty(); + }), m_noopTranslationMacroAll.end()); + + m_stores->QNoopTranlsationWithContext.emplace_bulk(std::move(m_noopTranslationMacroAll)); + + m_qDeclareTrMacroAll.erase(std::remove_if(m_qDeclareTrMacroAll.begin(), + m_qDeclareTrMacroAll.end(), [](const TranslationRelatedStore &store) { + // only fill if a context has been retrieved in the file we're currently visiting + return store.contextRetrieved.isEmpty(); + }), m_qDeclareTrMacroAll.end()); + m_stores->QDeclareTrWithContext.emplace_bulk(std::move(m_qDeclareTrMacroAll)); + + processIsolatedComments(); + m_stores->AST.emplace_bulk(std::move(m_trCalls)); +} + +QT_END_NAMESPACE diff --git a/src/linguist/lupdate/clangtoolastreader.h b/src/linguist/lupdate/clangtoolastreader.h new file mode 100644 index 0000000000..3a5ea7dfba --- /dev/null +++ b/src/linguist/lupdate/clangtoolastreader.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLANG_TOOL_AST_READER_H +#define CLANG_TOOL_AST_READER_H + +#include "cpp_clang.h" +#if defined(Q_CC_MSVC) +# pragma warning(push) +# pragma warning(disable: 4100) +# pragma warning(disable: 4146) +# pragma warning(disable: 4267) +# pragma warning(disable: 4624) +#endif + +#include +#include +#include +#include + +#if defined(Q_CC_MSVC) +# pragma warning(pop) +#endif + +#include +#include + +QT_BEGIN_NAMESPACE + +class Translator; + +class LupdateVisitor : public clang::RecursiveASTVisitor +{ +public: + explicit LupdateVisitor(clang::ASTContext *context, Stores *stores) + : m_context(context) + , m_stores(stores) + { + m_inputFile = m_context->getSourceManager().getFileEntryForID( + m_context->getSourceManager().getMainFileID())->getName(); + } + + bool VisitCallExpr(clang::CallExpr *callExpression); + void processPreprocessorCalls(); + bool VisitNamedDecl(clang::NamedDecl *namedDeclaration); + void findContextForTranslationStoresFromPP(clang::NamedDecl *namedDeclaration); + void generateOuput(); + +private: + std::vector rawCommentsForCallExpr(const clang::CallExpr *callExpr) const; + std::vector rawCommentsFromSourceLocation(clang::SourceLocation sourceLocation) const; + + void setInfoFromRawComment(const QString &commentString, TranslationRelatedStore *store); + + void processPreprocessorCall(TranslationRelatedStore store); + void processIsolatedComments(); + + clang::ASTContext *m_context = nullptr; + std::string m_inputFile; + + Stores *m_stores = nullptr; + + TranslationStores m_trCalls; + TranslationStores m_qDeclareTrMacroAll; + TranslationStores m_noopTranslationMacroAll; + bool m_macro = false; +}; + +class LupdateASTConsumer : public clang::ASTConsumer +{ +public: + explicit LupdateASTConsumer(clang::ASTContext *context, Stores *stores) + : m_visitor(context, stores) + {} + + // This method is called when the ASTs for entire translation unit have been + // parsed. + void HandleTranslationUnit(clang::ASTContext &context) override + { + m_visitor.processPreprocessorCalls(); + bool traverse = m_visitor.TraverseAST(context); + qCDebug(lcClang) << "TraverseAST: " << traverse; + m_visitor.generateOuput(); + } + +private: + LupdateVisitor m_visitor; +}; + +class LupdateFrontendAction : public clang::ASTFrontendAction +{ +public: + LupdateFrontendAction(Stores *stores) + : m_stores(stores) + {} + + std::unique_ptr CreateASTConsumer( + clang::CompilerInstance &compiler, llvm::StringRef /* inFile */) override + { + auto consumer = new LupdateASTConsumer(&compiler.getASTContext(), m_stores); + return std::unique_ptr(consumer); + } + +private: + Stores *m_stores = nullptr; +}; + +class LupdateToolActionFactory : public clang::tooling::FrontendActionFactory +{ +public: + LupdateToolActionFactory(Stores *stores) + : m_stores(stores) + {} + +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + std::unique_ptr create() override + { + return std::make_unique(m_stores); + } +#else + clang::FrontendAction *create() override + { + return new LupdateFrontendAction(m_stores); + } +#endif + +private: + Stores *m_stores = nullptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/linguist/lupdate/cpp.cpp b/src/linguist/lupdate/cpp.cpp index eb0549cee9..ed0947ccc7 100644 --- a/src/linguist/lupdate/cpp.cpp +++ b/src/linguist/lupdate/cpp.cpp @@ -26,29 +26,16 @@ ** ****************************************************************************/ -#include "lupdate.h" +#include "cpp.h" #include - #include -#include -#include -#include #include -#include -#include #include -#include - -#include - -#include // for isXXX() +#include QT_BEGIN_NAMESPACE -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; /* qmake ignore Q_OBJECT */ @@ -58,42 +45,18 @@ static QString MagicComment(QLatin1String("TRANSLATOR")); //#define DIAGNOSE_RETRANSLATABILITY // FIXME: should make a runtime option of this -class HashString { -public: - HashString() : m_hash(0x80000000) {} - explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {} - void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; } - const QString &value() const { return m_str; } - bool operator==(const HashString &other) const { return m_str == other.m_str; } -private: - QString m_str; - mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid) - friend uint qHash(const HashString &str); -}; - -uint qHash(const HashString &str) +size_t qHash(const HashString &str) { if (str.m_hash & 0x80000000) str.m_hash = qHash(str.m_str) & 0x7fffffff; return str.m_hash; } -class HashStringList { -public: - explicit HashStringList(const QList &list) : m_list(list), m_hash(0x80000000) {} - const QList &value() const { return m_list; } - bool operator==(const HashStringList &other) const { return m_list == other.m_list; } -private: - QList m_list; - mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid) - friend uint qHash(const HashStringList &list); -}; - -uint qHash(const HashStringList &list) +size_t qHash(const HashStringList &list) { if (list.m_hash & 0x80000000) { uint hash = 0; - foreach (const HashString &qs, list.m_list) { + for (const HashString &qs : list.m_list) { hash ^= qHash(qs) ^ 0x6ad9f526; hash = ((hash << 13) & 0x7fffffff) | (hash >> 18); } @@ -102,42 +65,6 @@ uint qHash(const HashStringList &list) return list.m_hash; } -typedef QList NamespaceList; - -struct Namespace { - - Namespace() : - classDef(this), - hasTrFunctions(false), complained(false) - {} - ~Namespace() - { - qDeleteAll(children); - } - - QHash children; - QHash aliases; - QList usings; - - // Class declarations set no flags and create no namespaces, so they are ignored. - // Class definitions may appear multiple times - but only because we are trying to - // "compile" all sources irrespective of build configuration. - // Nested classes may be forward-declared inside a definition, and defined in another file. - // The latter will detach the class' child list, so clones need a backlink to the original - // definition (either one in case of multiple definitions). - // Namespaces can have tr() functions as well, so we need to track parent definitions for - // them as well. The complication is that we may have to deal with a forrest instead of - // a tree - in that case the parent will be arbitrary. However, it seem likely that - // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central - // header or only locally in a file. - Namespace *classDef; - - QString trQualification; - - bool hasTrFunctions; - bool complained; // ... that tr functions are missing. -}; - static int nextFileId; class VisitRecorder { @@ -157,37 +84,6 @@ class VisitRecorder { QBitArray m_ba; }; -struct ParseResults { - int fileId; - Namespace rootNamespace; - QSet includes; -}; - -struct IncludeCycle { - QSet fileNames; - QSet results; -}; - -typedef QHash IncludeCycleHash; -typedef QHash TranslatorHash; - -class CppFiles { - -public: - static QSet getResults(const QString &cleanFile); - static void setResults(const QString &cleanFile, const ParseResults *results); - static const Translator *getTranslator(const QString &cleanFile); - static void setTranslator(const QString &cleanFile, const Translator *results); - static bool isBlacklisted(const QString &cleanFile); - static void setBlacklisted(const QString &cleanFile); - static void addIncludeCycle(const QSet &fileNames); - -private: - static IncludeCycleHash &includeCycles(); - static TranslatorHash &translatedFiles(); - static QSet &blacklistedFiles(); -}; - class CppParser { public: @@ -302,6 +198,7 @@ class CppParser { int yyCh; bool yyAtNewline; QString yyWord; + qsizetype yyWordInitialCapacity = 0; QStack yyIfdefStack; int yyBracketDepth; int yyBraceDepth; @@ -313,7 +210,7 @@ class CppParser { int yyParenLineNo; // the string to read from and current position in the string - QTextCodec *yySourceCodec; + QStringConverter::Encoding yySourceEncoding = QStringConverter::Utf8; QString yyInStr; const ushort *yyInPtr; @@ -376,14 +273,14 @@ void CppParser::setInput(const QString &in) { yyInStr = in; yyFileName = QString(); - yySourceCodec = 0; + yySourceEncoding = QStringConverter::Utf8; } void CppParser::setInput(QTextStream &ts, const QString &fileName) { yyInStr = ts.readAll(); yyFileName = fileName; - yySourceCodec = ts.codec(); + yySourceEncoding = ts.encoding(); } /* @@ -491,7 +388,7 @@ CppParser::TokenType CppParser::getToken() { restart: // Failing this assertion would mean losing the preallocated buffer. - Q_ASSERT(yyWord.isDetached()); + Q_ASSERT(yyWord.capacity() == yyWordInitialCapacity); while (yyCh != EOF) { yyLineNo = yyCurLineNo; @@ -1092,7 +989,7 @@ bool CppParser::visitNamespace(const NamespaceList &namespaces, int nsCount, if ((this->*callback)(ns, context)) return true; supers: - foreach (const ParseResults *sup, rslt->includes) + for (const ParseResults *sup : rslt->includes) if (vr.tryVisit(sup->fileId) && visitNamespace(namespaces, nsCount, callback, context, vr, sup)) return true; @@ -1127,7 +1024,7 @@ bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const *data->resolved << data->segment; return true; } - QHash::ConstIterator nsai = ns->aliases.constFind(data->segment); + auto nsai = ns->aliases.constFind(data->segment); if (nsai != ns->aliases.constEnd()) { const NamespaceList &nsl = *nsai; if (nsl.last().value().isEmpty()) { // Delayed alias resolution @@ -1149,7 +1046,7 @@ bool CppParser::qualifyOneCallbackOwn(const Namespace *ns, void *context) const bool CppParser::qualifyOneCallbackUsing(const Namespace *ns, void *context) const { QualifyOneData *data = (QualifyOneData *)context; - foreach (const HashStringList &use, ns->usings) + for (const HashStringList &use : ns->usings) if (!data->visitedUsings->contains(use)) { data->visitedUsings->insert(use); if (qualifyOne(use.value(), use.value().count(), data->segment, data->resolved, @@ -1234,7 +1131,7 @@ bool CppParser::fullyQualify(const NamespaceList &namespaces, static QString strColons(QLatin1String("::")); NamespaceList segments; - foreach (const QString &str, quali.split(strColons)) // XXX slow, but needs to be fast(?) + for (const QString &str : quali.split(strColons)) // XXX slow, but needs to be fast(?) segments << HashString(str); return fullyQualify(namespaces, segments, isDeclaration, resolved, unresolved); } @@ -1341,7 +1238,7 @@ void CppFiles::addIncludeCycle(const QSet &fileNames) cycle->fileNames = fileNames; QSet intersectingCycles; - foreach (const QString &fileName, fileNames) { + for (const QString &fileName : fileNames) { IncludeCycle *intersectingCycle = includeCycles().value(fileName); if (intersectingCycle && !intersectingCycles.contains(intersectingCycle)) { @@ -1353,7 +1250,7 @@ void CppFiles::addIncludeCycle(const QSet &fileNames) } qDeleteAll(intersectingCycles); - foreach (const QString &fileName, cycle->fileNames) + for (const QString &fileName : qAsConst(cycle->fileNames)) includeCycles().insert(fileName, cycle); } @@ -1368,9 +1265,9 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, const QS { QString cleanFile = QDir::cleanPath(file); - foreach (const QString &ex, cd.m_excludes) { - QRegExp rx(ex, Qt::CaseSensitive, QRegExp::Wildcard); - if (rx.exactMatch(cleanFile)) + for (const QString &ex : qAsConst(cd.m_excludes)) { + QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(ex)); + if (rx.match(cleanFile).hasMatch()) return; } @@ -1406,13 +1303,13 @@ void CppParser::processInclude(const QString &file, ConversionData &cd, const QS } QTextStream ts(&f); - ts.setCodec(yySourceCodec); + ts.setEncoding(yySourceEncoding); ts.setAutoDetectUnicode(true); inclusions.insert(cleanFile); if (isIndirect) { CppParser parser; - foreach (const QString &projectRoot, cd.m_projectRoots) + for (const QString &projectRoot : qAsConst(cd.m_projectRoots)) if (cleanFile.startsWith(projectRoot)) { parser.setTranslator(new Translator); break; @@ -1492,12 +1389,12 @@ bool CppParser::matchEncoding() if (yyTok == Tok_ColonColon) yyTok = getToken(); } - if (yyWord == strUnicodeUTF8 || yyWord == strDefaultCodec || yyWord == strCodecForTr) { + if (yyWord == strUnicodeUTF8) { yyTok = getToken(); return true; } - if (yyWord == strLatin1) - yyMsg() << qPrintable(LU::tr("Unsupported encoding Latin1\n")); + if (yyWord == strLatin1 || yyWord == strDefaultCodec || yyWord == strCodecForTr) + yyMsg() << qPrintable(LU::tr("Unsupported encoding Latin1/DefaultCodec/CodecForTr\n")); return false; } @@ -1784,6 +1681,7 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac pendingContext.clear(); yyWord.reserve(yyInStr.size()); // Rather insane. That's because we do no length checking. + yyWordInitialCapacity = yyWord.capacity(); yyInPtr = (const ushort *)yyInStr.unicode(); yyCh = getChar(); yyTok = getToken(); @@ -1809,13 +1707,13 @@ void CppParser::parseInternal(ConversionData &cd, const QStringList &includeStac } Q_FALLTHROUGH(); case Tok_AngledInclude: { - QStringList cSources = cd.m_allCSources.values(yyWord); + const QStringList cSources = cd.m_allCSources.values(yyWord); if (!cSources.isEmpty()) { - foreach (const QString &cSource, cSources) + for (const QString &cSource : cSources) processInclude(cSource, cd, includeStack, inclusions); goto incOk; } - foreach (const QString &incPath, cd.m_includePath) { + for (const QString &incPath : qAsConst(cd.m_includePath)) { text = QDir(incPath).absoluteFilePath(yyWord); text.detach(); if (QFileInfo(text).isFile()) { @@ -2314,7 +2212,7 @@ const ParseResults *CppParser::recordResults(bool isHeader) && results->rootNamespace.aliases.isEmpty() && results->rootNamespace.usings.isEmpty()) { // This is a forwarding header. Slash it. - pr = *results->includes.begin(); + pr = *results->includes.cbegin(); delete results; } else { results->fileId = nextFileId++; @@ -2330,9 +2228,9 @@ const ParseResults *CppParser::recordResults(bool isHeader) void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd) { - QTextCodec *codec = QTextCodec::codecForName(cd.m_sourceIsUtf16 ? "UTF-16" : "UTF-8"); + QStringConverter::Encoding e = cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8; - foreach (const QString &filename, filenames) { + for (const QString &filename : filenames) { if (!CppFiles::getResults(filename).isEmpty() || CppFiles::isBlacklisted(filename)) continue; @@ -2344,7 +2242,7 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat CppParser parser; QTextStream ts(&file); - ts.setCodec(codec); + ts.setEncoding(e); ts.setAutoDetectUnicode(true); parser.setInput(ts, filename); Translator *tor = new Translator; @@ -2354,10 +2252,10 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat parser.recordResults(isHeader(filename)); } - foreach (const QString &filename, filenames) { + for (const QString &filename : filenames) { if (!CppFiles::isBlacklisted(filename)) { if (const Translator *tor = CppFiles::getTranslator(filename)) { - foreach (const TranslatorMessage &msg, tor->messages()) + for (const TranslatorMessage &msg : tor->messages()) translator.extend(msg, cd); } } diff --git a/src/linguist/lupdate/cpp.h b/src/linguist/lupdate/cpp.h new file mode 100644 index 0000000000..d12c5e924d --- /dev/null +++ b/src/linguist/lupdate/cpp.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CPP_H +#define CPP_H + +#include "lupdate.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +struct HashString { + HashString() : m_hash(0x80000000) {} + explicit HashString(const QString &str) : m_str(str), m_hash(0x80000000) {} + void setValue(const QString &str) { m_str = str; m_hash = 0x80000000; } + const QString &value() const { return m_str; } + bool operator==(const HashString &other) const { return m_str == other.m_str; } + QString m_str; + + mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid) +}; + +struct HashStringList { + explicit HashStringList(const QList &list) : m_list(list), m_hash(0x80000000) {} + const QList &value() const { return m_list; } + bool operator==(const HashStringList &other) const { return m_list == other.m_list; } + + QList m_list; + mutable uint m_hash; // We use the highest bit as a validity indicator (set => invalid) +}; + +typedef QList NamespaceList; + +struct Namespace { + + Namespace() : + classDef(this), + hasTrFunctions(false), complained(false) + {} + ~Namespace() + { + qDeleteAll(children); + } + + QHash children; + QHash aliases; + QList usings; + + // Class declarations set no flags and create no namespaces, so they are ignored. + // Class definitions may appear multiple times - but only because we are trying to + // "compile" all sources irrespective of build configuration. + // Nested classes may be forward-declared inside a definition, and defined in another file. + // The latter will detach the class' child list, so clones need a backlink to the original + // definition (either one in case of multiple definitions). + // Namespaces can have tr() functions as well, so we need to track parent definitions for + // them as well. The complication is that we may have to deal with a forrest instead of + // a tree - in that case the parent will be arbitrary. However, it seem likely that + // Q_DECLARE_TR_FUNCTIONS would be used either in "class-like" namespaces with a central + // header or only locally in a file. + Namespace *classDef; + + QString trQualification; + + bool hasTrFunctions; + bool complained; // ... that tr functions are missing. +}; + +struct ParseResults { + int fileId; + Namespace rootNamespace; + QSet includes; +}; + +struct IncludeCycle { + QSet fileNames; + QSet results; +}; + +typedef QHash IncludeCycleHash; +typedef QHash TranslatorHash; + +class CppFiles { + +public: + static QSet getResults(const QString &cleanFile); + static void setResults(const QString &cleanFile, const ParseResults *results); + static const Translator *getTranslator(const QString &cleanFile); + static void setTranslator(const QString &cleanFile, const Translator *results); + static bool isBlacklisted(const QString &cleanFile); + static void setBlacklisted(const QString &cleanFile); + static void addIncludeCycle(const QSet &fileNames); + +private: + static IncludeCycleHash &includeCycles(); + static TranslatorHash &translatedFiles(); + static QSet &blacklistedFiles(); +}; + +QT_END_NAMESPACE + +#endif // CPP_H diff --git a/src/linguist/lupdate/cpp_clang.cpp b/src/linguist/lupdate/cpp_clang.cpp new file mode 100644 index 0000000000..59c7667cbd --- /dev/null +++ b/src/linguist/lupdate/cpp_clang.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "cpp_clang.h" +#include "clangtoolastreader.h" +#include "lupdatepreprocessoraction.h" +#include "synchronized.h" +#include "translator.h" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +using clang::tooling::CompilationDatabase; + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcClang, "qt.lupdate.clang"); + +// Makes sure all the comments will be parsed and part of the AST +// Clang will run with the flag -fparse-all-comments +clang::tooling::ArgumentsAdjuster getClangArgumentAdjuster() +{ + return [](const clang::tooling::CommandLineArguments &args, llvm::StringRef /*unused*/) { + clang::tooling::CommandLineArguments adjustedArgs; + for (size_t i = 0, e = args.size(); i < e; ++i) { + llvm::StringRef arg = args[i]; + // FIXME: Remove options that generate output. + if (!arg.startswith("-fcolor-diagnostics") && !arg.startswith("-fdiagnostics-color")) + adjustedArgs.push_back(args[i]); + } + adjustedArgs.push_back("-fparse-all-comments"); + adjustedArgs.push_back("-I"); + adjustedArgs.push_back(CLANG_RESOURCE_DIR); + adjustedArgs.push_back("-fsyntax-only"); + return adjustedArgs; + }; +} + +bool ClangCppParser::containsTranslationInformation(llvm::StringRef ba) +{ + // pre-process the files by a simple text search if there is any occurrence + // of things we are interested in + constexpr llvm::StringLiteral qDeclareTrFunction("Q_DECLARE_TR_FUNCTIONS("); + constexpr llvm::StringLiteral qtTrNoop("QT_TR_NOOP("); + constexpr llvm::StringLiteral qtTrNoopUTF8("QT_TR_NOOP)UTF8("); + constexpr llvm::StringLiteral qtTrNNoop("QT_TR_N_NOOP("); + constexpr llvm::StringLiteral qtTrIdNoop("QT_TRID_NOOP("); + constexpr llvm::StringLiteral qtTrIdNNoop("QT_TRID_N_NOOP("); + constexpr llvm::StringLiteral qtTranslateNoop("QT_TRANSLATE_NOOP("); + constexpr llvm::StringLiteral qtTranslateNoopUTF8("QT_TRANSLATE_NOOP_UTF8("); + constexpr llvm::StringLiteral qtTranslateNNoop("QT_TRANSLATE_N_NOOP("); + constexpr llvm::StringLiteral qtTranslateNoop3("QT_TRANSLATE_NOOP3("); + constexpr llvm::StringLiteral qtTranslateNoop3UTF8("QT_TRANSLATE_NOOP3_UTF8("); + constexpr llvm::StringLiteral qtTranslateNNoop3("QT_TRANSLATE_N_NOOP3("); + constexpr llvm::StringLiteral translatorComment("TRANSLATOR "); + constexpr llvm::StringLiteral qtTrId("qtTrId("); + constexpr llvm::StringLiteral tr("tr("); + constexpr llvm::StringLiteral trUtf8("trUtf8("); + constexpr llvm::StringLiteral translate("translate("); + + const size_t pos = ba.find_first_of("QT_TR"); + const auto baSliced = ba.slice(pos, llvm::StringRef::npos); + if (pos != llvm::StringRef::npos) { + if (baSliced.contains(qtTrNoop) || baSliced.contains(qtTrNoopUTF8) || baSliced.contains(qtTrNNoop) + || baSliced.contains(qtTrIdNoop) || baSliced.contains(qtTrIdNNoop) + || baSliced.contains(qtTranslateNoop) || baSliced.contains(qtTranslateNoopUTF8) + || baSliced.contains(qtTranslateNNoop) || baSliced.contains(qtTranslateNoop3) + || baSliced.contains(qtTranslateNoop3UTF8) || baSliced.contains(qtTranslateNNoop3)) + return true; + } + + if (ba.contains(qDeclareTrFunction) || ba.contains(translatorComment) || ba.contains(qtTrId) || ba.contains(tr) + || ba.contains(trUtf8) || ba.contains(translate)) + return true; + + return false; +} + +static bool generateCompilationDatabase(const QString &outputFilePath, const QStringList &sources, + const ConversionData &cd) +{ + QJsonArray commandObjects; + const QString buildDir = QDir::currentPath(); + for (const auto &source : sources) { + QFileInfo fi(source); + QJsonObject obj; + obj[QLatin1String("file")] = fi.fileName(); + obj[QLatin1String("directory")] = buildDir; + QJsonArray args = { + QLatin1String("clang++"), QLatin1String("-o"), + QString(fi.completeBaseName() + QLatin1String(".o")), + fi.fileName(), + QLatin1String("-fPIC"), + QLatin1String("-std=gnu++17") + }; + for (const QString &path : cd.m_includePath) { + QString arg = QLatin1String("-I") + path; + args.push_back(std::move(arg)); + } + obj[QLatin1String("arguments")] = args; + commandObjects.append(std::move(obj)); + } + QJsonDocument doc(commandObjects); + QFile file(outputFilePath); + if (!file.open(QIODevice::WriteOnly)) + return false; + file.write(doc.toJson()); + return true; +} + + +// Sort messages in such a way that they appear in the same order like in the given file list. +static void sortMessagesByFileOrder(ClangCppParser::TranslatorMessageVector &messages, + const QStringList &files) +{ + QHash indexByPath; + for (const TranslatorMessage &m : messages) + indexByPath[m.fileName()] = std::numeric_limits::max(); + + for (QStringList::size_type i = 0; i < files.size(); ++i) + indexByPath[files[i]] = i; + + std::stable_sort(messages.begin(), messages.end(), + [&](const TranslatorMessage &lhs, const TranslatorMessage &rhs) { + auto i = indexByPath.value(lhs.fileName()); + auto k = indexByPath.value(rhs.fileName()); + return i <= k; + }); +} + +void ClangCppParser::loadCPP(Translator &translator, const QStringList &files, ConversionData &cd, + bool *fail) +{ + // pre-process the files by a simple text search if there is any occurrence + // of things we are interested in + qCDebug(lcClang) << "Load CPP \n"; + std::vector sources, sourcesAst, sourcesPP; + for (const QString &filename : files) { + QFile file(filename); + qCDebug(lcClang) << "File: " << filename << " \n"; + if (file.open(QIODevice::ReadOnly)) { + if (const uchar *memory = file.map(0, file.size())) { + const auto ba = llvm::StringRef((const char*) (memory), file.size()); + if (containsTranslationInformation(ba)) { + sourcesPP.emplace_back(filename.toStdString()); + sourcesAst.emplace_back(sourcesPP.back()); + } + } else { + // mmap did not succeed, remember it anyway + sources.push_back(filename.toStdString()); + } + } else { + // we could not open the file, remember it anyway + sources.push_back(filename.toStdString()); + } + } + sourcesPP.insert(sourcesPP.cend(), sources.cbegin(), sources.cend()); + sourcesAst.insert(sourcesAst.cend(), sources.cbegin(), sources.cend()); + + std::string errorMessage; + std::unique_ptr db; + if (cd.m_compilationDatabaseDir.isEmpty()) { + db = CompilationDatabase::autoDetectFromDirectory(".", errorMessage); + if (!db && !files.isEmpty()) { + db = CompilationDatabase::autoDetectFromSource(files.first().toStdString(), + errorMessage); + } + } else { + db = CompilationDatabase::autoDetectFromDirectory(cd.m_compilationDatabaseDir.toStdString(), + errorMessage); + } + + if (!db) { + const QString dbFilePath = QStringLiteral("compile_commands.json"); + qCDebug(lcClang) << "Generating compilation database" << dbFilePath; + if (!generateCompilationDatabase(dbFilePath, files, cd)) { + *fail = true; + cd.appendError(LU::tr("Cannot generate compilation database.")); + return; + } + errorMessage.clear(); + db = CompilationDatabase::loadFromDirectory(".", errorMessage); + } + + if (!db) { + *fail = true; + cd.appendError(QString::fromStdString(errorMessage)); + return; + } + + TranslationStores ast, qdecl, qnoop; + Stores stores(ast, qdecl, qnoop); + + std::vector producers; + ReadSynchronizedRef ppSources(sourcesPP); + WriteSynchronizedRef ppStore(stores.Preprocessor); + size_t idealProducerCount = std::min(ppSources.size(), size_t(std::thread::hardware_concurrency())); + + for (size_t i = 0; i < idealProducerCount; ++i) { + std::thread producer([&ppSources, &db, &ppStore]() { + std::string file; + while (ppSources.next(&file)) { + clang::tooling::ClangTool tool(*db, file); + tool.appendArgumentsAdjuster(getClangArgumentAdjuster()); + tool.run(new LupdatePreprocessorActionFactory(&ppStore)); + } + }); + producers.emplace_back(std::move(producer)); + } + for (auto &producer : producers) + producer.join(); + producers.clear(); + + ReadSynchronizedRef astSources(sourcesAst); + idealProducerCount = std::min(astSources.size(), size_t(std::thread::hardware_concurrency())); + for (size_t i = 0; i < idealProducerCount; ++i) { + std::thread producer([&astSources, &db, &stores]() { + std::string file; + while (astSources.next(&file)) { + clang::tooling::ClangTool tool(*db, file); + tool.appendArgumentsAdjuster(getClangArgumentAdjuster()); + tool.run(new LupdateToolActionFactory(&stores)); + } + }); + producers.emplace_back(std::move(producer)); + } + for (auto &producer : producers) + producer.join(); + producers.clear(); + + TranslationStores finalStores; + WriteSynchronizedRef wsv(finalStores); + + ReadSynchronizedRef rsv(ast); + ClangCppParser::correctAstTranslationContext(rsv, wsv, qdecl); + + ReadSynchronizedRef rsvQNoop(qnoop); + //unlike ast translation context, qnoop context don't need to be corrected + //(because Q_DECLARE_TR_FUNCTION context is already applied). + ClangCppParser::finalize(rsvQNoop, wsv); + + TranslatorMessageVector messages; + for (const auto &store : finalStores) + ClangCppParser::collectMessages(messages, store); + + sortMessagesByFileOrder(messages, files); + + for (TranslatorMessage &msg : messages) + translator.extend(std::move(msg), cd); +} + +void ClangCppParser::collectMessages(TranslatorMessageVector &result, + const TranslationRelatedStore &store) +{ + if (!store.isValid()) + return; + qCDebug(lcClang) << "---------------------------------------------------------------Filling translator for " << store.funcName; + qCDebug(lcClang) << " contextRetrieved " << store.contextRetrieved; + qCDebug(lcClang) << " source " << store.lupdateSource; + + bool plural = false; + switch (trFunctionAliasManager.trFunctionByName(store.funcName)) { + // handle tr + case TrFunctionAliasManager::Function_QT_TR_N_NOOP: + plural = true; + Q_FALLTHROUGH(); + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + case TrFunctionAliasManager::Function_QT_TR_NOOP: + case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8: + if (!store.lupdateSourceWhenId.isEmpty()) + qCDebug(lcClang) << "//% is ignored when using tr function\n"; + if (store.contextRetrieved.isEmpty() && store.contextArg.isEmpty()) + qCDebug(lcClang) << "tr() cannot be called without context \n"; + else + result.push_back(translatorMessage(store, store.lupdateIdMetaData, plural, false)); + break; + + // handle translate and findMessage + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3: + plural = true; + Q_FALLTHROUGH(); + case TrFunctionAliasManager::Function_translate: + case TrFunctionAliasManager::Function_findMessage: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + if (!store.lupdateSourceWhenId.isEmpty()) + qCDebug(lcClang) << "//% is ignored when using translate function\n"; + result.push_back(translatorMessage(store, store.lupdateIdMetaData, plural, false)); + break; + + // handle qtTrId + case TrFunctionAliasManager::Function_QT_TRID_N_NOOP: + plural = true; + Q_FALLTHROUGH(); + case TrFunctionAliasManager::Function_qtTrId: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + if (!store.lupdateIdMetaData.isEmpty()) + qCDebug(lcClang) << "//= is ignored when using qtTrId function \n"; + result.push_back(translatorMessage(store, store.lupdateId, plural, true)); + break; + default: + if (store.funcName == QStringLiteral("TRANSLATOR")) + result.push_back(translatorMessage(store, store.lupdateIdMetaData, plural, false)); + } +} + +static QString ensureAbsolutePath(const QString &filePath) +{ + QFileInfo fi(filePath); + if (fi.isRelative()) + return QDir::current().absoluteFilePath(filePath); + return filePath; +} + +TranslatorMessage ClangCppParser::translatorMessage(const TranslationRelatedStore &store, + const QString &id, bool plural, bool isId) +{ + QString context; + if (!isId) { + context = ParserTool::transcode(store.contextArg.isEmpty() ? store.contextRetrieved + : store.contextArg); + } + + TranslatorMessage msg(context, + ParserTool::transcode(isId ? store.lupdateSourceWhenId + : store.lupdateSource), + ParserTool::transcode(store.lupdateComment), + QString(), + ensureAbsolutePath(store.lupdateLocationFile), + store.lupdateLocationLine, + QStringList(), + TranslatorMessage::Type::Unfinished, + (plural ? plural : !store.lupdatePlural.isEmpty())); + + if (!store.lupdateAllMagicMetaData.empty()) + msg.setExtras(store.lupdateAllMagicMetaData); + msg.setExtraComment(ParserTool::transcode(store.lupdateExtraComment)); + msg.setId(ParserTool::transcode(id)); + return msg; +} + +#define START_THREADS(RSV, WSV) \ + std::vector producers; \ + const size_t idealProducerCount = std::min(RSV.size(), size_t(std::thread::hardware_concurrency())); \ + \ + for (size_t i = 0; i < idealProducerCount; ++i) { \ + std::thread producer([&]() { \ + TranslationRelatedStore store; \ + while (RSV.next(&store)) { \ + if (!store.contextArg.isEmpty()) { \ + WSV.emplace_back(std::move(store)); \ + continue; \ + } + +#define JOIN_THREADS(WSV) \ + WSV.emplace_back(std::move(store)); \ + } \ + }); \ + producers.emplace_back(std::move(producer)); \ + } \ + \ + for (auto &producer : producers) \ + producer.join(); + +void ClangCppParser::finalize(ReadSynchronizedRef &ast, + WriteSynchronizedRef &newAst) +{ + START_THREADS(ast, newAst) + JOIN_THREADS(newAst) +} + +void ClangCppParser::correctAstTranslationContext(ReadSynchronizedRef &ast, + WriteSynchronizedRef &newAst, const TranslationStores &qDecl) +{ + START_THREADS(ast, newAst) + + // If there is a Q_DECLARE_TR_FUNCTION the context given there takes + // priority over the retrieved context. The retrieved context for + // Q_DECLARE_TR_FUNCTION (where the macro was) has to fit the retrieved + // context of the tr function if there is already a argument giving the + // context, it has priority + for (const auto &declareStore : qDecl) { + qCDebug(lcClang) << "----------------------------"; + qCDebug(lcClang) << "Tr call context retrieved " << store.contextRetrieved; + qCDebug(lcClang) << "Tr call source " << store.lupdateSource; + qCDebug(lcClang) << "- DECLARE context retrieved " << declareStore.contextRetrieved; + qCDebug(lcClang) << "- DECLARE context Arg " << declareStore.contextArg; + if (declareStore.contextRetrieved.isEmpty()) + continue; + if (!declareStore.contextRetrieved.startsWith(store.contextRetrieved)) + continue; + if (store.contextRetrieved == declareStore.contextRetrieved) { + qCDebug(lcClang) << "* Tr call context retrieved " << store.contextRetrieved; + qCDebug(lcClang) << "* Tr call source " << store.lupdateSource; + qCDebug(lcClang) << "* DECLARE context retrieved " << declareStore.contextRetrieved; + qCDebug(lcClang) << "* DECLARE context Arg " << declareStore.contextArg; + store.contextRetrieved = declareStore.contextArg; + // store.contextArg should never be overwritten. + break; + } + } + + JOIN_THREADS(newAst) +} + +#undef START_THREADS +#undef JOIN_THREADS + +QT_END_NAMESPACE diff --git a/src/linguist/lupdate/cpp_clang.h b/src/linguist/lupdate/cpp_clang.h new file mode 100644 index 0000000000..291b7684df --- /dev/null +++ b/src/linguist/lupdate/cpp_clang.h @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLANG_CPP_H +#define CLANG_CPP_H + +#include "lupdate.h" +#include "synchronized.h" + +#include +#include +#include + +#if defined(Q_CC_MSVC) +# pragma warning(push) +# pragma warning(disable: 4100) +# pragma warning(disable: 4146) +# pragma warning(disable: 4267) +# pragma warning(disable: 4624) +#endif + +#include +#include +#include +#include + +#if defined(Q_CC_MSVC) +# pragma warning(pop) +#endif + +#include + +QT_BEGIN_NAMESPACE + +inline QDebug operator<<(QDebug out, const std::string& str) +{ + out << QString::fromStdString(str); + return out; +} + +Q_DECLARE_LOGGING_CATEGORY(lcClang) + +inline QString toQt(llvm::StringRef str) +{ + return QString::fromUtf8(str.data(), str.size()); +} + +#define LUPDATE_CLANG_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch)) +#define LUPDATE_CLANG_VERSION LUPDATE_CLANG_VERSION_CHECK(LUPDATE_CLANG_VERSION_MAJOR, \ + LUPDATE_CLANG_VERSION_MINOR, LUPDATE_CLANG_VERSION_PATCH) + +// Local storage of translation information (information from the AST and linguist side) +struct TranslationRelatedStore +{ + QString callType; + QString rawCode; + QString funcName; + qint64 locationCol = -1; + QString contextArg; + QString contextRetrieved; + QString lupdateSource; + QString lupdateLocationFile; + qint64 lupdateLocationLine = -1; + QString lupdateId; + QString lupdateSourceWhenId; + QString lupdateIdMetaData; + QString lupdateMagicMetaData; + QHash lupdateAllMagicMetaData; + QString lupdateComment; + QString lupdateExtraComment; + QString lupdatePlural; + clang::SourceLocation sourceLocation; + + bool isValid() const + { + switch (trFunctionAliasManager.trFunctionByName(funcName)) { + // only one argument: the source + case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS: + if (contextArg.isEmpty()) + return false; + break; + case TrFunctionAliasManager::Function_tr: + case TrFunctionAliasManager::Function_trUtf8: + if (lupdateSource.isEmpty()) + return false; + break; + // two arguments: the context and the source + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3: + case TrFunctionAliasManager::Function_translate: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + if (contextArg.isEmpty() || lupdateSource.isEmpty()) + return false; + // not sure if the third argument is compulsory + break; + // only one argument (?) the message Id + case TrFunctionAliasManager::Function_QT_TRID_N_NOOP: + case TrFunctionAliasManager::Function_qtTrId: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + if (lupdateId.isEmpty()) + return false; + break; + default: + if (funcName == QStringLiteral("TRANSLATOR") && lupdateComment.isEmpty()) + return false; + } + return !lupdateLocationFile.isEmpty() && (lupdateLocationLine > -1) && (locationCol > -1); + } + + clang::SourceLocation callLocation(const clang::SourceManager &sourceManager) + { + if (sourceLocation.isInvalid()) { + auto sourceFile = sourceManager.getFileManager() + .getFile(lupdateLocationFile.toStdString()); +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + sourceLocation = sourceManager.translateFileLineCol(sourceFile.get(), + lupdateLocationLine, locationCol); +#else + sourceLocation = sourceManager.translateFileLineCol(sourceFile, lupdateLocationLine, + locationCol); +#endif + } + return sourceLocation; + } + + void printStore() const + { + qCDebug(lcClang) << "------------------ Printing Store----------------------------------\n"; + qCDebug(lcClang) + << "callType : " << callType << "\n" + << "rawCode : \n" << rawCode << "\n" + << "funcName : " << funcName << "\n" + << "LocationCol : " << locationCol << "\n" + << "contextArg : " << contextArg << "\n" + << "contextRetrieved : " << contextRetrieved << "\n" + << "lupdateSource : " << lupdateSource << "\n" + << "lupdateLocationFile : " << lupdateLocationFile << "\n" + << "lupdateLocationLine : " << lupdateLocationLine << "\n" + << "lupdateId : " << lupdateId << "\n" + << "lupdateIdMetaData : " << lupdateIdMetaData << "\n" + << "lupdateMagicMetaData: " << lupdateMagicMetaData << "\n" + << "lupdateComment : " << lupdateComment << "\n" + << "lupdateExtraComment : " << lupdateExtraComment << "\n" + << "lupdatePlural : " << lupdatePlural; + qCDebug(lcClang) << "-------------------------------------------------------------------\n"; + } +}; +using TranslationStores = std::vector; + +struct Stores +{ + Stores(TranslationStores &a, TranslationStores &qd, TranslationStores &qn) + : AST(a) + , QDeclareTrWithContext(qd) + , QNoopTranlsationWithContext(qn) + {} + + TranslationStores Preprocessor; + WriteSynchronizedRef AST; + WriteSynchronizedRef QDeclareTrWithContext; + WriteSynchronizedRef QNoopTranlsationWithContext; +}; + +namespace LupdatePrivate +{ + enum QuoteCompulsary + { + None = 0x01, + Left = 0x02, // Left quote is mandatory + Right = 0x04, // Right quote is mandatory + LeftAndRight = Left | Right // Both quotes are mandatory + }; + + /* + Removes the quotes around the lupdate extra, ID meta data, magic and + ID prefix comments and source string literals. + Depending on the given compulsory option, quotes can be unbalanced and + still some text is returned. This is to mimic the old lupdate behavior. + */ + inline QString cleanQuote(llvm::StringRef s, QuoteCompulsary quote) + { + if (s.empty()) + return {}; + s = s.trim(); + if (!s.consume_front("\"") && ((quote & Left) != 0)) + return {}; + if (!s.consume_back("\"") && ((quote & Right) != 0)) + return {}; + return toQt(s); + } + + /* + Removes the quotes and a possible existing string literal prefix + for a given string literal coming from the source code. Do not use + to clean the quotes around the lupdate translator specific comments. + */ + inline QString cleanQuote(const std::string &token) + { + if (token.empty()) + return {}; + + const QString string = QString::fromStdString(token).trimmed(); + const int index = string.indexOf(QLatin1Char('"')); + if (index <= 0) + return LupdatePrivate::cleanQuote(token, QuoteCompulsary::LeftAndRight); + + QRegularExpressionMatch result; + if (string.at(index - 1) == QLatin1Char('R')) { + static const QRegularExpression rawStringLiteral { + QStringLiteral( + "(?:\\bu8|\\b[LuU])??R\\\"([^\\(\\)\\\\ ]{0,16})\\((?.*)\\)\\1\\\"" + ), QRegularExpression::DotMatchesEverythingOption }; + result = rawStringLiteral.match(string); + } else { + static const QRegularExpression stringLiteral { + QStringLiteral( + "(?:\\bu8|\\b[LuU])+?\\\"(?[^\\\"\\\\]*(?:\\\\.[^\\\"\\\\]*)*)\\\"" + ) + }; + result = stringLiteral.match(string); + } + if (result.hasMatch()) + return result.captured(QStringLiteral("characters")); + return string; + } +} + +namespace ClangCppParser +{ + void loadCPP(Translator &translator, const QStringList &filenames, ConversionData &cd, + bool *fail); + + using TranslatorMessageVector = std::vector; + void collectMessages(TranslatorMessageVector &result, const TranslationRelatedStore &store); + TranslatorMessage translatorMessage(const TranslationRelatedStore &store, + const QString &id, bool plural, bool isID); + + void correctAstTranslationContext(ReadSynchronizedRef &ast, + WriteSynchronizedRef &newAst, const TranslationStores &qDecl); + void finalize(ReadSynchronizedRef &ast, + WriteSynchronizedRef &newAst); + + bool containsTranslationInformation(llvm::StringRef ba); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/linguist/lupdate/java.cpp b/src/linguist/lupdate/java.cpp index 40f5b9af1b..94aa99291a 100644 --- a/src/linguist/lupdate/java.cpp +++ b/src/linguist/lupdate/java.cpp @@ -32,11 +32,9 @@ #include #include -#include #include #include #include -#include #include #include @@ -45,10 +43,6 @@ QT_BEGIN_NAMESPACE -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; - enum { Tok_Eof, Tok_class, Tok_return, Tok_tr, Tok_translate, Tok_Ident, Tok_Package, Tok_Comment, Tok_String, Tok_Colon, Tok_Dot, @@ -83,7 +77,7 @@ static QChar yyCh; static QString yyIdent; static QString yyComment; static QString yyString; - +static bool yyEOF = false; static qlonglong yyInteger; static int yyParenDepth; @@ -107,12 +101,14 @@ std::ostream &yyMsg(int line = 0) static QChar getChar() { - if (yyInPos >= yyInStr.size()) - return EOF; + if (yyInPos >= yyInStr.size()) { + yyEOF = true; + return QChar(); + } QChar c = yyInStr[yyInPos++]; - if (c.unicode() == '\n') + if (c == QLatin1Char('\n')) ++yyCurLineNo; - return c.unicode(); + return c; } static int getToken() @@ -124,7 +120,7 @@ static int getToken() yyComment.clear(); yyString.clear(); - while ( yyCh != EOF ) { + while (!yyEOF) { yyLineNo = yyCurLineNo; if ( yyCh.isLetter() || yyCh.toLatin1() == '_' ) { @@ -169,7 +165,7 @@ static int getToken() if ( yyCh == QLatin1Char('/') ) { do { yyCh = getChar(); - if (yyCh == EOF) + if (yyEOF) break; yyComment.append(yyCh); } while (yyCh != QLatin1Char('\n')); @@ -181,7 +177,7 @@ static int getToken() while ( !metAsterSlash ) { yyCh = getChar(); - if ( yyCh == EOF ) { + if (yyEOF) { yyMsg() << qPrintable(LU::tr("Unterminated Java comment.\n")); return Tok_Comment; } @@ -204,7 +200,8 @@ static int getToken() case '"': yyCh = getChar(); - while ( yyCh != EOF && yyCh != QLatin1Char('\n') && yyCh != QLatin1Char('"') ) { + while (!yyEOF && yyCh != QLatin1Char('\n') && yyCh != QLatin1Char('"')) { + if ( yyCh == QLatin1Char('\\') ) { yyCh = getChar(); if ( yyCh == QLatin1Char('u') ) { @@ -257,7 +254,7 @@ static int getToken() yyCh = getChar(); do { yyCh = getChar(); - } while ( yyCh != EOF && yyCh != QLatin1Char('\'') ); + } while (!yyEOF && yyCh != QLatin1Char('\'')); yyCh = getChar(); break; case '{': @@ -453,6 +450,7 @@ static void parse(Translator *tor, ConversionData &cd) QString com; QString extracomment; + yyEOF = false; yyCh = getChar(); yyTok = getToken(); @@ -602,7 +600,7 @@ bool loadJava(Translator &translator, const QString &filename, ConversionData &c yyParenLineNo = 1; QTextStream ts(&file); - ts.setCodec(QTextCodec::codecForName(cd.m_sourceIsUtf16 ? "UTF-16" : "UTF-8")); + ts.setEncoding(cd.m_sourceIsUtf16 ? QStringConverter::Utf16 : QStringConverter::Utf8); ts.setAutoDetectUnicode(true); yyInStr = ts.readAll(); yyInPos = 0; diff --git a/src/linguist/lupdate/lupdate.h b/src/linguist/lupdate/lupdate.h index bb58cbd1e7..44336d9f5a 100644 --- a/src/linguist/lupdate/lupdate.h +++ b/src/linguist/lupdate/lupdate.h @@ -29,17 +29,19 @@ #ifndef LUPDATE_H #define LUPDATE_H -#include "qglobal.h" +#include +#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE class ConversionData; -class QStringList; class Translator; class TranslatorMessage; @@ -137,6 +139,10 @@ class TrFunctionAliasManager { mutable QHash m_nameToTrFunctionMap; }; +class LU { + Q_DECLARE_TR_FUNCTIONS(LUpdate) +}; + QT_END_NAMESPACE extern QT_PREPEND_NAMESPACE(TrFunctionAliasManager) trFunctionAliasManager; diff --git a/src/linguist/lupdate/lupdate.pro b/src/linguist/lupdate/lupdate.pro deleted file mode 100644 index 121717f036..0000000000 --- a/src/linguist/lupdate/lupdate.pro +++ /dev/null @@ -1,44 +0,0 @@ -option(host_build) -QT = core-private - -qtHaveModule(qmldevtools-private) { - QT += qmldevtools-private -} else { - DEFINES += QT_NO_QML -} - -DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII - -include(../shared/formats.pri) - -SOURCES += \ - main.cpp \ - merge.cpp \ - ../shared/projectdescriptionreader.cpp \ - ../shared/runqttool.cpp \ - ../shared/qrcreader.cpp \ - ../shared/simtexth.cpp \ - \ - cpp.cpp \ - java.cpp \ - ui.cpp - -qtHaveModule(qmldevtools-private): SOURCES += qdeclarative.cpp - -HEADERS += \ - lupdate.h \ - ../shared/projectdescriptionreader.h \ - ../shared/qrcreader.h \ - ../shared/runqttool.h \ - ../shared/simtexth.h - -mingw { - RC_FILE = lupdate.rc -} - -qmake.name = QMAKE -qmake.value = $$shell_path($$QMAKE_QMAKE) -QT_TOOL_ENV += qmake - -QMAKE_TARGET_DESCRIPTION = "Qt Translation File Update Tool" -load(qt_tool) diff --git a/src/linguist/lupdate/lupdatepreprocessoraction.cpp b/src/linguist/lupdate/lupdatepreprocessoraction.cpp new file mode 100644 index 0000000000..d66f3f053a --- /dev/null +++ b/src/linguist/lupdate/lupdatepreprocessoraction.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lupdatepreprocessoraction.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +void LupdatePPCallbacks::MacroExpands(const clang::Token &token, + const clang::MacroDefinition ¯oDefinition, clang::SourceRange sourceRange, + const clang::MacroArgs *macroArgs) +{ + Q_UNUSED(macroDefinition); + + const auto &sm = m_preprocessor.getSourceManager(); + llvm::StringRef fileName = sm.getFilename(sourceRange.getBegin()); + if (fileName != m_inputFile) + return; + + const QString funcName = QString::fromStdString(m_preprocessor.getSpelling(token)); + switch (trFunctionAliasManager.trFunctionByName(funcName)) { + default: + return; + case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + case TrFunctionAliasManager::Function_QT_TR_NOOP: + case TrFunctionAliasManager::Function_QT_TR_N_NOOP: + qCDebug(lcClang) << "MacroExpands: Function name:" << funcName; + break; + } + + TranslationRelatedStore store; + store.callType = QStringLiteral("MacroExpands"); + store.funcName = funcName; + store.lupdateLocationFile = toQt(fileName); + store.lupdateLocationLine = sm.getExpansionLineNumber(sourceRange.getBegin()); + store.locationCol = sm.getExpansionColumnNumber(sourceRange.getBegin()); + + if (macroArgs) { + std::vector arguments(macroArgs->getNumMacroArguments()); + for (unsigned i = 0; i < macroArgs->getNumMacroArguments(); i++) { + auto preExpArguments = const_cast(macroArgs)->getPreExpArgument(i, + m_preprocessor); + QString temp; + bool errorArgument = false; + for (const auto &preExpArgument : preExpArguments) { + const auto kind = preExpArgument.getKind(); + switch (trFunctionAliasManager.trFunctionByName(funcName)) { + default: + break; + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + case TrFunctionAliasManager::Function_QT_TR_NOOP: + case TrFunctionAliasManager::Function_QT_TR_N_NOOP: + if (!clang::tok::isStringLiteral(kind)) + errorArgument = true; + break; + } + if (errorArgument) + break; + if (clang::tok::isStringLiteral(kind)) + temp += LupdatePrivate::cleanQuote(m_preprocessor.getSpelling(preExpArgument)); + else + temp += QString::fromStdString(m_preprocessor.getSpelling(preExpArgument)); + } + arguments[i] = temp; + qCDebug(lcClang) << "*********** macro argument : " << temp; + } + storeMacroArguments(arguments, &store); + } + if (store.isValid()) + m_ppStores.emplace_back(std::move(store)); +} + +void LupdatePPCallbacks::storeMacroArguments(const std::vector &args, + TranslationRelatedStore *store) +{ + switch (trFunctionAliasManager.trFunctionByName(store->funcName)) { + // only one argument: the context with no " + case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS: + if (args.size() == 1) + store->contextArg = args[0]; + break; + case TrFunctionAliasManager::Function_QT_TR_NOOP: + case TrFunctionAliasManager::Function_QT_TR_N_NOOP: + if (args.size() >= 1) + store->lupdateSource = args[0]; + break; + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3: + case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8: + if (args.size() >= 2) { + store->contextArg = args[0]; + store->lupdateSource = args[1]; + } + if (args.size() == 3) + store->lupdateComment = args[2]; + break; + // only one argument (?) the message Id + case TrFunctionAliasManager::Function_QT_TRID_N_NOOP: + case TrFunctionAliasManager::Function_qtTrId: + case TrFunctionAliasManager::Function_QT_TRID_NOOP: + if (args.size() == 1) + store->lupdateId = args[0]; + break; + } +} + +// Hook called when a source range is skipped. +// Emit a warning if translation information is found within this range. +void LupdatePPCallbacks::SourceRangeSkipped(clang::SourceRange sourceRange, + clang::SourceLocation endifLoc) +{ + Q_UNUSED(endifLoc); + + const auto &sm = m_preprocessor.getSourceManager(); + llvm::StringRef fileName = sm.getFilename(sourceRange.getBegin()); + if (fileName != m_inputFile) + return; + const char *begin = sm.getCharacterData(sourceRange.getBegin()); + const char *end = sm.getCharacterData(sourceRange.getEnd()); + llvm::StringRef skippedText = llvm::StringRef(begin, end - begin); + if (ClangCppParser::containsTranslationInformation(skippedText)) { + qCDebug(lcClang) << "SourceRangeSkipped: skipped text:" << skippedText.str(); + unsigned int beginLine = sm.getExpansionLineNumber(sourceRange.getBegin()); + unsigned int endLine = sm.getExpansionLineNumber(sourceRange.getEnd()); + qWarning("Code with translation information has been skipped " + "in file %s between lines %d and %d", + m_inputFile.c_str(), beginLine, endLine); + } + +} + +QT_END_NAMESPACE diff --git a/src/linguist/lupdate/lupdatepreprocessoraction.h b/src/linguist/lupdate/lupdatepreprocessoraction.h new file mode 100644 index 0000000000..01caed52db --- /dev/null +++ b/src/linguist/lupdate/lupdatepreprocessoraction.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LUPDATEPREPROCESSORACTION_H +#define LUPDATEPREPROCESSORACTION_H + +#include "cpp_clang.h" +#include "synchronized.h" + +#if defined(Q_CC_MSVC) +# pragma warning(push) +# pragma warning(disable: 4100) +# pragma warning(disable: 4146) +# pragma warning(disable: 4267) +# pragma warning(disable: 4624) +#endif + +#include +#include +#include +#include +#include + +#if defined(Q_CC_MSVC) +# pragma warning(pop) +#endif + +#include + +QT_BEGIN_NAMESPACE + +class LupdatePPCallbacks : public clang::PPCallbacks +{ +public: + LupdatePPCallbacks(WriteSynchronizedRef *stores, clang::Preprocessor &pp) + : m_preprocessor(pp) + , m_stores(stores) + { + const auto &sm = m_preprocessor.getSourceManager(); + m_inputFile = sm.getFileEntryForID(sm.getMainFileID())->getName(); + } + + ~LupdatePPCallbacks() override + { + m_stores->emplace_bulk(std::move(m_ppStores)); + } + +private: + void MacroExpands(const clang::Token &token, const clang::MacroDefinition ¯oDefinition, + clang::SourceRange sourceRange, const clang::MacroArgs *macroArgs) override; + + void storeMacroArguments(const std::vector &args, TranslationRelatedStore *store); + + void SourceRangeSkipped(clang::SourceRange sourceRange, clang::SourceLocation endifLoc) override; + + std::string m_inputFile; + clang::Preprocessor &m_preprocessor; + + TranslationStores m_ppStores; + WriteSynchronizedRef *m_stores { nullptr }; +}; + +class LupdatePreprocessorAction : public clang::PreprocessOnlyAction +{ +public: + LupdatePreprocessorAction(WriteSynchronizedRef *stores) + : m_stores(stores) + {} + +private: + void ExecuteAction() override + { + auto &preprocessor = getCompilerInstance().getPreprocessor(); + preprocessor.SetSuppressIncludeNotFoundError(true); + auto callbacks = new LupdatePPCallbacks(m_stores, preprocessor); + preprocessor.addPPCallbacks(std::unique_ptr(callbacks)); + + clang::PreprocessOnlyAction::ExecuteAction(); + } + +private: + WriteSynchronizedRef *m_stores { nullptr }; +}; + +class LupdatePreprocessorActionFactory : public clang::tooling::FrontendActionFactory +{ +public: + explicit LupdatePreprocessorActionFactory(WriteSynchronizedRef *stores) + : m_stores(stores) + {} + +#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(10,0,0)) + std::unique_ptr create() override + { + return std::make_unique(m_stores); + } +#else + clang::FrontendAction *create() override + { + return new LupdatePreprocessorAction(m_stores); + } +#endif + +private: + WriteSynchronizedRef *m_stores { nullptr }; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/linguist/lupdate/main.cpp b/src/linguist/lupdate/main.cpp index 8bdfff4799..95620d0b49 100644 --- a/src/linguist/lupdate/main.cpp +++ b/src/linguist/lupdate/main.cpp @@ -28,6 +28,9 @@ ****************************************************************************/ #include "lupdate.h" +#if QT_CONFIG(clangcpp) +#include "cpp_clang.h" +#endif #include #include @@ -37,7 +40,6 @@ #include #include -#include #include #include #include @@ -47,6 +49,10 @@ #include +bool useClangToParseCpp = false; +QString commandLineCompilationDatabaseDir; // for the path to the json file passed as a command line argument. + // Has priority over what is in the .pro file and passed to the project. + // Can't have an array of QStaticStringData for different N, so // use QString, which requires constructor calls. Doesn't matter // much, since this is in an app, not a lib: @@ -84,9 +90,8 @@ int TrFunctionAliasManager::trFunctionByName(const QString &trFunctionName) cons { ensureTrFunctionHashUpdated(); // this function needs to be fast - const QHash::const_iterator it - = m_nameToTrFunctionMap.find(trFunctionName); - return it == m_nameToTrFunctionMap.end() ? -1 : *it; + const auto it = m_nameToTrFunctionMap.constFind(trFunctionName); + return it == m_nameToTrFunctionMap.cend() ? -1 : *it; } void TrFunctionAliasManager::modifyAlias(int trFunction, const QString &alias, Operation op) @@ -105,7 +110,7 @@ void TrFunctionAliasManager::ensureTrFunctionHashUpdated() const QHash nameToTrFunctionMap; for (int i = 0; i < NumTrFunctions; ++i) - foreach (const QString &alias, m_trFunctionAliases[i]) + for (const QString &alias : m_trFunctionAliases[i]) nameToTrFunctionMap[alias] = TrFunction(i); // commit: m_nameToTrFunctionMap.swap(nameToTrFunctionMap); @@ -197,15 +202,11 @@ static void printErr(const QString & out) std::cerr << qPrintable(out); } -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; - static void recursiveFileInfoList(const QDir &dir, const QSet &nameFilters, QDir::Filters filter, QFileInfoList *fileinfolist) { - foreach (const QFileInfo &fi, dir.entryInfoList(filter)) + for (const QFileInfo &fi : dir.entryInfoList(filter)) if (fi.isDir()) recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist); else if (nameFilters.contains(fi.suffix())) @@ -279,6 +280,16 @@ static void printUsage() " Specify the output file(s). This will override the TRANSLATIONS.\n" " -version\n" " Display the version of lupdate and exit.\n" + " -clang-parser [compilation-database-dir]\n" + " Use clang to parse cpp files. Otherwise a custom parser is used.\n" + " This option needs a clang compilation database (compile_commands.json)\n" + " for the files that needs to be parsed.\n" + " The path to the directory containing this file can be specified on the \n" + " command line, directly after the -clang-parser option, or in the .pro file\n" + " by setting the variable LUPDATE_COMPILE_COMMANDS_PATH.\n" + " A directory specified on the command line takes precedence.\n" + " If no path is given, the compilation database will be searched\n" + " in all parent paths of the first input file.\n" " @lst-file\n" " Read additional file names (one per line) or includepaths (one per\n" " line, and prefixed with -I) from lst-file.\n" @@ -289,7 +300,7 @@ static void printUsage() static bool handleTrFunctionAliases(const QString &arg) { - foreach (const QString &pair, arg.split(QLatin1Char(','), QString::SkipEmptyParts)) { + for (const QString &pair : arg.split(QLatin1Char(','), Qt::SkipEmptyParts)) { const int equalSign = pair.indexOf(QLatin1Char('=')); if (equalSign < 0) { printErr(LU::tr("tr-function mapping '%1' in -tr-function-alias is missing the '='.\n").arg(pair)); @@ -330,7 +341,7 @@ static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFil } QList aliens; - foreach (const QString &fileName, alienFiles) { + for (const QString &fileName : alienFiles) { ConversionData cd; Translator tor; if (!tor.load(fileName, cd, QLatin1String("auto"))) { @@ -344,7 +355,7 @@ static void updateTsFiles(const Translator &fetchedTor, const QStringList &tsFil QDir dir; QString err; - foreach (const QString &fileName, tsFileNames) { + for (const QString &fileName : tsFileNames) { QString fn = dir.relativeFilePath(fileName); ConversionData cd; Translator tor; @@ -466,11 +477,11 @@ static QStringList getResources(const QString &resourceFile) static bool processTs(Translator &fetchedTor, const QString &file, ConversionData &cd) { - foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { + for (const Translator::FileFormat &fmt : qAsConst(Translator::registeredFileFormats())) { if (file.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) { Translator tor; if (tor.load(file, cd, fmt.extension)) { - foreach (TranslatorMessage msg, tor.messages()) { + for (TranslatorMessage msg : tor.messages()) { msg.setType(TranslatorMessage::Unfinished); msg.setTranslations(QStringList()); msg.setTranslatorComment(QString()); @@ -484,32 +495,32 @@ static bool processTs(Translator &fetchedTor, const QString &file, ConversionDat } static void processSources(Translator &fetchedTor, - const QStringList &sourceFiles, ConversionData &cd) + const QStringList &sourceFiles, ConversionData &cd, bool *fail) { #ifdef QT_NO_QML bool requireQmlSupport = false; #endif QStringList sourceFilesCpp; - for (QStringList::const_iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) { - if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive)) - loadJava(fetchedTor, *it, cd); - else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive) - || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive)) - loadUI(fetchedTor, *it, cd); + for (const auto &sourceFile : sourceFiles) { + if (sourceFile.endsWith(QLatin1String(".java"), Qt::CaseInsensitive)) + loadJava(fetchedTor, sourceFile, cd); + else if (sourceFile.endsWith(QLatin1String(".ui"), Qt::CaseInsensitive) + || sourceFile.endsWith(QLatin1String(".jui"), Qt::CaseInsensitive)) + loadUI(fetchedTor, sourceFile, cd); #ifndef QT_NO_QML - else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive) - || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) - loadQScript(fetchedTor, *it, cd); - else if (it->endsWith(QLatin1String(".qml"), Qt::CaseInsensitive)) - loadQml(fetchedTor, *it, cd); + else if (sourceFile.endsWith(QLatin1String(".js"), Qt::CaseInsensitive) + || sourceFile.endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) + loadQScript(fetchedTor, sourceFile, cd); + else if (sourceFile.endsWith(QLatin1String(".qml"), Qt::CaseInsensitive)) + loadQml(fetchedTor, sourceFile, cd); #else - else if (it->endsWith(QLatin1String(".qml"), Qt::CaseInsensitive) - || it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive) - || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) + else if (sourceFile.endsWith(QLatin1String(".qml"), Qt::CaseInsensitive) + || sourceFile.endsWith(QLatin1String(".js"), Qt::CaseInsensitive) + || sourceFile.endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) requireQmlSupport = true; #endif // QT_NO_QML - else if (!processTs(fetchedTor, *it, cd)) - sourceFilesCpp << *it; + else if (!processTs(fetchedTor, sourceFile, cd)) + sourceFilesCpp << sourceFile; } #ifdef QT_NO_QML @@ -517,7 +528,17 @@ static void processSources(Translator &fetchedTor, printErr(LU::tr("lupdate warning: Some files have been ignored due to missing qml/javascript support\n")); #endif - loadCPP(fetchedTor, sourceFilesCpp, cd); + if (useClangToParseCpp) { +#if QT_CONFIG(clangcpp) + ClangCppParser::loadCPP(fetchedTor, sourceFilesCpp, cd, fail); +#else + *fail = true; + printErr(LU::tr("lupdate error: lupdate was built without clang support.")); +#endif + } + else + loadCPP(fetchedTor, sourceFilesCpp, cd); + if (!cd.error().isEmpty()) printErr(cd.error()); } @@ -583,9 +604,13 @@ class ProjectProcessor cd.m_includePath = prj.includePaths; cd.m_excludes = prj.excluded; cd.m_sourceIsUtf16 = options & SourceIsUtf16; + if (commandLineCompilationDatabaseDir.isEmpty()) + cd.m_compilationDatabaseDir = prj.compileCommands; + else + cd.m_compilationDatabaseDir = commandLineCompilationDatabaseDir; QStringList tsFiles; - if (hasTranslations(prj)) { + if (prj.translations) { tsFiles = *prj.translations; if (parentTor) { if (topLevel) { @@ -606,7 +631,7 @@ class ProjectProcessor } Translator tor; processProjects(false, options, prj.subProjects, false, &tor, fail); - processSources(tor, sources, cd); + processSources(tor, sources, cd, fail); updateTsFiles(tor, tsFiles, QStringList(), m_sourceLanguage, m_targetLanguage, options, fail); return; @@ -620,10 +645,10 @@ class ProjectProcessor } Translator tor; processProjects(false, options, prj.subProjects, nestComplain, &tor, fail); - processSources(tor, sources, cd); + processSources(tor, sources, cd, fail); } else { processProjects(false, options, prj.subProjects, nestComplain, parentTor, fail); - processSources(*parentTor, sources, cd); + processSources(*parentTor, sources, cd, fail); } } @@ -639,7 +664,7 @@ int main(int argc, char **argv) QTranslator translator; QTranslator qtTranslator; QString sysLocale = QLocale::system().name(); - QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + QString resourceDir = QLibraryInfo::path(QLibraryInfo::TranslationsPath); if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir) && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir)) { app.installTranslator(&translator); @@ -837,7 +862,19 @@ int main(int argc, char **argv) includePath += args[i].mid(2); } continue; - } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) { + } +#if QT_CONFIG(clangcpp) + else if (arg == QLatin1String("-clang-parser")) { + useClangToParseCpp = true; + // the option after -clang-parser is optional + if ((i + 1) != argc && !args[i + 1].startsWith(QLatin1String("-"))) { + i++; + commandLineCompilationDatabaseDir = args[i]; + } + continue; + } +#endif + else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) { printErr(LU::tr("Unrecognized option '%1'.\n").arg(arg)); return 1; } @@ -867,9 +904,9 @@ int main(int argc, char **argv) files << arg; } if (metTsFlag) { - foreach (const QString &file, files) { + for (const QString &file : qAsConst(files)) { bool found = false; - foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { + for (const Translator::FileFormat &fmt : qAsConst(Translator::registeredFileFormats())) { if (file.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) { QFileInfo fi(file); if (!fi.exists() || fi.isWritable()) { @@ -892,7 +929,7 @@ int main(int argc, char **argv) } else if (metXTsFlag) { alienFiles += files; } else { - foreach (const QString &file, files) { + for (const QString &file : qAsConst(files)) { QFileInfo fi(file); if (!fi.exists()) { printErr(LU::tr("lupdate error: File '%1' does not exist.\n").arg(file)); @@ -907,7 +944,7 @@ int main(int argc, char **argv) QDir dir = QDir(fi.filePath()); projectRoots.insert(dir.absolutePath() + QLatin1Char('/')); if (extensionsNameFilters.isEmpty()) { - foreach (QString ext, extensions.split(QLatin1Char(','))) { + for (QString ext : extensions.split(QLatin1Char(','))) { ext = ext.trimmed(); if (ext.startsWith(QLatin1Char('.'))) ext.remove(0, 1); @@ -920,7 +957,7 @@ int main(int argc, char **argv) QFileInfoList fileinfolist; recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist); int scanRootLen = dir.absolutePath().length(); - foreach (const QFileInfo &fi, fileinfolist) { + for (const QFileInfo &fi : qAsConst(fileinfolist)) { QString fn = QDir::cleanPath(fi.absoluteFilePath()); if (fn.endsWith(QLatin1String(".qrc"), Qt::CaseInsensitive)) { resourceFiles << fn; @@ -967,7 +1004,7 @@ int main(int argc, char **argv) QString errorString; if (!proFiles.isEmpty()) { - runQtTool(QStringLiteral("lupdate-pro"), app.arguments().mid(1)); + runInternalQtTool(QStringLiteral("lupdate-pro"), app.arguments().mid(1)); return 0; } @@ -999,9 +1036,10 @@ int main(int argc, char **argv) cd.m_projectRoots = projectRoots; cd.m_includePath = includePath; cd.m_allCSources = allCSources; + cd.m_compilationDatabaseDir = commandLineCompilationDatabaseDir; for (const QString &resource : qAsConst(resourceFiles)) sourceFiles << getResources(resource); - processSources(fetchedTor, sourceFiles, cd); + processSources(fetchedTor, sourceFiles, cd, &fail); updateTsFiles(fetchedTor, tsFileNames, alienFiles, sourceLanguage, targetLanguage, options, &fail); } else { diff --git a/src/linguist/lupdate/merge.cpp b/src/linguist/lupdate/merge.cpp index f413610f9a..9db8826c8d 100644 --- a/src/linguist/lupdate/merge.cpp +++ b/src/linguist/lupdate/merge.cpp @@ -33,16 +33,12 @@ #include #include +#include #include #include -#include QT_BEGIN_NAMESPACE -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; - static bool isDigitFriendly(QChar c) { return c.isPunct() || c.isSpace(); @@ -97,8 +93,8 @@ static QString translationAttempt(const QString &oldTranslation, QString attempt; QStringList oldNumbers; QStringList newNumbers; - QVector met(p); - QVector matchedYet(p); + QList met(p); + QList matchedYet(p); int i, j; int k = 0, ell, best; int m, n; @@ -213,7 +209,7 @@ static QString translationAttempt(const QString &oldTranslation, int applyNumberHeuristic(Translator &tor) { QMap > translated; - QVector untranslated(tor.messageCount()); + QList untranslated(tor.messageCount()); int inserted = 0; for (int i = 0; i < tor.messageCount(); ++i) { @@ -234,8 +230,7 @@ int applyNumberHeuristic(Translator &tor) TranslatorMessage &msg = tor.message(i); const QString &key = zeroKey(msg.sourceText()); if (!key.isEmpty()) { - QMap >::ConstIterator t = - translated.constFind(key); + const auto t = translated.constFind(key); if (t != translated.constEnd() && t->first != msg.sourceText()) { msg.setTranslation(translationAttempt(t->second, t->first, msg.sourceText())); @@ -262,7 +257,7 @@ int applySameTextHeuristic(Translator &tor) { QMap translated; QMap avoid; // Want a QTreeSet, in fact - QVector untranslated(tor.messageCount()); + QList untranslated(tor.messageCount()); int inserted = 0; for (int i = 0; i < tor.messageCount(); ++i) { @@ -272,7 +267,7 @@ int applySameTextHeuristic(Translator &tor) untranslated[i] = true; } else { const QString &key = msg.sourceText(); - QMap::ConstIterator t = translated.constFind(key); + const auto t = translated.constFind(key); if (t != translated.constEnd()) { /* The same source text is translated at least two @@ -291,7 +286,7 @@ int applySameTextHeuristic(Translator &tor) for (int i = 0; i < tor.messageCount(); ++i) { if (untranslated[i]) { TranslatorMessage &msg = tor.message(i); - QMap::ConstIterator t = translated.constFind(msg.sourceText()); + const auto t = translated.constFind(msg.sourceText()); if (t != translated.constEnd()) { msg.setTranslations(*t); ++inserted; @@ -329,7 +324,7 @@ Translator merge( The types of all the messages from the vernacular translator are updated according to the virgin translator. */ - foreach (TranslatorMessage m, tor.messages()) { + for (TranslatorMessage m : tor.messages()) { TranslatorMessage::Type newType = TranslatorMessage::Finished; if (m.sourceText().isEmpty() && m.id().isEmpty()) { @@ -450,7 +445,7 @@ Translator merge( Messages found only in the virgin translator are added to the vernacular translator. */ - foreach (const TranslatorMessage &mv, virginTor.messages()) { + for (const TranslatorMessage &mv : virginTor.messages()) { if (mv.sourceText().isEmpty() && mv.id().isEmpty()) { if (tor.find(mv.context()) >= 0) continue; @@ -481,8 +476,8 @@ Translator merge( /* "Alien" translators can be used to augment the vernacular translator. */ - foreach (const Translator &alf, aliens) { - foreach (TranslatorMessage mv, alf.messages()) { + for (const Translator &alf : aliens) { + for (TranslatorMessage mv : alf.messages()) { if (mv.sourceText().isEmpty() || !mv.isTranslated()) continue; int mvi = outTor.find(mv); diff --git a/src/linguist/lupdate/qdeclarative.cpp b/src/linguist/lupdate/qdeclarative.cpp index fa8ad260e6..753c239adb 100644 --- a/src/linguist/lupdate/qdeclarative.cpp +++ b/src/linguist/lupdate/qdeclarative.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -52,9 +53,11 @@ QT_BEGIN_NAMESPACE -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; +#if Q_QML_PRIVATE_API_VERSION < 8 +namespace QQmlJS { + using SourceLocation = AST::SourceLocation; +} +#endif using namespace QQmlJS; @@ -88,7 +91,7 @@ class FindTrCalls: protected AST::Visitor void accept(AST::Node *node) { AST::Node::acceptChild(node, this); } - void endVisit(AST::CallExpression *node) + void endVisit(AST::CallExpression *node) override { QString name; AST::ExpressionNode *base = node->base; @@ -112,6 +115,10 @@ class FindTrCalls: protected AST::Visitor yyMsg(identLineNo) << qPrintable(LU::tr("%1() requires at least one argument.\n").arg(name)); return; } + if (AST::cast(node->arguments->expression)) { + yyMsg(identLineNo) << qPrintable(LU::tr("%1() cannot be used with template literals. Ignoring\n").arg(name)); + return; + } QString source; if (!createString(node->arguments->expression, &source)) @@ -213,7 +220,7 @@ class FindTrCalls: protected AST::Visitor } } - virtual void postVisit(AST::Node *node); + void postVisit(AST::Node *node) override; private: std::ostream &yyMsg(int line) @@ -229,7 +236,7 @@ class FindTrCalls: protected AST::Visitor void processComments(quint32 offset, bool flush = false); - void processComment(const AST::SourceLocation &loc); + void processComment(const SourceLocation &loc); void consumeComment(); bool createString(AST::ExpressionNode *ast, QString *out) @@ -259,7 +266,7 @@ class FindTrCalls: protected AST::Visitor TranslatorMessage::ExtraData extra; QString sourcetext; QString trcontext; - QList m_todo; + QList m_todo; }; QString createErrorString(const QString &filename, const QString &code, Parser &parser) @@ -269,33 +276,29 @@ QString createErrorString(const QString &filename, const QString &code, Parser & lines.append(QLatin1String("\n")); // sentinel. QString errorString; - foreach (const DiagnosticMessage &m, parser.diagnosticMessages()) { + const auto messages = parser.diagnosticMessages(); + for (const DiagnosticMessage &m : messages) { if (m.isWarning()) continue; - QString error = filename + QLatin1Char(':') + QString::number(m.loc.startLine) - + QLatin1Char(':') + QString::number(m.loc.startColumn) + QLatin1String(": error: ") - + m.message + QLatin1Char('\n'); - - int line = 0; - if (m.loc.startLine > 0) - line = m.loc.startLine - 1; - - const QString textLine = lines.at(line); - +#if Q_QML_PRIVATE_API_VERSION >= 8 + const int line = m.loc.startLine; + const int column = m.loc.startColumn; +#else + const int line = m.line; + const int column = m.column; +#endif + QString error = filename + QLatin1Char(':') + + QString::number(line) + QLatin1Char(':') + QString::number(column) + + QLatin1String(": error: ") + m.message + QLatin1Char('\n'); + + const QString textLine = lines.at(line > 0 ? line - 1 : 0); error += textLine + QLatin1Char('\n'); - - int column = m.loc.startColumn - 1; - if (column < 0) - column = 0; - - column = qMin(column, textLine.length()); - - for (int i = 0; i < column; ++i) { + for (int i = 0, end = qMin(column > 0 ? column - 1 : 0, textLine.length()); i < end; ++i) { const QChar ch = textLine.at(i); if (ch.isSpace()) - error += ch.unicode(); + error += ch; else error += QLatin1Char(' '); } @@ -320,7 +323,7 @@ void FindTrCalls::postVisit(AST::Node *node) void FindTrCalls::processComments(quint32 offset, bool flush) { for (; !m_todo.isEmpty(); m_todo.removeFirst()) { - AST::SourceLocation loc = m_todo.first(); + SourceLocation loc = m_todo.first(); if (! flush && (loc.begin() >= offset)) break; @@ -337,12 +340,12 @@ void FindTrCalls::consumeComment() sourcetext.clear(); } -void FindTrCalls::processComment(const AST::SourceLocation &loc) +void FindTrCalls::processComment(const SourceLocation &loc) { if (!loc.length) return; - const QStringRef commentStr = engine->midRef(loc.begin(), loc.length); + const QStringView commentStr = engine->midRef(loc.begin(), loc.length); const QChar *chars = commentStr.constData(); const int length = commentStr.length(); @@ -467,8 +470,6 @@ static bool load(Translator &translator, const QString &filename, ConversionData code = QTextStream(&file).readAll(); } else { QTextStream ts(&file); - ts.setCodec("UTF-8"); - ts.setAutoDetectUnicode(true); code = ts.readAll(); } diff --git a/src/linguist/lupdate/synchronized.h b/src/linguist/lupdate/synchronized.h new file mode 100644 index 0000000000..46cbca57cc --- /dev/null +++ b/src/linguist/lupdate/synchronized.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SYNCHRONIZED_H +#define SYNCHRONIZED_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +template class WriteSynchronizedRef +{ + Q_DISABLE_COPY_MOVE(WriteSynchronizedRef) + +public: + WriteSynchronizedRef(std::vector &vector) Q_DECL_NOEXCEPT + : m_vector(vector) + {} + + void emplace_back(T &&value) + { + QMutexLocker lock(&m_mutex); + m_vector.push_back(std::move(value)); + } + + void emplace_back(const T &value) + { + QMutexLocker lock(&m_mutex); + m_vector.emplace_back(value); + } + + void emplace_bulk(std::vector && values) + { + QMutexLocker lock(&m_mutex); + if (!m_vector.empty()) { + m_vector.insert(m_vector.cend(), std::make_move_iterator(values.begin()), + std::make_move_iterator(values.end())); + } else { + m_vector = std::move(values); + } + } + +private: + mutable QMutex m_mutex; + std::vector &m_vector; +}; + +template class ReadSynchronizedRef +{ + Q_DISABLE_COPY_MOVE(ReadSynchronizedRef) + +public: + ReadSynchronizedRef(const std::vector &v) noexcept + : m_vector(v) + {} + + size_t size() const + { + return m_vector.size(); + } + + bool next(T *value) const + { + const auto idx = m_next.fetch_add(1, std::memory_order_acquire); + const bool hasNext = idx < m_vector.size(); + if (hasNext) + *value = m_vector[idx]; + return hasNext; + } + +private: + const std::vector &m_vector; + mutable std::atomic m_next = 0; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/linguist/lupdate/ui.cpp b/src/linguist/lupdate/ui.cpp index 417f32cc6b..5f84a92fc4 100644 --- a/src/linguist/lupdate/ui.cpp +++ b/src/linguist/lupdate/ui.cpp @@ -29,44 +29,41 @@ #include "lupdate.h" #include +#include #include #include #include #include - -#include -#include -#include -#include - +#include QT_BEGIN_NAMESPACE -class LU { - Q_DECLARE_TR_FUNCTIONS(LUpdate) -}; - -class UiReader : public QXmlDefaultHandler +class UiReader : public XmlParser { public: - UiReader(Translator &translator, ConversionData &cd) - : m_translator(translator), m_cd(cd), m_lineNumber(-1), m_isTrString(false), - m_insideStringList(false), m_idBasedTranslations(false) - {} - - bool startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts); - bool endElement(const QString &namespaceURI, const QString &localName, - const QString &qName); - bool characters(const QString &ch); - bool fatalError(const QXmlParseException &exception); - - void setDocumentLocator(QXmlLocator *locator) { m_locator = locator; } + UiReader(Translator &translator, ConversionData &cd, QXmlStreamReader &reader) + : XmlParser(reader), + m_translator(translator), + m_cd(cd), + m_lineNumber(-1), + m_isTrString(false), + m_insideStringList(false), + m_idBasedTranslations(false) + { + } + ~UiReader() override = default; private: + bool startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) override; + bool endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) override; + bool characters(QStringView ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; + void flush(); - void readTranslationAttributes(const QXmlAttributes &atts); + void readTranslationAttributes(const QXmlStreamAttributes &atts); Translator &m_translator; ConversionData &m_cd; @@ -75,7 +72,6 @@ class UiReader : public QXmlDefaultHandler QString m_comment; QString m_extracomment; QString m_id; - QXmlLocator *m_locator; QString m_accum; int m_lineNumber; @@ -84,8 +80,8 @@ class UiReader : public QXmlDefaultHandler bool m_idBasedTranslations; }; -bool UiReader::startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts) +bool UiReader::startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); @@ -99,16 +95,16 @@ bool UiReader::startElement(const QString &namespaceURI, m_insideStringList = true; readTranslationAttributes(atts); } else if (qName == QLatin1String("ui")) { // UI "header" - const int translationTypeIndex = atts.index(QStringLiteral("idbasedtr")); - m_idBasedTranslations = translationTypeIndex >= 0 - && atts.value(translationTypeIndex) == QLatin1String("true"); + const auto attr = QStringLiteral("idbasedtr"); + m_idBasedTranslations = + atts.hasAttribute(attr) && atts.value(attr) == QLatin1String("true"); } m_accum.clear(); return true; } -bool UiReader::endElement(const QString &namespaceURI, - const QString &localName, const QString &qName) +bool UiReader::endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); @@ -131,17 +127,18 @@ bool UiReader::endElement(const QString &namespaceURI, return true; } -bool UiReader::characters(const QString &ch) +bool UiReader::characters(QStringView ch) { - m_accum += ch; + m_accum += ch.toString(); return true; } -bool UiReader::fatalError(const QXmlParseException &exception) +bool UiReader::fatalError(qint64 line, qint64 column, const QString &message) { QString msg = LU::tr("XML error: Parse error at line %1, column %2 (%3).") - .arg(exception.lineNumber()).arg(exception.columnNumber()) - .arg(exception.message()); + .arg(line) + .arg(column) + .arg(message); m_cd.appendError(msg); return false; } @@ -164,17 +161,17 @@ void UiReader::flush() } } -void UiReader::readTranslationAttributes(const QXmlAttributes &atts) +void UiReader::readTranslationAttributes(const QXmlStreamAttributes &atts) { - const QString notr = atts.value(QStringLiteral("notr")); + const auto notr = atts.value(QStringLiteral("notr")); if (notr.isEmpty() || notr != QStringLiteral("true")) { m_isTrString = true; - m_comment = atts.value(QStringLiteral("comment")); - m_extracomment = atts.value(QStringLiteral("extracomment")); + m_comment = atts.value(QStringLiteral("comment")).toString(); + m_extracomment = atts.value(QStringLiteral("extracomment")).toString(); if (m_idBasedTranslations) - m_id = atts.value(QStringLiteral("id")); + m_id = atts.value(QStringLiteral("id")).toString(); if (!m_cd.m_noUiLines) - m_lineNumber = m_locator->lineNumber(); + m_lineNumber = static_cast(reader.lineNumber()); } else { m_isTrString = false; } @@ -188,20 +185,14 @@ bool loadUI(Translator &translator, const QString &filename, ConversionData &cd) cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString())); return false; } - QXmlInputSource in(&file); - QXmlSimpleReader reader; - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); - reader.setFeature(QLatin1String( - "http://trolltech.com/xml/features/report-whitespace-only-CharData"), false); - UiReader handler(translator, cd); - reader.setContentHandler(&handler); - reader.setErrorHandler(&handler); - bool result = reader.parse(in); + + QXmlStreamReader reader(&file); + reader.setNamespaceProcessing(false); + + UiReader uiReader(translator, cd, reader); + bool result = uiReader.parse(); if (!result) cd.appendError(LU::tr("Parse error in UI file")); - reader.setContentHandler(0); - reader.setErrorHandler(0); return result; } diff --git a/src/linguist/shared/formats.pri b/src/linguist/shared/formats.pri deleted file mode 100644 index e5f388f2a8..0000000000 --- a/src/linguist/shared/formats.pri +++ /dev/null @@ -1,22 +0,0 @@ - -# infrastructure -QT *= xml - -INCLUDEPATH *= $$PWD - -SOURCES += \ - $$PWD/numerus.cpp \ - $$PWD/translator.cpp \ - $$PWD/translatormessage.cpp - -HEADERS += \ - $$PWD/translator.h \ - $$PWD/translatormessage.h - -# "real" formats readers and writers -SOURCES += \ - $$PWD/qm.cpp \ - $$PWD/qph.cpp \ - $$PWD/po.cpp \ - $$PWD/ts.cpp \ - $$PWD/xliff.cpp diff --git a/src/linguist/shared/ioutils.cpp b/src/linguist/shared/ioutils.cpp index 12e3d63f59..d943484404 100644 --- a/src/linguist/shared/ioutils.cpp +++ b/src/linguist/shared/ioutils.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #ifdef Q_OS_WIN # include @@ -86,14 +86,14 @@ bool IoUtils::isRelativePath(const QString &path) return true; } -QStringRef IoUtils::pathName(const QString &fileName) +QStringView IoUtils::pathName(QStringView fileName) { - return fileName.leftRef(fileName.lastIndexOf(QLatin1Char('/')) + 1); + return fileName.left(fileName.lastIndexOf(QLatin1Char('/')) + 1); } -QStringRef IoUtils::fileName(const QString &fileName) +QStringView IoUtils::fileName(QStringView fileName) { - return fileName.midRef(fileName.lastIndexOf(QLatin1Char('/')) + 1); + return fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1); } QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName) @@ -173,9 +173,9 @@ QString IoUtils::shellQuoteWin(const QString &arg) // The process-level standard quoting allows escaping quotes with backslashes (note // that backslashes don't escape themselves, unless they are followed by a quote). // Consequently, quotes are escaped and their preceding backslashes are doubled. - ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); + ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\"")); // Trailing backslashes must be doubled as well, as they are followed by a quote. - ret.replace(QRegExp(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1")); + ret.replace(QRegularExpression(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1")); // However, the shell also interprets the command, and no backslash-escaping exists // there - a quote always toggles the quoting state, but is nonetheless passed down // to the called process verbatim. In the unquoted state, the circumflex escapes diff --git a/src/linguist/shared/ioutils.h b/src/linguist/shared/ioutils.h index 6887223efa..8726a35c3f 100644 --- a/src/linguist/shared/ioutils.h +++ b/src/linguist/shared/ioutils.h @@ -53,8 +53,8 @@ class QMAKE_EXPORT IoUtils { static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; } static bool isRelativePath(const QString &fileName); static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); } - static QStringRef pathName(const QString &fileName); // Requires normalized path - static QStringRef fileName(const QString &fileName); // Requires normalized path + static QStringView pathName(QStringView fileName); // Requires normalized path + static QStringView fileName(QStringView fileName); // Requires normalized path static QString resolvePath(const QString &baseDir, const QString &fileName); static QString shellQuoteUnix(const QString &arg); static QString shellQuoteWin(const QString &arg); diff --git a/src/linguist/shared/numerus.cpp b/src/linguist/shared/numerus.cpp index 6a1ca8130e..5b48952339 100644 --- a/src/linguist/shared/numerus.cpp +++ b/src/linguist/shared/numerus.cpp @@ -162,7 +162,6 @@ static const QLocale::Language englishStyleLanguages[] = { QLocale::Bashkir, QLocale::Basque, QLocale::Bengali, - QLocale::Bihari, QLocale::Bulgarian, QLocale::Catalan, QLocale::Cornish, @@ -206,7 +205,7 @@ static const QLocale::Language englishStyleLanguages[] = { // Missing: Nahuatl, QLocale::Nepali, QLocale::NorthernSotho, - QLocale::NorwegianBokmal, // same as Norwegian + QLocale::NorwegianBokmal, QLocale::NorwegianNynorsk, QLocale::Occitan, QLocale::Oriya, @@ -232,7 +231,6 @@ static const QLocale::Language englishStyleLanguages[] = { QLocale::Tsonga, QLocale::Tswana, QLocale::Turkmen, - // QLocale::Twi, // mapped to Akan QLocale::Uigur, QLocale::Urdu, QLocale::Uzbek, @@ -278,13 +276,11 @@ static const QLocale::Language russianStyleLanguages[] = { QLocale::Croatian, QLocale::Russian, QLocale::Serbian, - // QLocale::SerboCroatian, // deprecated, mapped to Serbian QLocale::Ukrainian, EOL }; static const QLocale::Language polishLanguage[] = { QLocale::Polish, EOL }; static const QLocale::Language romanianLanguages[] = { - // QLocale::Moldavian, // deprecated, mapped to Romanian QLocale::Romanian, EOL }; @@ -292,7 +288,7 @@ static const QLocale::Language slovenianLanguage[] = { QLocale::Slovenian, EOL } static const QLocale::Language malteseLanguage[] = { QLocale::Maltese, EOL }; static const QLocale::Language welshLanguage[] = { QLocale::Welsh, EOL }; static const QLocale::Language arabicLanguage[] = { QLocale::Arabic, EOL }; -static const QLocale::Language tagalogLanguage[] = { QLocale::Tagalog, EOL }; +static const QLocale::Language tagalogLanguage[] = { QLocale::Filipino, EOL }; static const QLocale::Country frenchStyleCountries[] = { // keep synchronized with frenchStyleLanguages diff --git a/src/linguist/shared/po.cpp b/src/linguist/shared/po.cpp index 4e623e6a34..d9aa24bbd0 100644 --- a/src/linguist/shared/po.cpp +++ b/src/linguist/shared/po.cpp @@ -31,9 +31,9 @@ #include #include #include -#include +#include #include -#include +#include #include #include @@ -103,10 +103,10 @@ static QString poEscapedString(const QString &prefix, const QString &keyword, if (lines.count() != 1 || lines.first().length() > MAX_LEN - keyword.length() - prefix.length() - 3) { - QStringList olines = lines; + const QStringList olines = lines; lines = QStringList(QString()); const int maxlen = MAX_LEN - prefix.length() - 2; - foreach (const QString &line, olines) { + for (const QString &line : olines) { int off = 0; while (off + maxlen < line.length()) { int idx = line.lastIndexOf(QLatin1Char(' '), off + maxlen - 1) + 1; @@ -138,7 +138,7 @@ static QString poEscapedString(const QString &prefix, const QString &keyword, static QString poEscapedLines(const QString &prefix, bool addSpace, const QStringList &lines) { QString out; - foreach (const QString &line, lines) { + for (const QString &line : lines) { out += prefix; if (addSpace && !line.isEmpty()) out += QLatin1Char(' ' ); @@ -397,7 +397,7 @@ static QByteArray QByteArrayList_join(const QList &that, char sep) bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) { - QTextCodec *codec = QTextCodec::codecForName("UTF-8"); + QStringDecoder toUnicode(QStringConverter::Utf8, QStringDecoder::Flag::Stateless); bool error = false; // format of a .po file entry: @@ -447,7 +447,7 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) QHash extras; QList hdrOrder; QByteArray pluralForms; - foreach (const QByteArray &hdr, item.msgStr.first().split('\n')) { + for (const QByteArray &hdr : item.msgStr.first().split('\n')) { if (hdr.isEmpty()) continue; int idx = hdr.indexOf(':'); @@ -476,18 +476,18 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) .arg(QString::fromLatin1(hdrValue))); error = true; // This will avoid a flood of conversion errors. - codec = QTextCodec::codecForName("latin1"); + toUnicode = QStringConverter::Latin1; } else { QByteArray cod = hdrValue.mid(20); - QTextCodec *cdc = QTextCodec::codecForName(cod); - if (!cdc) { - cd.appendError(QString::fromLatin1("Unsupported codec '%1'") + auto enc = QStringConverter::encodingForName(cod); + if (!enc) { + cd.appendError(QString::fromLatin1("Unsupported encoding '%1'") .arg(QString::fromLatin1(cod))); error = true; // This will avoid a flood of conversion errors. - codec = QTextCodec::codecForName("latin1"); + toUnicode = QStringConverter::Latin1; } else { - codec = cdc; + toUnicode = *enc; } } } else if (hdrName == "Content-Transfer-Encoding") { @@ -534,21 +534,19 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) extras[QLatin1String("po-header_comment")] = QByteArrayList_join(lines.mid(0, lastCmtLine + 1), '\n'); } - for (QHash::ConstIterator it = extras.constBegin(), - end = extras.constEnd(); - it != end; ++it) - translator.setExtra(it.key(), codec->toUnicode(it.value())); + for (auto it = extras.cbegin(), end = extras.cend(); it != end; ++it) + translator.setExtra(it.key(), toUnicode(it.value())); item = PoItem(); continue; } // build translator message TranslatorMessage msg; - msg.setContext(codec->toUnicode(item.context)); + msg.setContext(toUnicode(item.context)); if (!item.references.isEmpty()) { QString xrefs; - foreach (const QString &ref, - codec->toUnicode(item.references).split( - QRegExp(QLatin1String("\\s")), QString::SkipEmptyParts)) { + for (const QString &ref : + QString(toUnicode(item.references)).split( + QRegularExpression(QLatin1String("\\s")), Qt::SkipEmptyParts)) { int pos = ref.indexOf(QLatin1Char(':')); int lpos = ref.lastIndexOf(QLatin1Char(':')); if (pos != -1 && pos == lpos) { @@ -566,17 +564,17 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) if (!xrefs.isEmpty()) item.extra[QLatin1String("po-references")] = xrefs; } - msg.setId(codec->toUnicode(item.id)); - msg.setSourceText(codec->toUnicode(item.msgId)); - msg.setOldSourceText(codec->toUnicode(item.oldMsgId)); - msg.setComment(codec->toUnicode(item.tscomment)); - msg.setOldComment(codec->toUnicode(item.oldTscomment)); - msg.setExtraComment(codec->toUnicode(item.automaticComments)); - msg.setTranslatorComment(codec->toUnicode(item.translatorComments)); + msg.setId(toUnicode(item.id)); + msg.setSourceText(toUnicode(item.msgId)); + msg.setOldSourceText(toUnicode(item.oldMsgId)); + msg.setComment(toUnicode(item.tscomment)); + msg.setOldComment(toUnicode(item.oldTscomment)); + msg.setExtraComment(toUnicode(item.automaticComments)); + msg.setTranslatorComment(toUnicode(item.translatorComments)); msg.setPlural(item.isPlural || item.msgStr.size() > 1); QStringList translations; - foreach (const QByteArray &bstr, item.msgStr) { - QString str = codec->toUnicode(bstr); + for (const QByteArray &bstr : qAsConst(item.msgStr)) { + QString str = toUnicode(bstr); str.replace(QChar(Translator::TextVariantSeparator), QChar(Translator::BinaryVariantSeparator)); translations << str; @@ -607,13 +605,12 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) case ',': { QStringList flags = QString::fromLatin1(line.mid(2)).split( - QRegExp(QLatin1String("[, ]")), QString::SkipEmptyParts); + QRegularExpression(QLatin1String("[, ]")), Qt::SkipEmptyParts); if (flags.removeOne(QLatin1String("fuzzy"))) item.isFuzzy = true; flags.removeOne(QLatin1String("qt-format")); - TranslatorMessage::ExtraData::const_iterator it = - item.extra.find(QLatin1String("po-flags")); - if (it != item.extra.end()) + const auto it = item.extra.constFind(QLatin1String("po-flags")); + if (it != item.extra.cend()) flags.prepend(*it); if (!flags.isEmpty()) item.extra[QLatin1String("po-flags")] = flags.join(QLatin1String(", ")); @@ -642,14 +639,14 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) QByteArray extra = slurpEscapedString(lines, l, 16, "#| ", cd); if (extra != item.oldMsgId) item.extra[QLatin1String("po-old_msgid_plural")] = - codec->toUnicode(extra); + toUnicode(extra); } else if (line.startsWith("#| msgctxt ")) { item.oldTscomment = slurpEscapedString(lines, l, 11, "#| ", cd); if (qtContexts) splitContext(&item.oldTscomment, &item.context); } else { cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'")) - .arg(l + 1).arg(codec->toUnicode(lines[l]))); + .arg(l + 1).arg(toUnicode(lines[l]))); error = true; } break; @@ -660,7 +657,7 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) QByteArray extra = slurpEscapedString(lines, l, 16, "#~ ", cd); if (extra != item.msgId) item.extra[QLatin1String("po-msgid_plural")] = - codec->toUnicode(extra); + toUnicode(extra); item.isPlural = true; } else if (line.startsWith("#~ msgctxt ")) { item.tscomment = slurpEscapedString(lines, l, 11, "#~ ", cd); @@ -672,20 +669,20 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) QByteArray extra = slurpEscapedString(lines, l, 17, "#~| ", cd); if (extra != item.oldMsgId) item.extra[QLatin1String("po-old_msgid_plural")] = - codec->toUnicode(extra); + toUnicode(extra); } else if (line.startsWith("#~| msgctxt ")) { item.oldTscomment = slurpEscapedString(lines, l, 12, "#~| ", cd); if (qtContexts) splitContext(&item.oldTscomment, &item.context); } else { cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'")) - .arg(l + 1).arg(codec->toUnicode(lines[l]))); + .arg(l + 1).arg(toUnicode(lines[l]))); error = true; } break; default: cd.appendError(QString(QLatin1String("PO-format parse error in line %1: '%2'")) - .arg(l + 1).arg(codec->toUnicode(lines[l]))); + .arg(l + 1).arg(toUnicode(lines[l]))); error = true; break; } @@ -699,11 +696,11 @@ bool loadPO(Translator &translator, QIODevice &dev, ConversionData &cd) } else if (line.startsWith("msgid_plural ")) { QByteArray extra = slurpEscapedString(lines, l, 13, QByteArray(), cd); if (extra != item.msgId) - item.extra[QLatin1String("po-msgid_plural")] = codec->toUnicode(extra); + item.extra[QLatin1String("po-msgid_plural")] = toUnicode(extra); item.isPlural = true; } else { cd.appendError(QString(QLatin1String("PO-format error in line %1: '%2'")) - .arg(l + 1).arg(codec->toUnicode(lines[l]))); + .arg(l + 1).arg(toUnicode(lines[l]))); error = true; } } @@ -735,10 +732,9 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) bool ok = true; QTextStream out(&dev); - out.setCodec("UTF-8"); bool qtContexts = false; - foreach (const TranslatorMessage &msg, translator.messages()) + for (const TranslatorMessage &msg : translator.messages()) if (!msg.context().isEmpty()) { qtContexts = true; break; @@ -750,11 +746,11 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) out << "msgid \"\"\n"; Translator::ExtraData headers = translator.extras(); QStringList hdrOrder = translator.extra(QLatin1String("po-headers")).split( - QLatin1Char(','), QString::SkipEmptyParts); + QLatin1Char(','), Qt::SkipEmptyParts); // Keep in sync with loadPO addPoHeader(headers, hdrOrder, "MIME-Version", QLatin1String("1.0")); addPoHeader(headers, hdrOrder, "Content-Type", - QLatin1String("text/plain; charset=" + out.codec()->name())); + QLatin1String("text/plain; charset=UTF-8")); addPoHeader(headers, hdrOrder, "Content-Transfer-Encoding", QLatin1String("8bit")); if (!translator.languageCode().isEmpty()) { QLocale::Language l; @@ -770,7 +766,7 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) if (qtContexts) addPoHeader(headers, hdrOrder, "X-Qt-Contexts", QLatin1String("true")); QString hdrStr; - foreach (const QString &hdr, hdrOrder) { + for (const QString &hdr : qAsConst(hdrOrder)) { hdrStr += hdr; hdrStr += QLatin1String(": "); hdrStr += headers.value(makePoHeader(hdr)); @@ -778,8 +774,8 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) } out << poEscapedString(QString(), QString::fromLatin1("msgstr"), true, hdrStr); - foreach (const TranslatorMessage &msg, translator.messages()) { - out << endl; + for (const TranslatorMessage &msg : translator.messages()) { + out << Qt::endl; if (!msg.translatorComment().isEmpty()) out << poEscapedLines(QLatin1String("#"), true, msg.translatorComment()); @@ -793,7 +789,7 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) QString xrefs = msg.extra(QLatin1String("po-references")); if (!msg.fileName().isEmpty() || !xrefs.isEmpty()) { QStringList refs; - foreach (const TranslatorMessage::Reference &ref, msg.allReferences()) + for (const TranslatorMessage::Reference &ref : msg.allReferences()) refs.append(QString(QLatin1String("%2:%1")) .arg(ref.lineNumber()).arg(ref.fileName())); if (!xrefs.isEmpty()) @@ -807,11 +803,10 @@ bool savePO(const Translator &translator, QIODevice &dev, ConversionData &) if ((msg.type() == TranslatorMessage::Unfinished || msg.type() == TranslatorMessage::Obsolete) && msg.isTranslated()) flags.append(QLatin1String("fuzzy")); - TranslatorMessage::ExtraData::const_iterator itr = - msg.extras().find(QLatin1String("po-flags")); - if (itr != msg.extras().end()) { - QStringList atoms = itr->split(QLatin1String(", ")); - foreach (const QString &atom, atoms) + const auto itr = msg.extras().constFind(QLatin1String("po-flags")); + if (itr != msg.extras().cend()) { + const QStringList atoms = itr->split(QLatin1String(", ")); + for (const QString &atom : atoms) if (atom.endsWith(str_format)) { skipFormat = true; break; diff --git a/src/linguist/shared/profileevaluator.cpp b/src/linguist/shared/profileevaluator.cpp index aa32b9e01b..77059fa949 100644 --- a/src/linguist/shared/profileevaluator.cpp +++ b/src/linguist/shared/profileevaluator.cpp @@ -73,7 +73,7 @@ QStringList ProFileEvaluator::values(const QString &variableName) const const ProStringList &values = d->values(ProKey(variableName)); QStringList ret; ret.reserve(values.size()); - foreach (const ProString &str, values) + for (const ProString &str : values) ret << d->m_option->expandEnvVars(str.toQString()); return ret; } @@ -84,7 +84,7 @@ QStringList ProFileEvaluator::values(const QString &variableName, const ProFile const ProStringList &values = d->m_valuemapStack.front().value(ProKey(variableName)); QStringList ret; ret.reserve(values.size()); - foreach (const ProString &str, values) + for (const ProString &str : values) if (str.sourceFile() == pro->id()) ret << d->m_option->expandEnvVars(str.toQString()); return ret; @@ -109,7 +109,7 @@ QStringList ProFileEvaluator::absolutePathValues( const QString &variable, const QString &baseDirectory) const { QStringList result; - foreach (const QString &el, values(variable)) { + for (const QString &el : values(variable)) { QString absEl = IoUtils::isAbsolutePath(el) ? sysrootify(el, baseDirectory) : IoUtils::resolvePath(baseDirectory, el); if (IoUtils::fileType(absEl) == IoUtils::FileIsDir) @@ -123,7 +123,8 @@ QStringList ProFileEvaluator::absoluteFileValues( const ProFile *pro) const { QStringList result; - foreach (const QString &el, pro ? values(variable, pro) : values(variable)) { + const auto vals = pro ? values(variable, pro) : values(variable); + for (const QString &el : vals) { QString absEl; if (IoUtils::isAbsolutePath(el)) { const QString elWithSysroot = QDir::cleanPath(sysrootify(el, baseDirectory)); @@ -133,7 +134,7 @@ QStringList ProFileEvaluator::absoluteFileValues( } absEl = elWithSysroot; } else { - foreach (const QString &dir, searchDirs) { + for (const QString &dir : searchDirs) { QString fn = QDir::cleanPath(dir + QLatin1Char('/') + el); if (d->m_vfs->exists(fn, QMakeVfs::VfsCumulative)) { result << fn; @@ -153,9 +154,8 @@ QStringList ProFileEvaluator::absoluteFileValues( QString wildcard = d->m_tmp2.setRawData(absEl.constData() + nameOff + 1, absEl.length() - nameOff - 1); if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) { - wildcard.detach(); // Keep m_tmp out of QRegExp's cache QDir theDir(absDir); - foreach (const QString &fn, theDir.entryList(QStringList(wildcard))) + for (const QString &fn : theDir.entryList(QStringList(wildcard))) if (fn != QLatin1String(".") && fn != QLatin1String("..")) result << absDir + QLatin1Char('/') + fn; } // else if (acceptMissing) @@ -219,9 +219,7 @@ void ProFileEvaluator::setCumulative(bool on) void ProFileEvaluator::setExtraVars(const QHash &extraVars) { ProValueMap map; - QHash::const_iterator it = extraVars.constBegin(); - QHash::const_iterator end = extraVars.constEnd(); - for ( ; it != end; ++it) + for (auto it = extraVars.cbegin(), end = extraVars.cend() ; it != end; ++it) map.insert(ProKey(it.key()), ProStringList(it.value())); d->setExtraVars(map); } diff --git a/src/linguist/shared/proitems.cpp b/src/linguist/shared/proitems.cpp index 82b1791225..2d8faff730 100644 --- a/src/linguist/shared/proitems.cpp +++ b/src/linguist/shared/proitems.cpp @@ -36,9 +36,9 @@ QT_BEGIN_NAMESPACE // from qhash.cpp -uint ProString::hash(const QChar *p, int n) +size_t ProString::hash(const QChar *p, int n) { - uint h = 0; + size_t h = 0; while (n--) { h = (h << 4) + (*p++).unicode(); @@ -74,19 +74,19 @@ ProString::ProString(const QString &str) : { } -ProString::ProString(const QStringRef &str) : - m_string(*str.string()), m_offset(str.position()), m_length(str.size()), m_file(0), m_hash(0x80000000) +ProString::ProString(QStringView str) : + m_string(str.toString()), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000) { } ProString::ProString(const char *str, DoPreHashing) : - m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0) + m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0) { updatedHash(); } ProString::ProString(const char *str) : - m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0), m_hash(0x80000000) + m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0), m_hash(0x80000000) { } @@ -111,12 +111,12 @@ void ProString::setValue(const QString &str) m_string = str, m_offset = 0, m_length = str.length(), m_hash = 0x80000000; } -uint ProString::updatedHash() const +size_t ProString::updatedHash() const { return (m_hash = hash(m_string.constData() + m_offset, m_length)); } -uint qHash(const ProString &str) +size_t qHash(const ProString &str) { if (!(str.m_hash & 0x80000000)) return str.m_hash; @@ -156,7 +156,8 @@ QString ProString::toQString() const QString &ProString::toQString(QString &tmp) const { - return tmp.setRawData(m_string.constData() + m_offset, m_length); + tmp = m_string.mid(m_offset, m_length); + return tmp; } /*! @@ -238,7 +239,7 @@ ProString &ProString::append(const ProString &other, bool *pending) QChar *ptr; if (pending && !*pending) { ptr = prepareExtend(1 + other.m_length, 0, m_length); - *ptr++ = 32; + *ptr++ = u' '; } else { ptr = prepareExtend(other.m_length, 0, m_length); } @@ -276,7 +277,7 @@ ProString &ProString::append(const ProStringList &other, bool *pending, bool ski QChar *ptr = prepareExtend(totalLength, 0, m_length); for (int i = startIdx; i < sz; ++i) { if (putSpace) - *ptr++ = 32; + *ptr++ = u' '; else putSpace = true; const ProString &str = other.at(i); @@ -341,7 +342,7 @@ ProString ProString::trimmed() const QTextStream &operator<<(QTextStream &t, const ProString &str) { - t << str.toQStringRef(); + t << str.toQStringView(); return t; } @@ -466,10 +467,10 @@ bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const return false; } -bool ProStringList::contains(const QStringRef &str, Qt::CaseSensitivity cs) const +bool ProStringList::contains(QStringView str, Qt::CaseSensitivity cs) const { for (int i = 0; i < size(); i++) - if (!at(i).toQStringRef().compare(str, cs)) + if (!at(i).toQStringView().compare(str, cs)) return true; return false; } diff --git a/src/linguist/shared/proitems.h b/src/linguist/shared/proitems.h index c7af53b1c9..218d02a79c 100644 --- a/src/linguist/shared/proitems.h +++ b/src/linguist/shared/proitems.h @@ -31,9 +31,10 @@ #include "qmake_global.h" -#include -#include #include +#include +#include +#include QT_BEGIN_NAMESPACE @@ -67,8 +68,9 @@ class ProString { public: ProString(); ProString(const ProString &other); + ProString &operator=(const ProString &) = default; PROITEM_EXPLICIT ProString(const QString &str); - PROITEM_EXPLICIT ProString(const QStringRef &str); + PROITEM_EXPLICIT ProString(QStringView str); PROITEM_EXPLICIT ProString(const char *str); ProString(const QString &str, int offset, int length); void setValue(const QString &str); @@ -93,16 +95,16 @@ class ProString { void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; } void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; } - bool operator==(const ProString &other) const { return toQStringRef() == other.toQStringRef(); } - bool operator==(const QString &other) const { return toQStringRef() == other; } - bool operator==(const QStringRef &other) const { return toQStringRef() == other; } - bool operator==(QLatin1String other) const { return toQStringRef() == other; } - bool operator==(const char *other) const { return toQStringRef() == QLatin1String(other); } + bool operator==(const ProString &other) const { return toQStringView() == other.toQStringView(); } + bool operator==(const QString &other) const { return toQStringView() == other; } + bool operator==(QStringView other) const { return toQStringView() == other; } + bool operator==(QLatin1String other) const { return toQStringView() == other; } + bool operator==(const char *other) const { return toQStringView() == QLatin1String(other); } bool operator!=(const ProString &other) const { return !(*this == other); } bool operator!=(const QString &other) const { return !(*this == other); } bool operator!=(QLatin1String other) const { return !(*this == other); } bool operator!=(const char *other) const { return !(*this == other); } - bool operator<(const ProString &other) const { return toQStringRef() < other.toQStringRef(); } + bool operator<(const ProString &other) const { return toQStringView() < other.toQStringView(); } bool isNull() const { return m_string.isNull(); } bool isEmpty() const { return !m_length; } int length() const { return m_length; } @@ -113,34 +115,33 @@ class ProString { ProString left(int len) const { return mid(0, len); } ProString right(int len) const { return mid(qMax(0, size() - len)); } ProString trimmed() const; - int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub.toQStringRef(), cs); } - int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub, cs); } - int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(QLatin1String(sub), cs); } - bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub.toQStringRef(), cs); } - bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(sub, cs); } - bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(QLatin1String(sub), cs); } - bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().startsWith(c, cs); } - bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub.toQStringRef(), cs); } - bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(sub, cs); } - bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(QLatin1String(sub), cs); } - bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().endsWith(c, cs); } - int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(s, from, cs); } - int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(QLatin1String(s), from, cs); } - int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().indexOf(c, from, cs); } - int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(s, from, cs); } - int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(QLatin1String(s), from, cs); } - int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().lastIndexOf(c, from, cs); } + int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(sub.toQStringView(), cs); } + int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(sub, cs); } + int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(QLatin1String(sub), cs); } + bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(sub.toQStringView(), cs); } + bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(sub, cs); } + bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(QLatin1String(sub), cs); } + bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(c, cs); } + bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(sub.toQStringView(), cs); } + bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(sub, cs); } + bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(QLatin1String(sub), cs); } + bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(c, cs); } + int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(s, from, cs); } + int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(QLatin1String(s), from, cs); } + int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(c, from, cs); } + int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(s, from, cs); } + int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(QLatin1String(s), from, cs); } + int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(c, from, cs); } bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; } bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; } bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; } - int toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringRef().toLongLong(ok, base); } - int toInt(bool *ok = nullptr, int base = 10) const { return toQStringRef().toInt(ok, base); } - short toShort(bool *ok = nullptr, int base = 10) const { return toQStringRef().toShort(ok, base); } + int toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringView().toLongLong(ok, base); } + int toInt(bool *ok = nullptr, int base = 10) const { return toQStringView().toInt(ok, base); } + short toShort(bool *ok = nullptr, int base = 10) const { return toQStringView().toShort(ok, base); } - uint hash() const { return m_hash; } - static uint hash(const QChar *p, int n); + size_t hash() const { return m_hash; } + static size_t hash(const QChar *p, int n); - ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); } ALWAYS_INLINE QStringView toQStringView() const { return QStringView(m_string).mid(m_offset, m_length); } ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; } @@ -149,7 +150,7 @@ class ProString { QString toQString() const; QString &toQString(QString &tmp) const; - QByteArray toLatin1() const { return toQStringRef().toLatin1(); } + QByteArray toLatin1() const { return toQStringView().toLatin1(); } private: ProString(const ProKey &other); @@ -169,12 +170,12 @@ class ProString { int m_file; mutable uint m_hash; QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget); - uint updatedHash() const; - friend uint qHash(const ProString &str); + size_t updatedHash() const; + friend size_t qHash(const ProString &str); friend QString operator+(const ProString &one, const ProString &two); friend class ProKey; }; -Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProString, Q_RELOCATABLE_TYPE); class ProKey : public ProString { public: @@ -201,26 +202,26 @@ class ProKey : public ProString { private: ProKey(const ProString &other); }; -Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProKey, Q_RELOCATABLE_TYPE); -uint qHash(const ProString &str); +size_t qHash(const ProString &str); QString operator+(const ProString &one, const ProString &two); inline QString operator+(const ProString &one, const QString &two) - { return one.toQStringRef() + two; } + { return one.toQStringView() + two; } inline QString operator+(const QString &one, const ProString &two) - { return one + two.toQStringRef(); } + { return one + two.toQStringView(); } inline QString operator+(const ProString &one, const char *two) - { return one.toQStringRef() + QLatin1String(two); } + { return one.toQStringView() + QLatin1String(two); } inline QString operator+(const char *one, const ProString &two) - { return QLatin1String(one) + two.toQStringRef(); } + { return QLatin1String(one) + two.toQStringView(); } inline QString operator+(const ProString &one, QChar two) - { return one.toQStringRef() + two; } + { return one.toQStringView() + two; } inline QString operator+(QChar one, const ProString &two) - { return one + two.toQStringRef(); } + { return one + two.toQStringView(); } inline QString &operator+=(QString &that, const ProString &other) - { return that += other.toQStringRef(); } + { return that += other.toQStringView(); } inline bool operator==(const QString &that, const ProString &other) { return other == that; } @@ -236,7 +237,6 @@ class ProStringRoUser public: ProStringRoUser(QString &rs) { - Q_ASSERT(rs.isDetached() || rs.isEmpty()); m_rs = &rs; } ProStringRoUser(const ProString &ps, QString &rs) @@ -246,7 +246,7 @@ class ProStringRoUser } // No destructor, as a RAII pattern cannot be used: references to the // temporary string can legitimately outlive instances of this class - // (if they are held by Qt, e.g. in QRegExp). + // (if they are held by Qt, e.g. in QRegularExpression). QString &set(const ProString &ps) { return ps.toQString(*m_rs); } QString &str() { return *m_rs; } @@ -278,7 +278,7 @@ class ProStringRwUser : public ProStringRoUser const ProString *m_ps; }; -class ProStringList : public QVector { +class ProStringList : public QList { public: ProStringList() {} ProStringList(const ProString &str) { *this << str; } @@ -286,7 +286,7 @@ class ProStringList : public QVector { QStringList toQStringList() const; ProStringList &operator<<(const ProString &str) - { QVector::operator<<(str); return *this; } + { QList::operator<<(str); return *this; } int length() const { return size(); } @@ -304,17 +304,17 @@ class ProStringList : public QVector { void removeDuplicates(); bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; - bool contains(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; + bool contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return contains(ProString(str), cs); } bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; }; -Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProStringList, Q_RELOCATABLE_TYPE); inline ProStringList operator+(const ProStringList &one, const ProStringList &two) { ProStringList ret = one; ret += two; return ret; } -typedef QHash ProValueMap; +typedef QMap ProValueMap; // These token definitions affect both ProFileEvaluator and ProWriter enum ProToken { @@ -431,11 +431,12 @@ class ProFunctionDef { ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); } ProFunctionDef(ProFunctionDef &&other) Q_DECL_NOTHROW : m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; } - ~ProFunctionDef() { m_pro->deref(); } + ~ProFunctionDef() { if (m_pro) m_pro->deref(); } ProFunctionDef &operator=(const ProFunctionDef &o) { if (this != &o) { - m_pro->deref(); + if (m_pro) + m_pro->deref(); m_pro = o.m_pro; m_pro->ref(); m_offset = o.m_offset; @@ -461,7 +462,7 @@ class ProFunctionDef { int m_offset; }; -Q_DECLARE_TYPEINFO(ProFunctionDef, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ProFunctionDef, Q_RELOCATABLE_TYPE); struct ProFunctionDefs { QHash testFunctions; diff --git a/src/linguist/shared/projectdescriptionreader.cpp b/src/linguist/shared/projectdescriptionreader.cpp index e61b81e09e..9ba1d23f9e 100644 --- a/src/linguist/shared/projectdescriptionreader.cpp +++ b/src/linguist/shared/projectdescriptionreader.cpp @@ -70,6 +70,7 @@ class Validator << QStringLiteral("excluded") << QStringLiteral("includePaths") << QStringLiteral("sources") + << QStringLiteral("compileCommands") << QStringLiteral("subProjects") << QStringLiteral("translations"); QSet actualKeys; @@ -139,7 +140,7 @@ class ProjectConverter { Projects result; result.reserve(rawProjects.size()); - for (const QJsonValue &rawProject : rawProjects) { + for (const QJsonValue rawProject : rawProjects) { Project project = convertProject(rawProject); if (!m_errorString.isEmpty()) break; @@ -156,12 +157,13 @@ class ProjectConverter Project result; QJsonObject obj = v.toObject(); result.filePath = stringValue(obj, QLatin1String("projectFile")); + result.compileCommands = stringValue(obj, QLatin1String("compileCommands")); result.codec = stringValue(obj, QLatin1String("codec")); result.excluded = stringListValue(obj, QLatin1String("excluded")); result.includePaths = stringListValue(obj, QLatin1String("includePaths")); result.sources = stringListValue(obj, QLatin1String("sources")); if (obj.contains(QLatin1String("translations"))) - result.translations.reset(new QStringList(stringListValue(obj, QLatin1String("translations")))); + result.translations = stringListValue(obj, QLatin1String("translations")); result.subProjects = convertProjects(obj.value(QLatin1String("subProjects")).toArray()); return result; } @@ -226,7 +228,7 @@ class ProjectConverter QStringList result; const QJsonArray a = v.toArray(); result.reserve(a.count()); - for (const QJsonValue &v : a) { + for (const QJsonValue v : a) { if (!v.isString()) { m_errorString = FMT::tr("Unexpected type %1 in string array in key %2.") .arg(jsonTypeName(v.type()), key); diff --git a/src/linguist/shared/projectdescriptionreader.h b/src/linguist/shared/projectdescriptionreader.h index c7234d16b4..8aad4acbea 100644 --- a/src/linguist/shared/projectdescriptionreader.h +++ b/src/linguist/shared/projectdescriptionreader.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include struct Project; @@ -42,20 +42,15 @@ typedef std::vector Projects; struct Project { QString filePath; + QString compileCommands; QString codec; QStringList excluded; QStringList includePaths; QStringList sources; Projects subProjects; - // ### Change type of translations to std::optional once we can. - std::unique_ptr translations; + std::optional translations; }; -inline bool hasTranslations(const Project &project) -{ - return (bool)project.translations; -} - Projects readProjectDescription(const QString &filePath, QString *errorString); #endif // PROJECTDESCRIPTIONREADER_H diff --git a/src/linguist/shared/proparser.pri b/src/linguist/shared/proparser.pri deleted file mode 100644 index f3fcad515d..0000000000 --- a/src/linguist/shared/proparser.pri +++ /dev/null @@ -1,28 +0,0 @@ - -INCLUDEPATH *= $$PWD - -DEFINES += PROEVALUATOR_CUMULATIVE PROEVALUATOR_INIT_PROPS - -HEADERS += \ - $$PWD/qmake_global.h \ - $$PWD/ioutils.h \ - $$PWD/qmakevfs.h \ - $$PWD/proitems.h \ - $$PWD/qmakeglobals.h \ - $$PWD/qmakeparser.h \ - $$PWD/qmakeevaluator.h \ - $$PWD/qmakeevaluator_p.h \ - $$PWD/profileevaluator.h - -SOURCES += \ - $$PWD/ioutils.cpp \ - $$PWD/qmakevfs.cpp \ - $$PWD/proitems.cpp \ - $$PWD/qmakeglobals.cpp \ - $$PWD/qmakeparser.cpp \ - $$PWD/qmakeevaluator.cpp \ - $$PWD/qmakebuiltins.cpp \ - $$PWD/profileevaluator.cpp - -RESOURCES += $$PWD/proparser.qrc -DEFINES += QMAKE_BUILTIN_PRFS QMAKE_OVERRIDE_PRFS diff --git a/src/linguist/shared/qm.cpp b/src/linguist/shared/qm.cpp index 6963ad6cba..c94ca7b821 100644 --- a/src/linguist/shared/qm.cpp +++ b/src/linguist/shared/qm.cpp @@ -38,7 +38,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE @@ -119,7 +118,7 @@ class ByteTranslatorMessage QStringList m_translations; }; -Q_DECLARE_TYPEINFO(ByteTranslatorMessage, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(ByteTranslatorMessage, Q_RELOCATABLE_TYPE); bool ByteTranslatorMessage::operator<(const ByteTranslatorMessage& m) const { @@ -151,9 +150,9 @@ class Releaser uint o; }; - enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96 }; + enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96, Language = 0xa7 }; - Releaser() {} + Releaser(const QString &language) : m_language(language) {} bool save(QIODevice *iod); @@ -179,6 +178,7 @@ class Releaser void writeMessage(const ByteTranslatorMessage & msg, QDataStream & stream, TranslatorSaveMode strip, Prefix prefix) const; + QString m_language; // for squeezed but non-file data, this is what needs to be deleted QByteArray m_messageArray; QByteArray m_offsetArray; @@ -249,6 +249,12 @@ bool Releaser::save(QIODevice *iod) QDataStream s(iod); s.writeRawData((const char *)magic, MagicLength); + if (!m_language.isEmpty()) { + QByteArray lang = originalBytes(m_language); + quint32 las = quint32(lang.size()); + s << quint8(Language) << las; + s.writeRawData(lang, las); + } if (!m_dependencyArray.isEmpty()) { quint32 das = quint32(m_dependencyArray.size()); s << quint8(Dependencies) << das; @@ -281,13 +287,13 @@ void Releaser::squeeze(TranslatorSaveMode mode) { m_dependencyArray.clear(); QDataStream depstream(&m_dependencyArray, QIODevice::WriteOnly); - foreach (const QString &dep, m_dependencies) + for (const QString &dep : qAsConst(m_dependencies)) depstream << dep; if (m_messages.isEmpty() && mode == SaveEverything) return; - QMap messages = m_messages; + const auto messages = m_messages; // re-build contents m_messageArray.clear(); @@ -298,13 +304,11 @@ void Releaser::squeeze(TranslatorSaveMode mode) QMap offsets; QDataStream ms(&m_messageArray, QIODevice::WriteOnly); - QMap::const_iterator it, next; int cpPrev = 0, cpNext = 0; - for (it = messages.constBegin(); it != messages.constEnd(); ++it) { + for (auto it = messages.cbegin(), end = messages.cend(); it != end; ++it) { cpPrev = cpNext; - next = it; - ++next; - if (next == messages.constEnd()) + const auto next = std::next(it); + if (next == end) cpNext = 0; else cpNext = commonPrefix(it.key(), next.key()); @@ -312,10 +316,9 @@ void Releaser::squeeze(TranslatorSaveMode mode) writeMessage(it.key(), ms, mode, Prefix(qMax(cpPrev, cpNext + 1))); } - QMap::Iterator offset; - offset = offsets.begin(); + auto offset = offsets.cbegin(); QDataStream ds(&m_offsetArray, QIODevice::WriteOnly); - while (offset != offsets.end()) { + while (offset != offsets.cend()) { Offset k = offset.key(); ++offset; ds << quint32(k.h) << quint32(k.o); @@ -323,7 +326,7 @@ void Releaser::squeeze(TranslatorSaveMode mode) if (mode == SaveStripped) { QMap contextSet; - for (it = messages.constBegin(); it != messages.constEnd(); ++it) + for (auto it = messages.cbegin(), end = messages.cend(); it != end; ++it) ++contextSet[it.key().context()]; quint16 hTableSize; @@ -335,8 +338,7 @@ void Releaser::squeeze(TranslatorSaveMode mode) hTableSize = (contextSet.size() < 10000) ? 15013 : 3 * contextSet.size() / 2; QMultiMap hashMap; - QMap::const_iterator c; - for (c = contextSet.constBegin(); c != contextSet.constEnd(); ++c) + for (auto c = contextSet.cbegin(), end = contextSet.cend(); c != end; ++c) hashMap.insert(elfHash(c.key()) % hTableSize, c.key()); /* @@ -372,7 +374,7 @@ void Releaser::squeeze(TranslatorSaveMode mode) t << quint16(0); // the entry at offset 0 cannot be used uint upto = 2; - QMap::const_iterator entry = hashMap.constBegin(); + auto entry = hashMap.constBegin(); while (entry != hashMap.constEnd()) { int i = entry.key(); hTable[i] = quint16(upto >> 1); @@ -449,10 +451,9 @@ static quint32 read32(const uchar *data) static void fromBytes(const char *str, int len, QString *out, bool *utf8Fail) { - static QTextCodec *utf8Codec = QTextCodec::codecForName("UTF-8"); - QTextCodec::ConverterState cvtState; - *out = utf8Codec->toUnicode(str, len, &cvtState); - *utf8Fail = cvtState.invalidChars; + QStringDecoder toUnicode(QStringDecoder::Utf8, QStringDecoder::Flag::Stateless); + *out = toUnicode(QByteArrayView(str, len)); + *utf8Fail = toUnicode.hasError(); } bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) @@ -465,7 +466,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) return false; } - enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96 }; + enum { Contexts = 0x2f, Hashes = 0x42, Messages = 0x69, NumerusRules = 0x88, Dependencies = 0x96, Language = 0xa7 }; // for squeezed but non-file data, this is what needs to be deleted const uchar *messageArray = 0; @@ -473,6 +474,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) uint offsetLength = 0; bool ok = true; + bool utf8Fail = false; const uchar *end = data + len; data += MagicLength; @@ -505,6 +507,10 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) dependencies.append(dep); } translator.setDependencies(dependencies); + } else if (tag == Language) { + QString language; + fromBytes((const char *)data, blockLen, &language, &utf8Fail); + translator.setLanguageCode(language); } data += blockLen; @@ -524,7 +530,6 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) guessPlurals = (numerusForms.count() == 1); QString context, sourcetext, comment; - bool utf8Fail = false; QStringList translations; for (const uchar *start = offsetArray; start != offsetArray + (numItems << 3); start += 8) { @@ -541,12 +546,17 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) goto end; case Tag_Translation: { int len = read32(m); - if (len % 1) { + m += 4; + + // -1 indicates an empty string + // Otherwise streaming format is UTF-16 -> 2 bytes per character + if ((len != -1) && (len & 1)) { cd.appendError(QLatin1String("QM-Format error")); return false; } - m += 4; - QString str = QString((const QChar *)m, len/2); + QString str; + if (len != -1) + str = QString((const QChar *)m, len / 2); if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { for (int i = 0; i < str.length(); ++i) str[i] = QChar((str.at(i).unicode() >> 8) + @@ -612,7 +622,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) translator.append(msg); } if (utf8Fail) { - cd.appendError(QLatin1String("Cannot read file with UTF-8 codec")); + cd.appendError(QLatin1String("Error: File contains invalid UTF-8 sequences.")); return false; } return ok; @@ -622,7 +632,7 @@ bool loadQM(Translator &translator, QIODevice &dev, ConversionData &cd) static bool containsStripped(const Translator &translator, const TranslatorMessage &msg) { - foreach (const TranslatorMessage &tmsg, translator.messages()) + for (const TranslatorMessage &tmsg : translator.messages()) if (tmsg.sourceText() == msg.sourceText() && tmsg.context() == msg.context() && tmsg.comment().isEmpty()) @@ -632,7 +642,7 @@ static bool containsStripped(const Translator &translator, const TranslatorMessa bool saveQM(const Translator &translator, QIODevice &dev, ConversionData &cd) { - Releaser releaser; + Releaser releaser(translator.languageCode()); QLocale::Language l; QLocale::Country c; Translator::languageAndCountry(translator.languageCode(), &l, &c); diff --git a/src/linguist/shared/qmakebuiltins.cpp b/src/linguist/shared/qmakebuiltins.cpp index 92366b9f78..c0d1346a79 100644 --- a/src/linguist/shared/qmakebuiltins.cpp +++ b/src/linguist/shared/qmakebuiltins.cpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include @@ -635,7 +635,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (!var.isEmpty()) { const auto strings = values(map(var)); if (regexp) { - QRegExp sepRx(sep); + QRegularExpression sepRx(sep, QRegularExpression::DotMatchesEverythingOption); + if (!sepRx.isValid()) { + evalError(fL1S("section(): Encountered invalid regular expression '%1'.").arg(sep)); + goto allfail; + } for (const ProString &str : strings) { ProStringRwUser u1(str, m_tmp[m_toggle ^= 1]); ret << u1.extract(u1.str().section(sepRx, beg, end)); @@ -665,7 +669,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( bool leftalign = false; enum { DefaultSign, PadSign, AlwaysSign } sign = DefaultSign; if (args.count() >= 2) { - const auto opts = split_value_list(args.at(1).toQStringRef()); + const auto opts = split_value_list(args.at(1).toQStringView()); for (const ProString &opt : opts) { if (opt.startsWith(QLatin1String("ibase="))) { ibase = opt.mid(6).toInt(); @@ -768,7 +772,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( const auto vars = values(map(args.at(0))); for (const ProString &var : vars) { // FIXME: this is inconsistent with the "there are no empty strings" dogma. - const auto splits = var.toQStringRef().split(sep, QString::KeepEmptyParts); + const auto splits = var.toQStringView().split(sep, Qt::KeepEmptyParts); for (const auto &splt : splits) ret << ProString(splt).setSource(var); } @@ -858,7 +862,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ret += ProString(stream.readLine()); } else { const QString &line = stream.readLine(); - ret += split_value_list(QStringRef(&line).trimmed()); + ret += split_value_list(QStringView(line).trimmed()); if (!singleLine) ret += ProString("\n"); } @@ -882,15 +886,19 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ret = ProStringList(ProString(tmp)); ProStringList lst; for (const ProString &arg : args) - lst += split_value_list(arg.toQStringRef(), arg.sourceFile()); // Relies on deep copy + lst += split_value_list(arg.toQStringView(), arg.sourceFile()); // Relies on deep copy m_valuemapStack.top()[ret.at(0).toKey()] = lst; break; } case E_FIND: { - QRegExp regx(args.at(1).toQString()); + QRegularExpression regx(args.at(1).toQString(), QRegularExpression::DotMatchesEverythingOption); + if (!regx.isValid()) { + evalError(fL1S("find(): Encountered invalid regular expression '%1'.").arg(regx.pattern())); + goto allfail; + } const auto vals = values(map(args.at(0))); for (const ProString &val : vals) { ProStringRoUser u1(val, m_tmp[m_toggle ^= 1]); - if (regx.indexIn(u1.str()) != -1) + if (u1.str().contains(regx)) ret += val; } break; @@ -927,7 +935,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( output.replace(QLatin1Char('\t'), QLatin1Char(' ')); if (singleLine) output.replace(QLatin1Char('\n'), QLatin1Char(' ')); - ret += split_value_list(QStringRef(&output)); + ret += split_value_list(QStringView(output)); } } break; @@ -986,7 +994,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( case E_RE_ESCAPE: for (int i = 0; i < args.size(); ++i) { ProStringRwUser u1(args.at(i), m_tmp1); - ret << u1.extract(QRegExp::escape(u1.str())); + ret << u1.extract(QRegularExpression::escape(u1.str())); } break; case E_VAL_ESCAPE: { @@ -1034,8 +1042,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( dirs.append(QString()); } - r.detach(); // Keep m_tmp out of QRegExp's cache - QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard); + QString pattern = QRegularExpression::wildcardToRegularExpression(r); + QRegularExpression regex(pattern, QRegularExpression::DotMatchesEverythingOption); + if (!regex.isValid()) { + evalError(fL1S("section(): Encountered invalid wildcard expression '%1'.").arg(pattern)); + goto allfail; + } for (int d = 0; d < dirs.count(); d++) { QString dir = dirs[d]; QDir qdir(pfx + dir); @@ -1047,7 +1059,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( if (recursive) dirs.append(fname + QLatin1Char('/')); } - if (regex.exactMatch(qdir[i])) + if (regex.match(qdir[i]).hasMatch()) ret += ProString(fname).setSource(currentFileId()); } } @@ -1076,13 +1088,17 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( evalError(fL1S("Unexpected EOF.")); return ReturnError; } - ret = split_value_list(QStringRef(&line)); + ret = split_value_list(QStringView(line)); } break; } #endif case E_REPLACE: { - const QRegExp before(args.at(1).toQString()); + const QRegularExpression before(args.at(1).toQString(), QRegularExpression::DotMatchesEverythingOption); + if (!before.isValid()) { + evalError(fL1S("replace(): Encountered invalid regular expression '%1'.").arg(before.pattern())); + goto allfail; + } ProStringRwUser u2(args.at(2), m_tmp2); const QString &after = u2.str(); const auto vals = values(map(args.at(0))); @@ -1105,7 +1121,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( ProString priosfx = args.count() < 4 ? ProString(".priority") : args.at(3); populateDeps(orgList, prefix, args.count() < 3 ? ProStringList(ProString(".depends")) - : split_value_list(args.at(2).toQStringRef()), + : split_value_list(args.at(2).toQStringView()), priosfx, dependencies, dependees, rootSet); while (!rootSet.isEmpty()) { QMultiMap::iterator it = rootSet.begin(); @@ -1229,7 +1245,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::testFunc_cache(const ProStringList & enum { CacheSet, CacheAdd, CacheSub } mode = CacheSet; ProKey srcvar; if (args.count() >= 2) { - const auto opts = split_value_list(args.at(1).toQStringRef()); + const auto opts = split_value_list(args.at(1).toQStringView()); for (const ProString &opt : opts) { if (opt == QLatin1String("transient")) { persist = false; @@ -1490,21 +1506,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ok; if (args.count() == 2) return returnBool(vars.contains(map(args.at(1)))); - QRegExp regx; + QRegularExpression regx; + regx.setPatternOptions(QRegularExpression::DotMatchesEverythingOption); ProStringRoUser u1(args.at(2), m_tmp1); const QString &qry = u1.str(); - if (qry != QRegExp::escape(qry)) { - QString copy = qry; - copy.detach(); - regx.setPattern(copy); + if (qry != QRegularExpression::escape(qry)) { + regx.setPattern(QRegularExpression::anchoredPattern(qry)); + if (!regx.isValid()) { + evalError(fL1S("infile(): Encountered invalid regular expression '%1'.").arg(qry)); + return ReturnFalse; + } } const auto strings = vars.value(map(args.at(1))); for (const ProString &s : strings) { if (s == qry) return ReturnTrue; - if (!regx.isEmpty()) { + if (!regx.pattern().isEmpty()) { ProStringRoUser u2(s, m_tmp[m_toggle ^= 1]); - if (regx.exactMatch(u2.str())) + if (regx.match(u2.str()).hasMatch()) return ReturnTrue; } } @@ -1519,7 +1538,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( case T_EVAL: { VisitReturn ret = ReturnFalse; QString contents = args.join(statics.field_sep); - ProFile *pro = m_parser->parsedProBlock(QStringRef(&contents), + ProFile *pro = m_parser->parsedProBlock(QStringView(contents), 0, m_current.pro->fileName(), m_current.line); if (m_cumulative || pro->isOk()) { m_locationStack.push(m_current); @@ -1531,19 +1550,19 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( return ret; } case T_IF: { - return evaluateConditional(args.at(0).toQStringRef(), + return evaluateConditional(args.at(0).toQStringView(), m_current.pro->fileName(), m_current.line); } case T_CONFIG: { if (args.count() == 1) - return returnBool(isActiveConfig(args.at(0).toQStringRef())); - const auto &mutuals = args.at(1).toQStringRef().split(QLatin1Char('|'), - QString::SkipEmptyParts); + return returnBool(isActiveConfig(args.at(0).toQStringView())); + const auto &mutuals = args.at(1).toQStringView().split(QLatin1Char('|'), + Qt::SkipEmptyParts); const ProStringList &configs = values(statics.strCONFIG); for (int i = configs.size() - 1; i >= 0; i--) { for (int mut = 0; mut < mutuals.count(); mut++) { - if (configs[i].toQStringRef() == mutuals[mut].trimmed()) + if (configs[i].toQStringView() == mutuals[mut].trimmed()) return returnBool(configs[i] == args[0]); } } @@ -1552,11 +1571,14 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( case T_CONTAINS: { ProStringRoUser u1(args.at(1), m_tmp1); const QString &qry = u1.str(); - QRegExp regx; - if (qry != QRegExp::escape(qry)) { - QString copy = qry; - copy.detach(); - regx.setPattern(copy); + QRegularExpression regx; + regx.setPatternOptions(QRegularExpression::DotMatchesEverythingOption); + if (qry != QRegularExpression::escape(qry)) { + regx.setPattern(QRegularExpression::anchoredPattern(qry)); + if (!regx.isValid()) { + evalError(fL1S("contains(): Encountered invalid regular expression '%1'.").arg(qry)); + return ReturnFalse; + } } const ProStringList &l = values(map(args.at(0))); if (args.count() == 2) { @@ -1564,24 +1586,24 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( const ProString &val = l[i]; if (val == qry) return ReturnTrue; - if (!regx.isEmpty()) { + if (!regx.pattern().isEmpty()) { ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]); - if (regx.exactMatch(u2.str())) + if (regx.match(u2.str()).hasMatch()) return ReturnTrue; } } } else { - const auto mutuals = args.at(2).toQStringRef().split(QLatin1Char('|'), - QString::SkipEmptyParts); + const auto mutuals = args.at(2).toQStringView().split(QLatin1Char('|'), + Qt::SkipEmptyParts); for (int i = l.size() - 1; i >= 0; i--) { const ProString &val = l[i]; for (int mut = 0; mut < mutuals.count(); mut++) { - if (val.toQStringRef() == mutuals[mut].trimmed()) { + if (val.toQStringView() == mutuals[mut].trimmed()) { if (val == qry) return ReturnTrue; - if (!regx.isEmpty()) { + if (!regx.pattern().isEmpty()) { ProStringRoUser u2(val, m_tmp[m_toggle ^= 1]); - if (regx.exactMatch(u2.str())) + if (regx.match(u2.str()).hasMatch()) return ReturnTrue; } return ReturnFalse; @@ -1629,8 +1651,8 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( } } if (func_t == T_GREATERTHAN) - return returnBool(lhs > rhs.toQStringRef()); - return returnBool(lhs < rhs.toQStringRef()); + return returnBool(lhs > rhs.toQStringView()); + return returnBool(lhs < rhs.toQStringView()); } case T_EQUALS: return returnBool(values(map(args.at(0))).join(statics.field_sep) @@ -1821,7 +1843,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( if (!vals.isEmpty()) contents = vals.join(QLatin1Char('\n')) + QLatin1Char('\n'); if (args.count() >= 3) { - const auto opts = split_value_list(args.at(2).toQStringRef()); + const auto opts = split_value_list(args.at(2).toQStringView()); for (const ProString &opt : opts) { if (opt == QLatin1String("append")) { mode = QIODevice::Append; diff --git a/src/linguist/shared/qmakeevaluator.cpp b/src/linguist/shared/qmakeevaluator.cpp index 639114d20f..37601b3881 100644 --- a/src/linguist/shared/qmakeevaluator.cpp +++ b/src/linguist/shared/qmakeevaluator.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -107,7 +107,7 @@ QMakeBaseKey::QMakeBaseKey(const QString &_root, const QString &_stash, bool _ho { } -uint qHash(const QMakeBaseKey &key) +size_t qHash(const QMakeBaseKey &key) { return qHash(key.root) ^ qHash(key.stash) ^ (uint)key.hostBuild; } @@ -272,7 +272,7 @@ void QMakeEvaluator::skipHashStr(const ushort *&tokPtr) // FIXME: this should not build new strings for direct sections. // Note that the E_SPRINTF and E_LIST implementations rely on the deep copy. -ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, int source) +ProStringList QMakeEvaluator::split_value_list(QStringView vals, int source) { QString build; ProStringList ret; @@ -334,7 +334,7 @@ ProStringList QMakeEvaluator::split_value_list(const QStringRef &vals, int sourc } static void replaceInList(ProStringList *varlist, - const QRegExp ®exp, const QString &replace, bool global, QString &tmp) + const QRegularExpression ®exp, const QString &replace, bool global, QString &tmp) { for (ProStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) { ProStringRoUser u1(*varit, tmp); @@ -653,7 +653,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProBlock( evalError(fL1S("Conditional must expand to exactly one word.")); okey = false; } else { - okey = isActiveConfig(curr.at(0).toQStringRef(), true); + okey = isActiveConfig(curr.at(0).toQStringView(), true); traceMsg("condition %s is %s", dbgStr(curr.at(0)), dbgBool(okey)); okey ^= invert; } @@ -780,7 +780,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProLoop( } infinite = true; } else { - const QStringRef &itl = it_list.toQStringRef(); + QStringView itl = it_list.toQStringView(); int dotdot = itl.indexOf(statics.strDotDot); if (dotdot != -1) { bool ok; @@ -877,13 +877,13 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( ProStringList varVal; if (expandVariableReferences(tokPtr, sizeHint, &varVal, true) == ReturnError) return ReturnError; - const QStringRef &val = varVal.at(0).toQStringRef(); + QStringView val = varVal.at(0).toQStringView(); if (val.length() < 4 || val.at(0) != QLatin1Char('s')) { evalError(fL1S("The ~= operator can handle only the s/// function.")); return ReturnTrue; } QChar sep = val.at(1); - auto func = val.split(sep, QString::KeepEmptyParts); + auto func = val.split(sep, Qt::KeepEmptyParts); if (func.count() < 3 || func.count() > 4) { evalError(fL1S("The s/// function expects 3 or 4 arguments.")); return ReturnTrue; @@ -898,9 +898,11 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProVariable( QString pattern = func[1].toString(); QString replace = func[2].toString(); if (quote) - pattern = QRegExp::escape(pattern); + pattern = QRegularExpression::escape(pattern); - QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive); + QRegularExpression regexp(pattern, case_sense ? + QRegularExpression::NoPatternOption : + QRegularExpression::CaseInsensitiveOption); // We could make a union of modified and unmodified values, // but this will break just as much as it fixes, so leave it as is. @@ -1022,7 +1024,7 @@ static ProString msvcArchitecture(const QString &vcInstallDir, const QString &pa QString vcBinDir = vcInstallDir; if (vcBinDir.endsWith(QLatin1Char('\\'))) vcBinDir.chop(1); - const auto dirs = pathVar.split(QLatin1Char(';'), QString::SkipEmptyParts); + const auto dirs = pathVar.split(QLatin1Char(';'), Qt::SkipEmptyParts); for (const QString &dir : dirs) { if (!dir.startsWith(vcBinDir, Qt::CaseInsensitive)) continue; @@ -1314,7 +1316,7 @@ void QMakeEvaluator::setupProject() void QMakeEvaluator::evaluateCommand(const QString &cmds, const QString &where) { if (!cmds.isEmpty()) { - ProFile *pro = m_parser->parsedProBlock(QStringRef(&cmds), 0, where, -1); + ProFile *pro = m_parser->parsedProBlock(QStringView(cmds), 0, where, -1); if (pro->isOk()) { m_locationStack.push(m_current); visitProBlock(pro, pro->tokPtr()); @@ -1623,7 +1625,7 @@ QString QMakeEvaluator::currentDirectory() const return QString(); } -bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex) +bool QMakeEvaluator::isActiveConfig(QStringView config, bool regex) { // magic types for easy flipping if (config == statics.strtrue) @@ -1635,17 +1637,17 @@ bool QMakeEvaluator::isActiveConfig(const QStringRef &config, bool regex) return m_hostBuild; if (regex && (config.contains(QLatin1Char('*')) || config.contains(QLatin1Char('?')))) { - QRegExp re(config.toString(), Qt::CaseSensitive, QRegExp::Wildcard); + QRegularExpression re(QRegularExpression::wildcardToRegularExpression(config.toString())); // mkspecs - if (re.exactMatch(m_qmakespecName)) + if (re.match(m_qmakespecName).hasMatch()) return true; // CONFIG variable const auto configValues = values(statics.strCONFIG); for (const ProString &configValue : configValues) { ProStringRoUser u1(configValue, m_tmp[m_toggle ^= 1]); - if (re.exactMatch(u1.str())) + if (re.match(u1.str()).hasMatch()) return true; } } else { @@ -1819,7 +1821,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateExpandFunction( } QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateConditional( - const QStringRef &cond, const QString &where, int line) + QStringView cond, const QString &where, int line) { VisitReturn ret = ReturnFalse; ProFile *pro = m_parser->parsedProBlock(cond, 0, where, line, QMakeParser::TestGrammar); @@ -1837,7 +1839,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::checkRequirements(const ProStringLis { ProStringList &failed = valuesRef(ProKey("QMAKE_FAILED_REQUIREMENTS")); for (const ProString &dep : deps) { - VisitReturn vr = evaluateConditional(dep.toQStringRef(), m_current.pro->fileName(), m_current.line); + VisitReturn vr = evaluateConditional(dep.toQStringView(), m_current.pro->fileName(), m_current.line); if (vr == ReturnError) return ReturnError; if (vr != ReturnTrue) @@ -2003,7 +2005,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateFeatureFile( int start_root = 0; const QStringList &paths = m_featureRoots->paths; if (!currFn.isEmpty()) { - QStringRef currPath = IoUtils::pathName(currFn); + QStringView currPath = IoUtils::pathName(currFn); for (int root = 0; root < paths.size(); ++root) if (currPath == paths.at(root)) { start_root = root + 1; diff --git a/src/linguist/shared/qmakeevaluator.h b/src/linguist/shared/qmakeevaluator.h index 201275305f..5079173a90 100644 --- a/src/linguist/shared/qmakeevaluator.h +++ b/src/linguist/shared/qmakeevaluator.h @@ -180,7 +180,7 @@ class QMAKE_EXPORT QMakeEvaluator void setTemplate(); - ProStringList split_value_list(const QStringRef &vals, int source = 0); + ProStringList split_value_list(QStringView vals, int source = 0); VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined); QString currentFileName() const; @@ -224,7 +224,7 @@ class QMAKE_EXPORT QMakeEvaluator VisitReturn evaluateBuiltinConditional(const QMakeInternal::QMakeBuiltin &adef, const ProKey &function, const ProStringList &args); - VisitReturn evaluateConditional(const QStringRef &cond, const QString &where, int line = -1); + VisitReturn evaluateConditional(QStringView cond, const QString &where, int line = -1); #ifdef PROEVALUATOR_FULL VisitReturn checkRequirements(const ProStringList &deps); #endif @@ -232,7 +232,7 @@ class QMAKE_EXPORT QMakeEvaluator void updateMkspecPaths(); void updateFeaturePaths(); - bool isActiveConfig(const QStringRef &config, bool regex = false); + bool isActiveConfig(QStringView config, bool regex = false); void populateDeps( const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes, diff --git a/src/linguist/shared/qmakeevaluator_p.h b/src/linguist/shared/qmakeevaluator_p.h index 91c4e098f1..a7d9112896 100644 --- a/src/linguist/shared/qmakeevaluator_p.h +++ b/src/linguist/shared/qmakeevaluator_p.h @@ -31,7 +31,7 @@ #include "proitems.h" -#include +#include #define debugMsg if (!m_debugLevel) {} else debugMsgInternal #define traceMsg if (!m_debugLevel) {} else traceMsgInternal @@ -43,7 +43,7 @@ r == ReturnNext ? "next" : \ r == ReturnReturn ? "return" : \ "") -# define dbgKey(s) s.toString().toQStringRef().toLocal8Bit().constData() +# define dbgKey(s) s.toString().toQStringView().toLocal8Bit().constData() # define dbgStr(s) qPrintable(formatValue(s, true)) # define dbgStrList(s) qPrintable(formatValueList(s)) # define dbgSepStrList(s) qPrintable(formatValueList(s, true)) @@ -109,7 +109,7 @@ extern QMakeStatics statics; } -Q_DECLARE_TYPEINFO(QMakeInternal::QMakeBuiltin, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QMakeInternal::QMakeBuiltin, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE diff --git a/src/linguist/shared/qmakeglobals.cpp b/src/linguist/shared/qmakeglobals.cpp index 6ba7abf28a..f6aad6f2cb 100644 --- a/src/linguist/shared/qmakeglobals.cpp +++ b/src/linguist/shared/qmakeglobals.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -261,7 +260,7 @@ QStringList QMakeGlobals::splitPathList(const QString &val) const QStringList ret; if (!val.isEmpty()) { QString cwd(QDir::currentPath()); - const QStringList vals = val.split(dirlist_sep, QString::SkipEmptyParts); + const QStringList vals = val.split(dirlist_sep, Qt::SkipEmptyParts); ret.reserve(vals.length()); for (const QString &it : vals) ret << IoUtils::resolvePath(cwd, it); diff --git a/src/linguist/shared/qmakeglobals.h b/src/linguist/shared/qmakeglobals.h index 9d4b87b0b5..3b6299a1bf 100644 --- a/src/linguist/shared/qmakeglobals.h +++ b/src/linguist/shared/qmakeglobals.h @@ -62,7 +62,7 @@ class QMakeBaseKey bool hostBuild; }; -uint qHash(const QMakeBaseKey &key); +size_t qHash(const QMakeBaseKey &key); bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two); class QMakeBaseEnv diff --git a/src/linguist/shared/qmakeparser.cpp b/src/linguist/shared/qmakeparser.cpp index f7ad73b356..20ced58402 100644 --- a/src/linguist/shared/qmakeparser.cpp +++ b/src/linguist/shared/qmakeparser.cpp @@ -217,7 +217,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) #endif QString contents; if (readFile(id, flags, &contents)) { - pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); + pro = parsedProBlock(QStringView(contents), id, fileName, 1, FullGrammar); pro->itemsRef()->squeeze(); pro->ref(); } else { @@ -238,7 +238,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) } else { QString contents; if (readFile(id, flags, &contents)) - pro = parsedProBlock(QStringRef(&contents), id, fileName, 1, FullGrammar); + pro = parsedProBlock(QStringView(contents), id, fileName, 1, FullGrammar); else pro = nullptr; } @@ -246,7 +246,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags) } ProFile *QMakeParser::parsedProBlock( - const QStringRef &contents, int id, const QString &name, int line, SubGrammar grammar) + QStringView contents, int id, const QString &name, int line, SubGrammar grammar) { ProFile *pro = new ProFile(id, name); read(pro, contents, line, grammar); @@ -291,7 +291,7 @@ void QMakeParser::putBlock(ushort *&tokPtr, const ushort *buf, uint len) void QMakeParser::putHashStr(ushort *&pTokPtr, const ushort *buf, uint len) { - uint hash = ProString::hash((const QChar *)buf, len); + const size_t hash = ProString::hash((const QChar *)buf, len); ushort *tokPtr = pTokPtr; *tokPtr++ = (ushort)hash; *tokPtr++ = (ushort)(hash >> 16); @@ -305,12 +305,12 @@ void QMakeParser::finalizeHashStr(ushort *buf, uint len) { buf[-4] = TokHashLiteral; buf[-1] = len; - uint hash = ProString::hash((const QChar *)buf, len); + const size_t hash = ProString::hash((const QChar *)buf, len); buf[-3] = (ushort)hash; buf[-2] = (ushort)(hash >> 16); } -void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar grammar) +void QMakeParser::read(ProFile *pro, QStringView in, int line, SubGrammar grammar) { m_proFile = pro; m_lineNo = line; @@ -358,7 +358,7 @@ void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar QStack xprStack; xprStack.reserve(10); - const ushort *cur = (const ushort *)in.unicode(); + const ushort *cur = (const ushort *)in.data(); const ushort *inend = cur + in.length(); m_canElse = false; freshLine: @@ -581,7 +581,7 @@ void QMakeParser::read(ProFile *pro, const QStringRef &in, int line, SubGrammar &buf, &xprBuff, &tokPtr, &tokBuff, cur, in)) { if (rtok == TokVariable || rtok == TokProperty) { xprPtr[-4] = tok; - uint hash = ProString::hash((const QChar *)xprPtr, tlen); + const size_t hash = ProString::hash((const QChar *)xprPtr, tlen); xprPtr[-3] = (ushort)hash; xprPtr[-2] = (ushort)(hash >> 16); xprPtr[-1] = tlen; @@ -1260,7 +1260,7 @@ void QMakeParser::finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int arg bool QMakeParser::resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QStringRef &in) + const ushort *cur, QStringView in) { QString out; m_tmp.setRawData((const QChar *)xprPtr, tlen); diff --git a/src/linguist/shared/qmakeparser.h b/src/linguist/shared/qmakeparser.h index ae76d8c466..c301157500 100644 --- a/src/linguist/shared/qmakeparser.h +++ b/src/linguist/shared/qmakeparser.h @@ -93,7 +93,7 @@ class QMAKE_EXPORT QMakeParser enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar }; // fileName is expected to be absolute and cleanPath()ed. ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault); - ProFile *parsedProBlock(const QStringRef &contents, int id, const QString &name, int line = 0, + ProFile *parsedProBlock(QStringView contents, int id, const QString &name, int line = 0, SubGrammar grammar = FullGrammar); void discardFileFromCache(int id); @@ -111,7 +111,6 @@ class QMAKE_EXPORT QMakeParser struct BlockScope { BlockScope() : start(nullptr), braceLevel(0), special(false), inBranch(false), nest(NestNone) {} - BlockScope(const BlockScope &other) { *this = other; } ushort *start; // Where this block started; store length here int braceLevel; // Nesting of braces in scope bool special; // Single-line conditionals inside loops, etc. cannot have else branches @@ -136,7 +135,7 @@ class QMAKE_EXPORT QMakeParser }; bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents); - void read(ProFile *pro, const QStringRef &content, int line, SubGrammar grammar); + void read(ProFile *pro, QStringView content, int line, SubGrammar grammar); ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok); ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len); @@ -147,7 +146,7 @@ class QMAKE_EXPORT QMakeParser ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr, ushort **buf, QString *xprBuff, ushort **tokPtr, QString *tokBuff, - const ushort *cur, const QStringRef &in); + const ushort *cur, QStringView in); void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount); void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc); void warnOperator(const char *msg); @@ -231,7 +230,7 @@ class QMAKE_EXPORT ProFileCache }; #if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3) -Q_DECLARE_TYPEINFO(QMakeParser::BlockScope, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(QMakeParser::BlockScope, Q_RELOCATABLE_TYPE); Q_DECLARE_TYPEINFO(QMakeParser::Context, Q_PRIMITIVE_TYPE); #endif diff --git a/src/linguist/shared/qmakevfs.cpp b/src/linguist/shared/qmakevfs.cpp index a5cfe72f04..241cd4ee60 100644 --- a/src/linguist/shared/qmakevfs.cpp +++ b/src/linguist/shared/qmakevfs.cpp @@ -35,10 +35,6 @@ using namespace QMakeInternal; #include #include -#ifndef QT_NO_TEXTCODEC -#include -#endif - #define fL1S(s) QString::fromLatin1(s) QT_BEGIN_NAMESPACE @@ -49,9 +45,6 @@ QMakeVfs::QMakeVfs() , m_magicExisting(fL1S("existing")) #endif { -#ifndef QT_NO_TEXTCODEC - m_textCodec = nullptr; -#endif ref(); } @@ -149,7 +142,7 @@ bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, QMutexLocker locker(&m_mutex); # endif QString *cont = &m_files[id]; - Q_UNUSED(flags) + Q_UNUSED(flags); if (mode & QIODevice::Append) *cont += contents; else @@ -235,11 +228,7 @@ QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errS *errStr = fL1S("Unexpected UTF-8 BOM"); return ReadOtherError; } - *contents = -#ifndef QT_NO_TEXTCODEC - m_textCodec ? m_textCodec->toUnicode(bcont) : -#endif - QString::fromLocal8Bit(bcont); + *contents = QString::fromLocal8Bit(bcont); return ReadOk; } @@ -254,7 +243,7 @@ bool QMakeVfs::exists(const QString &fn, VfsFlags flags) if (it != m_files.constEnd()) return it->constData() != m_magicMissing.constData(); #else - Q_UNUSED(flags) + Q_UNUSED(flags); #endif bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular; #ifndef PROEVALUATOR_FULL @@ -290,11 +279,4 @@ void QMakeVfs::invalidateContents() } #endif -#ifndef QT_NO_TEXTCODEC -void QMakeVfs::setTextCodec(const QTextCodec *textCodec) -{ - m_textCodec = textCodec; -} -#endif - QT_END_NAMESPACE diff --git a/src/linguist/shared/qmakevfs.h b/src/linguist/shared/qmakevfs.h index 2afcbf99ff..0fbe8461d8 100644 --- a/src/linguist/shared/qmakevfs.h +++ b/src/linguist/shared/qmakevfs.h @@ -38,10 +38,6 @@ # include #endif -#ifndef QT_NO_TEXTCODEC -QT_FORWARD_DECLARE_CLASS(QTextCodec) -#endif - #ifdef PROEVALUATOR_DUAL_VFS # ifndef PROEVALUATOR_CUMULATIVE # error PROEVALUATOR_DUAL_VFS requires PROEVALUATOR_CUMULATIVE @@ -92,10 +88,6 @@ class QMAKE_EXPORT QMakeVfs void invalidateContents(); #endif -#ifndef QT_NO_TEXTCODEC - void setTextCodec(const QTextCodec *textCodec); -#endif - private: #ifdef PROEVALUATOR_THREAD_SAFE static QMutex s_mutex; @@ -129,9 +121,6 @@ class QMAKE_EXPORT QMakeVfs QString m_magicMissing; QString m_magicExisting; #endif -#ifndef QT_NO_TEXTCODEC - const QTextCodec *m_textCodec; -#endif }; Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeVfs::VfsFlags) diff --git a/src/linguist/shared/qph.cpp b/src/linguist/shared/qph.cpp index f29b3789bd..9f1b0f2b45 100644 --- a/src/linguist/shared/qph.cpp +++ b/src/linguist/shared/qph.cpp @@ -30,7 +30,6 @@ #include #include -#include #include #include @@ -147,7 +146,6 @@ static QString protect(const QString &str) static bool saveQPH(const Translator &translator, QIODevice &dev, ConversionData &) { QTextStream t(&dev); - t.setCodec(QTextCodec::codecForName("UTF-8")); t << "\n\n"; - foreach (const TranslatorMessage &msg, translator.messages()) { + for (const TranslatorMessage &msg : translator.messages()) { t << "\n"; t << " " << protect(msg.sourceText()) << "\n"; QString str = msg.translations().join(QLatin1Char('@')); diff --git a/src/linguist/shared/runqttool.cpp b/src/linguist/shared/runqttool.cpp index e36a3a2a81..caf1e41359 100644 --- a/src/linguist/shared/runqttool.cpp +++ b/src/linguist/shared/runqttool.cpp @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include @@ -45,10 +45,9 @@ class FMT { Q_DECLARE_TR_FUNCTIONS(Linguist) }; -static QString qtToolFilePath(const QString &toolName) +static QString qtToolFilePath(const QString &toolName, QLibraryInfo::LibraryPath location) { - QString filePath = QCoreApplication::instance()->applicationDirPath() - + QLatin1Char('/') + toolName; + QString filePath = QLibraryInfo::path(location) + QLatin1Char('/') + toolName; #ifdef Q_OS_WIN filePath.append(QLatin1String(".exe")); #endif @@ -62,7 +61,7 @@ static void printErr(const QString &out) static QString shellQuoted(const QString &str) { - static QRegExp rx(QStringLiteral("\\s")); + static QRegularExpression rx(QStringLiteral("\\s")); QString result = str; if (result.contains(rx)) { const QLatin1Char dblqt = QLatin1Char('"'); @@ -89,10 +88,11 @@ static QString commandLineForSystem(const QString &program, + shellQuoted(arguments).join(QLatin1Char(' ')); } -void runQtTool(const QString &toolName, const QStringList &arguments) +void runQtTool(const QString &toolName, const QStringList &arguments, + QLibraryInfo::LibraryPath location) { int exitCode = 0; - const QString commandLine = commandLineForSystem(qtToolFilePath(toolName), arguments); + const QString commandLine = commandLineForSystem(qtToolFilePath(toolName, location), arguments); #if defined(Q_OS_WIN) exitCode = _wsystem(reinterpret_cast(commandLine.utf16())); #elif defined(Q_OS_UNIX) @@ -105,6 +105,11 @@ void runQtTool(const QString &toolName, const QStringList &arguments) exit(exitCode); } +void runInternalQtTool(const QString &toolName, const QStringList &arguments) +{ + runQtTool(toolName, arguments, QLibraryInfo::LibraryExecutablesPath); +} + std::unique_ptr createProjectDescription(QStringList args) { std::unique_ptr file(new QTemporaryFile(QStringLiteral("XXXXXX.json"))); @@ -114,6 +119,6 @@ std::unique_ptr createProjectDescription(QStringList args) } file->close(); args << QStringLiteral("-out") << file->fileName(); - runQtTool(QStringLiteral("lprodump"), args); + runInternalQtTool(QStringLiteral("lprodump"), args); return file; } diff --git a/src/linguist/shared/runqttool.h b/src/linguist/shared/runqttool.h index 16fe54fdeb..4d92066ceb 100644 --- a/src/linguist/shared/runqttool.h +++ b/src/linguist/shared/runqttool.h @@ -29,13 +29,16 @@ #ifndef RUNQTTOOL_H #define RUNQTTOOL_H +#include #include #include #include #include -void runQtTool(const QString &toolName, const QStringList &arguments); +void runQtTool(const QString &toolName, const QStringList &arguments, + QLibraryInfo::LibraryPath location = QLibraryInfo::BinariesPath); +void runInternalQtTool(const QString &toolName, const QStringList &arguments); std::unique_ptr createProjectDescription(QStringList args); #endif // RUNQTTOOL_H diff --git a/src/linguist/shared/simtexth.cpp b/src/linguist/shared/simtexth.cpp index 996b431b17..feb570178a 100644 --- a/src/linguist/shared/simtexth.cpp +++ b/src/linguist/shared/simtexth.cpp @@ -190,7 +190,7 @@ CandidateList similarTextHeuristicCandidates(const Translator *tor, CandidateList candidates; StringSimilarityMatcher matcher(text); - foreach (const TranslatorMessage &mtm, tor->messages()) { + for (const TranslatorMessage &mtm : tor->messages()) { if (mtm.type() == TranslatorMessage::Unfinished || mtm.translation().isEmpty()) continue; diff --git a/src/linguist/shared/translator.cpp b/src/linguist/shared/translator.cpp index db28ea396a..cfe61cb0a9 100644 --- a/src/linguist/shared/translator.cpp +++ b/src/linguist/shared/translator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Linguist of the Qt Toolkit. @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include @@ -212,7 +212,7 @@ void Translator::appendSorted(const TranslatorMessage &msg) // Working vars int prevLine = 0; int curIdx = 0; - foreach (const TranslatorMessage &mit, m_messages) { + for (const TranslatorMessage &mit : qAsConst(m_messages)) { bool sameFile = mit.fileName() == msg.fileName() && mit.context() == msg.context(); int curLine; if (sameFile && (curLine = mit.lineNumber()) >= prevLine) { @@ -257,7 +257,7 @@ static QString guessFormat(const QString &filename, const QString &format) if (format != QLatin1String("auto")) return format; - foreach (const Translator::FileFormat &fmt, Translator::registeredFileFormats()) { + for (const Translator::FileFormat &fmt : qAsConst(Translator::registeredFileFormats())) { if (filename.endsWith(QLatin1Char('.') + fmt.extension, Qt::CaseInsensitive)) return fmt.extension; } @@ -294,7 +294,7 @@ bool Translator::load(const QString &filename, ConversionData &cd, const QString QString fmt = guessFormat(filename, format); - foreach (const FileFormat &format, registeredFileFormats()) { + for (const FileFormat &format : qAsConst(registeredFileFormats())) { if (fmt == format.extension) { if (format.loader) return (*format.loader)(*this, file, cd); @@ -335,7 +335,7 @@ bool Translator::save(const QString &filename, ConversionData &cd, const QString QString fmt = guessFormat(filename, format); cd.m_targetDir = QFileInfo(filename).absoluteDir(); - foreach (const FileFormat &format, registeredFileFormats()) { + for (const FileFormat &format : qAsConst(registeredFileFormats())) { if (fmt == format.extension) { if (format.saver) return (*format.saver)(*this, file, cd); @@ -359,11 +359,15 @@ QString Translator::makeLanguageCode(QLocale::Language language, QLocale::Countr return result; } -void Translator::languageAndCountry(const QString &languageCode, - QLocale::Language *lang, QLocale::Country *country) +void Translator::languageAndCountry(const QString &languageCode, QLocale::Language *lang, + QLocale::Country *country) { - QLocale::Script script; - QLocalePrivate::getLangAndCountry(languageCode, *lang, script, *country); + // ### Uses private API. + QLocaleId lid = QLocaleId::fromName(languageCode); + if (lang) + *lang = QLocale::Language(lid.language_id); + if (country) + *country = QLocale::Country(lid.country_id); } int Translator::find(const TranslatorMessage &msg) const @@ -383,12 +387,12 @@ int Translator::find(const QString &context, const QString &comment, const TranslatorMessage::References &refs) const { if (!refs.isEmpty()) { - for (TMM::ConstIterator it = m_messages.constBegin(); it != m_messages.constEnd(); ++it) { + for (auto it = m_messages.cbegin(), end = m_messages.cend(); it != end; ++it) { if (it->context() == context && it->comment() == comment) { - foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { - foreach (const TranslatorMessage::Reference &ref, refs) { + for (const auto &itref : it->allReferences()) { + for (const auto &ref : refs) { if (itref == ref) - return it - m_messages.constBegin(); + return it - m_messages.cbegin(); } } } @@ -405,7 +409,7 @@ int Translator::find(const QString &context) const void Translator::stripObsoleteMessages() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) + for (auto it = m_messages.begin(); it != m_messages.end(); ) if (it->type() == TranslatorMessage::Obsolete || it->type() == TranslatorMessage::Vanished) it = m_messages.erase(it); else @@ -415,7 +419,7 @@ void Translator::stripObsoleteMessages() void Translator::stripFinishedMessages() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) + for (auto it = m_messages.begin(); it != m_messages.end(); ) if (it->type() == TranslatorMessage::Finished) it = m_messages.erase(it); else @@ -425,7 +429,7 @@ void Translator::stripFinishedMessages() void Translator::stripUntranslatedMessages() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) + for (auto it = m_messages.begin(); it != m_messages.end(); ) if (!it->isTranslated()) it = m_messages.erase(it); else @@ -433,20 +437,18 @@ void Translator::stripUntranslatedMessages() m_indexOk = false; } -bool Translator::translationsExist() +bool Translator::translationsExist() const { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) { - if (it->isTranslated()) + for (const auto &message : m_messages) { + if (message.isTranslated()) return true; - else - ++it; } return false; } void Translator::stripEmptyContexts() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end();) + for (auto it = m_messages.begin(); it != m_messages.end(); ) if (it->sourceText() == QLatin1String(ContextComment)) it = m_messages.erase(it); else @@ -456,7 +458,7 @@ void Translator::stripEmptyContexts() void Translator::stripNonPluralForms() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) + for (auto it = m_messages.begin(); it != m_messages.end(); ) if (!it->isPlural()) it = m_messages.erase(it); else @@ -466,7 +468,7 @@ void Translator::stripNonPluralForms() void Translator::stripIdenticalSourceTranslations() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ) { + for (auto it = m_messages.begin(); it != m_messages.end(); ) { // we need to have just one translation, and it be equal to the source if (it->translations().count() == 1 && it->translation() == it->sourceText()) it = m_messages.erase(it); @@ -478,21 +480,21 @@ void Translator::stripIdenticalSourceTranslations() void Translator::dropTranslations() { - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) { - if (it->type() == TranslatorMessage::Finished) - it->setType(TranslatorMessage::Unfinished); - it->setTranslation(QString()); + for (auto &message : m_messages) { + if (message.type() == TranslatorMessage::Finished) + message.setType(TranslatorMessage::Unfinished); + message.setTranslation(QString()); } } void Translator::dropUiLines() { - QString uiXt = QLatin1String(".ui"); - QString juiXt = QLatin1String(".jui"); - for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) { + const QString uiXt = QLatin1String(".ui"); + const QString juiXt = QLatin1String(".jui"); + for (auto &message : m_messages) { QHash have; QList refs; - foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { + for (const auto &itref : message.allReferences()) { const QString &fn = itref.fileName(); if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) { if (++have[fn] == 1) @@ -501,7 +503,7 @@ void Translator::dropUiLines() refs.append(itref); } } - it->setReferences(refs); + message.setReferences(refs); } } @@ -519,9 +521,9 @@ struct TranslatorMessageIdPtr { const TranslatorMessage *ptr; }; -Q_DECLARE_TYPEINFO(TranslatorMessageIdPtr, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(TranslatorMessageIdPtr, Q_RELOCATABLE_TYPE); -inline int qHash(TranslatorMessageIdPtr tmp) +inline size_t qHash(TranslatorMessageIdPtr tmp) { return qHash(tmp->id()); } @@ -545,11 +547,11 @@ struct TranslatorMessageContentPtr { const TranslatorMessage *ptr; }; -Q_DECLARE_TYPEINFO(TranslatorMessageContentPtr, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(TranslatorMessageContentPtr, Q_RELOCATABLE_TYPE); -inline int qHash(TranslatorMessageContentPtr tmp) +inline size_t qHash(TranslatorMessageContentPtr tmp) { - int hash = qHash(tmp->context()) ^ qHash(tmp->sourceText()); + size_t hash = qHash(tmp->context()) ^ qHash(tmp->sourceText()); if (!tmp->sourceText().isEmpty()) // Special treatment for context comments (empty source). hash ^= qHash(tmp->comment()); @@ -568,17 +570,17 @@ inline bool operator==(TranslatorMessageContentPtr tmp1, TranslatorMessageConten Translator::Duplicates Translator::resolveDuplicates() { + QList duplicateIndices; Duplicates dups; QHash idRefs; QHash contentRefs; - for (int i = 0; i < m_messages.count();) { + for (int i = 0; i < m_messages.count(); ++i) { const TranslatorMessage &msg = m_messages.at(i); TranslatorMessage *omsg; int oi; QSet *pDup; if (!msg.id().isEmpty()) { - QHash::ConstIterator it = - idRefs.constFind(TranslatorMessageIdPtr(msg)); + const auto it = idRefs.constFind(TranslatorMessageIdPtr(msg)); if (it != idRefs.constEnd()) { oi = *it; omsg = &m_messages[oi]; @@ -587,8 +589,7 @@ Translator::Duplicates Translator::resolveDuplicates() } } { - QHash::ConstIterator it = - contentRefs.constFind(TranslatorMessageContentPtr(msg)); + const auto it = contentRefs.constFind(TranslatorMessageContentPtr(msg)); if (it != contentRefs.constEnd()) { oi = *it; omsg = &m_messages[oi]; @@ -606,15 +607,19 @@ Translator::Duplicates Translator::resolveDuplicates() if (!msg.id().isEmpty()) idRefs[TranslatorMessageIdPtr(msg)] = i; contentRefs[TranslatorMessageContentPtr(msg)] = i; - ++i; continue; gotDupe: pDup->insert(oi); if (!omsg->isTranslated() && msg.isTranslated()) omsg->setTranslations(msg.translations()); m_indexOk = false; - m_messages.removeAt(i); + // don't remove the duplicate entries yet to not mess up the pointers that + // are in the hashes + duplicateIndices.append(i); } + // now remove the duplicates from the messages + for (int i = duplicateIndices.size() - 1; i >= 0; --i) + m_messages.removeAt(duplicateIndices.at(i)); return dups; } @@ -627,9 +632,9 @@ void Translator::reportDuplicates(const Duplicates &dupes, std::cerr << "'\n(try -verbose for more info).\n"; } else { std::cerr << "':\n"; - foreach (int i, dupes.byId) + for (int i : dupes.byId) std::cerr << "\n* ID: " << qPrintable(message(i).id()) << std::endl; - foreach (int j, dupes.byContents) { + for (int j : dupes.byContents) { const TranslatorMessage &msg = message(j); std::cerr << "\n* Context: " << qPrintable(msg.context()) << "\n* Source: " << qPrintable(msg.sourceText()) << std::endl; @@ -644,11 +649,10 @@ void Translator::reportDuplicates(const Duplicates &dupes, // Used by lupdate to be able to search using absolute paths during merging void Translator::makeFileNamesAbsolute(const QDir &originalPath) { - for (TMM::iterator it = m_messages.begin(); it != m_messages.end(); ++it) { - TranslatorMessage &msg = *it; - TranslatorMessage::References refs = msg.allReferences(); + for (auto &msg : m_messages) { + const TranslatorMessage::References refs = msg.allReferences(); msg.setReferences(TranslatorMessage::References()); - foreach (const TranslatorMessage::Reference &ref, refs) { + for (const TranslatorMessage::Reference &ref : refs) { QString fileName = ref.fileName(); QFileInfo fi (fileName); if (fi.isRelative()) @@ -658,7 +662,7 @@ void Translator::makeFileNamesAbsolute(const QDir &originalPath) } } -QList Translator::messages() const +const QList &Translator::messages() const { return m_messages; } @@ -716,13 +720,13 @@ void Translator::normalizeTranslations(ConversionData &cd) QString Translator::guessLanguageCodeFromFileName(const QString &filename) { QString str = filename; - foreach (const FileFormat &format, registeredFileFormats()) { + for (const FileFormat &format : qAsConst(registeredFileFormats())) { if (str.endsWith(format.extension)) { str = str.left(str.size() - format.extension.size() - 1); break; } } - static QRegExp re(QLatin1String("[\\._]")); + static QRegularExpression re(QLatin1String("[\\._]")); while (true) { QLocale locale(str); //qDebug() << "LANGUAGE FROM " << str << "LANG: " << locale.language(); diff --git a/src/linguist/shared/translator.h b/src/linguist/shared/translator.h index 5b5d122507..29cf68fa76 100644 --- a/src/linguist/shared/translator.h +++ b/src/linguist/shared/translator.h @@ -80,6 +80,7 @@ class ConversionData QString m_unTrPrefix; // QM specific QString m_sourceFileName; QString m_targetFileName; + QString m_compilationDatabaseDir; QStringList m_excludes; QDir m_sourceDir; QDir m_targetDir; // FIXME: TS specific @@ -104,8 +105,11 @@ class TMMKey { { return context == o.context && source == o.source && comment == o.comment; } QString context, source, comment; }; -Q_DECLARE_TYPEINFO(TMMKey, Q_MOVABLE_TYPE); -inline uint qHash(const TMMKey &key) { return qHash(key.context) ^ qHash(key.source) ^ qHash(key.comment); } +Q_DECLARE_TYPEINFO(TMMKey, Q_RELOCATABLE_TYPE); +inline size_t qHash(const TMMKey &key) +{ + return qHash(key.context) ^ qHash(key.source) ^ qHash(key.comment); +} class Translator { @@ -135,7 +139,7 @@ class Translator void dropTranslations(); void dropUiLines(); void makeFileNamesAbsolute(const QDir &originalPath); - bool translationsExist(); + bool translationsExist() const; struct Duplicates { QSet byId, byContents; }; Duplicates resolveDuplicates(); @@ -154,7 +158,7 @@ class Translator void setLanguageCode(const QString &languageCode) { m_language = languageCode; } void setSourceLanguageCode(const QString &languageCode) { m_sourceLanguage = languageCode; } static QString guessLanguageCodeFromFileName(const QString &fileName); - QList messages() const; + const QList &messages() const; static QStringList normalizedTranslations(const TranslatorMessage &m, int numPlurals); void normalizeTranslations(ConversionData &cd); QStringList normalizedTranslations(const TranslatorMessage &m, ConversionData &cd, bool *ok) const; diff --git a/src/linguist/shared/translatormessage.cpp b/src/linguist/shared/translatormessage.cpp index 0cc17f1dea..fbdb88b316 100644 --- a/src/linguist/shared/translatormessage.cpp +++ b/src/linguist/shared/translatormessage.cpp @@ -74,7 +74,7 @@ void TranslatorMessage::addReferenceUniq(const QString &fileName, int lineNumber if (fileName == m_fileName && lineNumber == m_lineNumber) return; if (!m_extraRefs.isEmpty()) { // Rather common case, so special-case it - foreach (const Reference &ref, m_extraRefs) { + for (const Reference &ref : qAsConst(m_extraRefs)) { if (fileName == ref.fileName() && lineNumber == ref.lineNumber()) return; } diff --git a/src/linguist/shared/translatormessage.h b/src/linguist/shared/translatormessage.h index a8a34d2fd3..310d7dfa84 100644 --- a/src/linguist/shared/translatormessage.h +++ b/src/linguist/shared/translatormessage.h @@ -88,7 +88,7 @@ class TranslatorMessage void appendTranslation(const QString &translation) { m_translations.append(translation); } bool isTranslated() const { - foreach (const QString &trans, m_translations) + for (const QString &trans : m_translations) if (!trans.isEmpty()) return true; return false; @@ -150,7 +150,7 @@ class TranslatorMessage bool m_plural; }; -Q_DECLARE_TYPEINFO(TranslatorMessage, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(TranslatorMessage, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE diff --git a/src/linguist/shared/ts.cpp b/src/linguist/shared/ts.cpp index 153f9708b3..a5daf7c908 100644 --- a/src/linguist/shared/ts.cpp +++ b/src/linguist/shared/ts.cpp @@ -30,8 +30,7 @@ #include #include -#include -#include +#include #include #include @@ -191,7 +190,6 @@ bool TSReader::read(Translator &translator) STRING(catalog); STRING(comment); STRING(context); - STRING(defaultcodec); STRING(dependencies); STRING(dependency); STRING(extracomment); @@ -250,11 +248,6 @@ bool TSReader::read(Translator &translator) break; } else if (isWhiteSpace()) { // ignore these, just whitespace - } else if (elementStarts(strdefaultcodec)) { - // - readElementText(); - m_cd.appendError(QString::fromLatin1("Warning: ignoring element")); - // } else if (isStartElement() && name().toString().startsWith(strextrans)) { // @@ -373,7 +366,7 @@ bool TSReader::read(Translator &translator) } else if (elementStarts(strtranslation)) { // QXmlStreamAttributes atts = attributes(); - QStringRef type = atts.value(strtype); + QStringView type = atts.value(strtype); if (type == strunfinished) msg.setType(TranslatorMessage::Unfinished); else if (type == strvanished) @@ -464,7 +457,7 @@ static QString protect(const QString &str) result += QLatin1String("'"); break; default: - if ((c < 0x20 || (ch > 0x7f && ch.isSpace())) && c != '\n' && c != '\t') + if ((c < 0x20 || (ch > QChar(0x7f) && ch.isSpace())) && c != '\n' && c != '\t') result += numericEntity(c); else // this also covers surrogates result += QChar(c); @@ -474,19 +467,19 @@ static QString protect(const QString &str) } static void writeExtras(QTextStream &t, const char *indent, - const TranslatorMessage::ExtraData &extras, QRegExp drops) + const TranslatorMessage::ExtraData &extras, QRegularExpression drops) { QStringList outs; - for (Translator::ExtraData::ConstIterator it = extras.begin(); it != extras.end(); ++it) { - if (!drops.exactMatch(it.key())) { + for (auto it = extras.cbegin(), end = extras.cend(); it != end; ++it) { + if (!drops.match(it.key()).hasMatch()) { outs << (QStringLiteral("') + protect(it.value()) + QStringLiteral("')); } } outs.sort(); - foreach (const QString &out, outs) - t << indent << out << endl; + for (const QString &out : qAsConst(outs)) + t << indent << out << Qt::endl; } static void writeVariants(QTextStream &t, const char *indent, const QString &input) @@ -516,8 +509,6 @@ bool saveTS(const Translator &translator, QIODevice &dev, ConversionData &cd) { bool result = true; QTextStream t(&dev); - t.setCodec(QTextCodec::codecForName("UTF-8")); - //qDebug() << translator.codecName(); // The xml prolog allows processors to easily detect the correct encoding t << "\n\n"; @@ -532,21 +523,21 @@ bool saveTS(const Translator &translator, QIODevice &dev, ConversionData &cd) t << " sourcelanguage=\"" << languageCode << "\""; t << ">\n"; - QStringList deps = translator.dependencies(); + const QStringList deps = translator.dependencies(); if (!deps.isEmpty()) { t << "\n"; - foreach (const QString &dep, deps) + for (const QString &dep : deps) t << "\n"; t << "\n"; } - QRegExp drops(cd.dropTags().join(QLatin1Char('|'))); + QRegularExpression drops(QRegularExpression::anchoredPattern(cd.dropTags().join(QLatin1Char('|')))); writeExtras(t, " ", translator.extras(), drops); QHash > messageOrder; QList contextOrder; - foreach (const TranslatorMessage &msg, translator.messages()) { + for (const TranslatorMessage &msg : translator.messages()) { // no need for such noise if ((msg.type() == TranslatorMessage::Obsolete || msg.type() == TranslatorMessage::Vanished) && msg.translation().isEmpty()) { @@ -563,12 +554,12 @@ bool saveTS(const Translator &translator, QIODevice &dev, ConversionData &cd) QHash currentLine; QString currentFile; - foreach (const QString &context, contextOrder) { + for (const QString &context : qAsConst(contextOrder)) { t << "\n" " " << protect(context) << "\n"; - foreach (const TranslatorMessage &msg, messageOrder[context]) { + for (const TranslatorMessage &msg : qAsConst(messageOrder[context])) { //msg.dump(); t << " #include -#include +#include #include #include -#include #include -#include -#include -#include - - // The string value is historical and reflects the main purpose: Keeping // obsolete entries separate from the magic file message (which both have // no location information, but typically reside at opposite ends of the file). @@ -180,10 +175,10 @@ static QString protect(const QString &str, bool makePhs = true) static void writeExtras(QTextStream &ts, int indent, - const TranslatorMessage::ExtraData &extras, QRegExp drops) + const TranslatorMessage::ExtraData &extras, QRegularExpression drops) { - for (Translator::ExtraData::ConstIterator it = extras.begin(); it != extras.end(); ++it) { - if (!drops.exactMatch(it.key())) { + for (auto it = extras.cbegin(), end = extras.cend(); it != end; ++it) { + if (!drops.match(it.key()).hasMatch()) { writeIndent(ts, indent); ts << "' << protect(it.value()) @@ -199,7 +194,8 @@ static void writeLineNumber(QTextStream &ts, const TranslatorMessage &msg, int i writeIndent(ts, indent); ts << "" << msg.lineNumber() << "\n"; - foreach (const TranslatorMessage::Reference &ref, msg.extraReferences()) { + const auto refs = msg.extraReferences(); + for (const TranslatorMessage::Reference &ref : refs) { writeIndent(ts, indent); ts << ""; if (ref.fileName() != msg.fileName()) @@ -209,7 +205,7 @@ static void writeLineNumber(QTextStream &ts, const TranslatorMessage &msg, int i } } -static void writeComment(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent) +static void writeComment(QTextStream &ts, const TranslatorMessage &msg, const QRegularExpression &drops, int indent) { if (!msg.comment().isEmpty()) { writeIndent(ts, indent); @@ -236,21 +232,22 @@ static void writeComment(QTextStream &ts, const TranslatorMessage &msg, const QR } } -static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent) +static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegularExpression &drops, int indent) { static int msgid; QString msgidstr = !msg.id().isEmpty() ? msg.id() : QString::fromLatin1("_msg%1").arg(++msgid); QStringList translns = msg.translations(); - QHash::const_iterator it; QString pluralStr; QStringList sources(msg.sourceText()); - if ((it = msg.extras().find(QString::fromLatin1("po-msgid_plural"))) != msg.extras().end()) + const auto &extras = msg.extras(); + const auto extrasEnd = extras.cend(); + if (const auto it = extras.constFind(QString::fromLatin1("po-msgid_plural")); it != extrasEnd) sources.append(*it); QStringList oldsources; if (!msg.oldSourceText().isEmpty()) oldsources.append(msg.oldSourceText()); - if ((it = msg.extras().find(QString::fromLatin1("po-old_msgid_plural"))) != msg.extras().end()) { + if (const auto it = extras.constFind(QString::fromLatin1("po-old_msgid_plural")); it != extrasEnd) { if (oldsources.isEmpty()) { if (sources.count() == 2) oldsources.append(QString()); @@ -260,10 +257,9 @@ static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const oldsources.append(*it); } - QStringList::const_iterator - srcit = sources.begin(), srcend = sources.end(), - oldsrcit = oldsources.begin(), oldsrcend = oldsources.end(), - transit = translns.begin(), transend = translns.end(); + auto srcit = sources.cbegin(), srcend = sources.cend(), + oldsrcit = oldsources.cbegin(), oldsrcend = oldsources.cend(), + transit = translns.cbegin(), transend = translns.cend(); int plural = 0; QString source; while (srcit != srcend || oldsrcit != oldsrcend || transit != transend) { @@ -345,7 +341,7 @@ static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const } } -static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent) +static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegularExpression &drops, int indent) { if (msg.isPlural()) { writeIndent(ts, indent); @@ -368,22 +364,22 @@ static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QR } } - -class XLIFFHandler : public QXmlDefaultHandler +class XLIFFHandler : public XmlParser { public: - XLIFFHandler(Translator &translator, ConversionData &cd); + XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader); + ~XLIFFHandler() override = default; - bool startElement(const QString& namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts ); - bool endElement(const QString& namespaceURI, const QString &localName, - const QString &qName ); - bool characters(const QString &ch); - bool fatalError(const QXmlParseException &exception); +private: + bool startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) override; + bool endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) override; + bool characters(QStringView ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; - bool endDocument(); + bool endDocument() override; -private: enum XliffContext { XC_xliff, XC_group, @@ -442,14 +438,16 @@ class XLIFFHandler : public QXmlDefaultHandler QStack m_contextStack; }; -XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd) - : m_translator(translator), m_cd(cd), - m_translate(true), - m_approved(true), - m_lineNumber(-1), - m_URITT(QLatin1String(TrollTsNamespaceURI)), - m_URI(QLatin1String(XLIFF11namespaceURI)), - m_URI12(QLatin1String(XLIFF12namespaceURI)) +XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader) + : XmlParser(reader, true), + m_translator(translator), + m_cd(cd), + m_translate(true), + m_approved(true), + m_lineNumber(-1), + m_URITT(QLatin1String(TrollTsNamespaceURI)), + m_URI(QLatin1String(XLIFF11namespaceURI)), + m_URI12(QLatin1String(XLIFF12namespaceURI)) {} @@ -485,33 +483,35 @@ bool XLIFFHandler::hasContext(XliffContext ctx) const return false; } -bool XLIFFHandler::startElement(const QString& namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts ) +bool XLIFFHandler::startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts) { Q_UNUSED(qName); if (namespaceURI == m_URITT) goto bail; - if (namespaceURI != m_URI && namespaceURI != m_URI12) - return false; + if (namespaceURI != m_URI && namespaceURI != m_URI12) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Unknown namespace in the XLIFF file")); + } if (localName == QLatin1String("xliff")) { // make sure that the stack is not empty during parsing pushContext(XC_xliff); } else if (localName == QLatin1String("file")) { - m_fileName = atts.value(QLatin1String("original")); - m_language = atts.value(QLatin1String("target-language")); + m_fileName = atts.value(QLatin1String("original")).toString(); + m_language = atts.value(QLatin1String("target-language")).toString(); m_language.replace(QLatin1Char('-'), QLatin1Char('_')); - m_sourceLanguage = atts.value(QLatin1String("source-language")); + m_sourceLanguage = atts.value(QLatin1String("source-language")).toString(); m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_')); if (m_sourceLanguage == QLatin1String("en")) m_sourceLanguage.clear(); } else if (localName == QLatin1String("group")) { if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) { - m_context = atts.value(QLatin1String("resname")); + m_context = atts.value(QLatin1String("resname")).toString(); pushContext(XC_restype_context); } else { if (atts.value(QLatin1String("restype")) == QLatin1String(restypePlurals)) { pushContext(XC_restype_plurals); - m_id = atts.value(QLatin1String("id")); + m_id = atts.value(QLatin1String("id")).toString(); if (atts.value(QLatin1String("translate")) == QLatin1String("no")) m_translate = false; } else { @@ -523,7 +523,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, if (atts.value(QLatin1String("translate")) == QLatin1String("no")) m_translate = false; if (!hasContext(XC_restype_plurals)) { - m_id = atts.value(QLatin1String("id")); + m_id = atts.value(QLatin1String("id")).toString(); if (m_id.startsWith(QLatin1String("_msg"))) m_id.clear(); } @@ -539,19 +539,18 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, if (atts.value(QLatin1String("restype")) != QLatin1String(restypeDummy)) pushContext(XC_restype_translation); } else if (localName == QLatin1String("context-group")) { - QString purpose = atts.value(QLatin1String("purpose")); - if (purpose == QLatin1String("location")) + if (atts.value(QLatin1String("purpose")) == QLatin1String("location")) pushContext(XC_context_group); else pushContext(XC_context_group_any); } else if (currentContext() == XC_context_group && localName == QLatin1String("context")) { - QString ctxtype = atts.value(QLatin1String("context-type")); + const auto ctxtype = atts.value(QLatin1String("context-type")); if (ctxtype == QLatin1String("linenumber")) pushContext(XC_context_linenumber); else if (ctxtype == QLatin1String("sourcefile")) pushContext(XC_context_filename); } else if (currentContext() == XC_context_group_any && localName == QLatin1String("context")) { - QString ctxtype = atts.value(QLatin1String("context-type")); + const auto ctxtype = atts.value(QLatin1String("context-type")); if (ctxtype == QLatin1String(contextMsgctxt)) pushContext(XC_context_comment); else if (ctxtype == QLatin1String(contextOldMsgctxt)) @@ -563,7 +562,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, else pushContext(XC_translator_comment); } else if (localName == QLatin1String("ph")) { - QString ctype = atts.value(QLatin1String("ctype")); + QString ctype = atts.value(QLatin1String("ctype")).toString(); if (ctype.startsWith(QLatin1String("x-ch-"))) m_ctype = ctype.mid(5); pushContext(XC_ph); @@ -574,19 +573,21 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, return true; } -bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localName, - const QString &qName) +bool XLIFFHandler::endElement(QStringView namespaceURI, QStringView localName, + QStringView qName) { Q_UNUSED(qName); if (namespaceURI == m_URITT) { if (hasContext(XC_trans_unit) || hasContext(XC_restype_plurals)) - m_extra[localName] = accum; + m_extra[localName.toString()] = accum; else - m_translator.setExtra(localName, accum); + m_translator.setExtra(localName.toString(), accum); return true; } - if (namespaceURI != m_URI && namespaceURI != m_URI12) - return false; + if (namespaceURI != m_URI && namespaceURI != m_URI12) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Unknown namespace in the XLIFF file")); + } //qDebug() << "URI:" << namespaceURI << "QNAME:" << qName; if (localName == QLatin1String("xliff")) { popContext(XC_xliff); @@ -640,15 +641,19 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN if (!m_hadAlt) m_oldSources.append(QString()); if (!hasContext(XC_restype_plurals)) { - if (!finalizeMessage(false)) - return false; + if (!finalizeMessage(false)) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Element processing failed")); + } } } else if (localName == QLatin1String("alt-trans")) { popContext(XC_alt_trans); } else if (localName == QLatin1String("group")) { if (popContext(XC_restype_plurals)) { - if (!finalizeMessage(true)) - return false; + if (!finalizeMessage(true)) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Element processing failed")); + } } else if (popContext(XC_restype_context)) { m_context.clear(); } else { @@ -658,11 +663,11 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN return true; } -bool XLIFFHandler::characters(const QString &ch) +bool XLIFFHandler::characters(QStringView ch) { if (currentContext() == XC_ph) { // handle the content of elements - for (int i = 0; i < ch.count(); ++i) { + for (int i = 0; i < ch.size(); ++i) { QChar chr = ch.at(i); if (accum.endsWith(QLatin1Char('\\'))) accum[accum.size() - 1] = QLatin1Char(charFromEscape(chr.toLatin1())); @@ -670,7 +675,7 @@ bool XLIFFHandler::characters(const QString &ch) accum.append(chr); } } else { - QString t = ch; + QString t = ch.toString(); t.replace(QLatin1String("\r"), QLatin1String("")); accum.append(t); } @@ -730,23 +735,20 @@ bool XLIFFHandler::finalizeMessage(bool isPlural) return true; } -bool XLIFFHandler::fatalError(const QXmlParseException &exception) +bool XLIFFHandler::fatalError(qint64 line, qint64 column, const QString &message) { QString msg = QString::asprintf("XML error: Parse error at line %d, column %d (%s).\n", - exception.lineNumber(), exception.columnNumber(), - exception.message().toLatin1().data()); + static_cast(line), static_cast(column), + message.toLatin1().data()); m_cd.appendError(msg); return false; } bool loadXLIFF(Translator &translator, QIODevice &dev, ConversionData &cd) { - QXmlInputSource in(&dev); - QXmlSimpleReader reader; - XLIFFHandler hand(translator, cd); - reader.setContentHandler(&hand); - reader.setErrorHandler(&hand); - return reader.parse(in); + QXmlStreamReader reader(&dev); + XLIFFHandler hand(translator, cd, reader); + return hand.parse(); } bool saveXLIFF(const Translator &translator, QIODevice &dev, ConversionData &cd) @@ -755,16 +757,15 @@ bool saveXLIFF(const Translator &translator, QIODevice &dev, ConversionData &cd) int indent = 0; QTextStream ts(&dev); - ts.setCodec(QTextCodec::codecForName("UTF-8")); QStringList dtgs = cd.dropTags(); dtgs << QLatin1String("po-(old_)?msgid_plural"); - QRegExp drops(dtgs.join(QLatin1Char('|'))); + QRegularExpression drops(QRegularExpression::anchoredPattern(dtgs.join(QLatin1Char('|')))); QHash > > messageOrder; QHash > contextOrder; QList fileOrder; - foreach (const TranslatorMessage &msg, translator.messages()) { + for (const TranslatorMessage &msg : translator.messages()) { QString fn = msg.fileName(); if (fn.isEmpty() && msg.type() == TranslatorMessage::Obsolete) fn = QLatin1String(MAGIC_OBSOLETE_REFERENCE); @@ -791,16 +792,16 @@ bool saveXLIFF(const Translator &translator, QIODevice &dev, ConversionData &cd) sourceLanguageCode.replace(QLatin1Char('_'), QLatin1Char('-')); QString languageCode = translator.languageCode(); languageCode.replace(QLatin1Char('_'), QLatin1Char('-')); - foreach (const QString &fn, fileOrder) { + for (const QString &fn : qAsConst(fileOrder)) { writeIndent(ts, indent); ts << "first()) << "\"" + << " datatype=\"" << dataType(messageOrder[fn].cbegin()->first()) << "\"" << " source-language=\"" << sourceLanguageCode.toLatin1() << "\"" << " target-language=\"" << languageCode.toLatin1() << "\"" << ">\n"; ++indent; - foreach (const QString &ctx, contextOrder[fn]) { + for (const QString &ctx : qAsConst(contextOrder[fn])) { if (!ctx.isEmpty()) { writeIndent(ts, indent); ts << " +#include + +QT_BEGIN_NAMESPACE + +class XmlParser +{ +public: + XmlParser(QXmlStreamReader &r, bool whitespaceOnlyData = false) + : reader(r), reportWhitespaceOnlyData(whitespaceOnlyData) + { + } + virtual ~XmlParser() = default; + + bool parse(); + +protected: + virtual bool startElement(QStringView namespaceURI, QStringView localName, + QStringView qName, const QXmlStreamAttributes &atts); + virtual bool endElement(QStringView namespaceURI, QStringView localName, + QStringView qName); + virtual bool characters(QStringView text); + virtual bool endDocument(); + virtual bool fatalError(qint64 line, qint64 column, const QString &message); + + QXmlStreamReader &reader; + bool reportWhitespaceOnlyData; +}; + +QT_END_NAMESPACE + +#endif // XMLPARSER_H diff --git a/src/macdeployqt/CMakeLists.txt b/src/macdeployqt/CMakeLists.txt new file mode 100644 index 0000000000..cbce4e4ca3 --- /dev/null +++ b/src/macdeployqt/CMakeLists.txt @@ -0,0 +1,6 @@ +# Generated from macdeployqt.pro. + +if(NOT QT_FEATURE_macdeployqt) + return() +endif() +add_subdirectory(macdeployqt) diff --git a/src/macdeployqt/macchangeqt/macchangeqt.pro b/src/macdeployqt/macchangeqt/macchangeqt.pro deleted file mode 100644 index bf195f89a7..0000000000 --- a/src/macdeployqt/macchangeqt/macchangeqt.pro +++ /dev/null @@ -1,5 +0,0 @@ -SOURCES += main.cpp ../shared/shared.cpp -QT = core -LIBS += -framework CoreFoundation - -load(qt_app) diff --git a/src/macdeployqt/macchangeqt/main.cpp b/src/macdeployqt/macchangeqt/main.cpp deleted file mode 100644 index 8030123836..0000000000 --- a/src/macdeployqt/macchangeqt/main.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "../shared/shared.h" - -int main(int argc, char **argv) -{ - // useDebugLibs should always be false because even if set all Qt - // libraries inside a binary to point to debug versions, as soon as - // one of them loads a Qt plugin, the plugin itself will load the - // release version of Qt, and as such, the app will crash. - bool useDebugLibs = false; - - int optionsSpecified = 0; - for (int i = 2; i < argc; ++i) { - QByteArray argument = QByteArray(argv[i]); - if (argument.startsWith(QByteArray("-verbose="))) { - LogDebug() << "Argument found:" << argument; - optionsSpecified++; - int index = argument.indexOf("="); - bool ok = false; - int number = argument.mid(index+1).toInt(&ok); - if (!ok) - LogError() << "Could not parse verbose level"; - else - logLevel = number; - } - } - - if (argc != (3 + optionsSpecified)) { - qDebug() << "Changeqt: changes which Qt frameworks an application links against."; - qDebug() << "Usage: changeqt app-bundle qt-dir <-verbose=[0-3]>"; - return 0; - } - - const QString appPath = QString::fromLocal8Bit(argv[1]); - const QString qtPath = QString::fromLocal8Bit(argv[2]); - changeQtFrameworks(appPath, qtPath, useDebugLibs); -} diff --git a/src/macdeployqt/macdeployqt.pro b/src/macdeployqt/macdeployqt.pro deleted file mode 100644 index a0d90b640a..0000000000 --- a/src/macdeployqt/macdeployqt.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = macdeployqt macchangeqt diff --git a/src/macdeployqt/macdeployqt/CMakeLists.txt b/src/macdeployqt/macdeployqt/CMakeLists.txt new file mode 100644 index 0000000000..0c63a877f8 --- /dev/null +++ b/src/macdeployqt/macdeployqt/CMakeLists.txt @@ -0,0 +1,13 @@ +# Generated from macdeployqt.pro. + +##################################################################### +## macdeployqt App: +##################################################################### + +qt_internal_add_app(macdeployqt + SOURCES + ../shared/shared.cpp + main.cpp + PUBLIC_LIBRARIES + ${FWCoreFoundation} +) diff --git a/src/macdeployqt/macdeployqt/macdeployqt.pro b/src/macdeployqt/macdeployqt/macdeployqt.pro deleted file mode 100644 index bf195f89a7..0000000000 --- a/src/macdeployqt/macdeployqt/macdeployqt.pro +++ /dev/null @@ -1,5 +0,0 @@ -SOURCES += main.cpp ../shared/shared.cpp -QT = core -LIBS += -framework CoreFoundation - -load(qt_app) diff --git a/src/macdeployqt/macdeployqt/main.cpp b/src/macdeployqt/macdeployqt/main.cpp index 0599b739e9..628a71378a 100644 --- a/src/macdeployqt/macdeployqt/main.cpp +++ b/src/macdeployqt/macdeployqt/main.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include #include +#include #include "../shared/shared.h" @@ -42,19 +43,22 @@ int main(int argc, char **argv) qDebug() << "Usage: macdeployqt app-bundle [options]"; qDebug() << ""; qDebug() << "Options:"; - qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug"; - qDebug() << " -no-plugins : Skip plugin deployment"; - qDebug() << " -dmg : Create a .dmg disk image"; - qDebug() << " -no-strip : Don't run 'strip' on the binaries"; - qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)"; - qDebug() << " -executable= : Let the given executable use the deployed frameworks too"; - qDebug() << " -qmldir= : Scan for QML imports in the given path"; - qDebug() << " -qmlimport= : Add the given path to the QML module search locations"; - qDebug() << " -always-overwrite : Copy files even if the target file exists"; - qDebug() << " -codesign= : Run codesign with the given identity on all executables"; - qDebug() << " -appstore-compliant: Skip deployment of components that use private API"; - qDebug() << " -libpath= : Add the given path to the library search path"; - qDebug() << " -fs= : Set the filesystem used for the .dmg disk image (defaults to HFS+)"; + qDebug() << " -verbose=<0-3> : 0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug"; + qDebug() << " -no-plugins : Skip plugin deployment"; + qDebug() << " -dmg : Create a .dmg disk image"; + qDebug() << " -no-strip : Don't run 'strip' on the binaries"; + qDebug() << " -use-debug-libs : Deploy with debug versions of frameworks and plugins (implies -no-strip)"; + qDebug() << " -executable= : Let the given executable use the deployed frameworks too"; + qDebug() << " -qmldir= : Scan for QML imports in the given path"; + qDebug() << " -qmlimport= : Add the given path to the QML module search locations"; + qDebug() << " -always-overwrite : Copy files even if the target file exists"; + qDebug() << " -codesign= : Run codesign with the given identity on all executables"; + qDebug() << " -hardened-runtime : Enable Hardened Runtime when code signing"; + qDebug() << " -timestamp : Include a secure timestamp when code signing (requires internet connection)"; + qDebug() << " -sign-for-notarization=: Activate the necessary options for notarization (requires internet connection)"; + qDebug() << " -appstore-compliant : Skip deployment of components that use private API"; + qDebug() << " -libpath= : Add the given path to the library search path"; + qDebug() << " -fs= : Set the filesystem used for the .dmg disk image (defaults to HFS+)"; qDebug() << ""; qDebug() << "macdeployqt takes an application bundle as input and makes it"; qDebug() << "self-contained by copying in the Qt frameworks and plugins that"; @@ -96,8 +100,10 @@ int main(int argc, char **argv) QStringList qmlImportPaths; extern bool runCodesign; extern QString codesignIdentiy; + extern bool hardenedRuntime; extern bool appstoreCompliant; extern bool deployFramework; + extern bool secureTimestamp; for (int i = 2; i < argc; ++i) { QByteArray argument = QByteArray(argv[i]); @@ -164,6 +170,23 @@ int main(int argc, char **argv) runCodesign = true; codesignIdentiy = argument.mid(index+1); } + } else if (argument.startsWith(QByteArray("-sign-for-notarization"))) { + LogDebug() << "Argument found:" << argument; + int index = argument.indexOf("="); + if (index < 0 || index >= argument.size()) { + LogError() << "Missing code signing identity"; + } else { + runCodesign = true; + hardenedRuntime = true; + secureTimestamp = true; + codesignIdentiy = argument.mid(index+1); + } + } else if (argument.startsWith(QByteArray("-hardened-runtime"))) { + LogDebug() << "Argument found:" << argument; + hardenedRuntime = true; + } else if (argument.startsWith(QByteArray("-timestamp"))) { + LogDebug() << "Argument found:" << argument; + secureTimestamp = true; } else if (argument == QByteArray("-appstore-compliant")) { LogDebug() << "Argument found:" << argument; appstoreCompliant = true; @@ -210,14 +233,34 @@ int main(int argc, char **argv) // Update deploymentInfo.deployedFrameworks - the QML imports // may have brought in extra frameworks as dependencies. deploymentInfo.deployedFrameworks += findAppFrameworkNames(appBundlePath); - deploymentInfo.deployedFrameworks = deploymentInfo.deployedFrameworks.toSet().toList(); + deploymentInfo.deployedFrameworks = + QSet(deploymentInfo.deployedFrameworks.begin(), + deploymentInfo.deployedFrameworks.end()).values(); } - if (plugins && !deploymentInfo.qtPath.isEmpty()) { - deploymentInfo.pluginPath = deploymentInfo.qtPath + "/plugins"; - LogNormal(); - deployPlugins(appBundlePath, deploymentInfo, useDebugLibs); - createQtConf(appBundlePath); + // Handle plugins + if (plugins) { + // Set the plugins search directory + deploymentInfo.pluginPath = QLibraryInfo::path(QLibraryInfo::PluginsPath); + + // Sanity checks + if (deploymentInfo.pluginPath.isEmpty()) { + LogError() << "Missing Qt plugins path\n"; + return 1; + } + + if (!QDir(deploymentInfo.pluginPath).exists()) { + LogError() << "Plugins path does not exist" << deploymentInfo.pluginPath << "\n"; + return 1; + } + + // Deploy plugins + Q_ASSERT(!deploymentInfo.pluginPath.isEmpty()); + if (!deploymentInfo.pluginPath.isEmpty()) { + LogNormal(); + deployPlugins(appBundlePath, deploymentInfo, useDebugLibs); + createQtConf(appBundlePath); + } } if (runStripEnabled) @@ -233,4 +276,3 @@ int main(int argc, char **argv) return 0; } - diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp index a248d8ccde..0f87cc76ab 100644 --- a/src/macdeployqt/shared/shared.cpp +++ b/src/macdeployqt/shared/shared.cpp @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -53,6 +52,9 @@ bool alwaysOwerwriteEnabled = false; bool runCodesign = false; QStringList librarySearchPath; QString codesignIdentiy; +QString extraEntitlements; +bool hardenedRuntime = false; +bool secureTimestamp = false; bool appstoreCompliant = false; int logLevel = 1; bool deployFramework = false; @@ -180,10 +182,10 @@ OtoolInfo findDependencyInfo(const QString &binaryPath) static const QRegularExpression regexp(QStringLiteral( "^\\t(.+) \\(compatibility version (\\d+\\.\\d+\\.\\d+), " - "current version (\\d+\\.\\d+\\.\\d+)\\)$")); + "current version (\\d+\\.\\d+\\.\\d+)(, weak)?\\)$")); QString output = otool.readAllStandardOutput(); - QStringList outputLines = output.split("\n", QString::SkipEmptyParts); + QStringList outputLines = output.split("\n", Qt::SkipEmptyParts); if (outputLines.size() < 2) { LogError() << "Could not parse otool output:" << output; return info; @@ -193,13 +195,19 @@ OtoolInfo findDependencyInfo(const QString &binaryPath) if (binaryPath.contains(".framework/") || binaryPath.endsWith(".dylib")) { const auto match = regexp.match(outputLines.first()); if (match.hasMatch()) { - info.installName = match.captured(1); - info.compatibilityVersion = QVersionNumber::fromString(match.captured(2)); - info.currentVersion = QVersionNumber::fromString(match.captured(3)); + QString installname = match.captured(1); + if (QFileInfo(binaryPath).fileName() == QFileInfo(installname).fileName()) { + info.installName = installname; + info.compatibilityVersion = QVersionNumber::fromString(match.captured(2)); + info.currentVersion = QVersionNumber::fromString(match.captured(3)); + outputLines.removeFirst(); + } else { + info.installName = binaryPath; + } } else { LogError() << "Could not parse otool output line:" << outputLines.first(); + outputLines.removeFirst(); } - outputLines.removeFirst(); } for (const QString &outputLine : outputLines) { @@ -472,6 +480,23 @@ QStringList findAppBundleFiles(const QString &appBundlePath, bool absolutePath = return result; } +QString findEntitlementsFile(const QString& path) +{ + QDirIterator iter(path, QStringList() << QString::fromLatin1("*.entitlements"), + QDir::Files, QDirIterator::Subdirectories); + + while (iter.hasNext()) { + iter.next(); + if (iter.fileInfo().isSymLink()) + continue; + + //return the first entitlements file - only one is used for signing anyway + return iter.fileInfo().absoluteFilePath(); + } + + return QString(); +} + QList getQtFrameworks(const QList &dependencies, const QString &appBundlePath, const QSet &rpaths, bool useDebugLibs) { QList libraries; @@ -530,12 +555,11 @@ QSet getBinaryRPaths(const QString &path, bool resolve = true, QString QString output = otool.readAllStandardOutput(); QStringList outputLines = output.split("\n"); - QStringListIterator i(outputLines); - while (i.hasNext()) { - if (i.next().contains("cmd LC_RPATH") && i.hasNext() && - i.next().contains("cmdsize") && i.hasNext()) { - const QString &rpathCmd = i.next(); + for (auto i = outputLines.cbegin(), end = outputLines.cend(); i != end; ++i) { + if (i->contains("cmd LC_RPATH") && ++i != end && + i->contains("cmdsize") && ++i != end) { + const QString &rpathCmd = *i; int pathStart = rpathCmd.indexOf("path "); int pathEnd = rpathCmd.indexOf(" ("); if (pathStart >= 0 && pathEnd >= 0 && pathStart < pathEnd) { @@ -955,7 +979,7 @@ DeploymentInfo deployQtFrameworks(QList frameworks, deploymentInfo.isDebug = true; if (deploymentInfo.qtPath.isNull()) - deploymentInfo.qtPath = QLibraryInfo::location(QLibraryInfo::PrefixPath); + deploymentInfo.qtPath = QLibraryInfo::path(QLibraryInfo::PrefixPath); if (framework.frameworkDirectory.startsWith(bundlePath)) { LogError() << framework.frameworkName << "already deployed, skipping."; @@ -1014,7 +1038,7 @@ DeploymentInfo deployQtFrameworks(const QString &appBundlePath, const QStringLis QStringList allBinaryPaths = QStringList() << applicationBundle.binaryPath << applicationBundle.libraryPaths << additionalExecutables; QSet allLibraryPaths = getBinaryRPaths(applicationBundle.binaryPath, true); - allLibraryPaths.insert(QLibraryInfo::location(QLibraryInfo::LibrariesPath)); + allLibraryPaths.insert(QLibraryInfo::path(QLibraryInfo::LibrariesPath)); QList frameworks = getQtFrameworksForPaths(allBinaryPaths, appBundlePath, allLibraryPaths, useDebugLibs); if (frameworks.isEmpty() && !alwaysOwerwriteEnabled) { LogWarning(); @@ -1137,7 +1161,7 @@ void deployPlugins(const ApplicationBundleInfo &appBundleInfo, const QString &pl static const std::map> map { {QStringLiteral("Multimedia"), {QStringLiteral("mediaservice"), QStringLiteral("audio")}}, - {QStringLiteral("3DRender"), {QStringLiteral("sceneparsers"), QStringLiteral("geometryloaders")}}, + {QStringLiteral("3DRender"), {QStringLiteral("sceneparsers"), QStringLiteral("geometryloaders"), QStringLiteral("renderers")}}, {QStringLiteral("3DQuickRender"), {QStringLiteral("renderplugins")}}, {QStringLiteral("Positioning"), {QStringLiteral("position")}}, {QStringLiteral("Location"), {QStringLiteral("geoservices")}}, @@ -1237,7 +1261,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf LogNormal() << "QML module search path(s) is" << qmlImportPaths; // Use qmlimportscanner from QLibraryInfo::BinariesPath - QString qmlImportScannerPath = QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlimportscanner"); + QString qmlImportScannerPath = QDir::cleanPath(QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qmlimportscanner"); // Fallback: Look relative to the macdeployqt binary if (!QFile(qmlImportScannerPath).exists()) @@ -1259,7 +1283,7 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf } for (const QString &importPath : qmlImportPaths) argumentList << "-importPath" << importPath; - QString qmlImportsPath = QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath); + QString qmlImportsPath = QLibraryInfo::path(QLibraryInfo::Qml2ImportsPath); argumentList.append( "-importPath"); argumentList.append(qmlImportsPath); @@ -1335,48 +1359,31 @@ bool deployQmlImports(const QString &appBundlePath, DeploymentInfo deploymentInf return true; } -void changeQtFrameworks(const QList frameworks, const QStringList &binaryPaths, const QString &absoluteQtPath) -{ - LogNormal() << "Changing" << binaryPaths << "to link against"; - LogNormal() << "Qt in" << absoluteQtPath; - QString finalQtPath = absoluteQtPath; - - if (!absoluteQtPath.startsWith("/Library/Frameworks")) - finalQtPath += "/lib/"; - - foreach (FrameworkInfo framework, frameworks) { - const QString oldBinaryId = framework.installName; - const QString newBinaryId = finalQtPath + framework.frameworkName + framework.binaryPath; - foreach (const QString &binary, binaryPaths) - changeInstallName(oldBinaryId, newBinaryId, binary); - } -} - -void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs) -{ - const QString appBinaryPath = findAppBinary(appPath); - const QStringList libraryPaths = findAppLibraries(appPath); - const QList frameworks = getQtFrameworksForPaths(QStringList() << appBinaryPath << libraryPaths, appPath, getBinaryRPaths(appBinaryPath, true), useDebugLibs); - if (frameworks.isEmpty()) { - LogWarning(); - LogWarning() << "Could not find any _external_ Qt frameworks to change in" << appPath; - return; - } else { - const QString absoluteQtPath = QDir(qtPath).absolutePath(); - changeQtFrameworks(frameworks, QStringList() << appBinaryPath << libraryPaths, absoluteQtPath); - } -} - void codesignFile(const QString &identity, const QString &filePath) { if (!runCodesign) return; - LogNormal() << "codesign" << filePath; + QString codeSignLogMessage = "codesign"; + if (hardenedRuntime) + codeSignLogMessage += ", enable hardened runtime"; + if (secureTimestamp) + codeSignLogMessage += ", include secure timestamp"; + LogNormal() << codeSignLogMessage << filePath; + + QStringList codeSignOptions = { "--preserve-metadata=identifier,entitlements", "--force", "-s", + identity, filePath }; + if (hardenedRuntime) + codeSignOptions << "-o" << "runtime"; + + if (secureTimestamp) + codeSignOptions << "--timestamp"; + + if (!extraEntitlements.isEmpty()) + codeSignOptions << "--entitlements" << extraEntitlements; QProcess codesign; - codesign.start("codesign", QStringList() << "--preserve-metadata=identifier,entitlements" - << "--force" << "-s" << identity << filePath); + codesign.start("codesign", codeSignOptions); codesign.waitForFinished(-1); QByteArray err = codesign.readAllStandardError(); @@ -1463,11 +1470,12 @@ QSet codesignBundle(const QString &identity, continue; // Check if there are unsigned dependencies, sign these first. - QStringList dependencies = - getBinaryDependencies(rootBinariesPath, binary, additionalBinariesContainingRpaths).toSet() - .subtract(signedBinaries) - .subtract(pendingBinariesSet) - .toList(); + QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary, + additionalBinariesContainingRpaths); + dependencies = QSet(dependencies.begin(), dependencies.end()) + .subtract(signedBinaries) + .subtract(pendingBinariesSet) + .values(); if (!dependencies.isEmpty()) { pendingBinaries.push(binary); @@ -1496,6 +1504,9 @@ QSet codesignBundle(const QString &identity, } } + // Look for an entitlements file in the bundle to include when signing + extraEntitlements = findEntitlementsFile(appBundleAbsolutePath + "/Contents/Resources/"); + // All dependencies are signed, now sign this binary. codesignFile(identity, binary); signedBinaries.insert(binary); diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h index ab28360d51..15ff084305 100644 --- a/src/macdeployqt/shared/shared.h +++ b/src/macdeployqt/shared/shared.h @@ -111,9 +111,6 @@ class DeploymentInfo inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info); -void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs); -void changeQtFrameworks(const QList frameworks, const QStringList &binaryPaths, const QString &qtPath); - OtoolInfo findDependencyInfo(const QString &binaryPath); FrameworkInfo parseOtoolLibraryLine(const QString &line, const QString &appBundlePath, const QSet &rpaths, bool useDebugLibs); QString findAppBinary(const QString &appBundlePath); diff --git a/src/makeqpf/Blocks.txt b/src/makeqpf/Blocks.txt deleted file mode 100644 index ad8474bd55..0000000000 --- a/src/makeqpf/Blocks.txt +++ /dev/null @@ -1,185 +0,0 @@ -# Blocks-5.0.0.txt -# Date: 2006-02-15, 15:40:00 [KW] -# -# Unicode Character Database -# Copyright (c) 1991-2006 Unicode, Inc. -# For terms of use, see http://www.unicode.org/terms_of_use.html -# For documentation, see UCD.html -# -# Note: The casing of block names is not normative. -# For example, "Basic Latin" and "BASIC LATIN" are equivalent. -# -# Format: -# Start Code..End Code; Block Name - -# ================================================ - -# Note: When comparing block names, casing, whitespace, hyphens, -# and underbars are ignored. -# For example, "Latin Extended-A" and "latin extended a" are equivalent. -# For more information on the comparison of property values, -# see UCD.html. -# -# All code points not explicitly listed for Block -# have the value No_Block. - -# Property: Block -# -# @missing: 0000..10FFFF; No_Block - -0000..007F; Basic Latin -0080..00FF; Latin-1 Supplement -0100..017F; Latin Extended-A -0180..024F; Latin Extended-B -0250..02AF; IPA Extensions -02B0..02FF; Spacing Modifier Letters -0300..036F; Combining Diacritical Marks -0370..03FF; Greek and Coptic -0400..04FF; Cyrillic -0500..052F; Cyrillic Supplement -0530..058F; Armenian -0590..05FF; Hebrew -0600..06FF; Arabic -0700..074F; Syriac -0750..077F; Arabic Supplement -0780..07BF; Thaana -07C0..07FF; NKo -0900..097F; Devanagari -0980..09FF; Bengali -0A00..0A7F; Gurmukhi -0A80..0AFF; Gujarati -0B00..0B7F; Oriya -0B80..0BFF; Tamil -0C00..0C7F; Telugu -0C80..0CFF; Kannada -0D00..0D7F; Malayalam -0D80..0DFF; Sinhala -0E00..0E7F; Thai -0E80..0EFF; Lao -0F00..0FFF; Tibetan -1000..109F; Myanmar -10A0..10FF; Georgian -1100..11FF; Hangul Jamo -1200..137F; Ethiopic -1380..139F; Ethiopic Supplement -13A0..13FF; Cherokee -1400..167F; Unified Canadian Aboriginal Syllabics -1680..169F; Ogham -16A0..16FF; Runic -1700..171F; Tagalog -1720..173F; Hanunoo -1740..175F; Buhid -1760..177F; Tagbanwa -1780..17FF; Khmer -1800..18AF; Mongolian -1900..194F; Limbu -1950..197F; Tai Le -1980..19DF; New Tai Lue -19E0..19FF; Khmer Symbols -1A00..1A1F; Buginese -1B00..1B7F; Balinese -1D00..1D7F; Phonetic Extensions -1D80..1DBF; Phonetic Extensions Supplement -1DC0..1DFF; Combining Diacritical Marks Supplement -1E00..1EFF; Latin Extended Additional -1F00..1FFF; Greek Extended -2000..206F; General Punctuation -2070..209F; Superscripts and Subscripts -20A0..20CF; Currency Symbols -20D0..20FF; Combining Diacritical Marks for Symbols -2100..214F; Letterlike Symbols -2150..218F; Number Forms -2190..21FF; Arrows -2200..22FF; Mathematical Operators -2300..23FF; Miscellaneous Technical -2400..243F; Control Pictures -2440..245F; Optical Character Recognition -2460..24FF; Enclosed Alphanumerics -2500..257F; Box Drawing -2580..259F; Block Elements -25A0..25FF; Geometric Shapes -2600..26FF; Miscellaneous Symbols -2700..27BF; Dingbats -27C0..27EF; Miscellaneous Mathematical Symbols-A -27F0..27FF; Supplemental Arrows-A -2800..28FF; Braille Patterns -2900..297F; Supplemental Arrows-B -2980..29FF; Miscellaneous Mathematical Symbols-B -2A00..2AFF; Supplemental Mathematical Operators -2B00..2BFF; Miscellaneous Symbols and Arrows -2C00..2C5F; Glagolitic -2C60..2C7F; Latin Extended-C -2C80..2CFF; Coptic -2D00..2D2F; Georgian Supplement -2D30..2D7F; Tifinagh -2D80..2DDF; Ethiopic Extended -2E00..2E7F; Supplemental Punctuation -2E80..2EFF; CJK Radicals Supplement -2F00..2FDF; Kangxi Radicals -2FF0..2FFF; Ideographic Description Characters -3000..303F; CJK Symbols and Punctuation -3040..309F; Hiragana -30A0..30FF; Katakana -3100..312F; Bopomofo -3130..318F; Hangul Compatibility Jamo -3190..319F; Kanbun -31A0..31BF; Bopomofo Extended -31C0..31EF; CJK Strokes -31F0..31FF; Katakana Phonetic Extensions -3200..32FF; Enclosed CJK Letters and Months -3300..33FF; CJK Compatibility -3400..4DBF; CJK Unified Ideographs Extension A -4DC0..4DFF; Yijing Hexagram Symbols -4E00..9FFF; CJK Unified Ideographs -A000..A48F; Yi Syllables -A490..A4CF; Yi Radicals -A700..A71F; Modifier Tone Letters -A720..A7FF; Latin Extended-D -A800..A82F; Syloti Nagri -A840..A87F; Phags-pa -AC00..D7AF; Hangul Syllables -D800..DB7F; High Surrogates -DB80..DBFF; High Private Use Surrogates -DC00..DFFF; Low Surrogates -E000..F8FF; Private Use Area -F900..FAFF; CJK Compatibility Ideographs -FB00..FB4F; Alphabetic Presentation Forms -FB50..FDFF; Arabic Presentation Forms-A -FE00..FE0F; Variation Selectors -FE10..FE1F; Vertical Forms -FE20..FE2F; Combining Half Marks -FE30..FE4F; CJK Compatibility Forms -FE50..FE6F; Small Form Variants -FE70..FEFF; Arabic Presentation Forms-B -FF00..FFEF; Halfwidth and Fullwidth Forms -FFF0..FFFF; Specials -10000..1007F; Linear B Syllabary -10080..100FF; Linear B Ideograms -10100..1013F; Aegean Numbers -10140..1018F; Ancient Greek Numbers -10300..1032F; Old Italic -10330..1034F; Gothic -10380..1039F; Ugaritic -103A0..103DF; Old Persian -10400..1044F; Deseret -10450..1047F; Shavian -10480..104AF; Osmanya -10800..1083F; Cypriot Syllabary -10900..1091F; Phoenician -10A00..10A5F; Kharoshthi -12000..123FF; Cuneiform -12400..1247F; Cuneiform Numbers and Punctuation -1D000..1D0FF; Byzantine Musical Symbols -1D100..1D1FF; Musical Symbols -1D200..1D24F; Ancient Greek Musical Notation -1D300..1D35F; Tai Xuan Jing Symbols -1D360..1D37F; Counting Rod Numerals -1D400..1D7FF; Mathematical Alphanumeric Symbols -20000..2A6DF; CJK Unified Ideographs Extension B -2F800..2FA1F; CJK Compatibility Ideographs Supplement -E0000..E007F; Tags -E0100..E01EF; Variation Selectors Supplement -F0000..FFFFF; Supplementary Private Use Area-A -100000..10FFFF; Supplementary Private Use Area-B - -# EOF \ No newline at end of file diff --git a/src/makeqpf/README b/src/makeqpf/README deleted file mode 100644 index d536f50f28..0000000000 --- a/src/makeqpf/README +++ /dev/null @@ -1,2 +0,0 @@ -This tool is used to create pre-rendered fonts for QFontEngineQPF, used on -some embedded devices. diff --git a/src/makeqpf/main.cpp b/src/makeqpf/main.cpp deleted file mode 100644 index 3c6e9ef6a4..0000000000 --- a/src/makeqpf/main.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include - -#include "qpf2.h" -#include "mainwindow.h" - -#include - -QT_BEGIN_NAMESPACE - -static void help() -{ - printf("usage:\n"); - printf("makeqpf fontname pixelsize [italic] [bold] [--exclude-cmap] [-v]\n"); - printf("makeqpf -dump [-v] file.qpf2\n"); - exit(0); -} - -static int gui(const QString &customFont = QString()) -{ - MainWindow mw(customFont); - mw.show(); - return qApp->exec(); -} - -QT_END_NAMESPACE - -int main(int argc, char **argv) -{ - QT_USE_NAMESPACE - - QApplication app(argc, argv); - app.setOrganizationName(QLatin1String("QtProject")); - app.setApplicationName(QLatin1String("MakeQPF")); - - const QStringList arguments = app.arguments(); - - if (arguments.count() <= 1) { - return gui(); - } else if (arguments.count() == 2 - && QFile::exists(arguments.at(1))) { - return gui(arguments.at(1)); - } - - const QString &firstArg = arguments.at(1); - if (firstArg == QLatin1String("-h") || firstArg == QLatin1String("--help")) - help(); - if (firstArg == QLatin1String("-dump")) { - QString file; - for (int i = 2; i < arguments.count(); ++i) { - if (arguments.at(i).startsWith(QLatin1String("-v"))) - QPF::debugVerbosity += arguments.at(i).length() - 1; - else if (file.isEmpty()) - file = arguments.at(i); - else - help(); - } - - if (file.isEmpty()) - help(); - - QFile f(file); - if (!f.open(QIODevice::ReadOnly)) { - printf("cannot open %s\n", qPrintable(file)); - exit(1); - } - - QByteArray qpf = f.readAll(); - f.close(); - - QPF::dump(qpf); - return 0; - } - - if (arguments.count() < 3) help(); - - QFont font; - - QString fontName = firstArg; - if (QFile::exists(fontName)) { - int id = QFontDatabase::addApplicationFont(fontName); - if (id == -1) { - printf("cannot open font %s", qPrintable(fontName)); - help(); - } - QStringList families = QFontDatabase::applicationFontFamilies(id); - if (families.isEmpty()) { - printf("cannot find any font families in %s", qPrintable(fontName)); - help(); - } - fontName = families.first(); - } - font.setFamily(fontName); - - bool ok = false; - int pixelSize = arguments.at(2).toInt(&ok); - if (!ok) help(); - font.setPixelSize(pixelSize); - - int generationOptions = QPF::IncludeCMap | QPF::RenderGlyphs; - - for (int i = 3; i < arguments.count(); ++i) { - const QString &arg = arguments.at(i); - if (arg == QLatin1String("italic")) { - font.setItalic(true); - } else if (arg == QLatin1String("bold")) { - font.setBold(true); - } else if (arg == QLatin1String("--exclude-cmap")) { - generationOptions &= ~QPF::IncludeCMap; - } else if (arg == QLatin1String("--exclude-glyphs")) { - generationOptions &= ~QPF::RenderGlyphs; - } else if (arg == QLatin1String("-v")) { - ++QPF::debugVerbosity; - } else { - printf("unknown option %s\n", qPrintable(arg)); - help(); - } - } - - font.setStyleStrategy(QFont::NoFontMerging); - - QList ranges; - ranges.append(QPF::CharacterRange()); // default range from 0 to 0xffff - - QString origFont; - QByteArray qpf = QPF::generate(font, generationOptions, ranges, &origFont); - - QString fileName = QPF::fileNameForFont(font); - QFile f(fileName); - f.open(QIODevice::WriteOnly | QIODevice::Truncate); - f.write(qpf); - f.close(); - - if (generationOptions & QPF::IncludeCMap) { - printf("Created %s from %s\n", qPrintable(fileName), qPrintable(origFont)); - } else { - printf("Created %s from %s excluding the character-map\n", qPrintable(fileName), qPrintable(origFont)); - printf("The TrueType font file is therefore required for the font to work\n"); - } - - return 0; -} - diff --git a/src/makeqpf/mainwindow.cpp b/src/makeqpf/mainwindow.cpp deleted file mode 100644 index 215df6d47d..0000000000 --- a/src/makeqpf/mainwindow.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "mainwindow.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -MainWindow::MainWindow(const QString &customFont) -{ - setupUi(this); - pixelSize->setValue(QFontInfo(QFont()).pixelSize()); - populateCharacterRanges(); - - { - weightCombo->addItem(QLatin1String("Light"), QVariant(int(QFont::Light))); - const int normalIdx = weightCombo->count(); - weightCombo->addItem(QLatin1String("Normal"), QVariant(int(QFont::Normal))); - weightCombo->addItem(QLatin1String("DemiBold"), QVariant(int(QFont::DemiBold))); - weightCombo->addItem(QLatin1String("Bold"), QVariant(int(QFont::Bold))); - weightCombo->addItem(QLatin1String("Black"), QVariant(int(QFont::Black))); - - weightCombo->setCurrentIndex(normalIdx); - } - - QShortcut *sc = new QShortcut(Qt::ControlModifier + Qt::Key_A, this); - connect(sc, SIGNAL(activated()), - this, SLOT(on_selectAll_clicked())); - sc = new QShortcut(Qt::ControlModifier + Qt::Key_D, this); - connect(sc, SIGNAL(activated()), - this, SLOT(on_deselectAll_clicked())); - sc = new QShortcut(Qt::ControlModifier + Qt::Key_I, this); - connect(sc, SIGNAL(activated()), - this, SLOT(on_invertSelection_clicked())); - - QCompleter *completer = new QCompleter(this); - completer->setModel(new QDirModel(this)); - path->setCompleter(completer); - path->setText(QDir::currentPath()); - - completer = new QCompleter(this); - completer->setModel(new QDirModel(this)); - sampleFile->setCompleter(completer); - charCount->setText(QString()); - - if (!customFont.isEmpty()) - addCustomFont(customFont); - - fontChanged(); - - connect(fontComboBox, SIGNAL(currentFontChanged(QFont)), - this, SLOT(fontChanged())); - connect(pixelSize, SIGNAL(valueChanged(int)), - this, SLOT(fontChanged())); - connect(italic, SIGNAL(stateChanged(int)), - this, SLOT(fontChanged())); - connect(weightCombo, SIGNAL(currentIndexChanged(int)), - this, SLOT(fontChanged())); -} - -void MainWindow::on_actionAdd_Custom_Font_triggered() -{ - QString fontFile = QFileDialog::getOpenFileName(this, tr("Add Custom Font")); - if (fontFile.isEmpty()) - return; - addCustomFont(fontFile); -} - -void MainWindow::on_selectAll_clicked() -{ - for (int i = 0; i < characterRangeView->count(); ++i) - characterRangeView->item(i)->setCheckState(Qt::Checked); -} - -void MainWindow::on_deselectAll_clicked() -{ - for (int i = 0; i < characterRangeView->count(); ++i) - characterRangeView->item(i)->setCheckState(Qt::Unchecked); -} - -void MainWindow::on_invertSelection_clicked() -{ - for (int i = 0; i < characterRangeView->count(); ++i) { - QListWidgetItem *item = characterRangeView->item(i); - if (item->checkState() == Qt::Checked) - item->setCheckState(Qt::Unchecked); - else - item->setCheckState(Qt::Checked); - } -} - -void MainWindow::fontChanged() -{ - QFont f = preview->font(); - f.setStyleStrategy(QFont::NoFontMerging); - f.setPixelSize(pixelSize->value()); - f.setFamily(fontComboBox->currentFont().family()); - f.setItalic(italic->isChecked()); - f.setWeight(weightCombo->itemData(weightCombo->currentIndex()).toInt()); - - if (!preview->isModified()) { - QFontDatabase db; - QFontDatabase::WritingSystem ws = db.writingSystems(f.family()).value(0, QFontDatabase::Any); - QString sample = db.writingSystemSample(ws); - preview->setText(sample); - preview->setModified(false); - } - - fileName->setText(QPF::fileNameForFont(f)); - - preview->setFont(f); -} - -void MainWindow::on_browsePath_clicked() -{ - QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory")); - if (!dir.isEmpty()) - path->setText(dir); -} - -void MainWindow::on_browseSampleFile_clicked() -{ - QString dir = QFileDialog::getOpenFileName(this, tr("Select Sample File")); - if (!dir.isEmpty()) { - sampleFile->setText(dir); - on_sampleFile_editingFinished(); - } -} - -void MainWindow::on_generate_clicked() -{ - QFile f(path->text() + QDir::separator() + fileName->text()); - if (f.exists()) { - if (QMessageBox::warning(this, QString(), - tr("%1 already exists.\nDo you want to replace it?").arg(f.fileName()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No) - != QMessageBox::Yes) { - statusBar()->showMessage(tr("Pre-rendering aborted...")); - return; - } - } - - QList ranges; - - if (chooseFromSampleFile->isChecked()) { - ranges = sampleFileRanges; - } else if (chooseFromCodePoints->isChecked()) { - ranges.clear(); - for (int i = 0; i < characterRangeView->count(); ++i) { - QListWidgetItem *item = characterRangeView->item(i); - if (item->checkState() != Qt::Checked) - continue; - - QPF::CharacterRange range = qvariant_cast(item->data(Qt::UserRole)); - ranges.append(range); - } - } - - const int generationOptions = QPF::IncludeCMap | QPF::RenderGlyphs; - QByteArray qpf = QPF::generate(preview->font(), generationOptions, ranges); - f.open(QIODevice::WriteOnly | QIODevice::Truncate); - f.write(qpf); - f.close(); - - statusBar()->showMessage(tr("Font successfully pre-rendered to %1").arg(fileName->text())); -} - -void MainWindow::on_sampleFile_editingFinished() -{ - sampleFileRanges.clear(); - QFile f(sampleFile->text()); - if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) { - sampleFileRanges.append(QPF::CharacterRange()); // default = all - return; - } - QTextStream stream(&f); - stream.setCodec(QTextCodec::codecForName("utf-8")); - stream.setAutoDetectUnicode(true); - QString text = stream.readAll(); - - QSet coverage; - for (int i = 0; i < text.length(); ++i) - coverage.insert(text.at(i)); - - QList sortedCoverage = QList::fromSet(coverage); - std::sort(sortedCoverage.begin(), sortedCoverage.end()); - // play simple :) - for (QChar ch : qAsConst(sortedCoverage)) { - QPF::CharacterRange r; - r.start = ch.unicode(); - r.end = r.start + 1; - sampleFileRanges.append(r); - } - - charCount->setText(tr("(%1 unique characters found)").arg(sortedCoverage.count())); -} - -void MainWindow::populateCharacterRanges() -{ - QFile f(":/Blocks.txt"); - if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) - return; - - QRegularExpression rangeExpr( - QRegularExpression::anchoredPattern("([0-9a-f]+)\\.\\.([0-9a-f]+); (.+)"), - QRegularExpression::CaseInsensitiveOption - ); - - QString ellipsis(QChar(0x2026)); - if (!characterRangeView->fontMetrics().inFont(ellipsis.at(0))) - ellipsis = QLatin1String("..."); - - while (!f.atEnd()) { - QString line = QString::fromLatin1(f.readLine()); - - if (line.endsWith(QLatin1Char('\n'))) - line.chop(1); - if (line.endsWith(QLatin1Char('\r'))) - line.chop(1); - - line = line.trimmed(); - - if (line.isEmpty() || line.startsWith(QLatin1Char('#'))) - continue; - - QRegularExpressionMatch match = rangeExpr.match(line); - if (!match.hasMatch()) - continue; - - QPF::CharacterRange range; - - bool ok = false; - range.start = match.captured(1).toUInt(&ok, /*base*/16); - if (!ok) - continue; - range.end = match.captured(2).toUInt(&ok, /*base*/16); - if (!ok) - continue; - - if (range.start >= 0xffff || range.end >= 0xffff) - continue; - - QString description = match.captured(3); - - QListWidgetItem *item = new QListWidgetItem(characterRangeView); - QString text = description; - text.append(QLatin1String(" (")); - text.append(match.captured(1)); - text.append(ellipsis); - text.append(match.captured(2)); - text.append(QLatin1String(")")); - item->setText(text); - item->setCheckState(Qt::Checked); - - item->setData(Qt::UserRole, QVariant::fromValue(range)); - } -} - -void MainWindow::addCustomFont(const QString &fontFile) -{ - int id = QFontDatabase::addApplicationFont(fontFile); - if (id < 0) { - QMessageBox::warning(this, tr("Error Adding Custom Font"), - tr("The custom font %s could not be loaded.").arg(fontFile)); - return; - } - const QStringList families = QFontDatabase::applicationFontFamilies(id); - if (families.isEmpty()) { - QMessageBox::warning(this, tr("Error Adding Custom Font"), - tr("The custom font %s provides no font families.").arg(fontFile)); - return; - } - QFont f(families.first()); - fontComboBox->setCurrentFont(f); -} - -QT_END_NAMESPACE diff --git a/src/makeqpf/mainwindow.ui b/src/makeqpf/mainwindow.ui deleted file mode 100644 index f6eda4fdd6..0000000000 --- a/src/makeqpf/mainwindow.ui +++ /dev/null @@ -1,502 +0,0 @@ - - MainWindow - - - - 0 - 0 - 829 - 813 - - - - MakeQPF - - - - - 9 - - - 6 - - - - - Font Properties - - - - 9 - - - 6 - - - - - Family: - - - - - - - - - - Pixel Size: - - - - - - - 1 - - - - - - - Weight: - - - - - - - - - - Italic - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Glyph Coverage - - - - 9 - - - 6 - - - - - Choose from Unicode Codepoints: - - - true - - - - - - - 0 - - - 6 - - - - - - - - 0 - - - 6 - - - - - Select &All - - - - - - - &Deselect All - - - - - - - &Invert Selection - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Choose from Sample Text File (UTF-8 Encoded): - - - - - - - 0 - - - 6 - - - - - false - - - Path: - - - - - - - false - - - - - - - false - - - Browse... - - - - - - - false - - - TextLabel - - - - - - - - - - - - Preview - - - - 9 - - - 6 - - - - - - - - - - - Output Options - - - - 9 - - - 6 - - - - - Path: - - - - - - - - - - Browse... - - - - - - - Filename: - - - - - - - false - - - - - - - - - - 0 - - - 6 - - - - - Generate Pre-Rendered Font... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - 0 - 829 - 29 - - - - - File - - - - - - - - - - - &Add Custom Font... - - - - - &Exit - - - - - - - action_Exit - triggered() - MainWindow - close() - - - -1 - -1 - - - 383 - 215 - - - - - chooseFromCodePoints - toggled(bool) - characterRangeView - setEnabled(bool) - - - 183 - 144 - - - 146 - 295 - - - - - chooseFromCodePoints - toggled(bool) - selectAll - setEnabled(bool) - - - 236 - 146 - - - 46 - 508 - - - - - chooseFromCodePoints - toggled(bool) - deselectAll - setEnabled(bool) - - - 280 - 147 - - - 158 - 502 - - - - - chooseFromCodePoints - toggled(bool) - invertSelection - setEnabled(bool) - - - 364 - 143 - - - 281 - 509 - - - - - chooseFromSampleFile - toggled(bool) - sampleFile - setEnabled(bool) - - - 134 - 544 - - - 64 - 569 - - - - - chooseFromSampleFile - toggled(bool) - browseSampleFile - setEnabled(bool) - - - 79 - 545 - - - 710 - 582 - - - - - chooseFromSampleFile - toggled(bool) - charCount - setEnabled(bool) - - - 274 - 544 - - - 790 - 569 - - - - - chooseFromSampleFile - toggled(bool) - label_5 - setEnabled(bool) - - - 112 - 541 - - - 37 - 579 - - - - - diff --git a/src/makeqpf/makeqpf.pro b/src/makeqpf/makeqpf.pro deleted file mode 100644 index 5a8abc882f..0000000000 --- a/src/makeqpf/makeqpf.pro +++ /dev/null @@ -1,11 +0,0 @@ -QT += widgets gui-private core-private -CONFIG += console -DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 - -HEADERS += qpf2.h mainwindow.h -SOURCES += main.cpp qpf2.cpp mainwindow.cpp -DEFINES += QT_NO_FREETYPE -FORMS += mainwindow.ui -RESOURCES += makeqpf.qrc - -load(qt_app) diff --git a/src/makeqpf/makeqpf.qrc b/src/makeqpf/makeqpf.qrc deleted file mode 100644 index b1d73b0107..0000000000 --- a/src/makeqpf/makeqpf.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - Blocks.txt - - diff --git a/src/makeqpf/qpf2.cpp b/src/makeqpf/qpf2.cpp deleted file mode 100644 index c56ec391af..0000000000 --- a/src/makeqpf/qpf2.cpp +++ /dev/null @@ -1,780 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpf2.h" - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -int QPF::debugVerbosity = 0; - -// ### copied from qfontdatabase.cpp - -// see the Unicode subset bitfields in the MSDN docs -static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { - // Any, - { 127, 127 }, - // Latin, - { 0, 127 }, - // Greek, - { 7, 127 }, - // Cyrillic, - { 9, 127 }, - // Armenian, - { 10, 127 }, - // Hebrew, - { 11, 127 }, - // Arabic, - { 13, 127 }, - // Syriac, - { 71, 127 }, - //Thaana, - { 72, 127 }, - //Devanagari, - { 15, 127 }, - //Bengali, - { 16, 127 }, - //Gurmukhi, - { 17, 127 }, - //Gujarati, - { 18, 127 }, - //Oriya, - { 19, 127 }, - //Tamil, - { 20, 127 }, - //Telugu, - { 21, 127 }, - //Kannada, - { 22, 127 }, - //Malayalam, - { 23, 127 }, - //Sinhala, - { 73, 127 }, - //Thai, - { 24, 127 }, - //Lao, - { 25, 127 }, - //Tibetan, - { 70, 127 }, - //Myanmar, - { 74, 127 }, - // Georgian, - { 26, 127 }, - // Khmer, - { 80, 127 }, - // SimplifiedChinese, - { 126, 127 }, - // TraditionalChinese, - { 126, 127 }, - // Japanese, - { 126, 127 }, - // Korean, - { 56, 127 }, - // Vietnamese, - { 0, 127 }, // same as latin1 - // Other, - { 126, 127 } -}; - -#define SimplifiedChineseCsbBit 18 -#define TraditionalChineseCsbBit 20 -#define JapaneseCsbBit 17 -#define KoreanCsbBit 21 - -static const QFontEngineQPF2::TagType tagTypes[QFontEngineQPF2::NumTags] = { - QFontEngineQPF2::StringType, // FontName - QFontEngineQPF2::StringType, // FileName - QFontEngineQPF2::UInt32Type, // FileIndex - QFontEngineQPF2::UInt32Type, // FontRevision - QFontEngineQPF2::StringType, // FreeText - QFontEngineQPF2::FixedType, // Ascent - QFontEngineQPF2::FixedType, // Descent - QFontEngineQPF2::FixedType, // Leading - QFontEngineQPF2::FixedType, // XHeight - QFontEngineQPF2::FixedType, // AverageCharWidth - QFontEngineQPF2::FixedType, // MaxCharWidth - QFontEngineQPF2::FixedType, // LineThickness - QFontEngineQPF2::FixedType, // MinLeftBearing - QFontEngineQPF2::FixedType, // MinRightBearing - QFontEngineQPF2::FixedType, // UnderlinePosition - QFontEngineQPF2::UInt8Type, // GlyphFormat - QFontEngineQPF2::UInt8Type, // PixelSize - QFontEngineQPF2::UInt8Type, // Weight - QFontEngineQPF2::UInt8Type, // Style - QFontEngineQPF2::StringType, // EndOfHeader - QFontEngineQPF2::BitFieldType// WritingSystems -}; - -static QList determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) -{ - QList writingSystems; - bool hasScript = false; - - int i; - for(i = 0; i < QFontDatabase::WritingSystemsCount; i++) { - int bit = requiredUnicodeBits[i][0]; - int index = bit/32; - int flag = 1 << (bit&31); - if (bit != 126 && unicodeRange[index] & flag) { - bit = requiredUnicodeBits[i][1]; - index = bit/32; - - flag = 1 << (bit&31); - if (bit == 127 || unicodeRange[index] & flag) { - writingSystems.append(QFontDatabase::WritingSystem(i)); - hasScript = true; - // qDebug("font %s: index=%d, flag=%8x supports script %d", familyName.latin1(), index, flag, i); - } - } - } - if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) { - writingSystems.append(QFontDatabase::SimplifiedChinese); - hasScript = true; - //qDebug("font %s supports Simplified Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) { - writingSystems.append(QFontDatabase::TraditionalChinese); - hasScript = true; - //qDebug("font %s supports Traditional Chinese", familyName.latin1()); - } - if(codePageRange[0] & (1 << JapaneseCsbBit)) { - writingSystems.append(QFontDatabase::Japanese); - hasScript = true; - //qDebug("font %s supports Japanese", familyName.latin1()); - } - if(codePageRange[0] & (1 << KoreanCsbBit)) { - writingSystems.append(QFontDatabase::Korean); - hasScript = true; - //qDebug("font %s supports Korean", familyName.latin1()); - } - if (!hasScript) - writingSystems.append(QFontDatabase::Symbol); - - return writingSystems; -} - -static QByteArray getWritingSystems(QFontEngine *fontEngine) -{ - QByteArray os2Table = fontEngine->getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (os2Table.isEmpty()) - return QByteArray(); - - const uchar *data = reinterpret_cast(os2Table.constData()); - - quint32 unicodeRange[4] = { - qFromBigEndian(data + 42), - qFromBigEndian(data + 46), - qFromBigEndian(data + 50), - qFromBigEndian(data + 54) - }; - quint32 codePageRange[2] = { qFromBigEndian(data + 78), qFromBigEndian(data + 82) }; - QList systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - - QByteArray bitField((QFontDatabase::WritingSystemsCount + 7) / 8, 0); - - for (int i = 0; i < systems.count(); ++i) { - int bitPos = systems.at(i); - bitField[bitPos / 8] = bitField.at(bitPos / 8) | (1 << (bitPos % 8)); - } - - return bitField; -} - -static QString stringify(const QByteArray &bits) -{ - QString result; - for (int i = 0; i < bits.count(); ++i) { - uchar currentByte = bits.at(i); - for (int j = 0; j < 8; ++j) { - if (currentByte & 1) - result += '1'; - else - result += '0'; - currentByte >>= 1; - } - } - return result; -} - -static void dumpWritingSystems(const QByteArray &bits) -{ - QStringList writingSystems; - - QString bitString = stringify(bits); - for (int i = 0; i < qMin(int(QFontDatabase::WritingSystemsCount), bitString.length()); ++i) { - if (bitString.at(i) == QLatin1Char('1')) - writingSystems << QFontDatabase::writingSystemName(QFontDatabase::WritingSystem(i)); - } - - qDebug() << "Supported writing systems:" << writingSystems; -} - -static const char *headerTagNames[QFontEngineQPF2::NumTags] = { - "FontName", - "FileName", - "FileIndex", - "FontRevision", - "FreeText", - "Ascent", - "Descent", - "Leading", - "XHeight", - "AverageCharWidth", - "MaxCharWidth", - "LineThickness", - "MinLeftBearing", - "MinRightBearing", - "UnderlinePosition", - "GlyphFormat", - "PixelSize", - "Weight", - "Style", - "EndOfHeader", - "WritingSystems" -}; - -QString QPF::fileNameForFont(const QFont &f) -{ - QString fileName = f.family().toLower() + "_" + QString::number(f.pixelSize()) - + "_" + QString::number(f.weight()) - + (f.italic() ? "_italic" : "") - + ".qpf2"; - fileName.replace(QLatin1Char(' '), QLatin1Char('_')); - return fileName; -} - -QByteArray QPF::generate(const QFont &font, int options, const QList &ranges, QString *originalFontFile) -{ - QTextEngine engine("Test", font); - engine.itemize(); - engine.shape(0); - QFontEngine *fontEngine = engine.fontEngine(engine.layoutData->items[0]); - if (fontEngine->type() == QFontEngine::Multi) - fontEngine = static_cast(fontEngine)->engine(0); - - if (originalFontFile) - *originalFontFile = QFile::decodeName(fontEngine->faceId().filename); - - return generate(fontEngine, options, ranges); -} - -QByteArray QPF::generate(QFontEngine *fontEngine, int options, const QList &ranges) -{ - QPF font; - - font.options = options; - font.addHeader(fontEngine); - if (options & IncludeCMap) - font.addCMap(fontEngine); - font.addGlyphs(fontEngine, ranges); - - return font.qpf; -} - -void QPF::addHeader(QFontEngine *fontEngine) -{ - QFontEngineQPF2::Header *header = reinterpret_cast(addBytes(sizeof(QFontEngineQPF2::Header))); - - header->magic[0] = 'Q'; - header->magic[1] = 'P'; - header->magic[2] = 'F'; - header->magic[3] = '2'; - if (options & RenderGlyphs) - header->lock = 0xffffffff; - else - header->lock = 0; - header->majorVersion = QFontEngineQPF2::CurrentMajorVersion; - header->minorVersion = QFontEngineQPF2::CurrentMinorVersion; - header->dataSize = 0; - int oldSize = qpf.size(); - - addTaggedString(QFontEngineQPF2::Tag_FontName, fontEngine->fontDef.family.toUtf8()); - - QFontEngine::FaceId face = fontEngine->faceId(); - addTaggedString(QFontEngineQPF2::Tag_FileName, face.filename); - addTaggedUInt32(QFontEngineQPF2::Tag_FileIndex, face.index); - - { - const QByteArray head = fontEngine->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')); - const quint32 revision = qFromBigEndian(reinterpret_cast(head.constData()) + 4); - addTaggedUInt32(QFontEngineQPF2::Tag_FontRevision, revision); - } - - addTaggedQFixed(QFontEngineQPF2::Tag_Ascent, fontEngine->ascent()); - addTaggedQFixed(QFontEngineQPF2::Tag_Descent, fontEngine->descent()); - addTaggedQFixed(QFontEngineQPF2::Tag_Leading, fontEngine->leading()); - addTaggedQFixed(QFontEngineQPF2::Tag_XHeight, fontEngine->xHeight()); - addTaggedQFixed(QFontEngineQPF2::Tag_AverageCharWidth, fontEngine->averageCharWidth()); - addTaggedQFixed(QFontEngineQPF2::Tag_MaxCharWidth, QFixed::fromReal(fontEngine->maxCharWidth())); - addTaggedQFixed(QFontEngineQPF2::Tag_LineThickness, fontEngine->lineThickness()); - addTaggedQFixed(QFontEngineQPF2::Tag_MinLeftBearing, QFixed::fromReal(fontEngine->minLeftBearing())); - addTaggedQFixed(QFontEngineQPF2::Tag_MinRightBearing, QFixed::fromReal(fontEngine->minRightBearing())); - addTaggedQFixed(QFontEngineQPF2::Tag_UnderlinePosition, fontEngine->underlinePosition()); - addTaggedUInt8(QFontEngineQPF2::Tag_PixelSize, fontEngine->fontDef.pixelSize); - addTaggedUInt8(QFontEngineQPF2::Tag_Weight, fontEngine->fontDef.weight); - addTaggedUInt8(QFontEngineQPF2::Tag_Style, fontEngine->fontDef.style); - - QByteArray writingSystemBitField = getWritingSystems(fontEngine); - if (!writingSystemBitField.isEmpty()) - addTaggedString(QFontEngineQPF2::Tag_WritingSystems, writingSystemBitField); - - addTaggedUInt8(QFontEngineQPF2::Tag_GlyphFormat, QFontEngineQPF2::AlphamapGlyphs); - - addTaggedString(QFontEngineQPF2::Tag_EndOfHeader, QByteArray()); - align4(); - header = reinterpret_cast(qpf.data()); - header->dataSize = qToBigEndian(qpf.size() - oldSize); -} - -static uchar *appendBytes(QByteArray &array, int size) -{ - int oldSize = array.size(); - array.resize(array.size() + size); - return reinterpret_cast(array.data() + oldSize); -} - -#define APPEND(type, value) \ - qToBigEndian(value, appendBytes(cmap, sizeof(type))) - -struct CMapSegment -{ - int start; // codepoints - int end; - int startGlyphIndex; -}; - -static QByteArray generateTrueTypeCMap(QFontEngine *fe) -{ - QByteArray cmap; - const int glyphCount = fe->glyphCount(); - if (!glyphCount) - return cmap; - - // cmap header - APPEND(quint16, 0); // table version number - APPEND(quint16, 1); // number of tables - - // encoding record - APPEND(quint16, 3); // platform-id - APPEND(quint16, 10); // encoding-id (ucs-4) - const int cmapOffset = cmap.size() + sizeof(quint32); - APPEND(quint32, cmapOffset); // offset to sub-table - - APPEND(quint16, 4); // subtable format - const int cmapTableLengthOffset = cmap.size(); - APPEND(quint16, 0); // length in bytes, will fill in later - APPEND(quint16, 0); // language field - - QList segments; - CMapSegment currentSegment; - currentSegment.start = 0xffff; - currentSegment.end = 0; - currentSegment.startGlyphIndex = 0; - quint32 previousGlyphIndex = 0xfffffffe; - bool inSegment = false; - - QGlyphLayoutArray<1> layout; - for (uint uc = 0; uc < 0x10000; ++uc) { - QChar ch(uc); - int nglyphs = 1; - - bool validGlyph = fe->stringToCMap(&ch, 1, &layout, &nglyphs, /*flags*/ 0) - && nglyphs == 1 && layout.glyphs[0]; - - // leaving a segment? - if (inSegment && (!validGlyph || layout.glyphs[0] != previousGlyphIndex + 1)) { - Q_ASSERT(currentSegment.start != 0xffff); - // store the current segment - currentSegment.end = uc - 1; - segments.append(currentSegment); - currentSegment.start = 0xffff; - inSegment = false; - } - // entering a new segment? - if (validGlyph && (!inSegment || layout.glyphs[0] != previousGlyphIndex + 1)) { - currentSegment.start = uc; - currentSegment.startGlyphIndex = layout.glyphs[0]; - inSegment = true; - } - - if (validGlyph) - previousGlyphIndex = layout.glyphs[0]; - else - previousGlyphIndex = 0xfffffffe; - } - - currentSegment.start = 0xffff; - currentSegment.end = 0xffff; - currentSegment.startGlyphIndex = 0; - segments.append(currentSegment); - - if (QPF::debugVerbosity > 3) - qDebug() << "segments:" << segments.count(); - - Q_ASSERT(!inSegment); - - const quint16 entrySelector = int(log2(segments.count())); - const quint16 searchRange = 2 * (1 << entrySelector); - const quint16 rangeShift = segments.count() * 2 - searchRange; - - if (QPF::debugVerbosity > 3) - qDebug() << "entrySelector" << entrySelector << "searchRange" << searchRange - << "rangeShift" << rangeShift; - - APPEND(quint16, segments.count() * 2); // segCountX2 - APPEND(quint16, searchRange); - APPEND(quint16, entrySelector); - APPEND(quint16, rangeShift); - - // end character codes - for (int i = 0; i < segments.count(); ++i) - APPEND(quint16, segments.at(i).end); - - APPEND(quint16, 0); // pad - - // start character codes - for (int i = 0; i < segments.count(); ++i) - APPEND(quint16, segments.at(i).start); - - // id deltas - for (int i = 0; i < segments.count(); ++i) - APPEND(quint16, segments.at(i).startGlyphIndex - segments.at(i).start); - - // id range offsets - for (int i = 0; i < segments.count(); ++i) - APPEND(quint16, 0); - - uchar *lengthPtr = reinterpret_cast(cmap.data()) + cmapTableLengthOffset; - qToBigEndian(cmap.size() - cmapOffset, lengthPtr); - - return cmap; -} - -void QPF::addCMap(QFontEngine *fontEngine) -{ - QByteArray cmapTable = fontEngine->getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); - if (cmapTable.isEmpty()) - cmapTable = generateTrueTypeCMap(fontEngine); - addBlock(QFontEngineQPF2::CMapBlock, cmapTable); -} - -void QPF::addGlyphs(QFontEngine *fe, const QList &ranges) -{ - const quint16 glyphCount = fe->glyphCount(); - - QByteArray gmap; - gmap.resize(glyphCount * sizeof(quint32)); - gmap.fill(char(0xff)); - //qDebug() << "glyphCount" << glyphCount; - - QByteArray glyphs; - if (options & RenderGlyphs) { - // this is only a rough estimation - glyphs.reserve(glyphCount - * (sizeof(QFontEngineQPF2::Glyph) - + qRound(fe->maxCharWidth() * (fe->ascent() + fe->descent()).toReal()))); - - QGlyphLayoutArray<1> layout; - - for (CharacterRange range : ranges) { - if (debugVerbosity > 2) - qDebug() << "rendering range from" << range.start << "to" << range.end; - for (uint uc = range.start; uc < range.end; ++uc) { - QChar ch(uc); - int nglyphs = 1; - if (!fe->stringToCMap(&ch, 1, &layout, &nglyphs, /*flags*/ 0)) - continue; - - if (nglyphs != 1) - continue; - - const quint32 glyphIndex = layout.glyphs[0]; - - if (!glyphIndex) - continue; - - Q_ASSERT(glyphIndex < glyphCount); - - glyph_metrics_t metrics = fe->boundingBox(glyphIndex); - const bool valid = metrics.width.value() != 0 && metrics.height.value() != 0; - - QImage img = valid - ? fe->alphaMapForGlyph(glyphIndex).convertToFormat(QImage::Format_Indexed8) - : QPixmap(0,0).toImage(); - - const quint32 oldSize = glyphs.size(); - glyphs.resize(glyphs.size() + sizeof(QFontEngineQPF2::Glyph) + img.byteCount()); - uchar *data = reinterpret_cast(glyphs.data() + oldSize); - - uchar *gmapPtr = reinterpret_cast(gmap.data() + glyphIndex * sizeof(quint32)); - qToBigEndian(oldSize, gmapPtr); - - QFontEngineQPF2::Glyph *glyph = reinterpret_cast(data); - glyph->width = img.width(); - glyph->height = img.height(); - glyph->bytesPerLine = img.bytesPerLine(); - glyph->x = qRound(metrics.x); - glyph->y = qRound(metrics.y); - glyph->advance = qRound(metrics.xoff); - data += sizeof(QFontEngineQPF2::Glyph); - - if ((debugVerbosity && (uc >= 'A') && (uc <= 'z')) || debugVerbosity > 1) { - qDebug() << "adding glyph with index" << glyphIndex << " uc =" << char(uc) << ":\n" - << " glyph->x =" << glyph->x << "rounded from" << metrics.x << "\n" - << " glyph->y =" << glyph->y << "rounded from" << metrics.y << "\n" - << " width =" << glyph->width << "height =" << glyph->height - << " advance =" << glyph->advance << "rounded from" << metrics.xoff - ; - } - - memcpy(data, img.bits(), img.byteCount()); - } - } - } - - addBlock(QFontEngineQPF2::GMapBlock, gmap); - addBlock(QFontEngineQPF2::GlyphBlock, glyphs); -} - -void QPF::addBlock(QFontEngineQPF2::BlockTag tag, const QByteArray &blockData) -{ - addUInt16(tag); - addUInt16(0); // padding - const int padSize = ((blockData.size() + 3) / 4) * 4 - blockData.size(); - addUInt32(blockData.size() + padSize); - addByteArray(blockData); - for (int i = 0; i < padSize; ++i) - addUInt8(0); -} - -#define ADD_TAGGED_DATA(tag, qtype, type, value) \ - addUInt16(tag); \ - addUInt16(sizeof(qtype)); \ - add##type(value) - -void QPF::addTaggedString(QFontEngineQPF2::HeaderTag tag, const QByteArray &string) -{ - addUInt16(tag); - addUInt16(string.length()); - addByteArray(string); -} - -void QPF::addTaggedQFixed(QFontEngineQPF2::HeaderTag tag, QFixed value) -{ - ADD_TAGGED_DATA(tag, quint32, UInt32, value.value()); -} - -void QPF::addTaggedUInt8(QFontEngineQPF2::HeaderTag tag, quint8 value) -{ - ADD_TAGGED_DATA(tag, quint8, UInt8, value); -} - -void QPF::addTaggedInt8(QFontEngineQPF2::HeaderTag tag, qint8 value) -{ - ADD_TAGGED_DATA(tag, qint8, Int8, value); -} - -void QPF::addTaggedUInt16(QFontEngineQPF2::HeaderTag tag, quint16 value) -{ - ADD_TAGGED_DATA(tag, quint16, UInt16, value); -} - -void QPF::addTaggedUInt32(QFontEngineQPF2::HeaderTag tag, quint32 value) -{ - ADD_TAGGED_DATA(tag, quint32, UInt32, value); -} - -void QPF::dump(const QByteArray &qpf) -{ - QPF font; - font.qpf = qpf; - - const uchar *data = reinterpret_cast(qpf.constData()); - const uchar *endPtr = reinterpret_cast(qpf.constData() + qpf.size()); - data = font.dumpHeader(data); - - const quint32 *gmap = 0; - quint32 glyphCount = 0; - - while (data < endPtr) { - const QFontEngineQPF2::Block *block = reinterpret_cast(data); - quint32 tag = qFromBigEndian(block->tag); - quint32 blockSize = qFromBigEndian(block->dataSize); - qDebug() << "Block: Tag =" << qFromBigEndian(block->tag) << "; Size =" << blockSize << "; Offset =" << hex << data - reinterpret_cast(qpf.constData()); - data += sizeof(QFontEngineQPF2::Block); - - if (debugVerbosity) { - if (tag == QFontEngineQPF2::GMapBlock) { - gmap = reinterpret_cast(data); - glyphCount = blockSize / 4; - font.dumpGMapBlock(gmap, glyphCount); - } else if (tag == QFontEngineQPF2::GlyphBlock - && gmap && debugVerbosity > 1) { - font.dumpGlyphBlock(gmap, glyphCount, data, data + blockSize); - } - } - - data += blockSize; - } -} - -const uchar *QPF::dumpHeader(const uchar *data) -{ - const QFontEngineQPF2::Header *header = reinterpret_cast(data); - qDebug() << "Header:"; - qDebug() << "magic =" - << header->magic[0] - << header->magic[1] - << header->magic[2] - << header->magic[3]; - qDebug() << "lock =" << qFromBigEndian(header->lock); - qDebug() << "majorVersion =" << header->majorVersion; - qDebug() << "minorVersion =" << header->minorVersion; - qDebug() << "dataSize =" << qFromBigEndian(header->dataSize); - - data += sizeof(QFontEngineQPF2::Header); - - const uchar *endPtr = data + qFromBigEndian(header->dataSize); - - while (data && data < endPtr) { - data = dumpHeaderTag(data); - } - - return endPtr; -} - -const uchar *QPF::dumpHeaderTag(const uchar *data) -{ - const QFontEngineQPF2::Tag *tagPtr = reinterpret_cast(data); - quint16 tag = qFromBigEndian(tagPtr->tag); - quint16 size = qFromBigEndian(tagPtr->size); - - qDebug() << "Tag =" << tag << headerTagNames[tag]; - qDebug() << "Size =" << size; - - if (tag == QFontEngineQPF2::Tag_EndOfHeader) - return 0; - - data += sizeof(QFontEngineQPF2::Tag); - - Q_ASSERT(tag < QFontEngineQPF2::NumTags); - - switch (tagTypes[tag]) { - case QFontEngineQPF2::StringType: - qDebug() << "Payload =" << QString::fromUtf8(QByteArray(reinterpret_cast(data), size)); - break; - case QFontEngineQPF2::FixedType: - Q_ASSERT(size == sizeof(quint32)); - qDebug() << "Payload =" << QFixed::fromFixed(qFromBigEndian(data)).toReal(); - break; - case QFontEngineQPF2::UInt8Type: - Q_ASSERT(size == sizeof(quint8)); - qDebug() << "Payload =" << *data; - break; - case QFontEngineQPF2::UInt32Type: - Q_ASSERT(size == sizeof(quint32)); - qDebug() << "Payload =" << qFromBigEndian(data); - break; - case QFontEngineQPF2::BitFieldType: { - QByteArray bits(reinterpret_cast(data), size); - qDebug() << "Payload =" << stringify(bits); - if (QPF::debugVerbosity > 2 && tag == QFontEngineQPF2::Tag_WritingSystems) - dumpWritingSystems(bits); - } break; - } - - data += size; - return data; -} - -void QPF::dumpGMapBlock(const quint32 *gmap, int glyphCount) -{ - qDebug() << "glyphCount =" << glyphCount; - int renderedGlyphs = 0; - for (int i = 0; i < glyphCount; ++i) { - if (gmap[i] != 0xffffffff) { - const quint32 glyphPos = qFromBigEndian(gmap[i]); - qDebug("gmap[%d] = 0x%x / %u", i, glyphPos, glyphPos); - ++renderedGlyphs; - } - } - qDebug() << "Glyphs rendered:" << renderedGlyphs << "; Glyphs missing from the font:" << glyphCount - renderedGlyphs; -} - -void QPF::dumpGlyphBlock(const quint32 *gmap, int glyphCount, const uchar *data, const uchar *endPtr) -{ - // glyphPos -> glyphIndex - QMap reverseGlyphMap; - for (int i = 0; i < glyphCount; ++i) { - if (gmap[i] == 0xffffffff) - continue; - const quint32 glyphPos = qFromBigEndian(gmap[i]); - reverseGlyphMap[glyphPos] = i; - } - - const uchar *glyphBlockBegin = data; - while (data < endPtr) { - const QFontEngineQPF2::Glyph *g = reinterpret_cast(data); - - const quint64 glyphOffset = data - glyphBlockBegin; - const quint32 glyphIndex = reverseGlyphMap.value(glyphOffset, 0xffffffff); - - if (glyphIndex == 0xffffffff) - qDebug() << "############: Glyph present in glyph block is not listed in glyph map!"; - qDebug("glyph at offset 0x%x glyphIndex = %u", quint32(glyphOffset), glyphIndex); - qDebug() << " width =" << g->width << "height =" << g->height << "x =" << g->x << "y =" << g->y; - qDebug() << " advance =" << g->advance << "bytesPerLine =" << g->bytesPerLine; - - data += sizeof(*g); - if (glyphIndex == 0xffffffff || debugVerbosity > 4) { - dumpGlyph(data, g); - } - - data += g->height * g->bytesPerLine; - } -} - -void QPF::dumpGlyph(const uchar *data, const QFontEngineQPF2::Glyph *glyph) -{ - fprintf(stderr, "---- glyph data:\n"); - const char *alphas = " .o#"; - for (int y = 0; y < glyph->height; ++y) { - for (int x = 0; x < glyph->width; ++x) { - const uchar value = data[y * glyph->bytesPerLine + x]; - fprintf(stderr, "%c", alphas[value >> 6]); - } - fprintf(stderr, "\n"); - } - fprintf(stderr, "----\n"); -} - -QT_END_NAMESPACE diff --git a/src/makeqpf/qpf2.h b/src/makeqpf/qpf2.h deleted file mode 100644 index 6dbddcb0bb..0000000000 --- a/src/makeqpf/qpf2.h +++ /dev/null @@ -1,106 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPF2_H -#define QPF2_H - -#include -#include - -QT_BEGIN_NAMESPACE - -class QFontEngine; - -class QPF -{ -public: - static int debugVerbosity; - - enum GenerationOption { - IncludeCMap = 0x1, - RenderGlyphs = 0x2 - }; - - struct CharacterRange - { - inline CharacterRange() : start(0), end(0x10000) {} - uint start; - uint end; - }; - - static QString fileNameForFont(const QFont &f); - - static QByteArray generate(const QFont &font, int options, - const QList &ranges, - QString *originalFontFile = 0); - static QByteArray generate(QFontEngine *fontEngine, int options, const QList &ranges); - void addHeader(QFontEngine *fontEngine); - void addCMap(QFontEngine *fontEngine); - void addGlyphs(QFontEngine *fontEngine, const QList &ranges); - void addBlock(QFontEngineQPF2::BlockTag tag, const QByteArray &data); - - void addTaggedString(QFontEngineQPF2::HeaderTag tag, const QByteArray &string); - void addTaggedQFixed(QFontEngineQPF2::HeaderTag tag, QFixed value); - void addTaggedUInt8(QFontEngineQPF2::HeaderTag tag, quint8 value); - void addTaggedInt8(QFontEngineQPF2::HeaderTag tag, qint8 value); - void addTaggedUInt16(QFontEngineQPF2::HeaderTag tag, quint16 value); - void addTaggedUInt32(QFontEngineQPF2::HeaderTag tag, quint32 value); - - static void dump(const QByteArray &qpf); - const uchar *dumpHeader(const uchar *data); - const uchar *dumpHeaderTag(const uchar *data); - void dumpGMapBlock(const quint32 *gmap, int glyphCount); - void dumpGlyphBlock(const quint32 *gmap, int glyphCount, const uchar *data, const uchar *endPtr); - void dumpGlyph(const uchar *data, const QFontEngineQPF2::Glyph *glyph); - - void addUInt16(quint16 value) { qToBigEndian(value, addBytes(sizeof(value))); } - void addUInt32(quint32 value) { qToBigEndian(value, addBytes(sizeof(value))); } - void addUInt8(quint8 value) { *addBytes(sizeof(value)) = value; } - void addInt8(qint8 value) { *addBytes(sizeof(value)) = quint8(value); } - void addByteArray(const QByteArray &string) { - uchar *data = addBytes(string.length()); - qMemCopy(data, string.constData(), string.length()); - } - - void align4() { while (qpf.size() & 3) { addUInt8('\0'); } } - - uchar *addBytes(int size) { - const int oldSize = qpf.size(); - qpf.resize(qpf.size() + size); - return reinterpret_cast(qpf.data() + oldSize); - } - - QByteArray qpf; - int options; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QPF::CharacterRange) - -#endif // QPF2_H diff --git a/src/pixeltool/CMakeLists.txt b/src/pixeltool/CMakeLists.txt new file mode 100644 index 0000000000..eaf3f7a027 --- /dev/null +++ b/src/pixeltool/CMakeLists.txt @@ -0,0 +1,30 @@ +# Generated from pixeltool.pro. + +##################################################################### +## pixeltool App: +##################################################################### + +qt_internal_add_app(pixeltool + SOURCES + main.cpp + qpixeltool.cpp qpixeltool.h + PUBLIC_LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::GuiPrivate + Qt::Widgets +) + +#### Keys ignored in scope 1:.:.:pixeltool.pro:: +# QT_FOR_CONFIG = "tools-private" +# _REQUIREMENTS = "qtConfig(pixeltool)" + +## Scopes: +##################################################################### + +if(APPLE) + set_target_properties(pixeltool PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist" + MACOSX_BUNDLE TRUE + ) +endif() diff --git a/src/pixeltool/main.cpp b/src/pixeltool/main.cpp index 3e17d61b58..c4250d3670 100644 --- a/src/pixeltool/main.cpp +++ b/src/pixeltool/main.cpp @@ -35,20 +35,8 @@ QT_USE_NAMESPACE -static bool isOptionSet(int argc, char *argv[], const char *option) -{ - for (int i = 1; i < argc; ++i) { - if (!qstrcmp(argv[i], option)) - return true; - } - return false; -} - int main(int argc, char **argv) { - if (isOptionSet(argc, argv, "--no-scaling")) - QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); - QApplication app(argc, argv); QCoreApplication::setApplicationName(QLatin1String("PixelTool")); QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR)); @@ -57,9 +45,6 @@ int main(int argc, char **argv) QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption noScalingDummy(QStringLiteral("no-scaling"), - QStringLiteral("Set Qt::AA_DisableHighDpiScaling.")); - parser.addOption(noScalingDummy); parser.addPositionalArgument(QLatin1String("preview"), QLatin1String("The preview image to show.")); diff --git a/src/pixeltool/pixeltool.pro b/src/pixeltool/pixeltool.pro deleted file mode 100644 index f3d1bf436c..0000000000 --- a/src/pixeltool/pixeltool.pro +++ /dev/null @@ -1,10 +0,0 @@ -QT += core-private gui-private widgets - -mac { - QMAKE_INFO_PLIST=Info_mac.plist -} - -SOURCES += main.cpp qpixeltool.cpp -HEADERS += qpixeltool.h - -load(qt_app) diff --git a/src/pixeltool/qpixeltool.cpp b/src/pixeltool/qpixeltool.cpp index 67e2afdf5a..745fd5933e 100644 --- a/src/pixeltool/qpixeltool.cpp +++ b/src/pixeltool/qpixeltool.cpp @@ -29,11 +29,10 @@ #include "qpixeltool.h" #include -#include #include #include #include -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) #include #endif #include @@ -67,14 +66,6 @@ static QPoint initialPos(const QSettings &settings, const QSize &initialSize) QPixelTool::QPixelTool(QWidget *parent) : QWidget(parent) - , m_freeze(false) - , m_displayZoom(false) - , m_displayGridSize(false) - , m_mouseDown(false) - , m_preview_mode(false) - , m_displayZoomId(0) - , m_displayGridSizeId(0) - , m_currentColor(0) { setWindowTitle(QCoreApplication::applicationName()); QSettings settings(QLatin1String("QtProject"), QLatin1String("QPixelTool")); @@ -313,12 +304,14 @@ void QPixelTool::keyPressEvent(QKeyEvent *e) case Qt::Key_A: m_autoUpdate = !m_autoUpdate; break; -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) case Qt::Key_C: - if (e->modifiers() & Qt::ControlModifier) + if (e->modifiers().testFlag(Qt::ControlModifier)) copyToClipboard(); + else + copyColorToClipboard(); break; -#endif +#endif // QT_CONFIG(clipboard) case Qt::Key_S: if (e->modifiers() & Qt::ControlModifier) { releaseKeyboard(); @@ -355,8 +348,9 @@ void QPixelTool::mouseMoveEvent(QMouseEvent *e) if (m_mouseDown) m_dragCurrent = e->pos(); - int x = e->x() / m_zoom; - int y = e->y() / m_zoom; + const auto pos = e->position().toPoint(); + const int x = pos.x() / m_zoom; + const int y = pos.y() / m_zoom; QImage im = m_buffer.toImage().convertToFormat(QImage::Format_ARGB32); if (x < im.width() && y < im.height() && x >= 0 && y >= 0) { @@ -453,10 +447,12 @@ void QPixelTool::contextMenuEvent(QContextMenuEvent *e) // Copy to clipboard / save menu.addAction(QLatin1String("Save as image..."), this, &QPixelTool::saveToFile, QKeySequence::SaveAs); -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) menu.addAction(QLatin1String("Copy to clipboard"), this, &QPixelTool::copyToClipboard, QKeySequence::Copy); -#endif + menu.addAction(QLatin1String("Copy color value to clipboard"), + this, &QPixelTool::copyColorToClipboard, Qt::Key_C); +#endif // QT_CONFIG(clipboard) menu.addSeparator(); menu.addAction(QLatin1String("About Qt"), qApp, &QApplication::aboutQt); @@ -497,7 +493,7 @@ QSize QPixelTool::sizeHint() const return m_initialSize; } -static inline QString pixelToolTitle(QPoint pos) +static inline QString pixelToolTitle(QPoint pos, const QColor ¤tColor) { if (QHighDpiScaling::isActive()) { if (auto screen = QGuiApplication::screenAt(pos)) @@ -505,7 +501,8 @@ static inline QString pixelToolTitle(QPoint pos) } return QCoreApplication::applicationName() + QLatin1String(" [") + QString::number(pos.x()) - + QLatin1String(", ") + QString::number(pos.y()) + QLatin1Char(']'); + + QLatin1String(", ") + QString::number(pos.y()) + QLatin1String("] ") + + currentColor.name(); } void QPixelTool::grabScreen() @@ -523,7 +520,7 @@ void QPixelTool::grabScreen() return; if (m_lastMousePos != mousePos) - setWindowTitle(pixelToolTitle(mousePos)); + setWindowTitle(pixelToolTitle(mousePos, m_currentColor)); int w = int(width() / float(m_zoom)); int h = int(height() / float(m_zoom)); @@ -537,9 +534,8 @@ void QPixelTool::grabScreen() int y = mousePos.y() - h/2; const QBrush darkBrush = palette().color(QPalette::Dark); - const QDesktopWidget *desktopWidget = QApplication::desktop(); - if (QScreen *screen = QGuiApplication::screens().value(desktopWidget->screenNumber(this), nullptr)) { - m_buffer = screen->grabWindow(desktopWidget->winId(), x, y, w, h); + if (QScreen *screen = this->screen()) { + m_buffer = screen->grabWindow(0, x, y, w, h); } else { m_buffer = QPixmap(w, h); m_buffer.fill(darkBrush.color()); @@ -561,6 +557,7 @@ void QPixelTool::grabScreen() update(); + m_currentColor = m_buffer.toImage().pixel(m_buffer.rect().center()); m_lastMousePos = mousePos; } @@ -642,12 +639,17 @@ void QPixelTool::setGridSize(int gridSize) } } -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void QPixelTool::copyToClipboard() { QGuiApplication::clipboard()->setPixmap(m_buffer); } -#endif + +void QPixelTool::copyColorToClipboard() +{ + QGuiApplication::clipboard()->setText(QColor(m_currentColor).name()); +} +#endif // QT_CONFIG(clipboard) void QPixelTool::saveToFile() { @@ -682,8 +684,8 @@ QTextStream &operator<<(QTextStream &str, const QScreen *screen) { const QRect geometry = screen->geometry(); str << '"' << screen->name() << "\" " << geometry.width() - << 'x' << geometry.height() << forcesign << geometry.x() << geometry.y() - << noforcesign << ", " << qRound(screen->logicalDotsPerInch()) << "DPI" + << 'x' << geometry.height() << Qt::forcesign << geometry.x() << geometry.y() + << Qt::noforcesign << ", " << qRound(screen->logicalDotsPerInch()) << "DPI" << ", Depth: " << screen->depth() << ", " << screen->refreshRate() << "Hz"; const qreal dpr = screen->devicePixelRatio(); if (!qFuzzyCompare(dpr, qreal(1))) diff --git a/src/pixeltool/qpixeltool.h b/src/pixeltool/qpixeltool.h index ecf912353f..3fa9f1e7e8 100644 --- a/src/pixeltool/qpixeltool.h +++ b/src/pixeltool/qpixeltool.h @@ -51,8 +51,9 @@ public slots: void toggleGrid(); void toggleFreeze(); void setZoomVisible(bool visible); -#ifndef QT_NO_CLIPBOARD +#if QT_CONFIG(clipboard) void copyToClipboard(); + void copyColorToClipboard(); #endif void saveToFile(); void increaseGridSize() { setGridSize(m_gridSize + 1); } @@ -78,12 +79,12 @@ public slots: void startGridSizeVisibleTimer(); QString aboutText() const; - bool m_freeze; - bool m_displayZoom; - bool m_displayGridSize; - bool m_mouseDown; + bool m_freeze = false; + bool m_displayZoom = false; + bool m_displayGridSize = false; + bool m_mouseDown = false; bool m_autoUpdate; - bool m_preview_mode; + bool m_preview_mode = false; int m_gridActive; int m_zoom; @@ -92,9 +93,9 @@ public slots: int m_updateId; int m_displayZoomId; - int m_displayGridSizeId; + int m_displayGridSizeId = 0; - int m_currentColor; + QRgb m_currentColor = 0; QPoint m_lastMousePos; QPoint m_dragStart; diff --git a/src/qdbus/CMakeLists.txt b/src/qdbus/CMakeLists.txt new file mode 100644 index 0000000000..9bbbc51dba --- /dev/null +++ b/src/qdbus/CMakeLists.txt @@ -0,0 +1,11 @@ +# Generated from qdbus.pro. + +if(NOT QT_FEATURE_qdbus) + return() +endif() +if(QT_FEATURE_dom) + add_subdirectory(qdbus) +endif() +if(QT_FEATURE_dialogbuttonbox AND QT_FEATURE_inputdialog AND QT_FEATURE_menu AND QT_FEATURE_messagebox AND TARGET Qt::Widgets) + add_subdirectory(qdbusviewer) +endif() diff --git a/src/qdbus/qdbus.pro b/src/qdbus/qdbus.pro deleted file mode 100644 index 860c1e11e3..0000000000 --- a/src/qdbus/qdbus.pro +++ /dev/null @@ -1,9 +0,0 @@ -TEMPLATE = subdirs -QT_FOR_CONFIG += xml -qtConfig(dom): SUBDIRS = qdbus -qtHaveModule(widgets) { - QT_FOR_CONFIG += widgets - qtConfig(dialogbuttonbox):qtConfig(inputdialog):qtConfig(messagebox):qtConfig(menu) { - SUBDIRS += qdbusviewer - } -} diff --git a/src/qdbus/qdbus/CMakeLists.txt b/src/qdbus/qdbus/CMakeLists.txt new file mode 100644 index 0000000000..4fcbf5f39a --- /dev/null +++ b/src/qdbus/qdbus/CMakeLists.txt @@ -0,0 +1,22 @@ +# Generated from qdbus.pro. + +##################################################################### +## qdbus App: +##################################################################### + +qt_internal_add_app(qdbus + SOURCES + qdbus.cpp + PUBLIC_LIBRARIES + Qt::DBusPrivate + Qt::Xml +) + +## Scopes: +##################################################################### + +if(WIN32) + set_target_properties(qdbus PROPERTIES + WIN32_EXECUTABLE FALSE + ) +endif() diff --git a/src/qdbus/qdbus/qdbus.cpp b/src/qdbus/qdbus/qdbus.cpp index d25d53ec72..a5e7af95e1 100644 --- a/src/qdbus/qdbus/qdbus.cpp +++ b/src/qdbus/qdbus/qdbus.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include @@ -77,24 +77,24 @@ static void printArg(const QVariant &v) return; } - if (v.userType() == QVariant::StringList) { + if (v.metaType() == QMetaType::fromType()) { const QStringList sl = v.toStringList(); for (const QString &s : sl) printf("%s\n", qPrintable(s)); - } else if (v.userType() == QVariant::List) { + } else if (v.metaType() == QMetaType::fromType()) { const QVariantList vl = v.toList(); for (const QVariant &var : vl) printArg(var); - } else if (v.userType() == QVariant::Map) { + } else if (v.metaType() == QMetaType::fromType()) { const QVariantMap map = v.toMap(); QVariantMap::ConstIterator it = map.constBegin(); for ( ; it != map.constEnd(); ++it) { printf("%s: ", qPrintable(it.key())); printArg(it.value()); } - } else if (v.userType() == qMetaTypeId()) { + } else if (v.metaType() == QMetaType::fromType()) { printArg(qvariant_cast(v).variant()); - } else if (v.userType() == qMetaTypeId()) { + } else if (v.metaType() == QMetaType::fromType()) { QDBusArgument arg = qvariant_cast(v); if (arg.currentSignature() == QLatin1String("av")) printArg(qdbus_cast(arg)); @@ -103,7 +103,7 @@ static void printArg(const QVariant &v) else printf("qdbus: I don't know how to display an argument of type '%s', run with --literal.\n", qPrintable(arg.currentSignature())); - } else if (v.userType() != QVariant::Invalid) { + } else if (v.metaType().isValid()) { printf("%s\n", qPrintable(v.toString())); } } @@ -310,30 +310,29 @@ static int placeCall(const QString &service, const QString &path, const QString } for (int i = 0; !args.isEmpty() && i < types.count(); ++i) { - int id = QVariant::nameToType(types.at(i)); - if (id == QVariant::UserType) - id = QMetaType::type(types.at(i)); - if (!id) { + const QMetaType metaType = QMetaType::fromName(types.at(i)); + if (!metaType.isValid()) { fprintf(stderr, "Cannot call method '%s' because type '%s' is unknown to this tool\n", qPrintable(member), types.at(i).constData()); return 1; } + const int id = metaType.id(); QVariant p; QString argument; - if ((id == QVariant::List || id == QVariant::StringList) + if ((id == QMetaType::QVariantList || id == QMetaType::QStringList) && args.at(0) == QLatin1String("(")) p = readList(args); else p = argument = args.takeFirst(); - if (id == int(QMetaType::UChar)) { + if (id == QMetaType::UChar) { // special case: QVariant::convert doesn't convert to/from // UChar because it can't decide if it's a character or a number p = QVariant::fromValue(p.toUInt()); - } else if (id < int(QMetaType::User) && id != int(QVariant::Map)) { - p.convert(id); - if (p.type() == QVariant::Invalid) { + } else if (id < QMetaType::User && id != QMetaType::QVariantMap) { + p.convert(metaType); + if (!p.isValid()) { fprintf(stderr, "Could not convert '%s' to type '%s'.\n", qPrintable(argument), types.at(i).constData()); return 1 ; @@ -406,14 +405,14 @@ static int placeCall(const QString &service, const QString &path, const QString static bool globServices(QDBusConnectionInterface *bus, const QString &glob) { - QRegExp pattern(glob, Qt::CaseSensitive, QRegExp::Wildcard); + QRegularExpression pattern(QRegularExpression::wildcardToRegularExpression(glob)); if (!pattern.isValid()) return false; QStringList names = bus->registeredServiceNames(); names.sort(); for (const QString &name : qAsConst(names)) - if (pattern.exactMatch(name)) + if (pattern.match(name).hasMatch()) printf("%s\n", qPrintable(name)); return true; diff --git a/src/qdbus/qdbus/qdbus.pro b/src/qdbus/qdbus/qdbus.pro deleted file mode 100644 index 10a709e980..0000000000 --- a/src/qdbus/qdbus/qdbus.pro +++ /dev/null @@ -1,5 +0,0 @@ -SOURCES = qdbus.cpp -QT = core dbus-private xml -win32:CONFIG += console - -load(qt_app) diff --git a/src/qdbus/qdbusviewer/CMakeLists.txt b/src/qdbus/qdbusviewer/CMakeLists.txt new file mode 100644 index 0000000000..79df486c8c --- /dev/null +++ b/src/qdbus/qdbusviewer/CMakeLists.txt @@ -0,0 +1,63 @@ +# Generated from qdbusviewer.pro. + +##################################################################### +## qdbusviewer App: +##################################################################### + +qt_internal_add_app(qdbusviewer + SOURCES + logviewer.cpp logviewer.h + main.cpp + mainwindow.cpp mainwindow.h + propertydialog.cpp propertydialog.h + qdbusmodel.cpp qdbusmodel.h + qdbusviewer.cpp qdbusviewer.h + servicesproxymodel.cpp servicesproxymodel.h + PUBLIC_LIBRARIES + Qt::DBusPrivate + Qt::Gui + Qt::Widgets + Qt::Xml +) + +# Resources: +set(qdbusviewer_resource_files + "images/qdbusviewer-128.png" + "images/qdbusviewer.png" +) + +qt_internal_add_resource(qdbusviewer "qdbusviewer" + PREFIX + "/qt-project.org/qdbusviewer" + FILES + ${qdbusviewer_resource_files} +) + + +## Scopes: +##################################################################### + +if(APPLE) + set_target_properties(qdbusviewer PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist" + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_ICON_FILE "qdbusviewer.icns" + ) + set_source_files_properties(images/qdbusviewer.icns PROPERTIES + MACOSX_PACKAGE_LOCATION Resources + ) + target_sources(qdbusviewer PRIVATE + images/qdbusviewer.icns + ) + # special case end + # Set values to be replaced in the custom Info_mac.plist. + set(ICON "qdbusviewer.icns") + set(EXECUTABLE "qdbusviewer") + # special case end +endif() + +if(WIN32) + set_target_properties(qdbusviewer PROPERTIES + QT_TARGET_RC_ICONS "${CMAKE_CURRENT_SOURCE_DIR}/images/qdbusviewer.ico" + ) +endif() diff --git a/src/qdbus/qdbusviewer/logviewer.h b/src/qdbus/qdbusviewer/logviewer.h index 432d27f94b..4f56387bb8 100644 --- a/src/qdbus/qdbusviewer/logviewer.h +++ b/src/qdbus/qdbusviewer/logviewer.h @@ -38,7 +38,7 @@ class LogViewer : public QTextBrowser explicit LogViewer(QWidget *parent = 0); protected: - virtual void contextMenuEvent(QContextMenuEvent *event); + void contextMenuEvent(QContextMenuEvent *event) override; }; #endif // LOGVIEWER_H diff --git a/src/qdbus/qdbusviewer/mainwindow.cpp b/src/qdbus/qdbusviewer/mainwindow.cpp index ed0f882c9f..7eb83309a1 100644 --- a/src/qdbus/qdbusviewer/mainwindow.cpp +++ b/src/qdbus/qdbusviewer/mainwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). +** Copyright (C) 2020 The Qt Company Ltd and/or its subsidiary(-ies). ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -90,7 +90,7 @@ void MainWindow::about() "

%1

" "

Version %2

" "

Copyright (C) %3 The Qt Company Ltd.

") - .arg(tr("D-Bus Viewer"), QLatin1String(QT_VERSION_STR), QStringLiteral("2019"))); + .arg(tr("D-Bus Viewer"), QLatin1String(QT_VERSION_STR), QStringLiteral("2021"))); box.setWindowTitle(tr("D-Bus Viewer")); box.exec(); } diff --git a/src/qdbus/qdbusviewer/propertydialog.cpp b/src/qdbus/qdbusviewer/propertydialog.cpp index d9c7837f37..fb39493791 100644 --- a/src/qdbus/qdbusviewer/propertydialog.cpp +++ b/src/qdbus/qdbusviewer/propertydialog.cpp @@ -69,7 +69,7 @@ void PropertyDialog::addProperty(const QString &aname, int type) if (name.isEmpty()) name = QLatin1String("argument ") + QString::number(rowCount + 1); name += QLatin1String(" ("); - name += QLatin1String(QMetaType::typeName(type)); + name += QLatin1String(QMetaType(type).name()); name += QLatin1String(")"); QTableWidgetItem *nameItem = new QTableWidgetItem(name); nameItem->setFlags(nameItem->flags() & @@ -77,7 +77,7 @@ void PropertyDialog::addProperty(const QString &aname, int type) propertyTable->setItem(rowCount, 0, nameItem); QTableWidgetItem *valueItem = new QTableWidgetItem; - valueItem->setData(Qt::DisplayRole, QVariant(type, /* copy */ 0)); + valueItem->setData(Qt::DisplayRole, QVariant(QMetaType(type), /* copy */ 0)); propertyTable->setItem(rowCount, 1, valueItem); } diff --git a/src/qdbus/qdbusviewer/propertydialog.h b/src/qdbus/qdbusviewer/propertydialog.h index a151de4732..086a3e130a 100644 --- a/src/qdbus/qdbusviewer/propertydialog.h +++ b/src/qdbus/qdbusviewer/propertydialog.h @@ -38,14 +38,14 @@ class PropertyDialog: public QDialog { Q_OBJECT public: - explicit PropertyDialog(QWidget *parent = 0, Qt::WindowFlags f = 0); + explicit PropertyDialog(QWidget *parent = 0, Qt::WindowFlags f = {}); void addProperty(const QString &name, int type); void setInfo(const QString &caption); QList values() const; - int exec(); + int exec() override; private: QLabel *label; diff --git a/src/qdbus/qdbusviewer/qdbusmodel.cpp b/src/qdbus/qdbusviewer/qdbusmodel.cpp index 79239b264e..8f47b5bc58 100644 --- a/src/qdbus/qdbusviewer/qdbusmodel.cpp +++ b/src/qdbus/qdbusviewer/qdbusmodel.cpp @@ -28,13 +28,15 @@ #include "qdbusmodel.h" -#include #include -#include +#include + #include #include #include +#include + struct QDBusItem { inline QDBusItem(QDBusModel::Type aType, const QString &aName, QDBusItem *aParent = 0) @@ -62,7 +64,7 @@ struct QDBusItem QDBusModel::Type type; QDBusItem *parent; - QVector children; + QList children; bool isPrefetched; QString name; QString caption; @@ -305,7 +307,7 @@ QString QDBusModel::dBusTypeSignature(const QModelIndex &index) const QModelIndex QDBusModel::findObject(const QDBusObjectPath &objectPath) { - QStringList path = objectPath.path().split(QLatin1Char('/'), QString::SkipEmptyParts); + QStringList path = objectPath.path().split(QLatin1Char('/'), Qt::SkipEmptyParts); QDBusItem *item = root; int childIdx = -1; diff --git a/src/qdbus/qdbusviewer/qdbusmodel.h b/src/qdbus/qdbusviewer/qdbusmodel.h index 5552457358..44b9fdad85 100644 --- a/src/qdbus/qdbusviewer/qdbusmodel.h +++ b/src/qdbus/qdbusviewer/qdbusmodel.h @@ -49,12 +49,13 @@ class QDBusModel: public QAbstractItemModel QDBusModel(const QString &service, const QDBusConnection &connection); ~QDBusModel(); - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &child) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; Type itemType(const QModelIndex &index) const; QString dBusPath(const QModelIndex &index) const; diff --git a/src/qdbus/qdbusviewer/qdbusviewer.cpp b/src/qdbus/qdbusviewer/qdbusviewer.cpp index 4a513f3571..54949e2d5f 100644 --- a/src/qdbus/qdbusviewer/qdbusviewer.cpp +++ b/src/qdbus/qdbusviewer/qdbusviewer.cpp @@ -32,14 +32,7 @@ #include "propertydialog.h" #include "logviewer.h" - -#include -#include -#include -#include #include -#include -#include #include #include #include @@ -48,10 +41,19 @@ #include #include #include + #include #include #include +#include +#include +#include + +#include +#include +#include + #include class QDBusViewModel: public QDBusModel @@ -61,7 +63,7 @@ class QDBusViewModel: public QDBusModel : QDBusModel(service, connection) {} - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override { if (role == Qt::FontRole && itemType(index) == InterfaceItem) { QFont f; @@ -162,8 +164,7 @@ QDBusViewer::QDBusViewer(const QDBusConnection &connection, QWidget *parent) : logError(QLatin1String("Cannot connect to D-Bus: ") + c.lastError().message()); } - objectPathRegExp.setMinimal(true); - + objectPathRegExp.setPatternOptions(QRegularExpression::InvertedGreedinessOption); } static inline QString topSplitterStateKey() { return QStringLiteral("topSplitterState"); } @@ -273,7 +274,7 @@ void QDBusViewer::setProperty(const BusSignature &sig) return; QVariant value = input; - if (!value.convert(prop.type())) { + if (!value.convert(prop.metaType())) { QMessageBox::warning(this, tr("Unable to marshall"), tr("Value conversion failed, unable to set property")); return; @@ -291,10 +292,8 @@ static QString getDbusSignature(const QMetaMethod& method) { // create a D-Bus type signature from QMetaMethod's parameters QString sig; - for (int i = 0; i < method.parameterTypes().count(); ++i) { - int type = QMetaType::type(method.parameterTypes().at(i)); - sig.append(QString::fromLatin1(QDBusMetaType::typeToSignature(type))); - } + for (const auto &type : method.parameterTypes()) + sig.append(QString::fromLatin1(QDBusMetaType::typeToSignature(QMetaType::fromName(type)))); return sig; } @@ -329,7 +328,7 @@ void QDBusViewer::callMethod(const BusSignature &sig) if (paramType.endsWith('&')) continue; // ignore OUT parameters - int type = QMetaType::type(paramType); + const int type = QMetaType::fromName(paramType).id(); dialog.addProperty(QString::fromLatin1(paramNames.value(i)), type); types.append(type); } @@ -348,9 +347,10 @@ void QDBusViewer::callMethod(const BusSignature &sig) for (int i = 0; i < args.count(); ++i) { QVariant a = args.at(i); int desttype = types.at(i); - if (desttype < int(QMetaType::User) && desttype != int(QVariant::Map) - && a.canConvert(desttype)) { - args[i].convert(desttype); + if (desttype < int(QMetaType::User) && desttype != qMetaTypeId()) { + const QMetaType metaType(desttype); + if (a.canConvert(metaType)) + args[i].convert(metaType); } // Special case - convert a value to a QDBusVariant if the // interface wants a variant diff --git a/src/qdbus/qdbusviewer/qdbusviewer.h b/src/qdbus/qdbusviewer/qdbusviewer.h index 34002f8ff4..1b7faefd20 100644 --- a/src/qdbus/qdbusviewer/qdbusviewer.h +++ b/src/qdbus/qdbusviewer/qdbusviewer.h @@ -31,7 +31,7 @@ #include #include -#include +#include class ServicesProxyModel; @@ -101,7 +101,7 @@ private slots: QTextBrowser *log; QSplitter *topSplitter; QSplitter *splitter; - QRegExp objectPathRegExp; + QRegularExpression objectPathRegExp; }; #endif diff --git a/src/qdbus/qdbusviewer/qdbusviewer.pro b/src/qdbus/qdbusviewer/qdbusviewer.pro deleted file mode 100644 index 02ec7a2d21..0000000000 --- a/src/qdbus/qdbusviewer/qdbusviewer.pro +++ /dev/null @@ -1,29 +0,0 @@ -HEADERS = qdbusviewer.h \ - qdbusmodel.h \ - servicesproxymodel.h \ - propertydialog.h \ - logviewer.h \ - mainwindow.h - -SOURCES = qdbusviewer.cpp \ - qdbusmodel.cpp \ - servicesproxymodel.cpp \ - propertydialog.cpp \ - logviewer.cpp \ - mainwindow.cpp \ - main.cpp \ - -RESOURCES += qdbusviewer.qrc - -QT += widgets dbus-private xml - -mac { - ICON = images/qdbusviewer.icns - QMAKE_INFO_PLIST = Info_mac.plist -} - -win32 { - RC_FILE = qdbusviewer.rc -} - -load(qt_app) diff --git a/src/qdbus/qdbusviewer/qdbusviewer.rc b/src/qdbus/qdbusviewer/qdbusviewer.rc deleted file mode 100644 index c4b1d60b87..0000000000 --- a/src/qdbus/qdbusviewer/qdbusviewer.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "images/qdbusviewer.ico" diff --git a/src/qdbus/qdbusviewer/servicesproxymodel.cpp b/src/qdbus/qdbusviewer/servicesproxymodel.cpp index cf0e8a9fe4..fff348e14a 100644 --- a/src/qdbus/qdbusviewer/servicesproxymodel.cpp +++ b/src/qdbus/qdbusviewer/servicesproxymodel.cpp @@ -52,8 +52,8 @@ bool ServicesProxyModel::lessThan(const QModelIndex &left, const bool isNumber2 = s2.startsWith(QLatin1String(":1.")); if (isNumber1 == isNumber2) { if (isNumber1) { - int number1 = s1.midRef(3).toInt(); - int number2 = s2.midRef(3).toInt(); + int number1 = QStringView{s1}.mid(3).toInt(); + int number2 = QStringView{s2}.mid(3).toInt(); return number1 < number2; } else { return s1.compare(s2, Qt::CaseInsensitive) < 0; diff --git a/src/qdoc/CMakeLists.txt b/src/qdoc/CMakeLists.txt new file mode 100644 index 0000000000..84099ca320 --- /dev/null +++ b/src/qdoc/CMakeLists.txt @@ -0,0 +1,133 @@ +# Generated from qdoc.pro. + +# special case begin +if(CMAKE_VERSION VERSION_LESS "3.19" AND MSVC AND CMAKE_GENERATOR STREQUAL "Ninja Multi-Config") + message(WARNING "qdoc will not be built in this configuration.") + return() +endif() + +if (MINGW) + set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY _qt_skip_separate_debug_info ON) +endif() + +# special case end + +##################################################################### +## qdoc Tool: +##################################################################### + +qt_get_tool_target_name(target_name qdoc) +qt_internal_add_tool(${target_name} + TARGET_DESCRIPTION "Qt Documentation Compiler" + TOOLS_TARGET Tools # special case + USER_FACING + SOURCES + access.h + aggregate.cpp aggregate.h + atom.cpp atom.h + clangcodeparser.cpp clangcodeparser.h + classnode.cpp classnode.h + codechunk.cpp codechunk.h + codemarker.cpp codemarker.h + codeparser.cpp codeparser.h + collectionnode.cpp collectionnode.h + config.cpp config.h + cppcodemarker.cpp cppcodemarker.h + cppcodeparser.cpp cppcodeparser.h + doc.cpp doc.h + docbookgenerator.cpp docbookgenerator.h + docparser.cpp docparser.h + docprivate.cpp docprivate.h + docutilities.h + editdistance.cpp editdistance.h + enumitem.h + enumnode.cpp enumnode.h + examplenode.h + externalpagenode.cpp externalpagenode.h + functionnode.cpp functionnode.h + generator.cpp generator.h + headernode.cpp headernode.h + helpprojectwriter.cpp helpprojectwriter.h + htmlgenerator.cpp htmlgenerator.h + importrec.h + jscodemarker.cpp jscodemarker.h + location.cpp location.h + macro.h + main.cpp + manifestwriter.cpp manifestwriter.h + namespacenode.cpp namespacenode.h + node.cpp node.h + openedlist.cpp openedlist.h + pagenode.cpp pagenode.h + parameters.cpp parameters.h + propertynode.cpp propertynode.h + proxynode.cpp proxynode.h + puredocparser.cpp puredocparser.h + qdoccommandlineparser.cpp qdoccommandlineparser.h + qdocdatabase.cpp qdocdatabase.h + qdocindexfiles.cpp qdocindexfiles.h + qmlcodemarker.cpp qmlcodemarker.h + qmlcodeparser.cpp qmlcodeparser.h + qmlmarkupvisitor.cpp qmlmarkupvisitor.h + qmlpropertynode.cpp qmlpropertynode.h + qmltypenode.cpp qmltypenode.h + qmlvisitor.cpp qmlvisitor.h + quoter.cpp quoter.h + relatedclass.cpp relatedclass.h + sections.cpp sections.h + sharedcommentnode.cpp sharedcommentnode.h + singleton.h + tagfilewriter.cpp tagfilewriter.h + text.cpp text.h + tokenizer.cpp tokenizer.h + topic.h + tree.cpp tree.h + typedefnode.cpp typedefnode.h + usingclause.cpp usingclause.h + utilities.cpp utilities.h + variablenode.cpp variablenode.h + webxmlgenerator.cpp webxmlgenerator.h + xmlgenerator.cpp xmlgenerator.h + LIBRARIES # special case + WrapLibClang::WrapLibClang # special case + DEFINES + #(CLANG_RESOURCE_DIR=\"/clang//include\") # special case remove + CLANG_RESOURCE_DIR=${QT_LIBCLANG_RESOURCE_DIR} # special case + QDOC2_COMPAT + INCLUDE_DIRECTORIES + ${QT_SOURCE_TREE}/src/tools/qdoc + ${QT_SOURCE_TREE}/src/tools/qdoc/qmlparser +) + +#### Keys ignored in scope 1:.:.:qdoc.pro:: +# QMAKE_TARGET_DESCRIPTION = "Qt Documentation Compiler" +# TR_EXCLUDE = "$$PWD/*" +# _OPTION = "host_build" + +## Scopes: +##################################################################### + +#### Keys ignored in scope 2:.:.:qdoc.pro:NOT force_bootstrap: +# _REQUIREMENTS = "qtConfig(xmlstreamwriter)" + +qt_internal_extend_target(${target_name} CONDITION TARGET Qt::QmlDevToolsPrivate + PUBLIC_LIBRARIES + Qt::QmlDevToolsPrivate +) + +qt_internal_extend_target(${target_name} CONDITION NOT TARGET Qt::QmlDevToolsPrivate + DEFINES + QT_NO_DECLARATIVE +) + +#### Keys ignored in scope 6:.:.:qdoc.pro:NOT QMAKE_DEFAULT_LIBDIRS___contains____ss_CLANG_LIBDIR AND NOT disable_external_rpath: +# QMAKE_RPATHDIR = "$$CLANG_LIBDIR" + +qt_internal_extend_target(${target_name} CONDITION (WIN32 AND ICC) OR MSVC + LINK_OPTIONS + "/STACK:4194304" +) +qt_internal_add_docs(${target_name} + doc/config/qdoc.qdocconf +) + diff --git a/src/qdoc/Qt5DocToolsConfig.cmake.in b/src/qdoc/Qt5DocToolsConfig.cmake.in index daa3361271..2a252bb318 100644 --- a/src/qdoc/Qt5DocToolsConfig.cmake.in +++ b/src/qdoc/Qt5DocToolsConfig.cmake.in @@ -54,3 +54,14 @@ if (NOT TARGET Qt5::qdoc) IMPORTED_LOCATION ${imported_location} ) endif() + +# Create versionless tool targets. +foreach(__qt_tool qdoc) + if(NOT \"${QT_NO_CREATE_VERSIONLESS_TARGETS}\" AND NOT TARGET Qt::${__qt_tool} + AND TARGET Qt5::${__qt_tool}) + add_executable(Qt::${__qt_tool} IMPORTED) + get_target_property(__qt_imported_location Qt5::${__qt_tool} IMPORTED_LOCATION) + set_target_properties(Qt::${__qt_tool} + PROPERTIES IMPORTED_LOCATION \"${__qt_imported_location}\") + endif() +endforeach() diff --git a/src/qdoc/TODO.txt b/src/qdoc/TODO.txt deleted file mode 100644 index 9bf4a2864f..0000000000 --- a/src/qdoc/TODO.txt +++ /dev/null @@ -1,87 +0,0 @@ - * fix QWSPointerCalibrationData::devPoints and qwsServer - * Fix QMenu::addAction(QAction *) overload, "using" etc. - * fix space between two tables using

- * qpixmap-qt3.html; remove 8 public functions inherited from QPaintDevice - * \variable array - * Added support for parameterless macros (e.g. \macro Q_OBJECT). - * Made qdoc stricter regarding the data types (e.g. can't use \enum to document a typedef). - * Parse QT_MODULE() macro and generate proper warnings for the various editions. - * Fix parsing of \image following \value (e.g. qt.html). - * Don't turn X11 and similar names into links. - * Added automatic links from getters to setters and vice versa. - * Support \module and show which module each class is from. - * Fix occasional crash caused by misuse of const_cast(). - * Provide clearer error messages when resolves fail. - - - - -CHECK: - - * Identify editions - * Automatic \sa getter setter - * \macro Q_OBJECT - -MUST HAVES: - - * resolve [gs]etters for \sa using base class - - * fix \overload when one is a signal and the other a normal function - * use "project" for .dcf files - * functions.html: include the types from QtGlobal as well as the functions (whatever that means) - - * nice template function/class syntax - * spellchecker: built-in vs. builtin - - * verbose mode for functions that don't exist - * No links to Porting Guide sections (e.g. QStringList) - * link toggled(bool) - * autolink foo(1) - * handle using correctly - * QObject "reentrant" list: duplicates - * operator<< \overload - * \compat \overload - * qWarning() link - * operator<<() autolink - - * get rid of spurious 'global' functions - * Make automatic links in code work - - * Fix encoding bug (see Important email from Simon Hausmann) - * Make links to QFoo::bar().baz() work - * Fix automatic links in \sectionX (e.g. qt4-getting-started.html) - * Provide a "List of all properties" page. - - * expand QObjectList -> QList - * warning for unnamed parameters in property access functions - * \center...\endcenter - -LINKS: - - * explanation following nonstandard wording warning - - * omit \overload in operator<< and operator>> - * make operator-() unary and binary independent functions (no \overload) - * fix \overload - * fix \legalese - * remove warning for undocumented enum item like QLocale::LastLanguage - * improve the \a warnings for overloads; if one overload documents a para, fine - - * implement \sidebar - - * implement \legalesefile - - * show in which module each class is - * list namespaces, list header files - - -NICE FEATURES: - * implement inheritance tree for each class (as a PNG) - * avoid

...

in table/item cells without relying on horrible kludge - * prevent macros from having same name as commands - * be smart about enum types Foo::Bar vs. Bar when comparing functions - * be smart about const & non-const when comparing functions - -OTHER: - * make qdoc run faster - * make sure \headerfile works even if specified after \relates diff --git a/src/qdoc/loggingcategory.h b/src/qdoc/access.h similarity index 87% rename from src/qdoc/loggingcategory.h rename to src/qdoc/access.h index 812ef7af8a..668b0239e8 100644 --- a/src/qdoc/loggingcategory.h +++ b/src/qdoc/access.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,15 +26,15 @@ ** ****************************************************************************/ -#ifndef LOGGINGCATEGORY_H -#define LOGGINGCATEGORY_H +#include -#include +#ifndef ACCESS_H +#define ACCESS_H QT_BEGIN_NAMESPACE -Q_DECLARE_LOGGING_CATEGORY(lcQdoc) +enum class Access : unsigned char { Public, Protected, Private }; QT_END_NAMESPACE -#endif +#endif // ACCESS_H diff --git a/src/qdoc/aggregate.cpp b/src/qdoc/aggregate.cpp new file mode 100644 index 0000000000..9fcbf75aee --- /dev/null +++ b/src/qdoc/aggregate.cpp @@ -0,0 +1,1004 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "aggregate.h" + +#include "functionnode.h" +#include "parameters.h" +#include "typedefnode.h" +#include "qdocdatabase.h" +#include "qmlpropertynode.h" +#include "qmltypenode.h" +#include "sharedcommentnode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class Aggregate + */ + +/*! \fn Aggregate::Aggregate(NodeType type, Aggregate *parent, const QString &name) + The constructor should never be called directly. It is only called + by the constructors of subclasses of Aggregate. Those constructors + pass the node \a type they want to create, the \a parent of the new + node, and its \a name. + */ + +/*! + The destructor calls delete for each child of this Aggregate + that has this Aggregate as its parent. A child node that has + some other Aggregate as its parent is deleted by that + Aggregate's destructor. This is a fail-safe test. + + The destructor no longer deletes the collection of children + by calling qDeleteAll() because the child list can contain + pointers to children that have some other Aggregate as their + parent. This is because of how the \e{\\relates} command is + processed. An Aggregate can have a pointer to, for example, + a FunctionNode in its child list, but that FunctionNode has + a differen Aggregate as its parent because a \e{\\relates} + command was used to relate it to that parent. In that case, + the other Aggregate's destructor must delete that node. + + \note This function is the \b only place where delete is + called to delete any subclass of Node. + + \note This strategy depends on the node tree being destroyed + by calling delete on the root node of the tree. This happens + in the destructor of class Tree. + */ +Aggregate::~Aggregate() +{ + m_enumChildren.clear(); + m_nonfunctionMap.clear(); + m_functionMap.clear(); + for (int i = 0; i < m_children.size(); ++i) { + if ((m_children[i] != nullptr) && (m_children[i]->parent() == this)) + delete m_children[i]; + m_children[i] = nullptr; + } + m_children.clear(); +} + +/*! + If \a genus is \c{Node::DontCare}, find the first node in + this node's child list that has the given \a name. If this + node is a QML type, be sure to also look in the children + of its property group nodes. Return the matching node or 0. + + If \a genus is either \c{Node::CPP} or \c {Node::QML}, then + find all this node's children that have the given \a name, + and return the one that satisfies the \a genus requirement. + */ +Node *Aggregate::findChildNode(const QString &name, Node::Genus genus, int findFlags) const +{ + if (genus == Node::DontCare) { + Node *node = m_nonfunctionMap.value(name); + if (node) + return node; + } else { + const NodeList &nodes = m_nonfunctionMap.values(name); + for (auto *node : nodes) { + if (genus & node->genus()) { + if (findFlags & TypesOnly) { + if (!node->isTypedef() && !node->isClassNode() && !node->isQmlType() + && !node->isQmlBasicType() && !node->isJsType() + && !node->isJsBasicType() && !node->isEnumType()) + continue; + } else if (findFlags & IgnoreModules && node->isModule()) + continue; + return node; + } + } + } + if (genus != Node::DontCare && !(genus & this->genus())) + return nullptr; + return m_functionMap.value(name); +} + +/*! + Find all the child nodes of this node that are named + \a name and return them in \a nodes. + */ +void Aggregate::findChildren(const QString &name, NodeVector &nodes) const +{ + nodes.clear(); + int nonfunctionCount = m_nonfunctionMap.count(name); + auto it = m_functionMap.find(name); + if (it != m_functionMap.end()) { + int functionCount = 0; + FunctionNode *fn = it.value(); + while (fn != nullptr) { + ++functionCount; + fn = fn->nextOverload(); + } + nodes.reserve(nonfunctionCount + functionCount); + fn = it.value(); + while (fn != nullptr) { + nodes.append(fn); + fn = fn->nextOverload(); + } + } else { + nodes.reserve(nonfunctionCount); + } + if (nonfunctionCount > 0) { + for (auto it = m_nonfunctionMap.find(name); + it != m_nonfunctionMap.end() && it.key() == name; ++it) { + nodes.append(it.value()); + } + } +} + +/*! + This function searches for a child node of this Aggregate, + such that the child node has the spacified \a name and the + function \a isMatch returns true for the node. The function + passed must be one of the isXxx() functions in class Node + that tests the node type. + */ +Node *Aggregate::findNonfunctionChild(const QString &name, bool (Node::*isMatch)() const) +{ + const NodeList &nodes = m_nonfunctionMap.values(name); + for (auto *node : nodes) { + if ((node->*(isMatch))()) + return node; + } + return nullptr; +} + +/*! + Find a function node that is a child of this node, such that + the function node has the specified \a name and \a parameters. + If \a parameters is empty but no matching function is found + that has no parameters, return the first non-internal primary + function or overload, whether it has parameters or not. + */ +FunctionNode *Aggregate::findFunctionChild(const QString &name, const Parameters ¶meters) +{ + auto it = m_functionMap.find(name); + if (it == m_functionMap.end()) + return nullptr; + FunctionNode *fn = it.value(); + + if (parameters.isEmpty() && fn->parameters().isEmpty() && !fn->isInternal()) + return fn; + + while (fn != nullptr) { + if (parameters.count() == fn->parameters().count() && !fn->isInternal()) { + if (parameters.isEmpty()) + return fn; + bool matched = true; + for (int i = 0; i < parameters.count(); i++) { + if (parameters.at(i).type() != fn->parameters().at(i).type()) { + matched = false; + break; + } + } + if (matched) + return fn; + } + fn = fn->nextOverload(); + } + + if (parameters.isEmpty()) { + for (fn = it.value(); fn != nullptr; fn = fn->nextOverload()) + if (!fn->isInternal()) + return fn; + return it.value(); + } + return nullptr; +} + +/*! + Find the function node that is a child of this node, such + that the function described has the same name and signature + as the function described by the function node \a clone. + */ +FunctionNode *Aggregate::findFunctionChild(const FunctionNode *clone) +{ + FunctionNode *fn = m_functionMap.value(clone->name()); + while (fn != nullptr) { + if (isSameSignature(clone, fn)) + return fn; + fn = fn->nextOverload(); + } + return nullptr; +} + +/*! + Returns the list of keys from the primary function map. + */ +QStringList Aggregate::primaryKeys() +{ + return m_functionMap.keys(); +} + +/*! + Mark all child nodes that have no documentation as having + private access and internal status. qdoc will then ignore + them for documentation purposes. + */ +void Aggregate::markUndocumentedChildrenInternal() +{ + for (auto *child : qAsConst(m_children)) { + if (!child->isSharingComment() && !child->hasDoc() && !child->isDontDocument()) { + if (!child->docMustBeGenerated()) { + if (child->isFunction()) { + if (static_cast(child)->hasAssociatedProperties()) + continue; + } else if (child->isTypedef()) { + if (static_cast(child)->hasAssociatedEnum()) + continue; + } + child->setAccess(Access::Private); + child->setStatus(Node::Internal); + } + } + if (child->isAggregate()) { + static_cast(child)->markUndocumentedChildrenInternal(); + } + } +} + +/*! + This is where we set the overload numbers for function nodes. + */ +void Aggregate::normalizeOverloads() +{ + /* + Ensure that none of the primary functions is inactive, private, + or marked \e {overload}. + */ + for (auto it = m_functionMap.begin(); it != m_functionMap.end(); ++it) { + FunctionNode *fn = it.value(); + if (fn->isOverload()) { + FunctionNode *primary = fn->findPrimaryFunction(); + if (primary) { + primary->setNextOverload(fn); + it.value() = primary; + fn = primary; + } + } + int count = 0; + fn->setOverloadNumber(0); // also clears the overload flag + FunctionNode *internalFn = nullptr; + while (fn != nullptr) { + FunctionNode *next = fn->nextOverload(); + if (next) { + if (next->isInternal()) { + // internal overloads are moved to a separate list + // and processed last + fn->setNextOverload(next->nextOverload()); + next->setNextOverload(internalFn); + internalFn = next; + } else { + next->setOverloadNumber(++count); + } + fn = fn->nextOverload(); + } else { + fn->setNextOverload(internalFn); + break; + } + } + while (internalFn) { + internalFn->setOverloadNumber(++count); + internalFn = internalFn->nextOverload(); + } + } + + for (auto *node : qAsConst(m_children)) { + if (node->isAggregate()) + static_cast(node)->normalizeOverloads(); + } +} + +/*! + Returns a const reference to the list of child nodes of this + aggregate that are not function nodes. Duplicate nodes are + removed from the list. + */ +const NodeList &Aggregate::nonfunctionList() +{ + m_nonfunctionList = m_nonfunctionMap.values(); + std::sort(m_nonfunctionList.begin(), m_nonfunctionList.end(), Node::nodeNameLessThan); + m_nonfunctionList.erase(std::unique(m_nonfunctionList.begin(), m_nonfunctionList.end()), + m_nonfunctionList.end()); + return m_nonfunctionList; +} + +/*! \fn bool Aggregate::isAggregate() const + Returns \c true because this node is an instance of Aggregate, + which means it can have children. + */ + +/*! + Finds the enum type node that has \a enumValue as one of + its enum values and returns a pointer to it. Returns 0 if + no enum type node is found that has \a enumValue as one + of its values. + */ +const EnumNode *Aggregate::findEnumNodeForValue(const QString &enumValue) const +{ + for (const auto *node : m_enumChildren) { + const EnumNode *en = static_cast(node); + if (en->hasItem(enumValue)) + return en; + } + return nullptr; +} + +/*! + Appends \a includeFile file to the list of include files. + */ +void Aggregate::addIncludeFile(const QString &includeFile) +{ + m_includeFiles.append(includeFile); +} + +/*! + Sets the list of include files to \a includeFiles. + */ +void Aggregate::setIncludeFiles(const QStringList &includeFiles) +{ + m_includeFiles = includeFiles; +} + +/*! + Compare \a f1 to \a f2 and return \c true if they have the same + signature. Otherwise return \c false. They must have the same + number of parameters, and all the parameter types must be the + same. The functions must have the same constness and refness. + This is a private function. + */ +bool Aggregate::isSameSignature(const FunctionNode *f1, const FunctionNode *f2) +{ + if (f1->parameters().count() != f2->parameters().count()) + return false; + if (f1->isConst() != f2->isConst()) + return false; + if (f1->isRef() != f2->isRef()) + return false; + if (f1->isRefRef() != f2->isRefRef()) + return false; + + const Parameters &p1 = f1->parameters(); + const Parameters &p2 = f2->parameters(); + for (int i = 0; i < p1.count(); i++) { + if (p1.at(i).hasType() && p2.at(i).hasType()) { + QString t1 = p1.at(i).type(); + QString t2 = p2.at(i).type(); + + if (t1.length() < t2.length()) + qSwap(t1, t2); + + /* + ### hack for C++ to handle superfluous + "Foo::" prefixes gracefully + */ + if (t1 != t2 && t1 != (f2->parent()->name() + "::" + t2)) { + // Accept a difference in the template parametters of the type if one + // is omited (eg. "QAtomicInteger" == "QAtomicInteger") + auto ltLoc = t1.indexOf('<'); + auto gtLoc = t1.indexOf('>', ltLoc); + if (ltLoc < 0 || gtLoc < ltLoc) + return false; + t1.remove(ltLoc, gtLoc - ltLoc + 1); + if (t1 != t2) + return false; + } + } + } + return true; +} + +/*! + This function is only called by addChild(), when the child is a + FunctionNode. If the function map does not contain a function with + the name in \a fn, \a fn is inserted into the function map. If the + map already contains a function by that name, \a fn is appended to + that function's linked list of overloads. + + \note A function's overloads appear in the linked list in the same + order they were created. The first overload in the list is the first + overload created. This order is maintained in the numbering of + overloads. In other words, the first overload in the linked list has + overload number 1, and the last overload in the list has overload + number n, where n is the number of overloads not including the + function in the function map. + + \not Adding a function increments the aggregate's function count, + which is the total number of function nodes in the function map, + including the overloads. The overloads are not inserted into the map + but are in a linked list using the FunctionNode's m_nextOverload + pointer. + + \note The function's overload number and overload flag are set in + normalizeOverloads(). + + \note This is a private function. + + \sa normalizeOverloads() + */ +void Aggregate::addFunction(FunctionNode *fn) +{ + auto it = m_functionMap.find(fn->name()); + if (it == m_functionMap.end()) + m_functionMap.insert(fn->name(), fn); + else + it.value()->appendOverload(fn); +} + +/*! + When an Aggregate adopts a function \a fn that is a child of + another Aggregate, the function is inserted into this + Aggregate's function map. + + The function is also removed from the overload list + that's relative to the the original parent \a firstParent. + + \note This is a private function. + */ +void Aggregate::adoptFunction(FunctionNode *fn, Aggregate *firstParent) +{ + auto *primary = firstParent->m_functionMap.value(fn->name()); + if (primary) { + if (primary != fn) + primary->removeOverload(fn); + else if (primary->nextOverload()) + firstParent->m_functionMap.insert(primary->name(), + primary->nextOverload()); + /* else...technically we should call + firstParent->m_functionMap.remove(primary->name()); + but we want to be able to still find global functions + from the global namespace, even after adopting them + elsewhere. + */ + } + fn->setNextOverload(nullptr); + addFunction(fn); +} + +/*! + Adds the \a child to this node's child map using \a title + as the key. The \a child is not added to the child list + again, because it is presumed to already be there. We just + want to be able to find the child by its \a title. + */ +void Aggregate::addChildByTitle(Node *child, const QString &title) +{ + m_nonfunctionMap.insert(title, child); +} + +/*! + Adds the \a child to this node's child list and sets the child's + parent pointer to this Aggregate. It then mounts the child with + mountChild(). + + The \a child is then added to this Aggregate's searchable maps + and lists. + + \note This function does not test the child's parent pointer + for null before changing it. If the child's parent pointer + is not null, then it is being reparented. The child becomes + a child of this Aggregate, but it also remains a child of + the Aggregate that is it's old parent. But the child will + only have one parent, and it will be this Aggregate. The is + because of the \c relates command. + + \sa mountChild(), dismountChild() + */ +void Aggregate::addChild(Node *child) +{ + m_children.append(child); + child->setParent(this); + child->setOutputSubdirectory(this->outputSubdirectory()); + child->setUrl(QString()); + child->setIndexNodeFlag(isIndexNode()); + + if (child->isFunction()) { + addFunction(static_cast(child)); + } else if (!child->name().isEmpty()) { + m_nonfunctionMap.insert(child->name(), child); + if (child->isEnumType()) + m_enumChildren.append(child); + } +} + +/*! + This Aggregate becomes the adoptive parent of \a child. The + \a child knows this Aggregate as its parent, but its former + parent continues to have pointers to the child in its child + list and in its searchable data structures. But the child is + also added to the child list and searchable data structures + of this Aggregate. + */ +void Aggregate::adoptChild(Node *child) +{ + if (child->parent() != this) { + m_children.append(child); + auto firstParent = child->parent(); + child->setParent(this); + if (child->isFunction()) { + adoptFunction(static_cast(child), firstParent); + } else if (!child->name().isEmpty()) { + m_nonfunctionMap.insert(child->name(), child); + if (child->isEnumType()) + m_enumChildren.append(child); + } + if (child->isSharedCommentNode()) { + SharedCommentNode *scn = static_cast(child); + for (Node *n : scn->collective()) + adoptChild(n); + } + } +} + +/*! + Recursively sets the output subdirectory for children + */ +void Aggregate::setOutputSubdirectory(const QString &t) +{ + Node::setOutputSubdirectory(t); + for (auto *node : qAsConst(m_children)) + node->setOutputSubdirectory(t); +} + +/*! + If this node has a child that is a QML property or JS property + named \a n, return a pointer to that child. Otherwise, return \nullptr. + */ +QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n) const +{ + NodeType goal = Node::QmlProperty; + if (isJsNode()) + goal = Node::JsProperty; + for (auto *child : qAsConst(m_children)) { + if (child->nodeType() == goal) { + if (child->name() == n) + return static_cast(child); + } + } + return nullptr; +} + +/*! + If this node has a child that is a QML property or JS property + named \a n and that also matches \a attached, return a pointer + to that child. + */ +QmlPropertyNode *Aggregate::hasQmlProperty(const QString &n, bool attached) const +{ + NodeType goal = Node::QmlProperty; + if (isJsNode()) + goal = Node::JsProperty; + for (auto *child : qAsConst(m_children)) { + if (child->nodeType() == goal) { + if (child->name() == n && child->isAttached() == attached) + return static_cast(child); + } + } + return nullptr; +} + +/*! + The FunctionNode \a fn is assumed to be a member function + of this Aggregate. The function's name is looked up in the + Aggregate's function map. It should be found because it is + assumed that \a fn is in this Aggregate's function map. But + in case it is not found, \c false is returned. + + Normally, the name will be found in the function map, and + the value of the iterator is used to get the value, which + is a pointer to another FunctionNode, which is not itself + an overload. If that function has a non-null overload + pointer, true is returned. Otherwise false is returned. + + This is a convenience function that you should not need to + use. + */ +bool Aggregate::hasOverloads(const FunctionNode *fn) const +{ + auto it = m_functionMap.find(fn->name()); + return (it == m_functionMap.end() ? false : (it.value()->nextOverload() != nullptr)); +} + +/*! + Prints the inner node's list of children. + For debugging only. + */ +void Aggregate::printChildren(const QString &title) +{ + qDebug() << title << name() << m_children.size(); + if (m_children.size() > 0) { + for (int i = 0; i < m_children.size(); ++i) { + Node *n = m_children.at(i); + qDebug() << " CHILD:" << n->name() << n->nodeTypeString(); + } + } +} + +/*! + Removes \a fn from this aggregate's function map. That's + all it does. If \a fn is in the function map index and it + has an overload, the value pointer in the function map + index is set to the the overload pointer. If the function + has no overload pointer, the function map entry is erased. + + \note When removing a function node from the function map, + it is important to set the removed function node's next + overload pointer to null because the function node might + be added as a child to some other aggregate. + + \note This is a protected function. + */ +void Aggregate::removeFunctionNode(FunctionNode *fn) +{ + auto it = m_functionMap.find(fn->name()); + if (it != m_functionMap.end()) { + if (it.value() == fn) { + if (fn->nextOverload() != nullptr) { + it.value() = fn->nextOverload(); + fn->setNextOverload(nullptr); + fn->setOverloadNumber(0); + } else { + m_functionMap.erase(it); + } + } else { + FunctionNode *current = it.value(); + while (current != nullptr) { + if (current->nextOverload() == fn) { + current->setNextOverload(fn->nextOverload()); + fn->setNextOverload(nullptr); + fn->setOverloadNumber(0); + break; + } + current = current->nextOverload(); + } + } + } +} + +/* + When deciding whether to include a function in the function + index, if the function is marked private, don't include it. + If the function is marked obsolete, don't include it. If the + function is marked internal, don't include it. Or if the + function is a destructor or any kind of constructor, don't + include it. Otherwise include it. + */ +static bool keep(FunctionNode *fn) +{ + if (fn->isPrivate() || fn->isObsolete() || fn->isInternal() || fn->isSomeCtor() || fn->isDtor()) + return false; + return true; +} + +/*! + Insert all functions declared in this aggregate into the + \a functionIndex. Call the function recursively for each + child that is an aggregate. + + Only include functions that are in the public API and + that are not constructors or destructors. + */ +void Aggregate::findAllFunctions(NodeMapMap &functionIndex) +{ + for (auto it = m_functionMap.constBegin(); it != m_functionMap.constEnd(); ++it) { + FunctionNode *fn = it.value(); + if (keep(fn)) + functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn); + fn = fn->nextOverload(); + while (fn != nullptr) { + if (keep(fn)) + functionIndex[fn->name()].insert(fn->parent()->fullDocumentName(), fn); + fn = fn->nextOverload(); + } + } + for (Node *node : qAsConst(m_children)) { + if (node->isAggregate() && !node->isPrivate() && !node->isDontDocument()) + static_cast(node)->findAllFunctions(functionIndex); + } +} + +/*! + For each child of this node, if the child is a namespace node, + insert the child into the \a namespaces multimap. If the child + is an aggregate, call this function recursively for that child. + + When the function called with the root node of a tree, it finds + all the namespace nodes in that tree and inserts them into the + \a namespaces multimap. + + The root node of a tree is a namespace, but it has no name, so + it is not inserted into the map. So, if this function is called + for each tree in the qdoc database, it finds all the namespace + nodes in the database. + */ +void Aggregate::findAllNamespaces(NodeMultiMap &namespaces) +{ + for (auto *node : qAsConst(m_children)) { + if (node->isAggregate() && !node->isPrivate()) { + if (node->isNamespace() && !node->name().isEmpty()) + namespaces.insert(node->name(), node); + static_cast(node)->findAllNamespaces(namespaces); + } + } +} + +/*! + Returns true if this aggregate contains at least one child + that is marked obsolete. Otherwise returns false. + */ +bool Aggregate::hasObsoleteMembers() const +{ + for (const auto *node : m_children) { + if (!node->isPrivate() && node->isObsolete()) { + if (node->isFunction() || node->isProperty() || node->isEnumType() || node->isTypedef() + || node->isTypeAlias() || node->isVariable() || node->isQmlProperty() + || node->isJsProperty()) + return true; + } + } + return false; +} + +/*! + Finds all the obsolete C++ classes and QML types in this + aggregate and all the C++ classes and QML types with obsolete + members, and inserts them into maps used elsewhere for + generating documentation. + */ +void Aggregate::findAllObsoleteThings() +{ + for (auto *node : qAsConst(m_children)) { + if (!node->isPrivate()) { + QString name = node->name(); + if (node->isObsolete()) { + if (node->isClassNode()) + QDocDatabase::obsoleteClasses().insert(node->qualifyCppName(), node); + else if (node->isQmlType() || node->isJsType()) + QDocDatabase::obsoleteQmlTypes().insert(node->qualifyQmlName(), node); + } else if (node->isClassNode()) { + Aggregate *a = static_cast(node); + if (a->hasObsoleteMembers()) + QDocDatabase::classesWithObsoleteMembers().insert(node->qualifyCppName(), node); + } else if (node->isQmlType() || node->isJsType()) { + Aggregate *a = static_cast(node); + if (a->hasObsoleteMembers()) + QDocDatabase::qmlTypesWithObsoleteMembers().insert(node->qualifyQmlName(), + node); + } else if (node->isAggregate()) { + static_cast(node)->findAllObsoleteThings(); + } + } + } +} + +/*! + Finds all the C++ classes, QML types, JS types, QML and JS + basic types, and examples in this aggregate and inserts them + into appropriate maps for later use in generating documentation. + */ +void Aggregate::findAllClasses() +{ + for (auto *node : qAsConst(m_children)) { + if (!node->isPrivate() && !node->isInternal() && !node->isDontDocument() + && node->tree()->camelCaseModuleName() != QString("QDoc")) { + if (node->isClassNode()) { + QDocDatabase::cppClasses().insert(node->qualifyCppName().toLower(), node); + } else if (node->isQmlType() || node->isQmlBasicType() || node->isJsType() + || node->isJsBasicType()) { + QString name = node->unqualifyQmlName(); + QDocDatabase::qmlTypes().insert(name, node); + // also add to the QML basic type map + if (node->isQmlBasicType() || node->isJsBasicType()) + QDocDatabase::qmlBasicTypes().insert(name, node); + } else if (node->isExample()) { + // use the module index title as key for the example map + QString title = node->tree()->indexTitle(); + if (!QDocDatabase::examples().contains(title, node)) + QDocDatabase::examples().insert(title, node); + } else if (node->isAggregate()) { + static_cast(node)->findAllClasses(); + } + } + } +} + +/*! + Find all the attribution pages in this node and insert them + into \a attributions. + */ +void Aggregate::findAllAttributions(NodeMultiMap &attributions) +{ + for (auto *node : qAsConst(m_children)) { + if (!node->isPrivate()) { + if (node->pageType() == Node::AttributionPage) + attributions.insert(node->tree()->indexTitle(), node); + else if (node->isAggregate()) + static_cast(node)->findAllAttributions(attributions); + } + } +} + +/*! + Finds all the nodes in this node where a \e{since} command appeared + in the qdoc comment and sorts them into maps according to the kind + of node. + + This function is used for generating the "New Classes... in x.y" + section on the \e{What's New in Qt x.y} page. + */ +void Aggregate::findAllSince() +{ + for (auto *node : qAsConst(m_children)) { + if (node->isRelatedNonmember() && node->parent() != this) + continue; + QString sinceString = node->since(); + // Insert a new entry into each map for each new since string found. + if (!node->isPrivate() && !sinceString.isEmpty()) { + auto nsmap = QDocDatabase::newSinceMaps().find(sinceString); + if (nsmap == QDocDatabase::newSinceMaps().end()) + nsmap = QDocDatabase::newSinceMaps().insert(sinceString, {}); + + auto ncmap = QDocDatabase::newClassMaps().find(sinceString); + if (ncmap == QDocDatabase::newClassMaps().end()) + ncmap = QDocDatabase::newClassMaps().insert(sinceString, {}); + + auto nqcmap = QDocDatabase::newQmlTypeMaps().find(sinceString); + if (nqcmap == QDocDatabase::newQmlTypeMaps().end()) + nqcmap = QDocDatabase::newQmlTypeMaps().insert(sinceString, {}); + + if (node->isFunction()) { + // Insert functions into the general since map. + FunctionNode *fn = static_cast(node); + if (!fn->isObsolete() && !fn->isSomeCtor() && !fn->isDtor()) + nsmap.value().insert(fn->name(), fn); + } else if (node->isClassNode()) { + // Insert classes into the since and class maps. + QString name = node->qualifyWithParentName(); + nsmap.value().insert(name, node); + ncmap.value().insert(name, node); + } else if (node->isQmlType() || node->isJsType()) { + // Insert QML elements into the since and element maps. + QString name = node->qualifyWithParentName(); + nsmap.value().insert(name, node); + nqcmap.value().insert(name, node); + } else if (node->isQmlProperty() || node->isJsProperty()) { + // Insert QML properties into the since map. + nsmap.value().insert(node->name(), node); + } else { + // Insert external documents into the general since map. + QString name = node->qualifyWithParentName(); + nsmap.value().insert(name, node); + } + } + // Recursively find child nodes with since commands. + if (node->isAggregate()) + static_cast(node)->findAllSince(); + } +} + +/*! + Resolves the inheritance information for all QML type children + of this aggregate. +*/ +void Aggregate::resolveQmlInheritance() +{ + NodeMap previousSearches; + for (auto *child : qAsConst(m_children)) { + if (!child->isQmlType() && !child->isJsType()) + continue; + static_cast(child)->resolveInheritance(previousSearches); + } +} + +/*! + Returns a word representing the kind of Aggregate this node is. + Currently only works for class, struct, and union, but it can + easily be extended. If \a cap is true, the word is capitalised. + */ +QString Aggregate::typeWord(bool cap) const +{ + if (cap) { + switch (nodeType()) { + case Node::Class: + return QLatin1String("Class"); + case Node::Struct: + return QLatin1String("Struct"); + case Node::Union: + return QLatin1String("Union"); + default: + break; + } + } else { + switch (nodeType()) { + case Node::Class: + return QLatin1String("class"); + case Node::Struct: + return QLatin1String("struct"); + case Node::Union: + return QLatin1String("union"); + default: + break; + } + } + return QString(); +} + +/*! \fn int Aggregate::count() const + Returns the number of children in the child list. + */ + +/*! \fn const NodeList &Aggregate::childNodes() const + Returns a const reference to the child list. + */ + +/*! \fn NodeList::ConstIterator Aggregate::constBegin() const + Returns a const iterator pointing at the beginning of the child list. + */ + +/*! \fn NodeList::ConstIterator Aggregate::constEnd() const + Returns a const iterator pointing at the end of the child list. + */ + +/*! \fn const QStringList &Aggregate::includeFiles() const + This function returns a const reference to a list of strings, but + I no longer know what they are. + */ + +/*! \fn QmlTypeNode *Aggregate::qmlBaseNode() const + If this Aggregate is a QmlTypeNode, this function returns a pointer to + the QmlTypeNode that is its base type. Otherwise it returns \c nullptr. + A QmlTypeNode doesn't always have a base type, so even when this Aggregate + is aQmlTypeNode, the pointer returned can be \c nullptr. + */ + +/*! \fn FunctionMap &Aggregate::functionMap() + Returns a reference to this Aggregate's function map, which + is a map of all the children of this Aggregate that are + FunctionNodes. + */ + +/*! \fn void Aggregate::appendToRelatedByProxy(const NodeList &t) + Appends the list of node pointers to the list of elements that are + related to this Aggregate but are documented in a different module. + + \sa relatedByProxy() + */ + +/*! \fn NodeList &Aggregate::relatedByProxy() + Returns a reference to a list of node pointers where each element + points to a node in an index file for some other module, such that + whatever the node represents was documented in that other module, + but it is related to this Aggregate, so when the documentation for + this Aggregate is written, it will contain links to elements in the + other module. + */ + +QT_END_NAMESPACE diff --git a/src/qdoc/aggregate.h b/src/qdoc/aggregate.h new file mode 100644 index 0000000000..a8a8bb46c7 --- /dev/null +++ b/src/qdoc/aggregate.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AGGREGATE_H +#define AGGREGATE_H + +#include "pagenode.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class FunctionNode; +class QmlTypeNode; +class QmlPropertyNode; + +class Aggregate : public PageNode +{ +public: + Node *findChildNode(const QString &name, Node::Genus genus, int findFlags = 0) const; + Node *findNonfunctionChild(const QString &name, bool (Node::*)() const); + void findChildren(const QString &name, NodeVector &nodes) const; + FunctionNode *findFunctionChild(const QString &name, const Parameters ¶meters); + FunctionNode *findFunctionChild(const FunctionNode *clone); + + void normalizeOverloads(); + void markUndocumentedChildrenInternal(); + + bool isAggregate() const override { return true; } + const EnumNode *findEnumNodeForValue(const QString &enumValue) const; + + int count() const { return m_children.size(); } + const NodeList &childNodes() const { return m_children; } + const NodeList &nonfunctionList(); + NodeList::ConstIterator constBegin() const { return m_children.constBegin(); } + NodeList::ConstIterator constEnd() const { return m_children.constEnd(); } + + void addIncludeFile(const QString &includeFile); + void setIncludeFiles(const QStringList &includeFiles); + const QStringList &includeFiles() const { return m_includeFiles; } + + QStringList primaryKeys(); + QmlPropertyNode *hasQmlProperty(const QString &) const; + QmlPropertyNode *hasQmlProperty(const QString &, bool attached) const; + virtual QmlTypeNode *qmlBaseNode() const { return nullptr; } + void addChildByTitle(Node *child, const QString &title); + void printChildren(const QString &title); + void addChild(Node *child); + void adoptChild(Node *child); + void setOutputSubdirectory(const QString &t) override; + + FunctionMap &functionMap() { return m_functionMap; } + void findAllFunctions(NodeMapMap &functionIndex); + void findAllNamespaces(NodeMultiMap &namespaces); + void findAllAttributions(NodeMultiMap &attributions); + bool hasObsoleteMembers() const; + void findAllObsoleteThings(); + void findAllClasses(); + void findAllSince(); + void resolveQmlInheritance(); + bool hasOverloads(const FunctionNode *fn) const; + void appendToRelatedByProxy(const NodeList &t) { m_relatedByProxy.append(t); } + NodeList &relatedByProxy() { return m_relatedByProxy; } + QString typeWord(bool cap) const; + +protected: + Aggregate(NodeType type, Aggregate *parent, const QString &name) + : PageNode(type, parent, name) {} + ~Aggregate() override; + void removeFunctionNode(FunctionNode *fn); + +private: + friend class Node; + void addFunction(FunctionNode *fn); + void adoptFunction(FunctionNode *fn, Aggregate *firstParent); + static bool isSameSignature(const FunctionNode *f1, const FunctionNode *f2); + +protected: + NodeList m_children {}; + NodeList m_relatedByProxy {}; + FunctionMap m_functionMap {}; + +private: + QStringList m_includeFiles {}; + NodeList m_enumChildren {}; + NodeMultiMap m_nonfunctionMap {}; + NodeList m_nonfunctionList {}; +}; + +QT_END_NAMESPACE + +#endif // AGGREGATE_H diff --git a/src/qdoc/atom.cpp b/src/qdoc/atom.cpp index 43a164ada6..ee788ec2d4 100644 --- a/src/qdoc/atom.cpp +++ b/src/qdoc/atom.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,12 +26,15 @@ ** ****************************************************************************/ -#include #include "atom.h" + #include "location.h" +#include "proxynode.h" #include "qdocdatabase.h" -#include -#include + +#include + +#include QT_BEGIN_NAMESPACE @@ -142,120 +145,119 @@ QT_BEGIN_NAMESPACE QString Atom::noError_ = QString(); -static const struct { +static const struct +{ const char *english; int no; -} atms[] = { - { "AnnotatedList", Atom::AnnotatedList }, - { "AutoLink", Atom::AutoLink }, - { "BaseName", Atom::BaseName }, - { "br", Atom::BR}, - { "BriefLeft", Atom::BriefLeft }, - { "BriefRight", Atom::BriefRight }, - { "C", Atom::C }, - { "CaptionLeft", Atom::CaptionLeft }, - { "CaptionRight", Atom::CaptionRight }, - { "Code", Atom::Code }, - { "CodeBad", Atom::CodeBad }, - { "CodeNew", Atom::CodeNew }, - { "CodeOld", Atom::CodeOld }, - { "CodeQuoteArgument", Atom::CodeQuoteArgument }, - { "CodeQuoteCommand", Atom::CodeQuoteCommand }, - { "DivLeft", Atom::DivLeft }, - { "DivRight", Atom::DivRight }, - { "EndQmlText", Atom::EndQmlText }, - { "ExampleFileLink", Atom::ExampleFileLink}, - { "ExampleImageLink", Atom::ExampleImageLink}, - { "FootnoteLeft", Atom::FootnoteLeft }, - { "FootnoteRight", Atom::FootnoteRight }, - { "FormatElse", Atom::FormatElse }, - { "FormatEndif", Atom::FormatEndif }, - { "FormatIf", Atom::FormatIf }, - { "FormattingLeft", Atom::FormattingLeft }, - { "FormattingRight", Atom::FormattingRight }, - { "GeneratedList", Atom::GeneratedList }, - { "hr", Atom::HR}, - { "Image", Atom::Image }, - { "ImageText", Atom::ImageText }, - { "ImportantLeft", Atom::ImportantLeft }, - { "ImportantRight", Atom::ImportantRight }, - { "InlineImage", Atom::InlineImage }, - { "JavaScript", Atom::JavaScript }, - { "EndJavaScript", Atom::EndJavaScript }, - { "Keyword", Atom::Keyword }, - { "LegaleseLeft", Atom::LegaleseLeft }, - { "LegaleseRight", Atom::LegaleseRight }, - { "LineBreak", Atom::LineBreak }, - { "Link", Atom::Link }, - { "LinkNode", Atom::LinkNode }, - { "ListLeft", Atom::ListLeft }, - { "ListItemNumber", Atom::ListItemNumber }, - { "ListTagLeft", Atom::ListTagLeft }, - { "ListTagRight", Atom::ListTagRight }, - { "ListItemLeft", Atom::ListItemLeft }, - { "ListItemRight", Atom::ListItemRight }, - { "ListRight", Atom::ListRight }, - { "NavAutoLink", Atom::NavAutoLink }, - { "NavLink", Atom::NavLink }, - { "Nop", Atom::Nop }, - { "NoteLeft", Atom::NoteLeft }, - { "NoteRight", Atom::NoteRight }, - { "ParaLeft", Atom::ParaLeft }, - { "ParaRight", Atom::ParaRight }, - { "Qml", Atom::Qml}, - { "QmlText", Atom::QmlText }, - { "QuotationLeft", Atom::QuotationLeft }, - { "QuotationRight", Atom::QuotationRight }, - { "RawString", Atom::RawString }, - { "SectionLeft", Atom::SectionLeft }, - { "SectionRight", Atom::SectionRight }, - { "SectionHeadingLeft", Atom::SectionHeadingLeft }, - { "SectionHeadingRight", Atom::SectionHeadingRight }, - { "SidebarLeft", Atom::SidebarLeft }, - { "SidebarRight", Atom::SidebarRight }, - { "SinceList", Atom::SinceList }, - { "SinceTagLeft", Atom::SinceTagLeft }, - { "SinceTagRight", Atom::SinceTagRight }, - { "SnippetCommand", Atom::SnippetCommand }, - { "SnippetIdentifier", Atom::SnippetIdentifier }, - { "SnippetLocation", Atom::SnippetLocation }, - { "String", Atom::String }, - { "TableLeft", Atom::TableLeft }, - { "TableRight", Atom::TableRight }, - { "TableHeaderLeft", Atom::TableHeaderLeft }, - { "TableHeaderRight", Atom::TableHeaderRight }, - { "TableRowLeft", Atom::TableRowLeft }, - { "TableRowRight", Atom::TableRowRight }, - { "TableItemLeft", Atom::TableItemLeft }, - { "TableItemRight", Atom::TableItemRight }, - { "TableOfContents", Atom::TableOfContents }, - { "Target", Atom::Target }, - { "UnhandledFormat", Atom::UnhandledFormat }, - { "UnknownCommand", Atom::UnknownCommand }, - { nullptr, 0 } -}; - -/*! \fn Atom::Atom(AtomType type, const QString& string) +} atms[] = { { "AnnotatedList", Atom::AnnotatedList }, + { "AutoLink", Atom::AutoLink }, + { "BaseName", Atom::BaseName }, + { "br", Atom::BR }, + { "BriefLeft", Atom::BriefLeft }, + { "BriefRight", Atom::BriefRight }, + { "C", Atom::C }, + { "CaptionLeft", Atom::CaptionLeft }, + { "CaptionRight", Atom::CaptionRight }, + { "Code", Atom::Code }, + { "CodeBad", Atom::CodeBad }, + { "CodeNew", Atom::CodeNew }, + { "CodeOld", Atom::CodeOld }, + { "CodeQuoteArgument", Atom::CodeQuoteArgument }, + { "CodeQuoteCommand", Atom::CodeQuoteCommand }, + { "DivLeft", Atom::DivLeft }, + { "DivRight", Atom::DivRight }, + { "EndQmlText", Atom::EndQmlText }, + { "ExampleFileLink", Atom::ExampleFileLink }, + { "ExampleImageLink", Atom::ExampleImageLink }, + { "FootnoteLeft", Atom::FootnoteLeft }, + { "FootnoteRight", Atom::FootnoteRight }, + { "FormatElse", Atom::FormatElse }, + { "FormatEndif", Atom::FormatEndif }, + { "FormatIf", Atom::FormatIf }, + { "FormattingLeft", Atom::FormattingLeft }, + { "FormattingRight", Atom::FormattingRight }, + { "GeneratedList", Atom::GeneratedList }, + { "hr", Atom::HR }, + { "Image", Atom::Image }, + { "ImageText", Atom::ImageText }, + { "ImportantLeft", Atom::ImportantLeft }, + { "ImportantRight", Atom::ImportantRight }, + { "InlineImage", Atom::InlineImage }, + { "JavaScript", Atom::JavaScript }, + { "EndJavaScript", Atom::EndJavaScript }, + { "Keyword", Atom::Keyword }, + { "LegaleseLeft", Atom::LegaleseLeft }, + { "LegaleseRight", Atom::LegaleseRight }, + { "LineBreak", Atom::LineBreak }, + { "Link", Atom::Link }, + { "LinkNode", Atom::LinkNode }, + { "ListLeft", Atom::ListLeft }, + { "ListItemNumber", Atom::ListItemNumber }, + { "ListTagLeft", Atom::ListTagLeft }, + { "ListTagRight", Atom::ListTagRight }, + { "ListItemLeft", Atom::ListItemLeft }, + { "ListItemRight", Atom::ListItemRight }, + { "ListRight", Atom::ListRight }, + { "NavAutoLink", Atom::NavAutoLink }, + { "NavLink", Atom::NavLink }, + { "Nop", Atom::Nop }, + { "NoteLeft", Atom::NoteLeft }, + { "NoteRight", Atom::NoteRight }, + { "ParaLeft", Atom::ParaLeft }, + { "ParaRight", Atom::ParaRight }, + { "Qml", Atom::Qml }, + { "QmlText", Atom::QmlText }, + { "QuotationLeft", Atom::QuotationLeft }, + { "QuotationRight", Atom::QuotationRight }, + { "RawString", Atom::RawString }, + { "SectionLeft", Atom::SectionLeft }, + { "SectionRight", Atom::SectionRight }, + { "SectionHeadingLeft", Atom::SectionHeadingLeft }, + { "SectionHeadingRight", Atom::SectionHeadingRight }, + { "SidebarLeft", Atom::SidebarLeft }, + { "SidebarRight", Atom::SidebarRight }, + { "SinceList", Atom::SinceList }, + { "SinceTagLeft", Atom::SinceTagLeft }, + { "SinceTagRight", Atom::SinceTagRight }, + { "SnippetCommand", Atom::SnippetCommand }, + { "SnippetIdentifier", Atom::SnippetIdentifier }, + { "SnippetLocation", Atom::SnippetLocation }, + { "String", Atom::String }, + { "TableLeft", Atom::TableLeft }, + { "TableRight", Atom::TableRight }, + { "TableHeaderLeft", Atom::TableHeaderLeft }, + { "TableHeaderRight", Atom::TableHeaderRight }, + { "TableRowLeft", Atom::TableRowLeft }, + { "TableRowRight", Atom::TableRowRight }, + { "TableItemLeft", Atom::TableItemLeft }, + { "TableItemRight", Atom::TableItemRight }, + { "TableOfContents", Atom::TableOfContents }, + { "Target", Atom::Target }, + { "UnhandledFormat", Atom::UnhandledFormat }, + { "UnknownCommand", Atom::UnknownCommand }, + { nullptr, 0 } }; + +/*! \fn Atom::Atom(AtomType type, const QString &string) Constructs an atom of the specified \a type with the single parameter \a string and does not put the new atom in a list. */ -/*! \fn Atom::Atom(AtomType type, const QString& p1, const QString& p2) +/*! \fn Atom::Atom(AtomType type, const QString &p1, const QString &p2) Constructs an atom of the specified \a type with the two parameters \a p1 and \a p2 and does not put the new atom in a list. */ -/*! \fn Atom(Atom *previous, AtomType type, const QString& string) +/*! \fn Atom(Atom *previous, AtomType type, const QString &string) Constructs an atom of the specified \a type with the single parameter \a string and inserts the new atom into the list after the \a previous atom. */ -/*! \fn Atom::Atom(Atom* previous, AtomType type, const QString& p1, const QString& p2) +/*! \fn Atom::Atom(Atom *previous, AtomType type, const QString &p1, const QString &p2) Constructs an atom of the specified \a type with the two parameters \a p1 and \a p2 and inserts the new atom into @@ -269,7 +271,7 @@ static const struct { \also string() */ -/*! \fn void Atom::appendString(const QString& string) +/*! \fn void Atom::appendString(const QString &string) Appends \a string to the string parameter of this atom. @@ -290,7 +292,7 @@ static const struct { Return the next Atom in the list if it is of AtomType \a t. Otherwise return 0. */ -const Atom* Atom::next(AtomType t) const +const Atom *Atom::next(AtomType t) const { return (next_ && (next_->type() == t)) ? next_ : nullptr; } @@ -299,7 +301,7 @@ const Atom* Atom::next(AtomType t) const Return the next Atom in the list if it is of AtomType \a t and its string part is \a s. Otherwise return 0. */ -const Atom* Atom::next(AtomType t, const QString& s) const +const Atom *Atom::next(AtomType t, const QString &s) const { return (next_ && (next_->type() == t) && (next_->string() == s)) ? next_ : nullptr; } @@ -330,8 +332,9 @@ QString Atom::typeString() const int i = 0; while (atms[i].english != nullptr) { if (atms[i].no != i) - Location::internalError(QCoreApplication::translate("QDoc::Atom", "atom %1 missing").arg(i)); - i++; + Location::internalError( + QCoreApplication::translate("QDoc::Atom", "atom %1 missing").arg(i)); + ++i; } deja = true; } @@ -342,7 +345,7 @@ QString Atom::typeString() const return QLatin1String(atms[i].english); } -/*! \fn const QString& Atom::string() const +/*! \fn const QString &Atom::string() const Returns the string parameter that together with the type characterizes this atom. @@ -359,13 +362,31 @@ void Atom::dump() const str.replace(QLatin1String("\\"), QLatin1String("\\\\")); str.replace(QLatin1String("\""), QLatin1String("\\\"")); str.replace(QLatin1String("\n"), QLatin1String("\\n")); - str.replace(QRegExp(QLatin1String("[^\x20-\x7e]")), QLatin1String("?")); + str.replace(QRegularExpression(QLatin1String("[^\x20-\x7e]")), QLatin1String("?")); if (!str.isEmpty()) str = QLatin1String(" \"") + str + QLatin1Char('"'); - fprintf(stderr, - " %-15s%s\n", - typeString().toLatin1().data(), - str.toLatin1().data()); + fprintf(stderr, " %-15s%s\n", typeString().toLatin1().data(), str.toLatin1().data()); +} + +/*! + For a link atom, returns the string representing the link text + if one exist in the list of atoms. +*/ +QString Atom::linkText() const +{ + Q_ASSERT(type_ == Atom::Link); + QString result; + + if (next() && next()->string() == ATOM_FORMATTING_LINK) { + auto *atom = next()->next(); + while (atom && atom->type() != Atom::FormattingRight) { + result += atom->string(); + atom = atom->next(); + } + return result; + } + + return string(); } /*! @@ -376,8 +397,8 @@ void Atom::dump() const words separated by spaces. The constructor splits \a p2 on the space character. */ -LinkAtom::LinkAtom(const QString& p1, const QString& p2) - : Atom(p1), +LinkAtom::LinkAtom(const QString &p1, const QString &p2) + : Atom(Atom::Link, p1), resolved_(false), genus_(Node::DontCare), goal_(Node::NoType), @@ -396,31 +417,35 @@ void LinkAtom::resolveSquareBracketParams() { if (resolved_) return; - QStringList params = squareBracketParams_.toLower().split(QLatin1Char(' ')); - foreach (const QString& p, params) { + const QStringList params = squareBracketParams_.toLower().split(QLatin1Char(' ')); + for (const auto ¶m : params) { if (!domain_) { - domain_ = QDocDatabase::qdocDB()->findTree(p); + domain_ = QDocDatabase::qdocDB()->findTree(param); if (domain_) { - continue; + continue; } - } + } if (goal_ == Node::NoType) { - goal_ = Node::goal(p); + goal_ = Node::goal(param); if (goal_ != Node::NoType) continue; } - if (p == "qml") { + if (param == "qml") { genus_ = Node::QML; continue; } - if (p == "cpp") { + if (param == "cpp") { genus_ = Node::CPP; continue; } - if (p == "doc") { + if (param == "doc") { genus_ = Node::DOC; continue; } + if (param == "api") { + genus_ = Node::API; + continue; + } error_ = squareBracketParams_; break; } @@ -430,7 +455,7 @@ void LinkAtom::resolveSquareBracketParams() /*! Standard copy constructor of LinkAtom \a t. */ -LinkAtom::LinkAtom(const LinkAtom& t) +LinkAtom::LinkAtom(const LinkAtom &t) : Atom(Link, t.string()), resolved_(t.resolved_), genus_(t.genus_), @@ -447,7 +472,7 @@ LinkAtom::LinkAtom(const LinkAtom& t) where the new LinkAtom will not be the first one in the list. */ -LinkAtom::LinkAtom(Atom* previous, const LinkAtom& t) +LinkAtom::LinkAtom(Atom *previous, const LinkAtom &t) : Atom(previous, Link, t.string()), resolved_(t.resolved_), genus_(t.genus_), diff --git a/src/qdoc/atom.h b/src/qdoc/atom.h index b72264d180..b6d1a8840f 100644 --- a/src/qdoc/atom.h +++ b/src/qdoc/atom.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -29,9 +29,10 @@ #ifndef ATOM_H #define ATOM_H -#include #include "node.h" -#include + +#include +#include QT_BEGIN_NAMESPACE @@ -133,122 +134,125 @@ class Atom friend class LinkAtom; - Atom(const QString& string) - : next_(nullptr), type_(Link) - { - strs << string; - } - - Atom(AtomType type, const QString& string = "") - : next_(nullptr), type_(type) - { - strs << string; - } + explicit Atom(AtomType type, const QString &string = "") : type_(type), strs(string) {} - Atom(AtomType type, const QString& p1, const QString& p2) - : next_(nullptr), type_(type) + Atom(AtomType type, const QString &p1, const QString &p2) : type_(type), strs(p1) { - strs << p1; if (!p2.isEmpty()) strs << p2; } - Atom(Atom* previous, AtomType type, const QString& string = "") - : next_(previous->next_), type_(type) + Atom(Atom *previous, AtomType type, const QString &string) + : next_(previous->next_), type_(type), strs(string) { - strs << string; previous->next_ = this; } - Atom(Atom* previous, AtomType type, const QString& p1, const QString& p2) - : next_(previous->next_), type_(type) + Atom(Atom *previous, AtomType type, const QString &p1, const QString &p2) + : next_(previous->next_), type_(type), strs(p1) { - strs << p1; if (!p2.isEmpty()) strs << p2; previous->next_ = this; } - virtual ~Atom() { } + virtual ~Atom() = default; void appendChar(QChar ch) { strs[0] += ch; } - void appendString(const QString& string) { strs[0] += string; } + void appendString(const QString &string) { strs[0] += string; } void chopString() { strs[0].chop(1); } - void setString(const QString& string) { strs[0] = string; } - Atom* next() { return next_; } - void setNext(Atom* newNext) { next_ = newNext; } + void setString(const QString &string) { strs[0] = string; } + Atom *next() { return next_; } + void setNext(Atom *newNext) { next_ = newNext; } - const Atom* next() const { return next_; } - const Atom* next(AtomType t) const; - const Atom* next(AtomType t, const QString& s) const; + const Atom *next() const { return next_; } + const Atom *next(AtomType t) const; + const Atom *next(AtomType t, const QString &s) const; AtomType type() const { return type_; } QString typeString() const; - const QString& string() const { return strs[0]; } - const QString& string(int i) const { return strs[i]; } + const QString &string() const { return strs[0]; } + const QString &string(int i) const { return strs[i]; } int count() const { return strs.size(); } void dump() const; - const QStringList& strings() const { return strs; } + QString linkText() const; + const QStringList &strings() const { return strs; } virtual bool isLinkAtom() const { return false; } virtual Node::Genus genus() { return Node::DontCare; } virtual bool specifiesDomain() { return false; } - virtual Tree* domain() { return nullptr; } + virtual Tree *domain() { return nullptr; } virtual Node::NodeType goal() { return Node::NoType; } - virtual const QString& error() { return noError_; } - virtual void resolveSquareBracketParams() { } + virtual const QString &error() { return noError_; } + virtual void resolveSquareBracketParams() {} - protected: +protected: static QString noError_; - Atom* next_; + Atom *next_ = nullptr; AtomType type_; QStringList strs; }; class LinkAtom : public Atom { - public: - LinkAtom(const QString& p1, const QString& p2); - LinkAtom(const LinkAtom& t); - LinkAtom(Atom* previous, const LinkAtom& t); - virtual ~LinkAtom() { } +public: + LinkAtom(const QString &p1, const QString &p2); + LinkAtom(const LinkAtom &t); + LinkAtom(Atom *previous, const LinkAtom &t); + ~LinkAtom() override = default; bool isLinkAtom() const override { return true; } - Node::Genus genus() override { resolveSquareBracketParams(); return genus_; } - bool specifiesDomain() override { resolveSquareBracketParams(); return (domain_ != nullptr); } - Tree* domain() override { resolveSquareBracketParams(); return domain_; } - Node::NodeType goal() override { resolveSquareBracketParams(); return goal_; } - const QString& error() override { return error_; } + Node::Genus genus() override + { + resolveSquareBracketParams(); + return genus_; + } + bool specifiesDomain() override + { + resolveSquareBracketParams(); + return (domain_ != nullptr); + } + Tree *domain() override + { + resolveSquareBracketParams(); + return domain_; + } + Node::NodeType goal() override + { + resolveSquareBracketParams(); + return goal_; + } + const QString &error() override { return error_; } void resolveSquareBracketParams() override; - protected: - bool resolved_; +protected: + bool resolved_; Node::Genus genus_; - Node::NodeType goal_; - Tree* domain_; - QString error_; - QString squareBracketParams_; + Node::NodeType goal_; + Tree *domain_; + QString error_; + QString squareBracketParams_; }; -#define ATOM_FORMATTING_BOLD "bold" -#define ATOM_FORMATTING_INDEX "index" -#define ATOM_FORMATTING_ITALIC "italic" -#define ATOM_FORMATTING_LINK "link" -#define ATOM_FORMATTING_PARAMETER "parameter" -#define ATOM_FORMATTING_SPAN "span " -#define ATOM_FORMATTING_SUBSCRIPT "subscript" -#define ATOM_FORMATTING_SUPERSCRIPT "superscript" -#define ATOM_FORMATTING_TELETYPE "teletype" -#define ATOM_FORMATTING_UICONTROL "uicontrol" -#define ATOM_FORMATTING_UNDERLINE "underline" - -#define ATOM_LIST_BULLET "bullet" -#define ATOM_LIST_TAG "tag" -#define ATOM_LIST_VALUE "value" -#define ATOM_LIST_LOWERALPHA "loweralpha" -#define ATOM_LIST_LOWERROMAN "lowerroman" -#define ATOM_LIST_NUMERIC "numeric" -#define ATOM_LIST_UPPERALPHA "upperalpha" -#define ATOM_LIST_UPPERROMAN "upperroman" +#define ATOM_FORMATTING_BOLD "bold" +#define ATOM_FORMATTING_INDEX "index" +#define ATOM_FORMATTING_ITALIC "italic" +#define ATOM_FORMATTING_LINK "link" +#define ATOM_FORMATTING_PARAMETER "parameter" +#define ATOM_FORMATTING_SPAN "span " +#define ATOM_FORMATTING_SUBSCRIPT "subscript" +#define ATOM_FORMATTING_SUPERSCRIPT "superscript" +#define ATOM_FORMATTING_TELETYPE "teletype" +#define ATOM_FORMATTING_UICONTROL "uicontrol" +#define ATOM_FORMATTING_UNDERLINE "underline" + +#define ATOM_LIST_BULLET "bullet" +#define ATOM_LIST_TAG "tag" +#define ATOM_LIST_VALUE "value" +#define ATOM_LIST_LOWERALPHA "loweralpha" +#define ATOM_LIST_LOWERROMAN "lowerroman" +#define ATOM_LIST_NUMERIC "numeric" +#define ATOM_LIST_UPPERALPHA "upperalpha" +#define ATOM_LIST_UPPERROMAN "upperroman" QT_END_NAMESPACE diff --git a/src/qdoc/clangcodeparser.cpp b/src/qdoc/clangcodeparser.cpp index 4eaab69d7e..5bb32ab504 100644 --- a/src/qdoc/clangcodeparser.cpp +++ b/src/qdoc/clangcodeparser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -41,30 +41,45 @@ clangcodeparser.cpp */ -#include -#include -#include +#include "clangcodeparser.h" + +#include "access.h" +#include "classnode.h" #include "codechunk.h" #include "config.h" -#include "clangcodeparser.h" -#include "generator.h" -#include "loggingcategory.h" +#include "enumnode.h" +#include "functionnode.h" +#include "namespacenode.h" +#include "propertynode.h" #include "qdocdatabase.h" -#include -#include -#include -#include -#include "generator.h" +#include "typedefnode.h" +#include "utilities.h" +#include "variablenode.h" + +#include +#include +#include +#include +#include #include +#include + QT_BEGIN_NAMESPACE +// We're printing diagnostics in ClangCodeParser::printDiagnostics, +// so avoid clang itself printing them. +static const auto kClangDontDisplayDiagnostics = 0; + static CXTranslationUnit_Flags flags_ = static_cast(0); static CXIndex index_ = nullptr; +QByteArray ClangCodeParser::s_fn; +constexpr const char *fnDummyFileName = "/fn_dummyfile.cpp"; + #ifndef QT_NO_DEBUG_STREAM -template +template static QDebug operator<<(QDebug debug, const std::vector &v) { QDebugStateSaver saver(debug); @@ -87,10 +102,13 @@ static QDebug operator<<(QDebug debug, const std::vector &v) T can be any functor that is callable with a CXCursor parameter and returns a CXChildVisitResult (in other word compatible with function */ -template bool visitChildrenLambda(CXCursor cursor, T &&lambda) +template +bool visitChildrenLambda(CXCursor cursor, T &&lambda) { - CXCursorVisitor visitor = [](CXCursor c, CXCursor , CXClientData client_data) -> CXChildVisitResult - { return (*static_cast(client_data))(c); }; + CXCursorVisitor visitor = [](CXCursor c, CXCursor, + CXClientData client_data) -> CXChildVisitResult { + return (*static_cast(client_data))(c); + }; return clang_visitChildren(cursor, visitor, &lambda); } @@ -104,6 +122,53 @@ static QString fromCXString(CXString &&string) return ret; } +static QString templateDecl(CXCursor cursor); + +/*! + Returns a list of template parameters at \a cursor. +*/ +static QStringList getTemplateParameters(CXCursor cursor) +{ + QStringList parameters; + visitChildrenLambda(cursor, [¶meters](CXCursor cur) { + QString name = fromCXString(clang_getCursorSpelling(cur)); + QString type; + + switch (clang_getCursorKind(cur)) { + case CXCursor_TemplateTypeParameter: + type = QStringLiteral("typename"); + break; + case CXCursor_NonTypeTemplateParameter: + type = fromCXString(clang_getTypeSpelling(clang_getCursorType(cur))); + // Hack: Omit QtPrivate template parameters from public documentation + if (type.startsWith(QLatin1String("QtPrivate"))) + return CXChildVisit_Continue; + break; + case CXCursor_TemplateTemplateParameter: + type = templateDecl(cur) + QLatin1String(" class"); + break; + default: + return CXChildVisit_Continue; + } + + if (!name.isEmpty()) + name.prepend(QLatin1Char(' ')); + + parameters << type + name; + return CXChildVisit_Continue; + }); + + return parameters; +} + +/*! + Gets the template declaration at specified \a cursor. + */ +static QString templateDecl(CXCursor cursor) +{ + QStringList params = getTemplateParameters(cursor); + return QLatin1String("template <") + params.join(QLatin1String(", ")) + QLatin1Char('>'); +} /*! convert a CXSourceLocation to a qdoc Location @@ -122,12 +187,17 @@ static Location fromCXSourceLocation(CXSourceLocation location) /*! convert a CX_CXXAccessSpecifier to Node::Access */ -static Node::Access fromCX_CXXAccessSpecifier(CX_CXXAccessSpecifier spec) { +static Access fromCX_CXXAccessSpecifier(CX_CXXAccessSpecifier spec) +{ switch (spec) { - case CX_CXXPrivate: return Node::Private; - case CX_CXXProtected: return Node::Protected; - case CX_CXXPublic: return Node::Public; - default: return Node::Public; + case CX_CXXPrivate: + return Access::Private; + case CX_CXXProtected: + return Access::Protected; + case CX_CXXPublic: + return Access::Public; + default: + return Access::Public; } } @@ -142,16 +212,19 @@ static QString getSpelling(CXSourceRange range) unsigned int offset1, offset2; clang_getFileLocation(start, &file1, nullptr, nullptr, &offset1); clang_getFileLocation(end, &file2, nullptr, nullptr, &offset2); + if (file1 != file2 || offset2 <= offset1) return QString(); QFile file(fromCXString(clang_getFileName(file1))); - if (!file.open(QFile::ReadOnly)) + if (!file.open(QFile::ReadOnly)) { + if (file.fileName() == fnDummyFileName) + return QString::fromUtf8(ClangCodeParser::fn().mid(offset1, offset2 - offset1)); return QString(); + } file.seek(offset1); return QString::fromUtf8(file.read(offset2 - offset1)); } - /*! Returns the function name from a given cursor representing a function declaration. This is usually clang_getCursorSpelling, but @@ -160,9 +233,9 @@ static QString getSpelling(CXSourceRange range) QString functionName(CXCursor cursor) { if (clang_getCursorKind(cursor) == CXCursor_ConversionFunction) { - // For a CXCursor_ConversionFunction we don't want the spelling which would be something like - // "operator type-parameter-0-0" or "operator unsigned int". - // we want the actual name as spelled; + // For a CXCursor_ConversionFunction we don't want the spelling which would be something + // like "operator type-parameter-0-0" or "operator unsigned int". we want the actual name as + // spelled; QString type = fromCXString(clang_getTypeSpelling(clang_getCursorResultType(cursor))); if (type.isEmpty()) return fromCXString(clang_getCursorSpelling(cursor)); @@ -182,7 +255,8 @@ QString functionName(CXCursor cursor) Reconstruct the qualified path name of a function that is being overridden. */ -static QString reconstructQualifiedPathForCursor(CXCursor cur) { +static QString reconstructQualifiedPathForCursor(CXCursor cur) +{ QString path; auto kind = clang_getCursorKind(cur); while (!clang_isInvalid(kind) && kind != CXCursor_TranslationUnit) { @@ -216,7 +290,8 @@ static QString reconstructQualifiedPathForCursor(CXCursor cur) { Find the node from the QDocDatabase \a qdb that corrseponds to the declaration represented by the cursor \a cur, if it exists. */ -static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) { +static Node *findNodeForCursor(QDocDatabase *qdb, CXCursor cur) +{ auto kind = clang_getCursorKind(cur); if (clang_isInvalid(kind)) return nullptr; @@ -256,30 +331,39 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) { for (Node *candidate : qAsConst(candidates)) { if (!candidate->isFunction(Node::CPP)) continue; - auto fn = static_cast(candidate); + auto fn = static_cast(candidate); const Parameters ¶meters = fn->parameters(); - const int actualArg = numArg - parameters.isPrivateSignal(); - if (parameters.count() != actualArg + isVariadic) + if (parameters.count() != numArg + isVariadic) continue; if (fn->isConst() != bool(clang_CXXMethod_isConst(cur))) continue; if (isVariadic && parameters.last().type() != QLatin1String("...")) continue; bool different = false; - for (int i = 0; i < actualArg; i++) { + for (int i = 0; i < numArg; ++i) { + CXType argType = clang_getArgType(funcType, i); if (args.size() <= i) - args.append(fromCXString(clang_getTypeSpelling(clang_getArgType(funcType, i)))); - QString t1 = parameters.at(i).type(); - QString t2 = args.at(i); - auto p2 = parent; - while (p2 && t1 != t2) { - QString parentScope = p2->name() + QLatin1String("::"); - t1 = t1.remove(parentScope); - t2 = t2.remove(parentScope); - p2 = p2->parent(); + args.append(fromCXString(clang_getTypeSpelling(argType))); + QString recordedType = parameters.at(i).type(); + QString typeSpelling = args.at(i); + auto p = parent; + while (p && recordedType != typeSpelling) { + QString parentScope = p->name() + QLatin1String("::"); + recordedType.remove(parentScope); + typeSpelling.remove(parentScope); + p = p->parent(); } - if (t1 != t2) { - different = true; + different = recordedType != typeSpelling; + + // Retry with a canonical type spelling + if (different && (argType.kind == CXType_Typedef || argType.kind == CXType_Elaborated)) { + QStringView canonicalType = parameters.at(i).canonicalType(); + if (!canonicalType.isEmpty()) { + different = canonicalType != + fromCXString(clang_getTypeSpelling(clang_getCanonicalType(argType))); + } + } + if (different) { break; } } @@ -300,84 +384,31 @@ static Node *findNodeForCursor(QDocDatabase* qdb, CXCursor cur) { } } -/*! - Find the function node from the QDocDatabase \a qdb that - corrseponds to the declaration represented by the cursor - \a cur, if it exists. - */ -static Node *findFunctionNodeForCursor(QDocDatabase* qdb, CXCursor cur) { - auto kind = clang_getCursorKind(cur); - if (clang_isInvalid(kind)) - return nullptr; - if (kind == CXCursor_TranslationUnit) - return qdb->primaryTreeRoot(); - - Node *p = findNodeForCursor(qdb, clang_getCursorSemanticParent(cur)); - if (p == nullptr || !p->isAggregate()) - return nullptr; - auto parent = static_cast(p); - - switch (kind) { - case CXCursor_FunctionDecl: - case CXCursor_FunctionTemplate: - case CXCursor_CXXMethod: - case CXCursor_Constructor: - case CXCursor_Destructor: - case CXCursor_ConversionFunction: { - NodeVector candidates; - parent->findChildren(functionName(cur), candidates); - if (candidates.isEmpty()) - return nullptr; - CXType funcType = clang_getCursorType(cur); - auto numArg = clang_getNumArgTypes(funcType); - bool isVariadic = clang_isFunctionTypeVariadic(funcType); - QVarLengthArray args; - for (Node *candidate : qAsConst(candidates)) { - if (!candidate->isFunction(Node::CPP)) - continue; - auto fn = static_cast(candidate); - const Parameters ¶meters = fn->parameters(); - if (parameters.count() != (numArg + isVariadic)) - continue; - if (fn->isConst() != bool(clang_CXXMethod_isConst(cur))) - continue; - if (isVariadic && parameters.last().type() != QLatin1String("...")) - continue; - bool different = false; - for (int i = 0; i < numArg; i++) { - if (args.size() <= i) - args.append(fromCXString(clang_getTypeSpelling(clang_getArgType(funcType, i)))); - QString t1 = parameters.at(i).type(); - QString t2 = args.at(i); - auto p2 = parent; - while (p2 && t1 != t2) { - QString parentScope = p2->name() + QLatin1String("::"); - t1 = t1.remove(parentScope); - t2 = t2.remove(parentScope); - p2 = p2->parent(); - } - if (t1 != t2) { - different = true; - break; - } - } - if (!different) - return fn; +static void setOverridesForFunction(FunctionNode *fn, CXCursor cursor) +{ + CXCursor *overridden; + unsigned int numOverridden = 0; + clang_getOverriddenCursors(cursor, &overridden, &numOverridden); + for (uint i = 0; i < numOverridden; ++i) { + QString path = reconstructQualifiedPathForCursor(overridden[i]); + if (!path.isEmpty()) { + fn->setOverride(true); + fn->setOverridesThis(path); + break; } - break; - } - default: - break; } - return nullptr; + clang_disposeOverriddenCursors(overridden); } -class ClangVisitor { +class ClangVisitor +{ public: ClangVisitor(QDocDatabase *qdb, const QHash &allHeaders) - : qdb_(qdb), parent_(qdb->primaryTreeRoot()), allHeaders_(allHeaders) { } + : qdb_(qdb), parent_(qdb->primaryTreeRoot()), allHeaders_(allHeaders) + { + } - QDocDatabase* qdocDB() { return qdb_; } + QDocDatabase *qdocDB() { return qdb_; } CXChildVisitResult visitChildren(CXCursor cursor) { @@ -410,7 +441,7 @@ class ClangVisitor { Not sure about all the possibilities, when the cursor location is not in the main file. */ - CXChildVisitResult visitFnArg(CXCursor cursor, Node** fnNode, bool &ignoreSignature) + CXChildVisitResult visitFnArg(CXCursor cursor, Node **fnNode, bool &ignoreSignature) { auto ret = visitChildrenLambda(cursor, [&](CXCursor cur) { auto loc = clang_getCursorLocation(cur); @@ -422,6 +453,7 @@ class ClangVisitor { } Node *nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocation nextCommentLoc); + private: /*! SimpleLoc represents a simple location in the main source file, @@ -430,7 +462,8 @@ class ClangVisitor { struct SimpleLoc { unsigned int line, column; - friend bool operator<(const SimpleLoc &a, const SimpleLoc &b) { + friend bool operator<(const SimpleLoc &a, const SimpleLoc &b) + { return a.line != b.line ? a.line < b.line : a.column < b.column; } }; @@ -441,17 +474,22 @@ class ClangVisitor { */ QMap declMap_; - QDocDatabase* qdb_; + QDocDatabase *qdb_; Aggregate *parent_; + bool m_friendDecl { false }; // true if currently visiting a friend declaration const QHash allHeaders_; QHash isInterestingCache_; // doing a canonicalFilePath is slow, so keep a cache. /*! Returns true if the symbol should be ignored for the documentation. */ - bool ignoredSymbol(const QString &symbolName) { + bool ignoredSymbol(const QString &symbolName) + { if (symbolName == QLatin1String("QPrivateSignal")) return true; + // Ignore functions generated by property macros + if (symbolName.startsWith("_qt_property_")) + return true; return false; } @@ -461,18 +499,19 @@ class ClangVisitor { example: 'QLinkedList::iterator' -> 'iterator' */ - QString adjustTypeName(const QString &typeName) { + QString adjustTypeName(const QString &typeName) + { auto parent = parent_->parent(); if (parent && parent->isClassNode()) { - QStringRef typeNameConstRemoved(&typeName); + QStringView typeNameConstRemoved(typeName); if (typeNameConstRemoved.startsWith(QLatin1String("const "))) - typeNameConstRemoved = typeName.midRef(6); + typeNameConstRemoved = typeNameConstRemoved.mid(6); auto parentName = parent->fullName(); if (typeNameConstRemoved.startsWith(parentName) - && typeNameConstRemoved.mid(parentName.size(), 2) == QLatin1String("::")) { + && typeNameConstRemoved.mid(parentName.size(), 2) == QLatin1String("::")) { QString result = typeName; - result.remove(typeNameConstRemoved.position(), parentName.size() + 2); + result.remove(typeName.indexOf(typeNameConstRemoved), parentName.size() + 2); return result; } } @@ -481,9 +520,11 @@ class ClangVisitor { CXChildVisitResult visitSource(CXCursor cursor, CXSourceLocation loc); CXChildVisitResult visitHeader(CXCursor cursor, CXSourceLocation loc); - CXChildVisitResult visitFnSignature(CXCursor cursor, CXSourceLocation loc, Node** fnNode, bool &ignoreSignature); - void parseProperty(const QString &spelling, const Location &loc); - void readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cursor); + CXChildVisitResult visitFnSignature(CXCursor cursor, CXSourceLocation loc, Node **fnNode, + bool &ignoreSignature); + void processFunction(FunctionNode *fn, CXCursor cursor); + bool parseProperty(const QString &spelling, const Location &loc); + void readParameterNamesAndAttributes(FunctionNode *fn, CXCursor cursor); Aggregate *getSemanticParent(CXCursor cursor); }; @@ -513,17 +554,20 @@ Aggregate *ClangVisitor::getSemanticParent(CXCursor cursor) CXCursor sp = clang_getCursorSemanticParent(cursor); CXCursor lp = clang_getCursorLexicalParent(cursor); if (!clang_equalCursors(sp, lp) && clang_isDeclaration(clang_getCursorKind(sp))) { - Node* spn = findNodeForCursor(qdb_, sp); + Node *spn = findNodeForCursor(qdb_, sp); if (spn && spn->isAggregate()) { - return static_cast(spn); + return static_cast(spn); } } return parent_; } -CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocation , Node** fnNode, bool &ignoreSignature) +CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocation, Node **fnNode, + bool &ignoreSignature) { switch (clang_getCursorKind(cursor)) { + case CXCursor_Namespace: + return CXChildVisit_Recurse; case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: case CXCursor_CXXMethod: @@ -535,10 +579,27 @@ CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocat *fnNode = nullptr; ignoreSignature = true; } else { - *fnNode = findFunctionNodeForCursor(qdb_, cursor); - if (*fnNode && (*fnNode)->isFunction(Node::CPP)) { - FunctionNode* fn = static_cast(*fnNode); + *fnNode = findNodeForCursor(qdb_, cursor); + if (*fnNode) { + if ((*fnNode)->isFunction(Node::CPP)) { + FunctionNode *fn = static_cast(*fnNode); readParameterNamesAndAttributes(fn, cursor); + } + } else { // Possibly an implicitly generated special member + QString name = functionName(cursor); + if (ignoredSymbol(name)) + return CXChildVisit_Continue; + Aggregate *semanticParent = getSemanticParent(cursor); + if (semanticParent && semanticParent->isClass()) { + auto *candidate = new FunctionNode(nullptr, name); + processFunction(candidate, cursor); + if (!candidate->isSpecialMemberFunction()) { + delete candidate; + return CXChildVisit_Continue; + } + candidate->setDefault(true); + semanticParent->addChild(*fnNode = candidate); + } } } break; @@ -552,19 +613,26 @@ CXChildVisitResult ClangVisitor::visitFnSignature(CXCursor cursor, CXSourceLocat CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation loc) { auto kind = clang_getCursorKind(cursor); + QString templateString; switch (kind) { + case CXCursor_TypeAliasTemplateDecl: case CXCursor_TypeAliasDecl: { - QString spelling = getSpelling(clang_getCursorExtent(cursor)); - QStringList typeAlias = spelling.split(QChar('=')); + QString aliasDecl = getSpelling(clang_getCursorExtent(cursor)).simplified(); + QStringList typeAlias = aliasDecl.split(QLatin1Char('=')); if (typeAlias.size() == 2) { typeAlias[0] = typeAlias[0].trimmed(); - typeAlias[1] = typeAlias[1].trimmed(); - int lastBlank = typeAlias[0].lastIndexOf(QChar(' ')); - if (lastBlank > 0) { - typeAlias[0] = typeAlias[0].right(typeAlias[0].size() - (lastBlank + 1)); - TypeAliasNode* ta = new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]); + const QLatin1String usingString("using "); + int usingPos = typeAlias[0].indexOf(usingString); + if (usingPos != -1) { + if (kind == CXCursor_TypeAliasTemplateDecl) + templateString = typeAlias[0].left(usingPos).trimmed(); + typeAlias[0].remove(0, usingPos + usingString.size()); + typeAlias[0] = typeAlias[0].split(QLatin1Char(' ')).first(); + typeAlias[1] = typeAlias[1].trimmed(); + TypeAliasNode *ta = new TypeAliasNode(parent_, typeAlias[0], typeAlias[1]); ta->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); ta->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); + ta->setTemplateDecl(templateString); } } return CXChildVisit_Continue; @@ -574,40 +642,41 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l if (fromCXString(clang_getCursorSpelling(cursor)).isEmpty()) // anonymous struct or union return CXChildVisit_Continue; Q_FALLTHROUGH(); - case CXCursor_ClassDecl: - case CXCursor_ClassTemplate: { + case CXCursor_ClassTemplate: + templateString = templateDecl(cursor); + Q_FALLTHROUGH(); + case CXCursor_ClassDecl: { if (!clang_isCursorDefinition(cursor)) return CXChildVisit_Continue; - if (findNodeForCursor(qdb_, cursor)) // Was already parsed, propably in another translation unit + if (findNodeForCursor(qdb_, cursor)) // Was already parsed, probably in another TU return CXChildVisit_Continue; QString className = fromCXString(clang_getCursorSpelling(cursor)); - Aggregate* semanticParent = getSemanticParent(cursor); + Aggregate *semanticParent = getSemanticParent(cursor); if (semanticParent && semanticParent->findNonfunctionChild(className, &Node::isClassNode)) { return CXChildVisit_Continue; } - Node::NodeType type; - if (kind == CXCursor_ClassDecl || kind == CXCursor_ClassTemplate) - type = Node::Class; - else if (kind == CXCursor_StructDecl) + CXCursorKind actualKind = (kind == CXCursor_ClassTemplate) ? + clang_getTemplateCursorKind(cursor) : kind; + + Node::NodeType type = Node::Class; + if (actualKind == CXCursor_StructDecl) type = Node::Struct; - else + else if (actualKind == CXCursor_UnionDecl) type = Node::Union; + ClassNode *classe = new ClassNode(type, semanticParent, className); classe->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); classe->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); - if (kind == CXCursor_ClassTemplate) { - QString displayName = fromCXString(clang_getCursorSpelling(cursor)); - classe->setTemplateStuff(displayName.mid(className.size())); - } + if (kind == CXCursor_ClassTemplate) + classe->setTemplateDecl(templateString); QScopedValueRollback setParent(parent_, classe); return visitChildren(cursor); - } case CXCursor_CXXBaseSpecifier: { if (!parent_->isClassNode()) @@ -616,45 +685,46 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l auto type = clang_getCursorType(cursor); auto baseCursor = clang_getTypeDeclaration(type); auto baseNode = findNodeForCursor(qdb_, baseCursor); - auto classe = static_cast(parent_); + auto classe = static_cast(parent_); if (baseNode == nullptr || !baseNode->isClassNode()) { - QString bcName = fromCXString(clang_getCursorSpelling(baseCursor)); - classe->addUnresolvedBaseClass(access, QStringList(bcName), bcName); + QString bcName = reconstructQualifiedPathForCursor(baseCursor); + classe->addUnresolvedBaseClass( + access, bcName.split(QLatin1String("::"), Qt::SkipEmptyParts), bcName); return CXChildVisit_Continue; } - auto baseClasse = static_cast(baseNode); + auto baseClasse = static_cast(baseNode); classe->addResolvedBaseClass(access, baseClasse); return CXChildVisit_Continue; } case CXCursor_Namespace: { QString namespaceName = fromCXString(clang_getCursorDisplayName(cursor)); - NamespaceNode* ns = nullptr; + NamespaceNode *ns = nullptr; if (parent_) - ns = static_cast(parent_->findNonfunctionChild(namespaceName, &Node::isNamespace)); + ns = static_cast( + parent_->findNonfunctionChild(namespaceName, &Node::isNamespace)); if (!ns) { ns = new NamespaceNode(parent_, namespaceName); - ns->setAccess(Node::Public); + ns->setAccess(Access::Public); ns->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); } QScopedValueRollback setParent(parent_, ns); return visitChildren(cursor); } - case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: + templateString = templateDecl(cursor); + Q_FALLTHROUGH(); + case CXCursor_FunctionDecl: case CXCursor_CXXMethod: case CXCursor_Constructor: case CXCursor_Destructor: case CXCursor_ConversionFunction: { - if (findNodeForCursor(qdb_, cursor)) // Was already parsed, propably in another translation unit + if (findNodeForCursor(qdb_, cursor)) // Was already parsed, probably in another TU return CXChildVisit_Continue; QString name = functionName(cursor); if (ignoredSymbol(name)) return CXChildVisit_Continue; - CXType funcType = clang_getCursorType(cursor); - - FunctionNode* fn = new FunctionNode(parent_, name); - + FunctionNode *fn = new FunctionNode(parent_, name); CXSourceRange range = clang_Cursor_getCommentRange(cursor); if (!clang_Range_isNull(range)) { QString comment = getSpelling(range); @@ -667,111 +737,41 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l } } } - fn->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); - fn->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); - if (kind == CXCursor_Constructor - // a constructor template is classified as CXCursor_FunctionTemplate - || (kind == CXCursor_FunctionTemplate && name == parent_->name())) - fn->setMetaness(FunctionNode::Ctor); - else if (kind == CXCursor_Destructor) - fn->setMetaness(FunctionNode::Dtor); - else - fn->setReturnType(adjustTypeName(fromCXString( - clang_getTypeSpelling(clang_getResultType(funcType))))); - - fn->setStatic(clang_CXXMethod_isStatic(cursor)); - fn->setConst(clang_CXXMethod_isConst(cursor)); - fn->setVirtualness(!clang_CXXMethod_isVirtual(cursor) ? FunctionNode::NonVirtual - : clang_CXXMethod_isPureVirtual(cursor) ? FunctionNode::PureVirtual - : FunctionNode::NormalVirtual); - CXRefQualifierKind refQualKind = clang_Type_getCXXRefQualifier(funcType); - if (refQualKind == CXRefQualifier_LValue) - fn->setRef(true); - else if (refQualKind == CXRefQualifier_RValue) - fn->setRefRef(true); - // For virtual functions, determine what it overrides - // (except for destructor for which we do not want to classify as overridden) - if (!fn->isNonvirtual() && kind != CXCursor_Destructor) { - CXCursor *overridden; - unsigned int numOverridden = 0; - clang_getOverriddenCursors(cursor, &overridden, &numOverridden); - for (uint i = 0; i < numOverridden; ++i) { - QString path = reconstructQualifiedPathForCursor(overridden[i]); - if (!path.isEmpty()) { - fn->setOverride(true); - fn->setOverridesThis(path); - break; - } - } - clang_disposeOverriddenCursors(overridden); - } - auto numArg = clang_getNumArgTypes(funcType); - Parameters ¶meters = fn->parameters(); - parameters.clear(); - parameters.reserve(numArg); - for (int i = 0; i < numArg; ++i) { - CXType argType = clang_getArgType(funcType, i); - if (fn->isCtor()) { - if (fromCXString(clang_getTypeSpelling(clang_getPointeeType(argType))) == name) { - if (argType.kind == CXType_RValueReference) - fn->setMetaness(FunctionNode::MCtor); - else if (argType.kind == CXType_LValueReference) - fn->setMetaness(FunctionNode::CCtor); - } - } else if ((kind == CXCursor_CXXMethod) && (name == QLatin1String("operator="))) { - if (argType.kind == CXType_RValueReference) - fn->setMetaness(FunctionNode::MAssign); - else if (argType.kind == CXType_LValueReference) - fn->setMetaness(FunctionNode::CAssign); - } - parameters.append(adjustTypeName(fromCXString(clang_getTypeSpelling(argType)))); - } - if (parameters.count() > 0) { - if (parameters.last().type().endsWith(QLatin1String("::QPrivateSignal"))) { - parameters.pop_back(); // remove the QPrivateSignal argument - parameters.setPrivateSignal(); - } - } - if (clang_isFunctionTypeVariadic(funcType)) - parameters.append(QStringLiteral("...")); - readParameterNamesAndAttributes(fn, cursor); + processFunction(fn, cursor); + fn->setTemplateDecl(templateString); return CXChildVisit_Continue; } #if CINDEX_VERSION >= 36 case CXCursor_FriendDecl: { - // Friend functions are declared in the enclosing namespace - Aggregate *ns = parent_; - while (ns && ns->isClassNode()) - ns = ns->parent(); - QScopedValueRollback setParent(parent_, ns); + QScopedValueRollback setFriend(m_friendDecl, true); // Visit the friend functions return visitChildren(cursor); } #endif case CXCursor_EnumDecl: { - if (findNodeForCursor(qdb_, cursor)) // Was already parsed, propably in another tu - return CXChildVisit_Continue; + EnumNode *en = static_cast(findNodeForCursor(qdb_, cursor)); + if (en && en->items().count()) + return CXChildVisit_Continue; // Was already parsed, probably in another TU QString enumTypeName = fromCXString(clang_getCursorSpelling(cursor)); - EnumNode* en = nullptr; if (enumTypeName.isEmpty()) { enumTypeName = "anonymous"; if (parent_ && (parent_->isClassNode() || parent_->isNamespace())) { - Node* n = parent_->findNonfunctionChild(enumTypeName, &Node::isEnumType); + Node *n = parent_->findNonfunctionChild(enumTypeName, &Node::isEnumType); if (n) - en = static_cast(n); + en = static_cast(n); } } if (!en) { - en = new EnumNode(parent_, enumTypeName); + en = new EnumNode(parent_, enumTypeName, clang_EnumDecl_isScoped(cursor)); en->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); en->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); } + // Enum values visitChildrenLambda(cursor, [&](CXCursor cur) { if (clang_getCursorKind(cur) != CXCursor_EnumConstantDecl) return CXChildVisit_Continue; - QString value; visitChildrenLambda(cur, [&](CXCursor cur) { if (clang_isExpression(clang_getCursorKind(cur))) { @@ -796,8 +796,9 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l } case CXCursor_FieldDecl: case CXCursor_VarDecl: { - if (findNodeForCursor(qdb_, cursor)) // Was already parsed, propably in another translation unit + if (findNodeForCursor(qdb_, cursor)) // Was already parsed, probably in another TU return CXChildVisit_Continue; + auto access = fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor)); auto var = new VariableNode(parent_, fromCXString(clang_getCursorSpelling(cursor))); var->setAccess(access); @@ -807,23 +808,24 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l return CXChildVisit_Continue; } case CXCursor_TypedefDecl: { - if (findNodeForCursor(qdb_, cursor)) // Was already parsed, propably in another translation unit + if (findNodeForCursor(qdb_, cursor)) // Was already parsed, probably in another TU return CXChildVisit_Continue; - TypedefNode* td = new TypedefNode(parent_, fromCXString(clang_getCursorSpelling(cursor))); + TypedefNode *td = new TypedefNode(parent_, fromCXString(clang_getCursorSpelling(cursor))); td->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); td->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); // Search to see if this is a Q_DECLARE_FLAGS (if the type is QFlags) visitChildrenLambda(cursor, [&](CXCursor cur) { if (clang_getCursorKind(cur) != CXCursor_TemplateRef - || fromCXString(clang_getCursorSpelling(cur)) != QLatin1String("QFlags")) + || fromCXString(clang_getCursorSpelling(cur)) != QLatin1String("QFlags")) return CXChildVisit_Continue; // Found QFlags visitChildrenLambda(cursor, [&](CXCursor cur) { if (clang_getCursorKind(cur) != CXCursor_TypeRef) return CXChildVisit_Continue; - auto *en = findNodeForCursor(qdb_, clang_getTypeDeclaration(clang_getCursorType(cur))); + auto *en = + findNodeForCursor(qdb_, clang_getTypeDeclaration(clang_getCursorType(cur))); if (en && en->isEnumType()) - static_cast(en)->setFlagsType(td); + static_cast(en)->setFlagsType(td); return CXChildVisit_Break; }); return CXChildVisit_Break; @@ -832,19 +834,16 @@ CXChildVisitResult ClangVisitor::visitHeader(CXCursor cursor, CXSourceLocation l } default: if (clang_isDeclaration(kind) && parent_->isClassNode()) { - // maybe a static_assert (which is not exposed from the clang API) - QString spelling = getSpelling(clang_getCursorExtent(cursor)); - if (spelling.startsWith(QLatin1String("Q_PROPERTY")) - || spelling.startsWith(QLatin1String("QDOC_PROPERTY")) - || spelling.startsWith(QLatin1String("Q_OVERRIDE"))) { - parseProperty(spelling, fromCXSourceLocation(loc)); - } + // may be a property macro or a static_assert + // which is not exposed from the clang API + parseProperty(getSpelling(clang_getCursorExtent(cursor)), + fromCXSourceLocation(loc)); } return CXChildVisit_Continue; } } -void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cursor) +void ClangVisitor::readParameterNamesAndAttributes(FunctionNode *fn, CXCursor cursor) { Parameters ¶meters = fn->parameters(); // Visit the parameters and attributes @@ -866,59 +865,154 @@ void ClangVisitor::readParameterNamesAndAttributes(FunctionNode* fn, CXCursor cu if (i >= parameters.count()) return CXChildVisit_Break; // Attributes comes before parameters so we can break. QString name = fromCXString(clang_getCursorSpelling(cur)); - if (!name.isEmpty()) + if (!name.isEmpty()) { parameters[i].setName(name); - // Find the default value - visitChildrenLambda(cur, [&](CXCursor cur) { - if (clang_isExpression(clang_getCursorKind(cur))) { - QString defaultValue = getSpelling(clang_getCursorExtent(cur)); - if (defaultValue.startsWith('=')) // In some cases, the = is part of the range. - defaultValue = defaultValue.midRef(1).trimmed().toString(); - if (defaultValue.isEmpty()) - defaultValue = QStringLiteral("..."); - parameters[i].setDefaultValue(defaultValue); - return CXChildVisit_Break; - } - return CXChildVisit_Continue; - }); - i++; + // Find the default value + visitChildrenLambda(cur, [&](CXCursor cur) { + if (clang_isExpression(clang_getCursorKind(cur))) { + QString defaultValue = getSpelling(clang_getCursorExtent(cur)); + if (defaultValue.startsWith('=')) // In some cases, the = is part of the range. + defaultValue = QStringView{defaultValue}.mid(1).trimmed().toString(); + if (defaultValue.isEmpty()) + defaultValue = QStringLiteral("..."); + parameters[i].setDefaultValue(defaultValue); + return CXChildVisit_Break; + } + return CXChildVisit_Continue; + }); + } + ++i; } return CXChildVisit_Continue; }); } -void ClangVisitor::parseProperty(const QString& spelling, const Location& loc) +void ClangVisitor::processFunction(FunctionNode *fn, CXCursor cursor) { + CXCursorKind kind = clang_getCursorKind(cursor); + CXType funcType = clang_getCursorType(cursor); + fn->setAccess(fromCX_CXXAccessSpecifier(clang_getCXXAccessSpecifier(cursor))); + fn->setLocation(fromCXSourceLocation(clang_getCursorLocation(cursor))); + if (kind == CXCursor_Constructor + // a constructor template is classified as CXCursor_FunctionTemplate + || (kind == CXCursor_FunctionTemplate && fn->name() == parent_->name())) + fn->setMetaness(FunctionNode::Ctor); + else if (kind == CXCursor_Destructor) + fn->setMetaness(FunctionNode::Dtor); + else + fn->setReturnType(adjustTypeName( + fromCXString(clang_getTypeSpelling(clang_getResultType(funcType))))); + + fn->setStatic(clang_CXXMethod_isStatic(cursor)); + fn->setConst(clang_CXXMethod_isConst(cursor)); + fn->setVirtualness(!clang_CXXMethod_isVirtual(cursor) + ? FunctionNode::NonVirtual + : clang_CXXMethod_isPureVirtual(cursor) + ? FunctionNode::PureVirtual + : FunctionNode::NormalVirtual); + CXRefQualifierKind refQualKind = clang_Type_getCXXRefQualifier(funcType); + if (refQualKind == CXRefQualifier_LValue) + fn->setRef(true); + else if (refQualKind == CXRefQualifier_RValue) + fn->setRefRef(true); + // For virtual functions, determine what it overrides + // (except for destructor for which we do not want to classify as overridden) + if (!fn->isNonvirtual() && kind != CXCursor_Destructor) + setOverridesForFunction(fn, cursor); + + int numArg = clang_getNumArgTypes(funcType); + Parameters ¶meters = fn->parameters(); + parameters.clear(); + parameters.reserve(numArg); + for (int i = 0; i < numArg; ++i) { + CXType argType = clang_getArgType(funcType, i); + if (fn->isCtor()) { + if (fromCXString(clang_getTypeSpelling(clang_getPointeeType(argType))) == fn->name()) { + if (argType.kind == CXType_RValueReference) + fn->setMetaness(FunctionNode::MCtor); + else if (argType.kind == CXType_LValueReference) + fn->setMetaness(FunctionNode::CCtor); + } + } else if ((kind == CXCursor_CXXMethod) && (fn->name() == QLatin1String("operator="))) { + if (argType.kind == CXType_RValueReference) + fn->setMetaness(FunctionNode::MAssign); + else if (argType.kind == CXType_LValueReference) + fn->setMetaness(FunctionNode::CAssign); + } + parameters.append(adjustTypeName(fromCXString(clang_getTypeSpelling(argType)))); + if (argType.kind == CXType_Typedef || argType.kind == CXType_Elaborated) { + parameters.last().setCanonicalType(fromCXString( + clang_getTypeSpelling(clang_getCanonicalType(argType)))); + } + } + if (parameters.count() > 0) { + if (parameters.last().type().endsWith(QLatin1String("QPrivateSignal"))) { + parameters.pop_back(); // remove the QPrivateSignal argument + parameters.setPrivateSignal(); + } + } + if (clang_isFunctionTypeVariadic(funcType)) + parameters.append(QStringLiteral("...")); + readParameterNamesAndAttributes(fn, cursor); + // Friend functions are not members + if (m_friendDecl) + fn->setRelatedNonmember(true); +} + +bool ClangVisitor::parseProperty(const QString &spelling, const Location &loc) +{ + if (!spelling.startsWith(QLatin1String("Q_PROPERTY")) + && !spelling.startsWith(QLatin1String("QDOC_PROPERTY")) + && !spelling.startsWith(QLatin1String("Q_OVERRIDE"))) + return false; + int lpIdx = spelling.indexOf(QChar('(')); int rpIdx = spelling.lastIndexOf(QChar(')')); if (lpIdx <= 0 || rpIdx <= lpIdx) - return; + return false; + QString signature = spelling.mid(lpIdx + 1, rpIdx - lpIdx - 1); signature = signature.simplified(); - QStringList part = signature.split(QChar(' ')); - if (part.size() < 2) - return; - QString type = part.at(0); - QString name = part.at(1); - if (name.at(0) == QChar('*')) { + + QString type; + QString name; + QStringList parts = signature.split(QChar(' '), Qt::SkipEmptyParts); + if (parts.size() < 2) + return false; + if (parts.first() == QLatin1String("enum")) + parts.removeFirst(); // QTBUG-80027 + + type = parts.takeFirst(); + if (type == QLatin1String("const") && parts.size() > 0) + type += " " + parts.takeFirst(); + + if (parts.size() > 0) + name = parts.takeFirst(); + else + return false; + + if (name.front() == QChar('*')) { type.append(QChar('*')); - name.remove(0,1); + name.remove(0, 1); } auto *property = new PropertyNode(parent_, name); - property->setAccess(Node::Public); + property->setAccess(Access::Public); property->setLocation(loc); property->setDataType(type); - int i = 2; - while (i < part.size()) { - QString key = part.at(i++); + + int i = 0; + while (i < parts.size()) { + const QString &key = parts.at(i++); // Keywords with no associated values if (key == "CONSTANT") { property->setConstant(); } else if (key == "FINAL") { property->setFinal(); + } else if (key == "REQUIRED") { + property->setRequired(); } - if (i < part.size()) { - QString value = part.at(i++); + if (i < parts.size()) { + QString value = parts.at(i++); if (key == "READ") { qdb_->addPropertyFunction(property, value, PropertyNode::Getter); } else if (key == "WRITE") { @@ -936,6 +1030,8 @@ void ClangVisitor::parseProperty(const QString& spelling, const Location& loc) property->setDesignable(false); property->setRuntimeDesFunc(value); } + } else if (key == "BINDABLE") { + property->setPropertyType(PropertyNode::Bindable); } else if (key == "RESET") { qdb_->addPropertyFunction(property, value, PropertyNode::Resetter); } else if (key == "NOTIFY") { @@ -947,7 +1043,7 @@ void ClangVisitor::parseProperty(const QString& spelling, const Location& loc) if (ok) property->setRevision(revision); else - loc.warning(ClangCodeParser::tr("Invalid revision number: %1").arg(value)); + loc.warning(QStringLiteral("Invalid revision number: %1").arg(value)); } else if (key == "SCRIPTABLE") { QString v = value.toLower(); if (v == "true") @@ -961,6 +1057,7 @@ void ClangVisitor::parseProperty(const QString& spelling, const Location& loc) } } } + return true; } /*! @@ -969,7 +1066,7 @@ void ClangVisitor::parseProperty(const QString& spelling, const Location& loc) must be inbetween. Returns nullptr if no suitable declaration was found between the two comments. */ -Node* ClangVisitor::nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocation nextCommentLoc) +Node *ClangVisitor::nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocation nextCommentLoc) { ClangVisitor::SimpleLoc docloc; clang_getPresumedLocation(loc, nullptr, &docloc.line, &docloc.column); @@ -985,21 +1082,21 @@ Node* ClangVisitor::nodeForCommentAtLocation(CXSourceLocation loc, CXSourceLocat // make sure the previous decl was finished. if (decl_it != declMap_.begin()) { - CXSourceLocation prevDeclEnd = clang_getRangeEnd(clang_getCursorExtent(*(decl_it-1))); + CXSourceLocation prevDeclEnd = clang_getRangeEnd(clang_getCursorExtent(*(std::prev(decl_it)))); unsigned int prevDeclLine; clang_getPresumedLocation(prevDeclEnd, nullptr, &prevDeclLine, nullptr); if (prevDeclLine >= docloc.line) { // The previous declaration was still going. This is only valid if the previous // declaration is a parent of the next declaration. auto parent = clang_getCursorLexicalParent(*decl_it); - if (!clang_equalCursors(parent, *(decl_it-1))) + if (!clang_equalCursors(parent, *(std::prev(decl_it)))) return nullptr; } } auto *node = findNodeForCursor(qdb_, *decl_it); // borrow the parameter name from the definition if (node && node->isFunction(Node::CPP)) - readParameterNamesAndAttributes(static_cast(node), *decl_it); + readParameterNamesAndAttributes(static_cast(node), *decl_it); return node; } @@ -1016,30 +1113,42 @@ ClangCodeParser::~ClangCodeParser() \a config. Call the initializeParser() in the base class. Get the defines list from the qdocconf database. */ -void ClangCodeParser::initializeParser(const Config &config) +void ClangCodeParser::initializeParser() { - printParsingErrors_ = 1; - version_ = config.getString(CONFIG_VERSION); + Config &config = Config::instance(); + m_version = config.getString(CONFIG_VERSION); const auto args = config.getStringList(CONFIG_INCLUDEPATHS); - QStringList squeezedArgs; - int i = 0; - while (i < args.size()) { - if (args.at(i) != QLatin1String("-I")) { - if (args.at(i).startsWith(QLatin1String("-I"))) - squeezedArgs << args.at(i); - else - squeezedArgs << QLatin1String("-I") + args.at(i); + QSet seen; + m_includePaths.clear(); + // Remove empty paths and duplicates and add -I and canonicalize if necessary + for (const auto &p : args) { + QByteArray option; + QString rawpath; + if (p.startsWith(QLatin1String("-I")) || p.startsWith(QLatin1String("-F"))) { + rawpath = p.mid(2).trimmed(); + option = p.left(2).toUtf8(); + } else if (p.startsWith(QLatin1String("-isystem"))) { + rawpath = p.mid(8).trimmed(); + option = "-isystem"; + } else { + rawpath = p; + option = "-I"; } - i++; + if (rawpath.isEmpty() || seen.contains(rawpath)) + continue; + seen.insert(rawpath); + QByteArray path(rawpath.toUtf8()); + QFileInfo fi(QDir::current(), rawpath); + if (fi.exists()) + path = fi.canonicalFilePath().toUtf8(); + path.prepend(option); + m_includePaths.append(path); } - includePaths_.resize(squeezedArgs.size()); - std::transform(squeezedArgs.begin(), squeezedArgs.end(), includePaths_.begin(), - [](const QString &s) { return s.toUtf8(); }); - CppCodeParser::initializeParser(config); - pchFileDir_.reset(nullptr); - allHeaders_.clear(); - pchName_.clear(); - defines_.clear(); + CppCodeParser::initializeParser(); + m_pchFileDir.reset(nullptr); + m_allHeaders.clear(); + m_pchName.clear(); + m_defines.clear(); QSet accepted; { const QStringList tmpDefines = config.getStringList(CONFIG_CLANGDEFINES); @@ -1047,7 +1156,7 @@ void ClangCodeParser::initializeParser(const Config &config) if (!accepted.contains(def)) { QByteArray tmp("-D"); tmp.append(def.toUtf8()); - defines_.append(tmp.constData()); + m_defines.append(tmp.constData()); accepted.insert(def); } } @@ -1058,13 +1167,13 @@ void ClangCodeParser::initializeParser(const Config &config) if (!accepted.contains(def) && !def.contains(QChar('*'))) { QByteArray tmp("-D"); tmp.append(def.toUtf8()); - defines_.append(tmp.constData()); + m_defines.append(tmp.constData()); accepted.insert(def); } } } - qCDebug(lcQdoc).nospace() << __FUNCTION__ << " Clang v" << CINDEX_VERSION_MAJOR - << '.' << CINDEX_VERSION_MINOR; + qCDebug(lcQdoc).nospace() << __FUNCTION__ << " Clang v" << CINDEX_VERSION_MAJOR << '.' + << CINDEX_VERSION_MINOR; } /*! @@ -1086,7 +1195,12 @@ QString ClangCodeParser::language() */ QStringList ClangCodeParser::headerFileNameFilter() { - return QStringList() << "*.ch" << "*.h" << "*.h++" << "*.hh" << "*.hpp" << "*.hxx"; + return QStringList() << "*.ch" + << "*.h" + << "*.h++" + << "*.hh" + << "*.hpp" + << "*.hxx"; } /*! @@ -1095,7 +1209,11 @@ QStringList ClangCodeParser::headerFileNameFilter() */ QStringList ClangCodeParser::sourceFileNameFilter() { - return QStringList() << "*.c++" << "*.cc" << "*.cpp" << "*.cxx" << "*.mm"; + return QStringList() << "*.c++" + << "*.cc" + << "*.cpp" + << "*.cxx" + << "*.mm"; } /*! @@ -1106,27 +1224,28 @@ QStringList ClangCodeParser::sourceFileNameFilter() void ClangCodeParser::parseHeaderFile(const Location & /*location*/, const QString &filePath) { QFileInfo fi(filePath); - allHeaders_.insert(fi.fileName(), fi.canonicalPath()); + m_allHeaders.insert(fi.fileName(), fi.canonicalPath()); } static const char *defaultArgs_[] = { - "-std=c++14", + "-std=c++20", #ifndef Q_OS_WIN "-fPIC", #else "-fms-compatibility-version=19", #endif - "-fno-exceptions", // Workaround for clang bug http://reviews.llvm.org/D17988 "-DQ_QDOC", "-DQ_CLANG_QDOC", "-DQT_DISABLE_DEPRECATED_BEFORE=0", - "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__), #type);", - "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1, #a2), #type);", + "-DQT_ANNOTATE_CLASS(type,...)=static_assert(sizeof(#__VA_ARGS__),#type);", + "-DQT_ANNOTATE_CLASS2(type,a1,a2)=static_assert(sizeof(#a1,#a2),#type);", "-DQT_ANNOTATE_FUNCTION(a)=__attribute__((annotate(#a)))", "-DQT_ANNOTATE_ACCESS_SPECIFIER(a)=__attribute__((annotate(#a)))", "-Wno-constant-logical-operand", "-Wno-macro-redefined", "-Wno-nullability-completeness", + "-fvisibility=default", + "-ferror-limit=0", "-I" CLANG_RESOURCE_DIR }; @@ -1136,20 +1255,20 @@ static const char *defaultArgs_[] = { */ void ClangCodeParser::getDefaultArgs() { - args_.clear(); - args_.insert(args_.begin(), std::begin(defaultArgs_), std::end(defaultArgs_)); + m_args.clear(); + m_args.insert(m_args.begin(), std::begin(defaultArgs_), std::end(defaultArgs_)); // Add the defines from the qdocconf file. - for (const auto &p : qAsConst(defines_)) - args_.push_back(p.constData()); + for (const auto &p : qAsConst(m_defines)) + m_args.push_back(p.constData()); } -static QVector includePathsFromHeaders(const QHash &allHeaders) +static QList includePathsFromHeaders(const QHash &allHeaders) { - QVector result; - for (auto it = allHeaders.cbegin(), end = allHeaders.cend(); it != end; ++it) { + QList result; + for (auto it = allHeaders.cbegin(); it != allHeaders.cend(); ++it) { const QByteArray path = "-I" + it.value().toLatin1(); - const QByteArray parent = "-I" - + QDir::cleanPath(it.value() + QLatin1String("/../")).toLatin1(); + const QByteArray parent = + "-I" + QDir::cleanPath(it.value() + QLatin1String("/../")).toLatin1(); if (!result.contains(path)) result.append(path); if (!result.contains(parent)) @@ -1159,50 +1278,27 @@ static QVector includePathsFromHeaders(const QHash } /*! - Load the include paths into \a moreArgs and return false. - If no include paths were provided, try to guess reasonable - include paths but return true, so the clang diagnostics - can be turned off during PCH creation. - - The use case for returning true is the QtPlatformHeaders - module when running qdoc on macOS. For some reason, the - include paths are not passed to qdoc, so it guesses them. - This results in clang reporting a large number of errors - during the PCH build. The errors are useles, except that - it probably means the build system isn't working correctly - for QtPlatformHeaders when running qdoc. + Load the include paths into \a moreArgs. If no include paths + were provided, try to guess reasonable include paths. */ -bool ClangCodeParser::getMoreArgs() +void ClangCodeParser::getMoreArgs() { - bool guessedIncludePaths = false; - if (includePaths_.isEmpty()) { + if (m_includePaths.isEmpty()) { /* The include paths provided are inadequate. Make a list of reasonable places to look for include files and use that list instead. */ - Location::logToStdErrAlways("No include paths passed to qdoc; guessing reasonable include paths"); - guessedIncludePaths = true; + qCWarning(lcQdoc) << "No include paths passed to qdoc; guessing reasonable include paths"; auto forest = qdb_->searchOrder(); QByteArray version = qdb_->version().toUtf8(); QString basicIncludeDir = QDir::cleanPath(QString(Config::installDir + "/../include")); - moreArgs_ += "-I" + basicIncludeDir.toLatin1(); - moreArgs_ += includePathsFromHeaders(allHeaders_); - } - else { - moreArgs_ = includePaths_; - } - - // Canonicalize include paths - for (int i = 0; i < moreArgs_.size(); ++i) { - if (!moreArgs_.at(i).startsWith("-")) { - QFileInfo fi(QDir::current(), moreArgs_[i]); - if (fi.exists()) - moreArgs_[i] = fi.canonicalFilePath().toLatin1(); - } + m_moreArgs += "-I" + basicIncludeDir.toLatin1(); + m_moreArgs += includePathsFromHeaders(m_allHeaders); + } else { + m_moreArgs = m_includePaths; } - return guessedIncludePaths; } /*! @@ -1212,116 +1308,128 @@ bool ClangCodeParser::getMoreArgs() */ void ClangCodeParser::buildPCH() { - if (!pchFileDir_ && !moduleHeader().isEmpty()) { - pchFileDir_.reset(new QTemporaryDir(QDir::tempPath() + QLatin1String("/qdoc_pch"))); - if (pchFileDir_->isValid()) { - //const QByteArray module = qdb_->primaryTreeRoot()->tree()->camelCaseModuleName().toUtf8(); + if (!m_pchFileDir && !moduleHeader().isEmpty()) { + m_pchFileDir.reset(new QTemporaryDir(QDir::tempPath() + QLatin1String("/qdoc_pch"))); + if (m_pchFileDir->isValid()) { const QByteArray module = moduleHeader().toUtf8(); QByteArray header; QByteArray privateHeaderDir; - Location::logToStdErrAlways("Build & visit PCH for " + moduleHeader()); - // Find the path to the module's header (e.g. QtGui/QtGui) to be used - // as pre-compiled header - for (const auto &p : qAsConst(includePaths_)) { - if (p.endsWith(module)) { - QByteArray candidate = p + "/" + module; - if (QFile::exists(QString::fromUtf8(candidate))) { - header = candidate; - break; - } + qCDebug(lcQdoc) << "Build and visit PCH for" << moduleHeader(); + // A predicate for std::find_if() to locate a path to the module's header + // (e.g. QtGui/QtGui) to be used as pre-compiled header + struct FindPredicate + { + enum SearchType { Any, Module, Private }; + QByteArray &candidate_; + const QByteArray &module_; + SearchType type_; + FindPredicate(QByteArray &candidate, const QByteArray &module, + SearchType type = Any) + : candidate_(candidate), module_(module), type_(type) + { } - } - if (header.isEmpty()) { - for (const auto &p : qAsConst(includePaths_)) { - QByteArray candidate = p + "/" + module; - if (QFile::exists(QString::fromUtf8(candidate))) { - header = candidate; + + bool operator()(const QByteArray &p) const + { + if (type_ != Any && !p.endsWith(module_)) + return false; + candidate_ = p + "/"; + switch (type_) { + case Any: + case Module: + candidate_.append(module_); break; - } - } - } - // Find the path to the module's private header directory (e.g. - // include/QtGui/5.8.0/QtGui/private) to use for including all - // the private headers in the PCH. - for (const auto &p : qAsConst(includePaths_)) { - if (p.endsWith(module)) { - QByteArray candidate = p + "/private"; - if (QFile::exists(QString::fromUtf8(candidate))) { - privateHeaderDir = candidate; + case Private: + candidate_.append("private"); + break; + default: break; } + if (p.startsWith("-I")) + candidate_ = candidate_.mid(2); + return QFile::exists(QString::fromUtf8(candidate_)); } - } - if (header.isEmpty()) { - QByteArray installDocDir = Config::installDir.toUtf8(); - const QByteArray candidate = installDocDir + "/../include/" + module + "/" + module; - if (QFile::exists(QString::fromUtf8(candidate))) - header = candidate; - } + }; + + // First, search for an include path that contains the module name, then any path + QByteArray candidate; + auto it = std::find_if(m_includePaths.begin(), m_includePaths.end(), + FindPredicate(candidate, module, FindPredicate::Module)); + if (it == m_includePaths.end()) + it = std::find_if(m_includePaths.begin(), m_includePaths.end(), + FindPredicate(candidate, module, FindPredicate::Any)); + if (it != m_includePaths.end()) + header = candidate; + + // Find the path to module's private headers - currently unused + it = std::find_if(m_includePaths.begin(), m_includePaths.end(), + FindPredicate(candidate, module, FindPredicate::Private)); + if (it != m_includePaths.end()) + privateHeaderDir = candidate; + if (header.isEmpty()) { qWarning() << "(qdoc) Could not find the module header in include paths for module" - << module << " (include paths: "<< includePaths_ << ")"; - qWarning() << " Artificial module header built from header dirs in qdocconf file"; + << module << " (include paths: " << m_includePaths << ")"; + qWarning() << " Artificial module header built from header dirs in qdocconf " + "file"; } - args_.push_back("-xc++"); + m_args.push_back("-xc++"); CXTranslationUnit tu; - QString tmpHeader = pchFileDir_->path() + "/" + module; + QString tmpHeader = m_pchFileDir->path() + "/" + module; QFile tmpHeaderFile(tmpHeader); if (tmpHeaderFile.open(QIODevice::Text | QIODevice::WriteOnly)) { QTextStream out(&tmpHeaderFile); if (header.isEmpty()) { - QList keys = allHeaders_.keys(); - QList values = allHeaders_.values(); - for (int i = 0; i < keys.size(); i++) { - if (!keys.at(i).endsWith(QLatin1String("_p.h")) && - !keys.at(i).startsWith(QLatin1String("moc_"))) { - QString line = QLatin1String("#include \"") + values.at(i) + - QLatin1String("/") + keys.at(i) + QLatin1String("\""); + for (auto it = m_allHeaders.constKeyValueBegin(); + it != m_allHeaders.constKeyValueEnd(); ++it) { + if (!(*it).first.endsWith(QLatin1String("_p.h")) + && !(*it).first.startsWith(QLatin1String("moc_"))) { + QString line = QLatin1String("#include \"") + (*it).second + + QLatin1String("/") + (*it).first + QLatin1String("\""); out << line << "\n"; } } } else { - QFile headerFile(header); - if (!headerFile.open(QFile::ReadOnly)) { - qWarning() << "Could not read module header file" << header; + QFileInfo headerFile(header); + if (!headerFile.exists()) { + qWarning() << "Could not find module header file" << header; return; } - QTextStream in(&headerFile); - while (!in.atEnd()) { - QString line = in.readLine().simplified(); - if (line.startsWith(QLatin1String("#include"))) - out << line << "\n"; - } + out << QLatin1String("#include \"") + header + QLatin1String("\""); } + tmpHeaderFile.close(); } - if (printParsingErrors_ == 0) - Location::logToStdErrAlways("clang not printing errors; include paths were guessed"); - CXErrorCode err = clang_parseTranslationUnit2(index_, - tmpHeader.toLatin1().data(), - args_.data(), static_cast(args_.size()), nullptr, 0, - flags_ | CXTranslationUnit_ForSerialization, &tu); - qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" - << tmpHeader << args_ << ") returns" << err; + + CXErrorCode err = + clang_parseTranslationUnit2(index_, tmpHeader.toLatin1().data(), m_args.data(), + static_cast(m_args.size()), nullptr, 0, + flags_ | CXTranslationUnit_ForSerialization, &tu); + qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" << tmpHeader << m_args + << ") returns" << err; + + printDiagnostics(tu); + if (!err && tu) { - pchName_ = pchFileDir_->path().toUtf8() + "/" + module + ".pch"; - auto error = clang_saveTranslationUnit(tu, pchName_.constData(), clang_defaultSaveOptions(tu)); + m_pchName = m_pchFileDir->path().toUtf8() + "/" + module + ".pch"; + auto error = clang_saveTranslationUnit(tu, m_pchName.constData(), + clang_defaultSaveOptions(tu)); if (error) { - Location::logToStdErrAlways("Could not save PCH file for " + moduleHeader()); - pchName_.clear(); - } - else { - // Visit the header now, as token from pre-compiled header won't be visited later + qCCritical(lcQdoc) << "Could not save PCH file for" << moduleHeader(); + m_pchName.clear(); + } else { + // Visit the header now, as token from pre-compiled header won't be visited + // later CXCursor cur = clang_getTranslationUnitCursor(tu); - ClangVisitor visitor(qdb_, allHeaders_); + ClangVisitor visitor(qdb_, m_allHeaders); visitor.visitChildren(cur); - Location::logToStdErrAlways("PCH built & visited for " + moduleHeader()); + qCDebug(lcQdoc) << "PCH built and visited for" << moduleHeader(); } clang_disposeTranslationUnit(tu); } else { - pchFileDir_->remove(); - Location::logToStdErrAlways("Could not create PCH file for " + moduleHeader()); + m_pchFileDir->remove(); + qCCritical(lcQdoc) << "Could not create PCH file for " << moduleHeader(); } - args_.pop_back(); // remove the "-xc++"; + m_args.pop_back(); // remove the "-xc++"; } } } @@ -1332,14 +1440,16 @@ void ClangCodeParser::buildPCH() void ClangCodeParser::precompileHeaders() { getDefaultArgs(); - if (getMoreArgs()) - printParsingErrors_ = 0; - for (const auto &p : qAsConst(moreArgs_)) - args_.push_back(p.constData()); - - flags_ = static_cast(CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing); - // 1 as 2nd parameter tells clang to report parser errors. - index_ = clang_createIndex(1, printParsingErrors_); + getMoreArgs(); + for (const auto &p : qAsConst(m_moreArgs)) + m_args.push_back(p.constData()); + + flags_ = static_cast(CXTranslationUnit_Incomplete + | CXTranslationUnit_SkipFunctionBodies + | CXTranslationUnit_KeepGoing); + + index_ = clang_createIndex(1, kClangDontDisplayDiagnostics); + buildPCH(); clang_disposeIndex(index_); } @@ -1358,7 +1468,7 @@ static float getUnpatchedVersion(QString t) Call matchDocsAndStuff() to do all the parsing and tree building. */ -void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QString& filePath) +void ClangCodeParser::parseSourceFile(const Location & /*location*/, const QString &filePath) { /* The set of open namespaces is cleared before parsing @@ -1366,38 +1476,44 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin */ qdb_->clearOpenNamespaces(); currentFile_ = filePath; - flags_ = static_cast(CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies | CXTranslationUnit_KeepGoing); - index_ = clang_createIndex(1, 0); + flags_ = static_cast(CXTranslationUnit_Incomplete + | CXTranslationUnit_SkipFunctionBodies + | CXTranslationUnit_KeepGoing); + + index_ = clang_createIndex(1, kClangDontDisplayDiagnostics); getDefaultArgs(); - if (!pchName_.isEmpty() && !filePath.endsWith(".mm")) { - args_.push_back("-w"); - args_.push_back("-include-pch"); - args_.push_back(pchName_.constData()); + if (!m_pchName.isEmpty() && !filePath.endsWith(".mm")) { + m_args.push_back("-w"); + m_args.push_back("-include-pch"); + m_args.push_back(m_pchName.constData()); } getMoreArgs(); - for (const auto &p : qAsConst(moreArgs_)) - args_.push_back(p.constData()); + for (const auto &p : qAsConst(m_moreArgs)) + m_args.push_back(p.constData()); CXTranslationUnit tu; - CXErrorCode err = clang_parseTranslationUnit2(index_, filePath.toLocal8Bit(), args_.data(), - static_cast(args_.size()), nullptr, 0, flags_, &tu); - qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" - << filePath << args_ << ") returns" << err; + CXErrorCode err = + clang_parseTranslationUnit2(index_, filePath.toLocal8Bit(), m_args.data(), + static_cast(m_args.size()), nullptr, 0, flags_, &tu); + qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" << filePath << m_args + << ") returns" << err; + printDiagnostics(tu); + if (err || !tu) { qWarning() << "(qdoc) Could not parse source file" << filePath << " error code:" << err; clang_disposeIndex(index_); return; } - CXCursor cur = clang_getTranslationUnitCursor(tu); - ClangVisitor visitor(qdb_, allHeaders_); - visitor.visitChildren(cur); + CXCursor tuCur = clang_getTranslationUnitCursor(tu); + ClangVisitor visitor(qdb_, m_allHeaders); + visitor.visitChildren(tuCur); CXToken *tokens; unsigned int numTokens = 0; const QSet &commands = topicCommands() + metaCommands(); - clang_tokenize(tu, clang_getCursorExtent(cur), &tokens, &numTokens); + clang_tokenize(tu, clang_getCursorExtent(tuCur), &tokens, &numTokens); for (unsigned int i = 0; i < numTokens; ++i) { if (clang_getTokenKind(tokens[i]) != CXToken_Comment) @@ -1406,9 +1522,10 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin if (!comment.startsWith("/*!")) continue; - auto loc = fromCXSourceLocation(clang_getTokenLocation(tu, tokens[i])); + auto commentLoc = clang_getTokenLocation(tu, tokens[i]); + auto loc = fromCXSourceLocation(commentLoc); auto end_loc = fromCXSourceLocation(clang_getRangeEnd(clang_getTokenExtent(tu, tokens[i]))); - Doc::trimCStyleComment(loc,comment); + Doc::trimCStyleComment(loc, comment); // Doc constructor parses the comment. Doc doc(loc, end_loc, comment, commands, topicCommands()); @@ -1418,19 +1535,18 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin DocList docs; QString topic; NodeList nodes; - const TopicList& topics = doc.topicsUsed(); + const TopicList &topics = doc.topicsUsed(); if (!topics.isEmpty()) topic = topics[0].topic; if (topic.isEmpty()) { - CXSourceLocation commentLoc = clang_getTokenLocation(tu, tokens[i]); Node *n = nullptr; if (i + 1 < numTokens) { // Try to find the next declaration. CXSourceLocation nextCommentLoc = commentLoc; - while (i + 2 < numTokens && clang_getTokenKind(tokens[i+1]) != CXToken_Comment) + while (i + 2 < numTokens && clang_getTokenKind(tokens[i + 1]) != CXToken_Comment) ++i; // already skip all the tokens that are not comments - nextCommentLoc = clang_getTokenLocation(tu, tokens[i+1]); + nextCommentLoc = clang_getTokenLocation(tu, tokens[i + 1]); n = visitor.nodeForCommentAtLocation(commentLoc, nextCommentLoc); } @@ -1441,19 +1557,32 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin bool future = false; if (doc.metaCommandsUsed().contains(COMMAND_SINCE)) { QString sinceVersion = doc.metaCommandArgs(COMMAND_SINCE)[0].first; - if (getUnpatchedVersion(sinceVersion) > getUnpatchedVersion(version_)) + if (getUnpatchedVersion(sinceVersion) > getUnpatchedVersion(m_version)) future = true; } if (!future) { - doc.location().warning(tr("Cannot tie this documentation to anything"), - tr("qdoc found a /*! ... */ comment, but there was no " - "topic command (e.g., '\\%1', '\\%2') in the " - "comment and no function definition following " - "the comment.") - .arg(COMMAND_FN).arg(COMMAND_PAGE)); + doc.location().warning( + QStringLiteral("Cannot tie this documentation to anything"), + QStringLiteral("qdoc found a /*! ... */ comment, but there was no " + "topic command (e.g., '\\%1', '\\%2') in the " + "comment and no function definition following " + "the comment.") + .arg(COMMAND_FN) + .arg(COMMAND_PAGE)); } } } else { + // Store the namespace scope from lexical parents of the comment + m_namespaceScope.clear(); + CXCursor cur = clang_getCursor(tu, commentLoc); + while (true) { + CXCursorKind kind = clang_getCursorKind(cur); + if (clang_isTranslationUnit(kind) || clang_isInvalid(kind)) + break; + if (kind == CXCursor_Namespace) + m_namespaceScope << fromCXString(clang_getCursorSpelling(cur)); + cur = clang_getCursorLexicalParent(cur); + } processTopicArgs(doc, topic, nodes, docs); } processMetaCommands(nodes, docs); @@ -1462,6 +1591,8 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin clang_disposeTokens(tu, tokens, numTokens); clang_disposeTranslationUnit(tu); clang_disposeIndex(index_); + m_namespaceScope.clear(); + s_fn.clear(); } /*! @@ -1469,9 +1600,9 @@ void ClangCodeParser::parseSourceFile(const Location& /*location*/, const QStrin command. \a location is used for reporting errors. \a fnArg is the string to parse. It is always a function decl. */ -Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg) +Node *ClangCodeParser::parseFnArg(const Location &location, const QString &fnArg) { - Node* fnNode = nullptr; + Node *fnNode = nullptr; /* If the \fn command begins with a tag, then don't try to parse the \fn command with clang. Use the tag to search @@ -1479,20 +1610,23 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg not be found. Return 0 in that case. */ if (fnArg.startsWith('[')) { - int end = fnArg.indexOf(QChar(']', 0)); - if (end > 1) { - QString tag = fnArg.left(end + 1); + int tagEnd = fnArg.indexOf(QChar(']', 0)); + if (tagEnd > 1) { + QString tag = fnArg.left(++tagEnd); fnNode = qdb_->findFunctionNodeForTag(tag); if (!fnNode) { - location.error(ClangCodeParser::tr("tag \\fn %1 not used in any include file in current module").arg(tag)); + location.error( + QStringLiteral("tag \\fn %1 not used in any include file in current module") + .arg(tag)); } else { /* The function node was found. Use the formal - parameter names from the \FN command, because + parameter names from the \fn command, because they will be the names used in the documentation. */ - FunctionNode* fn = static_cast(fnNode); - QStringList leftParenSplit = fnArg.split('('); + QString fnSignature = fnArg.mid(tagEnd); + FunctionNode *fn = static_cast(fnNode); + QStringList leftParenSplit = fnSignature.mid(fnSignature.indexOf(fn->name())).split('('); if (leftParenSplit.size() > 1) { QStringList rightParenSplit = leftParenSplit[1].split(')'); if (rightParenSplit.size() > 0) { @@ -1502,16 +1636,14 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg Parameters ¶meters = fn->parameters(); if (parameters.count() == commaSplit.size()) { for (int i = 0; i < parameters.count(); ++i) { - QStringList blankSplit = commaSplit[i].split(' '); - if (blankSplit.size() > 0) { + QStringList blankSplit = commaSplit[i].split(' ', Qt::SkipEmptyParts); + if (blankSplit.size() > 1) { QString pName = blankSplit.last(); - int j = 0; - while (j < pName.length() && !pName.at(i).isLetter()) - j++; - if (j > 0) - pName = pName.mid(j); - if (!pName.isEmpty() && pName != parameters[i].name()) - parameters[i].setName(pName); + // Remove any non-letters from the start of parameter name + auto it = std::find_if(std::begin(pName), std::end(pName), + [](const QChar &c) { return c.isLetter(); }); + parameters[i].setName( + pName.remove(0, std::distance(std::begin(pName), it))); } } } @@ -1522,39 +1654,40 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg } return fnNode; } - CXTranslationUnit_Flags flags = static_cast(CXTranslationUnit_Incomplete | - CXTranslationUnit_SkipFunctionBodies | - CXTranslationUnit_KeepGoing); - // Change 2nd parameter to 1 to make clang report errors. - CXIndex index = clang_createIndex(1, Generator::debugging() ? 1 : 0); + CXTranslationUnit_Flags flags = static_cast( + CXTranslationUnit_Incomplete | CXTranslationUnit_SkipFunctionBodies + | CXTranslationUnit_KeepGoing); + + CXIndex index = clang_createIndex(1, kClangDontDisplayDiagnostics); std::vector args(std::begin(defaultArgs_), std::end(defaultArgs_)); // Add the defines from the qdocconf file. - for (const auto &p : qAsConst(defines_)) + for (const auto &p : qAsConst(m_defines)) args.push_back(p.constData()); - if (!pchName_.isEmpty()) { + if (!m_pchName.isEmpty()) { args.push_back("-w"); args.push_back("-include-pch"); - args.push_back(pchName_.constData()); + args.push_back(m_pchName.constData()); } CXTranslationUnit tu; - QByteArray fn = fnArg.toUtf8(); - if (!fn.endsWith(";")) - fn += "{ }"; - const char *dummyFileName = "/fn_dummyfile.cpp"; - CXUnsavedFile unsavedFile { dummyFileName, fn.constData(), - static_cast(fn.size()) }; - CXErrorCode err = clang_parseTranslationUnit2(index, dummyFileName, - args.data(), - args.size(), - &unsavedFile, - 1, - flags, - &tu); - qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" - << dummyFileName << args_ << ") returns" << err; + s_fn.clear(); + for (const auto &ns : qAsConst(m_namespaceScope)) + s_fn.prepend("namespace " + ns.toUtf8() + " {"); + s_fn += fnArg.toUtf8(); + if (!s_fn.endsWith(";")) + s_fn += "{ }"; + s_fn.append(m_namespaceScope.size(), '}'); + + const char *dummyFileName = fnDummyFileName; + CXUnsavedFile unsavedFile { dummyFileName, s_fn.constData(), + static_cast(s_fn.size()) }; + CXErrorCode err = clang_parseTranslationUnit2(index, dummyFileName, args.data(), + int(args.size()), &unsavedFile, 1, flags, &tu); + qCDebug(lcQdoc) << __FUNCTION__ << "clang_parseTranslationUnit2(" << dummyFileName << args + << ") returns" << err; + printDiagnostics(tu); if (err || !tu) { - location.error(ClangCodeParser::tr("clang could not parse \\fn %1").arg(fnArg)); + location.error(QStringLiteral("clang could not parse \\fn %1").arg(fnArg)); clang_disposeTranslationUnit(tu); clang_disposeIndex(index); return fnNode; @@ -1566,7 +1699,7 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg the diagnostics if they stop us finding the node. */ CXCursor cur = clang_getTranslationUnitCursor(tu); - ClangVisitor visitor(qdb_, allHeaders_); + ClangVisitor visitor(qdb_, m_allHeaders); bool ignoreSignature = false; visitor.visitFnArg(cur, &fnNode, ignoreSignature); /* @@ -1576,27 +1709,28 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg */ if (fnNode == nullptr) { unsigned diagnosticCount = clang_getNumDiagnostics(tu); - if (diagnosticCount > 0 && (!Generator::preparing() || Generator::singleExec())) { + const auto &config = Config::instance(); + if (diagnosticCount > 0 && (!config.preparing() || config.singleExec())) { bool report = true; - QStringList signature = fnArg.split(QLatin1String("::")); + QStringList signature = fnArg.split(QChar('(')); if (signature.size() > 1) { - QStringList typeAndQualifier = signature.at(0).split(' '); - QString qualifier = typeAndQualifier.last(); - int i = 0; - while (qualifier.size() > i && !qualifier.at(i).isLetter()) - qualifier[i++] = QChar(' '); - if (i > 0) - qualifier = qualifier.simplified(); - ClassNode* cn = qdb_->findClassNode(QStringList(qualifier)); - if (cn && cn->isInternal()) - report = false; + QStringList qualifiedName = signature.at(0).split(QChar(' ')); + qualifiedName = qualifiedName.last().split(QLatin1String("::")); + if (qualifiedName.size() > 1) { + QString qualifier = qualifiedName.at(0); + int i = 0; + while (qualifier.size() > i && !qualifier.at(i).isLetter()) + qualifier[i++] = QChar(' '); + if (i > 0) + qualifier = qualifier.simplified(); + ClassNode *cn = qdb_->findClassNode(QStringList(qualifier)); + if (cn && cn->isInternal()) + report = false; + } } if (report) { - location.warning(ClangCodeParser::tr("clang found diagnostics parsing \\fn %1").arg(fnArg)); - for (unsigned i = 0; i < diagnosticCount; ++i) { - CXDiagnostic diagnostic = clang_getDiagnostic(tu, i); - location.report(tr(" %1").arg(fromCXString(clang_formatDiagnostic(diagnostic, 0)))); - } + location.warning( + QStringLiteral("clang couldn't find function when parsing \\fn %1").arg(fnArg)); } } } @@ -1606,4 +1740,21 @@ Node* ClangCodeParser::parseFnArg(const Location& location, const QString& fnArg return fnNode; } +void ClangCodeParser::printDiagnostics(const CXTranslationUnit &translationUnit) const +{ + if (!lcQdocClang().isDebugEnabled()) + return; + + static const auto displayOptions = CXDiagnosticDisplayOptions::CXDiagnostic_DisplaySourceLocation + | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayColumn + | CXDiagnosticDisplayOptions::CXDiagnostic_DisplayOption; + + for (unsigned i = 0, numDiagnostics = clang_getNumDiagnostics(translationUnit); i < numDiagnostics; ++i) { + auto diagnostic = clang_getDiagnostic(translationUnit, i); + auto formattedDiagnostic = clang_formatDiagnostic(diagnostic, displayOptions); + qCDebug(lcQdocClang) << clang_getCString(formattedDiagnostic); + clang_disposeString(formattedDiagnostic); + } +} + QT_END_NAMESPACE diff --git a/src/qdoc/clangcodeparser.h b/src/qdoc/clangcodeparser.h index a022ca9d3c..9c09365d41 100644 --- a/src/qdoc/clangcodeparser.h +++ b/src/qdoc/clangcodeparser.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -40,44 +40,48 @@ #ifndef CLANGCODEPARSER_H #define CLANGCODEPARSER_H -#include - #include "cppcodeparser.h" +#include + +typedef struct CXTranslationUnitImpl *CXTranslationUnit; + QT_BEGIN_NAMESPACE class ClangCodeParser : public CppCodeParser { - Q_DECLARE_TR_FUNCTIONS(QDoc::ClangCodeParser) - public: - ~ClangCodeParser(); + ~ClangCodeParser() override; - void initializeParser(const Config& config) override; + void initializeParser() override; void terminateParser() override; QString language() override; QStringList headerFileNameFilter() override; QStringList sourceFileNameFilter() override; - void parseHeaderFile(const Location& location, const QString& filePath) override; - void parseSourceFile(const Location& location, const QString& filePath) override; + void parseHeaderFile(const Location &location, const QString &filePath) override; + void parseSourceFile(const Location &location, const QString &filePath) override; void precompileHeaders() override; Node *parseFnArg(const Location &location, const QString &fnArg) override; + static const QByteArray &fn() { return s_fn; } + +private: + void getDefaultArgs(); // FIXME: Clean up API + void getMoreArgs(); // FIXME: Clean up API - private: - void getDefaultArgs(); - bool getMoreArgs(); void buildPCH(); -private: - int printParsingErrors_; - QString version_; - QHash allHeaders_; // file name->path - QVector includePaths_; - QScopedPointer pchFileDir_; - QByteArray pchName_; - QVector defines_; - std::vector args_; - QVector moreArgs_; + void printDiagnostics(const CXTranslationUnit &translationUnit) const; + + QString m_version {}; + QHash m_allHeaders {}; // file name->path + QList m_includePaths {}; + QScopedPointer m_pchFileDir {}; + QByteArray m_pchName {}; + QList m_defines {}; + std::vector m_args {}; + QList m_moreArgs {}; + QStringList m_namespaceScope {}; + static QByteArray s_fn; }; QT_END_NAMESPACE diff --git a/src/qdoc/classnode.cpp b/src/qdoc/classnode.cpp new file mode 100644 index 0000000000..28d733a721 --- /dev/null +++ b/src/qdoc/classnode.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "classnode.h" + +#include "functionnode.h" +#include "propertynode.h" +#include "qdocdatabase.h" +#include "qmltypenode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class ClassNode + \brief The ClassNode represents a C++ class. + + It is also used to represent a C++ struct or union. There are some + actual uses for structs, but I don't think any unions have been + documented yet. + */ + +/*! + Adds the base class \a node to this class's list of base + classes. The base class has the specified \a access. This + is a resolved base class. + */ +void ClassNode::addResolvedBaseClass(Access access, ClassNode *node) +{ + m_bases.append(RelatedClass(access, node)); + node->m_derived.append(RelatedClass(access, this)); +} + +/*! + Adds the derived class \a node to this class's list of derived + classes. The derived class inherits this class with \a access. + */ +void ClassNode::addDerivedClass(Access access, ClassNode *node) +{ + m_derived.append(RelatedClass(access, node)); +} + +/*! + Add an unresolved base class to this class node's list of + base classes. The unresolved base class will be resolved + before the generate phase of qdoc. In an unresolved base + class, the pointer to the base class node is 0. + */ +void ClassNode::addUnresolvedBaseClass(Access access, const QStringList &path, + const QString &signature) +{ + m_bases.append(RelatedClass(access, path, signature)); +} + +/*! + Add an unresolved \c using clause to this class node's list + of \c using clauses. The unresolved \c using clause will be + resolved before the generate phase of qdoc. In an unresolved + \c using clause, the pointer to the function node is 0. + */ +void ClassNode::addUnresolvedUsingClause(const QString &signature) +{ + m_usingClauses.append(UsingClause(signature)); +} + +/*! + Search the child list to find the property node with the + specified \a name. + */ +PropertyNode *ClassNode::findPropertyNode(const QString &name) +{ + Node *n = findNonfunctionChild(name, &Node::isProperty); + + if (n) + return static_cast(n); + + PropertyNode *pn = nullptr; + + const QList &bases = baseClasses(); + if (!bases.isEmpty()) { + for (int i = 0; i < bases.size(); ++i) { + ClassNode *cn = bases[i].m_node; + if (cn) { + pn = cn->findPropertyNode(name); + if (pn) + break; + } + } + } + const QList &ignoredBases = ignoredBaseClasses(); + if (!ignoredBases.isEmpty()) { + for (int i = 0; i < ignoredBases.size(); ++i) { + ClassNode *cn = ignoredBases[i].m_node; + if (cn) { + pn = cn->findPropertyNode(name); + if (pn) + break; + } + } + } + + return pn; +} + +/*! + This function does a recursive search of this class node's + base classes looking for one that has a QML element. If it + finds one, it returns the pointer to that QML element. If + it doesn't find one, it returns null. + */ +QmlTypeNode *ClassNode::findQmlBaseNode() +{ + QmlTypeNode *result = nullptr; + const QList &bases = baseClasses(); + + if (!bases.isEmpty()) { + for (int i = 0; i < bases.size(); ++i) { + ClassNode *cn = bases[i].m_node; + if (cn && cn->qmlElement()) { + return cn->qmlElement(); + } + } + for (int i = 0; i < bases.size(); ++i) { + ClassNode *cn = bases[i].m_node; + if (cn) { + result = cn->findQmlBaseNode(); + if (result != nullptr) { + return result; + } + } + } + } + return result; +} + +/*! + \a fn is an overriding function in this class or in a class + derived from this class. Find the node for the function that + \a fn overrides in this class's children or in one of this + class's base classes. Return a pointer to the overridden + function or return 0. + + This should be revised because clang provides the path to the + overridden function. mws 15/12/2018 + */ +FunctionNode *ClassNode::findOverriddenFunction(const FunctionNode *fn) +{ + for (auto &bc : m_bases) { + ClassNode *cn = bc.m_node; + if (cn == nullptr) { + cn = QDocDatabase::qdocDB()->findClassNode(bc.m_path); + bc.m_node = cn; + } + if (cn != nullptr) { + FunctionNode *result = cn->findFunctionChild(fn); + if (result != nullptr && !result->isInternal() && !result->isNonvirtual() + && result->hasDoc()) + return result; + result = cn->findOverriddenFunction(fn); + if (result != nullptr && !result->isNonvirtual()) + return result; + } + } + return nullptr; +} + +/*! + \a fn is an overriding function in this class or in a class + derived from this class. Find the node for the property that + \a fn overrides in this class's children or in one of this + class's base classes. Return a pointer to the overridden + property or return 0. + */ +PropertyNode *ClassNode::findOverriddenProperty(const FunctionNode *fn) +{ + for (auto &baseClass : m_bases) { + ClassNode *cn = baseClass.m_node; + if (cn == nullptr) { + cn = QDocDatabase::qdocDB()->findClassNode(baseClass.m_path); + baseClass.m_node = cn; + } + if (cn != nullptr) { + const NodeList &children = cn->childNodes(); + for (const auto &child : children) { + if (child->isProperty()) { + auto *pn = static_cast(child); + if (pn->name() == fn->name() || pn->hasAccessFunction(fn->name())) { + if (pn->hasDoc()) + return pn; + } + } + } + PropertyNode *result = cn->findOverriddenProperty(fn); + if (result != nullptr) + return result; + } + } + return nullptr; +} + +/*! + Returns true if the class or struct represented by this class + node must be documented. If this function returns true, then + qdoc must find a qdoc comment for this class. If it returns + false, then the class need not be documented. + */ +bool ClassNode::docMustBeGenerated() const +{ + if (!hasDoc() || isPrivate() || isInternal() || isDontDocument()) + return false; + if (declLocation().fileName().endsWith(QLatin1String("_p.h")) && !hasDoc()) + return false; + + return true; +} + +/*! + A base class of this class node was private or internal. + That node's list of \a bases is traversed in this function. + Each of its public base classes is promoted to be a base + class of this node for documentation purposes. For each + private or internal class node in \a bases, this function + is called recursively with the list of base classes from + that private or internal class node. + */ +void ClassNode::promotePublicBases(const QList &bases) +{ + if (!bases.isEmpty()) { + for (int i = bases.size() - 1; i >= 0; --i) { + ClassNode *bc = bases.at(i).m_node; + if (bc == nullptr) + bc = QDocDatabase::qdocDB()->findClassNode(bases.at(i).m_path); + if (bc != nullptr) { + if (bc->isPrivate() || bc->isInternal()) + promotePublicBases(bc->baseClasses()); + else + m_bases.append(bases.at(i)); + } + } + } +} + +/*! + Remove private and internal bases classes from this class's list + of base classes. When a base class is removed from the list, add + its base classes to this class's list of base classes. + */ +void ClassNode::removePrivateAndInternalBases() +{ + int i; + i = 0; + QSet found; + + // Remove private and duplicate base classes. + while (i < m_bases.size()) { + ClassNode *bc = m_bases.at(i).m_node; + if (bc == nullptr) + bc = QDocDatabase::qdocDB()->findClassNode(m_bases.at(i).m_path); + if (bc != nullptr + && (bc->isPrivate() || bc->isInternal() || bc->isDontDocument() + || found.contains(bc))) { + RelatedClass rc = m_bases.at(i); + m_bases.removeAt(i); + m_ignoredBases.append(rc); + promotePublicBases(bc->baseClasses()); + } else { + ++i; + } + found.insert(bc); + } + + i = 0; + while (i < m_derived.size()) { + ClassNode *dc = m_derived.at(i).m_node; + if (dc != nullptr && (dc->isPrivate() || dc->isInternal() || dc->isDontDocument())) { + m_derived.removeAt(i); + const QList &dd = dc->derivedClasses(); + for (int j = dd.size() - 1; j >= 0; --j) + m_derived.insert(i, dd.at(j)); + } else { + ++i; + } + } +} + +/*! + */ +void ClassNode::resolvePropertyOverriddenFromPtrs(PropertyNode *pn) +{ + for (const auto &baseClass : qAsConst(baseClasses())) { + ClassNode *cn = baseClass.m_node; + if (cn) { + Node *n = cn->findNonfunctionChild(pn->name(), &Node::isProperty); + if (n) { + auto *baseProperty = static_cast(n); + cn->resolvePropertyOverriddenFromPtrs(baseProperty); + pn->setOverriddenFrom(baseProperty); + } else + cn->resolvePropertyOverriddenFromPtrs(pn); + } + } +} + +QT_END_NAMESPACE diff --git a/src/qdoc/classnode.h b/src/qdoc/classnode.h new file mode 100644 index 0000000000..c6bdc65c1a --- /dev/null +++ b/src/qdoc/classnode.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CLASSNODE_H +#define CLASSNODE_H + +#include "aggregate.h" +#include "relatedclass.h" +#include "usingclause.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class FunctionNode; +class PropertyNode; +class QmlTypeNode; + +class ClassNode : public Aggregate +{ +public: + ClassNode(NodeType type, Aggregate *parent, const QString &name) : Aggregate(type, parent, name) + { + } + bool isFirstClassAggregate() const override { return true; } + bool isClassNode() const override { return true; } + bool isRelatableType() const override { return true; } + bool isWrapper() const override { return m_wrapper; } + QString obsoleteLink() const override { return m_obsoleteLink; } + void setObsoleteLink(const QString &t) override { m_obsoleteLink = t; } + void setWrapper() override { m_wrapper = true; } + + void addResolvedBaseClass(Access access, ClassNode *node); + void addDerivedClass(Access access, ClassNode *node); + void addUnresolvedBaseClass(Access access, const QStringList &path, const QString &signature); + void addUnresolvedUsingClause(const QString &signature); + void removePrivateAndInternalBases(); + void resolvePropertyOverriddenFromPtrs(PropertyNode *pn); + + QList &baseClasses() { return m_bases; } + QList &derivedClasses() { return m_derived; } + QList &ignoredBaseClasses() { return m_ignoredBases; } + QList &usingClauses() { return m_usingClauses; } + + const QList &baseClasses() const { return m_bases; } + const QList &derivedClasses() const { return m_derived; } + const QList &ignoredBaseClasses() const { return m_ignoredBases; } + const QList &usingClauses() const { return m_usingClauses; } + + QmlTypeNode *qmlElement() { return m_qmlElement; } + void setQmlElement(QmlTypeNode *qcn) { m_qmlElement = qcn; } + bool isAbstract() const override { return m_abstract; } + void setAbstract(bool b) override { m_abstract = b; } + PropertyNode *findPropertyNode(const QString &name); + QmlTypeNode *findQmlBaseNode(); + FunctionNode *findOverriddenFunction(const FunctionNode *fn); + PropertyNode *findOverriddenProperty(const FunctionNode *fn); + bool docMustBeGenerated() const override; + +private: + void promotePublicBases(const QList &bases); + +private: + QList m_bases {}; + QList m_derived {}; + QList m_ignoredBases {}; + QList m_usingClauses {}; + bool m_abstract { false }; + bool m_wrapper { false }; + QString m_obsoleteLink {}; + QmlTypeNode *m_qmlElement { nullptr }; +}; + +QT_END_NAMESPACE + +#endif // CLASSNODE_H diff --git a/src/qdoc/codechunk.cpp b/src/qdoc/codechunk.cpp index 54d7f3131f..b562aa9379 100644 --- a/src/qdoc/codechunk.cpp +++ b/src/qdoc/codechunk.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -30,61 +30,58 @@ codechunk.cpp */ -#include -#include - #include "codechunk.h" +#include + QT_BEGIN_NAMESPACE enum { Other, Alnum, Gizmo, Comma, LBrace, RBrace, RAngle, Colon, Paren }; // entries 128 and above are Other -static const int charCategory[256] = { - Other, Other, Other, Other, Other, Other, Other, Other, - Other, Other, Other, Other, Other, Other, Other, Other, - Other, Other, Other, Other, Other, Other, Other, Other, - Other, Other, Other, Other, Other, Other, Other, Other, - // ! " # $ % & ' - Other, Other, Other, Other, Other, Gizmo, Gizmo, Other, - // ( ) * + , - . / - Paren, Paren, Gizmo, Gizmo, Comma, Other, Other, Gizmo, - // 0 1 2 3 4 5 6 7 - Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // 8 9 : ; < = > ? - Alnum, Alnum, Colon, Other, Other, Gizmo, RAngle, Gizmo, - // @ A B C D E F G - Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // H I J K L M N O - Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // P Q R S T U V W - Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // X Y Z [ \ ] ^ _ - Alnum, Alnum, Alnum, Other, Other, Other, Gizmo, Alnum, - // ` a b c d e f g - Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // h i j k l m n o - Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // p q r s t u v w - Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, - // x y z { | } ~ - Alnum, Alnum, Alnum, LBrace, Gizmo, RBrace, Other, Other -}; +static const int charCategory[256] = { Other, Other, Other, Other, Other, Other, Other, Other, + Other, Other, Other, Other, Other, Other, Other, Other, + Other, Other, Other, Other, Other, Other, Other, Other, + Other, Other, Other, Other, Other, Other, Other, Other, + // ! " # $ % & ' + Other, Other, Other, Other, Other, Gizmo, Gizmo, Other, + // ( ) * + , - . / + Paren, Paren, Gizmo, Gizmo, Comma, Other, Other, Gizmo, + // 0 1 2 3 4 5 6 7 + Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // 8 9 : ; < = > ? + Alnum, Alnum, Colon, Other, Other, Gizmo, RAngle, Gizmo, + // @ A B C D E F G + Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // H I J K L M N O + Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // P Q R S T U V W + Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // X Y Z [ \ ] ^ _ + Alnum, Alnum, Alnum, Other, Other, Other, Gizmo, Alnum, + // ` a b c d e f g + Other, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // h i j k l m n o + Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // p q r s t u v w + Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, Alnum, + // x y z { | } ~ + Alnum, Alnum, Alnum, LBrace, Gizmo, RBrace, Other, Other }; static const bool needSpace[9][9] = { /* [ a + , { } > : ) */ - /* [ */ { false, false, false, false, false, true, false, false, false }, - /* a */ { false, true, true, false, false, true, false, false, false }, - /* + */ { false, true, false, false, false, true, false, true, false }, - /* , */ { true, true, true, true, true, true, true, true, false }, + /* [ */ { false, false, false, false, false, true, false, false, false }, + /* a */ { false, true, true, false, false, true, false, false, false }, + /* + */ { false, true, false, false, false, true, false, true, false }, + /* , */ { true, true, true, true, true, true, true, true, false }, /* { */ { false, false, false, false, false, false, false, false, false }, /* } */ { false, false, false, false, false, false, false, false, false }, - /* > */ { true, true, true, false, true, true, true, false, false }, - /* : */ { false, false, true, true, true, true, true, false, false }, + /* > */ { true, true, true, false, true, true, true, false, false }, + /* : */ { false, false, true, true, true, true, true, false, false }, /* ( */ { false, false, false, false, false, false, false, false, false }, }; -static int category( QChar ch ) +static int category(QChar ch) { return charCategory[static_cast(ch.toLatin1())]; } @@ -120,31 +117,19 @@ static int category( QChar ch ) Appends \a lexeme to the current string contents, inserting a space if appropriate. */ -void CodeChunk::append( const QString& lexeme ) +void CodeChunk::append(const QString &lexeme) { - if ( !s.isEmpty() && !lexeme.isEmpty() ) { + if (!s.isEmpty() && !lexeme.isEmpty()) { /* Should there be a space or not between the code chunk so far and the new lexeme? */ int cat1 = category(s.at(s.size() - 1)); int cat2 = category(lexeme[0]); - if ( needSpace[cat1][cat2] ) - s += QLatin1Char( ' ' ); + if (needSpace[cat1][cat2]) + s += QLatin1Char(' '); } s += lexeme; } -/*! - Converts the string with a regular expression that I think - removes the angle brackets parts and then splits it on "::". - The result is returned as a string list. - */ -QStringList CodeChunk::toPath() const -{ - QString t = s; - t.remove(QRegExp(QLatin1String("<([^<>]|<([^<>]|<[^<>]*>)*>)*>"))); - return t.split(QLatin1String("::")); -} - QT_END_NAMESPACE diff --git a/src/qdoc/codechunk.h b/src/qdoc/codechunk.h index 0e1d3d2b4f..43d258c8f3 100644 --- a/src/qdoc/codechunk.h +++ b/src/qdoc/codechunk.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -33,7 +33,7 @@ #ifndef CODECHUNK_H #define CODECHUNK_H -#include +#include QT_BEGIN_NAMESPACE @@ -43,15 +43,17 @@ class CodeChunk { public: CodeChunk() : hotspot(-1) {} - CodeChunk(const QString& str) : s(str), hotspot(-1) {} - void append( const QString& lexeme ); - void appendHotspot() { if (hotspot == -1) hotspot = s.length(); } + void append(const QString &lexeme); + void appendHotspot() + { + if (hotspot == -1) + hotspot = s.length(); + } bool isEmpty() const { return s.isEmpty(); } void clear() { s.clear(); } QString toString() const { return s; } - QStringList toPath() const; QString left() const { return s.left(hotspot == -1 ? s.length() : hotspot); } QString right() const { return s.mid(hotspot == -1 ? s.length() : hotspot); } @@ -60,28 +62,34 @@ class CodeChunk int hotspot; }; -inline bool operator==( const CodeChunk& c, const CodeChunk& d ) { +inline bool operator==(const CodeChunk &c, const CodeChunk &d) +{ return c.toString() == d.toString(); } -inline bool operator!=( const CodeChunk& c, const CodeChunk& d ) { - return !( c == d ); +inline bool operator!=(const CodeChunk &c, const CodeChunk &d) +{ + return !(c == d); } -inline bool operator<( const CodeChunk& c, const CodeChunk& d ) { +inline bool operator<(const CodeChunk &c, const CodeChunk &d) +{ return c.toString() < d.toString(); } -inline bool operator>( const CodeChunk& c, const CodeChunk& d ) { +inline bool operator>(const CodeChunk &c, const CodeChunk &d) +{ return d < c; } -inline bool operator<=( const CodeChunk& c, const CodeChunk& d ) { - return !( c > d ); +inline bool operator<=(const CodeChunk &c, const CodeChunk &d) +{ + return !(c > d); } -inline bool operator>=( const CodeChunk& c, const CodeChunk& d ) { - return !( c < d ); +inline bool operator>=(const CodeChunk &c, const CodeChunk &d) +{ + return !(c < d); } QT_END_NAMESPACE diff --git a/src/qdoc/codemarker.cpp b/src/qdoc/codemarker.cpp index 3c88edf034..41a369ae1e 100644 --- a/src/qdoc/codemarker.cpp +++ b/src/qdoc/codemarker.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,12 +26,15 @@ ** ****************************************************************************/ -#include #include "codemarker.h" + +#include "classnode.h" #include "config.h" +#include "functionnode.h" #include "node.h" -#include -#include +#include "propertynode.h" + +#include QT_BEGIN_NAMESPACE @@ -63,9 +66,7 @@ CodeMarker::~CodeMarker() A code market performs no initialization by default. Marker-specific initialization is performed in subclasses. */ -void CodeMarker::initializeMarker(const Config& ) // config -{ -} +void CodeMarker::initializeMarker() {} /*! Terminating a code marker is trivial. @@ -79,14 +80,11 @@ void CodeMarker::terminateMarker() All the code markers in the static list are initialized here, after the qdoc configuration file has been loaded. */ -void CodeMarker::initialize(const Config& config) +void CodeMarker::initialize() { - defaultLang = config.getString(CONFIG_LANGUAGE); - QList::ConstIterator m = markers.constBegin(); - while (m != markers.constEnd()) { - (*m)->initializeMarker(config); - ++m; - } + defaultLang = Config::instance().getString(CONFIG_LANGUAGE); + for (const auto &marker : qAsConst(markers)) + marker->initializeMarker(); } /*! @@ -94,29 +92,25 @@ void CodeMarker::initialize(const Config& config) */ void CodeMarker::terminate() { - QList::ConstIterator m = markers.constBegin(); - while (m != markers.constEnd()) { - (*m)->terminateMarker(); - ++m; - } + for (const auto &marker : qAsConst(markers)) + marker->terminateMarker(); } -CodeMarker *CodeMarker::markerForCode(const QString& code) +CodeMarker *CodeMarker::markerForCode(const QString &code) { CodeMarker *defaultMarker = markerForLanguage(defaultLang); if (defaultMarker != nullptr && defaultMarker->recognizeCode(code)) return defaultMarker; - QList::ConstIterator m = markers.constBegin(); - while (m != markers.constEnd()) { - if ((*m)->recognizeCode(code)) - return *m; - ++m; + for (const auto &marker : qAsConst(markers)) { + if (marker->recognizeCode(code)) + return marker; } + return defaultMarker; } -CodeMarker *CodeMarker::markerForFileName(const QString& fileName) +CodeMarker *CodeMarker::markerForFileName(const QString &fileName) { CodeMarker *defaultMarker = markerForLanguage(defaultLang); int dot = -1; @@ -124,29 +118,25 @@ CodeMarker *CodeMarker::markerForFileName(const QString& fileName) QString ext = fileName.mid(dot + 1); if (defaultMarker != nullptr && defaultMarker->recognizeExtension(ext)) return defaultMarker; - QList::ConstIterator m = markers.constBegin(); - while (m != markers.constEnd()) { - if ((*m)->recognizeExtension(ext)) - return *m; - ++m; + for (const auto &marker : qAsConst(markers)) { + if (marker->recognizeExtension(ext)) + return marker; } --dot; } return defaultMarker; } -CodeMarker *CodeMarker::markerForLanguage(const QString& lang) +CodeMarker *CodeMarker::markerForLanguage(const QString &lang) { - QList::ConstIterator m = markers.constBegin(); - while (m != markers.constEnd()) { - if ((*m)->recognizeLanguage(lang)) - return *m; - ++m; + for (const auto &marker : qAsConst(markers)) { + if (marker->recognizeLanguage(lang)) + return marker; } return nullptr; } -const Node *CodeMarker::nodeForString(const QString& string) +const Node *CodeMarker::nodeForString(const QString &string) { #if QT_POINTER_SIZE == 4 const quintptr n = string.toUInt(); @@ -158,20 +148,94 @@ const Node *CodeMarker::nodeForString(const QString& string) QString CodeMarker::stringForNode(const Node *node) { - if (sizeof(const Node *) == sizeof(ulong)) { - return QString::number(reinterpret_cast(node)); + return QString::number(reinterpret_cast(node)); +} + +/*! + Returns the 'extra' synopsis string for \a node with status information, + using a specified section \a style. +*/ +QString CodeMarker::extraSynopsis(const Node *node, Section::Style style) +{ + QStringList extra; + if (style == Section::Details) { + switch (node->nodeType()) { + case Node::Function: { + const auto *func = static_cast(node); + if (func->isStatic()) { + extra << "static"; + } else if (!func->isNonvirtual()) { + if (func->isFinal()) + extra << "final"; + if (func->isOverride()) + extra << "override"; + if (func->isPureVirtual()) + extra << "pure"; + extra << "virtual"; + } + + if (func->access() == Access::Protected) + extra << "protected"; + else if (func->access() == Access::Private) + extra << "private"; + + if (func->isSignal()) { + if (func->parameters().isPrivateSignal()) + extra << "private"; + extra << "signal"; + } else if (func->isSlot()) + extra << "slot"; + else if (func->isDefault()) + extra << "default"; + else if (func->isInvokable()) + extra << "invokable"; + } + break; + case Node::TypeAlias: + extra << "alias"; + break; + case Node::Property: { + auto propertyNode = static_cast(node); + if (propertyNode->propertyType() == PropertyNode::Bindable) + extra << "bindable"; + if (!propertyNode->isWritable()) + extra << "read-only"; + } + break; + default: + break; + } + } else if (style == Section::Summary) { + if (node->isPreliminary()) + extra << "preliminary"; + else if (node->isDeprecated()) + extra << "deprecated"; + else if (node->isObsolete()) + extra << "obsolete"; } - else { - return QString::number(reinterpret_cast(node)); + + if (style == Section::Details && !node->since().isEmpty()) { + if (!extra.isEmpty()) + extra.last() += QLatin1Char(','); + extra << "since" << node->since(); + } + + QString extraStr = extra.join(QLatin1Char(' ')); + if (!extraStr.isEmpty()) { + extraStr.prepend(style == Section::Details ? '[' : '('); + extraStr.append(style == Section::Details ? ']' : ')'); + extraStr.append(' '); } + + return extraStr; } -static const QString samp = QLatin1String("&"); -static const QString slt = QLatin1String("<"); -static const QString sgt = QLatin1String(">"); +static const QString samp = QLatin1String("&"); +static const QString slt = QLatin1String("<"); +static const QString sgt = QLatin1String(">"); static const QString squot = QLatin1String("""); -QString CodeMarker::protect(const QString& str) +QString CodeMarker::protect(const QString &str) { int n = str.length(); QString marked; @@ -179,28 +243,46 @@ QString CodeMarker::protect(const QString& str) const QChar *data = str.constData(); for (int i = 0; i != n; ++i) { switch (data[i].unicode()) { - case '&': marked += samp; break; - case '<': marked += slt; break; - case '>': marked += sgt; break; - case '"': marked += squot; break; - default : marked += data[i]; + case '&': + marked += samp; + break; + case '<': + marked += slt; + break; + case '>': + marked += sgt; + break; + case '"': + marked += squot; + break; + default: + marked += data[i]; } } return marked; } -void CodeMarker::appendProtectedString(QString *output, const QStringRef &str) +void CodeMarker::appendProtectedString(QString *output, QStringView str) { int n = str.length(); output->reserve(output->size() + n * 2 + 30); const QChar *data = str.constData(); for (int i = 0; i != n; ++i) { switch (data[i].unicode()) { - case '&': *output += samp; break; - case '<': *output += slt; break; - case '>': *output += sgt; break; - case '"': *output += squot; break; - default : *output += data[i]; + case '&': + *output += samp; + break; + case '<': + *output += slt; + break; + case '>': + *output += sgt; + break; + case '"': + *output += squot; + break; + default: + *output += data[i]; } } } @@ -216,12 +298,10 @@ QString CodeMarker::typified(const QString &string, bool trailingSpace) ch = string.at(i); QChar lower = ch.toLower(); - if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) - || ch.digitValue() >= 0 || ch == QLatin1Char('_') - || ch == QLatin1Char(':')) { + if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) || ch.digitValue() >= 0 + || ch == QLatin1Char('_') || ch == QLatin1Char(':')) { pendingWord += ch; - } - else { + } else { if (!pendingWord.isEmpty()) { bool isProbablyType = (pendingWord != QLatin1String("const")); if (isProbablyType) @@ -250,14 +330,13 @@ QString CodeMarker::typified(const QString &string, bool trailingSpace) } } if (trailingSpace && string.size()) { - if (!string.endsWith(QLatin1Char('*')) - && !string.endsWith(QLatin1Char('&'))) - result += QLatin1Char(' '); + if (!string.endsWith(QLatin1Char('*')) && !string.endsWith(QLatin1Char('&'))) + result += QLatin1Char(' '); } return result; } -QString CodeMarker::taggedNode(const Node* node) +QString CodeMarker::taggedNode(const Node *node) { QString tag; QString name = node->name(); @@ -303,15 +382,15 @@ QString CodeMarker::taggedNode(const Node* node) tag = QLatin1String("@unknown"); break; } - return (QLatin1Char('<') + tag + QLatin1Char('>') + protect(name) - + QLatin1String("')); + return (QLatin1Char('<') + tag + QLatin1Char('>') + protect(name) + QLatin1String("')); } -QString CodeMarker::taggedQmlNode(const Node* node) +QString CodeMarker::taggedQmlNode(const Node *node) { QString tag; if (node->isFunction()) { - const FunctionNode* fn = static_cast(node); + const FunctionNode *fn = static_cast(node); switch (fn->metaness()) { case FunctionNode::JsSignal: case FunctionNode::QmlSignal: @@ -334,107 +413,14 @@ QString CodeMarker::taggedQmlNode(const Node* node) } else { tag = QLatin1String("@unknown"); } - return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) - + QLatin1String("'); -} - -QString CodeMarker::linkTag(const Node *node, const QString& body) -{ - return QLatin1String("<@link node=\"") + stringForNode(node) - + QLatin1String("\">") + body + QLatin1String(""); -} - -static QString encode(const QString &string) -{ - return string; -} - -QStringList CodeMarker::macRefsForNode(Node *node) -{ - QString result = QLatin1String("cpp/"); - switch (node->nodeType()) { - case Node::Class: - { - const ClassNode *classe = static_cast(node); - { - result += QLatin1String("cl/"); - } - result += macName(classe); // ### Maybe plainName? - } - break; - case Node::Enum: - { - QStringList stringList; - stringList << encode(result + QLatin1String("tag/") + macName(node)); - foreach (const QString &enumName, node->doc().enumItemNames()) { - // ### Write a plainEnumValue() and use it here - stringList << encode(result + QLatin1String("econst/") + - macName(node->parent(), enumName)); - } - return stringList; - } - case Node::Typedef: - result += QLatin1String("tdef/") + macName(node); - break; - case Node::Function: - { - bool isMacro = false; - Q_UNUSED(isMacro); - const FunctionNode *func = static_cast(node); - - // overloads are too clever for the Xcode documentation browser - if (func->isOverload()) - return QStringList(); - - if (func->isMacro()) { - result += QLatin1String("macro/"); - } - else if (func->isStatic()) { - result += QLatin1String("clm/"); - } - else if (!func->parent()->name().isEmpty()) { - result += QLatin1String("instm/"); - } - else { - result += QLatin1String("func/"); - } - - result += macName(func); - if (result.endsWith(QLatin1String("()"))) - result.chop(2); - } - break; - case Node::Variable: - result += QLatin1String("data/") + macName(node); - break; - case Node::Property: - { - NodeList list = static_cast(node)->functions(); - QStringList stringList; - foreach (Node* node, list) { - stringList += macRefsForNode(node); - } - return stringList; - } - default: - return QStringList(); - } - - return QStringList(encode(result)); + return QLatin1Char('<') + tag + QLatin1Char('>') + protect(node->name()) + QLatin1String("'); } -QString CodeMarker::macName(const Node *node, const QString &name) +QString CodeMarker::linkTag(const Node *node, const QString &body) { - QString myName = name; - if (myName.isEmpty()) { - myName = node->name(); - node = node->parent(); - } - - if (node->name().isEmpty()) - return QLatin1Char('/') + protect(myName); - else - return node->plainFullName() + QLatin1Char('/') + protect(myName); + return QLatin1String("<@link node=\"") + stringForNode(node) + QLatin1String("\">") + body + + QLatin1String(""); } QT_END_NAMESPACE diff --git a/src/qdoc/codemarker.h b/src/qdoc/codemarker.h index c7f58ab42a..73fdadbbd9 100644 --- a/src/qdoc/codemarker.h +++ b/src/qdoc/codemarker.h @@ -34,68 +34,65 @@ QT_BEGIN_NAMESPACE -class Config; - class CodeMarker { public: CodeMarker(); virtual ~CodeMarker(); - virtual void initializeMarker(const Config& config); + virtual void initializeMarker(); virtual void terminateMarker(); - virtual bool recognizeCode(const QString& /*code*/) { return true; } - virtual bool recognizeExtension(const QString& /*extension*/) { return true; } - virtual bool recognizeLanguage(const QString& /*language*/) { return false; } + virtual bool recognizeCode(const QString & /*code*/) { return true; } + virtual bool recognizeExtension(const QString & /*extension*/) { return true; } + virtual bool recognizeLanguage(const QString & /*language*/) { return false; } virtual Atom::AtomType atomType() const { return Atom::Code; } - virtual QString markedUpCode(const QString &code, - const Node* /*relative*/, - const Location& /*location*/) { return protect(code); } - virtual QString markedUpSynopsis(const Node* /*node*/, - const Node* /*relative*/, - Section::Style /*style*/) { return QString(); } - virtual QString markedUpQmlItem(const Node* , bool) { return QString(); } - virtual QString markedUpName(const Node* /*node*/) { return QString(); } - virtual QString markedUpFullName(const Node* /*node*/, - const Node* /*relative*/) { return QString(); } - virtual QString markedUpEnumValue(const QString& /*enumValue*/, - const Node* /*relative*/) { return QString(); } - virtual QString markedUpIncludes(const QStringList& /*includes*/) { return QString(); } - virtual QString functionBeginRegExp(const QString& /*funcName*/) { return QString(); } - virtual QString functionEndRegExp(const QString& /*funcName*/) { return QString(); } - virtual QStringList macRefsForNode(Node* node); + virtual QString markedUpCode(const QString &code, const Node * /*relative*/, + const Location & /*location*/) + { + return protect(code); + } + virtual QString markedUpSynopsis(const Node * /*node*/, const Node * /*relative*/, + Section::Style /*style*/) + { + return QString(); + } + virtual QString markedUpQmlItem(const Node *, bool) { return QString(); } + virtual QString markedUpName(const Node * /*node*/) { return QString(); } + virtual QString markedUpFullName(const Node * /*node*/, const Node * /*relative*/) + { + return QString(); + } + virtual QString markedUpEnumValue(const QString & /*enumValue*/, const Node * /*relative*/) + { + return QString(); + } + virtual QString markedUpIncludes(const QStringList & /*includes*/) { return QString(); } + virtual QString functionBeginRegExp(const QString & /*funcName*/) { return QString(); } + virtual QString functionEndRegExp(const QString & /*funcName*/) { return QString(); } - static void initialize(const Config& config); + static void initialize(); static void terminate(); - static CodeMarker *markerForCode(const QString& code); - static CodeMarker *markerForFileName(const QString& fileName); - static CodeMarker *markerForLanguage(const QString& lang); - static const Node *nodeForString(const QString& string); + static CodeMarker *markerForCode(const QString &code); + static CodeMarker *markerForFileName(const QString &fileName); + static CodeMarker *markerForLanguage(const QString &lang); + static const Node *nodeForString(const QString &string); static QString stringForNode(const Node *node); + static QString extraSynopsis(const Node *node, Section::Style style); QString typified(const QString &string, bool trailingSpace = false); protected: static QString protect(const QString &string); - static void appendProtectedString(QString *output, const QStringRef &str); - QString taggedNode(const Node* node); - QString taggedQmlNode(const Node* node); - QString linkTag(const Node *node, const QString& body); + static void appendProtectedString(QString *output, QStringView str); + QString taggedNode(const Node *node); + QString taggedQmlNode(const Node *node); + QString linkTag(const Node *node, const QString &body); private: - QString macName(const Node *parent, const QString &name = QString()); - static QString defaultLang; static QList markers; }; -class PlainCodeMarker : public CodeMarker -{ - public: - PlainCodeMarker() { } - ~PlainCodeMarker() { } -}; - QT_END_NAMESPACE #endif diff --git a/src/qdoc/codeparser.cpp b/src/qdoc/codeparser.cpp index 42adae2445..a1560a5057 100644 --- a/src/qdoc/codeparser.cpp +++ b/src/qdoc/codeparser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -31,12 +31,14 @@ */ #include "codeparser.h" -#include "node.h" -#include "tree.h" + #include "config.h" #include "generator.h" +#include "node.h" +#include "proxynode.h" #include "qdocdatabase.h" -#include + +#include QT_BEGIN_NAMESPACE @@ -66,10 +68,10 @@ CodeParser::~CodeParser() /*! Initialize the code parser base class. */ -void CodeParser::initializeParser(const Config& config) +void CodeParser::initializeParser() { - showInternal_ = config.getBool(CONFIG_SHOWINTERNAL); - singleExec_ = config.getBool(CONFIG_SINGLEEXEC); + showInternal_ = Config::instance().showInternal(); + singleExec_ = Config::instance().getBool(CONFIG_SINGLEEXEC); } /*! @@ -85,7 +87,7 @@ QStringList CodeParser::headerFileNameFilter() return sourceFileNameFilter(); } -void CodeParser::parseHeaderFile(const Location& location, const QString& filePath) +void CodeParser::parseHeaderFile(const Location &location, const QString &filePath) { parseSourceFile(location, filePath); } @@ -94,13 +96,10 @@ void CodeParser::parseHeaderFile(const Location& location, const QString& filePa All the code parsers in the static list are initialized here, after the qdoc configuration variables have been set. */ -void CodeParser::initialize(const Config& config) +void CodeParser::initialize() { - QList::ConstIterator p = parsers.constBegin(); - while (p != parsers.constEnd()) { - (*p)->initializeParser(config); - ++p; - } + for (const auto &parser : qAsConst(parsers)) + parser->initializeParser(); } /*! @@ -108,20 +107,15 @@ void CodeParser::initialize(const Config& config) */ void CodeParser::terminate() { - QList::ConstIterator p = parsers.constBegin(); - while (p != parsers.constEnd()) { - (*p)->terminateParser(); - ++p; - } + for (const auto parser : parsers) + parser->terminateParser(); } -CodeParser *CodeParser::parserForLanguage(const QString& language) +CodeParser *CodeParser::parserForLanguage(const QString &language) { - QList::ConstIterator p = parsers.constBegin(); - while (p != parsers.constEnd()) { - if ((*p)->language() == language) - return *p; - ++p; + for (const auto parser : qAsConst(parsers)) { + if (parser->language() == language) + return parser; } return nullptr; } @@ -130,16 +124,13 @@ CodeParser *CodeParser::parserForHeaderFile(const QString &filePath) { QString fileName = QFileInfo(filePath).fileName(); - QList::ConstIterator p = parsers.constBegin(); - while (p != parsers.constEnd()) { - - QStringList headerPatterns = (*p)->headerFileNameFilter(); - foreach (const QString &pattern, headerPatterns) { - QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.exactMatch(fileName)) - return *p; + for (const auto &parser : qAsConst(parsers)) { + const QStringList headerPatterns = parser->headerFileNameFilter(); + for (const auto &pattern : headerPatterns) { + auto re = QRegularExpression::fromWildcard(pattern, Qt::CaseInsensitive); + if (re.match(fileName).hasMatch()) + return parser; } - ++p; } return nullptr; } @@ -148,16 +139,13 @@ CodeParser *CodeParser::parserForSourceFile(const QString &filePath) { QString fileName = QFileInfo(filePath).fileName(); - QList::ConstIterator p = parsers.constBegin(); - while (p != parsers.constEnd()) { - - QStringList sourcePatterns = (*p)->sourceFileNameFilter(); - foreach (const QString &pattern, sourcePatterns) { - QRegExp re(pattern, Qt::CaseInsensitive, QRegExp::Wildcard); - if (re.exactMatch(fileName)) - return *p; + for (const auto &parser : parsers) { + const QStringList sourcePatterns = parser->sourceFileNameFilter(); + for (const QString &pattern : sourcePatterns) { + auto re = QRegularExpression::fromWildcard(pattern, Qt::CaseInsensitive); + if (re.match(fileName).hasMatch()) + return parser; } - ++p; } return nullptr; } @@ -166,63 +154,42 @@ static QSet commonMetaCommands_; /*! Returns the set of strings representing the common metacommands. */ -const QSet& CodeParser::commonMetaCommands() +const QSet &CodeParser::commonMetaCommands() { if (commonMetaCommands_.isEmpty()) { - commonMetaCommands_ << COMMAND_ABSTRACT - << COMMAND_DEPRECATED - << COMMAND_INGROUP - << COMMAND_INJSMODULE - << COMMAND_INMODULE - << COMMAND_INPUBLICGROUP - << COMMAND_INQMLMODULE - << COMMAND_INTERNAL - << COMMAND_MAINCLASS - << COMMAND_NOAUTOLIST - << COMMAND_NONREENTRANT - << COMMAND_OBSOLETE - << COMMAND_PAGEKEYWORDS - << COMMAND_PRELIMINARY - << COMMAND_QMLABSTRACT - << COMMAND_QMLDEFAULT - << COMMAND_QMLINHERITS - << COMMAND_QMLREADONLY - << COMMAND_QTVARIABLE - << COMMAND_REENTRANT - << COMMAND_SINCE - << COMMAND_STARTPAGE - << COMMAND_SUBTITLE - << COMMAND_THREADSAFE - << COMMAND_TITLE - << COMMAND_WRAPPER; - } + commonMetaCommands_ << COMMAND_ABSTRACT << COMMAND_DEPRECATED << COMMAND_INGROUP + << COMMAND_INJSMODULE << COMMAND_INMODULE << COMMAND_INPUBLICGROUP + << COMMAND_INQMLMODULE << COMMAND_INTERNAL << COMMAND_NOAUTOLIST + << COMMAND_NONREENTRANT << COMMAND_OBSOLETE << COMMAND_PRELIMINARY + << COMMAND_QMLABSTRACT << COMMAND_QMLDEFAULT << COMMAND_QMLINHERITS + << COMMAND_QMLREADONLY << COMMAND_QMLREQUIRED << COMMAND_QTCMAKEPACKAGE + << COMMAND_QTVARIABLE << COMMAND_REENTRANT << COMMAND_SINCE + << COMMAND_STARTPAGE << COMMAND_SUBTITLE << COMMAND_THREADSAFE + << COMMAND_TITLE << COMMAND_WRAPPER; + } return commonMetaCommands_; } /*! \internal */ -void CodeParser::extractPageLinkAndDesc(const QString& arg, - QString* link, - QString* desc) +void CodeParser::extractPageLinkAndDesc(QStringView arg, QString *link, QString *desc) { - QRegExp bracedRegExp(QLatin1String("\\{([^{}]*)\\}(?:\\{([^{}]*)\\})?")); - - if (bracedRegExp.exactMatch(arg)) { - *link = bracedRegExp.cap(1); - *desc = bracedRegExp.cap(2); + QRegularExpression bracedRegExp(QRegularExpression::anchoredPattern(QLatin1String("\\{([^{}]*)\\}(?:\\{([^{}]*)\\})?"))); + auto match = bracedRegExp.match(arg); + if (match.hasMatch()) { + *link = match.captured(1); + *desc = match.captured(2); if (desc->isEmpty()) *desc = *link; - } - else { + } else { int spaceAt = arg.indexOf(QLatin1Char(' ')); if (arg.contains(QLatin1String(".html")) && spaceAt != -1) { - *link = arg.leftRef(spaceAt).trimmed().toString(); - *desc = arg.midRef(spaceAt).trimmed().toString(); - } - else { - *link = arg; - *desc = arg; + *link = arg.left(spaceAt).trimmed().toString(); + *desc = arg.mid(spaceAt).trimmed().toString(); + } else { + *link = arg.toString(); + *desc = *link; } } } @@ -230,7 +197,7 @@ void CodeParser::extractPageLinkAndDesc(const QString& arg, /*! \internal */ -void CodeParser::setLink(Node* node, Node::LinkType linkType, const QString& arg) +void CodeParser::setLink(Node *node, Node::LinkType linkType, const QString &arg) { QString link; QString desc; @@ -299,31 +266,36 @@ bool CodeParser::isParsingQdoc() const In some cases it prints a qdoc warning that it has done this. Namely, for C++ classes and namespaces. */ -void CodeParser::checkModuleInclusion(Node* n) +void CodeParser::checkModuleInclusion(Node *n) { if (n->physicalModuleName().isEmpty()) { n->setPhysicalModuleName(Generator::defaultModuleName()); - QString word; - switch (n->nodeType()) { - case Node::Class: - word = QLatin1String("Class"); - break; - case Node::Struct: - word = QLatin1String("Struct"); - break; - case Node::Union: - word = QLatin1String("Union"); - break; - case Node::Namespace: - word = QLatin1String("Namespace"); - break; - default: - return; - } - if (!n->isPrivate() && !n->name().isEmpty() && !n->doc().isEmpty()) { - n->doc().location().warning(tr("%1 %2 has no \\inmodule command; " - "using project name by default: %3") - .arg(word).arg(n->name()).arg(Generator::defaultModuleName())); + + if (n->isInAPI() && !n->name().isEmpty()) { + QString word; + switch (n->nodeType()) { + case Node::Class: + word = QLatin1String("Class"); + break; + case Node::Struct: + word = QLatin1String("Struct"); + break; + case Node::Union: + word = QLatin1String("Union"); + break; + case Node::Namespace: + word = QLatin1String("Namespace"); + break; + default: + return; + } + + qdb_->addToModule(Generator::defaultModuleName(), n); + n->doc().location().warning(QStringLiteral("%1 %2 has no \\inmodule command; " + "using project name by default: %3") + .arg(word) + .arg(n->name()) + .arg(Generator::defaultModuleName())); } } } diff --git a/src/qdoc/codeparser.h b/src/qdoc/codeparser.h index 56183a2f8c..5fe0fc8c99 100644 --- a/src/qdoc/codeparser.h +++ b/src/qdoc/codeparser.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -29,59 +29,55 @@ #ifndef CODEPARSER_H #define CODEPARSER_H -#include #include "node.h" +#include + QT_BEGIN_NAMESPACE -class Config; class Location; class QString; class QDocDatabase; class CodeParser { - Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) - public: CodeParser(); virtual ~CodeParser(); - virtual void initializeParser(const Config& config); + virtual void initializeParser(); virtual void terminateParser(); virtual QString language() = 0; virtual QStringList headerFileNameFilter(); virtual QStringList sourceFileNameFilter() = 0; - virtual void parseHeaderFile(const Location& location, const QString& filePath); - virtual void parseSourceFile(const Location& location, const QString& filePath) = 0; - virtual void precompileHeaders() { } + virtual void parseHeaderFile(const Location &location, const QString &filePath); + virtual void parseSourceFile(const Location &location, const QString &filePath) = 0; + virtual void precompileHeaders() {} virtual Node *parseFnArg(const Location &, const QString &) { return nullptr; } bool isParsingH() const; bool isParsingCpp() const; bool isParsingQdoc() const; - const QString& currentFile() const { return currentFile_; } - const QString& moduleHeader() const { return moduleHeader_; } - void setModuleHeader(const QString& t) { moduleHeader_ = t; } - void checkModuleInclusion(Node* n); + const QString ¤tFile() const { return currentFile_; } + const QString &moduleHeader() const { return moduleHeader_; } + void setModuleHeader(const QString &t) { moduleHeader_ = t; } + void checkModuleInclusion(Node *n); - static void initialize(const Config& config); + static void initialize(); static void terminate(); - static CodeParser *parserForLanguage(const QString& language); + static CodeParser *parserForLanguage(const QString &language); static CodeParser *parserForHeaderFile(const QString &filePath); static CodeParser *parserForSourceFile(const QString &filePath); - static void setLink(Node* node, Node::LinkType linkType, const QString& arg); + static void setLink(Node *node, Node::LinkType linkType, const QString &arg); static bool isWorthWarningAbout(const Doc &doc); protected: - const QSet& commonMetaCommands(); - static void extractPageLinkAndDesc(const QString& arg, - QString* link, - QString* desc); + const QSet &commonMetaCommands(); + static void extractPageLinkAndDesc(QStringView arg, QString *link, QString *desc); static bool showInternal() { return showInternal_; } QString moduleHeader_; QString currentFile_; - QDocDatabase* qdb_; + QDocDatabase *qdb_; private: static QList parsers; @@ -89,96 +85,79 @@ class CodeParser static bool singleExec_; }; -#define COMMAND_ABSTRACT Doc::alias(QLatin1String("abstract")) -#define COMMAND_AUDIENCE Doc::alias(QLatin1String("audience")) -#define COMMAND_AUTHOR Doc::alias(QLatin1String("author")) -#define COMMAND_CATEGORY Doc::alias(QLatin1String("category")) -#define COMMAND_CLASS Doc::alias(QLatin1String("class")) -#define COMMAND_COMPONENT Doc::alias(QLatin1String("component")) -#define COMMAND_CONTENTSPAGE Doc::alias(QLatin1String("contentspage")) -#define COMMAND_COPYRHOLDER Doc::alias(QLatin1String("copyrholder")) -#define COMMAND_COPYRYEAR Doc::alias(QLatin1String("copyryear")) -#define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated")) // ### don't document -#define COMMAND_DONTDOCUMENT Doc::alias(QLatin1String("dontdocument")) -#define COMMAND_DITAMAP Doc::alias(QLatin1String("ditamap")) -#define COMMAND_ENUM Doc::alias(QLatin1String("enum")) -#define COMMAND_EXAMPLE Doc::alias(QLatin1String("example")) -#define COMMAND_EXTERNALPAGE Doc::alias(QLatin1String("externalpage")) -#define COMMAND_FN Doc::alias(QLatin1String("fn")) -#define COMMAND_GROUP Doc::alias(QLatin1String("group")) -#define COMMAND_HEADERFILE Doc::alias(QLatin1String("headerfile")) -#define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup")) -#define COMMAND_INHEADERFILE Doc::alias(QLatin1String("inheaderfile")) -#define COMMAND_INJSMODULE Doc::alias(QLatin1String("injsmodule")) -#define COMMAND_INMODULE Doc::alias(QLatin1String("inmodule")) // ### don't document -#define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) -#define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule")) -#define COMMAND_INTERNAL Doc::alias(QLatin1String("internal")) -#define COMMAND_JSATTACHEDMETHOD Doc::alias(QLatin1String("jsattachedmethod")) -#define COMMAND_JSATTACHEDPROPERTY Doc::alias(QLatin1String("jsattachedproperty")) -#define COMMAND_JSATTACHEDSIGNAL Doc::alias(QLatin1String("jsattachedsignal")) -#define COMMAND_JSBASICTYPE Doc::alias(QLatin1String("jsbasictype")) -#define COMMAND_JSMETHOD Doc::alias(QLatin1String("jsmethod")) -#define COMMAND_JSMODULE Doc::alias(QLatin1String("jsmodule")) -#define COMMAND_JSPROPERTY Doc::alias(QLatin1String("jsproperty")) -#define COMMAND_JSPROPERTYGROUP Doc::alias(QLatin1String("jspropertygroup")) -#define COMMAND_JSSIGNAL Doc::alias(QLatin1String("jssignal")) -#define COMMAND_JSTYPE Doc::alias(QLatin1String("jstype")) -#define COMMAND_LICENSEDESCRIPTION Doc::alias(QLatin1String("licensedescription")) -#define COMMAND_LICENSENAME Doc::alias(QLatin1String("licensename")) -#define COMMAND_LICENSEYEAR Doc::alias(QLatin1String("licenseyear")) -#define COMMAND_LIFECYCLEVERSION Doc::alias(QLatin1String("lifecycleversion")) -#define COMMAND_LIFECYCLEWSTATUS Doc::alias(QLatin1String("lifecyclestatus")) -#define COMMAND_MACRO Doc::alias(QLatin1String("macro")) -#define COMMAND_MAINCLASS Doc::alias(QLatin1String("mainclass")) -#define COMMAND_MODULE Doc::alias(QLatin1String("module")) -#define COMMAND_NAMESPACE Doc::alias(QLatin1String("namespace")) -#define COMMAND_NEXTPAGE Doc::alias(QLatin1String("nextpage")) -#define COMMAND_NOAUTOLIST Doc::alias(QLatin1String("noautolist")) -#define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant")) -#define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete")) -#define COMMAND_OVERLOAD Doc::alias(QLatin1String("overload")) -#define COMMAND_PAGE Doc::alias(QLatin1String("page")) -#define COMMAND_PAGEKEYWORDS Doc::alias(QLatin1String("pagekeywords")) -#define COMMAND_PERMISSIONS Doc::alias(QLatin1String("permissions")) -#define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) -#define COMMAND_PREVIOUSPAGE Doc::alias(QLatin1String("previouspage")) -#define COMMAND_PRODNAME Doc::alias(QLatin1String("prodname")) -#define COMMAND_PROPERTY Doc::alias(QLatin1String("property")) -#define COMMAND_PUBLISHER Doc::alias(QLatin1String("publisher")) -#define COMMAND_QMLABSTRACT Doc::alias(QLatin1String("qmlabstract")) -#define COMMAND_QMLATTACHEDMETHOD Doc::alias(QLatin1String("qmlattachedmethod")) -#define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty")) -#define COMMAND_QMLATTACHEDSIGNAL Doc::alias(QLatin1String("qmlattachedsignal")) -#define COMMAND_QMLBASICTYPE Doc::alias(QLatin1String("qmlbasictype")) -#define COMMAND_QMLCLASS Doc::alias(QLatin1String("qmlclass")) -#define COMMAND_QMLDEFAULT Doc::alias(QLatin1String("default")) -#define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits")) -#define COMMAND_QMLINSTANTIATES Doc::alias(QLatin1String("instantiates")) -#define COMMAND_QMLMETHOD Doc::alias(QLatin1String("qmlmethod")) -#define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule")) -#define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty")) -#define COMMAND_QMLPROPERTYGROUP Doc::alias(QLatin1String("qmlpropertygroup")) -#define COMMAND_QMLREADONLY Doc::alias(QLatin1String("readonly")) -#define COMMAND_QMLSIGNAL Doc::alias(QLatin1String("qmlsignal")) -#define COMMAND_QMLTYPE Doc::alias(QLatin1String("qmltype")) -#define COMMAND_QTVARIABLE Doc::alias(QLatin1String("qtvariable")) -#define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) -#define COMMAND_REIMP Doc::alias(QLatin1String("reimp")) -#define COMMAND_RELATES Doc::alias(QLatin1String("relates")) -#define COMMAND_RELEASEDATE Doc::alias(QLatin1String("releasedate")) -#define COMMAND_SINCE Doc::alias(QLatin1String("since")) -#define COMMAND_STRUCT Doc::alias(QLatin1String("struct")) -#define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle")) -#define COMMAND_STARTPAGE Doc::alias(QLatin1String("startpage")) -#define COMMAND_THREADSAFE Doc::alias(QLatin1String("threadsafe")) -#define COMMAND_TITLE Doc::alias(QLatin1String("title")) -#define COMMAND_TYPEALIAS Doc::alias(QLatin1String("typealias")) -#define COMMAND_TYPEDEF Doc::alias(QLatin1String("typedef")) -#define COMMAND_VARIABLE Doc::alias(QLatin1String("variable")) -#define COMMAND_VERSION Doc::alias(QLatin1String("version")) -#define COMMAND_UNION Doc::alias(QLatin1String("union")) -#define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper")) +#define COMMAND_ABSTRACT Doc::alias(QLatin1String("abstract")) +#define COMMAND_CLASS Doc::alias(QLatin1String("class")) +#define COMMAND_DEPRECATED Doc::alias(QLatin1String("deprecated")) // ### don't document +#define COMMAND_DONTDOCUMENT Doc::alias(QLatin1String("dontdocument")) +#define COMMAND_ENUM Doc::alias(QLatin1String("enum")) +#define COMMAND_EXAMPLE Doc::alias(QLatin1String("example")) +#define COMMAND_EXTERNALPAGE Doc::alias(QLatin1String("externalpage")) +#define COMMAND_FN Doc::alias(QLatin1String("fn")) +#define COMMAND_GROUP Doc::alias(QLatin1String("group")) +#define COMMAND_HEADERFILE Doc::alias(QLatin1String("headerfile")) +#define COMMAND_INGROUP Doc::alias(QLatin1String("ingroup")) +#define COMMAND_INHEADERFILE Doc::alias(QLatin1String("inheaderfile")) +#define COMMAND_INJSMODULE Doc::alias(QLatin1String("injsmodule")) +#define COMMAND_INMODULE Doc::alias(QLatin1String("inmodule")) // ### don't document +#define COMMAND_INPUBLICGROUP Doc::alias(QLatin1String("inpublicgroup")) +#define COMMAND_INQMLMODULE Doc::alias(QLatin1String("inqmlmodule")) +#define COMMAND_INTERNAL Doc::alias(QLatin1String("internal")) +#define COMMAND_JSATTACHEDMETHOD Doc::alias(QLatin1String("jsattachedmethod")) +#define COMMAND_JSATTACHEDPROPERTY Doc::alias(QLatin1String("jsattachedproperty")) +#define COMMAND_JSATTACHEDSIGNAL Doc::alias(QLatin1String("jsattachedsignal")) +#define COMMAND_JSBASICTYPE Doc::alias(QLatin1String("jsbasictype")) +#define COMMAND_JSMETHOD Doc::alias(QLatin1String("jsmethod")) +#define COMMAND_JSMODULE Doc::alias(QLatin1String("jsmodule")) +#define COMMAND_JSPROPERTY Doc::alias(QLatin1String("jsproperty")) +#define COMMAND_JSPROPERTYGROUP Doc::alias(QLatin1String("jspropertygroup")) +#define COMMAND_JSSIGNAL Doc::alias(QLatin1String("jssignal")) +#define COMMAND_JSTYPE Doc::alias(QLatin1String("jstype")) +#define COMMAND_MACRO Doc::alias(QLatin1String("macro")) +#define COMMAND_MODULE Doc::alias(QLatin1String("module")) +#define COMMAND_NAMESPACE Doc::alias(QLatin1String("namespace")) +#define COMMAND_NEXTPAGE Doc::alias(QLatin1String("nextpage")) +#define COMMAND_NOAUTOLIST Doc::alias(QLatin1String("noautolist")) +#define COMMAND_NONREENTRANT Doc::alias(QLatin1String("nonreentrant")) +#define COMMAND_OBSOLETE Doc::alias(QLatin1String("obsolete")) +#define COMMAND_OVERLOAD Doc::alias(QLatin1String("overload")) +#define COMMAND_PAGE Doc::alias(QLatin1String("page")) +#define COMMAND_PRELIMINARY Doc::alias(QLatin1String("preliminary")) +#define COMMAND_PREVIOUSPAGE Doc::alias(QLatin1String("previouspage")) +#define COMMAND_PROPERTY Doc::alias(QLatin1String("property")) +#define COMMAND_QMLABSTRACT Doc::alias(QLatin1String("qmlabstract")) +#define COMMAND_QMLATTACHEDMETHOD Doc::alias(QLatin1String("qmlattachedmethod")) +#define COMMAND_QMLATTACHEDPROPERTY Doc::alias(QLatin1String("qmlattachedproperty")) +#define COMMAND_QMLATTACHEDSIGNAL Doc::alias(QLatin1String("qmlattachedsignal")) +#define COMMAND_QMLBASICTYPE Doc::alias(QLatin1String("qmlbasictype")) +#define COMMAND_QMLCLASS Doc::alias(QLatin1String("qmlclass")) +#define COMMAND_QMLDEFAULT Doc::alias(QLatin1String("default")) +#define COMMAND_QMLINHERITS Doc::alias(QLatin1String("inherits")) +#define COMMAND_QMLINSTANTIATES Doc::alias(QLatin1String("instantiates")) +#define COMMAND_QMLMETHOD Doc::alias(QLatin1String("qmlmethod")) +#define COMMAND_QMLMODULE Doc::alias(QLatin1String("qmlmodule")) +#define COMMAND_QMLPROPERTY Doc::alias(QLatin1String("qmlproperty")) +#define COMMAND_QMLPROPERTYGROUP Doc::alias(QLatin1String("qmlpropertygroup")) +#define COMMAND_QMLREADONLY Doc::alias(QLatin1String("readonly")) +#define COMMAND_QMLREQUIRED Doc::alias(QLatin1String("required")) +#define COMMAND_QMLSIGNAL Doc::alias(QLatin1String("qmlsignal")) +#define COMMAND_QMLTYPE Doc::alias(QLatin1String("qmltype")) +#define COMMAND_QTCMAKEPACKAGE Doc::alias(QLatin1String("qtcmakepackage")) +#define COMMAND_QTVARIABLE Doc::alias(QLatin1String("qtvariable")) +#define COMMAND_REENTRANT Doc::alias(QLatin1String("reentrant")) +#define COMMAND_REIMP Doc::alias(QLatin1String("reimp")) +#define COMMAND_RELATES Doc::alias(QLatin1String("relates")) +#define COMMAND_SINCE Doc::alias(QLatin1String("since")) +#define COMMAND_STRUCT Doc::alias(QLatin1String("struct")) +#define COMMAND_SUBTITLE Doc::alias(QLatin1String("subtitle")) +#define COMMAND_STARTPAGE Doc::alias(QLatin1String("startpage")) +#define COMMAND_THREADSAFE Doc::alias(QLatin1String("threadsafe")) +#define COMMAND_TITLE Doc::alias(QLatin1String("title")) +#define COMMAND_TYPEALIAS Doc::alias(QLatin1String("typealias")) +#define COMMAND_TYPEDEF Doc::alias(QLatin1String("typedef")) +#define COMMAND_VARIABLE Doc::alias(QLatin1String("variable")) +#define COMMAND_VERSION Doc::alias(QLatin1String("version")) +#define COMMAND_UNION Doc::alias(QLatin1String("union")) +#define COMMAND_WRAPPER Doc::alias(QLatin1String("wrapper")) QT_END_NAMESPACE diff --git a/src/qdoc/collectionnode.cpp b/src/qdoc/collectionnode.cpp new file mode 100644 index 0000000000..ecf18915a3 --- /dev/null +++ b/src/qdoc/collectionnode.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "collectionnode.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class CollectionNode + \brief A class for holding the members of a collection of doc pages. + */ + +/*! + Returns \c true if the collection node's member list is + not empty. + */ +bool CollectionNode::hasMembers() const +{ + return !m_members.isEmpty(); +} + +/*! + Appends \a node to the collection node's member list, if + and only if it isn't already in the member list. + */ +void CollectionNode::addMember(Node *node) +{ + if (!m_members.contains(node)) + m_members.append(node); +} + +/*! + Returns \c true if this collection node contains at least + one namespace node. + */ +bool CollectionNode::hasNamespaces() const +{ + return std::any_of(m_members.cbegin(), m_members.cend(), [](const Node *member) { + return member->isClassNode() && member->isInAPI(); + }); +} + +/*! + Returns \c true if this collection node contains at least + one class node. + */ +bool CollectionNode::hasClasses() const +{ + return std::any_of(m_members.cbegin(), m_members.cend(), [](const Node *member) { + return member->isClassNode() && member->isInAPI(); + }); +} + +/*! + Loads \a out with all this collection node's members that + are namespace nodes. + */ +void CollectionNode::getMemberNamespaces(NodeMap &out) +{ + out.clear(); + for (const auto &member : qAsConst(m_members)) { + if (member->isNamespace() && member->isInAPI()) + out.insert(member->name(), member); + } +} + +/*! + Loads \a out with all this collection node's members that + are class nodes. + */ +void CollectionNode::getMemberClasses(NodeMap &out) const +{ + out.clear(); + for (const auto &member : qAsConst(m_members)) { + if (member->isClassNode() && member->isInAPI()) + out.insert(member->name(), member); + } +} + +/*! + Prints the collection node's list of members. + For debugging only. + */ +void CollectionNode::printMembers(const QString &title) +{ + qDebug() << title << name() << m_members.size(); + if (m_members.empty()) { + for (const auto &member : qAsConst(m_members)) + qDebug() << " MEMBER:" << member->name() << member->nodeTypeString(); + } +} + +/*! + This function splits \a arg on the blank character to get a + logical module name and version number. If the version number + is present, it splits the version number on the '.' character + to get a major version number and a minor version number. If + the version number is present, both the major and minor version + numbers should be there, but the minor version number is not + absolutely necessary. + */ +void CollectionNode::setLogicalModuleInfo(const QString &arg) +{ + QStringList blankSplit = arg.split(QLatin1Char(' ')); + m_logicalModuleName = blankSplit[0]; + if (blankSplit.size() > 1) { + QStringList dotSplit = blankSplit[1].split(QLatin1Char('.')); + m_logicalModuleVersionMajor = dotSplit[0]; + if (dotSplit.size() > 1) + m_logicalModuleVersionMinor = dotSplit[1]; + else + m_logicalModuleVersionMinor = "0"; + } +} + +/*! + This function accepts the logical module \a info as a string + list. If the logical module info contains the version number, + it splits the version number on the '.' character to get the + major and minor version numbers. Both major and minor version + numbers should be provided, but the minor version number is + not strictly necessary. + */ +void CollectionNode::setLogicalModuleInfo(const QStringList &info) +{ + m_logicalModuleName = info[0]; + if (info.size() > 1) { + QStringList dotSplit = info[1].split(QLatin1Char('.')); + m_logicalModuleVersionMajor = dotSplit[0]; + if (dotSplit.size() > 1) + m_logicalModuleVersionMinor = dotSplit[1]; + else + m_logicalModuleVersionMinor = "0"; + } +} + +QT_END_NAMESPACE diff --git a/src/qdoc/collectionnode.h b/src/qdoc/collectionnode.h new file mode 100644 index 0000000000..da85922077 --- /dev/null +++ b/src/qdoc/collectionnode.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COLLECTIONNODE_H +#define COLLECTIONNODE_H + +#include "pagenode.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class CollectionNode : public PageNode +{ +public: + CollectionNode(NodeType type, Aggregate *parent, const QString &name) + : PageNode(type, parent, name) + { + } + + bool isCollectionNode() const override { return true; } + QString qtVariable() const override { return m_qtVariable; } + void setQtVariable(const QString &v) override { m_qtVariable = v; } + QString qtCMakeComponent() const override { return m_qtCMakeComponent; } + void setQtCMakeComponent(const QString &target) override { m_qtCMakeComponent = target; } + void addMember(Node *node) override; + bool hasMembers() const override; + bool hasNamespaces() const override; + bool hasClasses() const override; + void getMemberNamespaces(NodeMap &out) override; + void getMemberClasses(NodeMap &out) const override; + bool wasSeen() const override { return m_seen; } + + QString fullTitle() const override { return title(); } + QString logicalModuleName() const override { return m_logicalModuleName; } + QString logicalModuleVersion() const override + { + return m_logicalModuleVersionMajor + QLatin1Char('.') + m_logicalModuleVersionMinor; + } + QString logicalModuleIdentifier() const override + { + return m_logicalModuleName + m_logicalModuleVersionMajor; + } + void setLogicalModuleInfo(const QString &arg) override; + void setLogicalModuleInfo(const QStringList &info) override; + + const NodeList &members() const { return m_members; } + void printMembers(const QString &title); + + void markSeen() { m_seen = true; } + void markNotSeen() { m_seen = false; } + +private: + bool m_seen { false }; + NodeList m_members {}; + QString m_logicalModuleName {}; + QString m_logicalModuleVersionMajor {}; + QString m_logicalModuleVersionMinor {}; + QString m_qtVariable {}; + QString m_qtCMakeComponent {}; +}; + +QT_END_NAMESPACE + +#endif // COLLECTIONNODE_H diff --git a/src/qdoc/config.cpp b/src/qdoc/config.cpp index e24e9e72f5..7464eaa9a8 100644 --- a/src/qdoc/config.cpp +++ b/src/qdoc/config.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -30,22 +30,20 @@ config.cpp */ -#include -#include -#include -#include -#include -#include #include "config.h" -#include "generator.h" -#include +#include "utilities.h" + +#include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE QString ConfigStrings::ALIAS = QStringLiteral("alias"); QString ConfigStrings::AUTOLINKERRORS = QStringLiteral("autolinkerrors"); -QString ConfigStrings::BASE = QStringLiteral("base"); -QString ConfigStrings::BASEDIR = QStringLiteral("basedir"); QString ConfigStrings::BUILDVERSION = QStringLiteral("buildversion"); QString ConfigStrings::CLANGDEFINES = QStringLiteral("clangdefines"); QString ConfigStrings::CODEINDENT = QStringLiteral("codeindent"); @@ -56,7 +54,7 @@ QString ConfigStrings::CPPCLASSESTITLE = QStringLiteral("cppclassestitle"); QString ConfigStrings::DEFINES = QStringLiteral("defines"); QString ConfigStrings::DEPENDS = QStringLiteral("depends"); QString ConfigStrings::DESCRIPTION = QStringLiteral("description"); -QString ConfigStrings::EDITION = QStringLiteral("edition"); +QString ConfigStrings::DOCBOOKEXTENSIONS = QStringLiteral("usedocbookextensions"); QString ConfigStrings::ENDHEADER = QStringLiteral("endheader"); QString ConfigStrings::EXAMPLEDIRS = QStringLiteral("exampledirs"); QString ConfigStrings::EXAMPLES = QStringLiteral("examples"); @@ -66,7 +64,6 @@ QString ConfigStrings::EXCLUDEFILES = QStringLiteral("excludefiles"); QString ConfigStrings::EXTRAIMAGES = QStringLiteral("extraimages"); QString ConfigStrings::FALSEHOODS = QStringLiteral("falsehoods"); QString ConfigStrings::FORMATTING = QStringLiteral("formatting"); -QString ConfigStrings::GENERATEINDEX = QStringLiteral("generateindex"); QString ConfigStrings::HEADERDIRS = QStringLiteral("headerdirs"); QString ConfigStrings::HEADERS = QStringLiteral("headers"); QString ConfigStrings::HEADERSCRIPTS = QStringLiteral("headerscripts"); @@ -74,7 +71,9 @@ QString ConfigStrings::HEADERSTYLES = QStringLiteral("headerstyles"); QString ConfigStrings::HOMEPAGE = QStringLiteral("homepage"); QString ConfigStrings::HOMETITLE = QStringLiteral("hometitle"); QString ConfigStrings::IGNOREDIRECTIVES = QStringLiteral("ignoredirectives"); +QString ConfigStrings::IGNORESINCE = QStringLiteral("ignoresince"); QString ConfigStrings::IGNORETOKENS = QStringLiteral("ignoretokens"); +QString ConfigStrings::IGNOREWORDS = QStringLiteral("ignorewords"); QString ConfigStrings::IMAGEDIRS = QStringLiteral("imagedirs"); QString ConfigStrings::IMAGES = QStringLiteral("images"); QString ConfigStrings::INCLUDEPATHS = QStringLiteral("includepaths"); @@ -82,24 +81,23 @@ QString ConfigStrings::INDEXES = QStringLiteral("indexes"); QString ConfigStrings::LANDINGPAGE = QStringLiteral("landingpage"); QString ConfigStrings::LANDINGTITLE = QStringLiteral("landingtitle"); QString ConfigStrings::LANGUAGE = QStringLiteral("language"); +QString ConfigStrings::LOCATIONINFO = QStringLiteral("locationinfo"); +QString ConfigStrings::LOGPROGRESS = QStringLiteral("logprogress"); QString ConfigStrings::MACRO = QStringLiteral("macro"); QString ConfigStrings::MANIFESTMETA = QStringLiteral("manifestmeta"); QString ConfigStrings::MODULEHEADER = QStringLiteral("moduleheader"); QString ConfigStrings::NATURALLANGUAGE = QStringLiteral("naturallanguage"); QString ConfigStrings::NAVIGATION = QStringLiteral("navigation"); QString ConfigStrings::NOLINKERRORS = QStringLiteral("nolinkerrors"); -QString ConfigStrings::OBSOLETELINKS = QStringLiteral("obsoletelinks"); QString ConfigStrings::OUTPUTDIR = QStringLiteral("outputdir"); -QString ConfigStrings::OUTPUTENCODING = QStringLiteral("outputencoding"); -QString ConfigStrings::OUTPUTLANGUAGE = QStringLiteral("outputlanguage"); QString ConfigStrings::OUTPUTFORMATS = QStringLiteral("outputformats"); QString ConfigStrings::OUTPUTPREFIXES = QStringLiteral("outputprefixes"); QString ConfigStrings::OUTPUTSUFFIXES = QStringLiteral("outputsuffixes"); QString ConfigStrings::PROJECT = QStringLiteral("project"); -QString ConfigStrings::REDIRECTDOCUMENTATIONTODEVNULL = QStringLiteral("redirectdocumentationtodevnull"); +QString ConfigStrings::REDIRECTDOCUMENTATIONTODEVNULL = + QStringLiteral("redirectdocumentationtodevnull"); QString ConfigStrings::QHP = QStringLiteral("qhp"); QString ConfigStrings::QUOTINGINFORMATION = QStringLiteral("quotinginformation"); -QString ConfigStrings::SCRIPTDIRS = QStringLiteral("scriptdirs"); QString ConfigStrings::SCRIPTS = QStringLiteral("scripts"); QString ConfigStrings::SHOWINTERNAL = QStringLiteral("showinternal"); QString ConfigStrings::SINGLEEXEC = QStringLiteral("singleexec"); @@ -107,14 +105,12 @@ QString ConfigStrings::SOURCEDIRS = QStringLiteral("sourcedirs"); QString ConfigStrings::SOURCEENCODING = QStringLiteral("sourceencoding"); QString ConfigStrings::SOURCES = QStringLiteral("sources"); QString ConfigStrings::SPURIOUS = QStringLiteral("spurious"); -QString ConfigStrings::STYLEDIRS = QStringLiteral("styledirs"); -QString ConfigStrings::STYLE = QStringLiteral("style"); -QString ConfigStrings::STYLES = QStringLiteral("styles"); QString ConfigStrings::STYLESHEETS = QStringLiteral("stylesheets"); QString ConfigStrings::SYNTAXHIGHLIGHTING = QStringLiteral("syntaxhighlighting"); -QString ConfigStrings::TEMPLATEDIR = QStringLiteral("templatedir"); QString ConfigStrings::TABSIZE = QStringLiteral("tabsize"); QString ConfigStrings::TAGFILE = QStringLiteral("tagfile"); +QString ConfigStrings::TIMESTAMPS = QStringLiteral("timestamps"); +QString ConfigStrings::TOCTITLES = QStringLiteral("toctitles"); QString ConfigStrings::TRANSLATORS = QStringLiteral("translators"); QString ConfigStrings::URL = QStringLiteral("url"); QString ConfigStrings::VERSION = QStringLiteral("version"); @@ -125,7 +121,6 @@ QString ConfigStrings::QMLONLY = QStringLiteral("qmlonly"); QString ConfigStrings::QMLTYPESPAGE = QStringLiteral("qmltypespage"); QString ConfigStrings::QMLTYPESTITLE = QStringLiteral("qmltypestitle"); QString ConfigStrings::WARNINGLIMIT = QStringLiteral("warninglimit"); -QString ConfigStrings::WRITEQAPAGES = QStringLiteral("writeqapages"); /*! An entry in a stack, where each entry is a list @@ -140,7 +135,7 @@ class MetaStackEntry QStringList accum; QStringList next; }; -Q_DECLARE_TYPEINFO(MetaStackEntry, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(MetaStackEntry, Q_RELOCATABLE_TYPE); /*! Start accumulating values in a list by appending an empty @@ -169,13 +164,11 @@ void MetaStackEntry::close() */ class MetaStack : private QStack { - Q_DECLARE_TR_FUNCTIONS(QDoc::MetaStack) - public: MetaStack(); - void process(QChar ch, const Location& location); - QStringList getExpanded(const Location& location); + void process(QChar ch, const Location &location); + QStringList getExpanded(const Location &location); }; /*! @@ -193,28 +186,23 @@ MetaStack::MetaStack() It really just builds up a name by appending \a ch to it. */ -void MetaStack::process(QChar ch, const Location& location) +void MetaStack::process(QChar ch, const Location &location) { if (ch == QLatin1Char('{')) { push(MetaStackEntry()); top().open(); } else if (ch == QLatin1Char('}')) { if (count() == 1) - location.fatal(tr("Unexpected '}'")); + location.fatal(QStringLiteral("Unexpected '}'")); top().close(); - QStringList suffixes = pop().accum; - QStringList prefixes = top().next; + const QStringList suffixes = pop().accum; + const QStringList prefixes = top().next; top().next.clear(); - QStringList::ConstIterator pre = prefixes.constBegin(); - while (pre != prefixes.constEnd()) { - QStringList::ConstIterator suf = suffixes.constBegin(); - while (suf != suffixes.constEnd()) { - top().next << (*pre + *suf); - ++suf; - } - ++pre; + for (const auto &prefix : prefixes) { + for (const auto &suffix : suffixes) + top().next << prefix + suffix; } } else if (ch == QLatin1Char(',') && count() > 1) { top().close(); @@ -223,36 +211,32 @@ void MetaStack::process(QChar ch, const Location& location) /* This is where all the processing is done. */ - QStringList::Iterator pre = top().next.begin(); - while (pre != top().next.end()) { - *pre += ch; - ++pre; - } + for (auto it = top().next.begin(); it != top().next.end(); ++it) + *it += ch; } } /*! Returns the accumulated string values. */ -QStringList MetaStack::getExpanded(const Location& location) +QStringList MetaStack::getExpanded(const Location &location) { if (count() > 1) - location.fatal(tr("Missing '}'")); + location.fatal(QStringLiteral("Missing '}'")); top().close(); return top().accum; } const QString Config::dot = QLatin1String("."); -bool Config::debug_ = false; +bool Config::m_debug = false; bool Config::generateExamples = true; QString Config::overrideOutputDir; QString Config::installDir; QSet Config::overrideOutputFormats; -QMap Config::extractedDirs; -int Config::numInstances; -QStack Config::workingDirs_; -QMap Config::includeFilesMap_; +QMap Config::m_extractedDirs; +QStack Config::m_workingDirs; +QMap Config::m_includeFilesMap; /*! \class Config @@ -263,64 +247,220 @@ QMap Config::includeFilesMap_; */ /*! - The constructor sets the \a programName and initializes all - internal state variables to empty values. + Initializes the Config with \a programName and sets all + internal state variables to either default values or to ones + defined in command line arguments \a args. + */ +void Config::init(const QString &programName, const QStringList &args) +{ + m_prog = programName; + processCommandLineOptions(args); + reset(); +} + +Config::~Config() +{ + clear(); +} + +/*! + Clears the location and internal maps for config variables. */ -Config::Config(const QString& programName) - : prog(programName) +void Config::clear() { - loc = Location::null; - lastLocation_ = Location::null; - configVars_.clear(); - numInstances++; - includeFilesMap_.clear(); + m_location = m_lastLocation = Location(); + m_configVars.clear(); + m_includeFilesMap.clear(); } /*! - The destructor has nothing special to do. + Resets the Config instance - used by load() */ -Config::~Config() +void Config::reset() { - includeFilesMap_.clear(); + clear(); + + // Default values + setStringList(CONFIG_CODEINDENT, QStringList("0")); + setStringList(CONFIG_FALSEHOODS, QStringList("0")); + setStringList(CONFIG_FILEEXTENSIONS, QStringList("*.cpp *.h *.qdoc *.qml")); + setStringList(CONFIG_LANGUAGE, QStringList("Cpp")); // i.e. C++ + setStringList(CONFIG_OUTPUTFORMATS, QStringList("HTML")); + setStringList(CONFIG_TABSIZE, QStringList("8")); + setStringList(CONFIG_LOCATIONINFO, QStringList("true")); + + // Publish options from the command line as config variables + const auto setListFlag = [this](const QString &key, bool test) { + setStringList(key, QStringList(test ? QStringLiteral("true") : QStringLiteral("false"))); + }; +#define SET(opt, test) setListFlag(opt, m_parser.isSet(m_parser.test)) + SET(CONFIG_SYNTAXHIGHLIGHTING, highlightingOption); + SET(CONFIG_SHOWINTERNAL, showInternalOption); + SET(CONFIG_SINGLEEXEC, singleExecOption); + SET(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL, redirectDocumentationToDevNullOption); + SET(CONFIG_AUTOLINKERRORS, autoLinkErrorsOption); +#undef SET + m_showInternal = getBool(CONFIG_SHOWINTERNAL); + setListFlag(CONFIG_NOLINKERRORS, + m_parser.isSet(m_parser.noLinkErrorsOption) + || qEnvironmentVariableIsSet("QDOC_NOLINKERRORS")); + + // CONFIG_DEFINES and CONFIG_INCLUDEPATHS are set in load() } /*! Loads and parses the qdoc configuration file \a fileName. - This function calls the other load() function, which does - the loading, parsing, and processing of the configuration - file. - - Intializes the location variables returned by location() - and lastLocation(). + If a previous project was loaded, this function first resets the + Config instance. Then it calls the other load() function, which + does the loading, parsing, and processing of the configuration file. */ -void Config::load(const QString& fileName) +void Config::load(const QString &fileName) { - load(Location::null, fileName); - if (loc.isEmpty()) - loc = Location(fileName); + // Reset if a previous project was loaded + if (m_configVars.contains(CONFIG_PROJECT)) + reset(); + + load(Location(), fileName); + if (m_location.isEmpty()) + m_location = Location(fileName); else - loc.setEtc(true); - lastLocation_ = Location::null; + m_location.setEtc(true); + m_lastLocation = Location(); + + expandVariables(); + + // Add defines and includepaths from command line to their + // respective configuration variables. Values set here are + // always added to what's defined in configuration file. + insertStringList(CONFIG_DEFINES, m_defines); + insertStringList(CONFIG_INCLUDEPATHS, m_includePaths); + + // Prefetch values that are used internally + m_exampleFiles = getCanonicalPathList(CONFIG_EXAMPLES); + m_exampleDirs = getCanonicalPathList(CONFIG_EXAMPLEDIRS); } /*! - Joins all the strings in \a values into a single string with the - individual \a values separated by ' '. Then it inserts the result - into the string list map with \a var as the key. + Expands other config variables referred to in all stored ConfigVars. +*/ +void Config::expandVariables() +{ + for (auto &configVar : m_configVars) { + for (auto it = configVar.m_expandVars.crbegin(); it != configVar.m_expandVars.crend(); ++it) { + Q_ASSERT(it->m_valueIndex < configVar.m_values.size()); + const QString &key = it->m_var; + const auto &refVar = m_configVars.value(key); + if (refVar.m_name.isEmpty()) { + configVar.m_location.fatal( + QStringLiteral("Environment or configuration variable '%1' undefined") + .arg(it->m_var)); + } else if (!refVar.m_expandVars.empty()) { + configVar.m_location.fatal(QStringLiteral("Nested variable expansion not allowed"), + QStringLiteral("When expanding '%1' at %2:%3") + .arg(refVar.m_name) + .arg(refVar.m_location.filePath()) + .arg(refVar.m_location.lineNo())); + } + QString expanded; + if (it->m_delim.isNull()) + expanded = getStringList(key).join(QString()); + else + expanded = getStringList(key).join(it->m_delim); + configVar.m_values[it->m_valueIndex].m_value.insert(it->m_index, expanded); + } + configVar.m_expandVars.clear(); + } +} - It also inserts the \a values string list into a separate map, - also with \a var as the key. +/*! + Sets the \a values of a configuration variable \a var from a string list. */ -void Config::setStringList(const QString& var, const QStringList& values) +void Config::setStringList(const QString &var, const QStringList &values) +{ + m_configVars.insert(var, ConfigVar(var, values, QDir::currentPath())); +} + +/*! + Adds the \a values from a string list to the configuration variable \a var. + Existing value(s) are kept. +*/ +void Config::insertStringList(const QString &var, const QStringList &values) { - configVars_.insert(var,ConfigVar(var, values, QDir::currentPath())); + m_configVars[var].append(ConfigVar(var, values, QDir::currentPath())); } /*! - Looks up the configuarion variable \a var in the string + Process and store variables from the command line. + */ +void Config::processCommandLineOptions(const QStringList &args) +{ + m_parser.process(args); + + m_defines = m_parser.values(m_parser.defineOption); + m_dependModules = m_parser.values(m_parser.dependsOption); + setIndexDirs(); + setIncludePaths(); + + generateExamples = !m_parser.isSet(m_parser.noExamplesOption); + if (m_parser.isSet(m_parser.installDirOption)) + installDir = m_parser.value(m_parser.installDirOption); + if (m_parser.isSet(m_parser.outputDirOption)) + overrideOutputDir = m_parser.value(m_parser.outputDirOption); + + const auto outputFormats = m_parser.values(m_parser.outputFormatOption); + for (const auto &format : outputFormats) + overrideOutputFormats.insert(format); + m_debug = m_parser.isSet(m_parser.debugOption) || qEnvironmentVariableIsSet("QDOC_DEBUG"); + m_showInternal = m_parser.isSet(m_parser.showInternalOption) + || qEnvironmentVariableIsSet("QDOC_SHOW_INTERNAL"); + + if (m_parser.isSet(m_parser.prepareOption)) + m_qdocPass = Prepare; + if (m_parser.isSet(m_parser.generateOption)) + m_qdocPass = Generate; + if (m_parser.isSet(m_parser.logProgressOption)) + setStringList(CONFIG_LOGPROGRESS, QStringList("true")); + if (m_parser.isSet(m_parser.timestampsOption)) + setStringList(CONFIG_TIMESTAMPS, QStringList("true")); + if (m_parser.isSet(m_parser.useDocBookExtensions)) + setStringList(CONFIG_DOCBOOKEXTENSIONS, QStringList("true")); +} + +void Config::setIncludePaths() +{ + QDir currentDir = QDir::current(); + const auto addIncludePaths = [this, currentDir](const char *flag, const QStringList &paths) { + for (const auto &path : paths) + m_includePaths << currentDir.absoluteFilePath(path).insert(0, flag); + }; + + addIncludePaths("-I", m_parser.values(m_parser.includePathOption)); +#ifdef QDOC_PASS_ISYSTEM + addIncludePaths("-isystem", m_parser.values(m_parser.includePathSystemOption)); +#endif + addIncludePaths("-F", m_parser.values(m_parser.frameworkOption)); +} + +/*! + Stores paths from -indexdir command line option(s). + */ +void Config::setIndexDirs() +{ + m_indexDirs = m_parser.values(m_parser.indexDirOption); + auto it = std::remove_if(m_indexDirs.begin(), m_indexDirs.end(), + [](const QString &s) { return !QFile::exists(s); }); + + std::for_each(it, m_indexDirs.end(), [](const QString &s) { + qCWarning(lcQdoc) << "Cannot find index directory: " << s; + }); + m_indexDirs.erase(it, m_indexDirs.end()); +} + +/*! + Looks up the configuration variable \a var in the string map and returns the boolean value. */ -bool Config::getBool(const QString& var) const +bool Config::getBool(const QString &var) const { return QVariant(getString(var)).toBool(); } @@ -331,19 +471,15 @@ bool Config::getBool(const QString& var) const string in the list as an integer and adding it to a total sum. Returns the sum or \c -1 if \a var is not set. */ -int Config::getInt(const QString& var) const +int Config::getInt(const QString &var) const { - QStringList strs = getStringList(var); + const QStringList strs = getStringList(var); if (strs.isEmpty()) return -1; - QStringList::ConstIterator s = strs.constBegin(); int sum = 0; - - while (s != strs.constEnd()) { - sum += (*s).toInt(); - ++s; - } + for (const auto &str : strs) + sum += str.toInt(); return sum; } @@ -360,7 +496,7 @@ QString Config::getOutputDir(const QString &format) const t = getString(CONFIG_OUTPUTDIR); else t = overrideOutputDir; - if (Generator::singleExec()) { + if (getBool(CONFIG_SINGLEEXEC)) { QString project = getString(CONFIG_PROJECT); t += QLatin1Char('/') + project.toLower(); } @@ -388,45 +524,33 @@ QSet Config::getOutputFormats() const } /*! - First, this function looks up the configuration variable \a var - in the location map and, if found, sets the internal variable - \c{lastLocation_} to the Location that \a var maps to. + Returns the value of a configuration variable \a var + as a string. If \a var is defined, updates the internal + location to the location of \a var for the purposes of + error reporting. - Then it looks up the configuration variable \a var in the string - map and returns the string that \a var maps to. - - If \a var is not contained in the location map it returns - \a defaultString. + If \a var is not defined, returns \a defaultString. \note By default, \a defaultString is a null string. If \a var is found but contains an empty string, that is returned instead. This allows determining whether a configuration variable is undefined (null string) or defined as empty (empty string). */ -QString Config::getString(const QString& var, const QString& defaultString) const +QString Config::getString(const QString &var, const QString &defaultString) const { - QList configVars = configVars_.values(var); - if (!configVars.empty()) { - QString value(""); - int i = configVars.size() - 1; - while (i >= 0) { - const ConfigVar& cv = configVars[i]; - if (!cv.location_.isEmpty()) - const_cast(this)->lastLocation_ = cv.location_; - if (!cv.values_.isEmpty()) { - if (!cv.plus_) - value.clear(); - for (int j=0; j Config::getStringSet(const QString& var) const +QSet Config::getStringSet(const QString &var) const { const auto &stringList = getStringList(var); return QSet(stringList.cbegin(), stringList.cend()); } /*! - First, this function looks up the configuration variable \a var - in the location map. If found, it sets the internal variable - \c{lastLocation_} to the Location that \a var maps to. - - Then it looks up the configuration variable \a var in the map of - configuration variable records. If found, it gets a list of all - the records for \a var. Then it appends all the values for \a var - to a list and returns the list. As it appends the values from each - record, if the \a var used '=' instead of '+=' the list is cleared - before the values are appended. \note '+=' should always be used. - The final list is returned. + Returns the string list contained in the configuration variable + \a var. If \a var is defined, updates the internal location + to the location of \a var for the purposes of error reporting. */ -QStringList Config::getStringList(const QString& var) const +QStringList Config::getStringList(const QString &var) const { - QList configVars = configVars_.values(var); - QStringList values; - if (!configVars.empty()) { - int i = configVars.size() - 1; - while (i >= 0) { - if (!configVars[i].location_.isEmpty()) - const_cast(this)->lastLocation_ = configVars[i].location_; - if (configVars[i].plus_) - values.append(configVars[i].values_); - else - values = configVars[i].values_; - --i; - } - } - return values; + const auto &configVar = m_configVars.value(var); + updateLocation(configVar); + + QStringList result; + for (const auto &value : configVar.m_values) + result << value.m_value; + return result; } /*! Returns the a path list where all paths from the config variable \a var - are canonicalized. If \a validate is true, a warning for invalid paths is - generated. - - First, this function looks up the configuration variable \a var - in the location map and, if found, sets the internal variable - \c{lastLocation_} the Location that \a var maps to. - - Then it looks up the configuration variable \a var in the string - list map, which maps to one or more records that each contains a - list of file paths. + are canonicalized. If \a validate is true, outputs a warning for invalid + paths. If \a var is defined, updates the internal location to the + location of \a var for the purposes of error reporting. \sa Location::canonicalRelativePath() */ -QStringList Config::getCanonicalPathList(const QString& var, bool validate) const +QStringList Config::getCanonicalPathList(const QString &var, bool validate) const { - QStringList t; - QList configVars = configVars_.values(var); - if (!configVars.empty()) { - int i = configVars.size() - 1; - while (i >= 0) { - const ConfigVar& cv = configVars[i]; - if (!cv.location_.isEmpty()) - const_cast(this)->lastLocation_ = cv.location_; - if (!cv.plus_) - t.clear(); - const QString d = cv.currentPath_; - const QStringList& sl = cv.values_; - if (!sl.isEmpty()) { - t.reserve(t.size() + sl.size()); - for (int i=0; i subRegExps = getRegExpList(var); - QList::ConstIterator s = subRegExps.constBegin(); + const auto subRegExps = getRegExpList(var); - while (s != subRegExps.constEnd()) { - if (!(*s).isValid()) - return *s; + for (const auto ®Exp : subRegExps) { + if (!regExp.isValid()) + return regExp; if (!pattern.isEmpty()) pattern += QLatin1Char('|'); - pattern += QLatin1String("(?:") + (*s).pattern() + QLatin1Char(')'); - ++s; + pattern += QLatin1String("(?:") + regExp.pattern() + QLatin1Char(')'); } if (pattern.isEmpty()) pattern = QLatin1String("$x"); // cannot match - return QRegExp(pattern); + return QRegularExpression(pattern); } /*! @@ -557,16 +644,12 @@ QRegExp Config::getRegExp(const QString& var) const map, converts the string list to a list of regular expressions, and returns it. */ -QList Config::getRegExpList(const QString& var) const +QList Config::getRegExpList(const QString &var) const { - QStringList strs = getStringList(var); - QStringList::ConstIterator s = strs.constBegin(); - QList regExps; - - while (s != strs.constEnd()) { - regExps += QRegExp(*s); - ++s; - } + const QStringList strs = getStringList(var); + QList regExps; + for (const auto &str : strs) + regExps += QRegularExpression(str); return regExps; } @@ -576,69 +659,71 @@ QList Config::getRegExpList(const QString& var) const the matching keys in a set, stripped of the matching prefix and dot. */ -QSet Config::subVars(const QString& var) const +QSet Config::subVars(const QString &var) const { QSet result; QString varDot = var + QLatin1Char('.'); - ConfigVarMultimap::ConstIterator i = configVars_.constBegin(); - while (i != configVars_.constEnd()) { - if (i.key().startsWith(varDot)) { - QString subVar = i.key().mid(varDot.length()); + for (auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) { + if (it.key().startsWith(varDot)) { + QString subVar = it.key().mid(varDot.length()); int dot = subVar.indexOf(QLatin1Char('.')); if (dot != -1) subVar.truncate(dot); - if (!result.contains(subVar)) - result.insert(subVar); + result.insert(subVar); } - ++i; } return result; } /*! - Same as subVars(), but in this case we return a config var - multimap with the matching keys (stripped of the prefix \a var - and mapped to their values. The pairs are inserted into \a t + Same as subVars(), but returns a ConfigVarMap \a map with the + matching keys (stripped of the prefix \a var and mapped to + their values. */ -void Config::subVarsAndValues(const QString& var, ConfigVarMultimap& t) const +void Config::subVarsAndValues(const QString &var, ConfigVarMap &map) const { QString varDot = var + QLatin1Char('.'); - ConfigVarMultimap::ConstIterator v = configVars_.constBegin(); - while (v != configVars_.constEnd()) { - if (v.key().startsWith(varDot)) { - QString subVar = v.key().mid(varDot.length()); + for (auto it = m_configVars.constBegin(); it != m_configVars.constEnd(); ++it) { + if (it.key().startsWith(varDot)) { + QString subVar = it.key().mid(varDot.length()); int dot = subVar.indexOf(QLatin1Char('.')); if (dot != -1) subVar.truncate(dot); - t.insert(subVar,v.value()); + map.insert(subVar, it.value()); } - ++v; } } /*! - Get all .qdocinc files. + Searches for a path to \a fileName in 'sources', 'sourcedirs', and + 'exampledirs' config variables and returns a full path to the first + match found. If the file is not found, returns an empty string. */ -QString Config::getIncludeFilePath(const QString& fileName) const +QString Config::getIncludeFilePath(const QString &fileName) const { - QString ext = fileName.mid(fileName.lastIndexOf('.')); - ext.prepend('*'); - - if (!includeFilesMap_.contains(ext)) { - QSet t; - QStringList result; - QStringList dirs = getCanonicalPathList(CONFIG_SOURCEDIRS); - QStringList::ConstIterator d = dirs.constBegin(); - while (d != dirs.constEnd()) { - result += getFilesHere(*d, ext, location(), t, t); - ++d; - } - includeFilesMap_.insert(ext, result); + QString ext = QFileInfo(fileName).suffix(); + + if (!m_includeFilesMap.contains(ext)) { + QStringList result = getCanonicalPathList(CONFIG_SOURCES); + result.erase(std::remove_if(result.begin(), result.end(), + [&](const QString &s) { return !s.endsWith(ext); }), + result.end()); + const QStringList dirs = + getCanonicalPathList(CONFIG_SOURCEDIRS) + + getCanonicalPathList(CONFIG_EXAMPLEDIRS); + + for (const auto &dir : dirs) + result += getFilesHere(dir, "*." + ext, location()); + result.removeDuplicates(); + m_includeFilesMap.insert(ext, result); } - const QStringList& paths = (*includeFilesMap_.find(ext)); - for (int i=0; i &excludedDirs, const QSet &excludedFiles) { QStringList result = getCanonicalPathList(filesVar, true); - QStringList dirs = getCanonicalPathList(dirsVar, true); + const QStringList dirs = getCanonicalPathList(dirsVar, true); - QString nameFilter = getString(filesVar + dot + CONFIG_FILEEXTENSIONS); + const QString nameFilter = getString(filesVar + dot + CONFIG_FILEEXTENSIONS); - QStringList::ConstIterator d = dirs.constBegin(); - while (d != dirs.constEnd()) { - result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles); - ++d; - } + for (const auto &dir : dirs) + result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles); return result; } @@ -674,14 +755,11 @@ QStringList Config::getExampleQdocFiles(const QSet &excludedDirs, const QSet &excludedFiles) { QStringList result; - QStringList dirs = getCanonicalPathList("exampledirs"); - QString nameFilter = " *.qdoc"; + const QStringList dirs = getCanonicalPathList("exampledirs"); + const QString nameFilter = " *.qdoc"; - QStringList::ConstIterator d = dirs.constBegin(); - while (d != dirs.constEnd()) { - result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles); - ++d; - } + for (const auto &dir : dirs) + result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles); return result; } @@ -689,17 +767,40 @@ QStringList Config::getExampleImageFiles(const QSet &excludedDirs, const QSet &excludedFiles) { QStringList result; - QStringList dirs = getCanonicalPathList("exampledirs"); - QString nameFilter = getString(CONFIG_EXAMPLES + dot + CONFIG_IMAGEEXTENSIONS); + const QStringList dirs = getCanonicalPathList("exampledirs"); + const QString nameFilter = getString(CONFIG_EXAMPLES + dot + CONFIG_IMAGEEXTENSIONS); - QStringList::ConstIterator d = dirs.constBegin(); - while (d != dirs.constEnd()) { - result += getFilesHere(*d, nameFilter, location(), excludedDirs, excludedFiles); - ++d; - } + for (const auto &dir : dirs) + result += getFilesHere(dir, nameFilter, location(), excludedDirs, excludedFiles); return result; } +/*! + Returns the path to the project file for \a examplePath, or an empty string + if no project file was found. + */ +QString Config::getExampleProjectFile(const QString &examplePath) +{ + QFileInfo fileInfo(examplePath); + QStringList validNames; + validNames << fileInfo.fileName() + QLatin1String(".pro") + << fileInfo.fileName() + QLatin1String(".qmlproject") + << fileInfo.fileName() + QLatin1String(".pyproject") + << QLatin1String("CMakeLists.txt") + << QLatin1String("qbuild.pro"); // legacy + + QString projectFile; + + for (const auto &name : qAsConst(validNames)) { + projectFile = Config::findFile(Location(), m_exampleFiles, m_exampleDirs, + examplePath + QLatin1Char('/') + name); + if (!projectFile.isEmpty()) + return projectFile; + } + + return projectFile; +} + /*! \a fileName is the path of the file to find. @@ -709,10 +810,8 @@ QStringList Config::getExampleImageFiles(const QSet &excludedDirs, \a location is used for obtaining the file and line numbers for report qdoc errors. */ -QString Config::findFile(const Location& location, - const QStringList& files, - const QStringList& dirs, - const QString& fileName, +QString Config::findFile(const Location &location, const QStringList &files, + const QStringList &dirs, const QString &fileName, QString *userFriendlyFilePath) { if (fileName.isEmpty() || fileName.startsWith(QLatin1Char('/'))) { @@ -725,25 +824,20 @@ QString Config::findFile(const Location& location, QStringList components = fileName.split(QLatin1Char('?')); QString firstComponent = components.first(); - QStringList::ConstIterator f = files.constBegin(); - while (f != files.constEnd()) { - if (*f == firstComponent || - (*f).endsWith(QLatin1Char('/') + firstComponent)) { - fileInfo.setFile(*f); + for (const auto &file : files) { + if (file == firstComponent || file.endsWith(QLatin1Char('/') + firstComponent)) { + fileInfo.setFile(file); if (!fileInfo.exists()) - location.fatal(tr("File '%1' does not exist").arg(*f)); + location.fatal(QStringLiteral("File '%1' does not exist").arg(file)); break; } - ++f; } if (fileInfo.fileName().isEmpty()) { - QStringList::ConstIterator d = dirs.constBegin(); - while (d != dirs.constEnd()) { - fileInfo.setFile(QDir(*d), firstComponent); + for (const auto &dir : dirs) { + fileInfo.setFile(QDir(dir), firstComponent); if (fileInfo.exists()) break; - ++d; } } @@ -753,13 +847,12 @@ QString Config::findFile(const Location& location, return QString(); if (userFriendlyFilePath) { - QStringList::ConstIterator c = components.constBegin(); - for (;;) { + for (auto c = components.constBegin();;) { bool isArchive = (c != components.constEnd() - 1); userFriendlyFilePath->append(*c); if (isArchive) { - QString extracted = extractedDirs[fileInfo.filePath()]; + QString extracted = m_extractedDirs[fileInfo.filePath()]; ++c; fileInfo.setFile(QDir(extracted), *c); } else { @@ -774,23 +867,15 @@ QString Config::findFile(const Location& location, /*! */ -QString Config::findFile(const Location& location, - const QStringList& files, - const QStringList& dirs, - const QString& fileBase, - const QStringList& fileExtensions, - QString *userFriendlyFilePath) +QString Config::findFile(const Location &location, const QStringList &files, + const QStringList &dirs, const QString &fileBase, + const QStringList &fileExtensions, QString *userFriendlyFilePath) { - QStringList::ConstIterator e = fileExtensions.constBegin(); - while (e != fileExtensions.constEnd()) { - QString filePath = findFile(location, - files, - dirs, - fileBase + QLatin1Char('.') + *e, + for (const auto &extension : fileExtensions) { + QString filePath = findFile(location, files, dirs, fileBase + QLatin1Char('.') + extension, userFriendlyFilePath); if (!filePath.isEmpty()) return filePath; - ++e; } return findFile(location, files, dirs, fileBase, userFriendlyFilePath); } @@ -802,15 +887,14 @@ QString Config::findFile(const Location& location, the file and line number where a qdoc error occurred. The constructed output file name is returned. */ -QString Config::copyFile(const Location& location, - const QString& sourceFilePath, - const QString& userFriendlySourceFilePath, - const QString& targetDirPath) +QString Config::copyFile(const Location &location, const QString &sourceFilePath, + const QString &userFriendlySourceFilePath, const QString &targetDirPath) { QFile inFile(sourceFilePath); if (!inFile.open(QFile::ReadOnly)) { - location.warning(tr("Cannot open input file for copy: '%1': %2") - .arg(sourceFilePath).arg(inFile.errorString())); + location.warning(QStringLiteral("Cannot open input file for copy: '%1': %2") + .arg(sourceFilePath) + .arg(inFile.errorString())); return QString(); } @@ -824,8 +908,9 @@ QString Config::copyFile(const Location& location, outFileName = targetDirPath + outFileName; QFile outFile(outFileName); if (!outFile.open(QFile::WriteOnly)) { - location.warning(tr("Cannot open output file for copy: '%1': %2") - .arg(outFileName).arg(outFile.errorString())); + location.warning(QStringLiteral("Cannot open output file for copy: '%1': %2") + .arg(outFileName) + .arg(outFile.errorString())); return QString(); } @@ -840,89 +925,52 @@ QString Config::copyFile(const Location& location, Finds the largest unicode digit in \a value in the range 1..7 and returns it. */ -int Config::numParams(const QString& value) +int Config::numParams(const QString &value) { int max = 0; - for (int i = 0; i != value.length(); i++) { + for (int i = 0; i != value.length(); ++i) { uint c = value[i].unicode(); if (c > 0 && c < 8) - max = qMax(max, (int)c); + max = qMax(max, static_cast(c)); } return max; } -/*! - Removes everything from \a dir. This function is recursive. - It doesn't remove \a dir itself, but if it was called - recursively, then the caller will remove \a dir. - */ -bool Config::removeDirContents(const QString& dir) -{ - QDir dirInfo(dir); - QFileInfoList entries = dirInfo.entryInfoList(); - - bool ok = true; - - QFileInfoList::Iterator it = entries.begin(); - while (it != entries.end()) { - if ((*it).isFile()) { - if (!dirInfo.remove((*it).fileName())) - ok = false; - } - else if ((*it).isDir()) { - if ((*it).fileName() != QLatin1String(".") && (*it).fileName() != QLatin1String("..")) { - if (removeDirContents((*it).absoluteFilePath())) { - if (!dirInfo.rmdir((*it).fileName())) - ok = false; - } - else { - ok = false; - } - } - } - ++it; - } - return ok; -} - /*! Returns \c true if \a ch is a letter, number, '_', '.', '{', '}', or ','. */ bool Config::isMetaKeyChar(QChar ch) { - return ch.isLetterOrNumber() - || ch == QLatin1Char('_') - || ch == QLatin1Char('.') - || ch == QLatin1Char('{') - || ch == QLatin1Char('}') - || ch == QLatin1Char(','); + return ch.isLetterOrNumber() || ch == QLatin1Char('_') || ch == QLatin1Char('.') + || ch == QLatin1Char('{') || ch == QLatin1Char('}') || ch == QLatin1Char(','); } /*! \a fileName is a master qdocconf file. It contains a list of qdocconf files and nothing else. Read the list and return it. */ -QStringList Config::loadMaster(const QString& fileName) +QStringList Config::loadMaster(const QString &fileName) { - Location location = Location::null; + Location location; QFile fin(fileName); if (!fin.open(QFile::ReadOnly | QFile::Text)) { if (!Config::installDir.isEmpty()) { int prefix = location.filePath().length() - location.fileName().length(); - fin.setFileName(Config::installDir + QLatin1Char('/') + fileName.right(fileName.length() - prefix)); + fin.setFileName(Config::installDir + QLatin1Char('/') + + fileName.right(fileName.length() - prefix)); } if (!fin.open(QFile::ReadOnly | QFile::Text)) - location.fatal(tr("Cannot open master qdocconf file '%1': %2").arg(fileName).arg(fin.errorString())); + location.fatal(QStringLiteral("Cannot open master qdocconf file '%1': %2") + .arg(fileName) + .arg(fin.errorString())); } QTextStream stream(&fin); -#ifndef QT_NO_TEXTCODEC - stream.setCodec("UTF-8"); -#endif QStringList qdocFiles; + QDir configDir(QFileInfo(fileName).canonicalPath()); QString line = stream.readLine(); while (!line.isNull()) { - qdocFiles.append(line); + qdocFiles.append(QFileInfo(configDir, line).filePath()); line = stream.readLine(); } fin.close(); @@ -935,47 +983,47 @@ QStringList Config::loadMaster(const QString& fileName) this one is recursive, i.e., it calls itself when it sees an \c{include} statement in the qdoc configuration file. */ -void Config::load(Location location, const QString& fileName) +void Config::load(Location location, const QString &fileName) { QFileInfo fileInfo(fileName); QString path = fileInfo.canonicalPath(); pushWorkingDir(path); QDir::setCurrent(path); - QRegExp keySyntax(QLatin1String("\\w+(?:\\.\\w+)*")); - -#define SKIP_CHAR() \ - do { \ - location.advance(c); \ - ++i; \ - c = text.at(i); \ - cc = c.unicode(); \ -} while (0) - -#define SKIP_SPACES() \ - while (c.isSpace() && cc != '\n') \ + QRegularExpression keySyntax(QRegularExpression::anchoredPattern(QLatin1String("\\w+(?:\\.\\w+)*"))); + +#define SKIP_CHAR() \ + do { \ + location.advance(c); \ + ++i; \ + c = text.at(i); \ + cc = c.unicode(); \ + } while (0) + +#define SKIP_SPACES() \ + while (c.isSpace() && cc != '\n') \ SKIP_CHAR() -#define PUT_CHAR() \ - word += c; \ +#define PUT_CHAR() \ + word += c; \ SKIP_CHAR(); if (location.depth() > 16) - location.fatal(tr("Too many nested includes")); + location.fatal(QStringLiteral("Too many nested includes")); QFile fin(fileInfo.fileName()); if (!fin.open(QFile::ReadOnly | QFile::Text)) { if (!Config::installDir.isEmpty()) { int prefix = location.filePath().length() - location.fileName().length(); - fin.setFileName(Config::installDir + QLatin1Char('/') + fileName.right(fileName.length() - prefix)); + fin.setFileName(Config::installDir + QLatin1Char('/') + + fileName.right(fileName.length() - prefix)); } if (!fin.open(QFile::ReadOnly | QFile::Text)) - location.fatal(tr("Cannot open file '%1': %2").arg(fileName).arg(fin.errorString())); + location.fatal(QStringLiteral("Cannot open file '%1': %2") + .arg(fileName) + .arg(fin.errorString())); } QTextStream stream(&fin); -#ifndef QT_NO_TEXTCODEC - stream.setCodec("UTF-8"); -#endif QString text = stream.readAll(); text += QLatin1String("\n\n"); text += QLatin1Char('\0'); @@ -987,7 +1035,7 @@ void Config::load(Location location, const QString& fileName) int i = 0; QChar c = text.at(0); uint cc = c.unicode(); - while (i < (int) text.length()) { + while (i < text.length()) { if (cc == 0) { ++i; } else if (c.isSpace()) { @@ -999,12 +1047,11 @@ void Config::load(Location location, const QString& fileName) } else if (isMetaKeyChar(c)) { Location keyLoc = location; bool plus = false; - QString stringValue; QStringList rhsValues; + QList expandVars; QString word; bool inQuote = false; - bool prevWordQuoted = true; - bool metWord = false; + bool needsExpansion = false; MetaStack stack; do { @@ -1012,14 +1059,14 @@ void Config::load(Location location, const QString& fileName) SKIP_CHAR(); } while (isMetaKeyChar(c)); - QStringList keys = stack.getExpanded(location); + const QStringList keys = stack.getExpanded(location); SKIP_SPACES(); if (keys.count() == 1 && keys.first() == QLatin1String("include")) { QString includeFile; if (cc != '(') - location.fatal(tr("Bad include syntax")); + location.fatal(QStringLiteral("Bad include syntax")); SKIP_CHAR(); SKIP_SPACES(); @@ -1035,9 +1082,9 @@ void Config::load(Location location, const QString& fileName) if (!var.isEmpty()) { const QByteArray val = qgetenv(var.toLatin1().data()); if (val.isNull()) { - location.fatal(tr("Environment variable '%1' undefined").arg(var)); - } - else { + location.fatal(QStringLiteral("Environment variable '%1' undefined") + .arg(var)); + } else { includeFile += QString::fromLatin1(val); } } @@ -1048,18 +1095,17 @@ void Config::load(Location location, const QString& fileName) } SKIP_SPACES(); if (cc != ')') - location.fatal(tr("Bad include syntax")); + location.fatal(QStringLiteral("Bad include syntax")); SKIP_CHAR(); SKIP_SPACES(); if (cc != '#' && cc != '\n') - location.fatal(tr("Trailing garbage")); + location.fatal(QStringLiteral("Trailing garbage")); /* Here is the recursive call. */ load(location, QFileInfo(QDir(path), includeFile).filePath()); - } - else { + } else { /* It wasn't an include statement, so it's something else. We must see either '=' or '+=' next. If not, fatal error. @@ -1069,7 +1115,7 @@ void Config::load(Location location, const QString& fileName) SKIP_CHAR(); } if (cc != '=') - location.fatal(tr("Expected '=' or '+=' after key")); + location.fatal(QStringLiteral("Expected '=' or '+=' after key")); SKIP_CHAR(); SKIP_SPACES(); @@ -1080,162 +1126,158 @@ void Config::load(Location location, const QString& fileName) SKIP_CHAR(); if (cc == '\n') { SKIP_CHAR(); - } - else if (cc > '0' && cc < '8') { + } else if (cc > '0' && cc < '8') { word += QChar(c.digitValue()); SKIP_CHAR(); - } - else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) != -1) { + } else if ((metaCharPos = QString::fromLatin1("abfnrtv").indexOf(c)) + != -1) { word += QLatin1Char("\a\b\f\n\r\t\v"[metaCharPos]); SKIP_CHAR(); - } - else { + } else { PUT_CHAR(); } - } - else if (c.isSpace() || cc == '#') { + } else if (c.isSpace() || cc == '#') { if (inQuote) { if (cc == '\n') - location.fatal(tr("Unterminated string")); + location.fatal(QStringLiteral("Unterminated string")); PUT_CHAR(); - } - else { - if (!word.isEmpty()) { - if (metWord) - stringValue += QLatin1Char(' '); - stringValue += word; -#if 0 - if (metWord) - rhsValues << QString(" " + word); - else -#endif + } else { + if (!word.isEmpty() || needsExpansion) { rhsValues << word; - metWord = true; word.clear(); - prevWordQuoted = false; + needsExpansion = false; } if (cc == '\n' || cc == '#') break; SKIP_SPACES(); } - } - else if (cc == '"') { + } else if (cc == '"') { if (inQuote) { - if (!prevWordQuoted) - stringValue += QLatin1Char(' '); - stringValue += word; - if (!word.isEmpty()) + if (!word.isEmpty() || needsExpansion) rhsValues << word; - metWord = true; word.clear(); - prevWordQuoted = true; + needsExpansion = false; } inQuote = !inQuote; SKIP_CHAR(); - } - else if (cc == '$') { + } else if (cc == '$') { QString var; + QChar delim(' '); + bool braces = false; SKIP_CHAR(); + if (cc == '{') { + SKIP_CHAR(); + braces = true; + } while (c.isLetterOrNumber() || cc == '_') { var += c; SKIP_CHAR(); } + if (braces) { + if (cc == ',') { + SKIP_CHAR(); + delim = c; + SKIP_CHAR(); + } + if (cc == '}') + SKIP_CHAR(); + else if (delim == '}') + delim = QChar(); // null delimiter + else + location.fatal(QStringLiteral("Missing '}'")); + } if (!var.isEmpty()) { const QByteArray val = qgetenv(var.toLatin1().constData()); if (val.isNull()) { - location.fatal(tr("Environment variable '%1' undefined").arg(var)); - } - else { + expandVars << ExpandVar(rhsValues.size(), word.size(), var, delim); + needsExpansion = true; + } else if (braces) { // ${VAR} inserts content from an env. variable for processing + text.insert(i, QString::fromLatin1(val)); + c = text.at(i); + cc = c.unicode(); + } else { // while $VAR simply reads the value and stores it to a config variable. word += QString::fromLatin1(val); } } - } - else { + } else { if (!inQuote && cc == '=') - location.fatal(tr("Unexpected '='")); + location.fatal(QStringLiteral("Unexpected '='")); PUT_CHAR(); } } + for (const auto &key : keys) { + if (!keySyntax.match(key).hasMatch()) + keyLoc.fatal(QStringLiteral("Invalid key '%1'").arg(key)); - QStringList::ConstIterator key = keys.constBegin(); - while (key != keys.constEnd()) { - if (!keySyntax.exactMatch(*key)) - keyLoc.fatal(tr("Invalid key '%1'").arg(*key)); - - ConfigVarMultimap::Iterator i; - i = configVars_.insert(*key, ConfigVar(*key, rhsValues, QDir::currentPath(), keyLoc)); - i.value().plus_ = plus; - ++key; + ConfigVar configVar(key, rhsValues, QDir::currentPath(), keyLoc, expandVars); + if (plus && m_configVars.contains(key)) { + m_configVars[key].append(configVar); + } else { + m_configVars.insert(key, configVar); + } } } } else { - location.fatal(tr("Unexpected character '%1' at beginning of line").arg(c)); + location.fatal(QStringLiteral("Unexpected character '%1' at beginning of line").arg(c)); } } popWorkingDir(); - if (!workingDirs_.isEmpty()) - QDir::setCurrent(workingDirs_.top()); + if (!m_workingDirs.isEmpty()) + QDir::setCurrent(m_workingDirs.top()); } bool Config::isFileExcluded(const QString &fileName, const QSet &excludedFiles) { - foreach (const QString &entry, excludedFiles) { + for (const QString &entry : excludedFiles) { if (entry.contains(QLatin1Char('*')) || entry.contains(QLatin1Char('?'))) { - QRegExp re(entry, Qt::CaseSensitive, QRegExp::Wildcard); - if (re.exactMatch(fileName)) + QRegularExpression re(QRegularExpression::wildcardToRegularExpression(entry)); + if (re.match(fileName).hasMatch()) return true; } } return excludedFiles.contains(fileName); } -QStringList Config::getFilesHere(const QString& uncleanDir, - const QString& nameFilter, - const Location &location, - const QSet &excludedDirs, +QStringList Config::getFilesHere(const QString &uncleanDir, const QString &nameFilter, + const Location &location, const QSet &excludedDirs, const QSet &excludedFiles) { - QString dir = location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath(); + QString dir = + location.isEmpty() ? QDir::cleanPath(uncleanDir) : QDir(uncleanDir).canonicalPath(); QStringList result; if (excludedDirs.contains(dir)) return result; QDir dirInfo(dir); - QStringList fileNames; - QStringList::const_iterator fn; dirInfo.setNameFilters(nameFilter.split(QLatin1Char(' '))); dirInfo.setSorting(QDir::Name); dirInfo.setFilter(QDir::Files); - fileNames = dirInfo.entryList(); - fn = fileNames.constBegin(); - while (fn != fileNames.constEnd()) { - if (!fn->startsWith(QLatin1Char('~'))) { - QString s = dirInfo.filePath(*fn); + QStringList fileNames = dirInfo.entryList(); + for (const auto &file : qAsConst(fileNames)) { + if (!file.startsWith(QLatin1Char('~'))) { + QString s = dirInfo.filePath(file); QString c = QDir::cleanPath(s); if (!isFileExcluded(c, excludedFiles)) result.append(c); } - ++fn; } dirInfo.setNameFilters(QStringList(QLatin1String("*"))); - dirInfo.setFilter(QDir::Dirs|QDir::NoDotAndDotDot); + dirInfo.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); fileNames = dirInfo.entryList(); - fn = fileNames.constBegin(); - while (fn != fileNames.constEnd()) { - result += getFilesHere(dirInfo.filePath(*fn), nameFilter, location, excludedDirs, excludedFiles); - ++fn; - } + for (const auto &file : fileNames) + result += getFilesHere(dirInfo.filePath(file), nameFilter, location, excludedDirs, + excludedFiles); return result; } /*! Push \a dir onto the stack of working directories. */ -void Config::pushWorkingDir(const QString& dir) +void Config::pushWorkingDir(const QString &dir) { - workingDirs_.push(dir); + m_workingDirs.push(dir); } /*! @@ -1244,8 +1286,8 @@ void Config::pushWorkingDir(const QString& dir) */ QString Config::popWorkingDir() { - if (!workingDirs_.isEmpty()) - return workingDirs_.pop(); + if (!m_workingDirs.isEmpty()) + return m_workingDirs.pop(); qDebug() << "RETURNED EMPTY WORKING DIR"; return QString(); diff --git a/src/qdoc/config.h b/src/qdoc/config.h index 0de7076eb1..44940dfa1a 100644 --- a/src/qdoc/config.h +++ b/src/qdoc/config.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -33,101 +33,149 @@ #ifndef CONFIG_H #define CONFIG_H -#include -#include -#include -#include -#include #include "location.h" +#include "qdoccommandlineparser.h" +#include "singleton.h" + +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE +/* + Contains information about a location + where a ConfigVar string needs to be expanded + from another config variable. +*/ +struct ExpandVar +{ + int m_valueIndex {}; + int m_index {}; + QString m_var {}; + QChar m_delim {}; + + ExpandVar(int valueIndex, int index, const QString &var, const QChar &delim) + : m_valueIndex(valueIndex), m_index(index), m_var(var), m_delim(delim) + { + } +}; + /* This struct contains all the information for one config variable found in a qdocconf file. */ -struct ConfigVar { - bool plus_; - QString name_; - QStringList values_; - QString currentPath_; - Location location_; +struct ConfigVar +{ + QString m_name {}; + + struct ConfigValue { + QString m_value; + QString m_path; + }; - ConfigVar() : plus_(false) { } + QList m_values {}; + Location m_location {}; + QList m_expandVars {}; - ConfigVar(const QString& name, const QStringList& values, const QString& dir) - : plus_(true), name_(name), values_(values), currentPath_(dir) { } + ConfigVar() = default; - ConfigVar(const QString& name, const QStringList& values, const QString& dir, const Location& loc) - : plus_(false), name_(name), values_(values), currentPath_(dir), location_(loc) { } + ConfigVar(const QString &name, const QStringList &values, const QString &dir, + const Location &loc = Location(), + const QList &expandVars = QList()) + : m_name(name), m_location(loc), m_expandVars(expandVars) + { + for (const auto &v : values) + m_values << ConfigValue {v, dir}; + } + + /* + Appends values to this ConfigVar, and adjusts the ExpandVar + parameters so they continue to refer to the correct values. + */ + void append(const ConfigVar &other) + { + m_expandVars << other.m_expandVars; + QList::Iterator it = m_expandVars.end(); + it -= other.m_expandVars.size(); + std::for_each(it, m_expandVars.end(), [this](ExpandVar &v) { + v.m_valueIndex += m_values.size(); + }); + m_values << other.m_values; + m_location = other.m_location; + } }; /* In this multimap, the key is a config variable name. */ -typedef QMultiMap ConfigVarMultimap; +typedef QMap ConfigVarMap; -class Config +class Config : public Singleton { - Q_DECLARE_TR_FUNCTIONS(QDoc::Config) - public: - Config(const QString& programName); ~Config(); - static bool debug_; + enum QDocPass { Neither, Prepare, Generate }; + + void init(const QString &programName, const QStringList &args); + bool getDebug() const { return m_debug; } + bool showInternal() const { return m_showInternal; } - void load(const QString& fileName); - void setStringList(const QString& var, const QStringList& values); + void clear(); + void reset(); + void load(const QString &fileName); + void setStringList(const QString &var, const QStringList &values); + void insertStringList(const QString &var, const QStringList &values); + + void showHelp(int exitCode = 0) { m_parser.showHelp(exitCode); } + QStringList qdocFiles() const { return m_parser.positionalArguments(); } + const QString &programName() const { return m_prog; } + const Location &location() const { return m_location; } + const Location &lastLocation() const { return m_lastLocation; } + bool getBool(const QString &var) const; + int getInt(const QString &var) const; - const QString& programName() const { return prog; } - const Location& location() const { return loc; } - const Location& lastLocation() const { return lastLocation_; } - bool getBool(const QString& var) const; - int getInt(const QString& var) const; QString getOutputDir(const QString &format = QString("HTML")) const; QSet getOutputFormats() const; - QString getString(const QString& var, const QString& defaultString = QString()) const; - QSet getStringSet(const QString& var) const; - QStringList getStringList(const QString& var) const; - QStringList getCanonicalPathList(const QString& var, bool validate = false) const; - QRegExp getRegExp(const QString& var) const; - QList getRegExpList(const QString& var) const; - QSet subVars(const QString& var) const; - void subVarsAndValues(const QString& var, ConfigVarMultimap& t) const; - QStringList getAllFiles(const QString& filesVar, - const QString& dirsVar, + QString getString(const QString &var, const QString &defaultString = QString()) const; + QSet getStringSet(const QString &var) const; + QStringList getStringList(const QString &var) const; + QStringList getCanonicalPathList(const QString &var, bool validate = false) const; + QRegularExpression getRegExp(const QString &var) const; + QList getRegExpList(const QString &var) const; + QSet subVars(const QString &var) const; + void subVarsAndValues(const QString &var, ConfigVarMap &map) const; + QStringList getAllFiles(const QString &filesVar, const QString &dirsVar, const QSet &excludedDirs = QSet(), const QSet &excludedFiles = QSet()); - QString getIncludeFilePath(const QString& fileName) const; - QStringList getExampleQdocFiles(const QSet &excludedDirs, const QSet &excludedFiles); - QStringList getExampleImageFiles(const QSet &excludedDirs, const QSet &excludedFiles); + QString getIncludeFilePath(const QString &fileName) const; + QStringList getExampleQdocFiles(const QSet &excludedDirs, + const QSet &excludedFiles); + QStringList getExampleImageFiles(const QSet &excludedDirs, + const QSet &excludedFiles); + QString getExampleProjectFile(const QString &examplePath); - static QStringList loadMaster(const QString& fileName); + static QStringList loadMaster(const QString &fileName); static bool isFileExcluded(const QString &fileName, const QSet &excludedFiles); - static QStringList getFilesHere(const QString& dir, - const QString& nameFilter, + static QStringList getFilesHere(const QString &dir, const QString &nameFilter, const Location &location = Location(), const QSet &excludedDirs = QSet(), const QSet &excludedFiles = QSet()); - static QString findFile(const Location& location, - const QStringList &files, - const QStringList& dirs, - const QString& fileName, + static QString findFile(const Location &location, const QStringList &files, + const QStringList &dirs, const QString &fileName, QString *userFriendlyFilePath = nullptr); - static QString findFile(const Location &location, - const QStringList &files, - const QStringList &dirs, - const QString &fileBase, + static QString findFile(const Location &location, const QStringList &files, + const QStringList &dirs, const QString &fileBase, const QStringList &fileExtensions, QString *userFriendlyFilePath = nullptr); - static QString copyFile(const Location& location, - const QString& sourceFilePath, - const QString& userFriendlySourceFilePath, - const QString& targetDirPath); - static int numParams(const QString& value); - static bool removeDirContents(const QString& dir); - static void pushWorkingDir(const QString& dir); + static QString copyFile(const Location &location, const QString &sourceFilePath, + const QString &userFriendlySourceFilePath, + const QString &targetDirPath); + static int numParams(const QString &value); + static void pushWorkingDir(const QString &dir); static QString popWorkingDir(); static const QString dot; @@ -137,28 +185,65 @@ class Config static QString overrideOutputDir; static QSet overrideOutputFormats; + inline bool singleExec() const; + inline bool dualExec() const; + QStringList &defines() { return m_defines; } + QStringList &dependModules() { return m_dependModules; } + QStringList &includePaths() { return m_includePaths; } + QStringList &indexDirs() { return m_indexDirs; } + QString currentDir() const { return m_currentDir; } + void setCurrentDir(const QString &path) { m_currentDir = path; } + QString previousCurrentDir() const { return m_previousCurrentDir; } + void setPreviousCurrentDir(const QString &path) { m_previousCurrentDir = path; } + + QDocPass qdocPass() const { return m_qdocPass; } + void setQDocPass(const QDocPass &pass) { m_qdocPass = pass; }; + bool preparing() const { return (m_qdocPass == Prepare); } + bool generating() const { return (m_qdocPass == Generate); } + private: + void processCommandLineOptions(const QStringList &args); + void setIncludePaths(); + void setIndexDirs(); + void expandVariables(); + inline void updateLocation(const ConfigVar &cv) const + { + if (!cv.m_location.isEmpty()) + const_cast(this)->m_lastLocation = cv.m_location; + } + + QStringList m_dependModules {}; + QStringList m_defines {}; + QStringList m_includePaths {}; + QStringList m_indexDirs {}; + QStringList m_exampleFiles {}; + QStringList m_exampleDirs {}; + QString m_currentDir {}; + QString m_previousCurrentDir {}; + + bool m_showInternal { false }; + static bool m_debug; static bool isMetaKeyChar(QChar ch); - void load(Location location, const QString& fileName); - - QString prog; - Location loc; - Location lastLocation_; - ConfigVarMultimap configVars_; - - static QMap uncompressedFiles; - static QMap extractedDirs; - static int numInstances; - static QStack workingDirs_; - static QMap includeFilesMap_; + void load(Location location, const QString &fileName); + + QString m_prog {}; + Location m_location {}; + Location m_lastLocation {}; + ConfigVarMap m_configVars {}; + + static QMap m_uncompressedFiles; + static QMap m_extractedDirs; + static QStack m_workingDirs; + static QMap m_includeFilesMap; + QDocCommandLineParser m_parser {}; + + QDocPass m_qdocPass { Neither }; }; struct ConfigStrings { static QString ALIAS; static QString AUTOLINKERRORS; - static QString BASE; - static QString BASEDIR; static QString BUILDVERSION; static QString CLANGDEFINES; static QString CODEINDENT; @@ -169,7 +254,7 @@ struct ConfigStrings static QString DEFINES; static QString DEPENDS; static QString DESCRIPTION; - static QString EDITION; + static QString DOCBOOKEXTENSIONS; static QString ENDHEADER; static QString EXAMPLEDIRS; static QString EXAMPLES; @@ -179,7 +264,6 @@ struct ConfigStrings static QString EXTRAIMAGES; static QString FALSEHOODS; static QString FORMATTING; - static QString GENERATEINDEX; static QString HEADERDIRS; static QString HEADERS; static QString HEADERSCRIPTS; @@ -188,6 +272,8 @@ struct ConfigStrings static QString HOMETITLE; static QString IGNOREDIRECTIVES; static QString IGNORETOKENS; + static QString IGNORESINCE; + static QString IGNOREWORDS; static QString IMAGEDIRS; static QString IMAGES; static QString INCLUDEPATHS; @@ -195,16 +281,15 @@ struct ConfigStrings static QString LANDINGPAGE; static QString LANDINGTITLE; static QString LANGUAGE; + static QString LOCATIONINFO; + static QString LOGPROGRESS; static QString MACRO; static QString MANIFESTMETA; static QString MODULEHEADER; static QString NATURALLANGUAGE; static QString NAVIGATION; static QString NOLINKERRORS; - static QString OBSOLETELINKS; static QString OUTPUTDIR; - static QString OUTPUTENCODING; - static QString OUTPUTLANGUAGE; static QString OUTPUTFORMATS; static QString OUTPUTPREFIXES; static QString OUTPUTSUFFIXES; @@ -212,7 +297,6 @@ struct ConfigStrings static QString REDIRECTDOCUMENTATIONTODEVNULL; static QString QHP; static QString QUOTINGINFORMATION; - static QString SCRIPTDIRS; static QString SCRIPTS; static QString SHOWINTERNAL; static QString SINGLEEXEC; @@ -220,14 +304,12 @@ struct ConfigStrings static QString SOURCEENCODING; static QString SOURCES; static QString SPURIOUS; - static QString STYLEDIRS; - static QString STYLE; - static QString STYLES; static QString STYLESHEETS; static QString SYNTAXHIGHLIGHTING; - static QString TEMPLATEDIR; static QString TABSIZE; static QString TAGFILE; + static QString TIMESTAMPS; + static QString TOCTITLES; static QString TRANSLATORS; static QString URL; static QString VERSION; @@ -238,13 +320,10 @@ struct ConfigStrings static QString QMLTYPESPAGE; static QString QMLTYPESTITLE; static QString WARNINGLIMIT; - static QString WRITEQAPAGES; }; #define CONFIG_ALIAS ConfigStrings::ALIAS #define CONFIG_AUTOLINKERRORS ConfigStrings::AUTOLINKERRORS -#define CONFIG_BASE ConfigStrings::BASE -#define CONFIG_BASEDIR ConfigStrings::BASEDIR #define CONFIG_BUILDVERSION ConfigStrings::BUILDVERSION #define CONFIG_CLANGDEFINES ConfigStrings::CLANGDEFINES #define CONFIG_CODEINDENT ConfigStrings::CODEINDENT @@ -255,7 +334,7 @@ struct ConfigStrings #define CONFIG_DEFINES ConfigStrings::DEFINES #define CONFIG_DEPENDS ConfigStrings::DEPENDS #define CONFIG_DESCRIPTION ConfigStrings::DESCRIPTION -#define CONFIG_EDITION ConfigStrings::EDITION +#define CONFIG_DOCBOOKEXTENSIONS ConfigStrings::DOCBOOKEXTENSIONS #define CONFIG_ENDHEADER ConfigStrings::ENDHEADER #define CONFIG_EXAMPLEDIRS ConfigStrings::EXAMPLEDIRS #define CONFIG_EXAMPLES ConfigStrings::EXAMPLES @@ -265,7 +344,6 @@ struct ConfigStrings #define CONFIG_EXTRAIMAGES ConfigStrings::EXTRAIMAGES #define CONFIG_FALSEHOODS ConfigStrings::FALSEHOODS #define CONFIG_FORMATTING ConfigStrings::FORMATTING -#define CONFIG_GENERATEINDEX ConfigStrings::GENERATEINDEX #define CONFIG_HEADERDIRS ConfigStrings::HEADERDIRS #define CONFIG_HEADERS ConfigStrings::HEADERS #define CONFIG_HEADERSCRIPTS ConfigStrings::HEADERSCRIPTS @@ -273,7 +351,9 @@ struct ConfigStrings #define CONFIG_HOMEPAGE ConfigStrings::HOMEPAGE #define CONFIG_HOMETITLE ConfigStrings::HOMETITLE #define CONFIG_IGNOREDIRECTIVES ConfigStrings::IGNOREDIRECTIVES +#define CONFIG_IGNORESINCE ConfigStrings::IGNORESINCE #define CONFIG_IGNORETOKENS ConfigStrings::IGNORETOKENS +#define CONFIG_IGNOREWORDS ConfigStrings::IGNOREWORDS #define CONFIG_IMAGEDIRS ConfigStrings::IMAGEDIRS #define CONFIG_IMAGES ConfigStrings::IMAGES #define CONFIG_INCLUDEPATHS ConfigStrings::INCLUDEPATHS @@ -281,16 +361,15 @@ struct ConfigStrings #define CONFIG_LANDINGPAGE ConfigStrings::LANDINGPAGE #define CONFIG_LANDINGTITLE ConfigStrings::LANDINGTITLE #define CONFIG_LANGUAGE ConfigStrings::LANGUAGE +#define CONFIG_LOCATIONINFO ConfigStrings::LOCATIONINFO +#define CONFIG_LOGPROGRESS ConfigStrings::LOGPROGRESS #define CONFIG_MACRO ConfigStrings::MACRO #define CONFIG_MANIFESTMETA ConfigStrings::MANIFESTMETA #define CONFIG_MODULEHEADER ConfigStrings::MODULEHEADER #define CONFIG_NATURALLANGUAGE ConfigStrings::NATURALLANGUAGE #define CONFIG_NAVIGATION ConfigStrings::NAVIGATION #define CONFIG_NOLINKERRORS ConfigStrings::NOLINKERRORS -#define CONFIG_OBSOLETELINKS ConfigStrings::OBSOLETELINKS #define CONFIG_OUTPUTDIR ConfigStrings::OUTPUTDIR -#define CONFIG_OUTPUTENCODING ConfigStrings::OUTPUTENCODING -#define CONFIG_OUTPUTLANGUAGE ConfigStrings::OUTPUTLANGUAGE #define CONFIG_OUTPUTFORMATS ConfigStrings::OUTPUTFORMATS #define CONFIG_OUTPUTPREFIXES ConfigStrings::OUTPUTPREFIXES #define CONFIG_OUTPUTSUFFIXES ConfigStrings::OUTPUTSUFFIXES @@ -298,7 +377,6 @@ struct ConfigStrings #define CONFIG_REDIRECTDOCUMENTATIONTODEVNULL ConfigStrings::REDIRECTDOCUMENTATIONTODEVNULL #define CONFIG_QHP ConfigStrings::QHP #define CONFIG_QUOTINGINFORMATION ConfigStrings::QUOTINGINFORMATION -#define CONFIG_SCRIPTDIRS ConfigStrings::SCRIPTDIRS #define CONFIG_SCRIPTS ConfigStrings::SCRIPTS #define CONFIG_SHOWINTERNAL ConfigStrings::SHOWINTERNAL #define CONFIG_SINGLEEXEC ConfigStrings::SINGLEEXEC @@ -306,14 +384,12 @@ struct ConfigStrings #define CONFIG_SOURCEENCODING ConfigStrings::SOURCEENCODING #define CONFIG_SOURCES ConfigStrings::SOURCES #define CONFIG_SPURIOUS ConfigStrings::SPURIOUS -#define CONFIG_STYLEDIRS ConfigStrings::STYLEDIRS -#define CONFIG_STYLE ConfigStrings::STYLE -#define CONFIG_STYLES ConfigStrings::STYLES #define CONFIG_STYLESHEETS ConfigStrings::STYLESHEETS #define CONFIG_SYNTAXHIGHLIGHTING ConfigStrings::SYNTAXHIGHLIGHTING -#define CONFIG_TEMPLATEDIR ConfigStrings::TEMPLATEDIR #define CONFIG_TABSIZE ConfigStrings::TABSIZE #define CONFIG_TAGFILE ConfigStrings::TAGFILE +#define CONFIG_TIMESTAMPS ConfigStrings::TIMESTAMPS +#define CONFIG_TOCTITLES ConfigStrings::TOCTITLES #define CONFIG_TRANSLATORS ConfigStrings::TRANSLATORS #define CONFIG_URL ConfigStrings::URL #define CONFIG_VERSION ConfigStrings::VERSION @@ -324,7 +400,16 @@ struct ConfigStrings #define CONFIG_QMLTYPESPAGE ConfigStrings::QMLTYPESPAGE #define CONFIG_QMLTYPESTITLE ConfigStrings::QMLTYPESTITLE #define CONFIG_WARNINGLIMIT ConfigStrings::WARNINGLIMIT -#define CONFIG_WRITEQAPAGES ConfigStrings::WRITEQAPAGES + +inline bool Config::singleExec() const +{ + return getBool(CONFIG_SINGLEEXEC); +} + +inline bool Config::dualExec() const +{ + return !getBool(CONFIG_SINGLEEXEC); +} QT_END_NAMESPACE diff --git a/src/qdoc/configure.json b/src/qdoc/configure.json deleted file mode 100644 index f7190fcb3c..0000000000 --- a/src/qdoc/configure.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "module": "qdoc", - "tests": { - "libclang": { - "label": "libclang", - "test": "libclang", - "type": "libclang" - } - }, - "features": { - "qdoc": { - "label": "QDoc", - "condition": "tests.libclang", - "output": [ - "privateFeature", - { "type": "varAssign", "name": "CLANG_LIBS", "value": "tests.libclang.libs" }, - { "type": "varAssign", "name": "CLANG_INCLUDEPATH", "value": "tests.libclang.includepath" }, - { "type": "varAssign", "name": "CLANG_LIBDIR", "value": "tests.libclang.libdir" }, - { "type": "varAssign", "name": "CLANG_DEFINES", "value": "tests.libclang.defines" }, - { "type": "varAssign", "name": "CLANG_VERSION", "value": "tests.libclang.version" } - ] - } - }, - "report": [ - { - "type": "warning", - "condition": "!features.qdoc", - "message": "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation. - -Either ensure that llvm-config is in your PATH environment variable, or set LLVM_INSTALL_DIR to the location of your llvm installation. -On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution. -On macOS, you can use Homebrew's llvm package. -On Windows, you must set LLVM_INSTALL_DIR to the installation path." - } - ], - "summary": [ - { - "section": "Qt Tools", - "entries": [ - "qdoc" - ] - } - ] -} diff --git a/src/qdoc/configure.pri b/src/qdoc/configure.pri deleted file mode 100644 index e9d7667c0b..0000000000 --- a/src/qdoc/configure.pri +++ /dev/null @@ -1,371 +0,0 @@ -defineReplace(extractVersion) { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)(svn)?$, \\1)) } -defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+(svn)?$, \\1)) } -defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+(svn)?$, \\1)) } -defineReplace(extractPatchVersion) { return($$replace(1, ^\\d+\\.\\d+\\.(\\d+)(svn)?$, \\1)) } - -defineTest(versionIsAtLeast) { - actual_major_version = $$extractMajorVersion($$1) - actual_minor_version = $$extractMinorVersion($$1) - actual_patch_version = $$extractPatchVersion($$1) - required_min_major_version = $$extractMajorVersion($$2) - required_min_minor_version = $$extractMinorVersion($$2) - required_min_patch_version = $$extractPatchVersion($$2) - - isEqual(actual_major_version, $$required_min_major_version) { - isEqual(actual_minor_version, $$required_min_minor_version) { - isEqual(actual_patch_version, $$required_min_patch_version): return(true) - greaterThan(actual_patch_version, $$required_min_patch_version): return(true) - } - greaterThan(actual_minor_version, $$required_min_minor_version): return(true) - } - greaterThan(actual_major_version, $$required_min_major_version): return(true) - - return(false) -} - -defineReplace(findLLVMVersionFromLibDir) { - libdir = $$1 - version_dirs = $$files($$libdir/clang/*) - for (version_dir, version_dirs) { - fileName = $$basename(version_dir) - version = $$find(fileName, ^(\\d+\\.\\d+\\.\\d+)$) - !isEmpty(version) { - isEmpty(candidateVersion): candidateVersion = $$version - else: versionIsAtLeast($$version, $$candidateVersion): candidateVersion = $$version - } - } - return($$candidateVersion) -} - -defineTest(qtConfTest_libclang) { - isEmpty(QDOC_USE_STATIC_LIBCLANG): QDOC_USE_STATIC_LIBCLANG = $$(QDOC_USE_STATIC_LIBCLANG) - - equals(QMAKE_HOST.os, Windows) { - # on Windows we have only two host compilers, MSVC or mingw. The former we never - # use for cross-compilation where it isn't also the target compiler. The latter - # is not detectable as this .prf file is evaluated against the target configuration - # and therefore checking for "mingw" won't work when the target compiler is clang (Android) - # or qcc (QNX). - msvc { - isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MSVC) - } else { - isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR_MINGW) - } - } - isEmpty(LLVM_INSTALL_DIR): LLVM_INSTALL_DIR = $$(LLVM_INSTALL_DIR) - - # Assume libclang is installed on the target system - isEmpty(LLVM_INSTALL_DIR) { - llvmConfigCandidates = \ - llvm-config-9 \ - llvm-config-8 \ - llvm-config-7 \ - llvm-config-6.0 \ - llvm-config-5.0 \ - llvm-config-4.0 \ - llvm-config-3.9 \ - llvm-config - - for (candidate, llvmConfigCandidates) { - LLVM_INSTALL_DIR = $$system("$$candidate --prefix 2>$$QMAKE_SYSTEM_NULL_DEVICE") - !isEmpty(LLVM_INSTALL_DIR) { - CLANG_INCLUDEPATH = $$system("$$candidate --includedir 2>/dev/null") - LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h - !exists($$LIBCLANG_MAIN_HEADER) { - !isEmpty(LLVM_INSTALL_DIR): \ - qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") - continue - } else { - qtLog("QDoc:" \ - "Using Clang installation found in $${LLVM_INSTALL_DIR}." \ - "Set the LLVM_INSTALL_DIR environment variable to override.") - break() - } - } - } - } - LLVM_INSTALL_DIR = $$clean_path($$LLVM_INSTALL_DIR) - - contains(QMAKE_HOST.arch, x86_64): \ - clangInstallDir = $$replace(LLVM_INSTALL_DIR, _ARCH_, 64) - else: \ - clangInstallDir = $$replace(LLVM_INSTALL_DIR, _ARCH_, 32) - isEmpty(LLVM_INSTALL_DIR) { - win32 { - return(false) - } - macos { - # Default to homebrew llvm on macOS. The CLANG_VERSION test below will complain if missing. - clangInstallDir = $$system("brew --prefix llvm") - } else { - clangInstallDir = /usr - } - } - - # note: llvm_config only exits on unix - llvm_config = $$clangInstallDir/bin/llvm-config - exists($$llvm_config) { - CLANG_LIBDIR = $$system("$$llvm_config --libdir 2>/dev/null") - CLANG_INCLUDEPATH = $$system("$$llvm_config --includedir 2>/dev/null") - output = $$system("$$llvm_config --version 2>/dev/null") - CLANG_VERSION = $$extractVersion($$output) - } else { - CLANG_LIBDIR = $$clangInstallDir/lib - CLANG_INCLUDEPATH = $$clangInstallDir/include - CLANG_VERSION = $$findLLVMVersionFromLibDir($$CLANG_LIBDIR) - } - isEmpty(CLANG_VERSION) { - !isEmpty(LLVM_INSTALL_DIR): \ - qtLog("Cannot determine version of clang installation in $${clangInstallDir}.") - return(false) - } - - LIBCLANG_MAIN_HEADER = $$CLANG_INCLUDEPATH/clang-c/Index.h - !exists($$LIBCLANG_MAIN_HEADER) { - !isEmpty(LLVM_INSTALL_DIR): \ - qtLog("Cannot find libclang's main header file, candidate: $${LIBCLANG_MAIN_HEADER}.") - return(false) - } - - !contains(QMAKE_DEFAULT_LIBDIRS, $$CLANG_LIBDIR): CLANG_LIBS = -L$${CLANG_LIBDIR} - - CLANG_DEFINES = - - isEmpty(QDOC_USE_STATIC_LIBCLANG) { - equals(QMAKE_HOST.os, Windows): \ - CLANG_LIBS += -llibclang -ladvapi32 -lshell32 - else: \ - CLANG_LIBS += -lclang - } else { - msvc { - CLANG_DEFINES += CINDEX_LINKAGE= - CLANG_LIBS += -llibclang_static -ladvapi32 -lshell32 -lMincore - } else { - !equals(QMAKE_HOST.os, Darwin): CLANG_LIBS+=-Wl,--start-group - CLANG_LIBS += -lclangAnalysis \ - -lclangApplyReplacements \ - -lclangARCMigrate \ - -lclangAST \ - -lclangASTMatchers \ - -lclangBasic \ - -lclangChangeNamespace \ - -lclangCodeGen \ - -lclangCrossTU \ - -lclangDaemon \ - -lclangDriver \ - -lclangDynamicASTMatchers \ - -lclangEdit \ - -lclangFormat \ - -lclangFrontend \ - -lclangFrontendTool \ - -lclangHandleCXX \ - -lclangIncludeFixer \ - -lclangIncludeFixerPlugin \ - -lclangIndex \ - -lclangLex \ - -lclangMove \ - -lclangParse \ - -lclangQuery \ - -lclangReorderFields \ - -lclangRewrite \ - -lclangRewriteFrontend \ - -lclangSema \ - -lclangSerialization \ - -lclang_static \ - -lclangStaticAnalyzerCheckers \ - -lclangStaticAnalyzerCore \ - -lclangStaticAnalyzerFrontend \ - -lclangTidy \ - -lclangTidyAndroidModule \ - -lclangTidyBoostModule \ - -lclangTidyBugproneModule \ - -lclangTidyCERTModule \ - -lclangTidyCppCoreGuidelinesModule \ - -lclangTidyFuchsiaModule \ - -lclangTidyGoogleModule \ - -lclangTidyHICPPModule \ - -lclangTidyLLVMModule \ - -lclangTidyMiscModule \ - -lclangTidyModernizeModule \ - -lclangTidyMPIModule \ - -lclangTidyObjCModule \ - -lclangTidyPerformanceModule \ - -lclangTidyPlugin \ - -lclangTidyReadabilityModule \ - -lclangTidyUtils \ - -lclangTooling \ - -lclangToolingASTDiff \ - -lclangToolingCore \ - -lclangToolingRefactor \ - -lfindAllSymbols \ - -lLLVMAArch64AsmParser \ - -lLLVMAArch64AsmPrinter \ - -lLLVMAArch64CodeGen \ - -lLLVMAArch64Desc \ - -lLLVMAArch64Disassembler \ - -lLLVMAArch64Info \ - -lLLVMAArch64Utils \ - -lLLVMAMDGPUAsmParser \ - -lLLVMAMDGPUAsmPrinter \ - -lLLVMAMDGPUCodeGen \ - -lLLVMAMDGPUDesc \ - -lLLVMAMDGPUDisassembler \ - -lLLVMAMDGPUInfo \ - -lLLVMAMDGPUUtils \ - -lLLVMAnalysis \ - -lLLVMARMAsmParser \ - -lLLVMARMAsmPrinter \ - -lLLVMARMCodeGen \ - -lLLVMARMDesc \ - -lLLVMARMDisassembler \ - -lLLVMARMInfo \ - -lLLVMARMUtils \ - -lLLVMAsmParser \ - -lLLVMAsmPrinter \ - -lLLVMBinaryFormat \ - -lLLVMBitReader \ - -lLLVMBitWriter \ - -lLLVMBPFAsmParser \ - -lLLVMBPFAsmPrinter \ - -lLLVMBPFCodeGen \ - -lLLVMBPFDesc \ - -lLLVMBPFDisassembler \ - -lLLVMBPFInfo \ - -lLLVMCodeGen \ - -lLLVMCore \ - -lLLVMCoroutines \ - -lLLVMCoverage \ - -lLLVMDebugInfoCodeView \ - -lLLVMDebugInfoDWARF \ - -lLLVMDebugInfoMSF \ - -lLLVMDebugInfoPDB \ - -lLLVMDemangle \ - -lLLVMDlltoolDriver \ - -lLLVMExecutionEngine \ - -lLLVMFuzzMutate \ - -lLLVMGlobalISel \ - -lLLVMHexagonAsmParser \ - -lLLVMHexagonCodeGen \ - -lLLVMHexagonDesc \ - -lLLVMHexagonDisassembler \ - -lLLVMHexagonInfo \ - -lLLVMInstCombine \ - -lLLVMInstrumentation \ - -lLLVMInterpreter \ - -lLLVMipo \ - -lLLVMIRReader \ - -lLLVMLanaiAsmParser \ - -lLLVMLanaiAsmPrinter \ - -lLLVMLanaiCodeGen \ - -lLLVMLanaiDesc \ - -lLLVMLanaiDisassembler \ - -lLLVMLanaiInfo \ - -lLLVMLibDriver \ - -lLLVMLineEditor \ - -lLLVMLinker \ - -lLLVMLTO \ - -lLLVMMC \ - -lLLVMMCDisassembler \ - -lLLVMMCJIT \ - -lLLVMMCParser \ - -lLLVMMipsAsmParser \ - -lLLVMMipsAsmPrinter \ - -lLLVMMipsCodeGen \ - -lLLVMMipsDesc \ - -lLLVMMipsDisassembler \ - -lLLVMMipsInfo \ - -lLLVMMIRParser \ - -lLLVMMSP430AsmPrinter \ - -lLLVMMSP430CodeGen \ - -lLLVMMSP430Desc \ - -lLLVMMSP430Info \ - -lLLVMNVPTXAsmPrinter \ - -lLLVMNVPTXCodeGen \ - -lLLVMNVPTXDesc \ - -lLLVMNVPTXInfo \ - -lLLVMObjCARCOpts \ - -lLLVMObject \ - -lLLVMObjectYAML \ - -lLLVMOption \ - -lLLVMOrcJIT \ - -lLLVMPasses \ - -lLLVMPowerPCAsmParser \ - -lLLVMPowerPCAsmPrinter \ - -lLLVMPowerPCCodeGen \ - -lLLVMPowerPCDesc \ - -lLLVMPowerPCDisassembler \ - -lLLVMPowerPCInfo \ - -lLLVMProfileData \ - -lLLVMRuntimeDyld \ - -lLLVMScalarOpts \ - -lLLVMSelectionDAG \ - -lLLVMSparcAsmParser \ - -lLLVMSparcAsmPrinter \ - -lLLVMSparcCodeGen \ - -lLLVMSparcDesc \ - -lLLVMSparcDisassembler \ - -lLLVMSparcInfo \ - -lLLVMSupport \ - -lLLVMSymbolize \ - -lLLVMSystemZAsmParser \ - -lLLVMSystemZAsmPrinter \ - -lLLVMSystemZCodeGen \ - -lLLVMSystemZDesc \ - -lLLVMSystemZDisassembler \ - -lLLVMSystemZInfo \ - -lLLVMTableGen \ - -lLLVMTarget \ - -lLLVMTransformUtils \ - -lLLVMVectorize \ - -lLLVMWindowsManifest \ - -lLLVMX86AsmParser \ - -lLLVMX86AsmPrinter \ - -lLLVMX86CodeGen \ - -lLLVMX86Desc \ - -lLLVMX86Disassembler \ - -lLLVMX86Info \ - -lLLVMX86Utils \ - -lLLVMXCoreAsmPrinter \ - -lLLVMXCoreCodeGen \ - -lLLVMXCoreDesc \ - -lLLVMXCoreDisassembler \ - -lLLVMXCoreInfo \ - -lLLVMXRay - !equals(QMAKE_HOST.os, Darwin): CLANG_LIBS+=-Wl,--end-group - CLANG_LIBS += -lz - equals(QMAKE_HOST.os, Windows): CLANG_LIBS += -lpsapi -lshell32 -lole32 -luuid -ladvapi32 -lversion - else: CLANG_LIBS += -ldl - equals(QMAKE_HOST.os, Darwin): CLANG_LIBS += -lcurses -lm -lxml2 - } - } - - !versionIsAtLeast($$CLANG_VERSION, "3.9.0") { - log("LLVM/Clang version >= 3.9.0 required, version provided: $${CLANG_VERSION}.$$escape_expand(\\n)") - return(false) - } - - $${1}.libs = $$CLANG_LIBS - export($${1}.libs) - $${1}.cache += libs - - $${1}.includepath = $$CLANG_INCLUDEPATH - export($${1}.includepath) - $${1}.cache += includepath - - $${1}.libdir = $$CLANG_LIBDIR - export($${1}.libdir) - $${1}.cache += libdir - - $${1}.defines = $$CLANG_DEFINES - export($${1}.defines) - $${1}.cache += defines - - $${1}.version = $$CLANG_VERSION - export($${1}.version) - $${1}.cache += version - - export($${1}.cache) - - return(true) -} - diff --git a/src/qdoc/cppcodemarker.cpp b/src/qdoc/cppcodemarker.cpp index 2387fb22d6..9846a0dd87 100644 --- a/src/qdoc/cppcodemarker.cpp +++ b/src/qdoc/cppcodemarker.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -31,29 +31,22 @@ */ #include "cppcodemarker.h" + +#include "access.h" +#include "enumnode.h" +#include "functionnode.h" +#include "namespacenode.h" +#include "propertynode.h" +#include "qmlpropertynode.h" #include "text.h" #include "tree.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE +#include "typedefnode.h" +#include "variablenode.h" -/*! - The constructor does nothing. - */ -CppCodeMarker::CppCodeMarker() -{ - // nothing. -} +#include +#include -/*! - The destructor does nothing. - */ -CppCodeMarker::~CppCodeMarker() -{ - // nothing. -} +QT_BEGIN_NAMESPACE /*! Returns \c true. @@ -67,23 +60,12 @@ bool CppCodeMarker::recognizeCode(const QString & /* code */) Returns \c true if \a ext is any of a list of file extensions for the C++ language. */ -bool CppCodeMarker::recognizeExtension(const QString& extension) +bool CppCodeMarker::recognizeExtension(const QString &extension) { QByteArray ext = extension.toLatin1(); - return ext == "c" || - ext == "c++" || - ext == "qdoc" || - ext == "qtt" || - ext == "qtx" || - ext == "cc" || - ext == "cpp" || - ext == "cxx" || - ext == "ch" || - ext == "h" || - ext == "h++" || - ext == "hh" || - ext == "hpp" || - ext == "hxx"; + return ext == "c" || ext == "c++" || ext == "qdoc" || ext == "qtt" || ext == "qtx" + || ext == "cc" || ext == "cpp" || ext == "cxx" || ext == "ch" || ext == "h" + || ext == "h++" || ext == "hh" || ext == "hpp" || ext == "hxx"; } /*! @@ -102,15 +84,13 @@ Atom::AtomType CppCodeMarker::atomType() const return Atom::Code; } -QString CppCodeMarker::markedUpCode(const QString &code, - const Node *relative, +QString CppCodeMarker::markedUpCode(const QString &code, const Node *relative, const Location &location) { return addMarkUp(code, relative, location); } -QString CppCodeMarker::markedUpSynopsis(const Node *node, - const Node * /* relative */, +QString CppCodeMarker::markedUpSynopsis(const Node *node, const Node * /* relative */, Section::Style style) { const int MaxEnumValues = 6; @@ -118,9 +98,7 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, const PropertyNode *property; const VariableNode *variable; const EnumNode *enume; - const TypedefNode *typedeff; QString synopsis; - QString extra; QString name; name = taggedNode(node); @@ -128,42 +106,46 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, name = linkTag(node, name); name = "<@name>" + name + ""; - if ((style == Section::Details) && !node->parent()->name().isEmpty() && - !node->isProperty() && !node->isQmlNode() && !node->isJsNode()) - name.prepend(taggedNode(node->parent()) + "::"); + if (style == Section::Details) { + if (!node->isRelatedNonmember() && !node->isProxyNode() && !node->parent()->name().isEmpty() + && !node->parent()->isHeader() && !node->isProperty() && !node->isQmlNode() + && !node->isJsNode()) { + name.prepend(taggedNode(node->parent()) + "::"); + } + } switch (node->nodeType()) { case Node::Namespace: - synopsis = "namespace " + name; - break; case Node::Class: - synopsis = "class " + name; + case Node::Struct: + case Node::Union: + synopsis = Node::nodeTypeString(node->nodeType()); + synopsis += QLatin1Char(' ') + name; break; case Node::Function: - func = (const FunctionNode *) node; - + func = (const FunctionNode *)node; + if (style == Section::Details) { + const QString &templateDecl = node->templateDecl(); + if (!templateDecl.isEmpty()) + synopsis = templateDecl + QLatin1Char(' '); + } if (style != Section::AllMembers && !func->returnType().isEmpty()) - synopsis = typified(func->returnType(), true); + synopsis += typified(func->returnType(), true); synopsis += name; if (!func->isMacroWithoutParams()) { synopsis += QLatin1Char('('); if (!func->parameters().isEmpty()) { const Parameters ¶meters = func->parameters(); - for (int i = 0; i < parameters.count(); i++) { + for (int i = 0; i < parameters.count(); ++i) { if (i > 0) synopsis += ", "; QString name = parameters.at(i).name(); QString type = parameters.at(i).type(); QString value = parameters.at(i).defaultValue(); - QString paramName; - if (!name.isEmpty()) { - synopsis += typified(type, true); - paramName = name; - } else { - paramName = type; - } - if (style != Section::AllMembers || name.isEmpty()) - synopsis += "<@param>" + protect(paramName) + ""; + bool trailingSpace = style != Section::AllMembers && !name.isEmpty(); + synopsis += typified(type, trailingSpace); + if (style != Section::AllMembers && !name.isEmpty()) + synopsis += "<@param>" + protect(name) + ""; if (style != Section::AllMembers && !value.isEmpty()) synopsis += " = " + protect(value); } @@ -183,96 +165,64 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, if (func->isPureVirtual()) synopsis.append(" = 0"); if (func->isRef()) - synopsis.append(" &"); + synopsis.append(" &"); else if (func->isRefRef()) - synopsis.append(" &&"); - } - else if (style == Section::AllMembers) { + synopsis.append(" &&"); + } else if (style == Section::AllMembers) { if (!func->returnType().isEmpty() && func->returnType() != "void") synopsis += " : " + typified(func->returnType()); - } - else { + } else { if (func->isRef()) - synopsis.append(" &"); + synopsis.append(" &"); else if (func->isRefRef()) - synopsis.append(" &&"); - QStringList bracketed; - if (func->isStatic()) { - bracketed += "static"; - } else if (!func->isNonvirtual()) { - if (func->isFinal()) - bracketed += "final"; - if (func->isOverride()) - bracketed += "override"; - if (func->isPureVirtual()) - bracketed += "pure"; - bracketed += "virtual"; - } - - if (func->access() == Node::Protected) { - bracketed += "protected"; - } - else if (func->access() == Node::Private) { - bracketed += "private"; - } - - if (func->isSignal()) { - bracketed += "signal"; - } - else if (func->isSlot()) { - bracketed += "slot"; - } - if (!bracketed.isEmpty()) - extra += QLatin1Char('[') + bracketed.join(' ') + QStringLiteral("] "); + synopsis.append(" &&"); } break; case Node::Enum: enume = static_cast(node); - synopsis = "enum " + name; + synopsis = "enum "; + if (enume->isScoped()) + synopsis += "class "; + synopsis += name; if (style == Section::Summary) { synopsis += " { "; QStringList documentedItems = enume->doc().enumItemNames(); if (documentedItems.isEmpty()) { - foreach (const EnumItem &item, enume->items()) + const auto &enumItems = enume->items(); + for (const auto &item : enumItems) documentedItems << item.name(); } - QStringList omitItems = enume->doc().omitEnumItemNames(); - foreach (const QString &item, omitItems) + const QStringList omitItems = enume->doc().omitEnumItemNames(); + for (const auto &item : omitItems) documentedItems.removeAll(item); - if (documentedItems.size() <= MaxEnumValues) { - for (int i = 0; i < documentedItems.size(); ++i) { - if (i != 0) - synopsis += ", "; - synopsis += documentedItems.at(i); - } - } - else { - for (int i = 0; i < documentedItems.size(); ++i) { - if (i < MaxEnumValues-2 || i == documentedItems.size()-1) { - if (i != 0) - synopsis += ", "; - synopsis += documentedItems.at(i); - } - else if (i == MaxEnumValues - 1) { - synopsis += ", ..."; - } - } + if (documentedItems.size() > MaxEnumValues) { + // Take the last element and keep it safe, then elide the surplus. + const QString last = documentedItems.last(); + documentedItems = documentedItems.mid(0, MaxEnumValues - 1); + documentedItems += "…"; + documentedItems += last; } + synopsis += documentedItems.join(QLatin1String(", ")); + if (!documentedItems.isEmpty()) synopsis += QLatin1Char(' '); synopsis += QLatin1Char('}'); } break; - case Node::Typedef: - typedeff = static_cast(node); - if (typedeff->associatedEnum()) { - synopsis = "flags " + name; - } - else { - synopsis = "typedef " + name; + case Node::TypeAlias: + if (style == Section::Details) { + QString templateDecl = node->templateDecl(); + if (!templateDecl.isEmpty()) + synopsis += templateDecl + QLatin1Char(' '); } + synopsis += name; + break; + case Node::Typedef: + if (static_cast(node)->associatedEnum()) + synopsis = "flags "; + synopsis += name; break; case Node::Property: property = static_cast(node); @@ -282,51 +232,42 @@ QString CppCodeMarker::markedUpSynopsis(const Node *node, variable = static_cast(node); if (style == Section::AllMembers) { synopsis = name + " : " + typified(variable->dataType()); - } - else { - synopsis = typified(variable->leftType(), true) + - name + protect(variable->rightType()); + } else { + synopsis = typified(variable->leftType(), true) + name + protect(variable->rightType()); } break; default: synopsis = name; } - if (style == Section::Summary) { - if (node->isPreliminary()) - extra += "(preliminary) "; - else if (node->isDeprecated()) - extra += "(deprecated) "; - else if (node->isObsolete()) - extra += "(obsolete) "; - } - + QString extra = CodeMarker::extraSynopsis(node, style); if (!extra.isEmpty()) { extra.prepend("<@extra>"); extra.append(""); } + return extra + synopsis; } /*! */ -QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) +QString CppCodeMarker::markedUpQmlItem(const Node *node, bool summary) { QString name = taggedQmlNode(node); - if (summary) - name = linkTag(node,name); - else if (node->isQmlProperty() || node->isJsProperty()) { - const QmlPropertyNode* pn = static_cast(node); + if (summary) { + name = linkTag(node, name); + } else if (node->isQmlProperty() || node->isJsProperty()) { + const QmlPropertyNode *pn = static_cast(node); if (pn->isAttached()) name.prepend(pn->element() + QLatin1Char('.')); } name = "<@name>" + name + ""; QString synopsis; if (node->isQmlProperty() || node->isJsProperty()) { - const QmlPropertyNode* pn = static_cast(node); + const QmlPropertyNode *pn = static_cast(node); synopsis = name + " : " + typified(pn->dataType()); } else if (node->isFunction(Node::QML) || node->isFunction(Node::JS)) { - const FunctionNode* func = static_cast(node); + const FunctionNode *func = static_cast(node); if (!func->returnType().isEmpty()) synopsis = typified(func->returnType(), true) + name; else @@ -334,7 +275,7 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) synopsis += QLatin1Char('('); if (!func->parameters().isEmpty()) { const Parameters ¶meters = func->parameters(); - for (int i = 0; i < parameters.count(); i++) { + for (int i = 0; i < parameters.count(); ++i) { if (i > 0) synopsis += ", "; QString name = parameters.at(i).name(); @@ -350,8 +291,9 @@ QString CppCodeMarker::markedUpQmlItem(const Node* node, bool summary) } } synopsis += QLatin1Char(')'); - } else + } else { synopsis = name; + } QString extra; if (summary) { @@ -380,20 +322,18 @@ QString CppCodeMarker::markedUpName(const Node *node) QString CppCodeMarker::markedUpFullName(const Node *node, const Node *relative) { - if (node->name().isEmpty()) { + if (node->name().isEmpty()) return "global"; + + QString fullName; + for (;;) { + fullName.prepend(markedUpName(node)); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + fullName.prepend("<@op>::"); + node = node->parent(); } - else { - QString fullName; - for (;;) { - fullName.prepend(markedUpName(node)); - if (node->parent() == relative || node->parent()->name().isEmpty()) - break; - fullName.prepend("<@op>::"); - node = node->parent(); - } - return fullName; - } + return fullName; } QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, const Node *relative) @@ -402,39 +342,36 @@ QString CppCodeMarker::markedUpEnumValue(const QString &enumValue, const Node *r return enumValue; const Node *node = relative->parent(); - QString fullName; - while (node->parent()) { - fullName.prepend(markedUpName(node)); + QStringList parts; + while (!node->isHeader() && node->parent()) { + parts.prepend(markedUpName(node)); if (node->parent() == relative || node->parent()->name().isEmpty()) break; - fullName.prepend("<@op>::"); node = node->parent(); } - if (!fullName.isEmpty()) - fullName.append("<@op>::"); - fullName.append(enumValue); - return fullName; + if (static_cast(relative)->isScoped()) + parts.append(relative->name()); + + parts.append(enumValue); + return parts.join(QLatin1String("<@op>::")); } -QString CppCodeMarker::markedUpIncludes(const QStringList& includes) +QString CppCodeMarker::markedUpIncludes(const QStringList &includes) { QString code; - QStringList::ConstIterator inc = includes.constBegin(); - while (inc != includes.constEnd()) { - code += "<@preprocessor>#include <<@headerfile>" + *inc + ">\n"; - ++inc; - } + for (const auto &include : includes) + code += "<@preprocessor>#include <<@headerfile>" + include + + ">\n"; return code; } -QString CppCodeMarker::functionBeginRegExp(const QString& funcName) +QString CppCodeMarker::functionBeginRegExp(const QString &funcName) { - return QLatin1Char('^') + QRegExp::escape(funcName) + QLatin1Char('$'); - + return QLatin1Char('^') + QRegularExpression::escape(funcName) + QLatin1Char('$'); } -QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) +QString CppCodeMarker::functionEndRegExp(const QString & /* funcName */) { return "^\\}$"; } @@ -452,8 +389,7 @@ QString CppCodeMarker::functionEndRegExp(const QString& /* funcName */) @type */ -QString CppCodeMarker::addMarkUp(const QString &in, - const Node * /* relative */, +QString CppCodeMarker::addMarkUp(const QString &in, const Node * /* relative */, const Location & /* location */) { static QSet types; @@ -463,26 +399,42 @@ QString CppCodeMarker::addMarkUp(const QString &in, // initialize statics Q_ASSERT(keywords.isEmpty()); static const QString typeTable[] = { - QLatin1String("bool"), QLatin1String("char"), QLatin1String("double"), QLatin1String("float"), QLatin1String("int"), QLatin1String("long"), QLatin1String("short"), - QLatin1String("signed"), QLatin1String("unsigned"), QLatin1String("uint"), QLatin1String("ulong"), QLatin1String("ushort"), QLatin1String("uchar"), QLatin1String("void"), - QLatin1String("qlonglong"), QLatin1String("qulonglong"), - QLatin1String("qint"), QLatin1String("qint8"), QLatin1String("qint16"), QLatin1String("qint32"), QLatin1String("qint64"), - QLatin1String("quint"), QLatin1String("quint8"), QLatin1String("quint16"), QLatin1String("quint32"), QLatin1String("quint64"), - QLatin1String("qreal"), QLatin1String("cond") + QLatin1String("bool"), QLatin1String("char"), QLatin1String("double"), + QLatin1String("float"), QLatin1String("int"), QLatin1String("long"), + QLatin1String("short"), QLatin1String("signed"), QLatin1String("unsigned"), + QLatin1String("uint"), QLatin1String("ulong"), QLatin1String("ushort"), + QLatin1String("uchar"), QLatin1String("void"), QLatin1String("qlonglong"), + QLatin1String("qulonglong"), QLatin1String("qint"), QLatin1String("qint8"), + QLatin1String("qint16"), QLatin1String("qint32"), QLatin1String("qint64"), + QLatin1String("quint"), QLatin1String("quint8"), QLatin1String("quint16"), + QLatin1String("quint32"), QLatin1String("quint64"), QLatin1String("qreal"), + QLatin1String("cond") }; static const QString keywordTable[] = { - QLatin1String("and"), QLatin1String("and_eq"), QLatin1String("asm"), QLatin1String("auto"), QLatin1String("bitand"), QLatin1String("bitor"), QLatin1String("break"), - QLatin1String("case"), QLatin1String("catch"), QLatin1String("class"), QLatin1String("compl"), QLatin1String("const"), QLatin1String("const_cast"), - QLatin1String("continue"), QLatin1String("default"), QLatin1String("delete"), QLatin1String("do"), QLatin1String("dynamic_cast"), QLatin1String("else"), - QLatin1String("enum"), QLatin1String("explicit"), QLatin1String("export"), QLatin1String("extern"), QLatin1String("false"), QLatin1String("for"), QLatin1String("friend"), - QLatin1String("goto"), QLatin1String("if"), QLatin1String("include"), QLatin1String("inline"), QLatin1String("monitor"), QLatin1String("mutable"), QLatin1String("namespace"), - QLatin1String("new"), QLatin1String("not"), QLatin1String("not_eq"), QLatin1String("operator"), QLatin1String("or"), QLatin1String("or_eq"), QLatin1String("private"), QLatin1String("protected"), - QLatin1String("public"), QLatin1String("register"), QLatin1String("reinterpret_cast"), QLatin1String("return"), QLatin1String("sizeof"), - QLatin1String("static"), QLatin1String("static_cast"), QLatin1String("struct"), QLatin1String("switch"), QLatin1String("template"), QLatin1String("this"), - QLatin1String("throw"), QLatin1String("true"), QLatin1String("try"), QLatin1String("typedef"), QLatin1String("typeid"), QLatin1String("typename"), QLatin1String("union"), - QLatin1String("using"), QLatin1String("virtual"), QLatin1String("volatile"), QLatin1String("wchar_t"), QLatin1String("while"), QLatin1String("xor"), - QLatin1String("xor_eq"), QLatin1String("synchronized"), + QLatin1String("and"), QLatin1String("and_eq"), QLatin1String("asm"), + QLatin1String("auto"), QLatin1String("bitand"), QLatin1String("bitor"), + QLatin1String("break"), QLatin1String("case"), QLatin1String("catch"), + QLatin1String("class"), QLatin1String("compl"), QLatin1String("const"), + QLatin1String("const_cast"), QLatin1String("continue"), QLatin1String("default"), + QLatin1String("delete"), QLatin1String("do"), QLatin1String("dynamic_cast"), + QLatin1String("else"), QLatin1String("enum"), QLatin1String("explicit"), + QLatin1String("export"), QLatin1String("extern"), QLatin1String("false"), + QLatin1String("for"), QLatin1String("friend"), QLatin1String("goto"), + QLatin1String("if"), QLatin1String("include"), QLatin1String("inline"), + QLatin1String("monitor"), QLatin1String("mutable"), QLatin1String("namespace"), + QLatin1String("new"), QLatin1String("not"), QLatin1String("not_eq"), + QLatin1String("operator"), QLatin1String("or"), QLatin1String("or_eq"), + QLatin1String("private"), QLatin1String("protected"), QLatin1String("public"), + QLatin1String("register"), QLatin1String("reinterpret_cast"), QLatin1String("return"), + QLatin1String("sizeof"), QLatin1String("static"), QLatin1String("static_cast"), + QLatin1String("struct"), QLatin1String("switch"), QLatin1String("template"), + QLatin1String("this"), QLatin1String("throw"), QLatin1String("true"), + QLatin1String("try"), QLatin1String("typedef"), QLatin1String("typeid"), + QLatin1String("typename"), QLatin1String("union"), QLatin1String("using"), + QLatin1String("virtual"), QLatin1String("volatile"), QLatin1String("wchar_t"), + QLatin1String("while"), QLatin1String("xor"), QLatin1String("xor_eq"), + QLatin1String("synchronized"), // Qt specific QLatin1String("signals"), QLatin1String("slots"), QLatin1String("emit") }; @@ -495,25 +447,30 @@ QString CppCodeMarker::addMarkUp(const QString &in, for (int j = sizeof(keywordTable) / sizeof(QString) - 1; j; --j) keywords.insert(keywordTable[j]); } -#define readChar() \ - ch = (i < (int)code.length()) ? code[i++].cell() : EOF QString code = in; QString out; - QStringRef text; + QStringView text; int braceDepth = 0; int parenDepth = 0; int i = 0; int start = 0; int finish = 0; QChar ch; - QRegExp classRegExp("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)"); - QRegExp functionRegExp("q([A-Z][a-z]+)+"); - QRegExp findFunctionRegExp(QStringLiteral("^\\s*\\(")); + QRegularExpression classRegExp(QRegularExpression::anchoredPattern("Qt?(?:[A-Z3]+[a-z][A-Za-z]*|t)")); + QRegularExpression functionRegExp(QRegularExpression::anchoredPattern("q([A-Z][a-z]+)+")); + QRegularExpression findFunctionRegExp(QStringLiteral("^\\s*\\(")); + bool atEOF = false; + + auto readChar = [&]() { + if (i < code.length()) + ch = code[i++]; + else + atEOF = true; + }; readChar(); - - while (ch != QChar(EOF)) { + while (!atEOF) { QString tag; bool target = false; @@ -523,11 +480,11 @@ QString CppCodeMarker::addMarkUp(const QString &in, ident += ch; finish = i; readChar(); - } while (ch.isLetterOrNumber() || ch == '_'); + } while (!atEOF && (ch.isLetterOrNumber() || ch == '_')); - if (classRegExp.exactMatch(ident)) { + if (classRegExp.match(ident).hasMatch()) { tag = QStringLiteral("type"); - } else if (functionRegExp.exactMatch(ident)) { + } else if (functionRegExp.match(ident).hasMatch()) { tag = QStringLiteral("func"); target = true; } else if (types.contains(ident)) { @@ -543,7 +500,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, do { finish = i; readChar(); - } while (ch.isLetterOrNumber() || ch == '.'); + } while (!atEOF && (ch.isLetterOrNumber() || ch == '.')); tag = QStringLiteral("number"); } else { switch (ch.unicode()) { @@ -572,7 +529,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, finish = i; readChar(); - while (ch != QChar(EOF) && ch != '"') { + while (!atEOF && ch != '"') { if (ch == '\\') readChar(); readChar(); @@ -584,7 +541,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, case '#': finish = i; readChar(); - while (ch != QChar(EOF) && ch != '\n') { + while (!atEOF && ch != '\n') { if (ch == '\\') readChar(); finish = i; @@ -596,7 +553,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, finish = i; readChar(); - while (ch != QChar(EOF) && ch != '\'') { + while (!atEOF && ch != '\'') { if (ch == '\\') readChar(); readChar(); @@ -608,17 +565,17 @@ QString CppCodeMarker::addMarkUp(const QString &in, case '(': finish = i; readChar(); - parenDepth++; + ++parenDepth; break; case ')': finish = i; readChar(); - parenDepth--; + --parenDepth; break; case ':': finish = i; readChar(); - if (ch == ':') { + if (!atEOF && ch == ':') { finish = i; readChar(); tag = QStringLiteral("op"); @@ -627,11 +584,11 @@ QString CppCodeMarker::addMarkUp(const QString &in, case '/': finish = i; readChar(); - if (ch == '/') { + if (!atEOF && ch == '/') { do { finish = i; readChar(); - } while (ch != QChar(EOF) && ch != '\n'); + } while (!atEOF && ch != '\n'); tag = QStringLiteral("comment"); } else if (ch == '*') { bool metAster = false; @@ -641,9 +598,8 @@ QString CppCodeMarker::addMarkUp(const QString &in, readChar(); while (!metAsterSlash) { - if (ch == QChar(EOF)) + if (atEOF) break; - if (ch == '*') metAster = true; else if (metAster && ch == '/') @@ -674,7 +630,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, } } - text = code.midRef(start, finish - start); + text = QStringView{code}.mid(start, finish - start); start = finish; if (!tag.isEmpty()) { @@ -698,7 +654,7 @@ QString CppCodeMarker::addMarkUp(const QString &in, } if (start < code.length()) { - appendProtectedString(&out, code.midRef(start)); + appendProtectedString(&out, QStringView{code}.mid(start)); } return out; diff --git a/src/qdoc/cppcodemarker.h b/src/qdoc/cppcodemarker.h index 23a54ca798..6a7515134a 100644 --- a/src/qdoc/cppcodemarker.h +++ b/src/qdoc/cppcodemarker.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -35,28 +35,27 @@ QT_BEGIN_NAMESPACE class CppCodeMarker : public CodeMarker { - Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeMarker) - public: - CppCodeMarker(); - ~CppCodeMarker(); + CppCodeMarker() = default; + ~CppCodeMarker() override = default; - bool recognizeCode(const QString& code) override; - bool recognizeExtension(const QString& ext) override; - bool recognizeLanguage(const QString& lang) override; + bool recognizeCode(const QString &code) override; + bool recognizeExtension(const QString &ext) override; + bool recognizeLanguage(const QString &lang) override; Atom::AtomType atomType() const override; - QString markedUpCode(const QString& code, const Node *relative, const Location &location) override; + QString markedUpCode(const QString &code, const Node *relative, + const Location &location) override; QString markedUpSynopsis(const Node *node, const Node *relative, Section::Style style) override; QString markedUpQmlItem(const Node *node, bool summary) override; QString markedUpName(const Node *node) override; QString markedUpFullName(const Node *node, const Node *relative) override; QString markedUpEnumValue(const QString &enumValue, const Node *relative) override; - QString markedUpIncludes(const QStringList& includes) override; - QString functionBeginRegExp(const QString& funcName) override; - QString functionEndRegExp(const QString& funcName) override; + QString markedUpIncludes(const QStringList &includes) override; + QString functionBeginRegExp(const QString &funcName) override; + QString functionEndRegExp(const QString &funcName) override; private: - QString addMarkUp(const QString& protectedCode, const Node *relative, const Location &location); + QString addMarkUp(const QString &protectedCode, const Node *relative, const Location &location); }; QT_END_NAMESPACE diff --git a/src/qdoc/cppcodeparser.cpp b/src/qdoc/cppcodeparser.cpp index 6d5ec5af03..c3f673b8d8 100644 --- a/src/qdoc/cppcodeparser.cpp +++ b/src/qdoc/cppcodeparser.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,27 +26,34 @@ ** ****************************************************************************/ -/* - cppcodeparser.cpp -*/ +#include "cppcodeparser.h" -#include -#include -#include +#include "access.h" +#include "classnode.h" +#include "collectionnode.h" #include "config.h" -#include "cppcodeparser.h" -#include "qdocdatabase.h" -#include +#include "examplenode.h" +#include "externalpagenode.h" +#include "functionnode.h" #include "generator.h" +#include "headernode.h" +#include "namespacenode.h" +#include "qdocdatabase.h" +#include "qmltypenode.h" +#include "qmlpropertynode.h" +#include "sharedcommentnode.h" + +#include +#include + +#include QT_BEGIN_NAMESPACE /* qmake ignore Q_OBJECT */ -QStringList CppCodeParser::exampleFiles; -QStringList CppCodeParser::exampleDirs; -QSet CppCodeParser::excludeDirs; -QSet CppCodeParser::excludeFiles; +QSet CppCodeParser::m_excludeDirs; +QSet CppCodeParser::m_excludeFiles; static QSet topicCommands_; static QSet metaCommands_; @@ -58,56 +65,26 @@ static QSet metaCommands_; CppCodeParser::CppCodeParser() { if (topicCommands_.isEmpty()) { - topicCommands_ << COMMAND_CLASS - << COMMAND_DITAMAP - << COMMAND_DONTDOCUMENT - << COMMAND_ENUM - << COMMAND_EXAMPLE - << COMMAND_EXTERNALPAGE - << COMMAND_FN - << COMMAND_GROUP - << COMMAND_HEADERFILE - << COMMAND_MACRO - << COMMAND_MODULE - << COMMAND_NAMESPACE - << COMMAND_PAGE - << COMMAND_PROPERTY - << COMMAND_TYPEALIAS - << COMMAND_TYPEDEF - << COMMAND_VARIABLE - << COMMAND_QMLTYPE - << COMMAND_QMLPROPERTY - << COMMAND_QMLPROPERTYGROUP // mws 13/03/2019 - << COMMAND_QMLATTACHEDPROPERTY - << COMMAND_QMLSIGNAL - << COMMAND_QMLATTACHEDSIGNAL - << COMMAND_QMLMETHOD - << COMMAND_QMLATTACHEDMETHOD - << COMMAND_QMLBASICTYPE - << COMMAND_QMLMODULE - << COMMAND_JSTYPE - << COMMAND_JSPROPERTY - << COMMAND_JSPROPERTYGROUP // mws 13/03/2019 - << COMMAND_JSATTACHEDPROPERTY - << COMMAND_JSSIGNAL - << COMMAND_JSATTACHEDSIGNAL - << COMMAND_JSMETHOD - << COMMAND_JSATTACHEDMETHOD - << COMMAND_JSBASICTYPE - << COMMAND_JSMODULE - << COMMAND_STRUCT - << COMMAND_UNION; + topicCommands_ << COMMAND_CLASS << COMMAND_DONTDOCUMENT << COMMAND_ENUM << COMMAND_EXAMPLE + << COMMAND_EXTERNALPAGE << COMMAND_FN << COMMAND_GROUP << COMMAND_HEADERFILE + << COMMAND_MACRO << COMMAND_MODULE << COMMAND_NAMESPACE << COMMAND_PAGE + << COMMAND_PROPERTY << COMMAND_TYPEALIAS << COMMAND_TYPEDEF + << COMMAND_VARIABLE << COMMAND_QMLTYPE << COMMAND_QMLPROPERTY + << COMMAND_QMLPROPERTYGROUP // mws 13/03/2019 + << COMMAND_QMLATTACHEDPROPERTY << COMMAND_QMLSIGNAL + << COMMAND_QMLATTACHEDSIGNAL << COMMAND_QMLMETHOD + << COMMAND_QMLATTACHEDMETHOD << COMMAND_QMLBASICTYPE << COMMAND_QMLMODULE + << COMMAND_JSTYPE << COMMAND_JSPROPERTY + << COMMAND_JSPROPERTYGROUP // mws 13/03/2019 + << COMMAND_JSATTACHEDPROPERTY << COMMAND_JSSIGNAL << COMMAND_JSATTACHEDSIGNAL + << COMMAND_JSMETHOD << COMMAND_JSATTACHEDMETHOD << COMMAND_JSBASICTYPE + << COMMAND_JSMODULE << COMMAND_STRUCT << COMMAND_UNION; } if (metaCommands_.isEmpty()) { metaCommands_ = commonMetaCommands(); - metaCommands_ << COMMAND_CONTENTSPAGE - << COMMAND_INHEADERFILE - << COMMAND_NEXTPAGE - << COMMAND_OVERLOAD - << COMMAND_PREVIOUSPAGE - << COMMAND_QMLINSTANTIATES - << COMMAND_REIMP - << COMMAND_RELATES; + metaCommands_ << COMMAND_INHEADERFILE << COMMAND_NEXTPAGE + << COMMAND_OVERLOAD << COMMAND_PREVIOUSPAGE << COMMAND_QMLINSTANTIATES + << COMMAND_REIMP << COMMAND_RELATES; } } @@ -116,58 +93,56 @@ CppCodeParser::CppCodeParser() for identifying important nodes. And it initializes some filters for identifying and excluding certain kinds of files. */ -void CppCodeParser::initializeParser(const Config &config) +void CppCodeParser::initializeParser() { - CodeParser::initializeParser(config); + CodeParser::initializeParser(); /* All these can appear in a C++ namespace. Don't add anything that can't be in a C++ namespace. */ - nodeTypeMap_.insert(COMMAND_NAMESPACE, Node::Namespace); - nodeTypeMap_.insert(COMMAND_CLASS, Node::Class); - nodeTypeMap_.insert(COMMAND_STRUCT, Node::Struct); - nodeTypeMap_.insert(COMMAND_UNION, Node::Union); - nodeTypeMap_.insert(COMMAND_ENUM, Node::Enum); - nodeTypeMap_.insert(COMMAND_TYPEALIAS, Node::Typedef); - nodeTypeMap_.insert(COMMAND_TYPEDEF, Node::Typedef); - nodeTypeMap_.insert(COMMAND_PROPERTY, Node::Property); - nodeTypeMap_.insert(COMMAND_VARIABLE, Node::Variable); - - nodeTypeTestFuncMap_.insert(COMMAND_NAMESPACE, &Node::isNamespace); - nodeTypeTestFuncMap_.insert(COMMAND_CLASS, &Node::isClassNode); - nodeTypeTestFuncMap_.insert(COMMAND_STRUCT, &Node::isStruct); - nodeTypeTestFuncMap_.insert(COMMAND_UNION, &Node::isUnion); - nodeTypeTestFuncMap_.insert(COMMAND_ENUM, &Node::isEnumType); - nodeTypeTestFuncMap_.insert(COMMAND_TYPEALIAS, &Node::isTypedef); - nodeTypeTestFuncMap_.insert(COMMAND_TYPEDEF, &Node::isTypedef); - nodeTypeTestFuncMap_.insert(COMMAND_PROPERTY, &Node::isProperty); - nodeTypeTestFuncMap_.insert(COMMAND_VARIABLE, &Node::isVariable); - - - exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES); - exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); - QStringList exampleFilePatterns = config.getStringList( - CONFIG_EXAMPLES + Config::dot + CONFIG_FILEEXTENSIONS); + m_nodeTypeMap.insert(COMMAND_NAMESPACE, Node::Namespace); + m_nodeTypeMap.insert(COMMAND_CLASS, Node::Class); + m_nodeTypeMap.insert(COMMAND_STRUCT, Node::Struct); + m_nodeTypeMap.insert(COMMAND_UNION, Node::Union); + m_nodeTypeMap.insert(COMMAND_ENUM, Node::Enum); + m_nodeTypeMap.insert(COMMAND_TYPEALIAS, Node::TypeAlias); + m_nodeTypeMap.insert(COMMAND_TYPEDEF, Node::Typedef); + m_nodeTypeMap.insert(COMMAND_PROPERTY, Node::Property); + m_nodeTypeMap.insert(COMMAND_VARIABLE, Node::Variable); + + m_nodeTypeTestFuncMap.insert(COMMAND_NAMESPACE, &Node::isNamespace); + m_nodeTypeTestFuncMap.insert(COMMAND_CLASS, &Node::isClassNode); + m_nodeTypeTestFuncMap.insert(COMMAND_STRUCT, &Node::isStruct); + m_nodeTypeTestFuncMap.insert(COMMAND_UNION, &Node::isUnion); + m_nodeTypeTestFuncMap.insert(COMMAND_ENUM, &Node::isEnumType); + m_nodeTypeTestFuncMap.insert(COMMAND_TYPEALIAS, &Node::isTypeAlias); + m_nodeTypeTestFuncMap.insert(COMMAND_TYPEDEF, &Node::isTypedef); + m_nodeTypeTestFuncMap.insert(COMMAND_PROPERTY, &Node::isProperty); + m_nodeTypeTestFuncMap.insert(COMMAND_VARIABLE, &Node::isVariable); + + Config &config = Config::instance(); + QStringList exampleFilePatterns = + config.getStringList(CONFIG_EXAMPLES + Config::dot + CONFIG_FILEEXTENSIONS); // Used for excluding dirs and files from the list of example files const auto &excludeDirsList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS); - excludeDirs = QSet(excludeDirsList.cbegin(), excludeDirsList.cend()); + m_excludeDirs = QSet(excludeDirsList.cbegin(), excludeDirsList.cend()); const auto &excludeFilesList = config.getCanonicalPathList(CONFIG_EXCLUDEDIRS); - excludeFiles = QSet(excludeFilesList.cbegin(), excludeFilesList.cend()); + m_excludeFiles = QSet(excludeFilesList.cbegin(), excludeFilesList.cend()); if (!exampleFilePatterns.isEmpty()) - exampleNameFilter = exampleFilePatterns.join(' '); + m_exampleNameFilter = exampleFilePatterns.join(' '); else - exampleNameFilter = "*.cpp *.h *.js *.xq *.svg *.xml *.dita *.ui"; + m_exampleNameFilter = "*.cpp *.h *.js *.xq *.svg *.xml *.ui"; - QStringList exampleImagePatterns = config.getStringList( - CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS); + QStringList exampleImagePatterns = + config.getStringList(CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS); if (!exampleImagePatterns.isEmpty()) - exampleImageFilter = exampleImagePatterns.join(' '); + m_exampleImageFilter = exampleImagePatterns.join(' '); else - exampleImageFilter = "*.png"; + m_exampleImageFilter = "*.png"; } /*! @@ -176,10 +151,10 @@ void CppCodeParser::initializeParser(const Config &config) */ void CppCodeParser::terminateParser() { - nodeTypeMap_.clear(); - nodeTypeTestFuncMap_.clear(); - excludeDirs.clear(); - excludeFiles.clear(); + m_nodeTypeMap.clear(); + m_nodeTypeTestFuncMap.clear(); + m_excludeDirs.clear(); + m_excludeFiles.clear(); CodeParser::terminateParser(); } @@ -203,7 +178,7 @@ QStringList CppCodeParser::sourceFileNameFilter() /*! Returns the set of strings reopresenting the topic commands. */ -const QSet& CppCodeParser::topicCommands() +const QSet &CppCodeParser::topicCommands() { return topicCommands_; } @@ -211,15 +186,13 @@ const QSet& CppCodeParser::topicCommands() /*! Process the topic \a command found in the \a doc with argument \a arg. */ -Node* CppCodeParser::processTopicCommand(const Doc& doc, - const QString& command, - const ArgLocPair& arg) +Node *CppCodeParser::processTopicCommand(const Doc &doc, const QString &command, + const ArgLocPair &arg) { ExtraFuncData extra; if (command == COMMAND_FN) { Q_UNREACHABLE(); - } - else if (nodeTypeMap_.contains(command)) { + } else if (m_nodeTypeMap.contains(command)) { /* We should only get in here if the command refers to something that can appear in a C++ namespace, @@ -228,7 +201,7 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, this way to allow the writer to refer to the entity without including the namespace qualifier. */ - Node::NodeType type = nodeTypeMap_[command]; + Node::NodeType type = m_nodeTypeMap[command]; QStringList words = arg.first.split(QLatin1Char(' ')); QStringList path; int idx = 0; @@ -238,28 +211,40 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, idx = words.size() - 1; path = words[idx].split("::"); - node = qdb_->findNodeInOpenNamespace(path, nodeTypeTestFuncMap_[command]); + node = qdb_->findNodeInOpenNamespace(path, m_nodeTypeTestFuncMap[command]); if (node == nullptr) - node = qdb_->findNodeByNameAndType(path, nodeTypeTestFuncMap_[command]); + node = qdb_->findNodeByNameAndType(path, m_nodeTypeTestFuncMap[command]); + // Allow representing a type alias as a class + if (node == nullptr && command == COMMAND_CLASS) { + node = qdb_->findNodeByNameAndType(path, &Node::isTypeAlias); + if (node) { + auto access = node->access(); + auto loc = node->location(); + auto templateDecl = node->templateDecl(); + node = new ClassNode(Node::Class, node->parent(), node->name()); + node->setAccess(access); + node->setLocation(loc); + node->setTemplateDecl(templateDecl); + } + } if (node == nullptr) { if (isWorthWarningAbout(doc)) { - doc.location().warning(tr("Cannot find '%1' specified with '\\%2' in any header file") - .arg(arg.first).arg(command)); + doc.location().warning( + QStringLiteral("Cannot find '%1' specified with '\\%2' in any header file") + .arg(arg.first) + .arg(command)); } - } - else if (node->isAggregate()) { + } else if (node->isAggregate()) { if (type == Node::Namespace) { - NamespaceNode* ns = static_cast(node); + auto *ns = static_cast(node); ns->markSeen(); ns->setWhereDocumented(ns->tree()->camelCaseModuleName()); } /* This treats a class as a namespace. */ - if ((type == Node::Class) || - (type == Node::Namespace) || - (type == Node::Struct) || - (type == Node::Union)) { + if ((type == Node::Class) || (type == Node::Namespace) || (type == Node::Struct) + || (type == Node::Union)) { if (path.size() > 1) { path.pop_back(); QString ns = path.join(QLatin1String("::")); @@ -268,54 +253,46 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, } } return node; - } - else if (command == COMMAND_EXAMPLE) { + } else if (command == COMMAND_EXAMPLE) { if (Config::generateExamples) { - ExampleNode* en = new ExampleNode(qdb_->primaryTreeRoot(), arg.first); + auto *en = new ExampleNode(qdb_->primaryTreeRoot(), arg.first); en->setLocation(doc.startLocation()); setExampleFileLists(en); return en; } - } - else if (command == COMMAND_EXTERNALPAGE) { - ExternalPageNode* epn = new ExternalPageNode(qdb_->primaryTreeRoot(), arg.first); + } else if (command == COMMAND_EXTERNALPAGE) { + auto *epn = new ExternalPageNode(qdb_->primaryTreeRoot(), arg.first); epn->setLocation(doc.startLocation()); return epn; - } - else if (command == COMMAND_HEADERFILE) { - HeaderNode* hn = new HeaderNode(qdb_->primaryTreeRoot(), arg.first); + } else if (command == COMMAND_HEADERFILE) { + auto *hn = new HeaderNode(qdb_->primaryTreeRoot(), arg.first); hn->setLocation(doc.startLocation()); return hn; - } - else if (command == COMMAND_GROUP) { - CollectionNode* cn = qdb_->addGroup(arg.first); + } else if (command == COMMAND_GROUP) { + CollectionNode *cn = qdb_->addGroup(arg.first); cn->setLocation(doc.startLocation()); cn->markSeen(); return cn; - } - else if (command == COMMAND_MODULE) { - CollectionNode* cn = qdb_->addModule(arg.first); + } else if (command == COMMAND_MODULE) { + CollectionNode *cn = qdb_->addModule(arg.first); cn->setLocation(doc.startLocation()); cn->markSeen(); return cn; - } - else if (command == COMMAND_QMLMODULE) { + } else if (command == COMMAND_QMLMODULE) { QStringList blankSplit = arg.first.split(QLatin1Char(' ')); - CollectionNode* cn = qdb_->addQmlModule(blankSplit[0]); + CollectionNode *cn = qdb_->addQmlModule(blankSplit[0]); cn->setLogicalModuleInfo(blankSplit); cn->setLocation(doc.startLocation()); cn->markSeen(); return cn; - } - else if (command == COMMAND_JSMODULE) { + } else if (command == COMMAND_JSMODULE) { QStringList blankSplit = arg.first.split(QLatin1Char(' ')); - CollectionNode* cn = qdb_->addJsModule(blankSplit[0]); + CollectionNode *cn = qdb_->addJsModule(blankSplit[0]); cn->setLogicalModuleInfo(blankSplit); cn->setLocation(doc.startLocation()); cn->markSeen(); return cn; - } - else if (command == COMMAND_PAGE) { + } else if (command == COMMAND_PAGE) { Node::PageType ptype = Node::ArticlePage; QStringList args = arg.first.split(QLatin1Char(' ')); if (args.size() > 1) { @@ -335,14 +312,14 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, else if (t == "attribution") ptype = Node::AttributionPage; } - PageNode* pn = new PageNode(qdb_->primaryTreeRoot(), args[0], ptype); + auto *pn = new PageNode(qdb_->primaryTreeRoot(), args[0], ptype); pn->setLocation(doc.startLocation()); return pn; } else if (command == COMMAND_QMLTYPE) { QmlTypeNode *qcn = nullptr; Node *candidate = qdb_->primaryTreeRoot()->findChildNode(arg.first, Node::QML); if (candidate != nullptr && candidate->isQmlType()) - qcn = static_cast(candidate); + qcn = static_cast(candidate); else qcn = new QmlTypeNode(qdb_->primaryTreeRoot(), arg.first); qcn->setLocation(doc.startLocation()); @@ -351,28 +328,23 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, QmlTypeNode *qcn = nullptr; Node *candidate = qdb_->primaryTreeRoot()->findChildNode(arg.first, Node::JS); if (candidate != nullptr && candidate->isJsType()) - qcn = static_cast(candidate); + qcn = static_cast(candidate); else qcn = new QmlTypeNode(qdb_->primaryTreeRoot(), arg.first, Node::JsType); qcn->setLocation(doc.startLocation()); return qcn; } else if (command == COMMAND_QMLBASICTYPE) { - QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first); - n->setLocation(doc.startLocation()); - return n; + auto *node = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first); + node->setLocation(doc.startLocation()); + return node; } else if (command == COMMAND_JSBASICTYPE) { - QmlBasicTypeNode* n = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first, Node::JsBasicType); - n->setLocation(doc.startLocation()); - return n; - } - else if ((command == COMMAND_QMLSIGNAL) || - (command == COMMAND_QMLMETHOD) || - (command == COMMAND_QMLATTACHEDSIGNAL) || - (command == COMMAND_QMLATTACHEDMETHOD) || - (command == COMMAND_JSSIGNAL) || - (command == COMMAND_JSMETHOD) || - (command == COMMAND_JSATTACHEDSIGNAL) || - (command == COMMAND_JSATTACHEDMETHOD)) { + auto *node = new QmlBasicTypeNode(qdb_->primaryTreeRoot(), arg.first, Node::JsBasicType); + node->setLocation(doc.startLocation()); + return node; + } else if ((command == COMMAND_QMLSIGNAL) || (command == COMMAND_QMLMETHOD) + || (command == COMMAND_QMLATTACHEDSIGNAL) || (command == COMMAND_QMLATTACHEDMETHOD) + || (command == COMMAND_JSSIGNAL) || (command == COMMAND_JSMETHOD) + || (command == COMMAND_JSATTACHEDSIGNAL) || (command == COMMAND_JSATTACHEDMETHOD)) { Q_UNREACHABLE(); } return nullptr; @@ -397,11 +369,8 @@ Node* CppCodeParser::processTopicCommand(const Doc& doc, \note The two QML types \e{Component} and \e{QtObject} never have a module qualifier. */ -bool CppCodeParser::splitQmlPropertyArg(const QString& arg, - QString& type, - QString& module, - QString& qmlTypeName, - QString& name, +bool CppCodeParser::splitQmlPropertyArg(const QString &arg, QString &type, QString &module, + QString &qmlTypeName, QString &name, const Location &location) { QStringList blankSplit = arg.split(QLatin1Char(' ')); @@ -420,12 +389,10 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, name = colonSplit[1]; return true; } - QString msg = "Unrecognizable QML module/component qualifier for " + arg; - location.warning(tr(msg.toLatin1().data())); - } - else { - QString msg = "Missing property type for " + arg; - location.warning(tr(msg.toLatin1().data())); + location.warning( + QStringLiteral("Unrecognizable QML module/component qualifier for %1").arg(arg)); + } else { + location.warning(QStringLiteral("Missing property type for %1").arg(arg)); } return false; } @@ -434,7 +401,7 @@ bool CppCodeParser::splitQmlPropertyArg(const QString& arg, */ void CppCodeParser::processQmlProperties(const Doc &doc, NodeList &nodes, DocList &docs) { - const TopicList& topics = doc.topicsUsed(); + const TopicList &topics = doc.topicsUsed(); if (topics.isEmpty()) return; @@ -454,61 +421,69 @@ void CppCodeParser::processQmlProperties(const Doc &doc, NodeList &nodes, DocLis group = property.left(i); } - QmlTypeNode* qmlType = qdb_->findQmlType(module, qmlTypeName); + NodeList sharedNodes; + QmlTypeNode *qmlType = qdb_->findQmlType(module, qmlTypeName); if (qmlType == nullptr) qmlType = new QmlTypeNode(qdb_->primaryTreeRoot(), qmlTypeName); - SharedCommentNode* scn = nullptr; - if (topics.size() > 1) { - scn = new SharedCommentNode(qmlType, topics.size(), group); - scn->setLocation(doc.startLocation()); - if (jsProps) - scn->setGenus(Node::JS); - else - scn->setGenus(Node::QML); - nodes.append(scn); - docs.append(doc); - } - - for (int i=0; ifindQmlType(module, qmlTypeName)) { - QString msg = tr("All properties in a group must belong to the same type: '%1'").arg(arg); - doc.startLocation().warning(msg); + doc.startLocation().warning( + QStringLiteral( + "All properties in a group must belong to the same type: '%1'") + .arg(arg)); continue; } - if (qmlType->hasQmlProperty(property, attached) != nullptr) { - QString msg = tr("QML property documented multiple times: '%1'").arg(arg); - doc.startLocation().warning(msg); + QmlPropertyNode *existingProperty = qmlType->hasQmlProperty(property, attached); + if (existingProperty) { + processMetaCommands(doc, existingProperty); + if (!doc.body().isEmpty()) { + doc.startLocation().warning( + QStringLiteral("QML property documented multiple times: '%1'") + .arg(arg)); + } continue; } - QmlPropertyNode* qpn = new QmlPropertyNode(qmlType, property, type, attached); - if (scn != nullptr) - qpn->setSharedCommentNode(scn); + auto *qpn = new QmlPropertyNode(qmlType, property, type, attached); qpn->setLocation(doc.startLocation()); - if (jsProps) - qpn->setGenus(Node::JS); - else - qpn->setGenus(Node::QML); + qpn->setGenus(jsProps ? Node::JS : Node::QML); nodes.append(qpn); docs.append(doc); + sharedNodes << qpn; } } else { - doc.startLocation().warning(tr("Command '\\%1'; not allowed with QML/JS property commands").arg(cmd)); + doc.startLocation().warning( + QStringLiteral("Command '\\%1'; not allowed with QML/JS property commands") + .arg(cmd)); } } + + // Construct a SharedCommentNode (scn) if multiple topics generated + // valid nodes. Note that it's important to do this *after* constructing + // the topic nodes - which need to be written to index before the related + // scn. + if (sharedNodes.count() > 1) { + auto *scn = new SharedCommentNode(qmlType, sharedNodes.count(), group); + scn->setLocation(doc.startLocation()); + nodes.append(scn); + docs.append(doc); + for (const auto n : sharedNodes) + scn->append(n); + scn->sort(); + } } /*! Returns the set of strings representing the common metacommands plus some other metacommands. */ -const QSet& CppCodeParser::metaCommands() +const QSet &CppCodeParser::metaCommands() { return metaCommands_; } @@ -520,19 +495,16 @@ const QSet& CppCodeParser::metaCommands() \a node is guaranteed to be non-null. */ -void CppCodeParser::processMetaCommand(const Doc &doc, - const QString &command, - const ArgLocPair &argLocPair, - Node *node) +void CppCodeParser::processMetaCommand(const Doc &doc, const QString &command, + const ArgLocPair &argLocPair, Node *node) { QString arg = argLocPair.first; if (command == COMMAND_INHEADERFILE) { if (node->isAggregate()) - static_cast(node)->addIncludeFile(arg); + static_cast(node)->addIncludeFile(arg); else - doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_INHEADERFILE)); - } - else if (command == COMMAND_OVERLOAD) { + doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_INHEADERFILE)); + } else if (command == COMMAND_OVERLOAD) { /* Note that this might set the overload flag of the primary function. This is ok because the overload @@ -540,54 +512,53 @@ void CppCodeParser::processMetaCommand(const Doc &doc, in Aggregate::normalizeOverloads(). */ if (node->isFunction()) - static_cast(node)->setOverloadFlag(); + static_cast(node)->setOverloadFlag(); else if (node->isSharedCommentNode()) - static_cast(node)->setOverloadFlags(); + static_cast(node)->setOverloadFlags(); else - doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_OVERLOAD)); - } - else if (command == COMMAND_REIMP) { + doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_OVERLOAD)); + } else if (command == COMMAND_REIMP) { if (node->parent() && !node->parent()->isInternal()) { if (node->isFunction()) { - FunctionNode *fn = static_cast(node); + auto *fn = static_cast(node); // The clang visitor class will have set the // qualified name of the ovverridden function. // If the name of the overridden function isn't // set, issue a warning. if (fn->overridesThis().isEmpty() && isWorthWarningAbout(doc)) { - doc.location().warning(tr("Cannot find base function for '\\%1' in %2()") - .arg(COMMAND_REIMP).arg(node->name()), - tr("The function either doesn't exist in any " - "base class with the same signature or it " - "exists but isn't virtual.")); + doc.location().warning( + QStringLiteral("Cannot find base function for '\\%1' in %2()") + .arg(COMMAND_REIMP) + .arg(node->name()), + QStringLiteral("The function either doesn't exist in any " + "base class with the same signature or it " + "exists but isn't virtual.")); } fn->setReimpFlag(); - } - else { - doc.location().warning(tr("Ignored '\\%1' in %2").arg(COMMAND_REIMP).arg(node->name())); + } else { + doc.location().warning(QStringLiteral("Ignored '\\%1' in %2") + .arg(COMMAND_REIMP) + .arg(node->name())); } } - } - else if (command == COMMAND_RELATES) { + } else if (command == COMMAND_RELATES) { QStringList path = arg.split("::"); Aggregate *aggregate = qdb_->findRelatesNode(path); if (aggregate == nullptr) aggregate = new ProxyNode(node->root(), arg); if (node->parent() == aggregate) { // node is already a child of aggregate - doc.location().warning(tr("Invalid '\\%1' (already a member of '%2')") - .arg(COMMAND_RELATES, arg)); + doc.location().warning(QStringLiteral("Invalid '\\%1' (already a member of '%2')") + .arg(COMMAND_RELATES, arg)); } else { if (node->isAggregate()) { - doc.location().warning(tr("Invalid '\\%1' not allowed in '\\%2'") - .arg(COMMAND_RELATES, node->nodeTypeString())); + doc.location().warning(QStringLiteral("Invalid '\\%1' not allowed in '\\%2'") + .arg(COMMAND_RELATES, node->nodeTypeString())); } else if (!node->isRelatedNonmember() && - //!node->parent()->name().isEmpty() && - !node->parent()->isNamespace() && - !node->parent()->isHeader()) { + !node->parent()->isNamespace() && !node->parent()->isHeader()) { if (!doc.isInternal()) { - doc.location().warning(tr("Invalid '\\%1' ('%2' must be global)") - .arg(COMMAND_RELATES, node->name())); + doc.location().warning(QStringLiteral("Invalid '\\%1' ('%2' must be global)") + .arg(COMMAND_RELATES, node->name())); } } else if (!node->isRelatedNonmember() && !node->parent()->isHeader()) { aggregate->adoptChild(node); @@ -600,52 +571,47 @@ void CppCodeParser::processMetaCommand(const Doc &doc, */ Node *clone = node->clone(aggregate); if (clone == nullptr) { - doc.location().warning(tr("Invalid '\\%1' (multiple uses not allowed in '%2')") - .arg(COMMAND_RELATES, node->nodeTypeString())); + doc.location().warning( + QStringLiteral("Invalid '\\%1' (multiple uses not allowed in '%2')") + .arg(COMMAND_RELATES, node->nodeTypeString())); } else { clone->setRelatedNonmember(true); } } } - } - else if (command == COMMAND_CONTENTSPAGE) { - setLink(node, Node::ContentsLink, arg); - } - else if (command == COMMAND_NEXTPAGE) { + } else if (command == COMMAND_NEXTPAGE) { setLink(node, Node::NextLink, arg); - } - else if (command == COMMAND_PREVIOUSPAGE) { + } else if (command == COMMAND_PREVIOUSPAGE) { setLink(node, Node::PreviousLink, arg); - } - else if (command == COMMAND_STARTPAGE) { + } else if (command == COMMAND_STARTPAGE) { setLink(node, Node::StartLink, arg); - } - else if (command == COMMAND_QMLINHERITS) { + } else if (command == COMMAND_QMLINHERITS) { if (node->name() == arg) - doc.location().warning(tr("%1 tries to inherit itself").arg(arg)); + doc.location().warning(QStringLiteral("%1 tries to inherit itself").arg(arg)); else if (node->isQmlType() || node->isJsType()) { - QmlTypeNode* qmlType = static_cast(node); + auto *qmlType = static_cast(node); qmlType->setQmlBaseName(arg); } - } - else if (command == COMMAND_QMLINSTANTIATES) { + } else if (command == COMMAND_QMLINSTANTIATES) { if (node->isQmlType() || node->isJsType()) { - ClassNode* classNode = qdb_->findClassNode(arg.split("::")); + ClassNode *classNode = qdb_->findClassNode(arg.split("::")); if (classNode) node->setClassNode(classNode); else - doc.location().warning(tr("C++ class %1 not found: \\instantiates %1").arg(arg)); - } - else - doc.location().warning(tr("\\instantiates is only allowed in \\qmltype")); - } - else if (command == COMMAND_QMLDEFAULT) { + doc.location().warning( + QStringLiteral("C++ class %1 not found: \\instantiates %1").arg(arg)); + } else + doc.location().warning(QStringLiteral("\\instantiates is only allowed in \\qmltype")); + } else if (command == COMMAND_QMLDEFAULT) { node->markDefault(); - } - else if (command == COMMAND_QMLREADONLY) { - node->markReadOnly(1); - } - else if ((command == COMMAND_QMLABSTRACT) || (command == COMMAND_ABSTRACT)) { + } else if (command == COMMAND_QMLREADONLY) { + node->markReadOnly(true); + } else if (command == COMMAND_QMLREQUIRED) { + if (!node->isQmlProperty()) + doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_QMLREQUIRED)); + else + static_cast(node)->setRequired(); + } else if ((command == COMMAND_QMLABSTRACT) || (command == COMMAND_ABSTRACT)) { if (node->isQmlType() || node->isJsType()) node->setAbstract(true); } else if (command == COMMAND_DEPRECATED) { @@ -654,13 +620,11 @@ void CppCodeParser::processMetaCommand(const Doc &doc, // Note: \ingroup and \inpublicgroup are the same (and now recognized as such). qdb_->addToGroup(arg, node); } else if (command == COMMAND_INMODULE) { - qdb_->addToModule(arg,node); + qdb_->addToModule(arg, node); } else if (command == COMMAND_INQMLMODULE) { - qdb_->addToQmlModule(arg,node); + qdb_->addToQmlModule(arg, node); } else if (command == COMMAND_INJSMODULE) { qdb_->addToJsModule(arg, node); - } else if (command == COMMAND_MAINCLASS) { - node->doc().location().warning(tr("'\\mainclass' is deprecated. Consider '\\ingroup mainclasses'")); } else if (command == COMMAND_OBSOLETE) { node->setStatus(Node::Obsolete); } else if (command == COMMAND_NONREENTRANT) { @@ -678,23 +642,29 @@ void CppCodeParser::processMetaCommand(const Doc &doc, node->setSince(arg); } else if (command == COMMAND_WRAPPER) { node->setWrapper(); - } else if (command == COMMAND_PAGEKEYWORDS) { - node->addPageKeywords(arg); } else if (command == COMMAND_THREADSAFE) { node->setThreadSafeness(Node::ThreadSafe); } else if (command == COMMAND_TITLE) { if (!node->setTitle(arg)) - doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_TITLE)); + doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_TITLE)); else if (node->isExample()) - qdb_->addExampleNode(static_cast(node)); + qdb_->addExampleNode(static_cast(node)); } else if (command == COMMAND_SUBTITLE) { if (!node->setSubtitle(arg)) - doc.location().warning(tr("Ignored '\\%1'").arg(COMMAND_SUBTITLE)); + doc.location().warning(QStringLiteral("Ignored '\\%1'").arg(COMMAND_SUBTITLE)); } else if (command == COMMAND_QTVARIABLE) { node->setQtVariable(arg); if (!node->isModule() && !node->isQmlModule()) - doc.location().warning(tr("Command '\\%1' is only meanigfule in '\\module' and '\\qmlmodule'.") - .arg(COMMAND_QTVARIABLE)); + doc.location().warning( + QStringLiteral( + "Command '\\%1' is only meaningful in '\\module' and '\\qmlmodule'.") + .arg(COMMAND_QTVARIABLE)); + } else if (command == COMMAND_QTCMAKEPACKAGE) { + node->setQtCMakeComponent(arg); + if (!node->isModule()) + doc.location().warning( + QStringLiteral("Command '\\%1' is only meaningful in '\\module'.") + .arg(COMMAND_QTCMAKEPACKAGE)); } else if (command == COMMAND_NOAUTOLIST) { node->setNoAutoList(true); } @@ -708,24 +678,19 @@ void CppCodeParser::processMetaCommand(const Doc &doc, */ void CppCodeParser::processMetaCommands(const Doc &doc, Node *node) { - QStringList metaCommandsUsed = doc.metaCommandsUsed().values(); - metaCommandsUsed.sort(); // TODO: why are these sorted? mws 24/12/2018 - QStringList::ConstIterator cmd = metaCommandsUsed.constBegin(); - while (cmd != metaCommandsUsed.constEnd()) { - ArgList args = doc.metaCommandArgs(*cmd); - ArgList::ConstIterator arg = args.constBegin(); - while (arg != args.constEnd()) { - processMetaCommand(doc, *cmd, *arg, node); - ++arg; - } - ++cmd; + const QStringList metaCommandsUsed = doc.metaCommandsUsed().values(); + for (const auto &command : metaCommandsUsed) { + const ArgList args = doc.metaCommandArgs(command); + for (const auto &arg : args) + processMetaCommand(doc, command, arg, node); } } /*! Parse QML/JS signal/method topic commands. */ -FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Location &location, const QString &funcArg) +FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Location &location, + const QString &funcArg) { QString funcName; QString returnType; @@ -744,7 +709,7 @@ FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Locat QStringList colonSplit(funcName.split("::")); if (colonSplit.size() < 2) { QString msg = "Unrecognizable QML module/component qualifier for " + funcArg; - location.warning(tr(msg.toLatin1().data())); + location.warning(msg.toLatin1().data()); return nullptr; } QString moduleName; @@ -767,14 +732,14 @@ FunctionNode *CppCodeParser::parseOtherFuncArg(const QString &topic, const Locat QStringList leftParenSplit = funcArg.split('('); if (leftParenSplit.size() > 1) { QStringList rightParenSplit = leftParenSplit[1].split(')'); - if (rightParenSplit.size() > 0) + if (!rightParenSplit.empty()) params = rightParenSplit[0]; } FunctionNode::Metaness metaness = FunctionNode::getMetanessFromTopic(topic); bool attached = topic.contains(QLatin1String("attached")); - FunctionNode *fn = new FunctionNode(metaness, aggregate, funcName, attached); - fn->setAccess(Node::Public); + auto *fn = new FunctionNode(metaness, aggregate, funcName, attached); + fn->setAccess(Access::Public); fn->setLocation(location); fn->setReturnType(returnType); fn->setParameters(params); @@ -793,9 +758,9 @@ FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QStri if (leftParenSplit.isEmpty()) return nullptr; QString macroName; - FunctionNode* oldMacroNode = nullptr; + FunctionNode *oldMacroNode = nullptr; QStringList blankSplit = leftParenSplit[0].split(' '); - if (blankSplit.size() > 0) { + if (!blankSplit.empty()) { macroName = blankSplit.last(); oldMacroNode = qdb_->findMacroNode(macroName); } @@ -821,98 +786,73 @@ FunctionNode *CppCodeParser::parseMacroArg(const Location &location, const QStri FunctionNode::Metaness metaness = FunctionNode::MacroWithParams; if (params.isEmpty()) metaness = FunctionNode::MacroWithoutParams; - FunctionNode* macro = new FunctionNode(metaness, qdb_->primaryTreeRoot(), macroName); - macro->setAccess(Node::Public); + auto *macro = new FunctionNode(metaness, qdb_->primaryTreeRoot(), macroName); + macro->setAccess(Access::Public); macro->setLocation(location); macro->setReturnType(returnType); macro->setParameters(params); - if (oldMacroNode && macro->compare(oldMacroNode)) { - location.warning(tr("\\macro %1 documented more than once").arg(macroArg)); - oldMacroNode->doc().location().warning(tr("(The previous doc is here)")); + if (macro->compare(oldMacroNode)) { + location.warning(QStringLiteral("\\macro %1 documented more than once").arg(macroArg)); + oldMacroNode->doc().location().warning(QStringLiteral("(The previous doc is here)")); } return macro; - } +} -void CppCodeParser::setExampleFileLists(PageNode *pn) +void CppCodeParser::setExampleFileLists(ExampleNode *en) { - QString examplePath = pn->name(); - QString proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".pro"; - QString fullPath = Config::findFile(pn->doc().location(), - exampleFiles, - exampleDirs, - proFileName); - + Config &config = Config::instance(); + QString fullPath = config.getExampleProjectFile(en->name()); if (fullPath.isEmpty()) { - QString tmp = proFileName; - proFileName = examplePath + QLatin1Char('/') + "qbuild.pro"; - fullPath = Config::findFile(pn->doc().location(), - exampleFiles, - exampleDirs, - proFileName); - if (fullPath.isEmpty()) { - proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".qmlproject"; - fullPath = Config::findFile(pn->doc().location(), - exampleFiles, - exampleDirs, - proFileName); - if (fullPath.isEmpty()) { - proFileName = examplePath + QLatin1Char('/') + examplePath.split(QLatin1Char('/')).last() + ".pyproject"; - fullPath = Config::findFile(pn->doc().location(), - exampleFiles, - exampleDirs, - proFileName); - if (fullPath.isEmpty()) { - QString details = QLatin1String("Example directories: ") + exampleDirs.join(QLatin1Char(' ')); - if (!exampleFiles.isEmpty()) - details += QLatin1String(", example files: ") + exampleFiles.join(QLatin1Char(' ')); - pn->location().warning(tr("Cannot find file '%1' or '%2'").arg(tmp).arg(proFileName), details); - pn->location().warning(tr(" EXAMPLE PATH DOES NOT EXIST: %1").arg(examplePath), details); - return; - } - } - } + QString details = QLatin1String("Example directories: ") + + config.getCanonicalPathList(CONFIG_EXAMPLEDIRS).join(QLatin1Char(' ')); + en->location().warning( + QStringLiteral("Cannot find project file for example '%1'").arg(en->name()), + details); + return; } - int sizeOfBoringPartOfName = fullPath.size() - proFileName.size(); - if (fullPath.startsWith("./")) - sizeOfBoringPartOfName = sizeOfBoringPartOfName - 2; - fullPath.truncate(fullPath.lastIndexOf('/')); + QDir exampleDir(QFileInfo(fullPath).dir()); - QStringList exampleFiles = Config::getFilesHere(fullPath, exampleNameFilter, Location(), excludeDirs, excludeFiles); + QStringList exampleFiles = Config::getFilesHere(exampleDir.path(), m_exampleNameFilter, + Location(), m_excludeDirs, m_excludeFiles); // Search for all image files under the example project, excluding doc/images directory. - QSet excludeDocDirs(excludeDirs); - excludeDocDirs.insert(QDir(fullPath).canonicalPath() + "/doc/images"); - QStringList imageFiles = Config::getFilesHere(fullPath, exampleImageFilter, Location(), excludeDocDirs, excludeFiles); + QSet excludeDocDirs(m_excludeDirs); + excludeDocDirs.insert(exampleDir.path() + QLatin1String("/doc/images")); + QStringList imageFiles = Config::getFilesHere(exampleDir.path(), m_exampleImageFilter, + Location(), excludeDocDirs, m_excludeFiles); if (!exampleFiles.isEmpty()) { - // move main.cpp and to the end, if it exists + // move main.cpp to the end, if it exists QString mainCpp; - QMutableStringListIterator i(exampleFiles); - i.toBack(); - while (i.hasPrevious()) { - QString fileName = i.previous(); + + const auto isGeneratedOrMainCpp = [&mainCpp](const QString &fileName) { if (fileName.endsWith("/main.cpp")) { - mainCpp = fileName; - i.remove(); + if (mainCpp.isEmpty()) + mainCpp = fileName; + return true; } - else if (fileName.contains("/qrc_") || fileName.contains("/moc_") - || fileName.contains("/ui_")) - i.remove(); - } + return fileName.contains("/qrc_") || fileName.contains("/moc_") + || fileName.contains("/ui_"); + }; + + exampleFiles.erase( + std::remove_if(exampleFiles.begin(), exampleFiles.end(), isGeneratedOrMainCpp), + exampleFiles.end()); + if (!mainCpp.isEmpty()) exampleFiles.append(mainCpp); - // add any qmake Qt resource files and qmake project files - exampleFiles += Config::getFilesHere(fullPath, "*.qrc *.pro *.qmlproject qmldir"); + // Add any resource and project files + exampleFiles += Config::getFilesHere(exampleDir.path(), + QLatin1String("*.qrc *.pro *.qmlproject *.pyproject CMakeLists.txt qmldir")); } - int i = 0; - foreach (const QString &exampleFile, exampleFiles) - exampleFiles[i++] = exampleFile.mid(sizeOfBoringPartOfName); - i = 0; - foreach (const QString &imageFile, imageFiles) - imageFiles[i++] = imageFile.mid(sizeOfBoringPartOfName); - ExampleNode* en = static_cast(pn); - en->setFiles(exampleFiles); + const int pathLen = exampleDir.path().size() - en->name().size(); + for (auto &file : exampleFiles) + file = file.mid(pathLen); + for (auto &file : imageFiles) + file = file.mid(pathLen); + + en->setFiles(exampleFiles, fullPath.mid(pathLen)); en->setImages(imageFiles); } @@ -922,10 +862,8 @@ void CppCodeParser::setExampleFileLists(PageNode *pn) */ bool CppCodeParser::isJSMethodTopic(const QString &t) { - return (t == COMMAND_JSSIGNAL || - t == COMMAND_JSMETHOD || - t == COMMAND_JSATTACHEDSIGNAL || - t == COMMAND_JSATTACHEDMETHOD); + return (t == COMMAND_JSSIGNAL || t == COMMAND_JSMETHOD || t == COMMAND_JSATTACHEDSIGNAL + || t == COMMAND_JSATTACHEDMETHOD); } /*! @@ -934,10 +872,8 @@ bool CppCodeParser::isJSMethodTopic(const QString &t) */ bool CppCodeParser::isQMLMethodTopic(const QString &t) { - return (t == COMMAND_QMLSIGNAL || - t == COMMAND_QMLMETHOD || - t == COMMAND_QMLATTACHEDSIGNAL || - t == COMMAND_QMLATTACHEDMETHOD); + return (t == COMMAND_QMLSIGNAL || t == COMMAND_QMLMETHOD || t == COMMAND_QMLATTACHEDSIGNAL + || t == COMMAND_QMLATTACHEDMETHOD); } /*! @@ -958,7 +894,8 @@ bool CppCodeParser::isQMLPropertyTopic(const QString &t) return (t == COMMAND_QMLPROPERTY || t == COMMAND_QMLATTACHEDPROPERTY); } -void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, DocList &docs) +void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, + DocList &docs) { if (isQMLPropertyTopic(topic) || isJSPropertyTopic(topic)) { processQmlProperties(doc, nodes, docs); @@ -983,53 +920,52 @@ void CppCodeParser::processTopicArgs(const Doc &doc, const QString &topic, NodeL docs.append(doc); } } else if (args.size() > 1) { - QVector sharedCommentNodes; - ArgList::ConstIterator arg = args.constBegin(); - while (arg != args.constEnd()) { + QList sharedCommentNodes; + for (const auto &arg : qAsConst(args)) { node = nullptr; if (topic == COMMAND_FN) { if (showInternal() || !doc.isInternal()) - node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg->first); + node = parserForLanguage("Clang")->parseFnArg(doc.location(), arg.first); } else if (topic == COMMAND_MACRO) { - node = parseMacroArg(doc.location(), arg->first); + node = parseMacroArg(doc.location(), arg.first); } else if (isQMLMethodTopic(topic) || isJSMethodTopic(topic)) { - node = parseOtherFuncArg(topic, doc.location(), arg->first); + node = parseOtherFuncArg(topic, doc.location(), arg.first); } else { - node = processTopicCommand(doc, topic, *arg); + node = processTopicCommand(doc, topic, arg); } if (node != nullptr) { bool found = false; for (SharedCommentNode *scn : sharedCommentNodes) { if (scn->parent() == node->parent()) { - node->setSharedCommentNode(scn); + scn->append(node); found = true; break; } } if (!found) { - SharedCommentNode *scn = new SharedCommentNode(node); + auto *scn = new SharedCommentNode(node); sharedCommentNodes.append(scn); nodes.append(scn); docs.append(doc); } } - ++arg; } + for (auto *scn : sharedCommentNodes) + scn->sort(); } } } void CppCodeParser::processMetaCommands(NodeList &nodes, DocList &docs) { - NodeList::Iterator n = nodes.begin(); QList::Iterator d = docs.begin(); - while (n != nodes.end()) { - if (*n != nullptr) { - processMetaCommands(*d, *n); - (*n)->setDoc(*d); - checkModuleInclusion(*n); - if ((*n)->isAggregate()) { - Aggregate *aggregate = static_cast(*n); + for (const auto &node : nodes) { + if (node != nullptr) { + processMetaCommands(*d, node); + node->setDoc(*d); + checkModuleInclusion(node); + if (node->isAggregate()) { + auto *aggregate = static_cast(node); if (aggregate->includeFiles().isEmpty()) { Aggregate *parent = aggregate; while (parent->physicalModuleName().isEmpty() && (parent->parent() != nullptr)) @@ -1042,13 +978,12 @@ void CppCodeParser::processMetaCommands(NodeList &nodes, DocList &docs) } } ++d; - ++n; } } bool CppCodeParser::hasTooManyTopics(const Doc &doc) const { - QSet topicCommandsUsed = topicCommands() & doc.metaCommandsUsed(); + const QSet topicCommandsUsed = topicCommands() & doc.metaCommandsUsed(); if (topicCommandsUsed.count() > 1) { bool ok = true; for (const auto &t : topicCommandsUsed) { @@ -1065,7 +1000,8 @@ bool CppCodeParser::hasTooManyTopics(const Doc &doc) const Q_ASSERT(i >= 0); // we had at least two commas topicList[i] = ' '; topicList.insert(i + 1, "and"); - doc.location().warning(tr("Multiple topic commands found in comment:%1").arg(topicList)); + doc.location().warning( + QStringLiteral("Multiple topic commands found in comment:%1").arg(topicList)); return true; } return false; diff --git a/src/qdoc/cppcodeparser.h b/src/qdoc/cppcodeparser.h index 3d3f6a52c1..f438a0082e 100644 --- a/src/qdoc/cppcodeparser.h +++ b/src/qdoc/cppcodeparser.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -34,73 +34,65 @@ QT_BEGIN_NAMESPACE class ClassNode; +class ExampleNode; class FunctionNode; class Aggregate; class CppCodeParser : public CodeParser { - Q_DECLARE_TR_FUNCTIONS(QDoc::CppCodeParser) - - struct ExtraFuncData { - Aggregate* root; // Used as the parent. + struct ExtraFuncData + { + Aggregate *root; // Used as the parent. Node::NodeType type; // The node type: Function, etc. bool isAttached; // If true, the method is attached. - bool isMacro; // If true, we are parsing a macro signature. - ExtraFuncData() : root(nullptr), type(Node::Function), isAttached(false), isMacro(false) { } - ExtraFuncData(Aggregate* r, Node::NodeType t, bool a) - : root(r), type(t), isAttached(a), isMacro(false) { } + bool isMacro; // If true, we are parsing a macro signature. + ExtraFuncData() : root(nullptr), type(Node::Function), isAttached(false), isMacro(false) {} }; public: CppCodeParser(); - ~CppCodeParser() = default; - void initializeParser(const Config& config) override; + void initializeParser() override; void terminateParser() override; QString language() override { return QStringLiteral("Cpp"); } QStringList headerFileNameFilter() override; QStringList sourceFileNameFilter() override; FunctionNode *parseMacroArg(const Location &location, const QString ¯oArg); - FunctionNode *parseOtherFuncArg(const QString &topic, const Location &location, const QString &funcArg); + FunctionNode *parseOtherFuncArg(const QString &topic, const Location &location, + const QString &funcArg); static bool isJSMethodTopic(const QString &t); static bool isQMLMethodTopic(const QString &t); static bool isJSPropertyTopic(const QString &t); static bool isQMLPropertyTopic(const QString &t); protected: - static const QSet& topicCommands(); - static const QSet& metaCommands(); - virtual Node* processTopicCommand(const Doc& doc, - const QString& command, - const ArgLocPair& arg); + static const QSet &topicCommands(); + static const QSet &metaCommands(); + virtual Node *processTopicCommand(const Doc &doc, const QString &command, + const ArgLocPair &arg); void processQmlProperties(const Doc &doc, NodeList &nodes, DocList &docs); - bool splitQmlPropertyArg(const QString& arg, - QString& type, - QString& module, - QString& element, - QString& name, - const Location& location); - void processMetaCommand(const Doc &doc, const QString &command, const ArgLocPair &argLocPair, Node *node); + bool splitQmlPropertyArg(const QString &arg, QString &type, QString &module, QString &element, + QString &name, const Location &location); + void processMetaCommand(const Doc &doc, const QString &command, const ArgLocPair &argLocPair, + Node *node); void processMetaCommands(const Doc &doc, Node *node); void processMetaCommands(NodeList &nodes, DocList &docs); void processTopicArgs(const Doc &doc, const QString &topic, NodeList &nodes, DocList &docs); bool hasTooManyTopics(const Doc &doc) const; - private: - void setExampleFileLists(PageNode *pn); +private: + void setExampleFileLists(ExampleNode *en); - protected: - typedef bool (Node::*NodeTypeTestFunc) () const; - QMap nodeTypeTestFuncMap_; - QMap nodeTypeMap_; +protected: + typedef bool (Node::*NodeTypeTestFunc)() const; + QMap m_nodeTypeTestFuncMap; + QMap m_nodeTypeMap; - private: - static QStringList exampleFiles; - static QStringList exampleDirs; - static QSet excludeDirs; - static QSet excludeFiles; - QString exampleNameFilter; - QString exampleImageFilter; +private: + static QSet m_excludeDirs; + static QSet m_excludeFiles; + QString m_exampleNameFilter; + QString m_exampleImageFilter; }; QT_END_NAMESPACE diff --git a/src/qdoc/doc.cpp b/src/qdoc/doc.cpp index b31125597a..742dbffe9e 100644 --- a/src/qdoc/doc.cpp +++ b/src/qdoc/doc.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,2830 +26,21 @@ ** ****************************************************************************/ -#include "config.h" -#include "doc.h" -#include "codemarker.h" -#include "editdistance.h" -#include "openedlist.h" -#include "quoter.h" -#include "text.h" -#include "atom.h" -#include "tokenizer.h" -#include "loggingcategory.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "generator.h" - -QT_BEGIN_NAMESPACE - -Q_GLOBAL_STATIC(QSet, null_Set_QString) -Q_GLOBAL_STATIC(TopicList, nullTopicList) -Q_GLOBAL_STATIC(QStringList, null_QStringList) -Q_GLOBAL_STATIC(QList, null_QList_Text) -Q_GLOBAL_STATIC(QStringMultiMap, null_QStringMultiMap) - -struct Macro -{ - QString defaultDef; - Location defaultDefLocation; - QStringMap otherDefs; - int numParams; -}; - -enum { - CMD_A, - CMD_ANNOTATEDLIST, - CMD_B, - CMD_BADCODE, - CMD_BOLD, - CMD_BR, - CMD_BRIEF, - CMD_C, - CMD_CAPTION, - CMD_CODE, - CMD_CODELINE, - CMD_DIV, - CMD_DOTS, - CMD_E, - CMD_ELSE, - CMD_ENDCODE, - CMD_ENDDIV, - CMD_ENDFOOTNOTE, - CMD_ENDIF, - CMD_ENDLEGALESE, - CMD_ENDLINK, - CMD_ENDLIST, - CMD_ENDMAPREF, - CMD_ENDOMIT, - CMD_ENDQUOTATION, - CMD_ENDRAW, - CMD_ENDSECTION1, - CMD_ENDSECTION2, - CMD_ENDSECTION3, - CMD_ENDSECTION4, - CMD_ENDSIDEBAR, - CMD_ENDTABLE, - CMD_ENDTOPICREF, - CMD_FOOTNOTE, - CMD_GENERATELIST, - CMD_GRANULARITY, - CMD_HEADER, - CMD_HR, - CMD_I, - CMD_IF, - CMD_IMAGE, - CMD_IMPORTANT, - CMD_INCLUDE, - CMD_INLINEIMAGE, - CMD_INDEX, - CMD_INPUT, - CMD_KEYWORD, - CMD_L, - CMD_LEGALESE, - CMD_LI, - CMD_LINK, - CMD_LIST, - CMD_MAPREF, - CMD_META, - CMD_NEWCODE, - CMD_NOTE, - CMD_O, - CMD_OLDCODE, - CMD_OMIT, - CMD_OMITVALUE, - CMD_OVERLOAD, - CMD_PRINTLINE, - CMD_PRINTTO, - CMD_PRINTUNTIL, - CMD_QUOTATION, - CMD_QUOTEFILE, - CMD_QUOTEFROMFILE, - CMD_QUOTEFUNCTION, - CMD_RAW, - CMD_ROW, - CMD_SA, - CMD_SECTION1, - CMD_SECTION2, - CMD_SECTION3, - CMD_SECTION4, - CMD_SIDEBAR, - CMD_SINCELIST, - CMD_SKIPLINE, - CMD_SKIPTO, - CMD_SKIPUNTIL, - CMD_SNIPPET, - CMD_SPAN, - CMD_SUB, - CMD_SUP, - CMD_TABLE, - CMD_TABLEOFCONTENTS, - CMD_TARGET, - CMD_TOPICREF, - CMD_TT, - CMD_UICONTROL, - CMD_UNDERLINE, - CMD_UNICODE, - CMD_VALUE, - CMD_WARNING, - CMD_QML, - CMD_ENDQML, - CMD_CPP, - CMD_ENDCPP, - CMD_QMLTEXT, - CMD_ENDQMLTEXT, - CMD_CPPTEXT, - CMD_ENDCPPTEXT, - CMD_JS, - CMD_ENDJS, - NOT_A_CMD -}; - -static struct { - const char *english; - int no; - QString *alias; -} cmds[] = { - { "a", CMD_A, nullptr }, - { "annotatedlist", CMD_ANNOTATEDLIST, nullptr }, - { "b", CMD_B, nullptr }, - { "badcode", CMD_BADCODE, nullptr }, - { "bold", CMD_BOLD, nullptr }, - { "br", CMD_BR, nullptr }, - { "brief", CMD_BRIEF, nullptr }, - { "c", CMD_C, nullptr }, - { "caption", CMD_CAPTION, nullptr }, - { "code", CMD_CODE, nullptr }, - { "codeline", CMD_CODELINE, nullptr }, - { "div", CMD_DIV, nullptr}, - { "dots", CMD_DOTS, nullptr }, - { "e", CMD_E, nullptr }, - { "else", CMD_ELSE, nullptr }, - { "endcode", CMD_ENDCODE, nullptr }, - { "enddiv", CMD_ENDDIV, nullptr }, - { "endfootnote", CMD_ENDFOOTNOTE, nullptr }, - { "endif", CMD_ENDIF, nullptr }, - { "endlegalese", CMD_ENDLEGALESE, nullptr }, - { "endlink", CMD_ENDLINK, nullptr }, - { "endlist", CMD_ENDLIST, nullptr }, - { "endmapref", CMD_ENDMAPREF, nullptr }, - { "endomit", CMD_ENDOMIT, nullptr }, - { "endquotation", CMD_ENDQUOTATION, nullptr }, - { "endraw", CMD_ENDRAW, nullptr }, - { "endsection1", CMD_ENDSECTION1, nullptr }, // ### don't document for now - { "endsection2", CMD_ENDSECTION2, nullptr }, // ### don't document for now - { "endsection3", CMD_ENDSECTION3, nullptr }, // ### don't document for now - { "endsection4", CMD_ENDSECTION4, nullptr }, // ### don't document for now - { "endsidebar", CMD_ENDSIDEBAR, nullptr }, - { "endtable", CMD_ENDTABLE, nullptr }, - { "endtopicref", CMD_ENDTOPICREF, nullptr }, - { "footnote", CMD_FOOTNOTE, nullptr }, - { "generatelist", CMD_GENERATELIST, nullptr }, - { "granularity", CMD_GRANULARITY, nullptr }, // ### don't document for now - { "header", CMD_HEADER, nullptr }, - { "hr", CMD_HR, nullptr }, - { "i", CMD_I, nullptr}, - { "if", CMD_IF, nullptr }, - { "image", CMD_IMAGE, nullptr }, - { "important", CMD_IMPORTANT, nullptr }, - { "include", CMD_INCLUDE, nullptr }, - { "inlineimage", CMD_INLINEIMAGE, nullptr }, - { "index", CMD_INDEX, nullptr }, // ### don't document for now - { "input", CMD_INPUT, nullptr }, - { "keyword", CMD_KEYWORD, nullptr }, - { "l", CMD_L, nullptr }, - { "legalese", CMD_LEGALESE, nullptr}, - { "li", CMD_LI, nullptr}, - { "link", CMD_LINK, nullptr }, - { "list", CMD_LIST, nullptr }, - { "mapref", CMD_MAPREF, nullptr }, - { "meta", CMD_META, nullptr }, - { "newcode", CMD_NEWCODE, nullptr }, - { "note", CMD_NOTE, nullptr }, - { "o", CMD_O, nullptr }, - { "oldcode", CMD_OLDCODE, nullptr }, - { "omit", CMD_OMIT, nullptr }, - { "omitvalue", CMD_OMITVALUE, nullptr }, - { "overload", CMD_OVERLOAD, nullptr }, - { "printline", CMD_PRINTLINE, nullptr }, - { "printto", CMD_PRINTTO, nullptr }, - { "printuntil", CMD_PRINTUNTIL, nullptr }, - { "quotation", CMD_QUOTATION, nullptr }, - { "quotefile", CMD_QUOTEFILE, nullptr }, - { "quotefromfile", CMD_QUOTEFROMFILE, nullptr }, - { "quotefunction", CMD_QUOTEFUNCTION, nullptr }, - { "raw", CMD_RAW, nullptr }, - { "row", CMD_ROW, nullptr }, - { "sa", CMD_SA, nullptr }, - { "section1", CMD_SECTION1, nullptr }, - { "section2", CMD_SECTION2, nullptr }, - { "section3", CMD_SECTION3, nullptr }, - { "section4", CMD_SECTION4, nullptr }, - { "sidebar", CMD_SIDEBAR, nullptr }, - { "sincelist", CMD_SINCELIST, nullptr }, - { "skipline", CMD_SKIPLINE, nullptr }, - { "skipto", CMD_SKIPTO, nullptr }, - { "skipuntil", CMD_SKIPUNTIL, nullptr }, - { "snippet", CMD_SNIPPET, nullptr }, - { "span", CMD_SPAN, nullptr }, - { "sub", CMD_SUB, nullptr }, - { "sup", CMD_SUP, nullptr }, - { "table", CMD_TABLE, nullptr }, - { "tableofcontents", CMD_TABLEOFCONTENTS, nullptr }, - { "target", CMD_TARGET, nullptr }, - { "topicref", CMD_TOPICREF, nullptr }, - { "tt", CMD_TT, nullptr }, - { "uicontrol", CMD_UICONTROL, nullptr }, - { "underline", CMD_UNDERLINE, nullptr }, - { "unicode", CMD_UNICODE, nullptr }, - { "value", CMD_VALUE, nullptr }, - { "warning", CMD_WARNING, nullptr }, - { "qml", CMD_QML, nullptr }, - { "endqml", CMD_ENDQML, nullptr }, - { "cpp", CMD_CPP, nullptr }, - { "endcpp", CMD_ENDCPP, nullptr }, - { "qmltext", CMD_QMLTEXT, nullptr }, - { "endqmltext", CMD_ENDQMLTEXT, nullptr }, - { "cpptext", CMD_CPPTEXT, nullptr }, - { "endcpptext", CMD_ENDCPPTEXT, nullptr }, - { "js", CMD_JS, nullptr }, - { "endjs", CMD_ENDJS, nullptr}, - { nullptr, 0, nullptr } -}; - -typedef QHash QHash_QString_int; -typedef QHash QHash_QString_Macro; - -Q_GLOBAL_STATIC(QStringMap, aliasMap) -Q_GLOBAL_STATIC(QHash_QString_int, cmdHash) -Q_GLOBAL_STATIC(QHash_QString_Macro, macroHash) - -class DocPrivateExtra -{ -public: - Doc::Sections granularity_; - Doc::Sections section_; // ### - QList tableOfContents_; - QVector tableOfContentsLevels_; - QList keywords_; - QList targets_; - QStringMultiMap metaMap_; - - DocPrivateExtra() - : granularity_(Doc::Part) - , section_(Doc::NoSection) - { } -}; - -struct Shared // ### get rid of -{ - Shared() - : count(1) { } - void ref() { ++count; } - bool deref() { return (--count == 0); } - - int count; -}; - -static QString cleanLink(const QString &link) -{ - int colonPos = link.indexOf(':'); - if ((colonPos == -1) || - (!link.startsWith("file:") && !link.startsWith("mailto:"))) - return link; - return link.mid(colonPos + 1).simplified(); -} - -typedef QMap CommandMap; - -class DocPrivate : public Shared -{ -public: - DocPrivate(const Location& start = Location::null, - const Location& end = Location::null, - const QString& source = QString()); - ~DocPrivate(); - - void addAlso(const Text& also); - void constructExtra(); - bool isEnumDocSimplifiable() const; - - // ### move some of this in DocPrivateExtra - Location start_loc; - Location end_loc; - QString src; - Text text; - QSet params; - QList alsoList; - QStringList enumItemList; - QStringList omitEnumItemList; - QSet metacommandsUsed; - CommandMap metaCommandMap; - bool hasLegalese : 1; - bool hasSectioningUnits : 1; - DocPrivateExtra *extra; - TopicList topics_; - DitaRefList ditamap_; -}; - -DocPrivate::DocPrivate(const Location& start, - const Location& end, - const QString& source) - : start_loc(start), - end_loc(end), - src(source), - hasLegalese(false), - hasSectioningUnits(false), - extra(nullptr) -{ - // nothing. -} - -/*! - If the doc is a ditamap, the destructor deletes each element - in the ditamap structure. These were allocated as needed. - */ -DocPrivate::~DocPrivate() -{ - delete extra; - foreach (DitaRef* t, ditamap_) { - delete t; - } -} - -void DocPrivate::addAlso(const Text& also) -{ - alsoList.append(also); -} - -void DocPrivate::constructExtra() -{ - if (extra == nullptr) - extra = new DocPrivateExtra; -} - -bool DocPrivate::isEnumDocSimplifiable() const -{ - bool justMetColon = false; - int numValueTables = 0; - - const Atom *atom = text.firstAtom(); - while (atom) { - if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) { - justMetColon = atom->string().endsWith(QLatin1Char(':')); - } - else if ((atom->type() == Atom::ListLeft) && - (atom->string() == ATOM_LIST_VALUE)) { - if (justMetColon || numValueTables > 0) - return false; - ++numValueTables; - } - atom = atom->next(); - } - return true; -} - -class DocParser -{ - Q_DECLARE_TR_FUNCTIONS(QDoc::DocParser) - -public: - void parse(const QString &source, - DocPrivate *docPrivate, - const QSet &metaCommandSet, - const QSet& possibleTopics); - - static int endCmdFor(int cmd); - static QString cmdName(int cmd); - static QString endCmdName(int cmd); - static QString untabifyEtc(const QString& str); - static int indentLevel(const QString& str); - static QString unindent(int level, const QString& str); - static QString slashed(const QString& str); - - static int tabSize; - static QStringList exampleFiles; - static QStringList exampleDirs; - static QStringList sourceFiles; - static QStringList sourceDirs; - static bool quoting; - -private: - Location& location(); - QString detailsUnknownCommand(const QSet& metaCommandSet, - const QString& str); - void insertTarget(const QString& target, bool keyword); - void include(const QString& fileName, const QString& identifier); - void startFormat(const QString& format, int cmd); - bool openCommand(int cmd); - bool closeCommand(int endCmd); - void startSection(Doc::Sections unit, int cmd); - void endSection(int unit, int endCmd); - void parseAlso(); - void append(const QString &string); - void append(Atom::AtomType type, const QString& string = QString()); - void append(Atom::AtomType type, const QString& p1, const QString& p2); - void append(const QString& p1, const QString& p2); - void appendChar(QChar ch); - void appendWord(const QString &word); - void appendToCode(const QString &code); - void appendToCode(const QString &code, Atom::AtomType defaultType); - void startNewPara(); - void enterPara(Atom::AtomType leftType = Atom::ParaLeft, - Atom::AtomType rightType = Atom::ParaRight, - const QString& string = QString()); - void leavePara(); - void leaveValue(); - void leaveValueList(); - void leaveTableRow(); - CodeMarker *quoteFromFile(); - bool expandMacro(); - void expandMacro(const QString& name, const QString& def, int numParams); - QString expandMacroToString(const QString &name, const QString &def, int numParams, const QString &matchExpr); - Doc::Sections getSectioningUnit(); - QString getArgument(bool verbatim = false); - QString getBracedArgument(bool verbatim); - QString getBracketedArgument(); - QString getOptionalArgument(); - QString getRestOfLine(); - QString getMetaCommandArgument(const QString &cmdStr); - QString getUntilEnd(int cmd); - QString getCode(int cmd, CodeMarker *marker, const QString &argStr = QString()); - QString getUnmarkedCode(int cmd); - - bool isBlankLine(); - bool isLeftBraceAhead(); - bool isLeftBracketAhead(); - void skipSpacesOnLine(); - void skipSpacesOrOneEndl(); - void skipAllSpaces(); - void skipToNextPreprocessorCommand(); - static bool isCode(const Atom *atom); - static bool isQuote(const Atom *atom); - - QStack openedInputs; - - QString input_; - int pos; - int backslashPos; - int endPos; - int len; - Location cachedLoc; - int cachedPos; - - DocPrivate* priv; - enum ParagraphState { - OutsideParagraph, - InSingleLineParagraph, - InMultiLineParagraph - }; - ParagraphState paraState; - bool inTableHeader; - bool inTableRow; - bool inTableItem; - bool indexStartedPara; // ### rename - Atom::AtomType pendingParaLeftType; - Atom::AtomType pendingParaRightType; - QString pendingParaString; - - int braceDepth; - Doc::Sections currentSection; - QMap targetMap_; - QMap pendingFormats; - QStack openedCommands; - QStack openedLists; - Quoter quoter; - QStack ditarefs_; - Atom *lastAtom; -}; - -int DocParser::tabSize; -QStringList DocParser::exampleFiles; -QStringList DocParser::exampleDirs; -QStringList DocParser::sourceFiles; -QStringList DocParser::sourceDirs; -bool DocParser::quoting = false; - -/*! - Parse the \a source string to build a Text data structure - in \a docPrivate. The Text data structure is a linked list - of Atoms. - - \a metaCommandSet is the set of metacommands that may be - found in \a source. These metacommands are not markup text - commands. They are topic commands and related metacommands. - */ -void DocParser::parse(const QString& source, - DocPrivate *docPrivate, - const QSet& metaCommandSet, - const QSet& possibleTopics) -{ - input_ = source; - pos = 0; - len = input_.length(); - cachedLoc = docPrivate->start_loc; - cachedPos = 0; - priv = docPrivate; - priv->text << Atom::Nop; - priv->topics_.clear(); - - paraState = OutsideParagraph; - inTableHeader = false; - inTableRow = false; - inTableItem = false; - indexStartedPara = false; - pendingParaLeftType = Atom::Nop; - pendingParaRightType = Atom::Nop; - - braceDepth = 0; - currentSection = Doc::NoSection; - openedCommands.push(CMD_OMIT); - quoter.reset(); - - CodeMarker *marker = nullptr; - Atom *currentLinkAtom = nullptr; - QString p1, p2; - QStack preprocessorSkipping; - int numPreprocessorSkipping = 0; - - while (pos < len) { - QChar ch = input_.at(pos); - - switch (ch.unicode()) { - case '\\': { - QString cmdStr; - backslashPos = pos; - pos++; - while (pos < len) { - ch = input_.at(pos); - if (ch.isLetterOrNumber()) { - cmdStr += ch; - pos++; - } - else { - break; - } - } - endPos = pos; - if (cmdStr.isEmpty()) { - if (pos < len) { - enterPara(); - if (input_.at(pos).isSpace()) { - skipAllSpaces(); - appendChar(QLatin1Char(' ')); - } - else { - appendChar(input_.at(pos++)); - } - } - } - else { - // Ignore quoting atoms to make appendToCode() - // append to the correct atom. - if (!quoting || !isQuote(priv->text.lastAtom())) - lastAtom = priv->text.lastAtom(); - - int cmd = cmdHash()->value(cmdStr,NOT_A_CMD); - switch (cmd) { - case CMD_A: - enterPara(); - p1 = getArgument(); - append(Atom::FormattingLeft,ATOM_FORMATTING_PARAMETER); - append(Atom::String, p1); - append(Atom::FormattingRight,ATOM_FORMATTING_PARAMETER); - priv->params.insert(p1); - break; - case CMD_BADCODE: - leavePara(); - append(Atom::CodeBad, getCode(CMD_BADCODE, marker, getMetaCommandArgument(cmdStr))); - break; - case CMD_BR: - enterPara(); - append(Atom::BR); - break; - case CMD_BOLD: - location().warning(tr("'\\bold' is deprecated. Use '\\b'")); - Q_FALLTHROUGH(); - case CMD_B: - startFormat(ATOM_FORMATTING_BOLD, cmd); - break; - case CMD_BRIEF: - leavePara(); - enterPara(Atom::BriefLeft, Atom::BriefRight); - break; - case CMD_C: - enterPara(); - p1 = untabifyEtc(getArgument(true)); - marker = CodeMarker::markerForCode(p1); - append(Atom::C, marker->markedUpCode(p1, nullptr, location())); - break; - case CMD_CAPTION: - leavePara(); - enterPara(Atom::CaptionLeft, Atom::CaptionRight); - break; - case CMD_CODE: - leavePara(); - append(Atom::Code, getCode(CMD_CODE, nullptr, getMetaCommandArgument(cmdStr))); - break; - case CMD_QML: - leavePara(); - append(Atom::Qml, getCode(CMD_QML, - CodeMarker::markerForLanguage(QLatin1String("QML")), - getMetaCommandArgument(cmdStr))); - break; - case CMD_QMLTEXT: - append(Atom::QmlText); - break; - case CMD_JS: - leavePara(); - append(Atom::JavaScript, getCode(CMD_JS, - CodeMarker::markerForLanguage(QLatin1String("JavaScript")), - getMetaCommandArgument(cmdStr))); - break; - case CMD_DIV: - leavePara(); - p1 = getArgument(true); - append(Atom::DivLeft, p1); - openedCommands.push(cmd); - break; - case CMD_ENDDIV: - leavePara(); - append(Atom::DivRight); - closeCommand(cmd); - break; - case CMD_CODELINE: - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, " "); - } - if (isCode(lastAtom) && lastAtom->string().endsWith("\n\n")) - lastAtom->chopString(); - appendToCode("\n"); - break; - case CMD_DOTS: { - QString arg = getOptionalArgument(); - if (arg.isEmpty()) - arg = "4"; - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, arg); - } - if (isCode(lastAtom) && lastAtom->string().endsWith("\n\n")) - lastAtom->chopString(); - - int indent = arg.toInt(); - for (int i = 0; i < indent; ++i) - appendToCode(" "); - appendToCode("...\n"); - break; - } - case CMD_ELSE: - if (preprocessorSkipping.size() > 0) { - if (preprocessorSkipping.top()) { - --numPreprocessorSkipping; - } else { - ++numPreprocessorSkipping; - } - preprocessorSkipping.top() = !preprocessorSkipping.top(); - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ELSE))); - } - break; - case CMD_ENDCODE: - closeCommand(cmd); - break; - case CMD_ENDQML: - closeCommand(cmd); - break; - case CMD_ENDQMLTEXT: - append(Atom::EndQmlText); - break; - case CMD_ENDJS: - closeCommand(cmd); - break; - case CMD_ENDFOOTNOTE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::FootnoteRight); - paraState = InMultiLineParagraph; // ### - } - break; - case CMD_ENDIF: - if (preprocessorSkipping.count() > 0) { - if (preprocessorSkipping.pop()) - --numPreprocessorSkipping; - (void)getRestOfLine(); // ### should ensure that it's empty - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - } else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDIF))); - } - break; - case CMD_ENDLEGALESE: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::LegaleseRight); - } - break; - case CMD_ENDLINK: - if (closeCommand(cmd)) { - if (priv->text.lastAtom()->type() == Atom::String - && priv->text.lastAtom()->string().endsWith(QLatin1Char(' '))) - priv->text.lastAtom()->chopString(); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - break; - case CMD_ENDLIST: - if (closeCommand(cmd)) { - leavePara(); - if (openedLists.top().isStarted()) { - append(Atom::ListItemRight, - openedLists.top().styleString()); - append(Atom::ListRight, - openedLists.top().styleString()); - } - openedLists.pop(); - } - break; - case CMD_ENDMAPREF: - case CMD_ENDTOPICREF: - if (closeCommand(cmd)) - ditarefs_.pop(); - break; - case CMD_ENDOMIT: - closeCommand(cmd); - break; - case CMD_ENDQUOTATION: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::QuotationRight); - } - break; - case CMD_ENDRAW: - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_ENDRAW))); - break; - case CMD_ENDSECTION1: - endSection(Doc::Section1, cmd); - break; - case CMD_ENDSECTION2: - endSection(Doc::Section2, cmd); - break; - case CMD_ENDSECTION3: - endSection(Doc::Section3, cmd); - break; - case CMD_ENDSECTION4: - endSection(Doc::Section4, cmd); - break; - case CMD_ENDSIDEBAR: - if (closeCommand(cmd)) { - leavePara(); - append(Atom::SidebarRight); - } - break; - case CMD_ENDTABLE: - if (closeCommand(cmd)) { - leaveTableRow(); - append(Atom::TableRight); - } - break; - case CMD_FOOTNOTE: - if (openCommand(cmd)) { - enterPara(); - append(Atom::FootnoteLeft); - paraState = OutsideParagraph; - } - break; - case CMD_ANNOTATEDLIST: - append(Atom::AnnotatedList, getArgument()); - break; - case CMD_SINCELIST: - append(Atom::SinceList, getRestOfLine().simplified()); - break; - case CMD_GENERATELIST: { - QString arg1 = getArgument(); - QString arg2 = getOptionalArgument(); - if (!arg2.isEmpty()) - arg1 += " " + arg2; - append(Atom::GeneratedList, arg1); - } - break; - case CMD_GRANULARITY: - priv->constructExtra(); - priv->extra->granularity_ = getSectioningUnit(); - break; - case CMD_HEADER: - if (openedCommands.top() == CMD_TABLE) { - leaveTableRow(); - append(Atom::TableHeaderLeft); - inTableHeader = true; - } else { - if (openedCommands.contains(CMD_TABLE)) - location().warning(tr("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(openedCommands.top()))); - else - location().warning(tr("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(CMD_TABLE))); - } - break; - case CMD_I: - location().warning(tr("'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item")); - Q_FALLTHROUGH(); - case CMD_E: - startFormat(ATOM_FORMATTING_ITALIC, cmd); - break; - case CMD_HR: - leavePara(); - append(Atom::HR); - break; - case CMD_IF: - preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine())); - if (preprocessorSkipping.top()) - ++numPreprocessorSkipping; - if (numPreprocessorSkipping) - skipToNextPreprocessorCommand(); - break; - case CMD_IMAGE: - leaveValueList(); - append(Atom::Image, getArgument()); - append(Atom::ImageText, getRestOfLine()); - break; - case CMD_IMPORTANT: - leavePara(); - enterPara(Atom::ImportantLeft, Atom::ImportantRight); - break; - case CMD_INCLUDE: - case CMD_INPUT: { - QString fileName = getArgument(); - QString identifier = getRestOfLine(); - include(fileName, identifier); - break; - } - case CMD_INLINEIMAGE: - enterPara(); - append(Atom::InlineImage, getArgument()); - append(Atom::ImageText, getRestOfLine()); - append(Atom::String, " "); - break; - case CMD_INDEX: - if (paraState == OutsideParagraph) { - enterPara(); - indexStartedPara = true; - } else { - const Atom *last = priv->text.lastAtom(); - if (indexStartedPara && - (last->type() != Atom::FormattingRight || - last->string() != ATOM_FORMATTING_INDEX)) - indexStartedPara = false; - } - startFormat(ATOM_FORMATTING_INDEX, cmd); - break; - case CMD_KEYWORD: - insertTarget(getRestOfLine(),true); - break; - case CMD_L: - enterPara(); - if (isLeftBracketAhead()) - p2 = getBracketedArgument(); - if (isLeftBraceAhead()) { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) - location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(priv->text.lastAtom()->error())); - if (isLeftBraceAhead()) { - currentLinkAtom = priv->text.lastAtom(); - startFormat(ATOM_FORMATTING_LINK, cmd); - } - else { - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - } else { - p1 = getArgument(); - append(p1, p2); - if (!p2.isEmpty() && !(priv->text.lastAtom()->error().isEmpty())) - location().warning(tr("Check parameter in '[ ]' of '\\l' command: '%1', " - "possible misspelling, or unrecognized module name") - .arg(priv->text.lastAtom()->error())); - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - append(Atom::String, cleanLink(p1)); - append(Atom::FormattingRight, ATOM_FORMATTING_LINK); - } - p2.clear(); - break; - case CMD_LEGALESE: - leavePara(); - if (openCommand(cmd)) - append(Atom::LegaleseLeft); - docPrivate->hasLegalese = true; - break; - case CMD_LINK: - if (openCommand(cmd)) { - enterPara(); - p1 = getArgument(); - append(p1); - append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - skipSpacesOrOneEndl(); - } - break; - case CMD_LIST: - if (openCommand(cmd)) { - leavePara(); - openedLists.push(OpenedList(location(), - getOptionalArgument())); - } - break; - case CMD_TOPICREF: - case CMD_MAPREF: - if (openCommand(cmd)) { - DitaRef* t = nullptr; - if (cmd == CMD_MAPREF) - t = new MapRef(); - else - t = new TopicRef(); - t->setNavtitle(getArgument(true)); - if (cmd == CMD_MAPREF) - t->setHref(getArgument()); - else - t->setHref(getOptionalArgument()); - if (ditarefs_.isEmpty()) - priv->ditamap_.append(t); - else - ditarefs_.top()->appendSubref(t); - ditarefs_.push(t); - } - break; - case CMD_META: - priv->constructExtra(); - p1 = getArgument(); - priv->extra->metaMap_.insert(p1, getArgument()); - break; - case CMD_NEWCODE: - location().warning(tr("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE))); - break; - case CMD_NOTE: - leavePara(); - enterPara(Atom::NoteLeft, Atom::NoteRight); - break; - case CMD_O: - location().warning(tr("'\\o' is deprecated. Use '\\li'")); - Q_FALLTHROUGH(); - case CMD_LI: - leavePara(); - if (openedCommands.top() == CMD_LIST) { - if (openedLists.top().isStarted()) - append(Atom::ListItemRight, openedLists.top().styleString()); - else - append(Atom::ListLeft, openedLists.top().styleString()); - openedLists.top().next(); - append(Atom::ListItemNumber, openedLists.top().numberString()); - append(Atom::ListItemLeft, openedLists.top().styleString()); - enterPara(); - } else if (openedCommands.top() == CMD_TABLE) { - p1 = "1,1"; - p2.clear(); - if (isLeftBraceAhead()) { - p1 = getArgument(); - if (isLeftBraceAhead()) - p2 = getArgument(); - } - - if (!inTableHeader && !inTableRow) { - location().warning(tr("Missing '\\%1' or '\\%2' before '\\%3'") - .arg(cmdName(CMD_HEADER)) - .arg(cmdName(CMD_ROW)) - .arg(cmdName(CMD_LI))); - append(Atom::TableRowLeft); - inTableRow = true; - } else if (inTableItem) { - append(Atom::TableItemRight); - inTableItem = false; - } - - append(Atom::TableItemLeft, p1, p2); - inTableItem = true; - } else - location().warning(tr("Command '\\%1' outside of '\\%2' and '\\%3'") - .arg(cmdName(cmd)) - .arg(cmdName(CMD_LIST)) - .arg(cmdName(CMD_TABLE))); - break; - case CMD_OLDCODE: - leavePara(); - append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); - append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); - break; - case CMD_OMIT: - getUntilEnd(cmd); - break; - case CMD_OMITVALUE: - p1 = getArgument(); - if (!priv->enumItemList.contains(p1)) - priv->enumItemList.append(p1); - if (!priv->omitEnumItemList.contains(p1)) - priv->omitEnumItemList.append(p1); - break; - case CMD_PRINTLINE: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(quoter.quoteLine(location(), cmdStr, rest)); - break; - } - case CMD_PRINTTO: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(quoter.quoteTo(location(), cmdStr, rest)); - break; - } - case CMD_PRINTUNTIL: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - appendToCode(quoter.quoteUntil(location(), cmdStr, rest)); - break; - } - case CMD_QUOTATION: - if (openCommand(cmd)) { - leavePara(); - append(Atom::QuotationLeft); - } - break; - case CMD_QUOTEFILE: { - leavePara(); - QString fileName = getArgument(); - Doc::quoteFromFile(location(), quoter, fileName); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, fileName); - } - append(Atom::Code, quoter.quoteTo(location(), cmdStr, QString())); - quoter.reset(); - break; - } - case CMD_QUOTEFROMFILE: { - leavePara(); - QString arg = getArgument(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, arg); - } - Doc::quoteFromFile(location(), quoter, arg); - break; - } - case CMD_QUOTEFUNCTION: { - leavePara(); - marker = quoteFromFile(); - p1 = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, slashed(marker->functionEndRegExp(p1))); - } - quoter.quoteTo(location(), cmdStr, slashed(marker->functionBeginRegExp(p1))); - append(Atom::Code, quoter.quoteUntil(location(), cmdStr, slashed(marker->functionEndRegExp(p1)))); - quoter.reset(); - break; - } - case CMD_RAW: - leavePara(); - p1 = getRestOfLine(); - if (p1.isEmpty()) - location().warning(tr("Missing format name after '\\%1'") - .arg(cmdName(CMD_RAW))); - append(Atom::FormatIf, p1); - append(Atom::RawString, untabifyEtc(getUntilEnd(cmd))); - append(Atom::FormatElse); - append(Atom::FormatEndif); - break; - case CMD_ROW: - if (openedCommands.top() == CMD_TABLE) { - p1.clear(); - if (isLeftBraceAhead()) - p1 = getArgument(true); - leaveTableRow(); - append(Atom::TableRowLeft,p1); - inTableRow = true; - } else { - if (openedCommands.contains(CMD_TABLE)) - location().warning(tr("Cannot use '\\%1' within '\\%2'") - .arg(cmdName(CMD_ROW)) - .arg(cmdName(openedCommands.top()))); - else - location().warning(tr("Cannot use '\\%1' outside of '\\%2'") - .arg(cmdName(CMD_ROW)) - .arg(cmdName(CMD_TABLE))); - } - break; - case CMD_SA: - parseAlso(); - break; - case CMD_SECTION1: - startSection(Doc::Section1, cmd); - break; - case CMD_SECTION2: - startSection(Doc::Section2, cmd); - break; - case CMD_SECTION3: - startSection(Doc::Section3, cmd); - break; - case CMD_SECTION4: - startSection(Doc::Section4, cmd); - break; - case CMD_SIDEBAR: - if (openCommand(cmd)) { - leavePara(); - append(Atom::SidebarLeft); - } - break; - case CMD_SKIPLINE: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - quoter.quoteLine(location(), cmdStr, rest); - break; - } - case CMD_SKIPTO: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - quoter.quoteTo(location(), cmdStr, rest); - break; - } - case CMD_SKIPUNTIL: { - leavePara(); - QString rest = getRestOfLine(); - if (quoting) { - append(Atom::CodeQuoteCommand, cmdStr); - append(Atom::CodeQuoteArgument, rest); - } - quoter.quoteUntil(location(), cmdStr, rest); - break; - } - case CMD_SPAN: - p1 = ATOM_FORMATTING_SPAN + getArgument(true); - startFormat(p1, cmd); - break; - case CMD_SNIPPET: { - leavePara(); - QString snippet = getArgument(); - QString identifier = getRestOfLine(); - if (quoting) { - append(Atom::SnippetCommand, cmdStr); - append(Atom::SnippetLocation, snippet); - append(Atom::SnippetIdentifier, identifier); - } - marker = Doc::quoteFromFile(location(), quoter, snippet); - appendToCode(quoter.quoteSnippet(location(), identifier), marker->atomType()); - break; - } - case CMD_SUB: - startFormat(ATOM_FORMATTING_SUBSCRIPT, cmd); - break; - case CMD_SUP: - startFormat(ATOM_FORMATTING_SUPERSCRIPT, cmd); - break; - case CMD_TABLE: - p1 = getOptionalArgument(); - p2 = getOptionalArgument(); - if (openCommand(cmd)) { - leavePara(); - append(Atom::TableLeft, p1, p2); - inTableHeader = false; - inTableRow = false; - inTableItem = false; - } - break; - case CMD_TABLEOFCONTENTS: - p1 = "1"; - if (isLeftBraceAhead()) - p1 = getArgument(); - p1 += QLatin1Char(','); - p1 += QString::number((int)getSectioningUnit()); - append(Atom::TableOfContents, p1); - break; - case CMD_TARGET: - insertTarget(getRestOfLine(),false); - break; - case CMD_TT: - startFormat(ATOM_FORMATTING_TELETYPE, cmd); - break; - case CMD_UICONTROL: - startFormat(ATOM_FORMATTING_UICONTROL, cmd); - break; - case CMD_UNDERLINE: - startFormat(ATOM_FORMATTING_UNDERLINE, cmd); - break; - case CMD_UNICODE: { - enterPara(); - p1 = getArgument(); - bool ok; - uint unicodeChar = p1.toUInt(&ok, 0); - if (!ok || (unicodeChar == 0x0000) || (unicodeChar > 0xFFFE)) - location().warning(tr("Invalid Unicode character '%1' specified with '%2'") - .arg(p1, cmdName(CMD_UNICODE))); - else - append(Atom::String, QChar(unicodeChar)); - break; - } - case CMD_VALUE: - leaveValue(); - if (openedLists.top().style() == OpenedList::Value) { - QString p2; - p1 = getArgument(); - if (p1.startsWith(QLatin1String("[since ")) && p1.endsWith(QLatin1String("]"))) { - p2 = p1.mid(7, p1.length() - 8); - p1 = getArgument(); - } - if (!priv->enumItemList.contains(p1)) - priv->enumItemList.append(p1); - - openedLists.top().next(); - append(Atom::ListTagLeft, ATOM_LIST_VALUE); - append(Atom::String, p1); - append(Atom::ListTagRight, ATOM_LIST_VALUE); - if (!p2.isEmpty()) { - append(Atom::SinceTagLeft, ATOM_LIST_VALUE); - append(Atom::String, p2); - append(Atom::SinceTagRight, ATOM_LIST_VALUE); - } - append(Atom::ListItemLeft, ATOM_LIST_VALUE); - - skipSpacesOrOneEndl(); - if (isBlankLine()) - append(Atom::Nop); - } else { - // ### unknown problems - } - break; - case CMD_WARNING: - leavePara(); - enterPara(); - append(Atom::FormattingLeft, ATOM_FORMATTING_BOLD); - append(Atom::String, "Warning:"); - append(Atom::FormattingRight, ATOM_FORMATTING_BOLD); - append(Atom::String, " "); - break; - case CMD_OVERLOAD: - priv->metacommandsUsed.insert(cmdStr); - p1.clear(); - if (!isBlankLine()) - p1 = getRestOfLine(); - if (!p1.isEmpty()) { - append(Atom::ParaLeft); - append(Atom::String, "This function overloads "); - append(Atom::AutoLink,p1); - append(Atom::String, "."); - append(Atom::ParaRight); - } else { - append(Atom::ParaLeft); - append(Atom::String,"This is an overloaded function."); - append(Atom::ParaRight); - p1 = getMetaCommandArgument(cmdStr); - } - priv->metaCommandMap[cmdStr].append(ArgLocPair(p1,location())); - break; - case NOT_A_CMD: - if (metaCommandSet.contains(cmdStr)) { - priv->metacommandsUsed.insert(cmdStr); - QString arg = getMetaCommandArgument(cmdStr); - priv->metaCommandMap[cmdStr].append(ArgLocPair(arg,location())); - if (possibleTopics.contains(cmdStr)) { - if (!cmdStr.endsWith(QLatin1String("propertygroup"))) - priv->topics_.append(Topic(cmdStr,arg)); - } - } else if (macroHash()->contains(cmdStr)) { - const Macro ¯o = macroHash()->value(cmdStr); - int numPendingFi = 0; - QStringMap::ConstIterator d; - int numFormatDefs = 0; - QString matchExpr; - d = macro.otherDefs.constBegin(); - while (d != macro.otherDefs.constEnd()) { - if (d.key() == "match") { - matchExpr = d.value(); - ++d; - } else { - append(Atom::FormatIf, d.key()); - expandMacro(cmdStr, *d, macro.numParams); - ++d; - ++numFormatDefs; - if (d == macro.otherDefs.constEnd()) { - append(Atom::FormatEndif); - } else { - append(Atom::FormatElse); - numPendingFi++; - } - } - } - while (numPendingFi-- > 0) - append(Atom::FormatEndif); - - if (!macro.defaultDef.isEmpty()) { - if (numFormatDefs > 0) { - macro.defaultDefLocation.warning( - tr("Macro cannot have both " - "format-specific and qdoc-" - "syntax definitions")); - } else { - QString expanded = expandMacroToString(cmdStr, - macro.defaultDef, - macro.numParams, - matchExpr); - input_.replace(backslashPos, endPos - backslashPos, expanded); - len = input_.length(); - pos = backslashPos; - } - } - } else { - int curPos = 0; - int numUppercase = 0; - int numLowercase = 0; - int numStrangeSymbols = 0; - - while (curPos < cmdStr.size()) { - unsigned char latin1Ch = cmdStr.at(curPos).toLatin1(); - if (islower(latin1Ch)) { - ++numLowercase; - ++curPos; - } else if (isupper(latin1Ch)) { - ++numUppercase; - ++curPos; - } else if (isdigit(latin1Ch)) { - if (curPos > 0) - ++curPos; - else - break; - } else if (latin1Ch == '_' || latin1Ch == '@') { - ++numStrangeSymbols; - ++curPos; - } else if ((latin1Ch == ':') && - (curPos < cmdStr.size() - 1) && - (cmdStr.at(curPos + 1) == QLatin1Char(':'))) { - ++numStrangeSymbols; - curPos += 2; - } else if (latin1Ch == '(') { - if (curPos > 0) { - if ((curPos < cmdStr.size() - 1) && - (cmdStr.at(curPos + 1) == QLatin1Char(')'))) { - ++numStrangeSymbols; - pos += 2; - break; - } else { - // ### handle functions with signatures - // and function calls - break; - } - } else { - break; - } - } else { - break; - } - } - if ((numUppercase >= 1 && numLowercase >= 2) || numStrangeSymbols > 0) { - appendWord(cmdStr); - } else { - if (!cmdStr.endsWith("propertygroup")) { - // The QML and JS property group commands are no longer required - // for grouping QML and JS properties. They are allowed but ignored. - location().warning(tr("Unknown command '\\%1'").arg(cmdStr), - detailsUnknownCommand(metaCommandSet,cmdStr)); - } - enterPara(); - append(Atom::UnknownCommand, cmdStr); - } - } - } - } // case '\\' (qdoc markup command) - break; - } - case '{': - enterPara(); - appendChar('{'); - braceDepth++; - pos++; - break; - case '}': { - braceDepth--; - pos++; - - QMap::Iterator f = pendingFormats.find(braceDepth); - if (f == pendingFormats.end()) { - enterPara(); - appendChar('}'); - } else { - append(Atom::FormattingRight, *f); - if (*f == ATOM_FORMATTING_INDEX) { - if (indexStartedPara) - skipAllSpaces(); - } else if (*f == ATOM_FORMATTING_LINK) { - // hack for C++ to support links like - // \l{QString::}{count()} - if (currentLinkAtom && - currentLinkAtom->string().endsWith("::")) { - QString suffix = Text::subText(currentLinkAtom, - priv->text.lastAtom()).toString(); - currentLinkAtom->appendString(suffix); - } - currentLinkAtom = nullptr; - } - pendingFormats.erase(f); - } - break; - } - // Do not parse content after '//!' comments - case '/': { - if (pos + 2 < len) - if (input_.at(pos + 1) == '/') - if (input_.at(pos + 2) == '!') { - pos += 2; - getRestOfLine(); - break; - } - Q_FALLTHROUGH(); // fall through - } - default: { - bool newWord; - switch (priv->text.lastAtom()->type()) { - case Atom::ParaLeft: - newWord = true; - break; - default: - newWord = false; - } - - if (paraState == OutsideParagraph) { - if (ch.isSpace()) { - ++pos; - newWord = false; - } else { - enterPara(); - newWord = true; - } - } else { - if (ch.isSpace()) { - ++pos; - if ((ch == '\n') && - (paraState == InSingleLineParagraph || - isBlankLine())) { - leavePara(); - newWord = false; - } else { - appendChar(' '); - newWord = true; - } - } else { - newWord = true; - } - } - - if (newWord) { - int startPos = pos; - int numInternalUppercase = 0; - int numLowercase = 0; - int numStrangeSymbols = 0; - - while (pos < len) { - unsigned char latin1Ch = input_.at(pos).toLatin1(); - if (islower(latin1Ch)) { - ++numLowercase; - ++pos; - } else if (isupper(latin1Ch)) { - if (pos > startPos) - ++numInternalUppercase; - ++pos; - } else if (isdigit(latin1Ch)) { - if (pos > startPos) - ++pos; - else - break; - } else if (latin1Ch == '_' || latin1Ch == '@') { - ++numStrangeSymbols; - ++pos; - } else if (latin1Ch == ':' && pos < len - 1 && input_.at(pos + 1) == QLatin1Char(':')) { - ++numStrangeSymbols; - pos += 2; - } else if (latin1Ch == '(') { - if (pos > startPos) { - if (pos < len - 1 && input_.at(pos + 1) == QLatin1Char(')')) { - ++numStrangeSymbols; - pos += 2; - break; - } else { - // ### handle functions with signatures - // and function calls - break; - } - } else { - break; - } - } else { - break; - } - } - - if (pos == startPos) { - if (!ch.isSpace()) { - appendChar(ch); - ++pos; - } - } else { - QString word = input_.mid(startPos, pos - startPos); - // is word a C++ symbol or an English word? - if ((numInternalUppercase >= 1 && numLowercase >= 2) || numStrangeSymbols > 0) { - if (word.startsWith(QString("__"))) - appendWord(word); - else - append(Atom::AutoLink, word); - } - else { - appendWord(word); - } - } - } - } // default: - } // switch (ch.unicode()) - } - leaveValueList(); - - // for compatibility - if (openedCommands.top() == CMD_LEGALESE) { - append(Atom::LegaleseRight); - openedCommands.pop(); - } - - if (openedCommands.top() != CMD_OMIT) { - location().warning(tr("Missing '\\%1'").arg(endCmdName(openedCommands.top()))); - } - else if (preprocessorSkipping.count() > 0) { - location().warning(tr("Missing '\\%1'").arg(cmdName(CMD_ENDIF))); - } - - if (currentSection > Doc::NoSection) { - append(Atom::SectionRight, QString::number(currentSection)); - currentSection = Doc::NoSection; - } - - if (priv->extra && priv->extra->granularity_ < priv->extra->section_) - priv->extra->granularity_ = priv->extra->section_; - priv->text.stripFirstAtom(); -} - -/*! - Returns the current location. - */ -Location &DocParser::location() -{ - while (!openedInputs.isEmpty() && openedInputs.top() <= pos) { - cachedLoc.pop(); - cachedPos = openedInputs.pop(); - } - while (cachedPos < pos) - cachedLoc.advance(input_.at(cachedPos++)); - return cachedLoc; -} - -QString DocParser::detailsUnknownCommand(const QSet &metaCommandSet, - const QString &str) -{ - QSet commandSet = metaCommandSet; - int i = 0; - while (cmds[i].english != nullptr) { - commandSet.insert(*cmds[i].alias); - i++; - } - - if (aliasMap()->contains(str)) - return tr("The command '\\%1' was renamed '\\%2' by the configuration" - " file. Use the new name.") - .arg(str).arg((*aliasMap())[str]); - - QString best = nearestName(str, commandSet); - if (best.isEmpty()) - return QString(); - return tr("Maybe you meant '\\%1'?").arg(best); -} - -void DocParser::insertTarget(const QString &target, bool keyword) -{ - if (targetMap_.contains(target)) { - location().warning(tr("Duplicate target name '%1'").arg(target)); - targetMap_[target].warning(tr("(The previous occurrence is here)")); - } - else { - targetMap_.insert(target, location()); - priv->constructExtra(); - if (keyword) { - append(Atom::Keyword, target); - priv->extra->keywords_.append(priv->text.lastAtom()); - } - else { - append(Atom::Target, target); - priv->extra->targets_.append(priv->text.lastAtom()); - } - } -} - -void DocParser::include(const QString& fileName, const QString& identifier) -{ - if (location().depth() > 16) - location().fatal(tr("Too many nested '\\%1's").arg(cmdName(CMD_INCLUDE))); - - QString userFriendlyFilePath; - QString filePath = Doc::config()->getIncludeFilePath(fileName); -#if 0 - QString filePath = Config::findFile(location(), - sourceFiles, - sourceDirs, - fileName, - userFriendlyFilePath); -#endif - if (filePath.isEmpty()) { - location().warning(tr("Cannot find qdoc include file '%1'").arg(fileName)); - } - else { - QFile inFile(filePath); - if (!inFile.open(QFile::ReadOnly)) { - location().warning(tr("Cannot open qdoc include file '%1'") - .arg(userFriendlyFilePath)); - } - else { - location().push(userFriendlyFilePath); - - QTextStream inStream(&inFile); - QString includedStuff = inStream.readAll(); - inFile.close(); - - if (identifier.isEmpty()) { - input_.insert(pos, includedStuff); - len = input_.length(); - openedInputs.push(pos + includedStuff.length()); - } - else { - QStringList lineBuffer = includedStuff.split(QLatin1Char('\n')); - int i = 0; - int startLine = -1; - while (i < lineBuffer.size()) { - if (lineBuffer[i].startsWith("//!")) { - if (lineBuffer[i].contains(identifier)) { - startLine = i+1; - break; - } - } - ++i; - } - if (startLine < 0) { - location().warning(tr("Cannot find '%1' in '%2'") - .arg(identifier) - .arg(userFriendlyFilePath)); - return; - - } - QString result; - i = startLine; - do { - if (lineBuffer[i].startsWith("//!")) { - if (i::ConstIterator f = pendingFormats.constBegin(); - while (f != pendingFormats.constEnd()) { - if (*f == format) { - location().warning(tr("Cannot nest '\\%1' commands") - .arg(cmdName(cmd))); - return; - } - ++f; - } - - append(Atom::FormattingLeft, format); - - if (isLeftBraceAhead()) { - skipSpacesOrOneEndl(); - pendingFormats.insert(braceDepth, format); - ++braceDepth; - ++pos; - } - else { - append(Atom::String, getArgument()); - append(Atom::FormattingRight, format); - if (format == ATOM_FORMATTING_INDEX && indexStartedPara) { - skipAllSpaces(); - indexStartedPara = false; - } - } -} - -bool DocParser::openCommand(int cmd) -{ - int outer = openedCommands.top(); - bool ok = true; - - if (cmd != CMD_LINK) { - if (outer == CMD_LIST) { - ok = (cmd == CMD_FOOTNOTE || cmd == CMD_LIST); - } - else if (outer == CMD_SIDEBAR) { - ok = (cmd == CMD_LIST || - cmd == CMD_QUOTATION || - cmd == CMD_SIDEBAR); - } - else if (outer == CMD_QUOTATION) { - ok = (cmd == CMD_LIST); - } - else if (outer == CMD_TABLE) { - ok = (cmd == CMD_LIST || - cmd == CMD_FOOTNOTE || - cmd == CMD_QUOTATION); - } - else if (outer == CMD_FOOTNOTE || outer == CMD_LINK) { - ok = false; - } - else if (outer == CMD_TOPICREF) - ok = (cmd == CMD_TOPICREF || cmd == CMD_MAPREF); - else if (outer == CMD_MAPREF) - ok = false; - } - - if (ok) { - openedCommands.push(cmd); - } - else { - location().warning(tr("Can't use '\\%1' in '\\%2'").arg(cmdName(cmd)).arg(cmdName(outer))); - } - return ok; -} - -bool DocParser::closeCommand(int endCmd) -{ - if (endCmdFor(openedCommands.top()) == endCmd && openedCommands.size() > 1) { - openedCommands.pop(); - return true; - } - else { - bool contains = false; - QStack opened2 = openedCommands; - while (opened2.size() > 1) { - if (endCmdFor(opened2.top()) == endCmd) { - contains = true; - break; - } - opened2.pop(); - } - - if (contains) { - while (endCmdFor(openedCommands.top()) != endCmd && openedCommands.size() > 1) { - location().warning(tr("Missing '\\%1' before '\\%2'") - .arg(endCmdName(openedCommands.top())) - .arg(cmdName(endCmd))); - openedCommands.pop(); - } - } - else { - location().warning(tr("Unexpected '\\%1'").arg(cmdName(endCmd))); - } - return false; - } -} - -void DocParser::startSection(Doc::Sections unit, int cmd) -{ - leaveValueList(); - - if (currentSection == Doc::NoSection) { - currentSection = (Doc::Sections) (unit); - priv->constructExtra(); - priv->extra->section_ = currentSection; - } - else - endSection(unit,cmd); - - append(Atom::SectionLeft, QString::number(unit)); - priv->constructExtra(); - priv->extra->tableOfContents_.append(priv->text.lastAtom()); - priv->extra->tableOfContentsLevels_.append(unit); - enterPara(Atom::SectionHeadingLeft, - Atom::SectionHeadingRight, - QString::number(unit)); - currentSection = unit; - -} - -void DocParser::endSection(int , int) // (int unit, int endCmd) -{ - leavePara(); - append(Atom::SectionRight, QString::number(currentSection)); - currentSection = (Doc::NoSection); -} - -void DocParser::parseAlso() -{ - leavePara(); - skipSpacesOnLine(); - while (pos < len && input_[pos] != '\n') { - QString target; - QString str; - bool skipMe = false; - - if (input_[pos] == '{') { - target = getArgument(); - skipSpacesOnLine(); - if (input_[pos] == '{') { - str = getArgument(); - - // hack for C++ to support links like \l{QString::}{count()} - if (target.endsWith("::")) - target += str; - } - else { - str = target; - } - } - else { - target = getArgument(); - str = cleanLink(target); - if (target == QLatin1String("and") || target == QLatin1String(".")) - skipMe = true; - } - - if (!skipMe) { - Text also; - also << Atom(Atom::Link, target) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << str - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - priv->addAlso(also); - } - - skipSpacesOnLine(); - if (pos < len && input_[pos] == ',') { - pos++; - skipSpacesOrOneEndl(); - } - else if (input_[pos] != '\n') { - location().warning(tr("Missing comma in '\\%1'").arg(cmdName(CMD_SA))); - } - } -} - -void DocParser::append(Atom::AtomType type, const QString &string) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(type, string); -} - -void DocParser::append(const QString &string) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(string); // The Atom type is Link. -} - -void DocParser::append(Atom::AtomType type, const QString& p1, const QString& p2) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - priv->text << Atom(type, p1, p2); -} - -void DocParser::append(const QString& p1, const QString& p2) -{ - Atom::AtomType lastType = priv->text.lastAtom()->type(); - if ((lastType == Atom::Code) && priv->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) - priv->text.lastAtom()->chopString(); - if (p2.isEmpty()) - priv->text << Atom(p1); // The Atom type is Link. - else - priv->text << LinkAtom(p1, p2); -} - -void DocParser::appendChar(QChar ch) -{ - if (priv->text.lastAtom()->type() != Atom::String) - append(Atom::String); - Atom *atom = priv->text.lastAtom(); - if (ch == QLatin1Char(' ')) { - if (!atom->string().endsWith(QLatin1Char(' '))) - atom->appendChar(QLatin1Char(' ')); - } - else - atom->appendChar(ch); -} - -void DocParser::appendWord(const QString &word) -{ - if (priv->text.lastAtom()->type() != Atom::String) { - append(Atom::String, word); - } - else - priv->text.lastAtom()->appendString(word); -} - -void DocParser::appendToCode(const QString& markedCode) -{ - if (!isCode(lastAtom)) { - append(Atom::Code); - lastAtom = priv->text.lastAtom(); - } - lastAtom->appendString(markedCode); -} - -void DocParser::appendToCode(const QString &markedCode, Atom::AtomType defaultType) -{ - if (!isCode(lastAtom)) { - append(defaultType, markedCode); - lastAtom = priv->text.lastAtom(); - } else { - lastAtom->appendString(markedCode); - } -} - -void DocParser::startNewPara() -{ - leavePara(); - enterPara(); -} - -void DocParser::enterPara(Atom::AtomType leftType, - Atom::AtomType rightType, - const QString& string) -{ - if (paraState == OutsideParagraph) { - - if ((priv->text.lastAtom()->type() != Atom::ListItemLeft) && - (priv->text.lastAtom()->type() != Atom::DivLeft)) { - leaveValueList(); - } - - append(leftType, string); - indexStartedPara = false; - pendingParaLeftType = leftType; - pendingParaRightType = rightType; - pendingParaString = string; - if (leftType == Atom::SectionHeadingLeft) { - paraState = InSingleLineParagraph; - } - else { - paraState = InMultiLineParagraph; - } - skipSpacesOrOneEndl(); - } -} - -void DocParser::leavePara() -{ - if (paraState != OutsideParagraph) { - if (!pendingFormats.isEmpty()) { - location().warning(tr("Missing '}'")); - pendingFormats.clear(); - } - - if (priv->text.lastAtom()->type() == pendingParaLeftType) { - priv->text.stripLastAtom(); - } - else { - if (priv->text.lastAtom()->type() == Atom::String && - priv->text.lastAtom()->string().endsWith(QLatin1Char(' '))) { - priv->text.lastAtom()->chopString(); - } - append(pendingParaRightType, pendingParaString); - } - paraState = OutsideParagraph; - indexStartedPara = false; - pendingParaRightType = Atom::Nop; - pendingParaString.clear(); - } -} - -void DocParser::leaveValue() -{ - leavePara(); - if (openedLists.isEmpty()) { - openedLists.push(OpenedList(OpenedList::Value)); - append(Atom::ListLeft, ATOM_LIST_VALUE); - } - else { - if (priv->text.lastAtom()->type() == Atom::Nop) - priv->text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - } -} - -void DocParser::leaveValueList() -{ - leavePara(); - if (!openedLists.isEmpty() && - (openedLists.top().style() == OpenedList::Value)) { - if (priv->text.lastAtom()->type() == Atom::Nop) - priv->text.stripLastAtom(); - append(Atom::ListItemRight, ATOM_LIST_VALUE); - append(Atom::ListRight, ATOM_LIST_VALUE); - openedLists.pop(); - } -} - -void DocParser::leaveTableRow() -{ - if (inTableItem) { - leavePara(); - append(Atom::TableItemRight); - inTableItem = false; - } - if (inTableHeader) { - append(Atom::TableHeaderRight); - inTableHeader = false; - } - if (inTableRow) { - append(Atom::TableRowRight); - inTableRow = false; - } -} - -CodeMarker *DocParser::quoteFromFile() -{ - return Doc::quoteFromFile(location(), quoter, getArgument()); -} - -/*! - Expands a macro in-place in input. - - Expects the current \e pos in the input to point to a backslash, and the macro to have a - default definition. Format-specific macros are currently not expanded. - - \note In addition to macros, a valid use for a backslash in an argument include - escaping non-alnum characters, and splitting a single argument across multiple - lines by escaping newlines. Escaping is also handled here. - - Returns \c true on successful macro expansion. - */ -bool DocParser::expandMacro() -{ - Q_ASSERT(input_[pos].unicode() == '\\'); - - QString cmdStr; - int backslashPos = pos++; - while (pos < (int) input_.length() && input_[pos].isLetterOrNumber()) - cmdStr += input_[pos++]; - - endPos = pos; - if (!cmdStr.isEmpty()) { - if (macroHash()->contains(cmdStr)) { - const Macro ¯o = macroHash()->value(cmdStr); - if (!macro.defaultDef.isEmpty()) { - QString expanded = expandMacroToString(cmdStr, - macro.defaultDef, - macro.numParams, - macro.otherDefs.value("match")); - input_.replace(backslashPos, pos - backslashPos, expanded); - len = input_.length(); - pos = backslashPos; - return true; - } else { - location().warning(tr("Macro '%1' does not have a default definition").arg(cmdStr)); - } - } else { - location().warning(tr("Unknown macro '%1'").arg(cmdStr)); - pos = ++backslashPos; - } - } else if (input_[pos].isSpace()) { - skipAllSpaces(); - } else if (input_[pos].unicode() == '\\') { - // allow escaping a backslash - input_.remove(pos--, 1); - --len; - } - return false; -} - -void DocParser::expandMacro(const QString &name, - const QString &def, - int numParams) -{ - if (numParams == 0) { - append(Atom::RawString, def); - } - else { - QStringList args; - QString rawString; - - for (int i = 0; i < numParams; i++) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(true); - } - else { - location().warning(tr("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name).arg(numParams).arg(i)); - numParams = i; - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && - (paramNo <= numParams)) { - if (!rawString.isEmpty()) { - append(Atom::RawString, rawString); - rawString.clear(); - } - append(Atom::String, args[paramNo - 1]); - j += 1; - } - else { - rawString += def[j++]; - } - } - if (!rawString.isEmpty()) - append(Atom::RawString, rawString); - } -} - -QString DocParser::expandMacroToString(const QString &name, const QString &def, int numParams, const QString &matchExpr) -{ - QString rawString; - - if (numParams == 0) { - rawString = def; - } else { - QStringList args; - for (int i = 0; i < numParams; i++) { - if (numParams == 1 || isLeftBraceAhead()) { - args << getArgument(true); - } - else { - location().warning(tr("Macro '\\%1' invoked with too few" - " arguments (expected %2, got %3)") - .arg(name).arg(numParams).arg(i)); - numParams = i; - break; - } - } - - int j = 0; - while (j < def.size()) { - int paramNo; - if (((paramNo = def[j].unicode()) >= 1) && - (paramNo <= numParams)) { - rawString += args[paramNo - 1]; - j += 1; - } - else { - rawString += def[j++]; - } - } - } - if (matchExpr.isEmpty()) - return rawString; - - QString result; - QRegExp re(matchExpr); - int capStart = (re.captureCount() > 0) ? 1 : 0; - int i = 0; - while ((i = re.indexIn(rawString, i)) != -1) { - for (int c = capStart; c <= re.captureCount(); ++c) - result += re.cap(c); - i += re.matchedLength(); - } - - return result; -} - -Doc::Sections DocParser::getSectioningUnit() -{ - QString name = getOptionalArgument(); - - if (name == "section1") { - return Doc::Section1; - } - else if (name == "section2") { - return Doc::Section2; - } - else if (name == "section3") { - return Doc::Section3; - } - else if (name == "section4") { - return Doc::Section4; - } - else if (name.isEmpty()) { - return Doc::NoSection; - } - else { - location().warning(tr("Invalid section '%1'").arg(name)); - return Doc::NoSection; - } -} - -/*! - Gets an argument that is enclosed in braces and returns it - without the enclosing braces. On entry, the current character - is the left brace. On exit, the current character is the one - that comes after the right brace. - - If \a verbatim is true, extra whitespace is retained in the - returned string. Otherwise, extra whitespace is removed. - */ -QString DocParser::getBracedArgument(bool verbatim) -{ - QString arg; - int delimDepth = 0; - if (pos < (int) input_.length() && input_[pos] == '{') { - pos++; - while (pos < (int) input_.length() && delimDepth >= 0) { - switch (input_[pos].unicode()) { - case '{': - delimDepth++; - arg += QLatin1Char('{'); - pos++; - break; - case '}': - delimDepth--; - if (delimDepth >= 0) - arg += QLatin1Char('}'); - pos++; - break; - case '\\': - if (verbatim || !expandMacro()) - arg += input_[pos++]; - break; - default: - if (input_[pos].isSpace() && !verbatim) - arg += QChar(' '); - else - arg += input_[pos]; - pos++; - } - } - if (delimDepth > 0) - location().warning(tr("Missing '}'")); - } - endPos = pos; - return arg; -} - -/*! - Typically, an argument ends at the next white-space. However, - braces can be used to group words: - - {a few words} - - Also, opening and closing parentheses have to match. Thus, - - printf("%d\n", x) - - is an argument too, although it contains spaces. Finally, - trailing punctuation is not included in an argument, nor is 's. -*/ -QString DocParser::getArgument(bool verbatim) -{ - skipSpacesOrOneEndl(); - - int delimDepth = 0; - int startPos = pos; - QString arg = getBracedArgument(verbatim); - if (arg.isEmpty()) { - while ((pos < input_.length()) && - ((delimDepth > 0) || ((delimDepth == 0) && !input_[pos].isSpace()))) { - switch (input_[pos].unicode()) { - case '(': - case '[': - case '{': - delimDepth++; - arg += input_[pos]; - pos++; - break; - case ')': - case ']': - case '}': - delimDepth--; - if (pos == startPos || delimDepth >= 0) { - arg += input_[pos]; - pos++; - } - break; - case '\\': - if (verbatim || !expandMacro()) - arg += input_[pos++]; - break; - default: - arg += input_[pos]; - pos++; - } - } - endPos = pos; - if ((arg.length() > 1) && - (QString(".,:;!?").indexOf(input_[pos - 1]) != -1) && - !arg.endsWith("...")) { - arg.truncate(arg.length() - 1); - pos--; - } - if (arg.length() > 2 && input_.mid(pos - 2, 2) == "'s") { - arg.truncate(arg.length() - 2); - pos -= 2; - } - } - return arg.simplified(); -} - -/*! - Gets an argument that is enclosed in brackets and returns it - without the enclosing brackets. On entry, the current character - is the left bracket. On exit, the current character is the one - that comes after the right bracket. - */ -QString DocParser::getBracketedArgument() -{ - QString arg; - int delimDepth = 0; - skipSpacesOrOneEndl(); - if (pos < input_.length() && input_[pos] == '[') { - pos++; - while (pos < input_.length() && delimDepth >= 0) { - switch (input_[pos].unicode()) { - case '[': - delimDepth++; - arg += QLatin1Char('['); - pos++; - break; - case ']': - delimDepth--; - if (delimDepth >= 0) - arg += QLatin1Char(']'); - pos++; - break; - case '\\': - arg += input_[pos]; - pos++; - break; - default: - arg += input_[pos]; - pos++; - } - } - if (delimDepth > 0) - location().warning(tr("Missing ']'")); - } - return arg; -} - -QString DocParser::getOptionalArgument() -{ - skipSpacesOrOneEndl(); - if (pos + 1 < (int) input_.length() && input_[pos] == '\\' && - input_[pos + 1].isLetterOrNumber()) { - return QString(); - } - else { - return getArgument(); - } -} - -QString DocParser::getRestOfLine() -{ - QString t; - - skipSpacesOnLine(); - - bool trailingSlash = false; - - do { - int begin = pos; - - while (pos < input_.size() && input_[pos] != '\n') { - if (input_[pos] == '\\' && !trailingSlash) { - trailingSlash = true; - ++pos; - while ((pos < input_.size()) && - input_[pos].isSpace() && - (input_[pos] != '\n')) - ++pos; - } - else { - trailingSlash = false; - ++pos; - } - } - - if (!t.isEmpty()) - t += QLatin1Char(' '); - t += input_.mid(begin, pos - begin).simplified(); - - if (trailingSlash) { - t.chop(1); - t = t.simplified(); - } - if (pos < input_.size()) - ++pos; - } while (pos < input_.size() && trailingSlash); - - return t; -} - -/*! - The metacommand argument is normally the remaining text to - the right of the metacommand itself. The extra blanks are - stripped and the argument string is returned. - */ -QString DocParser::getMetaCommandArgument(const QString &cmdStr) -{ - skipSpacesOnLine(); - - int begin = pos; - int parenDepth = 0; - - while (pos < input_.size() && (input_[pos] != '\n' || parenDepth > 0)) { - if (input_.at(pos) == '(') - ++parenDepth; - else if (input_.at(pos) == ')') - --parenDepth; - else if (input_.at(pos) == '\\' && expandMacro()) - continue; - ++pos; - } - if (pos == input_.size() && parenDepth > 0) { - pos = begin; - location().warning(tr("Unbalanced parentheses in '%1'").arg(cmdStr)); - } - - QString t = input_.mid(begin, pos - begin).simplified(); - skipSpacesOnLine(); - return t; -} - -QString DocParser::getUntilEnd(int cmd) -{ - int endCmd = endCmdFor(cmd); - QRegExp rx("\\\\" + cmdName(endCmd) + "\\b"); - QString t; - int end = rx.indexIn(input_, pos); - - if (end == -1) { - location().warning(tr("Missing '\\%1'").arg(cmdName(endCmd))); - pos = input_.length(); - } - else { - t = input_.mid(pos, end - pos); - pos = end + rx.matchedLength(); - } - return t; -} - -QString DocParser::getCode(int cmd, CodeMarker *marker, const QString &argStr) -{ - QString code = untabifyEtc(getUntilEnd(cmd)); - - if (!argStr.isEmpty()) { - QStringList args = argStr.split(" ", QString::SkipEmptyParts); - int paramNo, j = 0; - while (j < code.size()) { - if (code[j] == '\\' - && j < code.size() - 1 - && (paramNo = code[j + 1].digitValue()) >= 1 - && paramNo <= args.size()) { - QString p = args[paramNo - 1]; - code.replace(j, 2, p); - j += qMin(1, p.size()); - } else { - ++j; - } - } - } - - int indent = indentLevel(code); - code = unindent(indent, code); - if (marker == nullptr) - marker = CodeMarker::markerForCode(code); - return marker->markedUpCode(code, nullptr, location()); -} - -/*! - Was used only for generating doxygen output. - */ -QString DocParser::getUnmarkedCode(int cmd) -{ - QString code = getUntilEnd(cmd); - return code; -} - -bool DocParser::isBlankLine() -{ - int i = pos; - - while (i < len && input_[i].isSpace()) { - if (input_[i] == '\n') - return true; - i++; - } - return false; -} - -bool DocParser::isLeftBraceAhead() -{ - int numEndl = 0; - int i = pos; - - while (i < len && input_[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (input_[i] == '\n') - numEndl++; - i++; - } - return numEndl < 2 && i < len && input_[i] == '{'; -} - -bool DocParser::isLeftBracketAhead() -{ - int numEndl = 0; - int i = pos; - - while (i < len && input_[i].isSpace() && numEndl < 2) { - // ### bug with '\\' - if (input_[i] == '\n') - numEndl++; - i++; - } - return numEndl < 2 && i < len && input_[i] == '['; -} - -/*! - Skips to the next non-space character or EOL. - */ -void DocParser::skipSpacesOnLine() -{ - while ((pos < input_.length()) && - input_[pos].isSpace() && - (input_[pos].unicode() != '\n')) - ++pos; -} - -/*! - Skips spaces and on EOL. - */ -void DocParser::skipSpacesOrOneEndl() -{ - int firstEndl = -1; - while (pos < (int) input_.length() && input_[pos].isSpace()) { - QChar ch = input_[pos]; - if (ch == '\n') { - if (firstEndl == -1) { - firstEndl = pos; - } - else { - pos = firstEndl; - break; - } - } - pos++; - } -} - -void DocParser::skipAllSpaces() -{ - while (pos < len && input_[pos].isSpace()) - pos++; -} - -void DocParser::skipToNextPreprocessorCommand() -{ - QRegExp rx("\\\\(?:" + cmdName(CMD_IF) + QLatin1Char('|') + - cmdName(CMD_ELSE) + QLatin1Char('|') + - cmdName(CMD_ENDIF) + ")\\b"); - int end = rx.indexIn(input_, pos + 1); // ### + 1 necessary? - - if (end == -1) - pos = input_.length(); - else - pos = end; -} - -int DocParser::endCmdFor(int cmd) -{ - switch (cmd) { - case CMD_BADCODE: - return CMD_ENDCODE; - case CMD_CODE: - return CMD_ENDCODE; - case CMD_DIV: - return CMD_ENDDIV; - case CMD_QML: - return CMD_ENDQML; - case CMD_QMLTEXT: - return CMD_ENDQMLTEXT; - case CMD_JS: - return CMD_ENDJS; - case CMD_FOOTNOTE: - return CMD_ENDFOOTNOTE; - case CMD_LEGALESE: - return CMD_ENDLEGALESE; - case CMD_LINK: - return CMD_ENDLINK; - case CMD_LIST: - return CMD_ENDLIST; - case CMD_NEWCODE: - return CMD_ENDCODE; - case CMD_OLDCODE: - return CMD_NEWCODE; - case CMD_OMIT: - return CMD_ENDOMIT; - case CMD_QUOTATION: - return CMD_ENDQUOTATION; - case CMD_RAW: - return CMD_ENDRAW; - case CMD_SECTION1: - return CMD_ENDSECTION1; - case CMD_SECTION2: - return CMD_ENDSECTION2; - case CMD_SECTION3: - return CMD_ENDSECTION3; - case CMD_SECTION4: - return CMD_ENDSECTION4; - case CMD_SIDEBAR: - return CMD_ENDSIDEBAR; - case CMD_TABLE: - return CMD_ENDTABLE; - case CMD_TOPICREF: - return CMD_ENDTOPICREF; - case CMD_MAPREF: - return CMD_ENDMAPREF; - default: - return cmd; - } -} - -QString DocParser::cmdName(int cmd) -{ - return *cmds[cmd].alias; -} - -QString DocParser::endCmdName(int cmd) -{ - return cmdName(endCmdFor(cmd)); -} - -QString DocParser::untabifyEtc(const QString& str) -{ - QString result; - result.reserve(str.length()); - int column = 0; - - for (int i = 0; i < str.length(); i++) { - const QChar c = str.at(i); - if (c == QLatin1Char('\r')) - continue; - if (c == QLatin1Char('\t')) { - result += &" "[column % tabSize]; - column = ((column / tabSize) + 1) * tabSize; - continue; - } - if (c == QLatin1Char('\n')) { - while (result.endsWith(QLatin1Char(' '))) - result.chop(1); - result += c; - column = 0; - continue; - } - result += c; - column++; - } - - while (result.endsWith("\n\n")) - result.truncate(result.length() - 1); - while (result.startsWith(QLatin1Char('\n'))) - result = result.mid(1); - - return result; -} - -int DocParser::indentLevel(const QString& str) -{ - int minIndent = INT_MAX; - int column = 0; - - for (int i = 0; i < (int) str.length(); i++) { - if (str[i] == '\n') { - column = 0; - } - else { - if (str[i] != ' ' && column < minIndent) - minIndent = column; - column++; - } - } - return minIndent; -} - -QString DocParser::unindent(int level, const QString& str) -{ - if (level == 0) - return str; - - QString t; - int column = 0; - - for (int i = 0; i < (int) str.length(); i++) { - if (str[i] == QLatin1Char('\n')) { - t += '\n'; - column = 0; - } - else { - if (column >= level) - t += str[i]; - column++; - } - } - return t; -} +#include "doc.h" -QString DocParser::slashed(const QString& str) -{ - QString result = str; - result.replace(QLatin1Char('/'), "\\/"); - return QLatin1Char('/') + result + QLatin1Char('/'); -} +#include "atom.h" +#include "config.h" +#include "codemarker.h" +#include "docparser.h" +#include "docprivate.h" +#include "generator.h" +#include "qmltypenode.h" +#include "quoter.h" +#include "text.h" -/*! - Returns \c true if \a atom represents a code snippet. - */ -bool DocParser::isCode(const Atom *atom) -{ - Atom::AtomType type = atom->type(); - return (type == Atom::Code - || type == Atom::Qml - || type == Atom::JavaScript); -} +QT_BEGIN_NAMESPACE -/*! - Returns \c true if \a atom represents quoting information. - */ -bool DocParser::isQuote(const Atom *atom) -{ - Atom::AtomType type = atom->type(); - return (type == Atom::CodeQuoteArgument - || type == Atom::CodeQuoteCommand - || type == Atom::SnippetCommand - || type == Atom::SnippetIdentifier - || type == Atom::SnippetLocation); -} +DocUtilities &Doc::m_utilities = DocUtilities::instance(); /*! Parse the qdoc comment \a source. Build up a list of all the topic @@ -2859,19 +50,15 @@ bool DocParser::isQuote(const Atom *atom) QML documentation, there is the case where the qdoc \e{qmlproperty} command can appear multiple times in a qdoc comment. */ -Doc::Doc(const Location& start_loc, - const Location& end_loc, - const QString& source, - const QSet& metaCommandSet, - const QSet& topics) +Doc::Doc(const Location &start_loc, const Location &end_loc, const QString &source, + const QSet &metaCommandSet, const QSet &topics) { - priv = new DocPrivate(start_loc,end_loc,source); + priv = new DocPrivate(start_loc, end_loc, source); DocParser parser; - parser.parse(source,priv,metaCommandSet,topics); + parser.parse(source, priv, metaCommandSet, topics); } -Doc::Doc(const Doc& doc) - : priv(nullptr) +Doc::Doc(const Doc &doc) : priv(nullptr) { operator=(doc); } @@ -2882,7 +69,7 @@ Doc::~Doc() delete priv; } -Doc &Doc::operator=(const Doc& doc) +Doc &Doc::operator=(const Doc &doc) { if (doc.priv) doc.priv->ref(); @@ -2892,40 +79,6 @@ Doc &Doc::operator=(const Doc& doc) return *this; } -void Doc::simplifyEnumDoc() -{ - if (priv) { - if (priv->isEnumDocSimplifiable()) { - detach(); - - Text newText; - - Atom *atom = priv->text.firstAtom(); - while (atom) { - if ((atom->type() == Atom::ListLeft) && - (atom->string() == ATOM_LIST_VALUE)) { - while (atom && ((atom->type() != Atom::ListRight) || - (atom->string() != ATOM_LIST_VALUE))) - atom = atom->next(); - if (atom) - atom = atom->next(); - } - else { - newText << *atom; - atom = atom->next(); - } - } - priv->text = newText; - } - } -} - -void Doc::setBody(const Text &text) -{ - detach(); - priv->text = text; -} - /*! Returns the starting location of a qdoc comment. */ @@ -2938,20 +91,11 @@ const Location &Doc::location() const /*! Returns the starting location of a qdoc comment. */ -const Location& Doc::startLocation() const +const Location &Doc::startLocation() const { return location(); } -/*! - Returns the ending location of a qdoc comment. - */ -const Location& Doc::endLocation() const -{ - static const Location dummy; - return priv == nullptr ? dummy : priv->end_loc; -} - const QString &Doc::source() const { static QString null; @@ -2963,7 +107,7 @@ bool Doc::isEmpty() const return priv == nullptr || priv->src.isEmpty(); } -const Text& Doc::body() const +const Text &Doc::body() const { static const Text dummy; return priv == nullptr ? dummy : priv->text; @@ -2991,8 +135,7 @@ Text Doc::trimmedBriefText(const QString &className) const should be rethought. */ while (atom) { - if (atom->type() == Atom::AutoLink - || atom->type() == Atom::String) { + if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) { briefStr += atom->string(); } else if (atom->type() == Atom::C) { briefStr += Generator::plainCode(atom->string()); @@ -3002,20 +145,17 @@ Text Doc::trimmedBriefText(const QString &className) const QStringList w = briefStr.split(QLatin1Char(' ')); if (!w.isEmpty() && w.first() == "Returns") { - } - else { + } else { if (!w.isEmpty() && w.first() == "The") w.removeFirst(); if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly)) w.removeFirst(); - if (!w.isEmpty() && ((w.first() == "class") || - (w.first() == "function") || - (w.first() == "macro") || - (w.first() == "widget") || - (w.first() == "namespace") || - (w.first() == "header"))) + if (!w.isEmpty() + && ((w.first() == "class") || (w.first() == "function") || (w.first() == "macro") + || (w.first() == "widget") || (w.first() == "namespace") + || (w.first() == "header"))) w.removeFirst(); if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides")) @@ -3047,34 +187,24 @@ Text Doc::legaleseText() const return body().subText(Atom::LegaleseLeft, Atom::LegaleseRight); } -Doc::Sections Doc::granularity() const -{ - if (priv == nullptr || priv->extra == nullptr) { - return DocPrivateExtra().granularity_; - } - else { - return priv->extra->granularity_; - } -} - -const QSet &Doc::parameterNames() const +QSet Doc::parameterNames() const { - return priv == nullptr ? *null_Set_QString() : priv->params; + return priv == nullptr ? QSet() : priv->params; } -const QStringList &Doc::enumItemNames() const +QStringList Doc::enumItemNames() const { - return priv == nullptr ? *null_QStringList() : priv->enumItemList; + return priv == nullptr ? QStringList() : priv->enumItemList; } -const QStringList &Doc::omitEnumItemNames() const +QStringList Doc::omitEnumItemNames() const { - return priv == nullptr ? *null_QStringList() : priv->omitEnumItemList; + return priv == nullptr ? QStringList() : priv->omitEnumItemList; } -const QSet &Doc::metaCommandsUsed() const +QSet Doc::metaCommandsUsed() const { - return priv == nullptr ? *null_Set_QString() : priv->metacommandsUsed; + return priv == nullptr ? QSet() : priv->metacommandsUsed; } /*! @@ -3100,19 +230,19 @@ bool Doc::isMarkedReimp() const current qdoc comment. Normally there is only one, but there can be multiple \e{qmlproperty} commands, for example. */ -const TopicList& Doc::topicsUsed() const +TopicList Doc::topicsUsed() const { - return priv == nullptr ? *nullTopicList() : priv->topics_; + return priv == nullptr ? TopicList() : priv->topics_; } -ArgList Doc::metaCommandArgs(const QString& metacommand) const +ArgList Doc::metaCommandArgs(const QString &metacommand) const { return priv == nullptr ? ArgList() : priv->metaCommandMap.value(metacommand); } -const QList &Doc::alsoList() const +QList Doc::alsoList() const { - return priv == nullptr ? *null_QList_Text() : priv->alsoList; + return priv == nullptr ? QList() : priv->alsoList; } bool Doc::hasTableOfContents() const @@ -3136,7 +266,7 @@ const QList &Doc::tableOfContents() const return priv->extra->tableOfContents_; } -const QVector &Doc::tableOfContentsLevels() const +const QList &Doc::tableOfContentsLevels() const { priv->constructExtra(); return priv->extra->tableOfContentsLevels_; @@ -3154,47 +284,31 @@ const QList &Doc::targets() const return priv->extra->targets_; } -const QStringMultiMap &Doc::metaTagMap() const +QStringMultiMap *Doc::metaTagMap() const { - return priv && priv->extra ? priv->extra->metaMap_ : *null_QStringMultiMap(); + return priv && priv->extra ? &priv->extra->metaMap_ : nullptr; } -const Config* Doc::config_ = nullptr; - -void Doc::initialize(const Config& config) +void Doc::initialize() { - DocParser::tabSize = config.getInt(CONFIG_TABSIZE); - DocParser::exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES); - DocParser::exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); - DocParser::sourceFiles = config.getCanonicalPathList(CONFIG_SOURCES); - DocParser::sourceDirs = config.getCanonicalPathList(CONFIG_SOURCEDIRS); + Config &config = Config::instance(); + DocParser::initialize(config); QmlTypeNode::qmlOnly = config.getBool(CONFIG_QMLONLY); QStringMap reverseAliasMap; - config_ = &config; for (const auto &a : config.subVars(CONFIG_ALIAS)) { QString alias = config.getString(CONFIG_ALIAS + Config::dot + a); if (reverseAliasMap.contains(alias)) { - config.lastLocation().warning(tr("Command name '\\%1' cannot stand" - " for both '\\%2' and '\\%3'") - .arg(alias) - .arg(reverseAliasMap[alias]) - .arg(a)); + config.lastLocation().warning(QStringLiteral("Command name '\\%1' cannot stand" + " for both '\\%2' and '\\%3'") + .arg(alias) + .arg(reverseAliasMap[alias]) + .arg(a)); } else { reverseAliasMap.insert(alias, a); } - aliasMap()->insert(a, alias); - } - - int i = 0; - while (cmds[i].english) { - cmds[i].alias = new QString(alias(cmds[i].english)); - cmdHash()->insert(*cmds[i].alias, cmds[i].no); - - if (cmds[i].no != i) - Location::internalError(tr("command %1 missing").arg(i)); - i++; + m_utilities.aliasMap.insert(a, alias); } for (const auto ¯oName : config.subVars(CONFIG_MACRO)) { @@ -3217,18 +331,18 @@ void Doc::initialize(const Config& config) macro.numParams = m; else if (macro.numParams != m) { if (!silent) { - QString other = tr("default"); + QString other = QStringLiteral("default"); if (macro.defaultDef.isEmpty()) other = macro.otherDefs.constBegin().key(); - config.lastLocation().warning(tr("Macro '\\%1' takes" - " inconsistent number" - " of arguments (%2" - " %3, %4 %5)") - .arg(macroName) - .arg(f) - .arg(m) - .arg(other) - .arg(macro.numParams)); + config.lastLocation().warning(QStringLiteral("Macro '\\%1' takes" + " inconsistent number" + " of arguments (%2" + " %3, %4 %5)") + .arg(macroName) + .arg(f) + .arg(m) + .arg(other) + .arg(macro.numParams)); silent = true; } if (macro.numParams < m) @@ -3237,14 +351,8 @@ void Doc::initialize(const Config& config) } } if (macro.numParams != -1) - macroHash()->insert(macroName, macro); + m_utilities.macroHash.insert(macroName, macro); } - // If any of the formats define quotinginformation, activate quoting - DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION); - for (const auto &format : config.getOutputFormats()) - DocParser::quoting = DocParser::quoting || config.getBool(format - + Config::dot - + CONFIG_QUOTINGINFORMATION); } /*! @@ -3252,32 +360,22 @@ void Doc::initialize(const Config& config) */ void Doc::terminate() { - DocParser::exampleFiles.clear(); - DocParser::exampleDirs.clear(); - DocParser::sourceFiles.clear(); - DocParser::sourceDirs.clear(); - aliasMap()->clear(); - cmdHash()->clear(); - macroHash()->clear(); - - int i = 0; - while (cmds[i].english) { - delete cmds[i].alias; - cmds[i].alias = nullptr; - ++i; - } + m_utilities.aliasMap.clear(); + m_utilities.cmdHash.clear(); + m_utilities.macroHash.clear(); + DocParser::terminate(); } QString Doc::alias(const QString &english) { - return aliasMap()->value(english, english); + return m_utilities.aliasMap.value(english, english); } /*! Trims the deadwood out of \a str. i.e., this function cleans up \a str. */ -void Doc::trimCStyleComment(Location& location, QString& str) +void Doc::trimCStyleComment(Location &location, QString &str) { QString cleaned; Location m = location; @@ -3285,14 +383,13 @@ void Doc::trimCStyleComment(Location& location, QString& str) int asterColumn = location.columnNo() + 1; int i; - for (i = 0; i < (int) str.length(); i++) { + for (i = 0; i < str.length(); ++i) { if (m.columnNo() == asterColumn) { if (str[i] != '*') break; cleaned += ' '; metAsterColumn = true; - } - else { + } else { if (str[i] == '\n') { if (!metAsterColumn) break; @@ -3305,29 +402,23 @@ void Doc::trimCStyleComment(Location& location, QString& str) if (cleaned.length() == str.length()) str = cleaned; - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; ++i) location.advance(str[i]); str = str.mid(3, str.length() - 5); } -QString Doc::resolveFile(const Location &location, - const QString &fileName, +QString Doc::resolveFile(const Location &location, const QString &fileName, QString *userFriendlyFilePath) { - const QString result = Config::findFile(location, - DocParser::exampleFiles, - DocParser::exampleDirs, - fileName, userFriendlyFilePath); - qCDebug(lcQdoc).noquote().nospace() << __FUNCTION__ << "(location=" - << location.fileName() << ':' << location.lineNo() - << ", fileName=\"" << fileName << "\"), resolved to \"" - << result; + const QString result = Config::findFile(location, DocParser::exampleFiles, + DocParser::exampleDirs, fileName, userFriendlyFilePath); + qCDebug(lcQdoc).noquote().nospace() + << __FUNCTION__ << "(location=" << location.fileName() << ':' << location.lineNo() + << ", fileName=\"" << fileName << "\"), resolved to \"" << result; return result; } -CodeMarker *Doc::quoteFromFile(const Location &location, - Quoter "er, - const QString &fileName) +CodeMarker *Doc::quoteFromFile(const Location &location, Quoter "er, const QString &fileName) { quoter.reset(); @@ -3336,17 +427,19 @@ CodeMarker *Doc::quoteFromFile(const Location &location, QString userFriendlyFilePath; const QString filePath = resolveFile(location, fileName, &userFriendlyFilePath); if (filePath.isEmpty()) { - QString details = QLatin1String("Example directories: ") + DocParser::exampleDirs.join(QLatin1Char(' ')); + QString details = QLatin1String("Example directories: ") + + DocParser::exampleDirs.join(QLatin1Char(' ')); if (!DocParser::exampleFiles.isEmpty()) - details += QLatin1String(", example files: ") + DocParser::exampleFiles.join(QLatin1Char(' ')); - location.warning(tr("Cannot find file to quote from: '%1'").arg(fileName), details); - } - else { + details += QLatin1String(", example files: ") + + DocParser::exampleFiles.join(QLatin1Char(' ')); + location.warning(QStringLiteral("Cannot find file to quote from: '%1'").arg(fileName), + details); + } else { QFile inFile(filePath); if (!inFile.open(QFile::ReadOnly)) { - location.warning(tr("Cannot open file to quote from: '%1'").arg(userFriendlyFilePath)); - } - else { + location.warning(QStringLiteral("Cannot open file to quote from: '%1'") + .arg(userFriendlyFilePath)); + } else { QTextStream inStream(&inFile); code = DocParser::untabifyEtc(inStream.readAll()); } @@ -3363,7 +456,7 @@ QString Doc::canonicalTitle(const QString &title) // The code below is equivalent to the following chunk, but _much_ // faster (accounts for ~10% of total running time) // - // QRegExp attributeExpr("[^A-Za-z0-9]+"); + // QRegularExpression attributeExpr("[^A-Za-z0-9]+"); // QString result = title.toLower(); // result.replace(attributeExpr, " "); // result = result.simplified(); @@ -3385,8 +478,7 @@ QString Doc::canonicalTitle(const QString &title) begun = true; dashAppended = false; lastAlnum = result.size(); - } - else if (!dashAppended) { + } else if (!dashAppended) { if (begun) result += QLatin1Char('-'); dashAppended = true; @@ -3415,20 +507,4 @@ void Doc::detach() priv = newPriv; } -/*! - The destructor deletes all the sub-TopicRefs. - */ -TopicRef::~TopicRef() -{ - foreach (DitaRef* t, subrefs_) { - delete t; - } -} - -/*! - Returns a reference to the structure that will be used - for generating a DITA mao. - */ -const DitaRefList& Doc::ditamap() const { return priv->ditamap_; } - QT_END_NAMESPACE diff --git a/src/qdoc/doc.h b/src/qdoc/doc.h index ee3221a2de..6832743f08 100644 --- a/src/qdoc/doc.h +++ b/src/qdoc/doc.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -33,86 +33,29 @@ #ifndef DOC_H #define DOC_H -#include -#include -#include - #include "location.h" +#include "docutilities.h" +#include "topic.h" + +#include +#include +#include + QT_BEGIN_NAMESPACE class Atom; class CodeMarker; -class Config; class DocPrivate; class Quoter; class Text; -class DitaRef; typedef QPair ArgLocPair; typedef QList ArgList; -typedef QMap QStringMap; typedef QMultiMap QStringMultiMap; -struct Topic -{ - QString topic; - QString args; - Topic() { } - Topic(QString& t, const QString &a) : topic(t), args(a) { } - bool isEmpty() const { return topic.isEmpty(); } - void clear() { topic.clear(); args.clear(); } -}; -typedef QList TopicList; - -typedef QList DitaRefList; - -class DitaRef -{ -public: - DitaRef() { } - virtual ~DitaRef() { } - - const QString& navtitle() const { return navtitle_; } - const QString& href() const { return href_; } - void setNavtitle(const QString& t) { navtitle_ = t; } - void setHref(const QString& t) { href_ = t; } - virtual bool isMapRef() const = 0; - virtual const DitaRefList* subrefs() const { return nullptr; } - virtual void appendSubref(DitaRef* ) { } - -private: - QString navtitle_; - QString href_; -}; - -class TopicRef : public DitaRef -{ -public: - TopicRef() { } - ~TopicRef(); - - bool isMapRef() const override { return false; } - const DitaRefList* subrefs() const override { return &subrefs_; } - void appendSubref(DitaRef* t) override { subrefs_.append(t); } - -private: - DitaRefList subrefs_; -}; - -class MapRef : public DitaRef -{ -public: - MapRef() { } - ~MapRef() { } - - bool isMapRef() const override { return true; } -}; - class Doc { - Q_DECLARE_TR_FUNCTIONS(QDoc::Doc) - public: // the order is important enum Sections { @@ -125,66 +68,56 @@ class Doc Section4 = 4 }; - Doc() : priv(nullptr) {} - Doc(const Location& start_loc, - const Location& end_loc, - const QString& source, - const QSet& metaCommandSet, - const QSet& topics); + Doc() = default; + Doc(const Location &start_loc, const Location &end_loc, const QString &source, + const QSet &metaCommandSet, const QSet &topics); Doc(const Doc &doc); ~Doc(); - Doc& operator=( const Doc& doc ); - void simplifyEnumDoc(); - void setBody(const Text &body); - const DitaRefList& ditamap() const; + Doc &operator=(const Doc &doc); const Location &location() const; - const Location& startLocation() const; - const Location& endLocation() const; + const Location &startLocation() const; bool isEmpty() const; - const QString& source() const; - const Text& body() const; + const QString &source() const; + const Text &body() const; Text briefText(bool inclusive = false) const; Text trimmedBriefText(const QString &className) const; Text legaleseText() const; - Sections granularity() const; - const QSet ¶meterNames() const; - const QStringList &enumItemNames() const; - const QStringList &omitEnumItemNames() const; - const QSet &metaCommandsUsed() const; - const TopicList& topicsUsed() const; - ArgList metaCommandArgs(const QString& metaCommand) const; - const QList &alsoList() const; + QSet parameterNames() const; + QStringList enumItemNames() const; + QStringList omitEnumItemNames() const; + QSet metaCommandsUsed() const; + TopicList topicsUsed() const; + ArgList metaCommandArgs(const QString &metaCommand) const; + QList alsoList() const; bool hasTableOfContents() const; bool hasKeywords() const; bool hasTargets() const; bool isInternal() const; bool isMarkedReimp() const; const QList &tableOfContents() const; - const QVector &tableOfContentsLevels() const; + const QList &tableOfContentsLevels() const; const QList &keywords() const; const QList &targets() const; - const QStringMultiMap &metaTagMap() const; + QStringMultiMap *metaTagMap() const; - static void initialize( const Config &config ); + static void initialize(); static void terminate(); - static QString alias( const QString &english ); - static void trimCStyleComment( Location& location, QString& str ); - static QString resolveFile(const Location &location,const QString &fileName, + static QString alias(const QString &english); + static void trimCStyleComment(Location &location, QString &str); + static QString resolveFile(const Location &location, const QString &fileName, QString *userFriendlyFilePath = nullptr); - static CodeMarker *quoteFromFile(const Location &location, - Quoter "er, + static CodeMarker *quoteFromFile(const Location &location, Quoter "er, const QString &fileName); static QString canonicalTitle(const QString &title); - static const Config* config() { return config_; } private: void detach(); - DocPrivate *priv; - static const Config* config_; + DocPrivate *priv { nullptr }; + static DocUtilities &m_utilities; }; -Q_DECLARE_TYPEINFO(Doc, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(Doc, Q_RELOCATABLE_TYPE); typedef QList DocList; QT_END_NAMESPACE diff --git a/src/qdoc/doc/config/qdoc.qdocconf b/src/qdoc/doc/config/qdoc.qdocconf index 32b6b6409a..e4594c3acd 100644 --- a/src/qdoc/doc/config/qdoc.qdocconf +++ b/src/qdoc/doc/config/qdoc.qdocconf @@ -1,4 +1,5 @@ include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) +include($QT_INSTALL_DOCS/config/exampleurl-qttools.qdocconf) project = QDoc description = QDoc Manual @@ -35,28 +36,20 @@ qhp.QDoc.subprojects.overviews.indexTitle = QDoc Manual qhp.QDoc.subprojects.overviews.selectors = doc:page depends += \ - activeqt \ - qtassistant \ - qtbluetooth \ qtconcurrent \ qtcore \ qtdbus \ qtdesigner \ qtdoc \ qthelp \ - qtimageformats \ qtgui \ - qtlocation \ qtlinguist \ - qtmultimedia \ qtnetwork \ qtopengl \ qtprintsupport \ qtqml \ qtquick \ - qtscript \ - qtscripttools \ - qtsensors \ + qtquickcontrols \ qtsql \ qtsvg \ qttestlib \ @@ -64,4 +57,8 @@ depends += \ qtwidgets \ qtxml +ignorewords += QDoc + navigation.landingpage = "QDoc Manual" + +warninglimit = 0 diff --git a/src/qdoc/doc/examples/cpp.qdoc.sample b/src/qdoc/doc/examples/cpp.qdoc.sample index 892e9c30d8..0524a67563 100644 --- a/src/qdoc/doc/examples/cpp.qdoc.sample +++ b/src/qdoc/doc/examples/cpp.qdoc.sample @@ -46,7 +46,7 @@ \snippet code/doc_src_qcache.cpp 1 - ... detailed description ommitted + ... detailed description omitted \sa QPixmapCache, QHash, QMap */ diff --git a/src/qdoc/doc/examples/samples.qdocinc b/src/qdoc/doc/examples/samples.qdocinc index afe634326b..1b83428b28 100644 --- a/src/qdoc/doc/examples/samples.qdocinc +++ b/src/qdoc/doc/examples/samples.qdocinc @@ -62,10 +62,10 @@ \page generic-guide.html \title Generic QDoc Guide \nextpage Creating QDoc Configuration Files - There are three essential materials for generating documentation with qdoc: + There are three essential materials for generating documentation with QDoc: \list - \li \c qdoc binary + \li \c QDoc binary (\c {qdoc}) \li \c qdocconf configuration files \li \c Documentation in \c C++, \c QML, and \c .qdoc files \endlist diff --git a/src/qdoc/doc/files/basicqt.qdoc.sample b/src/qdoc/doc/files/basicqt.qdoc.sample index ce8df096fa..1243387b22 100644 --- a/src/qdoc/doc/files/basicqt.qdoc.sample +++ b/src/qdoc/doc/files/basicqt.qdoc.sample @@ -1,6 +1,5 @@ /*! \page basicqt.html - \contentspage {Basic Qt} {Contents} \nextpage Getting Started \indexpage Index @@ -24,7 +23,6 @@ /*! \page gettingstarted.html \previouspage Basic Qt - \contentspage {Basic Qt} {Contents} \nextpage Creating Dialogs \indexpage Index @@ -40,7 +38,6 @@ / *! \page creatingdialogs.html \previouspage Getting Started - \contentspage {Basic Qt} {Contents} \indexpage Index \startpage Basic Qt diff --git a/src/qdoc/doc/images/windowsvista-toolbutton.png b/src/qdoc/doc/images/windowsvista-toolbutton.png new file mode 100644 index 0000000000..0baa9809c1 Binary files /dev/null and b/src/qdoc/doc/images/windowsvista-toolbutton.png differ diff --git a/src/qdoc/doc/qa-pages.qdoc b/src/qdoc/doc/qa-pages.qdoc deleted file mode 100644 index 5602ba3e07..0000000000 --- a/src/qdoc/doc/qa-pages.qdoc +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \page 28-qdoc-qa-pages.html - \previouspage Generating DITA XML Output - \contentspage QDoc Manual - \nextpage QDoc Manual - - \title QA Pages - - qdoc can generate some extra HTML pages that can be useful for - debugging qdoc documentation. These \e QA pages make it easier for - those who write documentation to find links that either go to the - wrong targets or don't go anywhere at all. - - \section2 Generating the QA Pages - - Add \c {-write-qa-pages} to the command line to tell qdoc to - generate the QA pages. If this option is not provided, the QA - pages will not be generated, and previolusly generated QA pages - will be deleted. - - \section2 Finding the Module's Main QA Page - - The main QA page for a module is not linked into the module's - generated documentation, but it is located in the same output - directory. To find the top-level QA page for module \e {xxx}, set - your browser to the qdoc output directory for module \e {xxx}. - Several files whose names begin with \e {aaa} appear at the top of - the list. These are the QA pages for module \e{xxx}. The file - names begin with \e {aaa} to ensure that they are easy to find at - the top of the directory. - - For module \e{xxx}, find the file \e{aaa-xxx-qa-page.html}. This - is the top-level QA page for module \e{xxx}. Load that file into - the browser. The top-level QA page shows a table that contains - links to several QA sub-pages. - - For example, the main QA page for QtCore is \c{aaa-qtcore-qa-page.html}. - This was the table for QtCore at one point: - - \image qa-table.png - - Each table entry shows the number of links from QtCore to some - other module, except for the last entry, which shows the number of - broken links in QtCore. Click the \b qtquick entry to load the QA - subpage showing the links from QtCore to QtQuick. - - \section2 Links To Links Page - - Clicking the \b qtquick table entry on the main QA page for QtCore - loads the QA subpage showing a table containing all the links from - QtCore to QtQuick. The table contains all the links constructed - with the \l {l-command} {\\l command}, as well as the autolinks. - - \image links-to-links.png - - At the time this table was generated, there were six links from - QtCore to QtQuick. The first column of each table entry contains - a link to some link in QtCore. The link text as it appears in - QtCore is shown. The second and third columns contain the source - file name and line number for where qdoc saw the link in a qdoc - comment. - - \note The line number will normally refer to the first line of the - comment where qdoc saw the link. - - Clicking on a link in the table takes you to that link in the - documentation. There the link will be marked with three red - asterisks. For example, clicking on the link in the fifth table - entry takes you here: - - \image link-to-qquickitem.png - - The link is marked with three red asterisks. Now you can click on - the actual link to check that it goes to the correct place. In - this case, the link should go to the reference page for the - QQuickItem class. You can check each link in the table this - way. If you find a link that goes to the wrong place, use the - source file name and line number to find the link, and fix the - problem using the square bracket notation for the \l {l-command} - {\\l command}. - - */ diff --git a/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc b/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc index fd6dc7a75c..4dbaa52108 100644 --- a/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc +++ b/src/qdoc/doc/qdoc-guide/qdoc-guide.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -37,14 +37,14 @@ \l{writing-markup}{mark up} to enhance the layout and formatting of the final output. - There are three essential materials for generating documentation with qdoc: + There are three essential materials for generating documentation with QDoc: \list \li \c QDoc binary \li \c qdocconf configuration files \li \c Documentation in \c C++, \c QML, and \c .qdoc files \endlist - \note From Qt 5.11, \l{QDoc Manual}{QDoc} requires \l{http://clang.llvm.org}{Clang} + \note \l{QDoc Manual}{QDoc} requires \l{http://clang.llvm.org}{Clang} for parsing C++ header and source files, and for parsing the function signatures in \l {fn-command} {\\fn} commands. See \l {Installing Clang for QDoc} for details. @@ -95,12 +95,12 @@ can style the documentation in DITA at a later time. DITA XML is therefore more flexible in allowing different styles to apply to the same information. - To run qdoc, the project configuration file is supplied as an argument. + To run QDoc, the project configuration file is supplied as an argument. \code qdoc project.qdocconf \endcode - The project configuration contains information that qdoc uses to create the + The project configuration contains information that QDoc uses to create the documentation. \section2 Project Information @@ -205,18 +205,17 @@ The \l {Format-specific Configuration Variables} article outlines the usage of each variable. - \section2 Qt Index Reference + \section2 QDoc Index Files - Documentation projects can link to Qt APIs and other articles by specifying - the path to the \c qt.index file. When qdoc generates the Qt Reference - Documentation, it will also generate an index file, containing the URLs to - the articles. Other projects can use the links in the index file so that - they can link to other articles and API documentation within Qt. + Documentation projects can link to targets in other projects by specifying + a set of dependencies, or a set of direct paths to to index file(s) this + project depends on. When QDoc generates documentation for a project, + it will also generate an \c .index file containing URLs to each linkable + entity in the project. Other projects can then define a dependency to the + index file in order to link to the documentation within that project. - \badcode - indexes = $QT_INSTALL_DOCS/html/qt.index $OTHER_PROJECT/html/qt.index - \endcode - It is possible to specify multiple index files from several projects. + \b {See also}: \l {depends-variable}{depends} and + \l {indexes-variable}{indexes}. \section1 Macros and Other Configurations @@ -230,6 +229,8 @@ HTML file, which will appear as the Greek \pi symbol when viewed in browsers. + \b {See also:} \l {macro-variable}{macro}. + \section2 QML Additions QDoc is able to parse QML files for QDoc comments. QDoc will parse files @@ -266,7 +267,7 @@ comment; the comment itself and anything after it, until a newline, is omitted from the generated output. - QDoc will parse C++ and QML files to look for qdoc comments. To explicitly + QDoc will parse C++ and QML files to look for QDoc comments. To explicitly omit a certain file type, omit it from the \l{Input and Output Directories}{configuration} file. @@ -279,7 +280,7 @@ \target writing-topic-commands \section2 QDoc Topics - Each qdoc comment must have a \e topic type. A topic distinguishes it from + Each QDoc comment must have a \e topic type. A topic distinguishes it from other topics. To specify a topic type, use one of the several \l{Topic Commands}{topic commands}. @@ -291,12 +292,43 @@ Example of topic commands: \list - \li \l{enum-command}{\\enum} - for enumeration documentation + \li \l{enum-command}{\\enum} - for enumeration documentation \li \l{class-command}{\\class} - for C++ class documentation \li \l{qmltype-command}{\\qmltype} - for QML type documentation \li \l{page-command}{\\page} - for creating a page. \endlist + A QDoc comment can contain multiple topic commands in the same category, with + some restrictions. This way, it's possible to write a single comment that + documents all overloads of a function (using multiple \l {fn-command}{\\fn} + commands), or all properties in a QML property group (using + \l {qmlproperty-command}{\\qmlproperty} commands) in one go. + + If a QDoc comment contains multiple topic commands, it's possible to + provide additional \e {context commands} for individual topics in + follow-up comments: + + \badcode * + /\1! + \qmlproperty string Type::element.name + \qmlproperty int Type::element.id + + \brief Holds the element name and id. + \1/ + + /\1! + \qmlproperty int Type::element.id + \readonly + \1/ + \endcode + + Here, the follow-up comment marks the \e element.id property as read-only, + while \e element.name remains writable. + + \note A follow-up comment cannot contain any additional text, only + \l {writing-context}{context commands} that document the context of + the item. + The \l{page-command}{\\page} command is for creating articles that are not part of source documentation. The command can also accept two arguments: the file name of the article and the documentation type. The possible types are: @@ -305,6 +337,7 @@ \li \c overview \li \c tutorial \li \c faq + \li \c attribution - used for documenting license attributions \li \c article - \e default when there is no type \endlist @@ -319,15 +352,15 @@ Context commands give QDoc a hint about the \e context of the topic. For example, if a C++ function is obsolete, then it should be marked obsolete with the \l{obsolete-command}{\\obsolete} command. Likewise, - \l{nextpage-command}{page navigation} and \l{title-command}{page title}  + \l{nextpage-command}{page navigation} and \l{title-command}{page title} give extra page information to QDoc. QDoc will create additional links or pages for these contexts. For example, - a group is created using the \l{group-command}{\\group} command and the + a group is created using the \l{group-command}{\\group} command and the members have the \l{ingroup-command}{\\ingroup} command. The group name is supplied as an argument. - The \l{Context Commands} page has a listing of all the available context + The \l{Context Commands} page has a listing of all the available context commands. \target writing-markup @@ -541,26 +574,21 @@ For example, if a type called \c TabWidget is in the \c UIComponents module, it must be linked as \c {UIComponents::TabWidget}. - The \l{componentset}{UIComponents} example demonstrates proper usage of - QDoc commands to document QML types and QML modules. - \section3 Read-only and Internal QML Properties QDoc detects QML properties that are marked as \c readonly. Note that the property must be initialized with a value. - \code + \badcode readonly property int sampleReadOnlyProperty: 0 \endcode - For example, the example \l{TabWidget} type has a fictitious read-only - property \c sampleReadOnlyProperty. Its declaration has the \c readonly - identifier and it has an initial value. Properties and signals that are not meant for the public interface may be marked with the \l{internal-command}{\\internal} command. QDoc will not publish the documentation in the generated outputs. \section1 Articles & Overviews + Articles and overviews are a style of writing best used for providing summary detail on a topic or concept. It may introduce a technology or discuss how a concept may be applied, but without discussing exact steps @@ -575,7 +603,7 @@ \snippet examples/samples.qdocinc sample-overview - The \l{writing-topic-commands}{writing topic commands} section has a listing + The \l{writing-topic-commands}{writing topic commands} section has a listing of the available \\page command arguments. \section1 Tutorials, How-To's, FAQ's @@ -593,7 +621,7 @@ argument, with the file name being the first. \snippet examples/samples.qdocinc sample-faq - The \l{writing-topic-commands}{writing topic commands} section has a listing + The \l{writing-topic-commands}{writing topic commands} section has a listing of the available \\page command arguments. \section1 Code Examples @@ -634,56 +662,24 @@ \l {fn-command} {\\fn} commands. Clang is part of \l {https://llvm.org/}{the LLVM Compiler Infrastructure Project}. Therefore, if you are going to build QDoc from source, you need to install - \l{http://clang.llvm.org}{LLVM 6.0} or greater first. You can find the - required pre-built binaries - \l {http://releases.llvm.org/download.html}{here}. - - To build QDoc on Debian-based Linux distributions, it is sufficient to - install the \c libclang-dev package and its dependencies. For running QDoc, - the \c libclang package is required. + \l{http://clang.llvm.org}{LLVM 8.0} or greater first. - \section1 Set Clang location automatically + You can get Clang through various channels: - The Qt build system uses the tool \c llvm-config to discover the location - of LLVM on your system, and relies on the path to llvm-config being in - the \c PATH environment variable to do so. \c llvm-config is commonly - installed with LLVM and Clang on Linux systems, and also on macOS if - LLVM is installed using Brew. - - On Windows, the installation binaries provided by LLVM do not include - \c llvm-config. You may still have it on your system, if you have built - LLVM yourself from source. If that is the case, and you want to let the - build system find Clang automatically, add the path to \c llvm-config - to your \c PATH environment variable. For example: - - \badcode - C:\> set PATH=%PATH%;C:\[build directory]\bin\Release" - \endcode - - Make sure to set the path to your LLVM build directory. The \c llvm-config - executable is located in \c {bin\Release} or \c {bin\Debug}, reflecting the - build version. - - \section1 Specify Clang location manually - - If \c llvm-config is not in your \c PATH environment variable, or not - installed on your system, you can still build QDoc, by manually setting the - environment variable \c LLVM_INSTALL_DIR to point to the directory where - the Clang libraries are installed. This directory should be the top level - directory. For example, on a Linux or macOS system with LLVM installed to - \c /usr/llvm: - - \badcode - $ export LLVM_INSTALL_DIR=/usr/llvm - \endcode - - Debian-based Linux distributions usually offer multiple versions of the - \c libclang packages, such as \c libclang-. In this case, - \c LLVM_INSTALL_DIR should contain \c /usr/lib/clang/ . + \list + \li Qt provides \l{http://download.qt.io/development_releases/prebuilt/libclang/qt} + {prebuilt Clang packages} that are also used for the Qt binaries in the online + installer. They allow to link LLVM/clang libraries statically, but only support Release + builds on Windows. + \li Linux distributions often provide a package called libclang-dev or libclang-devel. + \li On macOS, you can also use Homebrew's + \l{https://formulae.brew.sh/formula/llvm}{llvm formula}. + \endlist - On a Windows system with LLVM installed to \c {C:\Program Files\LLVM}: + \note the prebuilt binaries from \l{http://releases.llvm.org/download.html} cannot + be used, as they miss certain components required by QDoc. - \badcode - C:\> set LLVM_INSTALL_DIR=C:\Program Files\LLVM - \endcode + If you install Clang in a custom location you need to tell CMake where + to find it. This can be done by adding the installation path to + the \c CMAKE_PREFIX_PATH CMake cache variable. */ diff --git a/src/qdoc/doc/qdoc-manual-DITA.qdoc b/src/qdoc/doc/qdoc-manual-DITA.qdoc deleted file mode 100644 index 1160826284..0000000000 --- a/src/qdoc/doc/qdoc-manual-DITA.qdoc +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: https://www.gnu.org/licenses/fdl-1.3.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \page 21-0-qdoc-creating-dita-maps.html - \previouspage Miscellaneous - \contentspage QDoc Manual - \nextpage The QDoc Configuration File - - \title Creating DITA Maps - - You can create DITA map files using three new qdoc commands, the \l{ditamap-command} - {ditamap} command, the \l{topicref-command} {topicref} command, and the \l{mapref-command} - {mapref} command. How these DITA maps will be used automatically or manually by the - documentation build process is still under consideration. This section will be updated - as the decisions are made. - - \section1 What is a DITA Map? - - A complete description of DITA can be found at the - \l{http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=dita} - {OASIS Darwin Information Typing Architecture} site. - - An explanation of the DITA map is found at that site - \l{http://docs.oasis-open.org/dita/v1.2/os/spec/langref/map.html}{here}. - - \target ditamap-command - \section1 \\ditamap - - The \\ditamap command is for creating a DITA map using qdoc commands. - The \\ditamap command is a kind of \\page command that produces a - \e{.ditamap} instead of a \e{.html} or \e{.xml} file. The file that - is created actually contains XML text, but the \e{.ditamap} suffix is - used to identify the file as containing a DITA MAP. - - The argument is the name of the file to be created. In the following - example, the file \e{creator.ditamap} is output: - \code - \ditamap creator.ditamap - \endcode - - \target topicref-command - \section1 \\topicref \\endtopicref - - The \\topicref \\endtopicref commands are for creating a topicref - in the ditamap. The \\endtopicref command is required because - \\topicref commands can be nested. - - \\topicref has two arguments. The first argument becomes the value - of the \e navtitle attribute. Normally, you use the title of the - topic being referenced. This title is often what will appear in a - table of contents constructed from the ditamap. - - The second argument is the name of the page being referenced. The - second argument is actually optional, for example if you are using - a topicref as a container for other topicrefs and maprefs. It is - also optional if you want qdoc to find the page name for you by - looking up the title in its internal data structure. It is recommended - that you provide the second parameter if you know the page name. - - \code - \topicref {QML Module QtQuick 2} {qtquick-2.xml} - \mapref {Creator Manual} {creator-manual.ditamap} \endmapref - \topicref {QML Mouse Events} {qtquick2-mouseevents.xml} \endtopicref - \topicref {Property Binding} {qtquick2-propertybinding.xml} \endtopicref - \endtopicref - \endcode - - \target mapref-command - \section1 \\mapref - - The \\mapref command is for creating a mapref in the ditamap. A - mapref refers to another ditamap, which you want to include in - your ditamap. Like the \\topicref command, the \\mapref command - has two arguments, but for the \\mapref command, both arguments - are required. The arguments are essentially the same as described - for \\topicref, but for \\mapref, the second command must be the - name of another ditamap, i.e. it must have the \e{.ditamap} - suffix. You must provide the file name. qdoc can't look up the - file name for you. - - \code - \mapref {Creator Manual} {creator-manual.ditamap} \endmapref - \endcode - - \section1 An Example Ditamap Page - - The following example uses the three qdoc ditamap commands described above. - - \code - \ditamap creator.ditamap - \title The DITA Map for Creator - - \topicref {QML Module QtQuick 1} - \topicref {QML Mouse Events} \endtopicref - \topicref {Property Binding} \endtopicref - \endtopicref - - \topicref {QML Module QtQuick 2} {qtquick-2.xml} - \mapref {Creator Manual} {creator-manual.ditamap} \endmapref - \topicref {QML Mouse Events} {qtquick2-mouseevents.xml} \endtopicref - \topicref {Property Binding} {qtquick2-propertybinding.xml} \endtopicref - \endtopicref - - \topicref {QML Module QtQuick.Particles 2} {qtquick-particles-2.xml} - \topicref {Age} {qml-qtquick-particles2-age.xml} \endtopicref - \endtopicref - \endcode - - \section1 The Resulting Ditamap File - - This is the \e{.ditamap} file you get when you input the qdoc - ditamap page shown above. Note that you can write ditamap files - directly in XML just as easily as you can write them using the - qdoc commands. The choice is yours. - - \code - - - - - The DITA Map for Creator - - - - - - - - - - - - - - - \endcode - -*/ - diff --git a/src/qdoc/doc/qdoc-manual-cmdindex.qdoc b/src/qdoc/doc/qdoc-manual-cmdindex.qdoc index 672c2e4098..45d58611ca 100644 --- a/src/qdoc/doc/qdoc-manual-cmdindex.qdoc +++ b/src/qdoc/doc/qdoc-manual-cmdindex.qdoc @@ -28,7 +28,6 @@ /*! \page 27-qdoc-commands-alphabetical.html \previouspage Introduction to QDoc - \contentspage QDoc Manual \nextpage Topic Commands \title Command Index @@ -49,7 +48,6 @@ \li \l {class-command} {\\class} \li \l {code-command} {\\code} \li \l {codeline-command} {\\codeline} - \li \l {contentspage-command} {\\contentspage} \li \l {default-command} {\\default} \li \l {div-command} {\\div} \li \l {dots-command} {\\dots} @@ -70,6 +68,7 @@ \li \l {image-command} {\\image} \li \l {include-command} {\\include} \li \l {ingroup-command} {\\ingroup} + \li \l {inheaderfile-command}{\\inheaderfile} \li \l {inherits-command}{\\inherits} \li \l {inlineimage-command} {\\inlineimage} \li \l {inmodule-command} {\\inmodule} @@ -115,13 +114,16 @@ \li \l {qmlproperty-command} {\\qmlproperty} \li \l {qmlsignal-command} {\\qmlsignal} \li \l {qmlmodule-command} {\\qmlmodule} + \li \l {qtcmakepackage-command} {\\qtcmakepackage} \li \l {quotation-command} {\\quotation} \li \l {quotefile-command} {\\quotefile} \li \l {quotefromfile-command} {\\quotefromfile} \li \l {raw-command} {\\raw} + \li \l {readonly-command} {\\readonly} \li \l {reentrant-command} {\\reentrant} \li \l {reimp-command} {\\reimp} \li \l {relates-command} {\\relates} + \li \l {required-command} {\\required} \li \l {row-command} {\\row} \li \l {sa-command} {\\sa} \li \l {sectionOne-command} {\\section1} @@ -144,6 +146,7 @@ \li \l {threadsafe-command} {\\threadsafe} \li \l {title-command} {\\title} \li \l {tt-command} {\\tt} + \li \l {typealias-command} {\\typealias} \li \l {typedef-command} {\\typedef} \li \l {uicontrol-command} {\\uicontrol} \li \l {underline-command} {\\underline} diff --git a/src/qdoc/doc/qdoc-manual-contextcmds.qdoc b/src/qdoc/doc/qdoc-manual-contextcmds.qdoc index 2fef88099e..802c91cf72 100644 --- a/src/qdoc/doc/qdoc-manual-contextcmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-contextcmds.qdoc @@ -28,7 +28,6 @@ /*! \page 14-qdoc-commands-contextcommands.html \previouspage Topic Commands - \contentspage QDoc Manual \nextpage Document Navigation \title Context Commands @@ -38,7 +37,8 @@ \list \li Is this class thread-safe? \li Is this function reentrant? - \li Of which module is this class a member ? + \li Of which module is this class a member? + \li Which include statement is needed to use this class? \endlist Context commands can appear anywhere in a QDoc comment, @@ -47,8 +47,8 @@ \list \li \l {abstract-command} {\\abstract} - \li \l {contentspage-command}{\\contentspage}, \li \l {ingroup-command}{\\ingroup}, + \li \l {inheaderfile-command}{\\inheaderfile}, \li \l {inherits-command}{\\inherits}, \li \l {inmodule-command}{\\inmodule}, \li \l {internal-command}{\\internal}, @@ -59,9 +59,12 @@ \li \l {preliminary-command}{\\preliminary}, \li \l {previouspage-command}{\\previouspage}, \li \l {qmlabstract-command} {\\qmlabstract} + \li \l {qtcmakepackage-command} {\\qtcmakepackage} + \li \l {readonly-command} {\\readonly} \li \l {reentrant-command}{\\reentrant}, \li \l {reimp-command}{\\reimp}, \li \l {relates-command}{\\relates}, + \li \l {required-command} {\\required} \li \l {since-command}{\\since}, \li \l {startpage-command}{\\startpage}, \li \l {subtitle-command}{\\subtitle} @@ -74,7 +77,6 @@ /*! \page 15-qdoc-commands-navigation.html \previouspage Context Commands - \contentspage QDoc Manual \nextpage Status \title Document Navigation @@ -141,7 +143,7 @@ \section2 \\previouspage The \\previouspage command links the current page to the previous - page in a sequence.a The command has two arguments, each enclosed + page in a sequence. The command has two arguments, each enclosed by curly braces: the first is the link target (the title of the previous page), the second is the link text. If the page's title is equivalent to the link text, the second argument can be @@ -169,20 +171,11 @@ documentation. The generated link type tells browsers and search engines which document is considered by the author to be the starting point of the collection. - - \target contentspage-command - \section2 \\contentspage - - The \\contentspage command links the current page to a table of - contents page. The command follows the same syntax and argument - convention as the \l {previouspage-command} {\\previouspage} - command. */ /*! \page 16-qdoc-commands-status.html \previouspage Document Navigation - \contentspage QDoc Manual \nextpage Thread Support \title Status @@ -228,14 +221,57 @@ This property holds the changes to apply for this state. \default - By default these changes are applied against the default state. If the state + By default, these changes are applied against the default state. If the state extends another state, then the changes are applied against the state being extended. * / \endcode See how QDoc renders this property on the reference page for the - \l {State::changes}{State} type. + \l {QtQuick::State::changes}{State} type. + + \target dontdocument-command + \section1 \\dontdocument + + The \\dontdocument command is only used in a dontdocument.qdoc file + for a particular module. This file specifies publically declared + classes or structs that are not meant to be documented. QDoc will + not print warnings about missing \\class comments for these classes + and structs. + + Below you will find the \\dontdocument command in the + dontdocument.qdoc for widgets: + + \badcode + / *! + \dontdocument (QTypeInfo QMetaTypeId) + * / + \endcode + + \target inheaderfile-command + \section1 \\inheaderfile + + The \\inheaderfile meta-command is used for overriding the include statement + generated for a C++ class, namespace, or header file reference documentation. + + By default, QDoc documents a \c {\class SomeClass} to be available with + a following include statement: + + \code + #include + \endcode + + If the actual include statement differs from the default, this can be + documented as + + \badcode + \class SomeClass + \inheaderfile Tools/SomeClass + ... + \endcode + + See also \l {class-command}{\\class} and + \l {headerfile-command}{\\headerfile}. \target obsolete-command \section1 \\obsolete @@ -244,7 +280,7 @@ deprecated, and it should no longer be used in new code. There is no guarantee for how long it will remain in the library. - The command must stand on its own line. + The \\obsolete command takes no arguments. When generating the reference documentation for a class, QDoc will create and link to a separate page documenting its obsolete @@ -316,7 +352,9 @@ } \endcode - This function will not be included in the documentation. + This function will not be included in the documentation, unless QDoc + is called with the \c{-showinternal} command line option or the + \c{QDOC_SHOW_INTERNAL} environment variable is set. \target preliminary-command \section1 \\preliminary @@ -373,6 +411,20 @@ \endlist \endquotation + \target readonly-command + \section1 \\readonly + + The \\readonly command is used in conjunction with a \l {qmlproperty-command} + {\\qmlproperty} command to mark the QML property as read-only. + + \target required-command + \section1 \\required + + The \\required command is used in conjunction with a \l {qmlproperty-command} + {\\qmlproperty} command to mark the QML property as required. + + \b {See also} \l {The Property System}. + \target since-command \section1 \\since @@ -423,7 +475,6 @@ /*! \page 17-qdoc-commands-thread.html \previouspage Status - \contentspage QDoc Manual \nextpage Relating Things \title Thread Support @@ -603,7 +654,6 @@ /*! \page 18-qdoc-commands-relating.html \previouspage Thread Support - \contentspage QDoc Manual \nextpage Grouping Things \title Relating Things @@ -654,11 +704,11 @@ \endcode QDoc includes this line on the reference page for the - \l{http://qt-project.org/doc/qt-4.7/qml-pauseanimation.html} {PauseAnimation} + \l [QML] PauseAnimation element: \quotation - Inherits \l{http://qt-project.org/doc/qt-4.7/qml-animation.html} {Animation} + Inherits \l [QML] Animation \endquotation \target overload-command @@ -675,9 +725,9 @@ should be fully documented. Each overload can have whatever extra documentation you want to add for just that overloaded version. - From Qt 4.5, you can include the function name plus '()' as a - parameter to the \b{\\overload} command, which will include a - standard \e{This function overloads...} line of text with a link + You can include the function name plus '()' as a parameter to + the \b{\\overload} command, which will include a standard + \e{This function overloads...} line of text with a link to the documentation for the primary version of the function. \code @@ -790,7 +840,6 @@ /*! \page 19-qdoc-commands-grouping.html \previouspage Relating Things - \contentspage QDoc Manual \nextpage Naming Things \title Grouping Things @@ -872,7 +921,6 @@ /*! \page 20-qdoc-commands-namingthings.html \previouspage Grouping Things - \contentspage QDoc Manual \nextpage Markup Commands \title Naming Things diff --git a/src/qdoc/doc/qdoc-manual-intro.qdoc b/src/qdoc/doc/qdoc-manual-intro.qdoc index 7ea3f1e364..8a89d66472 100644 --- a/src/qdoc/doc/qdoc-manual-intro.qdoc +++ b/src/qdoc/doc/qdoc-manual-intro.qdoc @@ -27,7 +27,6 @@ /*! \page 01-qdoc-manual.html - \contentspage QDoc Manual \previouspage QDoc Manual \nextpage Command Index @@ -89,7 +88,7 @@ \section1 Running QDoc - The name of the QDoc program is \c {qdoc}. To run qdoc from the + The name of the QDoc program is \c {qdoc}. To run QDoc from the command line, give it the name of a configuration file: \quotation @@ -161,7 +160,6 @@ /Users/me/qt5/qttools/src/designer/src/designer/doc/qtdesigner.qdocconf /Users/me/qt5/qttools/src/linguist/linguist/doc/qtlinguist.qdocconf /Users/me/qt5/qtwebkit-examples/doc/qtwebkitexamples.qdocconf - /Users/me/qt5/qtimageformats/src/imageformats/doc/qtimageformats.qdocconf /Users/me/qt5/qtgraphicaleffects/src/effects/doc/qtgraphicaleffects.qdocconf /Users/me/qt5/qtscript/src/script/doc/qtscript.qdocconf /Users/me/qt5/qtscript/src/scripttools/doc/qtscripttools.qdocconf @@ -206,7 +204,7 @@ module's, that module is said to depend on those other Qt modules. Hence when QDoc runs the \e {generate phase} for that module, it must also load the index files for those modules so it can create - those thinks. + those links. Hence, when the Qt build system generates the Qt documentation, it first runs QDoc once for each module to perform the \e {prepare @@ -285,7 +283,7 @@ For each QDoc comment it finds, it searches the master tree for the item where the documentation belongs. Then it interprets the - qdoc commands in the comment and stores the interpreted commands + QDoc commands in the comment and stores the interpreted commands and the comment text in the tree node for the item. Finally, QDoc traverses the master tree. For each node, if the diff --git a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc index 22b0b4e6b1..ee5387673a 100644 --- a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -27,7 +27,6 @@ /*! \page 03-qdoc-commands-markup.html - \contentspage QDoc Manual \previouspage Naming Things \nextpage Text Markup @@ -109,7 +108,6 @@ /*! \page 04-qdoc-commands-textmarkup.html - \contentspage QDoc Manual \previouspage Markup Commands \nextpage Document Structure @@ -208,9 +206,9 @@ text (which may include other QDoc commands) to which special formatting attributes should be applied. - An argument must be provided in curly braces, as in the qdoc + An argument must be provided in curly braces, as in the QDoc comment shown below. The argument is not interpreted but is used - as attribute(s) of the tag that is output by qdoc. + as attribute(s) of the tag that is output by QDoc. For example, we might want to render an inline image so that it floats to the right of the current block of text: @@ -224,7 +222,7 @@ * / \endcode - If qdoc is generating HTML, it will translate these commands to: + If QDoc is generating HTML, it will translate these commands to: \code

@@ -240,21 +238,6 @@ } \endcode - If qdoc is generating DITA XML, it will translate the commands to: - - \code - -

- - - -

-
- \endcode - - Your DITA XML publishing program must then recognize the \e - {outputclass} attribute value. - \note Note that the \b {\\div} command can be nested. Below you can find an example taken from the index.qdoc file used to @@ -320,53 +303,6 @@ \enddiv \enddiv - When generating DITA XML, qdoc outputs the nested \e {div} commands as: - - \code - - -

Qt Developer Guide

-
- - - -

Qt is a cross-platform application and UI - framework. Using Qt, you can write - web-enabled applications once and deploy - them across desktop, mobile and embedded - operating systems without rewriting the - source code. -

-
- -
    -
  • - Getting started -
  • -
  • - Installation -
  • -
  • - How to learn Qt -
  • -
  • - Tutorials -
  • -
  • - Examples -
  • -
  • - What's new in Qt 4.7 -
  • -
-
-
-
- \endcode - - Your DITA XML publishing program must recognize the values of the - \e {outputclass} attribute. - See also \l {span-command} {\\span}. \target span-command @@ -640,7 +576,6 @@ The \\uicontrol command is used to mark content as being used for UI control elements. When using HTML, the output is rendered in bold. - When using DITA XML the content is enclosed in a \c{uicontrol} tag. \sa \\b @@ -722,7 +657,6 @@ /*! \page 05-qdoc-commands-documentstructure.html \previouspage Text Markup - \contentspage QDoc Manual \nextpage Including Code Inline \title Document Structure @@ -921,7 +855,6 @@ /*! \page 06-qdoc-commands-includecodeinline.html \previouspage Document Structure - \contentspage QDoc Manual \nextpage Including External Code \title Including Code Inline @@ -1154,7 +1087,6 @@ /*! \page 07-0-qdoc-commands-includingexternalcode.html \previouspage Including Code Inline - \contentspage QDoc Manual \nextpage Creating Links \title Including External Code @@ -1364,7 +1296,7 @@ \target substring If the substring argument is surrounded by slashes it is - interpreted as a \l {QRegExp}{regular expression}. + interpreted as a \l {QRegularExpression}{regular expression}. \code / *! @@ -1503,10 +1435,10 @@ \printuntil hello First we create a \l - {http://doc.qt.io/qt-5/qapplication.html} {QApplication} + {http://doc.qt.io/qt-6/qapplication.html} {QApplication} object using the \c argc and \c argv parameters, then we create a \l - {http://doc.qt.io/qt-5/qpushbutton.html} {QPushButton}. + {http://doc.qt.io/qt-6/qpushbutton.html} {QPushButton}. \endquotation See also \l {printline-command} {\\printline} and \l @@ -1767,10 +1699,10 @@ ... \endcode - By default, qdoc looks for \c{//!} as a code snippet marker. + By default, QDoc looks for \c{//!} as a code snippet marker. For \c{.pro}, \c{.py}, \c{.cmake}, and \c{CMakeLists.txt} files, \c {#!} is detected. Finally, \c{ - - QWidget - the QWidget class is the base class of all user interface objects. - - Qt Development Frameworks - Qt Project - - - Qt Project - - - - - - - Class reference - - Qt Reference Documentation - - - - QtGui - - - - - - - \endcode - - In the example output, several values have been set using default - values obtained from the QDoc configuration file. See \l - {Generating DITA XML Output} for details. + effect on the generated output. \b {Example Metadata} @@ -3888,6 +3795,31 @@ This would result in the following tags: \e {tutorial,basic,hello,world}. Common words such as \e example are ignored. + \b {Excluding Examples} + + Marking an example \e broken will exclude it from the generated manifest + file, effectively removing it from Qt Creator's Welcome mode. + + \badcode + \meta tag broken + \endcode + + \b {Example Install Paths} + + The \\meta command combined with an argument \c installpath specifies the + location of an installed example. This value overrides the one that is set + using the \c examplesinstallpath configuration variable. + + \badcode + / *! + \example helloworld + \title Hello World Example + \meta {installpath} {tutorials} + * / + \endcode + + See also \l {examplesinstallpath}. + \target noautolist-command \section1 \\noautolist @@ -3898,15 +3830,12 @@ also be used with the \l {group-command}{\\group} command to omit the list of group members, when they are listed manually. - The command must stand on its own line. See \l {Qt Sensors QML Types} for - an example. The page is generated from \c {qtsensors5.qdoc}. There you will - find a qdoc comment containing the \c{\qmlmodule} command for the QtSensors - module. The same qdoc comment contains two \c {\annotated-list} commands to - list the QML types in two separate groups. The QML types have been divided - into these two groups because it makes more sense to list them this way than - it does to list them in a single alphabetical list. At the bottom of the - comment, \c {\noautolist} has been used to tell qdoc not to generate the - automatic annotated list. + The command must stand on its own line. See \l {Qt Quick Controls QML Types} + for an example. The page is generated from \c {qtquickcontrols2-qmlmodule.qdoc}. + There you will find a QDoc comment containing the \c{\qmlmodule} command for + the QtQuick.Controls module. The same comment contains a \c {\noautolist} + command to disable automatic list generation, and a \l {generatelist-command} + {\\generatelist} to list the QML types in a specific section of the document. This command was introduced in QDoc 5.6. @@ -3968,8 +3897,7 @@ The \\raw command and the corresponding \\endraw command delimit a block of raw mark-up language code. - \note Avoid using this command if possible, because it generates - DITA XML code that causes problems. If you are trying to generate + \note Avoid using this command if possible. If you are trying to generate special table or list behavior, try to get the behavior you want using the \l {span-command} {\\span} and \l {div-command} {\\div} commands in your \l {table-command} {\\table} or \l {list-command} @@ -4021,7 +3949,7 @@ \endraw \endquotation - \note But you can achieve the exact same thing using qdoc + \note But you can achieve the exact same thing using QDoc commands. In this case, all you have to do is include the color styles in your style.css file. Then you can write: diff --git a/src/qdoc/doc/qdoc-manual-qdocconf.qdoc b/src/qdoc/doc/qdoc-manual-qdocconf.qdoc index 0f38aabce4..eb2f8f5bf8 100644 --- a/src/qdoc/doc/qdoc-manual-qdocconf.qdoc +++ b/src/qdoc/doc/qdoc-manual-qdocconf.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -27,8 +27,7 @@ /*! \page 21-0-qdoc-configuration.html - \previouspage Creating DITA Maps - \contentspage QDoc Manual + \previouspage Miscellaneous \nextpage Generic Configuration Variables \title The QDoc Configuration File @@ -57,14 +56,17 @@ Qt online documentation. See the \l {Supporting Derived projects} section. + A valid configuration variable name can include upper and lower case + letters, numbers, and an underscore, '_'. + The value of a configuration variable can be set using either '=' or '+='. The difference is that '=' overrides the previous value, while '+=' adds a new value to the current one. - Some configuration variables accept a list of strings as their - value, for example: + Values of some configuration variables are interpreted as a list of + strings, for example: \l {sourcedirs-variable} - {\c{sourcedirs}}, while others accept only a single string. Double + {\c{sourcedirs}}, while others are treated as a single string. Double quotes around a value string are optional, but including them allows you to use special characters like '=' and ' \" ' within the value string, for example: @@ -76,12 +78,87 @@ If an entry spans many lines, use a backslash at the end of every line but the last: + \badcode + sourcedirs = kernel tools widgets + \endcode + + This can be written as: \badcode sourcedirs = kernel \ tools \ widgets \endcode + If a value spans multiple lines but is interpreted as a single string, + the lines are joined with spaces. + + \section1 Expansion of Configuration Values + + QDoc supports expanding environment variables within configuration files. + For example, Qt modules rely on the environment variable QT_INSTALL_DOCS + to include definitions related to all Qt module documentation projects: + + \badcode + include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf) + \endcode + + A variable to expand is prefixed with '$'. To use the literal character + '$' within a value string, escape it with a backslash: '\\$'. + + Since QDoc 6.0, values can be expanded also from other configuration + variables. In addition to the \c {$variable} syntax, also \c {${variable}} + is valid. The latter eliminates the need to separate the variable + name with whitespace or non-variable characters. For example: + + \badcode + baseurl = https://doc.qt.io/ + ... + url = ${baseurl}qtcreator + \endcode + + If the target variable refers to a list of strings, they will be + joined using spaces in the expanded value: + + \badcode + vars = foo \ + bar \ + baz + + items = "Items: $vars" # Expands to "Items: foo bar baz" + \endcode + + Controlling which character is used for joining the string list is also + possible: + + \badcode + items = "Items: ${vars,|}" # Expands to "Items: foo|bar|baz" + items = "Items: ${vars,,}" # Expands to "Items: foo,bar,baz" + items = "Items: ${vars,}" # Expands to "Items: foobarbaz" + \endcode + + As the expansion is performed after reading in all variables, the order + in which they are defined does not matter. + + \note Nested variable expansion is not supported. + + \section2 Expanding Environment Variables + + When expanding environment variables, the \c {${variable}} syntax has + different behavior compared to \c {$variable}. The former expands the + content of the variable in place to be parsed as part of the + configuration file, while the latter simply assigns the content as a + value for the current configuration variable. This has implications if + the environment variable contains a list of elements separated by + whitespace, or other formatting recognized by QDoc. + + For example, if the value of an environment variable \c SRCDIRS is + \c {"../src/a ../src/b"}, then + + \badcode + sourcedirs = $SRCDIRS # Fail - value is interpreted as a single path. + sourcedirs = ${SRCDIRS} # Ok - whitespace is used as a delimiter. + \endcode + \section1 Configuration Variables \section1 Variable List @@ -91,7 +168,7 @@ \li \l {Cpp.ignoredirectives-variable} {Cpp.ignoredirectives} \li \l {Cpp.ignoretokens-variable} {Cpp.ignoretokens} \li \l {defines-variable} {defines} - \li \l {edition-variable} {edition} + \li \l {depends-variable} {depends} \li \l {exampledirs-variable} {exampledirs} \li \l {examples-variable} {examples} \li \l {examples.fileextensions-variable} {examples.fileextensions} @@ -105,10 +182,14 @@ \li \l {HTML.footer-variable} {HTML.footer} \li \l {HTML.postheader-variable} {HTML.postheader} \li \l {HTML.style-variable} {HTML.style} + \li \l {ignorewords-variable} {ignorewords} + \li \l {ignoresince-variable} {ignoresince} \li \l {imagedirs-variable} {imagedirs} \li \l {images-variable} {images} \li \l {images.fileextensions-variable} {images.fileextensions} + \li \l {indexes-variable} {indexes} \li \l {language-variable} {language} + \li \l {locationinfo-variable} {locationinfo} \li \l {macro-variable} {macro} \li \l {manifestmeta-variable} {manifestmeta} \li \l {navigation-variable} {navigation} @@ -116,6 +197,7 @@ \li \l {outputformats-variable} {outputformats} \li \l {outputprefixes-variable} {outputprefixes} \li \l {outputsuffixes-variable} {outputsuffixes} + \li \l {project-variable} {project} \li \l {sourcedirs-variable} {sourcedirs} \li \l {sources-variable} {sources} \li \l {sources.fileextensions-variable} {sources.fileextensions} @@ -148,7 +230,6 @@ /*! \page 22-qdoc-configuration-generalvariables.html \previouspage The QDoc Configuration File - \contentspage QDoc Manual \nextpage Creating Help Project Files \title Generic Configuration Variables @@ -207,7 +288,7 @@ enclose documentation that only will be included if the preprocessor symbol is defined. - The values of the variable are regular expressions (see QRegExp + The values of the variable are regular expressions (see QRegularExpression for details). By default, no symbol is defined, meaning that code protected with #ifdef...#endif will be ignored. @@ -240,46 +321,67 @@ line using the -D option. For example: \badcode - currentdirectory$ qdoc -Dconsoleedition qtgui.qdocconf + currentdirectory$ qdoc -Dqtforpython qtgui.qdocconf \endcode - In this case the -D option ensures that the \c consoleedition + In this case the -D option ensures that the \c qtforpython preprocessor symbol is defined when QDoc processes the source files defined in the qtgui.qdocconf file. See also \l {falsehoods-variable} {falsehoods} and \l {if-command} {\\if}. - \target edition-variable - \section1 edition + \target depends-variable + \section1 depends + + The \c depends variable defines a list of other documentation projects + that this project depends on for resolving link targets for type + inheritance and anything else the documentation needs to link to. - The \c edition variable specifies which modules are included in - each edition of a package, and provides QDoc with information to - provide class lists for each edition. + Like Qt itself, documentation for Qt is distributed across multiple + modules. In a multi-module documentation project, the minimum set + of dependencies for a single module consists of actual build + dependencies. In addition, if there is a documentation project + (module) that acts as a top-level entry point for the entire + documentation set and provides \l {navigation-variable}[navigation} + links, each module documentation should include it as a dependency. - This feature is mostly used when providing documentation for Qt - packages. + When QDoc generates documentation for a project, it will also generate + an \c .index file containing URLs to each linkable entity in the project. + Each dependency is a (lowercase) name of a project. This name must + match with the base name of the index file generated for that + project. + + \badcode + depends = \ + qtdoc \ + qtcore \ + qtquick + \endcode - The \c edition variable is always used with a particular edition - name to define the modules for that edition: + When invoking QDoc on a project that has dependencies and uses the + \c depends variable, one or more \c -indexdir path(s) must be passed + as command line option(s). QDoc uses these paths to search for + the dependencies' index files. \badcode - edition.Console = QtCore QtNetwork QtSql QtXml - edition.Desktop = QtCore QtGui QtNetwork QtOpenGL QtSql QtXml \ - QtDesigner QtAssistant Qt3Support QAxContainer \ - QAxServer - edition.DesktopLight = QtCore QtGui Qt3SupportLight + qdoc mydoc.qdocconf -outputdir $PWD/html -indexdir $QT_INSTALL_DOCS \endcode - In the above examples, the \c Console edition only includes the - contents of four modules. Only the classes from these modules will - be used when the \l{Miscellaneous#generatelist-command} - {generatelist} command is used to generate a list of classes for - this edition: + With above, QDoc will search for a file + \c {$T_INSTALL_DOCS/qtdoc/qtdoc.index} for a dependency to \c qtdoc. + If an index file for a dependency is not found, QDoc will output a + warning. + + The \c depends command accepts also a special value of '*'. This + instructs QDoc to load all index files found in specified index + directories; that is, "depends on everything". \badcode - \generatelist{classesbyedition Console} + depends = * \endcode + See also \l indexes, \l project, and \l url. + \target exampledirs-variable \section1 exampledirs @@ -366,7 +468,7 @@ \section1 examples.fileextensions The \c examples.fileextensions variable specifies the file - extensions that qdoc will look for when collecting example files + extensions that QDoc will look for when collecting example files for display in the documentation. The default extensions are *.cpp, *.h, *.js, *.xq, *.svg, *.xml @@ -385,7 +487,7 @@ \section1 excludedirs The \c excludedirs variable is for listing directories that should \e{not} - be processed by qdoc, even if the same directories are included by the + be processed by QDoc, even if the same directories are included by the \l {sourcedirs-variable} {sourcedirs} or \l {headerdirs-variable} {headerdirs} variables. @@ -398,7 +500,7 @@ When executed, QDoc will exclude the listed directories from further consideration. Files in these directories will not be - read by qdoc. + read by QDoc. See also \l {excludefiles-variable} {excludefiles}. @@ -406,7 +508,7 @@ \section1 excludefiles The \c excludefiles variable allows you to specify individual files - that should \e{not} be processed by qdoc. + that should \e{not} be processed by QDoc. \badcode excludefiles += $QT_CORE_SOURCES/../../src/widgets/kernel/qwidget.h \ @@ -459,7 +561,7 @@ The \c falsehoods variable defines the truth value of specified preprocessor symbols as false. - The values of the variable are regular expressions (see QRegExp + The values of the variable are regular expressions (see QRegularExpression for details). If this variable is not set for a preprocessor symbol, QDoc assumes its truth value is true. The exception is '0', which is always false. @@ -595,6 +697,70 @@ See also \l headerdirs. + \target ignorewords-variable + \section1 ignorewords + + The \c ignorewords variable is used for specifying a list of strings + that QDoc will ignore when resolving hyperlink targets. + + QDoc has an auto-linking feature, where linking is attempted for words + that resemble C++, QML, or JavaScript entities. Specifically, a string + qualifies for auto-linking if it is at least three characters in + length, has no whitespace, and it + + \list + \li is a \e camelCase word, that is, it contains at least one + uppercase character at index greater than zero, or + \li contains the substring \c {()} or \c {::}, or + \li contains at least one special character, \c {@} or \c {_}. + \endlist + + Adding a qualified word to \c ignorewords stops QDoc from linking + that word automatically. For example, if the word \e OpenGL is a + valid link target (a section, \l{page-command}{\\page}, or + \l {externalpage-command}{\\externalpage} title), a hyperlink for + each occurrence can be avoided with + + \badcode + ignorewords += OpenGL + \endcode + + Linking explicitly with \l {l-command}{\\l} continues to work for + ignored words. + + The \c ignorewords variable was introduced in QDoc 5.14. + + \target ignoresince-variable + \section1 ignoresince + + The \c ignoresince variable is used for setting a cutoff value for + versions passed to the \l {since-command}{\\since} command. All + \\since commands that define a version lower than the cutoff are + ignored and do not generate output. + + The cutoff values are project-specific. The project name can be + defined as a subvariable. The default project name is \e Qt. For + example: + + \badcode + ignoresince = 5.0 + ignoresince.QDoc = 5.0 + \endcode + + These will ignore \\since commands where the major version is 4 + or lower and the project is either \c QDoc or undefined. + + \badcode + \since 3.2 # Ignored + \since 5.2 # Documented (as 'Qt 5.2') + \since QDoc 4.6 # Ignored + \since QtQuick 2.5 # Documented + \endcode + + The \c ignoresince variable was introduced in QDoc 5.15. + + See also \l {since-command}{\\since}. + \target imagedirs-variable \section1 imagedirs @@ -723,6 +889,28 @@ This identifies C++ as the language of the Qt source code. + \target locationinfo-variable + \section1 locationinfo + + The \c locationinfo boolean variable determines whether detailed + location information about each entity is written to + \c {.index}-files and \c {.webxml}-files (when using the WebXML + output format). + + Location information consists of the full path and line + number of either the declaration or documentation comment block + in the source code. + + Setting this to \c false turns off location info: + + \badcode + locationinfo = false + \endcode + + The default value is \c true. + + The \c locationinfo variable was introduced in QDoc 5.15. + \target macro-variable \section1 macro @@ -732,9 +920,7 @@ A macro variable can be restricted for use in one type of output generation. By appending \c {.HTML} to the macro name, for - example, the macro is only used when generating HTML output. By - appending \c {.DITAXML} to the macro name, the macro is only used - when generating DITA XML. + example, the macro is only used when generating HTML output. \badcode macro.gui = "\\b" @@ -800,7 +986,7 @@ \section1 naturallanguage The \c naturallanguage variable specifies the natural language - used for the documentation generated by qdoc. + used for the documentation generated by QDoc. \badcode naturallanguage = zh-Hans @@ -809,7 +995,7 @@ By default, the natural language is \c en for compatibility with legacy documentation. - qdoc will add the natural language information to the HTML it + QDoc will add the natural language information to the HTML it generates, using the \c lang and \c xml:lang attributes. See also \l {sourceencoding-variable} {sourceencoding}, @@ -855,6 +1041,12 @@ \row \li \c navigation.qmltypestitle \li (Optional) User-visible title for the QML types page. Default is "QML Types". + \row \li \c navigation.toctitles (Since QDoc 6.0) + \li Page title(s) containing a \l {list-command}{\\list} structure that + acts as a table of contents (TOC). QDoc generates navigation links + for pages listed in the TOC, without the need for + \l {nextpage-command}{\\nextpage} and \l {previouspage-command} + {\\previouspage} commands. \endtable For example: @@ -903,7 +1095,7 @@ \section1 outputencoding The \c outputencoding variable specifies the encoding used for the - documentation generated by qdoc. + documentation generated by QDoc. \badcode outputencoding = UTF-8 @@ -915,7 +1107,7 @@ languages, this is not sufficient and an encoding such as UTF-8 is required. - qdoc will encode HTML using this encoding and generate the correct + QDoc will encode HTML using this encoding and generate the correct declarations to indicate to browsers which encoding is being used. The \l naturallanguage configuration variable should also be specified to provide browsers with a complete set of character @@ -929,9 +1121,10 @@ The \c outputformats variable specifies the format(s) of the generated documentation. - Since Qt 5.11, QDoc supports the HTML and WebXML formats. If no + Since Qt 5.11, QDoc supports the HTML and WebXML formats; since + Qt 5.15, it can also generate the documentation in DocBook. If no \c outputformats are specified, QDoc generates the documentation - in HTML (the default format). Both output formats can be specified, + in HTML (the default format). All output formats can be specified, with dedicated output directories and other settings. For example: \badcode @@ -1047,7 +1240,7 @@ particularly non-European languages, this is not sufficient and an encoding such as UTF-8 is required. - Although qdoc will use the encoding to read source and + Although QDoc will use the encoding to read source and documentation files, limitations of C++ compilers may prevent you from using non-ASCII characters in source code comments. In cases like these, it is possible to write API documentation completely @@ -1187,7 +1380,7 @@ QT_VERSION_STR is defined in qglobal.h as follows \badcode - #define QT_VERSION_STR "4.0.1" + #define QT_VERSION_STR "5.14.1" \endcode When a version number is specified (using the \tt{\l version} or @@ -1229,7 +1422,6 @@ /*! \page 22-creating-help-project-files.html \previouspage Generic Configuration Variables - \contentspage QDoc Manual \nextpage C++ Specific Configuration Variables \title Creating Help Project Files @@ -1363,7 +1555,6 @@ /*! \page 23-qdoc-configuration-cppvariables.html \previouspage Creating Help Project Files - \contentspage QDoc Manual \nextpage Format-specific Configuration Variables \title C++ Specific Configuration Variables @@ -1474,7 +1665,6 @@ /*! \page 24-qdoc-configuration-htmlvariables.html \previouspage C++ Specific Configuration Variables - \contentspage QDoc Manual \nextpage Supporting Derived Projects \keyword HTML Specific Configuration Variables @@ -1625,7 +1815,6 @@ /*! \page 25-qdoc-configuration-derivedprojects.html \previouspage Format-specific Configuration Variables - \contentspage QDoc Manual \nextpage Example Manifest Files \title Supporting Derived Projects @@ -1647,24 +1836,30 @@ \target indexes-variable \section1 indexes - The \c indexes variable lists the index files that will be used to - generate references. - - For example. to make a derived Qt project contain links to the Qt - Reference documentation, you need to specify the associated index - file: + The \l {indexes-variable}[indexes} variable defines a set of paths + to index files to load. \badcode - indexes = $QTDIR/doc/html/qt.index + indexes = \ + $QT_INSTALL_DOCS/qtcore/qtcore.index \ + $SOME_OTHER_PROJECT/doc/foo.index \endcode - See also \l project and \l url. + The \c indexes variable provides an alternative to \l depends for + defining project's dependencies. As direct paths are provided, no + \c -indexdir command line option(s) are required when invoking QDoc. + + It is possible to define dependencies using either variable. Qt + documentation only uses the \c depends variable. + + See also \l depends, \l project and \l url. \target project-variable \section1 project The \c project variable provides a name for the project associated - with the \c .qdocconf file. + with the \c .qdocconf file. This is a mandatory variable that all + projects must set. The project's name is used to form a file name for the associated project's \e index file. @@ -1676,12 +1871,16 @@ This will cause an index file called \c qtcreator.index to be created. - See also \l description and \l indexes. + If the project name contains whitespace or special characters, + these are replaced with dashes ('-') in the generated index file + name. + + See also \l depends, \l indexes, and \l description. \target url-variable \section1 url - The \c url variable holds the base URL for the reference + The \c url variable holds the base URL for the documentation associated with the current project. The URL is stored in the generated index file for the @@ -1690,18 +1889,18 @@ other things listed in the index. \badcode - project = Qt - description = Qt Reference Documentation - url = http://doc.qt.io/qt-4.8/ + project = QtCore + description = Qt Core Reference Documentation + url = https://doc.qt.io/qt/ - ... + ... \endcode - This makes sure that whenever \c qt.index is used to generate - references to for example Qt classes, the base URL is \c - http://doc.qt.io/qt-4.8/. + This ensures that whenever QDoc generates + references to entities in the Qt Core module, the base URL is + \c https://doc.qt.io/qt/. - See also \l indexes and \l {url.examples}. + See also \l depends, \l indexes and \l {url.examples}. \target url.examples-variable \section1 url.examples @@ -1761,29 +1960,29 @@ This feature makes use of the comprehensive indexes generated by QDoc when it creates the Qt reference documentation. - For example, \l qtgui.qdocconf (the configuration file for Qt) + For example, \l qtgui.qdocconf (the configuration file for Qt GUI) contains the following variable definitions: \badcode - project = Qt - description = Qt Reference Documentation - url = http://doc.qt.io/qt-4.8/ + project = QtGui + description = Qt GUI Reference Documentation + url = http://doc.qt.io/qt/ ... \endcode The \l project variable name is used to form a file name for the - index file; in this case the \c qt.index file is created. The \l + index file; in this case the \c qtgui.index file is created. The \l url is stored in the index file. Afterwards, QDoc will use this as the base URL when constructing links to classes, functions, and other things listed in the index. + See also \l depends, \l indexes, \l project, and \l url. */ /*! \page 26-qdoc-configuration-example-manifest-files.html \previouspage Supporting Derived Projects - \contentspage QDoc Manual \title Example Manifest Files @@ -1861,71 +2060,11 @@ another tag is applied to all examples by using just \c {*} as the match string. */ -/*! - \page 21-3-qt-dita-xml-output.html - \previouspage minimum.qdocconf - \contentspage QDoc Manual - \nextpage QA Pages - - \title Generating DITA XML Output - - QDoc can generate \l {http://dita.xml.org} {DITA XML output}. - - In your configuration file, set your \c {outputformats} variable - to \c {DITAXML}, and send the output to an appropriate directory: - - \badcode - outputdir = $QTDIR/doc/ditaxml - outputformats = DITAXML - \endcode - - And include these macros in your configuration file to prevent - QDoc from doing some escaping that doesn't validate in XML: - - \badcode - macro.aacute.DITAXML = "á" - macro.Aring.DITAXML = "Å" - macro.aring.DITAXML = "å" - macro.Auml.DITAXML = "Ä" - macro.br.DITAXML = " " - macro.BR.DITAXML = " " - macro.copyright.DITAXML = "©" - macro.eacute.DITAXML = "é" - macro.hr.DITAXML = " " - macro.iacute.DITAXML = "í" - macro.oslash.DITAXML = "ø" - macro.ouml.DITAXML = "ö" - macro.raisedaster.DITAXML = "*" - macro.rarrow.DITAXML = "→" - macro.reg.DITAXML = "®" - macro.uuml.DITAXML = "ü" - macro.mdash.DITAXML = "—" - macro.emptyspan.DITAXML = " " - \endcode - - You can also set default values for some of the tags in the DITA - \c {} and \c {} elements: - - \badcode - dita.metadata.default.author = Qt Development Frameworks - dita.metadata.default.permissions = all - dita.metadata.default.publisher = Qt Project - dita.metadata.default.copyryear = 2018 - dita.metadata.default.copyrholder = Qt Project - dita.metadata.default.audience = programmer - \endcode - - See the \l {meta-command} - {\\meta} command for more details on DITA metadata. - -*/ - /*! \page 21-1-minimum-qdocconf.html \previouspage qtgui.qdocconf - \contentspage QDoc Manual - \nextpage Generating DITA XML Output + \nextpage The QDoc Configuration File \title minimum.qdocconf @@ -1935,7 +2074,6 @@ /*! \page 21-2-qtgui-qdocconf.html \previouspage Supporting Derived Projects - \contentspage QDoc Manual \nextpage minimum.qdocconf \title qtgui.qdocconf diff --git a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc index 4e80f8f125..97befbe509 100644 --- a/src/qdoc/doc/qdoc-manual-topiccmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-topiccmds.qdoc @@ -28,7 +28,6 @@ /*! \page 13-qdoc-commands-topics.html \previouspage Command Index - \contentspage QDoc Manual \nextpage Context Commands \title Topic Commands @@ -307,6 +306,7 @@ \omitvalue TopRight \omitvalue BottomLeft \omitvalue BottomRight + Bottom-right (omitted; not documented). * / \endcode @@ -465,9 +465,15 @@ \section1 \\fn (function) The \\fn command is for documenting a function. The argument is - the function's signature, including its return type, const-ness, - and list of formal arguments with types. If the named function - doesn't exist, QDoc emits a warning. + the function's signature, including its template parameters (if + any), return type, const-ness, and list of formal arguments with + types. If the named function doesn't exist, QDoc emits a warning. + + Since QDoc version 6.0, the \\fn command can be used for documenting + class members that are not explicitly declared in the header, + but are implicitly generated by the compiler; default constructor + and destructor, copy constructor and move-copy constructor, + assignment operator, and move-assignment operator. \note The \\fn command is QDoc's default command: when no topic command can be found in a QDoc comment, QDoc tries to tie @@ -500,6 +506,11 @@ \a area; otherwise returns \c false. \endquotation + \note Running in debug mode (pass the \c {-debug} command line option + or set the \c QDOC_DEBUG environment variable before invoking QDoc) + can help troubleshoot \\fn commands that QDoc fails to parse. In + debug mode, additional diagnostic information is available. + See also \l {overload-command} {\\overload}. \target group-command @@ -665,6 +676,8 @@ ... \endquotation + See also \l {inheaderfile-command}{\\inheaderfile}. + \target macro-command \section1 \\macro @@ -812,20 +825,12 @@ - - - - @@ -884,7 +889,7 @@ \quotation \raw HTML -

Qt Namespace Reference

+

Qt Namespace

The Qt namespace contains miscellaneous identifiers used throughout the Qt library. More... @@ -893,15 +898,15 @@

#include <Qt>

Types


\endraw @@ -937,22 +942,24 @@ \list + \li api - This is the type of page used for C++ class references and + QML type references. You should never use this one for the pages + you write, because this one is reserved for QDoc. + + \li attribution - A page describing (code) attributions. + + \li example - A page that describes a working example. + \li faq - A frequently asked question. \li howto - A user guide on how to use some components of the software. - \li example - A page that describes a working example. - \li overview - For text pages that provide an overview of some important subject. \li tutorial - For text pages that are part of a tutorial. - \li api - This is the type of page used for C++ class references and - QML type references. You should never use this one for the pages - you write, because this one is reserved for qdoc. - \endlist The page title is set using the \l {title-command} {\\title} @@ -1206,7 +1213,7 @@ \endcode This example generates the - \l {http://qt-project.org/doc/qt-4.7/qml-transform.html} {QML Transform} + \l {https://doc.qt.io/qt-5/qml-qtquick-transform.html} {QML Transform} page. The \\qmlclass comment should include the \l {since-command} {\\since} command, because all QML types are new. It should also include the \l{brief-command} {\\brief} @@ -1254,33 +1261,16 @@ / *! \qmltype Transform \instantiates QGraphicsTransform - \ingroup qml-transform-elements - \since 4.7 - \brief The Transform elements provide a way to build - advanced transformations on Items. + \inqmlmodule QtQuick - The Transform element is a base type which cannot be - instantiated directly. The concrete Transform types are: - - \list - \li \l Rotation - \li \l Scale - \li \l Translate - \endlist - - The Transform elements let you create and control advanced - transformations that can be configured independently using - specialized properties. - - You can assign any number of Transform elements to an \l - Item. Each Transform is applied in order, one at a time. + \brief Provides a way to build advanced transformations on Items. + The Transform element is a base type which cannot be + instantiated directly. * / \endcode - The example generates the \l - {http://qt-project.org/doc/qt-4.7/qml-transform.html} {QML Transform} - page. The \e{\\qmltype} comment includes \l{instantiates-command} + Here, the \e{\\qmltype} comment includes \l{instantiates-command} {\\instantiates} to specify that a Transform is instantiated by the C++ class QGraphicsTransform. A \\qmltype comment should always include a \l {since-command} {\\since} command, because all @@ -1365,9 +1355,6 @@ responds to a \c clicked() event. \endcode - The \l{componentset}{UIComponents} example demonstrates proper usage of - QDoc commands to document QML types and QML modules. - \target inqmlmodule-command \section1 \\inqmlmodule @@ -1387,9 +1374,6 @@ To link to the \c ClickableButton, use the \c{\l ClickableComponents::ClickableButton} format. - The \l{componentset}{UIComponents} example demonstrates proper usage of - QDoc commands to document QML types and QML modules. - The \l {noautolist-command} {\\noautolist} command can be used here to omit the automatically generated list of types at the end. @@ -1407,21 +1391,52 @@ / *! \qmltype Transform \instantiates QGraphicsTransform - \ingroup qml-transform-elements - \since 4.7 - \brief Provides elements provide a way to build - advanced transformations on Items. + \inqmlmodule QtQuick + + \brief Provides a way to build advanced transformations on Items. The Transform element is a base type which cannot be instantiated directly. * / \endcode - The example generates the \l - {http://qt-project.org/doc/qt-4.7/qml-transform.html} {QML Transform} - page. The \e{\\qmltype} comment includes \l{instantiates-command} + Here, the \e{\\qmltype} comment includes \l{instantiates-command} {\\instantiates} to specify that a Transform is instantiated by - the C++ class QGraphicsTransform. A \\qmltype comment should + the C++ class QGraphicsTransform. + + \target typealias-command + \section1 \\typealias + + The \\typealias command is similar to \l {typedef-command}{\\typedef}, + but specific to documenting a C++ type alias: + + \code + class Foo + { + public: + using ptr = void*; + // ... + } + \endcode + + This can be documented as + + \badcode * + /\1! + \typealias Foo::ptr + \1/ + \endcode + + QDoc will automatically generate a sentence in the documentation describing + the alias: + + \quotation + This is a type alias for \c {void*}. + \endquotation + + The \\typealias command was introduced in QDoc 5.15. + + See also \l {typedef-command}{\\typedef}. \target typedef-command \section1 \\typedef @@ -1467,7 +1482,7 @@ void myMsgHandler(QtMsgType, const char *); \ endcode - \sa QtMsgType, qInstallMsgHandler() + \sa QtMsgType, qInstallMessageHandler() * / \endcode @@ -1487,7 +1502,7 @@ \endraw - See also QtMsgType and qInstallMsgHandler(). + See also QtMsgType and qInstallMessageHandler(). \endquotation Other typedefs are located on the reference page for the class @@ -1495,22 +1510,24 @@ \code / *! - \typedef QLinkedList::Iterator + \typedef QList::Iterator Qt-style synonym for QList::iterator. * / \endcode - QDoc includes this one on the reference page for class QLinkedList as: + QDoc includes this one on the reference page for class QList as: \quotation \raw HTML -

typedef QLinkedList::Iterator

+

typedef QList::Iterator

\endraw Qt-style synonym for QList::iterator. \endquotation + See also \l {typealias-command}{\\typealias}. + \target variable-command \section1 \\variable diff --git a/src/qdoc/doc/qdoc-manual.qdoc b/src/qdoc/doc/qdoc-manual.qdoc index 716f8c73f7..1650865b29 100644 --- a/src/qdoc/doc/qdoc-manual.qdoc +++ b/src/qdoc/doc/qdoc-manual.qdoc @@ -57,7 +57,6 @@ \li \l {Special Content} \li \l {Miscellaneous} \endlist - \li \l{Creating DITA Maps} \li \l {The QDoc Configuration File} \list \li \l {Generic Configuration Variables} @@ -68,11 +67,7 @@ \li \l {Example Manifest Files} \li \l {qtgui.qdocconf} \li \l {minimum.qdocconf} - \li \l {Generating DITA XML Output} \endlist - \li \l {QA Pages} \endlist - */ - diff --git a/src/qdoc/doc/qtgui-qdocconf.qdoc b/src/qdoc/doc/qtgui-qdocconf.qdoc index eaed76c674..89c46ff94d 100644 --- a/src/qdoc/doc/qtgui-qdocconf.qdoc +++ b/src/qdoc/doc/qtgui-qdocconf.qdoc @@ -137,7 +137,7 @@ to content listed in the index. \note QDoc omits this value when the -installdir argument is specified when running QDoc. -\keyword examplesinstallpath +\target examplesinstallpath \badcode examplesinstallpath = gui @@ -150,7 +150,11 @@ installed in the \e gui directory under the parent examples directory \note The examplepath variable has to match the example directory specified in \c exampledirs. -\b {See also}: \l {exampledirs}. +\note It is possible to override the \c exampleinstallpath for a specific + \l {example-command}{\\example} using the \l {meta-command}{\\meta} + command. + +\b {See also}: \l {exampledirs} and \l {meta-command}{\\meta}. \badcode qhp.projects = QtGui @@ -269,7 +273,7 @@ Add the specified directories to the list of directories containing the \e .cpp \endcode The \c excludedirs variable is for listing directories that should not be processed -by qdoc, even if the same directories are included by the \c sourcedirs or \c headerdirs +by QDoc, even if the same directories are included by the \c sourcedirs or \c headerdirs variables. When executed, QDoc will ignore the directories listed. diff --git a/src/qdoc/docbookgenerator.cpp b/src/qdoc/docbookgenerator.cpp new file mode 100644 index 0000000000..c04eccd9d6 --- /dev/null +++ b/src/qdoc/docbookgenerator.cpp @@ -0,0 +1,4267 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Thibaut Cuvelier +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "docbookgenerator.h" + +#include "access.h" +#include "aggregate.h" +#include "classnode.h" +#include "codemarker.h" +#include "collectionnode.h" +#include "config.h" +#include "enumnode.h" +#include "examplenode.h" +#include "functionnode.h" +#include "generator.h" +#include "node.h" +#include "propertynode.h" +#include "quoter.h" +#include "qdocdatabase.h" +#include "qmlpropertynode.h" +#include "sharedcommentnode.h" +#include "typedefnode.h" +#include "variablenode.h" + +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static const char dbNamespace[] = "http://docbook.org/ns/docbook"; +static const char xlinkNamespace[] = "http://www.w3.org/1999/xlink"; + +inline void DocBookGenerator::newLine() +{ + writer->writeCharacters("\n"); +} + +void DocBookGenerator::startSectionBegin() +{ + writer->writeStartElement(dbNamespace, "section"); + newLine(); + writer->writeStartElement(dbNamespace, "title"); +} + +void DocBookGenerator::startSectionBegin(const QString &id) +{ + writer->writeStartElement(dbNamespace, "section"); + writer->writeAttribute("xml:id", id); + newLine(); + writer->writeStartElement(dbNamespace, "title"); +} + +void DocBookGenerator::startSectionEnd() +{ + writer->writeEndElement(); // title + newLine(); +} + +void DocBookGenerator::startSection(const QString &id, const QString &title) +{ + startSectionBegin(id); + writer->writeCharacters(title); + startSectionEnd(); +} + +void DocBookGenerator::endSection() +{ + writer->writeEndElement(); // section + newLine(); +} + +void DocBookGenerator::writeAnchor(const QString &id) +{ + writer->writeEmptyElement(dbNamespace, "anchor"); + writer->writeAttribute("xml:id", id); + newLine(); +} + +/*! + Initializes the DocBook output generator's data structures + from the configuration (Config). + */ +void DocBookGenerator::initializeGenerator() +{ + // Excerpts from HtmlGenerator::initializeGenerator. + Generator::initializeGenerator(); + config = &Config::instance(); + + project = config->getString(CONFIG_PROJECT); + + projectDescription = config->getString(CONFIG_DESCRIPTION); + if (projectDescription.isEmpty() && !project.isEmpty()) + projectDescription = project + QLatin1String(" Reference Documentation"); + + naturalLanguage = config->getString(CONFIG_NATURALLANGUAGE); + if (naturalLanguage.isEmpty()) + naturalLanguage = QLatin1String("en"); + + buildversion = config->getString(CONFIG_BUILDVERSION); +} + +QString DocBookGenerator::format() +{ + return QStringLiteral("DocBook"); +} + +/*! + Returns "xml" for this subclass of Generator. + */ +QString DocBookGenerator::fileExtension() const +{ + return QStringLiteral("xml"); +} + +/*! + Generate the documentation for \a relative. i.e. \a relative + is the node that represents the entity where a qdoc comment + was found, and \a text represents the qdoc comment. + */ +bool DocBookGenerator::generateText(const Text &text, const Node *relative, CodeMarker *marker) +{ + Q_UNUSED(marker); + // From Generator::generateText. + if (!text.firstAtom()) + return false; + + int numAtoms = 0; + initializeTextOutput(); + generateAtomList(text.firstAtom(), relative, true, numAtoms); + closeTextSections(); + return true; +} + +/*! + Generate the text for \a atom relatively to \a relative. + \a generate indicates if output to \a writer is expected. + The number of generated atoms is returned in the argument + \a numAtoms. The returned value is the first atom that was not + generated. + */ +const Atom *DocBookGenerator::generateAtomList(const Atom *atom, const Node *relative, + bool generate, int &numAtoms) +{ + Q_ASSERT(writer); + // From Generator::generateAtomList. + while (atom) { + switch (atom->type()) { + case Atom::FormatIf: { + int numAtoms0 = numAtoms; + atom = generateAtomList(atom->next(), relative, generate, numAtoms); + if (!atom) + return nullptr; + + if (atom->type() == Atom::FormatElse) { + ++numAtoms; + atom = generateAtomList(atom->next(), relative, false, numAtoms); + if (!atom) + return nullptr; + } + + if (atom->type() == Atom::FormatEndif) { + if (generate && numAtoms0 == numAtoms) { + relative->location().warning(QStringLiteral("Output format %1 not handled %2") + .arg(format()) + .arg(outFileName())); + Atom unhandledFormatAtom(Atom::UnhandledFormat, format()); + generateAtomList(&unhandledFormatAtom, relative, generate, numAtoms); + } + atom = atom->next(); + } + } break; + case Atom::FormatElse: + case Atom::FormatEndif: + return atom; + default: + int n = 1; + if (generate) { + n += generateAtom(atom, relative); + numAtoms += n; + } + while (n-- > 0) + atom = atom->next(); + } + } + return nullptr; +} + +/*! + Generate DocBook from an instance of Atom. + */ +int DocBookGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker) +{ + Q_ASSERT(writer); + Q_UNUSED(marker); + // From HtmlGenerator::generateAtom, without warning generation. + int idx = 0; + int skipAhead = 0; + static bool inPara = false; + Node::Genus genus = Node::DontCare; + + switch (atom->type()) { + case Atom::AutoLink: + // Allow auto-linking to nodes in API reference + genus = Node::API; + Q_FALLTHROUGH(); + case Atom::NavAutoLink: + if (!inLink && !m_inContents && !m_inSectionHeading) { + const Node *node = nullptr; + QString link = getAutoLink(atom, relative, &node, genus); + if (!link.isEmpty() && node && node->status() == Node::Obsolete + && relative->parent() != node && !relative->isObsolete()) { + link.clear(); + } + if (link.isEmpty()) { + writer->writeCharacters(atom->string()); + } else { + beginLink(link, node, relative); + generateLink(atom); + endLink(); + } + } else { + writer->writeCharacters(atom->string()); + } + break; + case Atom::BaseName: + break; + case Atom::BriefLeft: + if (!hasBrief(relative)) { + skipAhead = skipAtoms(atom, Atom::BriefRight); + break; + } + writer->writeStartElement(dbNamespace, "para"); + rewritePropertyBrief(atom, relative); + break; + case Atom::BriefRight: + if (hasBrief(relative)) { + writer->writeEndElement(); // para + newLine(); + } + break; + case Atom::C: + // This may at one time have been used to mark up C++ code but it is + // now widely used to write teletype text. As a result, text marked + // with the \c command is not passed to a code marker. + writer->writeTextElement(dbNamespace, "code", plainCode(atom->string())); + break; + case Atom::CaptionLeft: + writer->writeStartElement(dbNamespace, "title"); + break; + case Atom::CaptionRight: + endLink(); + writer->writeEndElement(); // title + newLine(); + break; + case Atom::Qml: + writer->writeStartElement(dbNamespace, "programlisting"); + writer->writeAttribute("language", "qml"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // programlisting + newLine(); + break; + case Atom::JavaScript: + writer->writeStartElement(dbNamespace, "programlisting"); + writer->writeAttribute("language", "js"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // programlisting + newLine(); + break; + case Atom::CodeNew: + writer->writeTextElement(dbNamespace, "para", "you can rewrite it as"); + newLine(); + writer->writeStartElement(dbNamespace, "programlisting"); + writer->writeAttribute("language", "cpp"); + writer->writeAttribute("role", "new"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // programlisting + newLine(); + break; + case Atom::Code: + writer->writeStartElement(dbNamespace, "programlisting"); + writer->writeAttribute("language", "cpp"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // programlisting + newLine(); + break; + case Atom::CodeOld: + writer->writeTextElement(dbNamespace, "para", "For example, if you have code like"); + newLine(); + Q_FALLTHROUGH(); + case Atom::CodeBad: + writer->writeStartElement(dbNamespace, "programlisting"); + writer->writeAttribute("language", "cpp"); + writer->writeAttribute("role", "bad"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // programlisting + newLine(); + break; + case Atom::DivLeft: + case Atom::DivRight: + break; + case Atom::FootnoteLeft: + writer->writeStartElement(dbNamespace, "footnote"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + break; + case Atom::FootnoteRight: + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // footnote + break; + case Atom::FormatElse: + case Atom::FormatEndif: + case Atom::FormatIf: + break; + case Atom::FormattingLeft: + if (atom->string() == ATOM_FORMATTING_BOLD) { + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + } else if (atom->string() == ATOM_FORMATTING_ITALIC) { + writer->writeStartElement(dbNamespace, "emphasis"); + } else if (atom->string() == ATOM_FORMATTING_UNDERLINE) { + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "underline"); + } else if (atom->string() == ATOM_FORMATTING_SUBSCRIPT) { + writer->writeStartElement(dbNamespace, "sub"); + } else if (atom->string() == ATOM_FORMATTING_SUPERSCRIPT) { + writer->writeStartElement(dbNamespace, "sup"); + } else if (atom->string() == ATOM_FORMATTING_TELETYPE + || atom->string() == ATOM_FORMATTING_PARAMETER) { + writer->writeStartElement(dbNamespace, "code"); + + if (atom->string() == ATOM_FORMATTING_PARAMETER) + writer->writeAttribute("role", "parameter"); + } + break; + case Atom::FormattingRight: + if (atom->string() == ATOM_FORMATTING_BOLD || atom->string() == ATOM_FORMATTING_ITALIC + || atom->string() == ATOM_FORMATTING_UNDERLINE + || atom->string() == ATOM_FORMATTING_SUBSCRIPT + || atom->string() == ATOM_FORMATTING_SUPERSCRIPT + || atom->string() == ATOM_FORMATTING_TELETYPE + || atom->string() == ATOM_FORMATTING_PARAMETER) { + writer->writeEndElement(); + } + if (atom->string() == ATOM_FORMATTING_LINK) + endLink(); + break; + case Atom::AnnotatedList: + if (const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), Node::Group)) + generateList(cn, atom->string()); + break; + case Atom::GeneratedList: + if (atom->string() == QLatin1String("annotatedclasses") + || atom->string() == QLatin1String("attributions") + || atom->string() == QLatin1String("namespaces")) { + const NodeMultiMap things = atom->string() == QLatin1String("annotatedclasses") + ? m_qdb->getCppClasses() + : atom->string() == QLatin1String("attributions") ? m_qdb->getAttributions() + : m_qdb->getNamespaces(); + generateAnnotatedList(relative, things.values(), atom->string()); + } else if (atom->string() == QLatin1String("annotatedexamples") + || atom->string() == QLatin1String("annotatedattributions")) { + const NodeMultiMap things = atom->string() == QLatin1String("annotatedexamples") + ? m_qdb->getAttributions() + : m_qdb->getExamples(); + generateAnnotatedLists(relative, things, atom->string()); + } else if (atom->string() == QLatin1String("classes") + || atom->string() == QLatin1String("qmlbasictypes") + || atom->string() == QLatin1String("qmltypes")) { + const NodeMultiMap things = atom->string() == QLatin1String("classes") + ? m_qdb->getCppClasses() + : atom->string() == QLatin1String("qmlbasictypes") ? m_qdb->getQmlBasicTypes() + : m_qdb->getQmlTypes(); + generateCompactList(Generic, relative, things, QString(), atom->string()); + } else if (atom->string().contains("classes ")) { + QString rootName = atom->string().mid(atom->string().indexOf("classes") + 7).trimmed(); + generateCompactList(Generic, relative, m_qdb->getCppClasses(), rootName, + atom->string()); + } else if ((idx = atom->string().indexOf(QStringLiteral("bymodule"))) != -1) { + QString moduleName = atom->string().mid(idx + 8).trimmed(); + Node::NodeType type = typeFromString(atom); + QDocDatabase *qdb = QDocDatabase::qdocDB(); + if (const CollectionNode *cn = qdb->getCollectionNode(moduleName, type)) { + if (type == Node::Module) { + NodeMap m; + cn->getMemberClasses(m); + if (!m.isEmpty()) + generateAnnotatedList(relative, m.values(), atom->string()); + } else { + generateAnnotatedList(relative, cn->members(), atom->string()); + } + } + } else if (atom->string().startsWith("examplefiles") + || atom->string().startsWith("exampleimages")) { + if (relative->isExample()) + qDebug() << "GENERATE FILE LIST CALLED" << relative->name() << atom->string(); + } else if (atom->string() == QLatin1String("classhierarchy")) { + generateClassHierarchy(relative, m_qdb->getCppClasses()); + } else if (atom->string().startsWith("obsolete")) { + ListType type = atom->string().endsWith("members") ? Obsolete : Generic; + QString prefix = atom->string().contains("cpp") ? QStringLiteral("Q") : QString(); + const NodeMultiMap &things = atom->string() == QLatin1String("obsoleteclasses") + ? m_qdb->getObsoleteClasses() + : atom->string() == QLatin1String("obsoleteqmltypes") + ? m_qdb->getObsoleteQmlTypes() + : atom->string() == QLatin1String("obsoletecppmembers") + ? m_qdb->getClassesWithObsoleteMembers() + : m_qdb->getQmlTypesWithObsoleteMembers(); + generateCompactList(type, relative, things, prefix, atom->string()); + } else if (atom->string() == QLatin1String("functionindex")) { + generateFunctionIndex(relative); + } else if (atom->string() == QLatin1String("legalese")) { + generateLegaleseList(relative); + } else if (atom->string() == QLatin1String("overviews") + || atom->string() == QLatin1String("cpp-modules") + || atom->string() == QLatin1String("qml-modules") + || atom->string() == QLatin1String("related")) { + generateList(relative, atom->string()); + } + break; + case Atom::SinceList: + // Table of contents, should automatically be generated by the DocBook processor. + break; + case Atom::LineBreak: + case Atom::BR: + case Atom::HR: + // Not supported in DocBook. + break; + case Atom::Image: // mediaobject + case Atom::InlineImage: { // inlinemediaobject + QString tag = atom->type() == Atom::Image ? "mediaobject" : "inlinemediaobject"; + writer->writeStartElement(dbNamespace, tag); + newLine(); + + QString fileName = imageFileName(relative, atom->string()); + if (fileName.isEmpty()) { + writer->writeStartElement(dbNamespace, "textobject"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeTextElement(dbNamespace, "emphasis", + "[Missing image " + atom->string() + "]"); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // textobject + newLine(); + } else { + if (atom->next() && !atom->next()->string().isEmpty()) + writer->writeTextElement(dbNamespace, "alt", atom->next()->string()); + + writer->writeStartElement(dbNamespace, "imageobject"); + newLine(); + writer->writeEmptyElement(dbNamespace, "imagedata"); + writer->writeAttribute("fileref", fileName); + newLine(); + writer->writeEndElement(); // imageobject + newLine(); + + setImageFileName(relative, fileName); + } + + writer->writeEndElement(); // [inline]mediaobject + if (atom->type() == Atom::Image) + newLine(); + } break; + case Atom::ImageText: + break; + case Atom::ImportantLeft: + case Atom::NoteLeft: { + QString tag = atom->type() == Atom::ImportantLeft ? "important" : "note"; + writer->writeStartElement(dbNamespace, tag); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + } break; + case Atom::ImportantRight: + case Atom::NoteRight: + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // note/important + newLine(); + break; + case Atom::LegaleseLeft: + case Atom::LegaleseRight: + break; + case Atom::Link: + case Atom::NavLink: { + const Node *node = nullptr; + QString link = getLink(atom, relative, &node); + beginLink(link, node, relative); // Ended at Atom::FormattingRight + skipAhead = 1; + } break; + case Atom::LinkNode: { + const Node *node = CodeMarker::nodeForString(atom->string()); + beginLink(linkForNode(node, relative), node, relative); + skipAhead = 1; + } break; + case Atom::ListLeft: + if (inPara) { + writer->writeEndElement(); // para + newLine(); + inPara = false; + } + if (atom->string() == ATOM_LIST_BULLET) { + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + } else if (atom->string() == ATOM_LIST_TAG) { + writer->writeStartElement(dbNamespace, "variablelist"); + newLine(); + } else if (atom->string() == ATOM_LIST_VALUE) { + writer->writeStartElement(dbNamespace, "informaltable"); + newLine(); + writer->writeStartElement(dbNamespace, "thead"); + newLine(); + writer->writeStartElement(dbNamespace, "tr"); + newLine(); + writer->writeTextElement(dbNamespace, "th", "Constant"); + newLine(); + + m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); + if (m_threeColumnEnumValueTable && relative->nodeType() == Node::Enum) { + // If not in \enum topic, skip the value column + writer->writeTextElement(dbNamespace, "th", "Value"); + newLine(); + } + + writer->writeTextElement(dbNamespace, "th", "Description"); + newLine(); + + writer->writeEndElement(); // tr + newLine(); + writer->writeEndElement(); // thead + newLine(); + } else { + writer->writeStartElement(dbNamespace, "orderedlist"); + + if (atom->next() != nullptr && atom->next()->string().toInt() > 1) + writer->writeAttribute("startingnumber", atom->next()->string()); + + if (atom->string() == ATOM_LIST_UPPERALPHA) + writer->writeAttribute("numeration", "upperalpha"); + else if (atom->string() == ATOM_LIST_LOWERALPHA) + writer->writeAttribute("numeration", "loweralpha"); + else if (atom->string() == ATOM_LIST_UPPERROMAN) + writer->writeAttribute("numeration", "upperroman"); + else if (atom->string() == ATOM_LIST_LOWERROMAN) + writer->writeAttribute("numeration", "lowerroman"); + else // (atom->string() == ATOM_LIST_NUMERIC) + writer->writeAttribute("numeration", "arabic"); + + newLine(); + } + break; + case Atom::ListItemNumber: + break; + case Atom::ListTagLeft: + if (atom->string() == ATOM_LIST_TAG) { + writer->writeStartElement(dbNamespace, "varlistentry"); + newLine(); + writer->writeStartElement(dbNamespace, "item"); + } else { // (atom->string() == ATOM_LIST_VALUE) + QPair pair = getAtomListValue(atom); + skipAhead = pair.second; + + writer->writeStartElement(dbNamespace, "tr"); + newLine(); + writer->writeStartElement(dbNamespace, "td"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + generateEnumValue(pair.first, relative); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // td + newLine(); + + if (relative->nodeType() == Node::Enum) { + const auto enume = static_cast(relative); + QString itemValue = enume->itemValue(atom->next()->string()); + + writer->writeStartElement(dbNamespace, "td"); + if (itemValue.isEmpty()) + writer->writeCharacters("?"); + else + writer->writeTextElement(dbNamespace, "code", itemValue); + writer->writeEndElement(); // td + newLine(); + } + } + break; + case Atom::SinceTagRight: + case Atom::ListTagRight: + if (atom->string() == ATOM_LIST_TAG) { + writer->writeEndElement(); // item + newLine(); + } + break; + case Atom::ListItemLeft: + inListItemLineOpen = false; + if (atom->string() == ATOM_LIST_TAG) { + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + } else if (atom->string() == ATOM_LIST_VALUE) { + if (m_threeColumnEnumValueTable) { + if (matchAhead(atom, Atom::ListItemRight)) { + writer->writeEmptyElement(dbNamespace, "td"); + newLine(); + inListItemLineOpen = false; + } else { + writer->writeStartElement(dbNamespace, "td"); + newLine(); + inListItemLineOpen = true; + } + } + } else { + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + } + // Don't skip a paragraph, DocBook requires them within list items. + break; + case Atom::ListItemRight: + if (atom->string() == ATOM_LIST_TAG) { + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + writer->writeEndElement(); // varlistentry + newLine(); + } else if (atom->string() == ATOM_LIST_VALUE) { + if (inListItemLineOpen) { + writer->writeEndElement(); // td + newLine(); + inListItemLineOpen = false; + } + writer->writeEndElement(); // tr + newLine(); + } else { + writer->writeEndElement(); // listitem + newLine(); + } + break; + case Atom::ListRight: + // Depending on atom->string(), closing a different item: + // - ATOM_LIST_BULLET: itemizedlist + // - ATOM_LIST_TAG: variablelist + // - ATOM_LIST_VALUE: informaltable + // - ATOM_LIST_NUMERIC: orderedlist + writer->writeEndElement(); + newLine(); + break; + case Atom::Nop: + break; + case Atom::ParaLeft: + writer->writeStartElement(dbNamespace, "para"); + inPara = true; + break; + case Atom::ParaRight: + endLink(); + if (inPara) { + writer->writeEndElement(); // para + newLine(); + inPara = false; + } + break; + case Atom::QuotationLeft: + writer->writeStartElement(dbNamespace, "blockquote"); + inPara = true; + break; + case Atom::QuotationRight: + writer->writeEndElement(); // blockquote + newLine(); + break; + case Atom::RawString: + writer->writeCharacters(atom->string()); + break; + case Atom::SectionLeft: + currentSectionLevel = atom->string().toInt() + hOffset(relative); + // Level 1 is dealt with at the header level (info tag). + if (currentSectionLevel > 1) { + // Unfortunately, SectionRight corresponds to the end of any section, + // i.e. going to a new section, even deeper. + while (!sectionLevels.empty() && sectionLevels.top() >= currentSectionLevel) { + sectionLevels.pop(); + writer->writeEndElement(); // section + newLine(); + } + + sectionLevels.push(currentSectionLevel); + + writer->writeStartElement(dbNamespace, "section"); + writer->writeAttribute("xml:id", + Doc::canonicalTitle(Text::sectionHeading(atom).toString())); + newLine(); + // Unlike startSectionBegin, don't start a title here. + } + break; + case Atom::SectionRight: + // All the logic about closing sections is done in the SectionLeft case + // and generateFooter() for the end of the page. + break; + case Atom::SectionHeadingLeft: + // Level 1 is dealt with at the header level (info tag). + if (currentSectionLevel > 1) { + writer->writeStartElement(dbNamespace, "title"); + m_inSectionHeading = true; + } + break; + case Atom::SectionHeadingRight: + // Level 1 is dealt with at the header level (info tag). + if (currentSectionLevel > 1) { + writer->writeEndElement(); // title + newLine(); + m_inSectionHeading = false; + } + break; + case Atom::SidebarLeft: + writer->writeStartElement(dbNamespace, "sidebar"); + break; + case Atom::SidebarRight: + writer->writeEndElement(); // sidebar + newLine(); + break; + case Atom::String: + if (inLink && !m_inContents && !m_inSectionHeading) + generateLink(atom); + else + writer->writeCharacters(atom->string()); + break; + case Atom::TableLeft: { + QPair pair = getTableWidthAttr(atom); + QString attr = pair.second; + QString width = pair.first; + + if (inPara) { + writer->writeEndElement(); // para or blockquote + newLine(); + inPara = false; + } + + writer->writeStartElement(dbNamespace, "informaltable"); + writer->writeAttribute("style", attr); + if (!width.isEmpty()) + writer->writeAttribute("width", width); + newLine(); + m_numTableRows = 0; + } break; + case Atom::TableRight: + writer->writeEndElement(); // table + newLine(); + break; + case Atom::TableHeaderLeft: + writer->writeStartElement(dbNamespace, "thead"); + newLine(); + writer->writeStartElement(dbNamespace, "tr"); + newLine(); + m_inTableHeader = true; + break; + case Atom::TableHeaderRight: + writer->writeEndElement(); // tr + newLine(); + if (matchAhead(atom, Atom::TableHeaderLeft)) { + skipAhead = 1; + writer->writeStartElement(dbNamespace, "tr"); + newLine(); + } else { + writer->writeEndElement(); // thead + newLine(); + m_inTableHeader = false; + } + break; + case Atom::TableRowLeft: + writer->writeStartElement(dbNamespace, "tr"); + if (atom->string().isEmpty()) { + writer->writeAttribute("valign", "top"); + } else { + // Basic parsing of attributes, should be enough. The input string (atom->string()) + // looks like: + // arg1="val1" arg2="val2" + QStringList args = atom->string().split("\"", Qt::SkipEmptyParts); + // arg1=, val1, arg2=, val2, + // \-- 1st --/ \-- 2nd --/ \-- remainder + if (args.size() % 2) { + // Problem... + relative->doc().location().warning( + QStringLiteral("Error when parsing attributes for the table: got \"%1\"") + .arg(atom->string())); + } + for (int i = 0; i + 1 < args.size(); i += 2) + writer->writeAttribute(args.at(i).chopped(1), args.at(i + 1)); + } + newLine(); + break; + case Atom::TableRowRight: + writer->writeEndElement(); // tr + newLine(); + break; + case Atom::TableItemLeft: + writer->writeStartElement(dbNamespace, m_inTableHeader ? "th" : "td"); + + for (int i = 0; i < atom->count(); ++i) { + const QString &p = atom->string(i); + if (p.contains('=')) { + QStringList lp = p.split(QLatin1Char('=')); + writer->writeAttribute(lp.at(0), lp.at(1)); + } else { + QStringList spans = p.split(QLatin1Char(',')); + if (spans.size() == 2) { + if (spans.at(0) != "1") + writer->writeAttribute("colspan", spans.at(0)); + if (spans.at(1) != "1") + writer->writeAttribute("rowspan", spans.at(1)); + } + } + } + newLine(); + // No skipahead, as opposed to HTML: in DocBook, the text must be wrapped in paragraphs. + break; + case Atom::TableItemRight: + writer->writeEndElement(); // th if m_inTableHeader, otherwise td + newLine(); + break; + case Atom::TableOfContents: + break; + case Atom::Keyword: + break; + case Atom::Target: + writeAnchor(Doc::canonicalTitle(atom->string())); + break; + case Atom::UnhandledFormat: + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("<Missing DocBook>"); + writer->writeEndElement(); // emphasis + break; + case Atom::UnknownCommand: + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("<Unknown command>"); + writer->writeStartElement(dbNamespace, "code"); + writer->writeCharacters(atom->string()); + writer->writeEndElement(); // code + writer->writeEndElement(); // emphasis + break; + case Atom::QmlText: + case Atom::EndQmlText: + // don't do anything with these. They are just tags. + break; + case Atom::CodeQuoteArgument: + case Atom::CodeQuoteCommand: + case Atom::SnippetCommand: + case Atom::SnippetIdentifier: + case Atom::SnippetLocation: + // no output (ignore) + break; + default: + unknownAtom(atom); + } + return skipAhead; +} + +void DocBookGenerator::generateClassHierarchy(const Node *relative, NodeMultiMap &classMap) +{ + // From HtmlGenerator::generateClassHierarchy. + if (classMap.isEmpty()) + return; + + NodeMap topLevel; + for (Node *c : classMap) { + auto *classNode = static_cast(c); + if (classNode->baseClasses().isEmpty()) + topLevel.insert(classNode->name(), classNode); + } + + QStack stack; + stack.push(topLevel); + + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + while (!stack.isEmpty()) { + if (stack.top().isEmpty()) { + stack.pop(); + writer->writeEndElement(); // listitem + newLine(); + writer->writeEndElement(); // itemizedlist + newLine(); + } else { + ClassNode *child = static_cast(*stack.top().begin()); + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + generateFullName(child, relative); + writer->writeEndElement(); // para + newLine(); + // Don't close the listitem now, as DocBook requires sublists to reside in items. + stack.top().erase(stack.top().begin()); + + NodeMap newTop; + for (const RelatedClass &d : child->derivedClasses()) { + if (d.m_node && !d.isPrivate() && !d.m_node->isInternal() && d.m_node->hasDoc()) + newTop.insert(d.m_node->name(), d.m_node); + } + if (!newTop.isEmpty()) { + stack.push(newTop); + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + } + } + } +} + +void DocBookGenerator::generateLink(const Atom *atom) +{ + // From HtmlGenerator::generateLink. + QRegularExpression funcLeftParen("\\S(\\()"); + auto match = funcLeftParen.match(atom->string()); + if (match.hasMatch()) { + // hack for C++: move () outside of link + int k = match.capturedStart(1); + writer->writeCharacters(atom->string().left(k)); + writer->writeEndElement(); // link + inLink = false; + writer->writeCharacters(atom->string().mid(k)); + } else { + writer->writeCharacters(atom->string()); + } +} + +/*! + This version of the function is called when the \a link is known + to be correct. + */ +void DocBookGenerator::beginLink(const QString &link, const Node *node, const Node *relative) +{ + // From HtmlGenerator::beginLink. + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", link); + if (node && !(relative && node->status() == relative->status()) + && node->status() == Node::Obsolete) + writer->writeAttribute("role", "obsolete"); + inLink = true; +} + +void DocBookGenerator::endLink() +{ + // From HtmlGenerator::endLink. + if (inLink) + writer->writeEndElement(); // link + inLink = false; +} + +void DocBookGenerator::generateList(const Node *relative, const QString &selector) +{ + // From HtmlGenerator::generateList, without warnings, changing prototype. + CNMap cnm; + Node::NodeType type = Node::NoType; + if (selector == QLatin1String("overviews")) + type = Node::Group; + else if (selector == QLatin1String("cpp-modules")) + type = Node::Module; + else if (selector == QLatin1String("qml-modules")) + type = Node::QmlModule; + else if (selector == QLatin1String("js-modules")) + type = Node::JsModule; + + if (type != Node::NoType) { + NodeList nodeList; + m_qdb->mergeCollections(type, cnm, relative); + const QList collectionList = cnm.values(); + nodeList.reserve(collectionList.size()); + for (auto *collectionNode : collectionList) + nodeList.append(collectionNode); + generateAnnotatedList(relative, nodeList, selector); + } else { + /* + \generatelist {selector} is only allowed in a + comment where the topic is \group, \module, + \qmlmodule, or \jsmodule + */ + Node *n = const_cast(relative); + auto *cn = static_cast(n); + m_qdb->mergeCollections(cn); + generateAnnotatedList(cn, cn->members(), selector); + } +} + +/*! + Outputs an annotated list of the nodes in \a nodeList. + A two-column table is output. + */ +void DocBookGenerator::generateAnnotatedList(const Node *relative, const NodeList &nodeList, + const QString &selector) +{ + if (nodeList.isEmpty()) + return; + + // Do nothing if all items are internal or obsolete + if (std::all_of(nodeList.cbegin(), nodeList.cend(), [](const Node *n) { + return n->isInternal() || n->isObsolete(); })) { + return; + } + + // From WebXMLGenerator::generateAnnotatedList. + writer->writeStartElement(dbNamespace, "variablelist"); + writer->writeAttribute("role", selector); + newLine(); + + for (const auto node : nodeList) { + if (node->isInternal() || node->isObsolete()) + continue; + writer->writeStartElement(dbNamespace, "varlistentry"); + newLine(); + writer->writeStartElement(dbNamespace, "term"); + generateFullName(node, relative); + writer->writeEndElement(); // term + newLine(); + + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters(node->doc().briefText().toString()); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + writer->writeEndElement(); // varlistentry + newLine(); + } + writer->writeEndElement(); // variablelist + newLine(); +} + +/*! + Outputs a series of annotated lists from the nodes in \a nmm, + divided into sections based by the key names in the multimap. + */ +void DocBookGenerator::generateAnnotatedLists(const Node *relative, const NodeMultiMap &nmm, + const QString &selector) +{ + // From HtmlGenerator::generateAnnotatedLists. + for (const QString &name : nmm.uniqueKeys()) { + if (!name.isEmpty()) + startSection(registerRef(name.toLower()), name); + generateAnnotatedList(relative, nmm.values(name), selector); + if (!name.isEmpty()) + endSection(); + } +} + +/*! + This function finds the common prefix of the names of all + the classes in the class map \a nmm and then generates a + compact list of the class names alphabetized on the part + of the name not including the common prefix. You can tell + the function to use \a comonPrefix as the common prefix, + but normally you let it figure it out itself by looking at + the name of the first and last classes in the class map + \a nmm. + */ +void DocBookGenerator::generateCompactList(ListType listType, const Node *relative, + const NodeMultiMap &nmm, const QString &commonPrefix, + const QString &selector) +{ + // From HtmlGenerator::generateCompactList. No more "includeAlphabet", this should be handled by + // the DocBook toolchain afterwards. + // TODO: In DocBook, probably no need for this method: this is purely presentational, i.e. to be + // fully handled by the DocBook toolchain. + if (nmm.isEmpty()) + return; + + const int NumParagraphs = 37; // '0' to '9', 'A' to 'Z', '_' + int commonPrefixLen = commonPrefix.length(); + + /* + Divide the data into 37 paragraphs: 0, ..., 9, A, ..., Z, + underscore (_). QAccel will fall in paragraph 10 (A) and + QXtWidget in paragraph 33 (X). This is the only place where we + assume that NumParagraphs is 37. Each paragraph is a NodeMultiMap. + */ + NodeMultiMap paragraph[NumParagraphs + 1]; + QString paragraphName[NumParagraphs + 1]; + QSet usedParagraphNames; + + NodeMultiMap::ConstIterator c = nmm.constBegin(); + while (c != nmm.constEnd()) { + QStringList pieces = c.key().split("::"); + QString key; + int idx = commonPrefixLen; + if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive)) + idx = 0; + key = pieces.last().mid(idx).toLower(); + + int paragraphNr = NumParagraphs - 1; + + if (key[0].digitValue() != -1) + paragraphNr = key[0].digitValue(); + else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) + paragraphNr = 10 + key[0].unicode() - 'a'; + + paragraphName[paragraphNr] = key[0].toUpper(); + usedParagraphNames.insert(key[0].toLower().cell()); + paragraph[paragraphNr].insert(c.key(), c.value()); + ++c; + } + + /* + Each paragraph j has a size: paragraph[j].count(). In the + discussion, we will assume paragraphs 0 to 5 will have sizes + 3, 1, 4, 1, 5, 9. + + We now want to compute the paragraph offset. Paragraphs 0 to 6 + start at offsets 0, 3, 4, 8, 9, 14, 23. + */ + int paragraphOffset[NumParagraphs + 1]; // 37 + 1 + paragraphOffset[0] = 0; + for (int i = 0; i < NumParagraphs; i++) // i = 0..36 + paragraphOffset[i + 1] = paragraphOffset[i] + paragraph[i].count(); + + // No table of contents in DocBook. + + // Actual output. + m_numTableRows = 0; + + int curParNr = 0; + int curParOffset = 0; + QString previousName; + bool multipleOccurrences = false; + + for (int i = 0; i < nmm.count(); i++) { + while ((curParNr < NumParagraphs) && (curParOffset == paragraph[curParNr].count())) { + ++curParNr; + curParOffset = 0; + } + + /* + Starting a new paragraph means starting a new variablelist. + */ + if (curParOffset == 0) { + if (i > 0) { + writer->writeEndElement(); // variablelist + newLine(); + } + + writer->writeStartElement(dbNamespace, "variablelist"); + writer->writeAttribute("role", selector); + newLine(); + writer->writeStartElement(dbNamespace, "varlistentry"); + newLine(); + + writer->writeStartElement(dbNamespace, "term"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters(paragraphName[curParNr]); + writer->writeEndElement(); // emphasis + writer->writeEndElement(); // term + newLine(); + } + + /* + Output a listitem for the current offset in the current paragraph. + */ + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) { + NodeMultiMap::Iterator it; + NodeMultiMap::Iterator next; + it = paragraph[curParNr].begin(); + for (int j = 0; j < curParOffset; j++) + ++it; + + if (listType == Generic) { + generateFullName(it.value(), relative); + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", fullDocumentLocation(*it)); + writer->writeAttribute("type", targetType(it.value())); + } else if (listType == Obsolete) { + QString fn = fileName(it.value(), fileExtension()); + QString link; + if (useOutputSubdirs()) + link = QString("../" + it.value()->outputSubdirectory() + QLatin1Char('/')); + link += fn; + + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", link); + writer->writeAttribute("type", targetType(it.value())); + } + + QStringList pieces; + if (it.value()->isQmlType() || it.value()->isJsType()) { + QString name = it.value()->name(); + next = it; + ++next; + if (name != previousName) + multipleOccurrences = false; + if ((next != paragraph[curParNr].end()) && (name == next.value()->name())) { + multipleOccurrences = true; + previousName = name; + } + if (multipleOccurrences) + name += ": " + it.value()->tree()->camelCaseModuleName(); + pieces << name; + } else + pieces = it.value()->fullName(relative).split("::"); + + writer->writeCharacters(pieces.last()); + writer->writeEndElement(); // link + + if (pieces.size() > 1) { + writer->writeCharacters(" ("); + generateFullName(it.value()->parent(), relative); + writer->writeCharacters(")"); + } + } + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + writer->writeEndElement(); // varlistentry + newLine(); + curParOffset++; + } + if (nmm.count() > 0) { + writer->writeEndElement(); // variablelist + } +} + +void DocBookGenerator::generateFunctionIndex(const Node *relative) +{ + // From HtmlGenerator::generateFunctionIndex. + writer->writeStartElement(dbNamespace, "simplelist"); + writer->writeAttribute("role", "functionIndex"); + newLine(); + for (int i = 0; i < 26; i++) { + QChar ch('a' + i); + writer->writeStartElement(dbNamespace, "member"); + writer->writeAttribute(xlinkNamespace, "href", QString("#") + ch); + writer->writeCharacters(ch.toUpper()); + writer->writeEndElement(); // member + newLine(); + } + writer->writeEndElement(); // simplelist + newLine(); + + char nextLetter = 'a'; + char currentLetter; + + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + + NodeMapMap &funcIndex = m_qdb->getFunctionIndex(); + QMap::ConstIterator f = funcIndex.constBegin(); + while (f != funcIndex.constEnd()) { + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters(f.key() + ": "); + + currentLetter = f.key()[0].unicode(); + while (islower(currentLetter) && currentLetter >= nextLetter) { + writeAnchor(QString(nextLetter)); + nextLetter++; + } + + NodeMap::ConstIterator s = (*f).constBegin(); + while (s != (*f).constEnd()) { + writer->writeCharacters(" "); + generateFullName((*s)->parent(), relative); + ++s; + } + + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + ++f; + } + writer->writeEndElement(); // itemizedlist + newLine(); +} + +void DocBookGenerator::generateLegaleseList(const Node *relative) +{ + // From HtmlGenerator::generateLegaleseList. + TextToNodeMap &legaleseTexts = m_qdb->getLegaleseTexts(); + for (auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) { + Text text = it.key(); + generateText(text, relative); + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + do { + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + generateFullName(it.value(), relative); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + ++it; + } while (it != legaleseTexts.constEnd() && it.key() == text); + writer->writeEndElement(); // itemizedlist + newLine(); + } +} + +void DocBookGenerator::generateBrief(const Node *node) +{ + // From HtmlGenerator::generateBrief. Also see generateHeader, which is specifically dealing + // with the DocBook header (and thus wraps the brief in an abstract). + Text brief = node->doc().briefText(); + + if (!brief.isEmpty()) { + if (!brief.lastAtom()->string().endsWith('.')) + brief << Atom(Atom::String, "."); + + writer->writeStartElement(dbNamespace, "para"); + generateText(brief, node); + writer->writeEndElement(); // para + newLine(); + } +} + +bool DocBookGenerator::generateSince(const Node *node) +{ + // From Generator::generateSince. + if (!node->since().isEmpty()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("This " + typeString(node) + " was introduced"); + if (node->nodeType() == Node::Enum) + writer->writeCharacters(" or modified"); + writer->writeCharacters(" in " + formatSince(node) + "."); + writer->writeEndElement(); // para + newLine(); + + return true; + } + + return false; +} + +void DocBookGenerator::generateHeader(const QString &title, const QString &subTitle, + const Node *node) +{ + // From HtmlGenerator::generateHeader. + refMap.clear(); + + // Output the DocBook header. + writer->writeStartElement(dbNamespace, "info"); + newLine(); + writer->writeTextElement(dbNamespace, "title", title); + newLine(); + + if (!subTitle.isEmpty()) { + writer->writeTextElement(dbNamespace, "subtitle", subTitle); + newLine(); + } + + if (!project.isEmpty()) { + writer->writeTextElement(dbNamespace, "productname", project); + newLine(); + } + + if (!buildversion.isEmpty()) { + writer->writeTextElement(dbNamespace, "edition", buildversion); + newLine(); + } + + if (!projectDescription.isEmpty()) { + writer->writeTextElement(dbNamespace, "titleabbrev", projectDescription); + newLine(); + } + + // Deal with links. + // Adapted from HtmlGenerator::generateHeader (output part: no need to update a navigationLinks + // or useSeparator field, as this content is only output in the info tag, not in the main + // content). + if (node && !node->links().empty()) { + QPair linkPair; + QPair anchorPair; + const Node *linkNode; + + if (node->links().contains(Node::PreviousLink)) { + linkPair = node->links()[Node::PreviousLink]; + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + writer->writeStartElement(dbNamespace, "extendedlink"); + writer->writeEmptyElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "to", anchorPair.first); + writer->writeAttribute(xlinkNamespace, "title", "prev"); + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + writer->writeAttribute(xlinkNamespace, "label", anchorPair.second); + else + writer->writeAttribute(xlinkNamespace, "label", linkPair.second); + writer->writeEndElement(); // extendedlink + } + if (node->links().contains(Node::NextLink)) { + linkPair = node->links()[Node::NextLink]; + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + writer->writeStartElement(dbNamespace, "extendedlink"); + writer->writeEmptyElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "to", anchorPair.first); + writer->writeAttribute(xlinkNamespace, "title", "prev"); + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + writer->writeAttribute(xlinkNamespace, "label", anchorPair.second); + else + writer->writeAttribute(xlinkNamespace, "label", linkPair.second); + writer->writeEndElement(); // extendedlink + } + if (node->links().contains(Node::StartLink)) { + linkPair = node->links()[Node::StartLink]; + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (!linkNode || linkNode == node) + anchorPair = linkPair; + else + anchorPair = anchorForNode(linkNode); + + writer->writeStartElement(dbNamespace, "extendedlink"); + writer->writeEmptyElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "to", anchorPair.first); + writer->writeAttribute(xlinkNamespace, "title", "start"); + if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) + writer->writeAttribute(xlinkNamespace, "label", anchorPair.second); + else + writer->writeAttribute(xlinkNamespace, "label", linkPair.second); + writer->writeEndElement(); // extendedlink + } + } + + // Deal with the abstract (what qdoc calls brief). + if (node) { + // Adapted from HtmlGenerator::generateBrief, without extraction marks. The parameter + // addLink is always false. Factoring this function out is not as easy as in HtmlGenerator: + // abstracts only happen in the header (info tag), slightly different tags must be used at + // other places. Also includes code from HtmlGenerator::generateCppReferencePage to handle + // the name spaces. + writer->writeStartElement(dbNamespace, "abstract"); + newLine(); + + bool generatedSomething = false; + + Text brief; + const NamespaceNode *ns = node->isAggregate() + ? static_cast(static_cast(node)) + : nullptr; + if (node->isAggregate() && ns && !ns->hasDoc() && ns->docNode()) { + NamespaceNode *NS = ns->docNode(); + brief << "The " << ns->name() + << " namespace includes the following elements from module " + << ns->tree()->camelCaseModuleName() << ". The full namespace is " + << "documented in module " << NS->tree()->camelCaseModuleName() + << Atom(Atom::LinkNode, fullDocumentLocation(NS)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, " here.") + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + } else { + brief = node->doc().briefText(); + } + + if (!brief.isEmpty()) { + if (!brief.lastAtom()->string().endsWith('.')) + brief << Atom(Atom::String, "."); + + writer->writeStartElement(dbNamespace, "para"); + generateText(brief, node); + writer->writeEndElement(); // para + newLine(); + + generatedSomething = true; + } + + // Generate other paragraphs that should go into the abstract. + generatedSomething |= generateStatus(node); + generatedSomething |= generateSince(node); + generatedSomething |= generateThreadSafeness(node); + + // An abstract cannot be empty, hence use the project description. + if (!generatedSomething) + writer->writeTextElement(dbNamespace, "para", projectDescription + "."); + + writer->writeEndElement(); // abstract + newLine(); + } + + // End of the DocBook header. + writer->writeEndElement(); // info + newLine(); +} + +void DocBookGenerator::closeTextSections() +{ + while (!sectionLevels.isEmpty()) { + sectionLevels.pop(); + endSection(); + } +} + +void DocBookGenerator::generateFooter() +{ + closeTextSections(); + writer->writeEndElement(); // article +} + +void DocBookGenerator::generateSimpleLink(const QString &href, const QString &text) +{ + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", href); + writer->writeCharacters(text); + writer->writeEndElement(); // link +} + +void DocBookGenerator::generateObsoleteMembers(const Sections §ions) +{ + // From HtmlGenerator::generateObsoleteMembersFile. + SectionPtrVector summary_spv; // Summaries are ignored in DocBook (table of contents). + SectionPtrVector details_spv; + if (!sections.hasObsoleteMembers(&summary_spv, &details_spv)) + return; + + Aggregate *aggregate = sections.aggregate(); + QString link; + if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty()) + link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')); + link += fileName(aggregate, fileExtension()); + aggregate->setObsoleteLink(link); + + startSection("obsolete", "Obsolete Members for " + aggregate->name()); + + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("The following members of class "); + generateSimpleLink(linkForNode(aggregate, nullptr), aggregate->name()); + writer->writeCharacters(" are obsolete."); + writer->writeEndElement(); // emphasis bold + writer->writeCharacters(" They are provided to keep old source code working. " + "We strongly advise against using them in new code."); + writer->writeEndElement(); // para + newLine(); + + for (int i = 0; i < details_spv.size(); ++i) { + QString title = details_spv.at(i)->title(); + QString ref = registerRef(title.toLower()); + startSection(ref, title); + + const NodeVector &members = details_spv.at(i)->obsoleteMembers(); + NodeVector::ConstIterator m = members.constBegin(); + while (m != members.constEnd()) { + if ((*m)->access() != Access::Private) + generateDetailedMember(*m, aggregate); + ++m; + } + + endSection(); + } + + endSection(); +} + +/*! + Generates a separate file where obsolete members of the QML + type \a qcn are listed. The \a marker is used to generate + the section lists, which are then traversed and output here. + + Note that this function currently only handles correctly the + case where \a status is \c {Section::Obsolete}. + */ +void DocBookGenerator::generateObsoleteQmlMembers(const Sections §ions) +{ + // From HtmlGenerator::generateObsoleteQmlMembersFile. + SectionPtrVector summary_spv; // Summaries are not useful in DocBook. + SectionPtrVector details_spv; + if (!sections.hasObsoleteMembers(&summary_spv, &details_spv)) + return; + + Aggregate *aggregate = sections.aggregate(); + QString title = "Obsolete Members for " + aggregate->name(); + QString fn = fileName(aggregate, fileExtension()); + QString link; + if (useOutputSubdirs() && !Generator::outputSubdir().isEmpty()) + link = QString("../" + Generator::outputSubdir() + QLatin1Char('/')); + link += fn; + aggregate->setObsoleteLink(link); + + startSection("obsolete", "Obsolete Members for " + aggregate->name()); + + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("The following members of QML type "); + generateSimpleLink(linkForNode(aggregate, nullptr), aggregate->name()); + writer->writeCharacters(" are obsolete."); + writer->writeEndElement(); // emphasis bold + writer->writeCharacters("They are provided to keep old source code working. " + "We strongly advise against using them in new code."); + writer->writeEndElement(); // para + newLine(); + + for (auto i : details_spv) { + QString ref = registerRef(i->title().toLower()); + startSection(ref, i->title()); + + NodeVector::ConstIterator m = i->members().constBegin(); + while (m != i->members().constEnd()) { + generateDetailedQmlMember(*m, aggregate); + ++m; + } + + endSection(); + } + + endSection(); +} + +static QString nodeToSynopsisTag(const Node *node) +{ + // Order from Node::nodeTypeString. + if (node->isClass() || node->isQmlType() || node->isQmlBasicType()) + return QStringLiteral("classsynopsis"); + if (node->isNamespace()) + return QStringLiteral("namespacesynopsis"); + if (node->isPageNode()) { + node->doc().location().warning("Unexpected document node in nodeToSynopsisTag"); + return QString(); + } + if (node->isEnumType()) + return QStringLiteral("enumsynopsis"); + if (node->isTypedef()) + return QStringLiteral("typedefsynopsis"); + if (node->isFunction()) { + // Signals are also encoded as functions (including QML/JS ones). + const auto fn = static_cast(node); + if (fn->isCtor() || fn->isCCtor() || fn->isMCtor()) + return QStringLiteral("constructorsynopsis"); + if (fn->isDtor()) + return QStringLiteral("destructorsynopsis"); + return QStringLiteral("methodsynopsis"); + } + if (node->isProperty() || node->isVariable() || node->isQmlProperty()) + return QStringLiteral("fieldsynopsis"); + + node->doc().location().warning(QString("Unknown node tag %1").arg(node->nodeTypeString())); + return QStringLiteral("synopsis"); +} + +void DocBookGenerator::generateStartRequisite(const QString &description) +{ + writer->writeStartElement(dbNamespace, "varlistentry"); + newLine(); + writer->writeTextElement(dbNamespace, "term", description); + newLine(); + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); +} + +void DocBookGenerator::generateEndRequisite() +{ + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + writer->writeEndElement(); // varlistentry + newLine(); +} + +void DocBookGenerator::generateRequisite(const QString &description, const QString &value) +{ + generateStartRequisite(description); + writer->writeCharacters(value); + generateEndRequisite(); +} + +/*! + * \internal + * Generates the CMake (\a description) requisites + */ +void DocBookGenerator::generateCMakeRequisite(const QStringList &values) +{ + const QString description("CMake"); + generateStartRequisite(description); + writer->writeCharacters(values.first()); + writer->writeEndElement(); // para + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters(values.last()); + generateEndRequisite(); +} + +void DocBookGenerator::generateSortedNames(const ClassNode *cn, const QList &rc) +{ + // From Generator::appendSortedNames. + QMap classMap; + QList::ConstIterator r = rc.constBegin(); + while (r != rc.constEnd()) { + ClassNode *rcn = (*r).m_node; + if (rcn && rcn->access() == Access::Public && rcn->status() != Node::Internal + && !rcn->doc().isEmpty()) { + classMap[rcn->plainFullName(cn).toLower()] = rcn; + } + ++r; + } + + QStringList classNames = classMap.keys(); + classNames.sort(); + + int index = 0; + for (const QString &className : classNames) { + generateFullName(classMap.value(className), cn); + writer->writeCharacters(Utilities::comma(index++, classNames.count())); + } +} + +void DocBookGenerator::generateSortedQmlNames(const Node *base, const NodeList &subs) +{ + // From Generator::appendSortedQmlNames. + QMap classMap; + int index = 0; + + for (auto sub : subs) + if (!base->isQtQuickNode() || !sub->isQtQuickNode() + || (base->logicalModuleName() == sub->logicalModuleName())) + classMap[sub->plainFullName(base).toLower()] = sub; + + QStringList names = classMap.keys(); + names.sort(); + + for (const QString &name : names) { + generateFullName(classMap.value(name), base); + writer->writeCharacters(Utilities::comma(index++, names.count())); + } +} + +/*! + Lists the required imports and includes. +*/ +void DocBookGenerator::generateRequisites(const Aggregate *aggregate) +{ + // Adapted from HtmlGenerator::generateRequisites, but simplified: no need to store all the + // elements, they can be produced one by one. + writer->writeStartElement(dbNamespace, "variablelist"); + newLine(); + + // Includes. + if (!aggregate->includeFiles().isEmpty()) { + for (const QString &include : aggregate->includeFiles()) + generateRequisite("Header", include); + } + + // Since and project. + if (!aggregate->since().isEmpty()) + generateRequisite("Since", formatSince(aggregate)); + + if (aggregate->isClassNode() || aggregate->isNamespace()) { + // CMake and QT variable. + if (!aggregate->physicalModuleName().isEmpty()) { + const CollectionNode *cn = + m_qdb->getCollectionNode(aggregate->physicalModuleName(), Node::Module); + if (cn && !cn->qtCMakeComponent().isEmpty()) { + const QString qtComponent = "Qt" + QString::number(QT_VERSION_MAJOR); + const QString findpackageText = "find_package(" + qtComponent + " COMPONENTS " + + cn->qtCMakeComponent() + " REQUIRED)"; + const QString targetLinkLibrariesText = "target_link_libraries(mytarget PRIVATE " + + qtComponent + "::" + cn->qtCMakeComponent() + ")"; + const QStringList cmakeInfo { findpackageText, targetLinkLibrariesText }; + generateCMakeRequisite(cmakeInfo); + } + if (cn && !cn->qtVariable().isEmpty()) + generateRequisite("qmake", "QT += " + cn->qtVariable()); + } + } + + if (aggregate->nodeType() == Node::Class) { + // Instantiated by. + auto *classe = const_cast(static_cast(aggregate)); + if (classe->qmlElement() != nullptr && classe->status() != Node::Internal) { + generateStartRequisite("Inherited By"); + generateSortedNames(classe, classe->derivedClasses()); + generateEndRequisite(); + generateRequisite("Instantiated By", fullDocumentLocation(classe->qmlElement())); + } + + // Inherits. + QList::ConstIterator r; + if (!classe->baseClasses().isEmpty()) { + generateStartRequisite("Inherits"); + + r = classe->baseClasses().constBegin(); + int index = 0; + while (r != classe->baseClasses().constEnd()) { + if ((*r).m_node) { + generateFullName((*r).m_node, classe); + + if ((*r).m_access == Access::Protected) + writer->writeCharacters(" (protected)"); + else if ((*r).m_access == Access::Private) + writer->writeCharacters(" (private)"); + writer->writeCharacters( + Utilities::comma(index++, classe->baseClasses().count())); + } + ++r; + } + + generateEndRequisite(); + } + + // Inherited by. + if (!classe->derivedClasses().isEmpty()) { + generateStartRequisite("Inherited By"); + generateSortedNames(classe, classe->derivedClasses()); + generateEndRequisite(); + } + } + + writer->writeEndElement(); // variablelist + newLine(); +} + +/*! + Lists the required imports and includes. +*/ +void DocBookGenerator::generateQmlRequisites(const QmlTypeNode *qcn) +{ + // From HtmlGenerator::generateQmlRequisites, but simplified: no need to store all the elements, + // they can be produced one by one. + if (!qcn) + return; + + writer->writeStartElement(dbNamespace, "variablelist"); + newLine(); + + // Module name and version (i.e. import). + QString logicalModuleVersion; + const CollectionNode *collection = qcn->logicalModule(); + + // skip import statement for \internal collections + if (!collection || !collection->isInternal() || m_showInternal) { + logicalModuleVersion = + collection ? collection->logicalModuleVersion() : qcn->logicalModuleVersion(); + + generateRequisite("Import Statement", + "import " + qcn->logicalModuleName() + QLatin1Char(' ') + + logicalModuleVersion); + } + + // Since and project. + if (!qcn->since().isEmpty()) + generateRequisite("Since:", formatSince(qcn)); + + // Inherited by. + NodeList subs; + QmlTypeNode::subclasses(qcn, subs); + if (!subs.isEmpty()) { + generateStartRequisite("Inherited By:"); + generateSortedQmlNames(qcn, subs); + generateEndRequisite(); + } + + // Inherits. + QmlTypeNode *base = qcn->qmlBaseNode(); + while (base && base->isInternal()) { + base = base->qmlBaseNode(); + } + if (base) { + const Node *otherNode = nullptr; + Atom a = Atom(Atom::LinkNode, CodeMarker::stringForNode(base)); + QString link = getAutoLink(&a, qcn, &otherNode); + + generateStartRequisite("Inherits:"); + generateSimpleLink(link, base->name()); + generateEndRequisite(); + } + + // Instantiates. + ClassNode *cn = (const_cast(qcn))->classNode(); + if (cn && (cn->status() != Node::Internal)) { + const Node *otherNode = nullptr; + Atom a = Atom(Atom::LinkNode, CodeMarker::stringForNode(qcn)); + QString link = getAutoLink(&a, cn, &otherNode); + + generateStartRequisite("Instantiates:"); + generateSimpleLink(fullDocumentLocation(cn), cn->name()); + generateEndRequisite(); + } + + writer->writeEndElement(); // variablelist + newLine(); +} + +bool DocBookGenerator::generateStatus(const Node *node) +{ + // From Generator::generateStatus. + switch (node->status()) { + case Node::Active: + // Do nothing. + return false; + case Node::Preliminary: + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("This " + typeString(node) + + " is under development and is subject to change."); + writer->writeEndElement(); // emphasis + writer->writeEndElement(); // para + newLine(); + return true; + case Node::Deprecated: + writer->writeStartElement(dbNamespace, "para"); + if (node->isAggregate()) { + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + } + writer->writeCharacters("This " + typeString(node) + " is deprecated."); + if (node->isAggregate()) + writer->writeEndElement(); // emphasis + writer->writeEndElement(); // para + newLine(); + return true; + case Node::Obsolete: + writer->writeStartElement(dbNamespace, "para"); + if (node->isAggregate()) { + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + } + writer->writeCharacters("This " + typeString(node) + " is obsolete."); + if (node->isAggregate()) + writer->writeEndElement(); // emphasis + writer->writeCharacters(" It is provided to keep old source code working. " + "We strongly advise against using it in new code."); + writer->writeEndElement(); // para + newLine(); + return true; + case Node::Internal: + default: + return false; + } +} + +/*! + Generate a list of function signatures. The function nodes + are in \a nodes. + */ +void DocBookGenerator::generateSignatureList(const NodeList &nodes) +{ + // From Generator::signatureList and Generator::appendSignature. + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + + NodeList::ConstIterator n = nodes.constBegin(); + while (n != nodes.constEnd()) { + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + + generateSimpleLink(currentGenerator()->fullDocumentLocation(*n), + (*n)->signature(false, true)); + + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // itemizedlist + newLine(); + ++n; + } + + writer->writeEndElement(); // itemizedlist + newLine(); +} + +/*! + Generates text that explains how threadsafe and/or reentrant + \a node is. + */ +bool DocBookGenerator::generateThreadSafeness(const Node *node) +{ + // From Generator::generateThreadSafeness + Node::ThreadSafeness ts = node->threadSafeness(); + + const Node *reentrantNode; + Atom reentrantAtom = Atom(Atom::Link, "reentrant"); + QString linkReentrant = getAutoLink(&reentrantAtom, node, &reentrantNode); + const Node *threadSafeNode; + Atom threadSafeAtom = Atom(Atom::Link, "thread-safe"); + QString linkThreadSafe = getAutoLink(&threadSafeAtom, node, &threadSafeNode); + + if (ts == Node::NonReentrant) { + writer->writeStartElement(dbNamespace, "warning"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("This " + typeString(node) + " is not "); + generateSimpleLink(linkReentrant, "reentrant"); + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // warning + + return true; + } + if (ts == Node::Reentrant || ts == Node::ThreadSafe) { + writer->writeStartElement(dbNamespace, "note"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + + if (node->isAggregate()) { + writer->writeCharacters("All functions in this " + typeString(node) + " are "); + if (ts == Node::ThreadSafe) + generateSimpleLink(linkThreadSafe, "thread-safe"); + else + generateSimpleLink(linkReentrant, "reentrant"); + + NodeList reentrant; + NodeList threadsafe; + NodeList nonreentrant; + bool exceptions = hasExceptions(node, reentrant, threadsafe, nonreentrant); + if (!exceptions || (ts == Node::Reentrant && !threadsafe.isEmpty())) { + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + } else { + writer->writeCharacters(" with the following exceptions:"); + writer->writeEndElement(); // para + newLine(); + writer->writeStartElement(dbNamespace, "para"); + + if (ts == Node::Reentrant) { + if (!nonreentrant.isEmpty()) { + writer->writeCharacters("These functions are not "); + generateSimpleLink(linkReentrant, "reentrant"); + writer->writeCharacters(":"); + writer->writeEndElement(); // para + newLine(); + generateSignatureList(nonreentrant); + } + if (!threadsafe.isEmpty()) { + writer->writeCharacters("These functions are also "); + generateSimpleLink(linkThreadSafe, "thread-safe"); + writer->writeCharacters(":"); + writer->writeEndElement(); // para + newLine(); + generateSignatureList(threadsafe); + } + } else { // thread-safe + if (!reentrant.isEmpty()) { + writer->writeCharacters("These functions are only "); + generateSimpleLink(linkReentrant, "reentrant"); + writer->writeCharacters(":"); + writer->writeEndElement(); // para + newLine(); + generateSignatureList(reentrant); + } + if (!nonreentrant.isEmpty()) { + writer->writeCharacters("These functions are not "); + generateSimpleLink(linkReentrant, "reentrant"); + writer->writeCharacters(":"); + writer->writeEndElement(); // para + newLine(); + generateSignatureList(nonreentrant); + } + } + } + } else { + writer->writeCharacters("This " + typeString(node) + " is "); + if (ts == Node::ThreadSafe) + generateSimpleLink(linkThreadSafe, "thread-safe"); + else + generateSimpleLink(linkReentrant, "reentrant"); + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + } + writer->writeEndElement(); // note + + return true; + } + + return false; +} + +/*! + Generate the body of the documentation from the qdoc comment + found with the entity represented by the \a node. + */ +void DocBookGenerator::generateBody(const Node *node) +{ + // From Generator::generateBody, without warnings. + const FunctionNode *fn = node->isFunction() ? static_cast(node) : nullptr; + + if (!node->hasDoc() && !node->hasSharedDoc()) { + /* + Test for special function, like a destructor or copy constructor, + that has no documentation. + */ + if (fn) { + QString t; + if (fn->isDtor()) { + t = "Destroys the instance of " + fn->parent()->name() + "."; + if (fn->isVirtual()) + t += " The destructor is virtual."; + } else if (fn->isCtor()) { + t = "Default constructs an instance of " + fn->parent()->name() + "."; + } else if (fn->isCCtor()) { + t = "Copy constructor."; + } else if (fn->isMCtor()) { + t = "Move-copy constructor."; + } else if (fn->isCAssign()) { + t = "Copy-assignment constructor."; + } else if (fn->isMAssign()) { + t = "Move-assignment constructor."; + } + + if (!t.isEmpty()) + writer->writeTextElement(dbNamespace, "para", t); + } + } else if (!node->isSharingComment()) { + // Reimplements clause and type alias info precede body text + if (fn && !fn->overridesThis().isEmpty()) + generateReimplementsClause(fn); + else if (node->isProperty()) { + if (static_cast(node)->propertyType() != PropertyNode::Standard) + generateAddendum(node, BindableProperty, nullptr, false); + } + if (!generateText(node->doc().body(), node)) { + if (node->isMarkedReimp()) + return; + } + + if (fn) { + if (fn->isQmlSignal()) + generateAddendum(node, QmlSignalHandler); + if (fn->isPrivateSignal()) + generateAddendum(node, PrivateSignal); + if (fn->isInvokable()) + generateAddendum(node, Invokable); + if (fn->hasAssociatedProperties()) + generateAddendum(node, AssociatedProperties); + } + + // Warning generation skipped with respect to Generator::generateBody. + } + + generateRequiredLinks(node); +} + +/*! + Generates either a link to the project folder for example \a node, or a list + of links files/images if 'url.examples config' variable is not defined. + + Does nothing for non-example nodes. +*/ +void DocBookGenerator::generateRequiredLinks(const Node *node) +{ + // From Generator::generateRequiredLinks. + if (!node->isExample()) + return; + + const auto en = static_cast(node); + QString exampleUrl = Config::instance().getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES); + + if (exampleUrl.isEmpty()) { + if (!en->noAutoList()) { + generateFileList(en, false); // files + generateFileList(en, true); // images + } + } else { + generateLinkToExample(en, exampleUrl); + } +} + +/*! + The path to the example replaces a placeholder '\1' character if + one is found in the \a baseUrl string. If no such placeholder is found, + the path is appended to \a baseUrl, after a '/' character if \a baseUrl did + not already end in one. +*/ +void DocBookGenerator::generateLinkToExample(const ExampleNode *en, const QString &baseUrl) +{ + // From Generator::generateLinkToExample. + QString exampleUrl(baseUrl); + QString link; +#ifndef QT_BOOTSTRAPPED + link = QUrl(exampleUrl).host(); +#endif + if (!link.isEmpty()) + link.prepend(" @ "); + link.prepend("Example project"); + + const QLatin1Char separator('/'); + const QLatin1Char placeholder('\1'); + if (!exampleUrl.contains(placeholder)) { + if (!exampleUrl.endsWith(separator)) + exampleUrl += separator; + exampleUrl += placeholder; + } + + // Construct a path to the example; / + QStringList path = QStringList() + << Config::instance().getString(CONFIG_EXAMPLESINSTALLPATH) << en->name(); + path.removeAll(QString()); + + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", + exampleUrl.replace(placeholder, path.join(separator))); + writer->writeCharacters(link); + writer->writeEndElement(); // link + writer->writeEndElement(); // para + newLine(); +} + +/*! + This function is called when the documentation for an example is + being formatted. It outputs a list of files for the example, which + can be the example's source files or the list of images used by the + example. The images are copied into a subtree of + \c{...doc/html/images/used-in-examples/...} +*/ +void DocBookGenerator::generateFileList(const ExampleNode *en, bool images) +{ + // From Generator::generateFileList + QString tag; + QStringList paths; + if (images) { + paths = en->images(); + tag = "Images:"; + } else { // files + paths = en->files(); + tag = "Files:"; + } + std::sort(paths.begin(), paths.end(), Generator::comparePaths); + + if (paths.isEmpty()) + return; + + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters(tag); + writer->writeEndElement(); // para + newLine(); + + writer->writeStartElement(dbNamespace, "itemizedlist"); + + for (const auto &file : qAsConst(paths)) { + if (images) { + if (!file.isEmpty()) + addImageToCopy(en, file); + } else { + generateExampleFilePage(en, file); + } + + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + generateSimpleLink(file, file); + writer->writeEndElement(); // para + writer->writeEndElement(); // listitem + newLine(); + } + + writer->writeEndElement(); // itemizedlist + newLine(); +} + +/*! + Generate a file with the contents of a C++ or QML source file. + */ +void DocBookGenerator::generateExampleFilePage(const Node *node, const QString &file, + CodeMarker *marker) +{ + Q_UNUSED(marker); + // From HtmlGenerator::generateExampleFilePage. + if (!node->isExample()) + return; + + const auto en = static_cast(node); + + // Store current (active) writer + QXmlStreamWriter *currentWriter = writer; + writer = startDocument(en, file); + generateHeader(en->fullTitle(), en->subtitle(), en); + + Text text; + Quoter quoter; + Doc::quoteFromFile(en->doc().location(), quoter, file); + QString code = quoter.quoteTo(en->location(), QString(), QString()); + CodeMarker *codeMarker = CodeMarker::markerForFileName(file); + text << Atom(codeMarker->atomType(), code); + Atom a(codeMarker->atomType(), code); + generateText(text, en); + + endDocument(); + // Restore writer + writer = currentWriter; +} + +void DocBookGenerator::generateReimplementsClause(const FunctionNode *fn) +{ + // From Generator::generateReimplementsClause, without warning generation. + if (!fn->overridesThis().isEmpty()) { + if (fn->parent()->isClassNode()) { + auto cn = static_cast(fn->parent()); + const FunctionNode *overrides = cn->findOverriddenFunction(fn); + if (overrides && !overrides->isPrivate() && !overrides->parent()->isPrivate()) { + if (overrides->hasDoc()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("Reimplements: "); + QString fullName = + overrides->parent()->name() + "::" + overrides->signature(false, true); + generateFullName(overrides->parent(), fullName, overrides); + writer->writeCharacters("."); + return; + } + } + const PropertyNode *sameName = cn->findOverriddenProperty(fn); + if (sameName && sameName->hasDoc()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("Reimplements an access function for property: "); + QString fullName = sameName->parent()->name() + "::" + sameName->name(); + generateFullName(sameName->parent(), fullName, overrides); + writer->writeCharacters("."); + return; + } + } + } +} + +void DocBookGenerator::generateAlsoList(const Node *node, CodeMarker *marker) +{ + Q_UNUSED(marker); + // From Generator::generateAlsoList. + QList alsoList = node->doc().alsoList(); + supplementAlsoList(node, alsoList); + + if (!alsoList.isEmpty()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeCharacters("See also "); + writer->writeEndElement(); // emphasis + newLine(); + + writer->writeStartElement(dbNamespace, "simplelist"); + writer->writeAttribute("type", "vert"); + writer->writeAttribute("role", "see-also"); + for (const Text &text : alsoList) { + writer->writeStartElement(dbNamespace, "member"); + generateText(text, node); + writer->writeEndElement(); // member + newLine(); + } + writer->writeEndElement(); // simplelist + newLine(); + + writer->writeEndElement(); // para + } +} + +/*! + Generate a list of maintainers in the output + */ +void DocBookGenerator::generateMaintainerList(const Aggregate *node, CodeMarker *marker) +{ + Q_UNUSED(marker); + // From Generator::generateMaintainerList. + QStringList sl = getMetadataElements(node, "maintainer"); + + if (!sl.isEmpty()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeCharacters("Maintained by: "); + writer->writeEndElement(); // emphasis + newLine(); + + writer->writeStartElement(dbNamespace, "simplelist"); + writer->writeAttribute("type", "vert"); + writer->writeAttribute("role", "maintainer"); + for (int i = 0; i < sl.size(); ++i) { + writer->writeStartElement(dbNamespace, "member"); + writer->writeCharacters(sl.at(i)); + writer->writeEndElement(); // member + newLine(); + } + writer->writeEndElement(); // simplelist + newLine(); + + writer->writeEndElement(); // para + } +} + +/*! + Open a new file to write XML contents, including the DocBook + opening tag. + */ +QXmlStreamWriter *DocBookGenerator::startGenericDocument(const Node *node, const QString &fileName) +{ + QFile *outFile = openSubPageFile(node, fileName); + writer = new QXmlStreamWriter(outFile); + writer->setAutoFormatting(false); // We need a precise handling of line feeds. + + writer->writeStartDocument(); + newLine(); + writer->writeNamespace(dbNamespace, "db"); + writer->writeNamespace(xlinkNamespace, "xlink"); + writer->writeStartElement(dbNamespace, "article"); + writer->writeAttribute("version", "5.2"); + if (!naturalLanguage.isEmpty()) + writer->writeAttribute("xml:lang", naturalLanguage); + newLine(); + + // Empty the section stack for the new document. + sectionLevels.resize(0); + + return writer; +} + +QXmlStreamWriter *DocBookGenerator::startDocument(const Node *node) +{ + QString fileName = Generator::fileName(node, fileExtension()); + return startGenericDocument(node, fileName); +} + +QXmlStreamWriter *DocBookGenerator::startDocument(const ExampleNode *en, const QString &file) +{ + QString fileName = linkForExampleFile(file, en); + return startGenericDocument(en, fileName); +} + +void DocBookGenerator::endDocument() +{ + writer->writeEndElement(); // article + writer->writeEndDocument(); + writer->device()->close(); + delete writer; + writer = nullptr; +} + +/*! + Generate a reference page for the C++ class, namespace, or + header file documented in \a node. + */ +void DocBookGenerator::generateCppReferencePage(Node *node) +{ + // Based on HtmlGenerator::generateCppReferencePage. + Q_ASSERT(node->isAggregate()); + const auto aggregate = static_cast(node); + + QString title; + QString rawTitle; + QString fullTitle; + if (aggregate->isNamespace()) { + rawTitle = aggregate->plainName(); + fullTitle = aggregate->plainFullName(); + title = rawTitle + " Namespace"; + } else if (aggregate->isClass()) { + rawTitle = aggregate->plainName(); + QString templateDecl = node->templateDecl(); + if (!templateDecl.isEmpty()) + fullTitle = QString("%1 %2 ").arg(templateDecl, aggregate->typeWord(false)); + fullTitle += aggregate->plainFullName(); + title = rawTitle + QLatin1Char(' ') + aggregate->typeWord(true); + } else if (aggregate->isHeader()) { + title = fullTitle = rawTitle = aggregate->fullTitle(); + } + + QString subtitleText; + if (rawTitle != fullTitle) + subtitleText = fullTitle; + + // Start producing the DocBook file. + writer = startDocument(node); + + // Info container. + generateHeader(title, subtitleText, aggregate); + + generateRequisites(aggregate); + generateStatus(aggregate); + + // Element synopsis. + generateDocBookSynopsis(node); + + // Actual content. + if (!aggregate->doc().isEmpty()) { + startSection(registerRef("details"), "Detailed Description"); + + generateBody(aggregate); + generateAlsoList(aggregate); + generateMaintainerList(aggregate); + + endSection(); + } + + Sections sections(const_cast(aggregate)); + auto *sectionVector = + (aggregate->isNamespace() || aggregate->isHeader()) ? + §ions.stdDetailsSections() : + §ions.stdCppClassDetailsSections(); + SectionVector::ConstIterator section = sectionVector->constBegin(); + while (section != sectionVector->constEnd()) { + bool headerGenerated = false; + NodeVector::ConstIterator member = section->members().constBegin(); + while (member != section->members().constEnd()) { + if ((*member)->access() == Access::Private) { // ### check necessary? + ++member; + continue; + } + + if (!headerGenerated) { + // Equivalent to h2 + startSection(registerRef(section->title().toLower()), section->title()); + headerGenerated = true; + } + + if ((*member)->nodeType() != Node::Class) { + // This function starts its own section. + generateDetailedMember(*member, aggregate); + } else { + startSectionBegin(); + writer->writeCharacters("class "); + generateFullName(*member, aggregate); + startSectionEnd(); + generateBrief(*member); + endSection(); + } + + ++member; + } + + if (headerGenerated) + endSection(); + ++section; + } + + generateObsoleteMembers(sections); + + endDocument(); +} + +void DocBookGenerator::generateSynopsisInfo(const QString &key, const QString &value) +{ + writer->writeStartElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", key); + writer->writeCharacters(value); + writer->writeEndElement(); // synopsisinfo + newLine(); +} + +void DocBookGenerator::generateModifier(const QString &value) +{ + writer->writeTextElement(dbNamespace, "modifier", value); + newLine(); +} + +/*! + Generate the metadata for the given \a node in DocBook. + */ +void DocBookGenerator::generateDocBookSynopsis(const Node *node) +{ + if (!node) + return; + + // From Generator::generateStatus, HtmlGenerator::generateRequisites, + // Generator::generateThreadSafeness, QDocIndexFiles::generateIndexSection. + + // This function is the only place where DocBook extensions are used. + if (config->getBool(CONFIG_DOCBOOKEXTENSIONS)) + return; + + // Nothing to export in some cases. Note that isSharedCommentNode() returns + // true also for QML property groups. + if (node->isGroup() || node->isGroup() || node->isSharedCommentNode() || node->isModule() + || node->isJsModule() || node->isQmlModule() || node->isPageNode()) + return; + + // Cast the node to several subtypes (null pointer if the node is not of the required type). + const Aggregate *aggregate = + node->isAggregate() ? static_cast(node) : nullptr; + const ClassNode *classNode = node->isClass() ? static_cast(node) : nullptr; + const FunctionNode *functionNode = + node->isFunction() ? static_cast(node) : nullptr; + const PropertyNode *propertyNode = + node->isProperty() ? static_cast(node) : nullptr; + const VariableNode *variableNode = + node->isVariable() ? static_cast(node) : nullptr; + const EnumNode *enumNode = node->isEnumType() ? static_cast(node) : nullptr; + const QmlPropertyNode *qpn = + node->isQmlProperty() ? static_cast(node) : nullptr; + const QmlTypeNode *qcn = node->isQmlType() ? static_cast(node) : nullptr; + // Typedefs are ignored, as they correspond to enums. + // Groups and modules are ignored. + // Documents are ignored, they have no interesting metadata. + + // Start the synopsis tag. + QString synopsisTag = nodeToSynopsisTag(node); + writer->writeStartElement(dbNamespace, synopsisTag); + newLine(); + + // Name and basic properties of each tag (like types and parameters). + if (node->isClass()) { + writer->writeStartElement(dbNamespace, "ooclass"); + writer->writeTextElement(dbNamespace, "classname", node->plainName()); + writer->writeEndElement(); // ooclass + newLine(); + } else if (node->isNamespace()) { + writer->writeTextElement(dbNamespace, "namespacename", node->plainName()); + newLine(); + } else if (node->isQmlType()) { + writer->writeStartElement(dbNamespace, "ooclass"); + writer->writeTextElement(dbNamespace, "classname", node->plainName()); + writer->writeEndElement(); // ooclass + newLine(); + if (!qcn->groupNames().isEmpty()) + writer->writeAttribute("groups", qcn->groupNames().join(QLatin1Char(','))); + } else if (node->isProperty()) { + writer->writeTextElement(dbNamespace, "modifier", "(Qt property)"); + newLine(); + writer->writeTextElement(dbNamespace, "type", propertyNode->dataType()); + newLine(); + writer->writeTextElement(dbNamespace, "varname", node->plainName()); + newLine(); + } else if (node->isVariable()) { + if (variableNode->isStatic()) { + writer->writeTextElement(dbNamespace, "modifier", "static"); + newLine(); + } + writer->writeTextElement(dbNamespace, "type", variableNode->dataType()); + newLine(); + writer->writeTextElement(dbNamespace, "varname", node->plainName()); + newLine(); + } else if (node->isEnumType()) { + writer->writeTextElement(dbNamespace, "enumname", node->plainName()); + newLine(); + } else if (node->isQmlProperty()) { + QString name = node->name(); + if (qpn->isAttached()) + name.prepend(qpn->element() + QLatin1Char('.')); + + writer->writeTextElement(dbNamespace, "type", qpn->dataType()); + newLine(); + writer->writeTextElement(dbNamespace, "varname", name); + newLine(); + + if (qpn->isAttached()) { + writer->writeTextElement(dbNamespace, "modifier", "attached"); + newLine(); + } + if ((const_cast(qpn))->isWritable()) { + writer->writeTextElement(dbNamespace, "modifier", "writable"); + newLine(); + } + if ((const_cast(qpn))->isRequired()) { + writer->writeTextElement(dbNamespace, "modifier", "required"); + newLine(); + } + if (qpn->isReadOnly()) { + generateModifier("[read-only]"); + newLine(); + } + if (qpn->isDefault()) { + generateModifier("[default]"); + newLine(); + } + } else if (node->isFunction()) { + if (functionNode->virtualness() != "non") + generateModifier("virtual"); + if (functionNode->isConst()) + generateModifier("const"); + if (functionNode->isStatic()) + generateModifier("static"); + + if (!functionNode->isMacro()) { + if (functionNode->returnType() == "void") + writer->writeEmptyElement(dbNamespace, "void"); + else + writer->writeTextElement(dbNamespace, "type", functionNode->returnType()); + newLine(); + } + // Remove two characters from the plain name to only get the name + // of the method without parentheses. + writer->writeTextElement(dbNamespace, "methodname", node->plainName().chopped(2)); + newLine(); + + if (functionNode->isOverload()) + generateModifier("overload"); + if (functionNode->isDefault()) + generateModifier("default"); + if (functionNode->isFinal()) + generateModifier("final"); + if (functionNode->isOverride()) + generateModifier("override"); + + if (!functionNode->isMacro() && functionNode->parameters().isEmpty()) { + writer->writeEmptyElement(dbNamespace, "void"); + newLine(); + } + + const Parameters &lp = functionNode->parameters(); + for (int i = 0; i < lp.count(); ++i) { + const Parameter ¶meter = lp.at(i); + writer->writeStartElement(dbNamespace, "methodparam"); + newLine(); + writer->writeTextElement(dbNamespace, "type", parameter.type()); + newLine(); + writer->writeTextElement(dbNamespace, "parameter", parameter.name()); + newLine(); + if (!parameter.defaultValue().isEmpty()) { + writer->writeTextElement(dbNamespace, "initializer", parameter.defaultValue()); + newLine(); + } + writer->writeEndElement(); // methodparam + newLine(); + } + + generateSynopsisInfo("meta", functionNode->metanessString()); + + if (functionNode->isOverload()) + generateSynopsisInfo("overload-number", + QString::number(functionNode->overloadNumber())); + + if (functionNode->isRef()) + generateSynopsisInfo("refness", QString::number(1)); + else if (functionNode->isRefRef()) + generateSynopsisInfo("refness", QString::number(2)); + + if (functionNode->hasAssociatedProperties()) { + QStringList associatedProperties; + const NodeList &nodes = functionNode->associatedProperties(); + for (const Node *n : nodes) { + const auto pn = static_cast(n); + associatedProperties << pn->name(); + } + associatedProperties.sort(); + generateSynopsisInfo("associated-property", + associatedProperties.join(QLatin1Char(','))); + } + + QString signature = functionNode->signature(false, false); + // 'const' is already part of FunctionNode::signature() + if (functionNode->isFinal()) + signature += " final"; + if (functionNode->isOverride()) + signature += " override"; + if (functionNode->isPureVirtual()) + signature += " = 0"; + else if (functionNode->isDefault()) + signature += " = default"; + generateSynopsisInfo("signature", signature); + } else if (node->isTypedef()) { + writer->writeTextElement(dbNamespace, "type", node->plainName()); + } else { + node->doc().location().warning( + QStringLiteral("Unexpected node type in generateDocBookSynopsis: %1") + .arg(node->nodeTypeString())); + newLine(); + } + + // Accessibility status. + if (!node->isPageNode() && !node->isCollectionNode()) { + switch (node->access()) { + case Access::Public: + generateSynopsisInfo("access", "public"); + break; + case Access::Protected: + generateSynopsisInfo("access", "protected"); + break; + case Access::Private: + generateSynopsisInfo("access", "private"); + break; + default: + break; + } + if (node->isAbstract()) + generateSynopsisInfo("abstract", "true"); + } + + // Status. + switch (node->status()) { + case Node::Active: + generateSynopsisInfo("status", "active"); + break; + case Node::Preliminary: + generateSynopsisInfo("status", "preliminary"); + break; + case Node::Deprecated: + generateSynopsisInfo("status", "deprecated"); + break; + case Node::Obsolete: + generateSynopsisInfo("status", "obsolete"); + break; + case Node::Internal: + generateSynopsisInfo("status", "internal"); + break; + default: + generateSynopsisInfo("status", "main"); + break; + } + + // C++ classes and name spaces. + if (aggregate) { + // Includes. + if (!aggregate->includeFiles().isEmpty()) { + for (const QString &include : aggregate->includeFiles()) + generateSynopsisInfo("headers", include); + } + + // Since and project. + if (!aggregate->since().isEmpty()) + generateSynopsisInfo("since", formatSince(aggregate)); + + if (aggregate->nodeType() == Node::Class || aggregate->nodeType() == Node::Namespace) { + // CMake and QT variable. + if (!aggregate->physicalModuleName().isEmpty()) { + const CollectionNode *cn = + m_qdb->getCollectionNode(aggregate->physicalModuleName(), Node::Module); + if (cn && !cn->qtCMakeComponent().isEmpty()) { + const QString qtComponent = "Qt" + QString::number(QT_VERSION_MAJOR); + const QString findpackageText = "find_package(" + qtComponent + + " COMPONENTS " + cn->qtCMakeComponent() + " REQUIRED)"; + const QString targetLinkLibrariesText = + "target_link_libraries(mytarget PRIVATE " + qtComponent + "::" + cn->qtCMakeComponent() + + ")"; + generateSynopsisInfo("cmake-find-package", findpackageText); + generateSynopsisInfo("cmake-target-link-libraries", targetLinkLibrariesText); + } + if (cn && !cn->qtVariable().isEmpty()) + generateSynopsisInfo("qmake", "QT += " + cn->qtVariable()); + } + } + + if (aggregate->nodeType() == Node::Class) { + // Instantiated by. + auto *classe = const_cast(static_cast(aggregate)); + if (classe->qmlElement() != nullptr && classe->status() != Node::Internal) { + const Node *otherNode = nullptr; + Atom a = Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement())); + QString link = getAutoLink(&a, aggregate, &otherNode); + + writer->writeStartElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "instantiatedBy"); + generateSimpleLink(link, classe->qmlElement()->name()); + writer->writeEndElement(); // synopsisinfo + newLine(); + } + + // Inherits. + QList::ConstIterator r; + if (!classe->baseClasses().isEmpty()) { + writer->writeStartElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "inherits"); + + r = classe->baseClasses().constBegin(); + int index = 0; + while (r != classe->baseClasses().constEnd()) { + if ((*r).m_node) { + generateFullName((*r).m_node, classe); + + if ((*r).m_access == Access::Protected) { + writer->writeCharacters(" (protected)"); + } else if ((*r).m_access == Access::Private) { + writer->writeCharacters(" (private)"); + } + writer->writeCharacters( + Utilities::comma(index++, classe->baseClasses().count())); + } + ++r; + } + + writer->writeEndElement(); // synopsisinfo + newLine(); + } + + // Inherited by. + if (!classe->derivedClasses().isEmpty()) { + writer->writeStartElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "inheritedBy"); + generateSortedNames(classe, classe->derivedClasses()); + writer->writeEndElement(); // synopsisinfo + newLine(); + } + } + } + + // QML types. + if (qcn) { + // Module name and version (i.e. import). + QString logicalModuleVersion; + const CollectionNode *collection = + m_qdb->getCollectionNode(qcn->logicalModuleName(), qcn->nodeType()); + if (collection) + logicalModuleVersion = collection->logicalModuleVersion(); + else + logicalModuleVersion = qcn->logicalModuleVersion(); + + generateSynopsisInfo("import", + "import " + qcn->logicalModuleName() + QLatin1Char(' ') + + logicalModuleVersion); + + // Since and project. + if (!qcn->since().isEmpty()) + generateSynopsisInfo("since", formatSince(qcn)); + + // Inherited by. + NodeList subs; + QmlTypeNode::subclasses(qcn, subs); + if (!subs.isEmpty()) { + writer->writeTextElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "inheritedBy"); + generateSortedQmlNames(qcn, subs); + writer->writeEndElement(); // synopsisinfo + newLine(); + } + + // Inherits. + QmlTypeNode *base = qcn->qmlBaseNode(); + while (base && base->isInternal()) + base = base->qmlBaseNode(); + if (base) { + const Node *otherNode = nullptr; + Atom a = Atom(Atom::LinkNode, CodeMarker::stringForNode(base)); + QString link = getAutoLink(&a, base, &otherNode); + + writer->writeTextElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "inherits"); + generateSimpleLink(link, base->name()); + writer->writeEndElement(); // synopsisinfo + newLine(); + } + + // Instantiates. + ClassNode *cn = (const_cast(qcn))->classNode(); + if (cn && (cn->status() != Node::Internal)) { + const Node *otherNode = nullptr; + Atom a = Atom(Atom::LinkNode, CodeMarker::stringForNode(qcn)); + QString link = getAutoLink(&a, cn, &otherNode); + + writer->writeTextElement(dbNamespace, "synopsisinfo"); + writer->writeAttribute(dbNamespace, "role", "instantiates"); + generateSimpleLink(link, cn->name()); + writer->writeEndElement(); // synopsisinfo + newLine(); + } + } + + // Thread safeness. + switch (node->threadSafeness()) { + case Node::UnspecifiedSafeness: + generateSynopsisInfo("threadsafeness", "unspecified"); + break; + case Node::NonReentrant: + generateSynopsisInfo("threadsafeness", "non-reentrant"); + break; + case Node::Reentrant: + generateSynopsisInfo("threadsafeness", "reentrant"); + break; + case Node::ThreadSafe: + generateSynopsisInfo("threadsafeness", "thread safe"); + break; + default: + generateSynopsisInfo("threadsafeness", "unspecified"); + break; + } + + // Module. + if (!node->physicalModuleName().isEmpty()) + generateSynopsisInfo("module", node->physicalModuleName()); + + // Group. + if (classNode && !classNode->groupNames().isEmpty()) { + generateSynopsisInfo("groups", classNode->groupNames().join(QLatin1Char(','))); + } else if (qcn && !qcn->groupNames().isEmpty()) { + generateSynopsisInfo("groups", qcn->groupNames().join(QLatin1Char(','))); + } + + // Properties. + if (propertyNode) { + for (const Node *fnNode : propertyNode->getters()) { + if (fnNode) { + const auto funcNode = static_cast(fnNode); + generateSynopsisInfo("getter", funcNode->name()); + } + } + for (const Node *fnNode : propertyNode->setters()) { + if (fnNode) { + const auto funcNode = static_cast(fnNode); + generateSynopsisInfo("setter", funcNode->name()); + } + } + for (const Node *fnNode : propertyNode->resetters()) { + if (fnNode) { + const auto funcNode = static_cast(fnNode); + generateSynopsisInfo("resetter", funcNode->name()); + } + } + for (const Node *fnNode : propertyNode->notifiers()) { + if (fnNode) { + const auto funcNode = static_cast(fnNode); + generateSynopsisInfo("notifier", funcNode->name()); + } + } + } + + // Enums and typedefs. + if (enumNode) { + for (const EnumItem &item : enumNode->items()) { + writer->writeStartElement(dbNamespace, "enumitem"); + writer->writeAttribute(dbNamespace, "enumidentifier", item.name()); + writer->writeAttribute(dbNamespace, "enumvalue", item.value()); + writer->writeEndElement(); // enumitem + newLine(); + } + } + + writer->writeEndElement(); // nodeToSynopsisTag (like classsynopsis) + newLine(); + + // The typedef associated to this enum. + if (enumNode && enumNode->flagsType()) { + writer->writeStartElement(dbNamespace, "typedefsynopsis"); + newLine(); + + writer->writeTextElement(dbNamespace, "typedefname", + enumNode->flagsType()->fullDocumentName()); + + writer->writeEndElement(); // typedefsynopsis + newLine(); + } +} + +QString taggedNode(const Node *node) +{ + // From CodeMarker::taggedNode, but without the tag part (i.e. only the QML specific case + // remaining). + // TODO: find a better name for this. + if (node->nodeType() == Node::QmlType && node->name().startsWith(QLatin1String("QML:"))) + return node->name().mid(4); + return node->name(); +} + +/*! + Parses a string with method/variable name and (return) type + to include type tags. + */ +void DocBookGenerator::typified(const QString &string, const Node *relative, bool trailingSpace, + bool generateType) +{ + // Adapted from CodeMarker::typified and HtmlGenerator::highlightedCode. + // Note: CppCodeMarker::markedUpIncludes is not needed for DocBook, as this part is natively + // generated as DocBook. Hence, there is no need to reimplement <@headerfile> from + // HtmlGenerator::highlightedCode. + QString result; + QString pendingWord; + + for (int i = 0; i <= string.size(); ++i) { + QChar ch; + if (i != string.size()) + ch = string.at(i); + + QChar lower = ch.toLower(); + if ((lower >= QLatin1Char('a') && lower <= QLatin1Char('z')) || ch.digitValue() >= 0 + || ch == QLatin1Char('_') || ch == QLatin1Char(':')) { + pendingWord += ch; + } else { + if (!pendingWord.isEmpty()) { + bool isProbablyType = (pendingWord != QLatin1String("const")); + if (generateType && isProbablyType) { + // Flush the current buffer. + writer->writeCharacters(result); + result.truncate(0); + + // Add the link, logic from HtmlGenerator::highlightedCode. + const Node *n = m_qdb->findTypeNode(pendingWord, relative, Node::DontCare); + QString href; + if (!(n && (n->isQmlBasicType() || n->isJsBasicType())) + || (relative + && (relative->genus() == n->genus() || Node::DontCare == n->genus()))) { + href = linkForNode(n, relative); + } + + writer->writeStartElement(dbNamespace, "type"); + if (href.isEmpty()) + writer->writeCharacters(pendingWord); + else + generateSimpleLink(href, pendingWord); + writer->writeEndElement(); // type + } else { + result += pendingWord; + } + } + pendingWord.clear(); + + if (ch.unicode() != '\0') + result += ch; + } + } + + if (trailingSpace && string.size()) { + if (!string.endsWith(QLatin1Char('*')) && !string.endsWith(QLatin1Char('&'))) + result += QLatin1Char(' '); + } + + writer->writeCharacters(result); +} + +void DocBookGenerator::generateSynopsisName(const Node *node, const Node *relative, + bool generateNameLink) +{ + // Implements the rewriting of <@link> from HtmlGenerator::highlightedCode, only due to calls to + // CodeMarker::linkTag in CppCodeMarker::markedUpSynopsis. + QString name = taggedNode(node); + + if (!generateNameLink) { + writer->writeCharacters(name); + return; + } + + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + generateSimpleLink(linkForNode(node, relative), name); + writer->writeEndElement(); // emphasis +} + +void DocBookGenerator::generateParameter(const Parameter ¶meter, const Node *relative, + bool generateExtra, bool generateType) +{ + const QString &pname = parameter.name(); + const QString &ptype = parameter.type(); + QString paramName; + if (!pname.isEmpty()) { + typified(ptype, relative, true, generateType); + paramName = pname; + } else { + paramName = ptype; + } + if (generateExtra || pname.isEmpty()) { + // Look for the _ character in the member name followed by a number (or n): + // this is intended to be rendered as a subscript. + QRegularExpression sub("([a-z]+)_([0-9]+|n)"); + + writer->writeStartElement(dbNamespace, "emphasis"); + auto match = sub.match(paramName); + if (match.hasMatch()) { + writer->writeCharacters(match.captured(0)); + writer->writeStartElement(dbNamespace, "sub"); + writer->writeCharacters(match.captured(1)); + writer->writeEndElement(); // sub + } else { + writer->writeCharacters(paramName); + } + writer->writeEndElement(); // emphasis + } + + const QString &pvalue = parameter.defaultValue(); + if (generateExtra && !pvalue.isEmpty()) + writer->writeCharacters(" = " + pvalue); +} + +void DocBookGenerator::generateSynopsis(const Node *node, const Node *relative, + Section::Style style) +{ + // From HtmlGenerator::generateSynopsis (conditions written as booleans). + const bool generateExtra = style != Section::AllMembers; + const bool generateType = style != Section::Details; + const bool generateNameLink = style != Section::Details; + + // From CppCodeMarker::markedUpSynopsis, reversed the generation of "extra" and "synopsis". + const int MaxEnumValues = 6; + + if (generateExtra) + writer->writeCharacters(CodeMarker::extraSynopsis(node, style)); + + // Then generate the synopsis. + if (style == Section::Details) { + if (!node->isRelatedNonmember() && !node->isProxyNode() && !node->parent()->name().isEmpty() + && !node->parent()->isHeader() && !node->isProperty() && !node->isQmlNode() + && !node->isJsNode()) { + writer->writeCharacters(taggedNode(node->parent()) + "::"); + } + } + + switch (node->nodeType()) { + case Node::Namespace: + writer->writeCharacters("namespace "); + generateSynopsisName(node, relative, generateNameLink); + break; + case Node::Class: + writer->writeCharacters("class "); + generateSynopsisName(node, relative, generateNameLink); + break; + case Node::Function: { + const auto func = (const FunctionNode *)node; + + // First, the part coming before the name. + if (style == Section::Summary || style == Section::Accessors) { + if (!func->isNonvirtual()) + writer->writeCharacters(QStringLiteral("virtual ")); + } + + // Name and parameters. + if (style != Section::AllMembers && !func->returnType().isEmpty()) + typified(func->returnType(), relative, true, generateType); + generateSynopsisName(node, relative, generateNameLink); + + if (!func->isMacroWithoutParams()) { + writer->writeCharacters(QStringLiteral("(")); + if (!func->parameters().isEmpty()) { + const Parameters ¶meters = func->parameters(); + for (int i = 0; i < parameters.count(); i++) { + if (i > 0) + writer->writeCharacters(QStringLiteral(", ")); + generateParameter(parameters.at(i), relative, generateExtra, generateType); + } + } + writer->writeCharacters(QStringLiteral(")")); + } + if (func->isConst()) + writer->writeCharacters(QStringLiteral(" const")); + + if (style == Section::Summary || style == Section::Accessors) { + // virtual is prepended, if needed. + QString synopsis; + if (func->isFinal()) + synopsis += QStringLiteral(" final"); + if (func->isOverride()) + synopsis += QStringLiteral(" override"); + if (func->isPureVirtual()) + synopsis += QStringLiteral(" = 0"); + if (func->isRef()) + synopsis += QStringLiteral(" &"); + else if (func->isRefRef()) + synopsis += QStringLiteral(" &&"); + writer->writeCharacters(synopsis); + } else if (style == Section::AllMembers) { + if (!func->returnType().isEmpty() && func->returnType() != "void") { + writer->writeCharacters(QStringLiteral(" : ")); + typified(func->returnType(), relative, false, generateType); + } + } else { + QString synopsis; + if (func->isRef()) + synopsis += QStringLiteral(" &"); + else if (func->isRefRef()) + synopsis += QStringLiteral(" &&"); + writer->writeCharacters(synopsis); + } + } break; + case Node::Enum: { + const auto enume = static_cast(node); + writer->writeCharacters(QStringLiteral("enum ")); + generateSynopsisName(node, relative, generateNameLink); + + QString synopsis; + if (style == Section::Summary) { + synopsis += " { "; + + QStringList documentedItems = enume->doc().enumItemNames(); + if (documentedItems.isEmpty()) { + const auto &enumItems = enume->items(); + for (const auto &item : enumItems) + documentedItems << item.name(); + } + const QStringList omitItems = enume->doc().omitEnumItemNames(); + for (const auto &item : omitItems) + documentedItems.removeAll(item); + + if (documentedItems.size() > MaxEnumValues) { + // Take the last element and keep it safe, then elide the surplus. + const QString last = documentedItems.last(); + documentedItems = documentedItems.mid(0, MaxEnumValues - 1); + documentedItems += "…"; // Ellipsis: in HTML, …. + documentedItems += last; + } + synopsis += documentedItems.join(QLatin1String(", ")); + + if (!documentedItems.isEmpty()) + synopsis += QLatin1Char(' '); + synopsis += QLatin1Char('}'); + } + writer->writeCharacters(synopsis); + } break; + case Node::TypeAlias: { + if (style == Section::Details) { + QString templateDecl = node->templateDecl(); + if (!templateDecl.isEmpty()) + writer->writeCharacters(templateDecl + QLatin1Char(' ')); + } + generateSynopsisName(node, relative, generateNameLink); + } break; + case Node::Typedef: { + if (static_cast(node)->associatedEnum()) + writer->writeCharacters("flags "); + generateSynopsisName(node, relative, generateNameLink); + } break; + case Node::Property: { + const auto property = static_cast(node); + generateSynopsisName(node, relative, generateNameLink); + writer->writeCharacters(" : "); + typified(property->qualifiedDataType(), relative, false, generateType); + } break; + case Node::Variable: { + const auto variable = static_cast(node); + if (style == Section::AllMembers) { + generateSynopsisName(node, relative, generateNameLink); + writer->writeCharacters(" : "); + typified(variable->dataType(), relative, false, generateType); + } else { + typified(variable->leftType(), relative, false, generateType); + writer->writeCharacters(" "); + generateSynopsisName(node, relative, generateNameLink); + writer->writeCharacters(variable->rightType()); + } + } break; + default: + generateSynopsisName(node, relative, generateNameLink); + } +} + +void DocBookGenerator::generateEnumValue(const QString &enumValue, const Node *relative) +{ + // From CppCodeMarker::markedUpEnumValue, simplifications from Generator::plainCode (removing + // <@op>). With respect to CppCodeMarker::markedUpEnumValue, the order of generation of parents + // must be reversed so that they are processed in the order + if (!relative->isEnumType()) { + writer->writeCharacters(enumValue); + return; + } + + QList parents; + const Node *node = relative->parent(); + while (!node->isHeader() && node->parent()) { + parents.prepend(node); + if (node->parent() == relative || node->parent()->name().isEmpty()) + break; + node = node->parent(); + } + if (static_cast(relative)->isScoped()) + parents << relative; + + writer->writeStartElement(dbNamespace, "code"); + for (auto parent : parents) { + generateSynopsisName(parent, relative, true); + writer->writeCharacters("::"); + } + + writer->writeCharacters(enumValue); + writer->writeEndElement(); // code +} + +/*! + If the node is an overloaded signal, and a node with an + example on how to connect to it + + Someone didn't finish writing this comment, and I don't know what this + function is supposed to do, so I have not tried to complete the comment + yet. + */ +void DocBookGenerator::generateOverloadedSignal(const Node *node) +{ + // From Generator::generateOverloadedSignal. + QString code = getOverloadedSignalCode(node); + if (code.isEmpty()) + return; + + writer->writeStartElement(dbNamespace, "note"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("Signal "); + writer->writeTextElement(dbNamespace, "emphasis", node->name()); + writer->writeCharacters(" is overloaded in this class. To connect to this " + "signal by using the function pointer syntax, Qt " + "provides a convenient helper for obtaining the " + "function pointer as shown in this example:"); + writer->writeTextElement(dbNamespace, "code", code); + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // note + newLine(); +} + +/*! + Generates an addendum note of type \a type for \a node. \a marker + is unused in this generator. +*/ +void DocBookGenerator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote) +{ + Q_UNUSED(marker); + Q_ASSERT(node && !node->name().isEmpty()); + if (generateNote) { + writer->writeStartElement(dbNamespace, "note"); + newLine(); + } + switch (type) { + case Invokable: + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters( + "This function can be invoked via the meta-object system and from QML. See "); + generateSimpleLink(node->url(), "Q_INVOKABLE"); + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + break; + case PrivateSignal: + writer->writeTextElement(dbNamespace, "para", + "This is a private signal. It can be used in signal connections but " + "cannot be emitted by the user."); + break; + case QmlSignalHandler: + { + QString handler(node->name()); + int prefixLocation = handler.lastIndexOf('.', -2) + 1; + handler[prefixLocation] = handler[prefixLocation].toTitleCase(); + handler.insert(prefixLocation, QLatin1String("on")); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("The corresponding handler is "); + writer->writeTextElement(dbNamespace, "code", handler); + writer->writeCharacters("."); + writer->writeEndElement(); // para + newLine(); + break; + } + case AssociatedProperties: + { + if (!node->isFunction()) + return; + const FunctionNode *fn = static_cast(node); + NodeList nodes = fn->associatedProperties(); + if (nodes.isEmpty()) + return; + std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); + for (const auto node : qAsConst(nodes)) { + QString msg; + const auto pn = static_cast(node); + switch (pn->role(fn)) { + case PropertyNode::Getter: + msg = QStringLiteral("Getter function"); + break; + case PropertyNode::Setter: + msg = QStringLiteral("Setter function"); + break; + case PropertyNode::Resetter: + msg = QStringLiteral("Resetter function"); + break; + case PropertyNode::Notifier: + msg = QStringLiteral("Notifier signal"); + break; + default: + continue; + } + writer->writeCharacters(msg + " for property "); + generateSimpleLink(linkForNode(pn, nullptr), pn->name()); + writer->writeCharacters(". "); + } + break; + } + case BindableProperty: + { + const Node *linkNode; + Atom linkAtom = Atom(Atom::Link, "QProperty"); + QString link = getAutoLink(&linkAtom, node, &linkNode); + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("This property supports "); + generateSimpleLink(link, "QProperty"); + writer->writeCharacters(" bindings."); + writer->writeEndElement(); // para + newLine(); + break; + } + default: + break; + } + + if (generateNote) { + writer->writeEndElement(); // note + newLine(); + } +} + +void DocBookGenerator::generateDetailedMember(const Node *node, const PageNode *relative) +{ + // From HtmlGenerator::generateDetailedMember. + writer->writeStartElement(dbNamespace, "section"); + if (node->isSharedCommentNode()) { + const auto scn = reinterpret_cast(node); + const QList &collective = scn->collective(); + + bool firstFunction = true; + for (const Node *n : collective) { + if (n->isFunction()) { + QString nodeRef = refForNode(n); + + if (firstFunction) { + writer->writeAttribute("xml:id", refForNode(collective.at(0))); + newLine(); + writer->writeStartElement(dbNamespace, "title"); + generateSynopsis(n, relative, Section::Details); + writer->writeEndElement(); // title + newLine(); + + firstFunction = false; + } else { + writer->writeStartElement(dbNamespace, "bridgehead"); + writer->writeAttribute("renderas", "sect2"); + writer->writeAttribute("xml:id", nodeRef); + generateSynopsis(n, relative, Section::Details); + writer->writeEndElement(); // bridgehead + newLine(); + } + } + } + } else { + const EnumNode *etn; + QString nodeRef = refForNode(node); + if (node->isEnumType() && (etn = static_cast(node))->flagsType()) { + writer->writeAttribute("xml:id", nodeRef); + newLine(); + writer->writeStartElement(dbNamespace, "title"); + generateSynopsis(etn, relative, Section::Details); + writer->writeEndElement(); // title + newLine(); + writer->writeStartElement(dbNamespace, "bridgehead"); + generateSynopsis(etn->flagsType(), relative, Section::Details); + writer->writeEndElement(); // bridgehead + newLine(); + } else { + writer->writeAttribute("xml:id", nodeRef); + newLine(); + writer->writeStartElement(dbNamespace, "title"); + generateSynopsis(node, relative, Section::Details); + writer->writeEndElement(); // title + newLine(); + } + } + + generateDocBookSynopsis(node); + + generateStatus(node); + generateBody(node); + generateOverloadedSignal(node); + generateThreadSafeness(node); + generateSince(node); + + if (node->isProperty()) { + const auto property = static_cast(node); + if (property->propertyType() == PropertyNode::Standard) { + Section section(Section::Accessors, Section::Active); + + section.appendMembers(property->getters().toVector()); + section.appendMembers(property->setters().toVector()); + section.appendMembers(property->resetters().toVector()); + + if (!section.members().isEmpty()) { + writer->writeStartElement(dbNamespace, "para"); + newLine(); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("Access functions:"); + newLine(); + writer->writeEndElement(); // emphasis + newLine(); + writer->writeEndElement(); // para + newLine(); + generateSectionList(section, node); + } + + Section notifiers(Section::Accessors, Section::Active); + notifiers.appendMembers(property->notifiers().toVector()); + + if (!notifiers.members().isEmpty()) { + writer->writeStartElement(dbNamespace, "para"); + newLine(); + writer->writeStartElement(dbNamespace, "emphasis"); + writer->writeAttribute("role", "bold"); + writer->writeCharacters("Notifier signal:"); + newLine(); + writer->writeEndElement(); // emphasis + newLine(); + writer->writeEndElement(); // para + newLine(); + generateSectionList(notifiers, node); + } + } + } else if (node->isEnumType()) { + const auto en = static_cast(node); + + if (qflagsHref_.isEmpty()) { + Node *qflags = m_qdb->findClassNode(QStringList("QFlags")); + if (qflags) + qflagsHref_ = linkForNode(qflags, nullptr); + } + + if (en->flagsType()) { + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("The " + en->flagsType()->name() + " type is a typedef for "); + generateSimpleLink(qflagsHref_, "QFlags"); + writer->writeCharacters("<" + en->name() + ">. "); + writer->writeCharacters("It stores an OR combination of " + en->name() + "values."); + writer->writeEndElement(); // para + newLine(); + } + } + generateAlsoList(node); + endSection(); // section +} + +void DocBookGenerator::generateSectionList(const Section §ion, const Node *relative, + Section::Status status) +{ + // From HtmlGenerator::generateSectionList, just generating a list (not tables). + const NodeVector &members = + (status == Section::Obsolete ? section.obsoleteMembers() : section.members()); + if (!members.isEmpty()) { + bool hasPrivateSignals = false; + bool isInvokable = false; + + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + + int i = 0; + NodeVector::ConstIterator m = members.constBegin(); + while (m != members.constEnd()) { + if ((*m)->access() == Access::Private) { + ++m; + continue; + } + + writer->writeStartElement(dbNamespace, "listitem"); + newLine(); + writer->writeStartElement(dbNamespace, "para"); + + // prefix no more needed. + generateSynopsis(*m, relative, section.style()); + if ((*m)->isFunction()) { + const auto fn = static_cast(*m); + if (fn->isPrivateSignal()) + hasPrivateSignals = true; + else if (fn->isInvokable()) + isInvokable = true; + } + + writer->writeEndElement(); // para + newLine(); + writer->writeEndElement(); // listitem + newLine(); + + i++; + ++m; + } + + writer->writeEndElement(); // itemizedlist + newLine(); + + if (hasPrivateSignals) + generateAddendum(relative, Generator::PrivateSignal); + if (isInvokable) + generateAddendum(relative, Generator::Invokable); + } + + if (status != Section::Obsolete && section.style() == Section::Summary + && !section.inheritedMembers().isEmpty()) { + writer->writeStartElement(dbNamespace, "itemizedlist"); + newLine(); + + generateSectionInheritedList(section, relative); + + writer->writeEndElement(); // itemizedlist + newLine(); + } +} + +void DocBookGenerator::generateSectionInheritedList(const Section §ion, const Node *relative) +{ + // From HtmlGenerator::generateSectionInheritedList. + QList>::ConstIterator p = section.inheritedMembers().constBegin(); + while (p != section.inheritedMembers().constEnd()) { + writer->writeStartElement(dbNamespace, "listitem"); + writer->writeCharacters(QString::number((*p).second) + u' '); + if ((*p).second == 1) + writer->writeCharacters(section.singular()); + else + writer->writeCharacters(section.plural()); + writer->writeCharacters(" inherited from "); + generateSimpleLink(fileName((*p).first) + '#' + + Generator::cleanRef(section.title().toLower()), + (*p).first->plainFullName(relative)); + ++p; + } +} + +/*! + Generate the DocBook page for an entity that doesn't map + to any underlying parsable C++, QML, or Javascript element. + */ +void DocBookGenerator::generatePageNode(PageNode *pn) +{ + Q_ASSERT(writer == nullptr); + // From HtmlGenerator::generatePageNode, remove anything related to TOCs. + writer = startDocument(pn); + + generateHeader(pn->fullTitle(), pn->subtitle(), pn); + generateBody(pn); + generateAlsoList(pn); + generateFooter(); + + endDocument(); +} + +/*! + Extract sections of markup text and output them. + */ +bool DocBookGenerator::generateQmlText(const Text &text, const Node *relative, CodeMarker *marker, + const QString &qmlName) +{ + Q_UNUSED(marker); + Q_UNUSED(qmlName); + // From Generator::generateQmlText. + const Atom *atom = text.firstAtom(); + bool result = false; + + if (atom != nullptr) { + initializeTextOutput(); + while (atom) { + if (atom->type() != Atom::QmlText) + atom = atom->next(); + else { + atom = atom->next(); + while (atom && (atom->type() != Atom::EndQmlText)) { + int n = 1 + generateAtom(atom, relative); + while (n-- > 0) + atom = atom->next(); + } + } + } + result = true; + } + return result; +} + +/*! + Generate the DocBook page for a QML type. \qcn is the QML type. + */ +void DocBookGenerator::generateQmlTypePage(QmlTypeNode *qcn) +{ + // From HtmlGenerator::generateQmlTypePage. + // Start producing the DocBook file. + Q_ASSERT(writer == nullptr); + writer = startDocument(qcn); + + Generator::setQmlTypeContext(qcn); + QString title = qcn->fullTitle(); + if (qcn->isJsType()) + title += " JavaScript Type"; + else + title += " QML Type"; + + generateHeader(title, qcn->subtitle(), qcn); + generateQmlRequisites(qcn); + + startSection(registerRef("details"), "Detailed Description"); + generateBody(qcn); + + ClassNode *cn = qcn->classNode(); + if (cn) + generateQmlText(cn->doc().body(), cn); + generateAlsoList(qcn); + + endSection(); + + Sections sections(qcn); + for (const auto §ion : sections.stdQmlTypeDetailsSections()) { + if (!section.isEmpty()) { + startSection(registerRef(section.title().toLower()), section.title()); + + for (const auto &member : section.members()) + generateDetailedQmlMember(member, qcn); + + endSection(); + } + } + + generateObsoleteQmlMembers(sections); + + generateFooter(); + Generator::setQmlTypeContext(nullptr); + + endDocument(); +} + +/*! + Generate the DocBook page for the QML basic type represented + by the QML basic type node \a qbtn. + */ +void DocBookGenerator::generateQmlBasicTypePage(QmlBasicTypeNode *qbtn) +{ + // From HtmlGenerator::generateQmlBasicTypePage. + // Start producing the DocBook file. + Q_ASSERT(writer == nullptr); + writer = startDocument(qbtn); + + QString htmlTitle = qbtn->fullTitle(); + if (qbtn->isJsType()) + htmlTitle += " JavaScript Basic Type"; + else + htmlTitle += " QML Basic Type"; + + Sections sections(qbtn); + generateHeader(htmlTitle, qbtn->subtitle(), qbtn); + + startSection(registerRef("details"), "Detailed Description"); + + generateBody(qbtn); + generateAlsoList(qbtn); + + endSection(); + + SectionVector::ConstIterator s = sections.stdQmlTypeDetailsSections().constBegin(); + while (s != sections.stdQmlTypeDetailsSections().constEnd()) { + if (!s->isEmpty()) { + startSection(registerRef(s->title().toLower()), s->title()); + + NodeVector::ConstIterator m = s->members().constBegin(); + while (m != s->members().constEnd()) { + generateDetailedQmlMember(*m, qbtn); + ++m; + } + + endSection(); + } + ++s; + } + generateFooter(); + + endDocument(); +} + +/*! + Outputs the DocBook detailed documentation for a section + on a QML element reference page. + */ +void DocBookGenerator::generateDetailedQmlMember(Node *node, const Aggregate *relative) +{ + // From HtmlGenerator::generateDetailedQmlMember, with elements from + // CppCodeMarker::markedUpQmlItem and HtmlGenerator::generateQmlItem. + std::function getQmlPropertyTitle = [&](QmlPropertyNode *n) { + if (!n->isReadOnlySet() && n->declarativeCppNode()) + n->markReadOnly(!n->isWritable()); + + QString title; + QStringList extra; + if (n->isDefault()) + extra << "default"; + else if (n->isReadOnly()) + extra << "read-only"; + else if (n->isRequired()) + extra << "required"; + + if (!n->since().isEmpty()) { + if (!extra.isEmpty()) + extra.last().append(','); + extra << "since " + n->since(); + } + if (!extra.isEmpty()) + title = QString("[%1] ").arg(extra.join(QLatin1Char(' '))); + + // Finalise generation of name, as per CppCodeMarker::markedUpQmlItem. + if (n->isAttached()) + title += n->element() + QLatin1Char('.'); + title += n->name() + " : " + n->dataType(); + + return title; + }; + + std::function generateQmlMethodTitle = [&](Node *node) { + generateSynopsis(node, relative, Section::Details); + }; + + bool generateEndSection = true; + + if (node->isPropertyGroup()) { + const auto scn = static_cast(node); + + QString heading; + if (!scn->name().isEmpty()) + heading = scn->name() + " group"; + else + heading = node->name(); + startSection(refForNode(scn), heading); + // This last call creates a title for this section. In other words, + // titles are forbidden for the rest of the section. + + const QList sharedNodes = scn->collective(); + for (const auto &node : sharedNodes) { + if (node->isQmlProperty() || node->isJsProperty()) { + auto *qpn = static_cast(node); + + writer->writeStartElement(dbNamespace, "bridgehead"); + writer->writeAttribute("renderas", "sect2"); + writer->writeAttribute("xml:id", refForNode(qpn)); + writer->writeCharacters(getQmlPropertyTitle(qpn)); + writer->writeEndElement(); // bridgehead + newLine(); + + generateDocBookSynopsis(qpn); + } + } + } else if (node->isQmlProperty() || node->isJsProperty()) { + auto qpn = static_cast(node); + startSection(refForNode(qpn), getQmlPropertyTitle(qpn)); + generateDocBookSynopsis(qpn); + } else if (node->isSharedCommentNode()) { + const auto scn = reinterpret_cast(node); + const QList &sharedNodes = scn->collective(); + + // In the section, generate a title for the first node, then bridgeheads for + // the next ones. + int i = 0; + for (const auto m : sharedNodes) { + // Ignore this element if there is nothing to generate. + if (!node->isFunction(Node::QML) && !node->isFunction(Node::JS) + && !node->isQmlProperty() && !node->isJsProperty()) { + continue; + } + + // Complete the section tag. + if (i == 0) { + writer->writeStartElement(dbNamespace, "section"); + writer->writeAttribute("xml:id", refForNode(m)); + newLine(); + } + + // Write the tag containing the title. + writer->writeStartElement(dbNamespace, (i == 0) ? "title" : "bridgehead"); + if (i > 0) + writer->writeAttribute("renderas", "sect2"); + + // Write the title. + QString title; + if (node->isFunction(Node::QML) || node->isFunction(Node::JS)) + generateQmlMethodTitle(node); + else if (node->isQmlProperty() || node->isJsProperty()) + writer->writeCharacters(getQmlPropertyTitle(static_cast(node))); + + // Complete the title and the synopsis. + generateDocBookSynopsis(m); + ++i; + } + + if (i == 0) + generateEndSection = false; + } else { // assume the node is a method/signal handler + startSectionBegin(refForNode(node)); + generateQmlMethodTitle(node); + startSectionEnd(); + } + + generateStatus(node); + generateBody(node); + generateThreadSafeness(node); + generateSince(node); + generateAlsoList(node); + + if (generateEndSection) + endSection(); +} + +/*! + Recursive writing of DocBook files from the root \a node. + */ +void DocBookGenerator::generateDocumentation(Node *node) +{ + // Mainly from Generator::generateDocumentation, with parts from + // Generator::generateDocumentation and WebXMLGenerator::generateDocumentation. + // Don't generate nodes that are already processed, or if they're not + // supposed to generate output, ie. external, index or images nodes. + if (!node->url().isNull()) + return; + if (node->isIndexNode()) + return; + if (node->isInternal() && !m_showInternal) + return; + if (node->isExternalPage()) + return; + + if (node->parent()) { + if (node->isCollectionNode()) { + /* + A collection node collects: groups, C++ modules, + QML modules or JavaScript modules. Testing for a + CollectionNode must be done before testing for a + TextPageNode because a CollectionNode is a PageNode + at this point. + + Don't output an HTML page for the collection + node unless the \group, \module, \qmlmodule or + \jsmodule command was actually seen by qdoc in + the qdoc comment for the node. + + A key prerequisite in this case is the call to + mergeCollections(cn). We must determine whether + this group, module, QML module, or JavaScript + module has members in other modules. We know at + this point that cn's members list contains only + members in the current module. Therefore, before + outputting the page for cn, we must search for + members of cn in the other modules and add them + to the members list. + */ + auto cn = static_cast(node); + if (cn->wasSeen()) { + m_qdb->mergeCollections(cn); + generateCollectionNode(cn); + } else if (cn->isGenericCollection()) { + // Currently used only for the module's related orphans page + // but can be generalized for other kinds of collections if + // other use cases pop up. + generateGenericCollectionPage(cn); + } + } else if (node->isTextPageNode()) { // Pages. + generatePageNode(static_cast(node)); + } else if (node->isAggregate()) { // Aggregates. + if ((node->isClassNode() || node->isHeader() || node->isNamespace()) + && node->docMustBeGenerated()) { + generateCppReferencePage(static_cast(node)); + } else if (node->isQmlType() || node->isJsType()) { + generateQmlTypePage(static_cast(node)); + } else if (node->isQmlBasicType() || node->isJsBasicType()) { + generateQmlBasicTypePage(static_cast(node)); + } else if (node->isProxyNode()) { + generateProxyPage(static_cast(node)); + } + } + } + + if (node->isAggregate()) { + auto *aggregate = static_cast(node); + for (auto c : aggregate->childNodes()) { + if (node->isPageNode() && !node->isPrivate()) + generateDocumentation(c); + } + } +} + +void DocBookGenerator::generateProxyPage(Aggregate *aggregate) +{ + // Adapted from HtmlGenerator::generateProxyPage. + Q_ASSERT(aggregate->isProxyNode()); + + // Start producing the DocBook file. + Q_ASSERT(writer == nullptr); + writer = startDocument(aggregate); + + // Info container. + generateHeader(aggregate->plainFullName(), "", aggregate); + + // No element synopsis. + + // Actual content. + if (!aggregate->doc().isEmpty()) { + startSection(registerRef("details"), "Detailed Description"); + + generateBody(aggregate); + generateAlsoList(aggregate); + generateMaintainerList(aggregate); + + endSection(); + } + + Sections sections(aggregate); + SectionVector *detailsSections = §ions.stdDetailsSections(); + + for (const auto §ion : qAsConst(*detailsSections)) { + if (section.isEmpty()) + continue; + + startSection(section.title().toLower(), section.title()); + + const QList &members = section.members(); + for (const auto &member : members) { + if (!member->isPrivate()) { // ### check necessary? + if (!member->isClassNode()) { + generateDetailedMember(member, aggregate); + } else { + startSectionBegin(); + generateFullName(member, aggregate); + startSectionEnd(); + generateBrief(member); + endSection(); + } + } + } + + endSection(); + } + + generateFooter(); + + endDocument(); +} + +/*! + Generate the HTML page for a group, module, or QML module. + */ +void DocBookGenerator::generateCollectionNode(CollectionNode *cn) +{ + // Adapted from HtmlGenerator::generateCollectionNode. + // Start producing the DocBook file. + Q_ASSERT(writer == nullptr); + writer = startDocument(cn); + + // Info container. + generateHeader(cn->fullTitle(), cn->subtitle(), cn); + + // Element synopsis. + generateDocBookSynopsis(cn); + + // Generate brief for C++ modules, status for all modules. + if (cn->genus() != Node::DOC && cn->genus() != Node::DontCare) { + if (cn->isModule()) + generateBrief(cn); + generateStatus(cn); + generateSince(cn); + } + + // Actual content. + if (cn->isModule()) { + if (!cn->noAutoList()) { + NodeMap nmm; + cn->getMemberNamespaces(nmm); + if (!nmm.isEmpty()) { + startSection(registerRef("namespaces"), "Namespaces"); + generateAnnotatedList(cn, nmm.values(), "namespaces"); + endSection(); + } + nmm.clear(); + cn->getMemberClasses(nmm); + if (!nmm.isEmpty()) { + startSection(registerRef("classes"), "Classes"); + generateAnnotatedList(cn, nmm.values(), "classes"); + endSection(); + } + } + } + + bool generatedTitle = false; + if (cn->isModule() && !cn->doc().briefText().isEmpty()) { + startSection(registerRef("details"), "Detailed Description"); + generatedTitle = true; + } else { + writeAnchor(registerRef("details")); + } + + generateBody(cn); + generateAlsoList(cn); + + if (!cn->noAutoList() && (cn->isGroup() || cn->isQmlModule() || cn->isJsModule())) + generateAnnotatedList(cn, cn->members(), "members"); + + if (generatedTitle) + endSection(); + + generateFooter(); + + endDocument(); +} + +/*! + Generate the HTML page for a generic collection. This is usually + a collection of C++ elements that are related to an element in + a different module. + */ +void DocBookGenerator::generateGenericCollectionPage(CollectionNode *cn) +{ + // Adapted from HtmlGenerator::generateGenericCollectionPage. + // TODO: factor out this code to generate a file name. + QString name = cn->name().toLower(); + name.replace(QChar(' '), QString("-")); + QString filename = cn->tree()->physicalModuleName() + "-" + name + "." + fileExtension(); + + // Start producing the DocBook file. + Q_ASSERT(writer == nullptr); + writer = startGenericDocument(cn, filename); + + // Info container. + generateHeader(cn->fullTitle(), cn->subtitle(), cn); + + // Element synopsis. + generateDocBookSynopsis(cn); + + // Actual content. + writer->writeStartElement(dbNamespace, "para"); + writer->writeCharacters("Each function or type documented here is related to a class or " + "namespace that is documented in a different module. The reference " + "page for that class or namespace will link to the function or type " + "on this page."); + writer->writeEndElement(); // para + + const CollectionNode *cnc = cn; + const QList members = cn->members(); + for (const auto &member : members) + generateDetailedMember(member, cnc); + + generateFooter(); + + endDocument(); +} + +void DocBookGenerator::generateFullName(const Node *node, const Node *relative) +{ + Q_ASSERT(node); + Q_ASSERT(relative); + + // From Generator::appendFullName. + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", fullDocumentLocation(node)); + writer->writeAttribute(xlinkNamespace, "role", targetType(node)); + writer->writeCharacters(node->fullName(relative)); + writer->writeEndElement(); // link +} + +void DocBookGenerator::generateFullName(const Node *apparentNode, const QString &fullName, + const Node *actualNode) +{ + Q_ASSERT(apparentNode); + Q_ASSERT(actualNode); + + // From Generator::appendFullName. + if (actualNode == nullptr) + actualNode = apparentNode; + writer->writeStartElement(dbNamespace, "link"); + writer->writeAttribute(xlinkNamespace, "href", fullDocumentLocation(actualNode)); + writer->writeAttribute("type", targetType(actualNode)); + writer->writeCharacters(fullName); + writer->writeEndElement(); // link +} + +QT_END_NAMESPACE diff --git a/src/qdoc/docbookgenerator.h b/src/qdoc/docbookgenerator.h new file mode 100644 index 0000000000..8de9160cfa --- /dev/null +++ b/src/qdoc/docbookgenerator.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Thibaut Cuvelier +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOCBOOKGENERATOR_H +#define DOCBOOKGENERATOR_H + +#include "codemarker.h" +#include "config.h" +#include "xmlgenerator.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class Aggregate; +class ExampleNode; +class FunctionNode; + +class DocBookGenerator : public XmlGenerator +{ +public: + explicit DocBookGenerator() = default; + + void initializeGenerator() override; + QString format() override; + +protected: + QString fileExtension() const override; + void generateDocumentation(Node *node) override; + using Generator::generateCppReferencePage; + void generateCppReferencePage(Node *node); + using Generator::generatePageNode; + void generatePageNode(PageNode *pn); + using Generator::generateQmlTypePage; + void generateQmlTypePage(QmlTypeNode *qcn); + using Generator::generateQmlBasicTypePage; + void generateQmlBasicTypePage(QmlBasicTypeNode *qbtn); + using Generator::generateCollectionNode; + void generateCollectionNode(CollectionNode *cn); + using Generator::generateGenericCollectionPage; + void generateGenericCollectionPage(CollectionNode *cn); + using Generator::generateProxyPage; + void generateProxyPage(Aggregate *aggregate); + + void generateList(const Node *relative, const QString &selector); + void generateHeader(const QString &title, const QString &subtitle, const Node *node); + void closeTextSections(); + void generateFooter(); + void generateDocBookSynopsis(const Node *node); + void generateRequisites(const Aggregate *inner); + void generateQmlRequisites(const QmlTypeNode *qcn); + void generateSortedNames(const ClassNode *cn, const QList &rc); + void generateSortedQmlNames(const Node *base, const NodeList &subs); + bool generateStatus(const Node *node); + bool generateThreadSafeness(const Node *node); + bool generateSince(const Node *node); + void generateAddendum(const Node *node, Generator::Addendum type, CodeMarker *marker = nullptr, + bool generateNote = true) override; + using Generator::generateBody; + void generateBody(const Node *node); + + bool generateText(const Text &text, const Node *relative, + CodeMarker *marker = nullptr) override; + const Atom *generateAtomList(const Atom *atom, const Node *relative, bool generate, + int &numAtoms); + int generateAtom(const Atom *atom, const Node *relative, CodeMarker *marker = nullptr) override; + +private: + QXmlStreamWriter *startDocument(const Node *node); + QXmlStreamWriter *startDocument(const ExampleNode *en, const QString &file); + QXmlStreamWriter *startGenericDocument(const Node *node, const QString &fileName); + void endDocument(); + + void generateAnnotatedList(const Node *relative, const NodeList &nodeList, + const QString &selector); + void generateAnnotatedLists(const Node *relative, const NodeMultiMap &nmm, + const QString &selector); + void generateCompactList(ListType listType, const Node *relative, const NodeMultiMap &nmm, + const QString &commonPrefix, const QString &selector); + using Generator::generateFileList; + void generateFileList(const ExampleNode *en, bool images); + void generateObsoleteMembers(const Sections §ions); + void generateObsoleteQmlMembers(const Sections §ions); + void generateSectionList(const Section §ion, const Node *relative, + Section::Status status = Section::Active); + void generateSectionInheritedList(const Section §ion, const Node *relative); + void generateSynopsisName(const Node *node, const Node *relative, bool generateNameLink); + void generateParameter(const Parameter ¶meter, const Node *relative, bool generateExtra, + bool generateType); + void generateSynopsis(const Node *node, const Node *relative, Section::Style style); + void generateEnumValue(const QString &enumValue, const Node *relative); + void generateDetailedMember(const Node *node, const PageNode *relative); + void generateDetailedQmlMember(Node *node, const Aggregate *relative); + + void generateFullName(const Node *node, const Node *relative); + void generateFullName(const Node *apparentNode, const QString &fullName, + const Node *actualNode); + void generateBrief(const Node *node); + void generateAlsoList(const Node *node, CodeMarker *marker = nullptr) override; + void generateSignatureList(const NodeList &nodes); + void generateMaintainerList(const Aggregate *node, CodeMarker *marker = nullptr) override; + void generateReimplementsClause(const FunctionNode *fn); + void generateClassHierarchy(const Node *relative, NodeMultiMap &classMap); + void generateFunctionIndex(const Node *relative); + void generateLegaleseList(const Node *relative); + void generateExampleFilePage(const Node *en, const QString &file, + CodeMarker *marker = nullptr) override; + void generateOverloadedSignal(const Node *node); + bool generateQmlText(const Text &text, const Node *relative, CodeMarker *marker = nullptr, + const QString &qmlName = QString()) override; + void generateRequiredLinks(const Node *node); + void generateLinkToExample(const ExampleNode *en, const QString &baseUrl); + + void typified(const QString &string, const Node *relative, bool trailingSpace = false, + bool generateType = true); + void generateLink(const Atom *atom); + void beginLink(const QString &link, const Node *node, const Node *relative); + void endLink(); + inline void newLine(); + void startSectionBegin(); + void startSectionBegin(const QString &id); + void startSectionEnd(); + void startSection(const QString &id, const QString &title); + void endSection(); + void writeAnchor(const QString &id); + void generateSimpleLink(const QString &href, const QString &text); + void generateStartRequisite(const QString &description); + void generateEndRequisite(); + void generateRequisite(const QString &description, const QString &value); + void generateCMakeRequisite(const QStringList &values); + void generateSynopsisInfo(const QString &key, const QString &value); + void generateModifier(const QString &value); + + bool inListItemLineOpen {}; + bool inLink {}; + int currentSectionLevel {}; + QStack sectionLevels {}; + QString qflagsHref_; + + QString project; + QString projectDescription; + QString naturalLanguage; + QString buildversion; + QXmlStreamWriter *writer = nullptr; + + Config *config = nullptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/qdoc/docparser.cpp b/src/qdoc/docparser.cpp new file mode 100644 index 0000000000..14e4aff9e4 --- /dev/null +++ b/src/qdoc/docparser.cpp @@ -0,0 +1,2489 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "docparser.h" + +#include "codemarker.h" +#include "doc.h" +#include "docprivate.h" +#include "editdistance.h" +#include "macro.h" +#include "openedlist.h" +#include "tokenizer.h" + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +DocUtilities &DocParser::m_utilities = DocUtilities::instance(); + +enum { + CMD_A, + CMD_ANNOTATEDLIST, + CMD_B, + CMD_BADCODE, + CMD_BOLD, + CMD_BR, + CMD_BRIEF, + CMD_C, + CMD_CAPTION, + CMD_CODE, + CMD_CODELINE, + CMD_DIV, + CMD_DOTS, + CMD_E, + CMD_ELSE, + CMD_ENDCODE, + CMD_ENDDIV, + CMD_ENDFOOTNOTE, + CMD_ENDIF, + CMD_ENDLEGALESE, + CMD_ENDLINK, + CMD_ENDLIST, + CMD_ENDMAPREF, + CMD_ENDOMIT, + CMD_ENDQUOTATION, + CMD_ENDRAW, + CMD_ENDSECTION1, + CMD_ENDSECTION2, + CMD_ENDSECTION3, + CMD_ENDSECTION4, + CMD_ENDSIDEBAR, + CMD_ENDTABLE, + CMD_FOOTNOTE, + CMD_GENERATELIST, + CMD_GRANULARITY, + CMD_HEADER, + CMD_HR, + CMD_I, + CMD_IF, + CMD_IMAGE, + CMD_IMPORTANT, + CMD_INCLUDE, + CMD_INLINEIMAGE, + CMD_INDEX, + CMD_INPUT, + CMD_KEYWORD, + CMD_L, + CMD_LEGALESE, + CMD_LI, + CMD_LINK, + CMD_LIST, + CMD_META, + CMD_NEWCODE, + CMD_NOTE, + CMD_O, + CMD_OLDCODE, + CMD_OMIT, + CMD_OMITVALUE, + CMD_OVERLOAD, + CMD_PRINTLINE, + CMD_PRINTTO, + CMD_PRINTUNTIL, + CMD_QUOTATION, + CMD_QUOTEFILE, + CMD_QUOTEFROMFILE, + CMD_QUOTEFUNCTION, + CMD_RAW, + CMD_ROW, + CMD_SA, + CMD_SECTION1, + CMD_SECTION2, + CMD_SECTION3, + CMD_SECTION4, + CMD_SIDEBAR, + CMD_SINCELIST, + CMD_SKIPLINE, + CMD_SKIPTO, + CMD_SKIPUNTIL, + CMD_SNIPPET, + CMD_SPAN, + CMD_SUB, + CMD_SUP, + CMD_TABLE, + CMD_TABLEOFCONTENTS, + CMD_TARGET, + CMD_TT, + CMD_UICONTROL, + CMD_UNDERLINE, + CMD_UNICODE, + CMD_VALUE, + CMD_WARNING, + CMD_QML, + CMD_ENDQML, + CMD_CPP, + CMD_ENDCPP, + CMD_QMLTEXT, + CMD_ENDQMLTEXT, + CMD_CPPTEXT, + CMD_ENDCPPTEXT, + CMD_JS, + CMD_ENDJS, + NOT_A_CMD +}; + +static struct +{ + const char *english; + int no; + QString *alias; +} cmds[] = { { "a", CMD_A, nullptr }, + { "annotatedlist", CMD_ANNOTATEDLIST, nullptr }, + { "b", CMD_B, nullptr }, + { "badcode", CMD_BADCODE, nullptr }, + { "bold", CMD_BOLD, nullptr }, + { "br", CMD_BR, nullptr }, + { "brief", CMD_BRIEF, nullptr }, + { "c", CMD_C, nullptr }, + { "caption", CMD_CAPTION, nullptr }, + { "code", CMD_CODE, nullptr }, + { "codeline", CMD_CODELINE, nullptr }, + { "div", CMD_DIV, nullptr }, + { "dots", CMD_DOTS, nullptr }, + { "e", CMD_E, nullptr }, + { "else", CMD_ELSE, nullptr }, + { "endcode", CMD_ENDCODE, nullptr }, + { "enddiv", CMD_ENDDIV, nullptr }, + { "endfootnote", CMD_ENDFOOTNOTE, nullptr }, + { "endif", CMD_ENDIF, nullptr }, + { "endlegalese", CMD_ENDLEGALESE, nullptr }, + { "endlink", CMD_ENDLINK, nullptr }, + { "endlist", CMD_ENDLIST, nullptr }, + { "endmapref", CMD_ENDMAPREF, nullptr }, + { "endomit", CMD_ENDOMIT, nullptr }, + { "endquotation", CMD_ENDQUOTATION, nullptr }, + { "endraw", CMD_ENDRAW, nullptr }, + { "endsection1", CMD_ENDSECTION1, nullptr }, // ### don't document for now + { "endsection2", CMD_ENDSECTION2, nullptr }, // ### don't document for now + { "endsection3", CMD_ENDSECTION3, nullptr }, // ### don't document for now + { "endsection4", CMD_ENDSECTION4, nullptr }, // ### don't document for now + { "endsidebar", CMD_ENDSIDEBAR, nullptr }, + { "endtable", CMD_ENDTABLE, nullptr }, + { "footnote", CMD_FOOTNOTE, nullptr }, + { "generatelist", CMD_GENERATELIST, nullptr }, + { "granularity", CMD_GRANULARITY, nullptr }, // ### don't document for now + { "header", CMD_HEADER, nullptr }, + { "hr", CMD_HR, nullptr }, + { "i", CMD_I, nullptr }, + { "if", CMD_IF, nullptr }, + { "image", CMD_IMAGE, nullptr }, + { "important", CMD_IMPORTANT, nullptr }, + { "include", CMD_INCLUDE, nullptr }, + { "inlineimage", CMD_INLINEIMAGE, nullptr }, + { "index", CMD_INDEX, nullptr }, // ### don't document for now + { "input", CMD_INPUT, nullptr }, + { "keyword", CMD_KEYWORD, nullptr }, + { "l", CMD_L, nullptr }, + { "legalese", CMD_LEGALESE, nullptr }, + { "li", CMD_LI, nullptr }, + { "link", CMD_LINK, nullptr }, + { "list", CMD_LIST, nullptr }, + { "meta", CMD_META, nullptr }, + { "newcode", CMD_NEWCODE, nullptr }, + { "note", CMD_NOTE, nullptr }, + { "o", CMD_O, nullptr }, + { "oldcode", CMD_OLDCODE, nullptr }, + { "omit", CMD_OMIT, nullptr }, + { "omitvalue", CMD_OMITVALUE, nullptr }, + { "overload", CMD_OVERLOAD, nullptr }, + { "printline", CMD_PRINTLINE, nullptr }, + { "printto", CMD_PRINTTO, nullptr }, + { "printuntil", CMD_PRINTUNTIL, nullptr }, + { "quotation", CMD_QUOTATION, nullptr }, + { "quotefile", CMD_QUOTEFILE, nullptr }, + { "quotefromfile", CMD_QUOTEFROMFILE, nullptr }, + { "quotefunction", CMD_QUOTEFUNCTION, nullptr }, + { "raw", CMD_RAW, nullptr }, + { "row", CMD_ROW, nullptr }, + { "sa", CMD_SA, nullptr }, + { "section1", CMD_SECTION1, nullptr }, + { "section2", CMD_SECTION2, nullptr }, + { "section3", CMD_SECTION3, nullptr }, + { "section4", CMD_SECTION4, nullptr }, + { "sidebar", CMD_SIDEBAR, nullptr }, + { "sincelist", CMD_SINCELIST, nullptr }, + { "skipline", CMD_SKIPLINE, nullptr }, + { "skipto", CMD_SKIPTO, nullptr }, + { "skipuntil", CMD_SKIPUNTIL, nullptr }, + { "snippet", CMD_SNIPPET, nullptr }, + { "span", CMD_SPAN, nullptr }, + { "sub", CMD_SUB, nullptr }, + { "sup", CMD_SUP, nullptr }, + { "table", CMD_TABLE, nullptr }, + { "tableofcontents", CMD_TABLEOFCONTENTS, nullptr }, + { "target", CMD_TARGET, nullptr }, + { "tt", CMD_TT, nullptr }, + { "uicontrol", CMD_UICONTROL, nullptr }, + { "underline", CMD_UNDERLINE, nullptr }, + { "unicode", CMD_UNICODE, nullptr }, + { "value", CMD_VALUE, nullptr }, + { "warning", CMD_WARNING, nullptr }, + { "qml", CMD_QML, nullptr }, + { "endqml", CMD_ENDQML, nullptr }, + { "cpp", CMD_CPP, nullptr }, + { "endcpp", CMD_ENDCPP, nullptr }, + { "qmltext", CMD_QMLTEXT, nullptr }, + { "endqmltext", CMD_ENDQMLTEXT, nullptr }, + { "cpptext", CMD_CPPTEXT, nullptr }, + { "endcpptext", CMD_ENDCPPTEXT, nullptr }, + { "js", CMD_JS, nullptr }, + { "endjs", CMD_ENDJS, nullptr }, + { nullptr, 0, nullptr } }; + +int DocParser::tabSize; +QStringList DocParser::exampleFiles; +QStringList DocParser::exampleDirs; +QStringList DocParser::sourceFiles; +QStringList DocParser::sourceDirs; +QStringList DocParser::ignoreWords; +bool DocParser::quoting = false; + +static QString cleanLink(const QString &link) +{ + int colonPos = link.indexOf(':'); + if ((colonPos == -1) || (!link.startsWith("file:") && !link.startsWith("mailto:"))) + return link; + return link.mid(colonPos + 1).simplified(); +} + +void DocParser::initialize(const Config &config) +{ + tabSize = config.getInt(CONFIG_TABSIZE); + exampleFiles = config.getCanonicalPathList(CONFIG_EXAMPLES); + exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); + sourceFiles = config.getCanonicalPathList(CONFIG_SOURCES); + sourceDirs = config.getCanonicalPathList(CONFIG_SOURCEDIRS); + ignoreWords = config.getStringList(CONFIG_IGNOREWORDS); + + int i = 0; + while (cmds[i].english) { + cmds[i].alias = new QString(Doc::alias(cmds[i].english)); + m_utilities.cmdHash.insert(*cmds[i].alias, cmds[i].no); + + if (cmds[i].no != i) + Location::internalError(QStringLiteral("command %1 missing").arg(i)); + ++i; + } + + // If any of the formats define quotinginformation, activate quoting + DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION); + for (const auto &format : config.getOutputFormats()) + DocParser::quoting = DocParser::quoting + || config.getBool(format + Config::dot + CONFIG_QUOTINGINFORMATION); +} + +void DocParser::terminate() +{ + exampleFiles.clear(); + exampleDirs.clear(); + sourceFiles.clear(); + sourceDirs.clear(); + + int i = 0; + while (cmds[i].english) { + delete cmds[i].alias; + cmds[i].alias = nullptr; + ++i; + } +} + +/*! + Parse the \a source string to build a Text data structure + in \a docPrivate. The Text data structure is a linked list + of Atoms. + + \a metaCommandSet is the set of metacommands that may be + found in \a source. These metacommands are not markup text + commands. They are topic commands and related metacommands. + */ +void DocParser::parse(const QString &source, DocPrivate *docPrivate, + const QSet &metaCommandSet, const QSet &possibleTopics) +{ + m_input = source; + m_position = 0; + m_inputLength = m_input.length(); + m_cachedLocation = docPrivate->start_loc; + m_cachedPosition = 0; + m_private = docPrivate; + m_private->text << Atom::Nop; + m_private->topics_.clear(); + + m_paragraphState = OutsideParagraph; + m_inTableHeader = false; + m_inTableRow = false; + m_inTableItem = false; + m_indexStartedParagraph = false; + m_pendingParagraphLeftType = Atom::Nop; + m_pendingParagraphRightType = Atom::Nop; + + m_braceDepth = 0; + m_currentSection = Doc::NoSection; + m_openedCommands.push(CMD_OMIT); + m_quoter.reset(); + + CodeMarker *marker = nullptr; + Atom *currentLinkAtom = nullptr; + QString p1, p2; + QStack preprocessorSkipping; + int numPreprocessorSkipping = 0; + + while (m_position < m_inputLength) { + QChar ch = m_input.at(m_position); + + switch (ch.unicode()) { + case '\\': { + QString cmdStr; + m_backslashPosition = m_position; + ++m_position; + while (m_position < m_inputLength) { + ch = m_input.at(m_position); + if (ch.isLetterOrNumber()) { + cmdStr += ch; + ++m_position; + } else { + break; + } + } + m_endPosition = m_position; + if (cmdStr.isEmpty()) { + if (m_position < m_inputLength) { + enterPara(); + if (m_input.at(m_position).isSpace()) { + skipAllSpaces(); + appendChar(QLatin1Char(' ')); + } else { + appendChar(m_input.at(m_position++)); + } + } + } else { + // Ignore quoting atoms to make appendToCode() + // append to the correct atom. + if (!quoting || !isQuote(m_private->text.lastAtom())) + m_lastAtom = m_private->text.lastAtom(); + + int cmd = m_utilities.cmdHash.value(cmdStr, NOT_A_CMD); + switch (cmd) { + case CMD_A: + enterPara(); + p1 = getArgument(); + append(Atom::FormattingLeft, ATOM_FORMATTING_PARAMETER); + append(Atom::String, p1); + append(Atom::FormattingRight, ATOM_FORMATTING_PARAMETER); + m_private->params.insert(p1); + break; + case CMD_BADCODE: + leavePara(); + append(Atom::CodeBad, + getCode(CMD_BADCODE, marker, getMetaCommandArgument(cmdStr))); + break; + case CMD_BR: + enterPara(); + append(Atom::BR); + break; + case CMD_BOLD: + location().warning(QStringLiteral("'\\bold' is deprecated. Use '\\b'")); + Q_FALLTHROUGH(); + case CMD_B: + startFormat(ATOM_FORMATTING_BOLD, cmd); + break; + case CMD_BRIEF: + leavePara(); + enterPara(Atom::BriefLeft, Atom::BriefRight); + break; + case CMD_C: + enterPara(); + p1 = untabifyEtc(getArgument(true)); + marker = CodeMarker::markerForCode(p1); + append(Atom::C, marker->markedUpCode(p1, nullptr, location())); + break; + case CMD_CAPTION: + leavePara(); + enterPara(Atom::CaptionLeft, Atom::CaptionRight); + break; + case CMD_CODE: + leavePara(); + append(Atom::Code, getCode(CMD_CODE, nullptr, getMetaCommandArgument(cmdStr))); + break; + case CMD_QML: + leavePara(); + append(Atom::Qml, + getCode(CMD_QML, CodeMarker::markerForLanguage(QLatin1String("QML")), + getMetaCommandArgument(cmdStr))); + break; + case CMD_QMLTEXT: + append(Atom::QmlText); + break; + case CMD_JS: + leavePara(); + append(Atom::JavaScript, + getCode(CMD_JS, + CodeMarker::markerForLanguage(QLatin1String("JavaScript")), + getMetaCommandArgument(cmdStr))); + break; + case CMD_DIV: + leavePara(); + p1 = getArgument(true); + append(Atom::DivLeft, p1); + m_openedCommands.push(cmd); + break; + case CMD_ENDDIV: + leavePara(); + append(Atom::DivRight); + closeCommand(cmd); + break; + case CMD_CODELINE: + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, " "); + } + if (isCode(m_lastAtom) && m_lastAtom->string().endsWith("\n\n")) + m_lastAtom->chopString(); + appendToCode("\n"); + break; + case CMD_DOTS: { + QString arg = getOptionalArgument(); + if (arg.isEmpty()) + arg = "4"; + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, arg); + } + if (isCode(m_lastAtom) && m_lastAtom->string().endsWith("\n\n")) + m_lastAtom->chopString(); + + int indent = arg.toInt(); + for (int i = 0; i < indent; ++i) + appendToCode(" "); + appendToCode("...\n"); + break; + } + case CMD_ELSE: + if (preprocessorSkipping.size() > 0) { + if (preprocessorSkipping.top()) { + --numPreprocessorSkipping; + } else { + ++numPreprocessorSkipping; + } + preprocessorSkipping.top() = !preprocessorSkipping.top(); + (void)getRestOfLine(); // ### should ensure that it's empty + if (numPreprocessorSkipping) + skipToNextPreprocessorCommand(); + } else { + location().warning( + QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ELSE))); + } + break; + case CMD_ENDCODE: + closeCommand(cmd); + break; + case CMD_ENDQML: + closeCommand(cmd); + break; + case CMD_ENDQMLTEXT: + append(Atom::EndQmlText); + break; + case CMD_ENDJS: + closeCommand(cmd); + break; + case CMD_ENDFOOTNOTE: + if (closeCommand(cmd)) { + leavePara(); + append(Atom::FootnoteRight); + } + break; + case CMD_ENDIF: + if (preprocessorSkipping.count() > 0) { + if (preprocessorSkipping.pop()) + --numPreprocessorSkipping; + (void)getRestOfLine(); // ### should ensure that it's empty + if (numPreprocessorSkipping) + skipToNextPreprocessorCommand(); + } else { + location().warning( + QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ENDIF))); + } + break; + case CMD_ENDLEGALESE: + if (closeCommand(cmd)) { + leavePara(); + append(Atom::LegaleseRight); + } + break; + case CMD_ENDLINK: + if (closeCommand(cmd)) { + if (m_private->text.lastAtom()->type() == Atom::String + && m_private->text.lastAtom()->string().endsWith(QLatin1Char(' '))) + m_private->text.lastAtom()->chopString(); + append(Atom::FormattingRight, ATOM_FORMATTING_LINK); + } + break; + case CMD_ENDLIST: + if (closeCommand(cmd)) { + leavePara(); + if (m_openedLists.top().isStarted()) { + append(Atom::ListItemRight, m_openedLists.top().styleString()); + append(Atom::ListRight, m_openedLists.top().styleString()); + } + m_openedLists.pop(); + } + break; + case CMD_ENDOMIT: + closeCommand(cmd); + break; + case CMD_ENDQUOTATION: + if (closeCommand(cmd)) { + leavePara(); + append(Atom::QuotationRight); + } + break; + case CMD_ENDRAW: + location().warning( + QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_ENDRAW))); + break; + case CMD_ENDSECTION1: + endSection(Doc::Section1, cmd); + break; + case CMD_ENDSECTION2: + endSection(Doc::Section2, cmd); + break; + case CMD_ENDSECTION3: + endSection(Doc::Section3, cmd); + break; + case CMD_ENDSECTION4: + endSection(Doc::Section4, cmd); + break; + case CMD_ENDSIDEBAR: + if (closeCommand(cmd)) { + leavePara(); + append(Atom::SidebarRight); + } + break; + case CMD_ENDTABLE: + if (closeCommand(cmd)) { + leaveTableRow(); + append(Atom::TableRight); + } + break; + case CMD_FOOTNOTE: + if (openCommand(cmd)) { + enterPara(); + append(Atom::FootnoteLeft); + } + break; + case CMD_ANNOTATEDLIST: + append(Atom::AnnotatedList, getArgument()); + break; + case CMD_SINCELIST: + append(Atom::SinceList, getRestOfLine().simplified()); + break; + case CMD_GENERATELIST: { + QString arg1 = getArgument(); + QString arg2 = getOptionalArgument(); + if (!arg2.isEmpty()) + arg1 += " " + arg2; + append(Atom::GeneratedList, arg1); + } break; + case CMD_GRANULARITY: + m_private->constructExtra(); + m_private->extra->granularity_ = getSectioningUnit(); + break; + case CMD_HEADER: + if (m_openedCommands.top() == CMD_TABLE) { + leaveTableRow(); + append(Atom::TableHeaderLeft); + m_inTableHeader = true; + } else { + if (m_openedCommands.contains(CMD_TABLE)) + location().warning(QStringLiteral("Cannot use '\\%1' within '\\%2'") + .arg(cmdName(CMD_HEADER)) + .arg(cmdName(m_openedCommands.top()))); + else + location().warning(QStringLiteral("Cannot use '\\%1' outside of '\\%2'") + .arg(cmdName(CMD_HEADER)) + .arg(cmdName(CMD_TABLE))); + } + break; + case CMD_I: + location().warning(QStringLiteral( + "'\\i' is deprecated. Use '\\e' for italic or '\\li' for list item")); + Q_FALLTHROUGH(); + case CMD_E: + startFormat(ATOM_FORMATTING_ITALIC, cmd); + break; + case CMD_HR: + leavePara(); + append(Atom::HR); + break; + case CMD_IF: + preprocessorSkipping.push(!Tokenizer::isTrue(getRestOfLine())); + if (preprocessorSkipping.top()) + ++numPreprocessorSkipping; + if (numPreprocessorSkipping) + skipToNextPreprocessorCommand(); + break; + case CMD_IMAGE: + leaveValueList(); + append(Atom::Image, getArgument()); + append(Atom::ImageText, getRestOfLine()); + break; + case CMD_IMPORTANT: + leavePara(); + enterPara(Atom::ImportantLeft, Atom::ImportantRight); + break; + case CMD_INCLUDE: + case CMD_INPUT: { + QString fileName = getArgument(); + QString identifier = getRestOfLine(); + include(fileName, identifier); + break; + } + case CMD_INLINEIMAGE: + enterPara(); + append(Atom::InlineImage, getArgument()); + append(Atom::ImageText, getRestOfLine()); + append(Atom::String, " "); + break; + case CMD_INDEX: + if (m_paragraphState == OutsideParagraph) { + enterPara(); + m_indexStartedParagraph = true; + } else { + const Atom *last = m_private->text.lastAtom(); + if (m_indexStartedParagraph + && (last->type() != Atom::FormattingRight + || last->string() != ATOM_FORMATTING_INDEX)) + m_indexStartedParagraph = false; + } + startFormat(ATOM_FORMATTING_INDEX, cmd); + break; + case CMD_KEYWORD: + insertTarget(getRestOfLine(), true); + break; + case CMD_L: + enterPara(); + if (isLeftBracketAhead()) + p2 = getBracketedArgument(); + if (isLeftBraceAhead()) { + p1 = getArgument(); + append(p1, p2); + if (!p2.isEmpty() && !(m_private->text.lastAtom()->error().isEmpty())) + location().warning( + QStringLiteral( + "Check parameter in '[ ]' of '\\l' command: '%1', " + "possible misspelling, or unrecognized module name") + .arg(m_private->text.lastAtom()->error())); + if (isLeftBraceAhead()) { + currentLinkAtom = m_private->text.lastAtom(); + startFormat(ATOM_FORMATTING_LINK, cmd); + } else { + append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + append(Atom::String, cleanLink(p1)); + append(Atom::FormattingRight, ATOM_FORMATTING_LINK); + } + } else { + p1 = getArgument(); + append(p1, p2); + if (!p2.isEmpty() && !(m_private->text.lastAtom()->error().isEmpty())) + location().warning( + QStringLiteral( + "Check parameter in '[ ]' of '\\l' command: '%1', " + "possible misspelling, or unrecognized module name") + .arg(m_private->text.lastAtom()->error())); + append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + append(Atom::String, cleanLink(p1)); + append(Atom::FormattingRight, ATOM_FORMATTING_LINK); + } + p2.clear(); + break; + case CMD_LEGALESE: + leavePara(); + if (openCommand(cmd)) + append(Atom::LegaleseLeft); + docPrivate->hasLegalese = true; + break; + case CMD_LINK: + if (openCommand(cmd)) { + enterPara(); + p1 = getArgument(); + append(p1); + append(Atom::FormattingLeft, ATOM_FORMATTING_LINK); + skipSpacesOrOneEndl(); + } + break; + case CMD_LIST: + if (openCommand(cmd)) { + leavePara(); + m_openedLists.push(OpenedList(location(), getOptionalArgument())); + } + break; + case CMD_META: + m_private->constructExtra(); + p1 = getArgument(); + m_private->extra->metaMap_.insert(p1, getArgument()); + break; + case CMD_NEWCODE: + location().warning( + QStringLiteral("Unexpected '\\%1'").arg(cmdName(CMD_NEWCODE))); + break; + case CMD_NOTE: + leavePara(); + enterPara(Atom::NoteLeft, Atom::NoteRight); + break; + case CMD_O: + location().warning(QStringLiteral("'\\o' is deprecated. Use '\\li'")); + Q_FALLTHROUGH(); + case CMD_LI: + leavePara(); + if (m_openedCommands.top() == CMD_LIST) { + if (m_openedLists.top().isStarted()) + append(Atom::ListItemRight, m_openedLists.top().styleString()); + else + append(Atom::ListLeft, m_openedLists.top().styleString()); + m_openedLists.top().next(); + append(Atom::ListItemNumber, m_openedLists.top().numberString()); + append(Atom::ListItemLeft, m_openedLists.top().styleString()); + enterPara(); + } else if (m_openedCommands.top() == CMD_TABLE) { + p1 = "1,1"; + p2.clear(); + if (isLeftBraceAhead()) { + p1 = getArgument(); + if (isLeftBraceAhead()) + p2 = getArgument(); + } + + if (!m_inTableHeader && !m_inTableRow) { + location().warning( + QStringLiteral("Missing '\\%1' or '\\%2' before '\\%3'") + .arg(cmdName(CMD_HEADER)) + .arg(cmdName(CMD_ROW)) + .arg(cmdName(CMD_LI))); + append(Atom::TableRowLeft); + m_inTableRow = true; + } else if (m_inTableItem) { + append(Atom::TableItemRight); + m_inTableItem = false; + } + + append(Atom::TableItemLeft, p1, p2); + m_inTableItem = true; + } else + location().warning( + QStringLiteral("Command '\\%1' outside of '\\%2' and '\\%3'") + .arg(cmdName(cmd)) + .arg(cmdName(CMD_LIST)) + .arg(cmdName(CMD_TABLE))); + break; + case CMD_OLDCODE: + leavePara(); + append(Atom::CodeOld, getCode(CMD_OLDCODE, marker)); + append(Atom::CodeNew, getCode(CMD_NEWCODE, marker)); + break; + case CMD_OMIT: + getUntilEnd(cmd); + break; + case CMD_OMITVALUE: + p1 = getArgument(); + if (!m_private->enumItemList.contains(p1)) + m_private->enumItemList.append(p1); + if (!m_private->omitEnumItemList.contains(p1)) + m_private->omitEnumItemList.append(p1); + skipSpacesOrOneEndl(); + getRestOfLine(); + break; + case CMD_PRINTLINE: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + appendToCode(m_quoter.quoteLine(location(), cmdStr, rest)); + break; + } + case CMD_PRINTTO: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + appendToCode(m_quoter.quoteTo(location(), cmdStr, rest)); + break; + } + case CMD_PRINTUNTIL: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + appendToCode(m_quoter.quoteUntil(location(), cmdStr, rest)); + break; + } + case CMD_QUOTATION: + if (openCommand(cmd)) { + leavePara(); + append(Atom::QuotationLeft); + } + break; + case CMD_QUOTEFILE: { + leavePara(); + QString fileName = getArgument(); + Doc::quoteFromFile(location(), m_quoter, fileName); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, fileName); + } + append(Atom::Code, m_quoter.quoteTo(location(), cmdStr, QString())); + m_quoter.reset(); + break; + } + case CMD_QUOTEFROMFILE: { + leavePara(); + QString arg = getArgument(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, arg); + } + Doc::quoteFromFile(location(), m_quoter, arg); + break; + } + case CMD_QUOTEFUNCTION: { + leavePara(); + marker = quoteFromFile(); + p1 = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, slashed(marker->functionEndRegExp(p1))); + } + m_quoter.quoteTo(location(), cmdStr, slashed(marker->functionBeginRegExp(p1))); + append(Atom::Code, + m_quoter.quoteUntil(location(), cmdStr, + slashed(marker->functionEndRegExp(p1)))); + m_quoter.reset(); + break; + } + case CMD_RAW: + leavePara(); + p1 = getRestOfLine(); + if (p1.isEmpty()) + location().warning(QStringLiteral("Missing format name after '\\%1'") + .arg(cmdName(CMD_RAW))); + append(Atom::FormatIf, p1); + append(Atom::RawString, untabifyEtc(getUntilEnd(cmd))); + append(Atom::FormatElse); + append(Atom::FormatEndif); + break; + case CMD_ROW: + if (m_openedCommands.top() == CMD_TABLE) { + p1.clear(); + if (isLeftBraceAhead()) + p1 = getArgument(true); + leaveTableRow(); + append(Atom::TableRowLeft, p1); + m_inTableRow = true; + } else { + if (m_openedCommands.contains(CMD_TABLE)) + location().warning(QStringLiteral("Cannot use '\\%1' within '\\%2'") + .arg(cmdName(CMD_ROW)) + .arg(cmdName(m_openedCommands.top()))); + else + location().warning(QStringLiteral("Cannot use '\\%1' outside of '\\%2'") + .arg(cmdName(CMD_ROW)) + .arg(cmdName(CMD_TABLE))); + } + break; + case CMD_SA: + parseAlso(); + break; + case CMD_SECTION1: + startSection(Doc::Section1, cmd); + break; + case CMD_SECTION2: + startSection(Doc::Section2, cmd); + break; + case CMD_SECTION3: + startSection(Doc::Section3, cmd); + break; + case CMD_SECTION4: + startSection(Doc::Section4, cmd); + break; + case CMD_SIDEBAR: + if (openCommand(cmd)) { + leavePara(); + append(Atom::SidebarLeft); + } + break; + case CMD_SKIPLINE: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + m_quoter.quoteLine(location(), cmdStr, rest); + break; + } + case CMD_SKIPTO: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + m_quoter.quoteTo(location(), cmdStr, rest); + break; + } + case CMD_SKIPUNTIL: { + leavePara(); + QString rest = getRestOfLine(); + if (quoting) { + append(Atom::CodeQuoteCommand, cmdStr); + append(Atom::CodeQuoteArgument, rest); + } + m_quoter.quoteUntil(location(), cmdStr, rest); + break; + } + case CMD_SPAN: + p1 = ATOM_FORMATTING_SPAN + getArgument(true); + startFormat(p1, cmd); + break; + case CMD_SNIPPET: { + leavePara(); + QString snippet = getArgument(); + QString identifier = getRestOfLine(); + if (quoting) { + append(Atom::SnippetCommand, cmdStr); + append(Atom::SnippetLocation, snippet); + append(Atom::SnippetIdentifier, identifier); + } + marker = Doc::quoteFromFile(location(), m_quoter, snippet); + appendToCode(m_quoter.quoteSnippet(location(), identifier), marker->atomType()); + break; + } + case CMD_SUB: + startFormat(ATOM_FORMATTING_SUBSCRIPT, cmd); + break; + case CMD_SUP: + startFormat(ATOM_FORMATTING_SUPERSCRIPT, cmd); + break; + case CMD_TABLE: + p1 = getOptionalArgument(); + p2 = getOptionalArgument(); + if (openCommand(cmd)) { + leavePara(); + append(Atom::TableLeft, p1, p2); + m_inTableHeader = false; + m_inTableRow = false; + m_inTableItem = false; + } + break; + case CMD_TABLEOFCONTENTS: + p1 = "1"; + if (isLeftBraceAhead()) + p1 = getArgument(); + p1 += QLatin1Char(','); + p1 += QString::number((int)getSectioningUnit()); + append(Atom::TableOfContents, p1); + break; + case CMD_TARGET: + insertTarget(getRestOfLine(), false); + break; + case CMD_TT: + startFormat(ATOM_FORMATTING_TELETYPE, cmd); + break; + case CMD_UICONTROL: + startFormat(ATOM_FORMATTING_UICONTROL, cmd); + break; + case CMD_UNDERLINE: + startFormat(ATOM_FORMATTING_UNDERLINE, cmd); + break; + case CMD_UNICODE: { + enterPara(); + p1 = getArgument(); + bool ok; + uint unicodeChar = p1.toUInt(&ok, 0); + if (!ok || (unicodeChar == 0x0000) || (unicodeChar > 0xFFFE)) + location().warning( + QStringLiteral("Invalid Unicode character '%1' specified with '%2'") + .arg(p1, cmdName(CMD_UNICODE))); + else + append(Atom::String, QChar(unicodeChar)); + break; + } + case CMD_VALUE: + leaveValue(); + if (m_openedLists.top().style() == OpenedList::Value) { + QString p2; + p1 = getArgument(); + if (p1.startsWith(QLatin1String("[since ")) + && p1.endsWith(QLatin1String("]"))) { + p2 = p1.mid(7, p1.length() - 8); + p1 = getArgument(); + } + if (!m_private->enumItemList.contains(p1)) + m_private->enumItemList.append(p1); + + m_openedLists.top().next(); + append(Atom::ListTagLeft, ATOM_LIST_VALUE); + append(Atom::String, p1); + append(Atom::ListTagRight, ATOM_LIST_VALUE); + if (!p2.isEmpty()) { + append(Atom::SinceTagLeft, ATOM_LIST_VALUE); + append(Atom::String, p2); + append(Atom::SinceTagRight, ATOM_LIST_VALUE); + } + append(Atom::ListItemLeft, ATOM_LIST_VALUE); + + skipSpacesOrOneEndl(); + if (isBlankLine()) + append(Atom::Nop); + } else { + // ### unknown problems + } + break; + case CMD_WARNING: + leavePara(); + enterPara(); + append(Atom::FormattingLeft, ATOM_FORMATTING_BOLD); + append(Atom::String, "Warning:"); + append(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + append(Atom::String, " "); + break; + case CMD_OVERLOAD: + m_private->metacommandsUsed.insert(cmdStr); + p1.clear(); + if (!isBlankLine()) + p1 = getRestOfLine(); + if (!p1.isEmpty()) { + append(Atom::ParaLeft); + append(Atom::String, "This function overloads "); + append(Atom::AutoLink, p1); + append(Atom::String, "."); + append(Atom::ParaRight); + } else { + append(Atom::ParaLeft); + append(Atom::String, "This is an overloaded function."); + append(Atom::ParaRight); + p1 = getMetaCommandArgument(cmdStr); + } + m_private->metaCommandMap[cmdStr].append(ArgLocPair(p1, location())); + break; + case NOT_A_CMD: + if (metaCommandSet.contains(cmdStr)) { + m_private->metacommandsUsed.insert(cmdStr); + // Force a linebreak after \obsolete or \deprecated + // to treat potential arguments as a new text paragraph. + if (m_position < m_inputLength + && (cmdStr == QLatin1String("obsolete") + || cmdStr == QLatin1String("deprecated"))) + m_input[m_position] = '\n'; + QString arg = getMetaCommandArgument(cmdStr); + m_private->metaCommandMap[cmdStr].append(ArgLocPair(arg, location())); + if (possibleTopics.contains(cmdStr)) { + if (!cmdStr.endsWith(QLatin1String("propertygroup"))) + m_private->topics_.append(Topic(cmdStr, arg)); + } + } else if (m_utilities.macroHash.contains(cmdStr)) { + const Macro ¯o = m_utilities.macroHash.value(cmdStr); + int numPendingFi = 0; + int numFormatDefs = 0; + QString matchExpr; + for (auto it = macro.otherDefs.constBegin(); + it != macro.otherDefs.constEnd(); ++it) { + if (it.key() == "match") { + matchExpr = it.value(); + } else { + append(Atom::FormatIf, it.key()); + expandMacro(cmdStr, *it, macro.numParams); + ++numFormatDefs; + if (it == macro.otherDefs.constEnd()) { + append(Atom::FormatEndif); + } else { + append(Atom::FormatElse); + ++numPendingFi; + } + } + } + while (numPendingFi-- > 0) + append(Atom::FormatEndif); + + if (!macro.defaultDef.isEmpty()) { + if (numFormatDefs > 0) { + macro.defaultDefLocation.warning( + QStringLiteral("Macro cannot have both " + "format-specific and qdoc-" + "syntax definitions")); + } else { + QString expanded = expandMacroToString(cmdStr, macro.defaultDef, + macro.numParams, matchExpr); + m_input.replace(m_backslashPosition, + m_endPosition - m_backslashPosition, expanded); + m_inputLength = m_input.length(); + m_position = m_backslashPosition; + } + } + } else if (isAutoLinkString(cmdStr)) { + appendWord(cmdStr); + } else { + if (!cmdStr.endsWith("propertygroup")) { + // The QML and JS property group commands are no longer required + // for grouping QML and JS properties. They are allowed but ignored. + location().warning(QStringLiteral("Unknown command '\\%1'").arg(cmdStr), + detailsUnknownCommand(metaCommandSet, cmdStr)); + } + enterPara(); + append(Atom::UnknownCommand, cmdStr); + } + } + } // case '\\' (qdoc markup command) + break; + } + case '{': + enterPara(); + appendChar('{'); + ++m_braceDepth; + ++m_position; + break; + case '}': { + --m_braceDepth; + ++m_position; + + auto format = m_pendingFormats.find(m_braceDepth); + if (format == m_pendingFormats.end()) { + enterPara(); + appendChar('}'); + } else { + append(Atom::FormattingRight, *format); + if (*format == ATOM_FORMATTING_INDEX) { + if (m_indexStartedParagraph) + skipAllSpaces(); + } else if (*format == ATOM_FORMATTING_LINK) { + // hack for C++ to support links like + // \l{QString::}{count()} + if (currentLinkAtom && currentLinkAtom->string().endsWith("::")) { + QString suffix = Text::subText(currentLinkAtom, m_private->text.lastAtom()) + .toString(); + currentLinkAtom->appendString(suffix); + } + currentLinkAtom = nullptr; + } + m_pendingFormats.erase(format); + } + break; + } + // Do not parse content after '//!' comments + case '/': { + if (m_position + 2 < m_inputLength) + if (m_input.at(m_position + 1) == '/') + if (m_input.at(m_position + 2) == '!') { + m_position += 2; + getRestOfLine(); + break; + } + Q_FALLTHROUGH(); // fall through + } + default: { + bool newWord; + switch (m_private->text.lastAtom()->type()) { + case Atom::ParaLeft: + newWord = true; + break; + default: + newWord = false; + } + + if (m_paragraphState == OutsideParagraph) { + if (ch.isSpace()) { + ++m_position; + newWord = false; + } else { + enterPara(); + newWord = true; + } + } else { + if (ch.isSpace()) { + ++m_position; + if ((ch == '\n') + && (m_paragraphState == InSingleLineParagraph || isBlankLine())) { + leavePara(); + newWord = false; + } else { + appendChar(' '); + newWord = true; + } + } else { + newWord = true; + } + } + + if (newWord) { + int startPos = m_position; + bool autolink = isAutoLinkString(m_input, m_position); + if (m_position == startPos) { + if (!ch.isSpace()) { + appendChar(ch); + ++m_position; + } + } else { + QString word = m_input.mid(startPos, m_position - startPos); + if (autolink) { + if (ignoreWords.contains(word) || word.startsWith(QString("__"))) + appendWord(word); + else + append(Atom::AutoLink, word); + } else { + appendWord(word); + } + } + } + } // default: + } // switch (ch.unicode()) + } + leaveValueList(); + + // for compatibility + if (m_openedCommands.top() == CMD_LEGALESE) { + append(Atom::LegaleseRight); + m_openedCommands.pop(); + } + + if (m_openedCommands.top() != CMD_OMIT) { + location().warning( + QStringLiteral("Missing '\\%1'").arg(endCmdName(m_openedCommands.top()))); + } else if (preprocessorSkipping.count() > 0) { + location().warning(QStringLiteral("Missing '\\%1'").arg(cmdName(CMD_ENDIF))); + } + + if (m_currentSection > Doc::NoSection) { + append(Atom::SectionRight, QString::number(m_currentSection)); + m_currentSection = Doc::NoSection; + } + + if (m_private->extra && m_private->extra->granularity_ < m_private->extra->section_) + m_private->extra->granularity_ = m_private->extra->section_; + m_private->text.stripFirstAtom(); +} + +/*! + Returns the current location. + */ +Location &DocParser::location() +{ + while (!m_openedInputs.isEmpty() && m_openedInputs.top() <= m_position) { + m_cachedLocation.pop(); + m_cachedPosition = m_openedInputs.pop(); + } + while (m_cachedPosition < m_position) + m_cachedLocation.advance(m_input.at(m_cachedPosition++)); + return m_cachedLocation; +} + +QString DocParser::detailsUnknownCommand(const QSet &metaCommandSet, const QString &str) +{ + QSet commandSet = metaCommandSet; + int i = 0; + while (cmds[i].english != nullptr) { + commandSet.insert(*cmds[i].alias); + ++i; + } + + if (m_utilities.aliasMap.contains(str)) + return QStringLiteral("The command '\\%1' was renamed '\\%2' by the configuration" + " file. Use the new name.") + .arg(str) + .arg(m_utilities.aliasMap[str]); + + QString best = nearestName(str, commandSet); + if (best.isEmpty()) + return QString(); + return QStringLiteral("Maybe you meant '\\%1'?").arg(best); +} + +void DocParser::insertTarget(const QString &target, bool keyword) +{ + if (m_targetMap.contains(target)) { + location().warning(QStringLiteral("Duplicate target name '%1'").arg(target)); + m_targetMap[target].warning(QStringLiteral("(The previous occurrence is here)")); + } else { + m_targetMap.insert(target, location()); + m_private->constructExtra(); + if (keyword) { + append(Atom::Keyword, target); + m_private->extra->keywords_.append(m_private->text.lastAtom()); + } else { + append(Atom::Target, target); + m_private->extra->targets_.append(m_private->text.lastAtom()); + } + } +} + +void DocParser::include(const QString &fileName, const QString &identifier) +{ + if (location().depth() > 16) + location().fatal(QStringLiteral("Too many nested '\\%1's").arg(cmdName(CMD_INCLUDE))); + QString filePath = Config::instance().getIncludeFilePath(fileName); + if (filePath.isEmpty()) { + location().warning(QStringLiteral("Cannot find qdoc include file '%1'").arg(fileName)); + } else { + QFile inFile(filePath); + if (!inFile.open(QFile::ReadOnly)) { + location().warning( + QStringLiteral("Cannot open qdoc include file '%1'").arg(filePath)); + } else { + location().push(fileName); + QTextStream inStream(&inFile); + QString includedStuff = inStream.readAll(); + inFile.close(); + + if (identifier.isEmpty()) { + m_input.insert(m_position, includedStuff); + m_inputLength = m_input.length(); + m_openedInputs.push(m_position + includedStuff.length()); + } else { + QStringList lineBuffer = includedStuff.split(QLatin1Char('\n')); + int i = 0; + int startLine = -1; + while (i < lineBuffer.size()) { + if (lineBuffer[i].startsWith("//!")) { + if (lineBuffer[i].contains(identifier)) { + startLine = i + 1; + break; + } + } + ++i; + } + if (startLine < 0) { + location().warning(QStringLiteral("Cannot find '%1' in '%2'") + .arg(identifier) + .arg(filePath)); + return; + } + QString result; + i = startLine; + do { + if (lineBuffer[i].startsWith("//!")) { + if (i < lineBuffer.size()) { + if (lineBuffer[i].contains(identifier)) { + break; + } + } + } else + result += lineBuffer[i] + QLatin1Char('\n'); + ++i; + } while (i < lineBuffer.size()); + if (result.isEmpty()) { + location().warning(QStringLiteral("Empty qdoc snippet '%1' in '%2'") + .arg(identifier) + .arg(filePath)); + } else { + m_input.insert(m_position, result); + m_inputLength = m_input.length(); + m_openedInputs.push(m_position + result.length()); + } + } + } + } +} + +void DocParser::startFormat(const QString &format, int cmd) +{ + enterPara(); + + for (const auto &item : qAsConst(m_pendingFormats)) { + if (item == format) { + location().warning(QStringLiteral("Cannot nest '\\%1' commands").arg(cmdName(cmd))); + return; + } + } + + append(Atom::FormattingLeft, format); + + if (isLeftBraceAhead()) { + skipSpacesOrOneEndl(); + m_pendingFormats.insert(m_braceDepth, format); + ++m_braceDepth; + ++m_position; + } else { + append(Atom::String, getArgument()); + append(Atom::FormattingRight, format); + if (format == ATOM_FORMATTING_INDEX && m_indexStartedParagraph) { + skipAllSpaces(); + m_indexStartedParagraph = false; + } + } +} + +bool DocParser::openCommand(int cmd) +{ + int outer = m_openedCommands.top(); + bool ok = true; + + if (cmd != CMD_LINK) { + if (outer == CMD_LIST) { + ok = (cmd == CMD_FOOTNOTE || cmd == CMD_LIST); + } else if (outer == CMD_SIDEBAR) { + ok = (cmd == CMD_LIST || cmd == CMD_QUOTATION || cmd == CMD_SIDEBAR); + } else if (outer == CMD_QUOTATION) { + ok = (cmd == CMD_LIST); + } else if (outer == CMD_TABLE) { + ok = (cmd == CMD_LIST || cmd == CMD_FOOTNOTE || cmd == CMD_QUOTATION); + } else if (outer == CMD_FOOTNOTE || outer == CMD_LINK) { + ok = false; + } + } + + if (ok) { + m_openedCommands.push(cmd); + } else { + location().warning( + QStringLiteral("Can't use '\\%1' in '\\%2'").arg(cmdName(cmd)).arg(cmdName(outer))); + } + return ok; +} + +/*! + Returns \c true if \a word qualifies for auto-linking. +*/ +inline bool DocParser::isAutoLinkString(const QString &word) +{ + int start = 0; + return isAutoLinkString(word, start); +} + +bool DocParser::isAutoLinkString(const QString &word, int &curPos) +{ + int len = word.size(); + int startPos = curPos; + int numUppercase = 0; + int numLowercase = 0; + int numStrangeSymbols = 0; + + while (curPos < len) { + unsigned char latin1Ch = word.at(curPos).toLatin1(); + if (islower(latin1Ch)) { + ++numLowercase; + ++curPos; + } else if (isupper(latin1Ch)) { + if (curPos > startPos) + ++numUppercase; + ++curPos; + } else if (isdigit(latin1Ch)) { + if (curPos > startPos) + ++curPos; + else + break; + } else if (latin1Ch == '_' || latin1Ch == '@') { + ++numStrangeSymbols; + ++curPos; + } else if ((latin1Ch == ':') && (curPos < len - 1) + && (word.at(curPos + 1) == QLatin1Char(':'))) { + ++numStrangeSymbols; + curPos += 2; + } else if (latin1Ch == '(') { + if (curPos > startPos) { + if ((curPos < len - 1) && (word.at(curPos + 1) == QLatin1Char(')'))) { + ++numStrangeSymbols; + m_position += 2; + break; + } else { + break; + } + } else { + break; + } + } else { + break; + } + } + return ((numUppercase >= 1 && numLowercase >= 2) || numStrangeSymbols > 0); +} + +bool DocParser::closeCommand(int endCmd) +{ + if (endCmdFor(m_openedCommands.top()) == endCmd && m_openedCommands.size() > 1) { + m_openedCommands.pop(); + return true; + } else { + bool contains = false; + QStack opened2 = m_openedCommands; + while (opened2.size() > 1) { + if (endCmdFor(opened2.top()) == endCmd) { + contains = true; + break; + } + opened2.pop(); + } + + if (contains) { + while (endCmdFor(m_openedCommands.top()) != endCmd && m_openedCommands.size() > 1) { + location().warning(QStringLiteral("Missing '\\%1' before '\\%2'") + .arg(endCmdName(m_openedCommands.top())) + .arg(cmdName(endCmd))); + m_openedCommands.pop(); + } + } else { + location().warning(QStringLiteral("Unexpected '\\%1'").arg(cmdName(endCmd))); + } + return false; + } +} + +void DocParser::startSection(Doc::Sections unit, int cmd) +{ + leaveValueList(); + + if (m_currentSection == Doc::NoSection) { + m_currentSection = (Doc::Sections)(unit); + m_private->constructExtra(); + m_private->extra->section_ = m_currentSection; + } else + endSection(unit, cmd); + + append(Atom::SectionLeft, QString::number(unit)); + m_private->constructExtra(); + m_private->extra->tableOfContents_.append(m_private->text.lastAtom()); + m_private->extra->tableOfContentsLevels_.append(unit); + enterPara(Atom::SectionHeadingLeft, Atom::SectionHeadingRight, QString::number(unit)); + m_currentSection = unit; +} + +void DocParser::endSection(int, int) // (int unit, int endCmd) +{ + leavePara(); + append(Atom::SectionRight, QString::number(m_currentSection)); + m_currentSection = (Doc::NoSection); +} + +void DocParser::parseAlso() +{ + leavePara(); + skipSpacesOnLine(); + while (m_position < m_inputLength && m_input[m_position] != '\n') { + QString target; + QString str; + bool skipMe = false; + + if (m_input[m_position] == '{') { + target = getArgument(); + skipSpacesOnLine(); + if (m_position < m_inputLength && m_input[m_position] == '{') { + str = getArgument(); + + // hack for C++ to support links like \l{QString::}{count()} + if (target.endsWith("::")) + target += str; + } else { + str = target; + } + } else { + target = getArgument(); + str = cleanLink(target); + if (target == QLatin1String("and") || target == QLatin1String(".")) + skipMe = true; + } + + if (!skipMe) { + Text also; + also << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << str << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + m_private->addAlso(also); + } + + skipSpacesOnLine(); + if (m_position < m_inputLength && m_input[m_position] == ',') { + m_position++; + skipSpacesOrOneEndl(); + } else if (m_position >= m_inputLength || m_input[m_position] != '\n') { + location().warning(QStringLiteral("Missing comma in '\\%1'").arg(cmdName(CMD_SA))); + } + } +} + +void DocParser::append(Atom::AtomType type, const QString &string) +{ + Atom::AtomType lastType = m_private->text.lastAtom()->type(); + if ((lastType == Atom::Code) + && m_private->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) + m_private->text.lastAtom()->chopString(); + m_private->text << Atom(type, string); +} + +void DocParser::append(const QString &string) +{ + Atom::AtomType lastType = m_private->text.lastAtom()->type(); + if ((lastType == Atom::Code) + && m_private->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) + m_private->text.lastAtom()->chopString(); + m_private->text << Atom(Atom::Link, string); +} + +void DocParser::append(Atom::AtomType type, const QString &p1, const QString &p2) +{ + Atom::AtomType lastType = m_private->text.lastAtom()->type(); + if ((lastType == Atom::Code) + && m_private->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) + m_private->text.lastAtom()->chopString(); + m_private->text << Atom(type, p1, p2); +} + +void DocParser::append(const QString &p1, const QString &p2) +{ + Atom::AtomType lastType = m_private->text.lastAtom()->type(); + if ((lastType == Atom::Code) + && m_private->text.lastAtom()->string().endsWith(QLatin1String("\n\n"))) + m_private->text.lastAtom()->chopString(); + if (p2.isEmpty()) + m_private->text << Atom(Atom::Link, p1); + else + m_private->text << LinkAtom(p1, p2); +} + +void DocParser::appendChar(QChar ch) +{ + if (m_private->text.lastAtom()->type() != Atom::String) + append(Atom::String); + Atom *atom = m_private->text.lastAtom(); + if (ch == QLatin1Char(' ')) { + if (!atom->string().endsWith(QLatin1Char(' '))) + atom->appendChar(QLatin1Char(' ')); + } else + atom->appendChar(ch); +} + +void DocParser::appendWord(const QString &word) +{ + if (m_private->text.lastAtom()->type() != Atom::String) { + append(Atom::String, word); + } else + m_private->text.lastAtom()->appendString(word); +} + +void DocParser::appendToCode(const QString &markedCode) +{ + if (!isCode(m_lastAtom)) { + append(Atom::Code); + m_lastAtom = m_private->text.lastAtom(); + } + m_lastAtom->appendString(markedCode); +} + +void DocParser::appendToCode(const QString &markedCode, Atom::AtomType defaultType) +{ + if (!isCode(m_lastAtom)) { + append(defaultType, markedCode); + m_lastAtom = m_private->text.lastAtom(); + } else { + m_lastAtom->appendString(markedCode); + } +} + +void DocParser::enterPara(Atom::AtomType leftType, Atom::AtomType rightType, const QString &string) +{ + if (m_paragraphState == OutsideParagraph) { + + if ((m_private->text.lastAtom()->type() != Atom::ListItemLeft) + && (m_private->text.lastAtom()->type() != Atom::DivLeft)) { + leaveValueList(); + } + + append(leftType, string); + m_indexStartedParagraph = false; + m_pendingParagraphLeftType = leftType; + m_pendingParagraphRightType = rightType; + m_pendingParagraphString = string; + if (leftType == Atom::SectionHeadingLeft) { + m_paragraphState = InSingleLineParagraph; + } else { + m_paragraphState = InMultiLineParagraph; + } + skipSpacesOrOneEndl(); + } +} + +void DocParser::leavePara() +{ + if (m_paragraphState != OutsideParagraph) { + if (!m_pendingFormats.isEmpty()) { + location().warning(QStringLiteral("Missing '}'")); + m_pendingFormats.clear(); + } + + if (m_private->text.lastAtom()->type() == m_pendingParagraphLeftType) { + m_private->text.stripLastAtom(); + } else { + if (m_private->text.lastAtom()->type() == Atom::String + && m_private->text.lastAtom()->string().endsWith(QLatin1Char(' '))) { + m_private->text.lastAtom()->chopString(); + } + append(m_pendingParagraphRightType, m_pendingParagraphString); + } + m_paragraphState = OutsideParagraph; + m_indexStartedParagraph = false; + m_pendingParagraphRightType = Atom::Nop; + m_pendingParagraphString.clear(); + } +} + +void DocParser::leaveValue() +{ + leavePara(); + if (m_openedLists.isEmpty()) { + m_openedLists.push(OpenedList(OpenedList::Value)); + append(Atom::ListLeft, ATOM_LIST_VALUE); + } else { + if (m_private->text.lastAtom()->type() == Atom::Nop) + m_private->text.stripLastAtom(); + append(Atom::ListItemRight, ATOM_LIST_VALUE); + } +} + +void DocParser::leaveValueList() +{ + leavePara(); + if (!m_openedLists.isEmpty() && (m_openedLists.top().style() == OpenedList::Value)) { + if (m_private->text.lastAtom()->type() == Atom::Nop) + m_private->text.stripLastAtom(); + append(Atom::ListItemRight, ATOM_LIST_VALUE); + append(Atom::ListRight, ATOM_LIST_VALUE); + m_openedLists.pop(); + } +} + +void DocParser::leaveTableRow() +{ + if (m_inTableItem) { + leavePara(); + append(Atom::TableItemRight); + m_inTableItem = false; + } + if (m_inTableHeader) { + append(Atom::TableHeaderRight); + m_inTableHeader = false; + } + if (m_inTableRow) { + append(Atom::TableRowRight); + m_inTableRow = false; + } +} + +CodeMarker *DocParser::quoteFromFile() +{ + return Doc::quoteFromFile(location(), m_quoter, getArgument()); +} + +/*! + Expands a macro in-place in input. + + Expects the current \e pos in the input to point to a backslash, and the macro to have a + default definition. Format-specific macros are currently not expanded. + + \note In addition to macros, a valid use for a backslash in an argument include + escaping non-alnum characters, and splitting a single argument across multiple + lines by escaping newlines. Escaping is also handled here. + + Returns \c true on successful macro expansion. + */ +bool DocParser::expandMacro() +{ + Q_ASSERT(m_input[m_position].unicode() == '\\'); + + QString cmdStr; + int backslashPos = m_position++; + while (m_position < m_input.length() && m_input[m_position].isLetterOrNumber()) + cmdStr += m_input[m_position++]; + + m_endPosition = m_position; + if (!cmdStr.isEmpty()) { + if (m_utilities.macroHash.contains(cmdStr)) { + const Macro ¯o = m_utilities.macroHash.value(cmdStr); + if (!macro.defaultDef.isEmpty()) { + QString expanded = expandMacroToString(cmdStr, macro.defaultDef, macro.numParams, + macro.otherDefs.value("match")); + m_input.replace(backslashPos, m_position - backslashPos, expanded); + m_inputLength = m_input.length(); + m_position = backslashPos; + return true; + } else { + location().warning(QStringLiteral("Macro '%1' does not have a default definition") + .arg(cmdStr)); + } + } else { + location().warning(QStringLiteral("Unknown macro '%1'").arg(cmdStr)); + m_position = ++backslashPos; + } + } else if (m_input[m_position].isSpace()) { + skipAllSpaces(); + } else if (m_input[m_position].unicode() == '\\') { + // allow escaping a backslash + m_input.remove(m_position--, 1); + --m_inputLength; + } + return false; +} + +void DocParser::expandMacro(const QString &name, const QString &def, int numParams) +{ + if (numParams == 0) { + append(Atom::RawString, def); + } else { + QStringList args; + QString rawString; + + for (int i = 0; i < numParams; ++i) { + if (numParams == 1 || isLeftBraceAhead()) { + args << getArgument(); + } else { + location().warning(QStringLiteral("Macro '\\%1' invoked with too few" + " arguments (expected %2, got %3)") + .arg(name) + .arg(numParams) + .arg(i)); + numParams = i; + break; + } + } + + int j = 0; + while (j < def.size()) { + int paramNo; + if (((paramNo = def[j].unicode()) >= 1) && (paramNo <= numParams)) { + if (!rawString.isEmpty()) { + append(Atom::RawString, rawString); + rawString.clear(); + } + append(Atom::String, args[paramNo - 1]); + j += 1; + } else { + rawString += def[j++]; + } + } + if (!rawString.isEmpty()) + append(Atom::RawString, rawString); + } +} + +QString DocParser::expandMacroToString(const QString &name, const QString &def, int numParams, + const QString &matchExpr) +{ + QString rawString; + + if (numParams == 0) { + rawString = def; + } else { + QStringList args; + for (int i = 0; i < numParams; ++i) { + if (numParams == 1 || isLeftBraceAhead()) { + args << getArgument(true); + } else { + location().warning(QStringLiteral("Macro '\\%1' invoked with too few" + " arguments (expected %2, got %3)") + .arg(name) + .arg(numParams) + .arg(i)); + numParams = i; + break; + } + } + + int j = 0; + while (j < def.size()) { + int paramNo; + if (((paramNo = def[j].unicode()) >= 1) && (paramNo <= numParams)) { + rawString += args[paramNo - 1]; + j += 1; + } else { + rawString += def[j++]; + } + } + } + if (matchExpr.isEmpty()) + return rawString; + + QString result; + QRegularExpression re(matchExpr); + int capStart = (re.captureCount() > 0) ? 1 : 0; + int i = 0; + QRegularExpressionMatch match; + while ((match = re.match(rawString, i)).hasMatch()) { + for (int c = capStart; c <= re.captureCount(); ++c) + result += match.captured(c); + i = match.capturedEnd(); + } + + return result; +} + +Doc::Sections DocParser::getSectioningUnit() +{ + QString name = getOptionalArgument(); + + if (name == "section1") { + return Doc::Section1; + } else if (name == "section2") { + return Doc::Section2; + } else if (name == "section3") { + return Doc::Section3; + } else if (name == "section4") { + return Doc::Section4; + } else if (name.isEmpty()) { + return Doc::NoSection; + } else { + location().warning(QStringLiteral("Invalid section '%1'").arg(name)); + return Doc::NoSection; + } +} + +/*! + Gets an argument that is enclosed in braces and returns it + without the enclosing braces. On entry, the current character + is the left brace. On exit, the current character is the one + that comes after the right brace. + + If \a verbatim is true, extra whitespace is retained in the + returned string. Otherwise, extra whitespace is removed. + */ +QString DocParser::getBracedArgument(bool verbatim) +{ + QString arg; + int delimDepth = 0; + if (m_position < m_input.length() && m_input[m_position] == '{') { + ++m_position; + while (m_position < m_input.length() && delimDepth >= 0) { + switch (m_input[m_position].unicode()) { + case '{': + ++delimDepth; + arg += QLatin1Char('{'); + ++m_position; + break; + case '}': + --delimDepth; + if (delimDepth >= 0) + arg += QLatin1Char('}'); + ++m_position; + break; + case '\\': + if (verbatim || !expandMacro()) + arg += m_input[m_position++]; + break; + default: + if (m_input[m_position].isSpace() && !verbatim) + arg += QChar(' '); + else + arg += m_input[m_position]; + ++m_position; + } + } + if (delimDepth > 0) + location().warning(QStringLiteral("Missing '}'")); + } + m_endPosition = m_position; + return arg; +} + +/*! + Typically, an argument ends at the next white-space. However, + braces can be used to group words: + + {a few words} + + Also, opening and closing parentheses have to match. Thus, + + printf("%d\n", x) + + is an argument too, although it contains spaces. Finally, + trailing punctuation is not included in an argument, nor is 's. +*/ +QString DocParser::getArgument(bool verbatim) +{ + skipSpacesOrOneEndl(); + + int delimDepth = 0; + int startPos = m_position; + QString arg = getBracedArgument(verbatim); + if (arg.isEmpty()) { + while ((m_position < m_input.length()) + && ((delimDepth > 0) || ((delimDepth == 0) && !m_input[m_position].isSpace()))) { + switch (m_input[m_position].unicode()) { + case '(': + case '[': + case '{': + ++delimDepth; + arg += m_input[m_position]; + ++m_position; + break; + case ')': + case ']': + case '}': + --delimDepth; + if (m_position == startPos || delimDepth >= 0) { + arg += m_input[m_position]; + ++m_position; + } + break; + case '\\': + if (verbatim || !expandMacro()) + arg += m_input[m_position++]; + break; + default: + arg += m_input[m_position]; + ++m_position; + } + } + m_endPosition = m_position; + if ((arg.length() > 1) && (QString(".,:;!?").indexOf(m_input[m_position - 1]) != -1) + && !arg.endsWith("...")) { + arg.truncate(arg.length() - 1); + --m_position; + } + if (arg.length() > 2 && m_input.mid(m_position - 2, 2) == "'s") { + arg.truncate(arg.length() - 2); + m_position -= 2; + } + } + return arg.simplified(); +} + +/*! + Gets an argument that is enclosed in brackets and returns it + without the enclosing brackets. On entry, the current character + is the left bracket. On exit, the current character is the one + that comes after the right bracket. + */ +QString DocParser::getBracketedArgument() +{ + QString arg; + int delimDepth = 0; + skipSpacesOrOneEndl(); + if (m_position < m_input.length() && m_input[m_position] == '[') { + ++m_position; + while (m_position < m_input.length() && delimDepth >= 0) { + switch (m_input[m_position].unicode()) { + case '[': + ++delimDepth; + arg += QLatin1Char('['); + ++m_position; + break; + case ']': + --delimDepth; + if (delimDepth >= 0) + arg += QLatin1Char(']'); + ++m_position; + break; + case '\\': + arg += m_input[m_position]; + ++m_position; + break; + default: + arg += m_input[m_position]; + ++m_position; + } + } + if (delimDepth > 0) + location().warning(QStringLiteral("Missing ']'")); + } + return arg; +} + +QString DocParser::getOptionalArgument() +{ + skipSpacesOrOneEndl(); + if (m_position + 1 < m_input.length() && m_input[m_position] == '\\' + && m_input[m_position + 1].isLetterOrNumber()) { + return QString(); + } else { + return getArgument(); + } +} + +QString DocParser::getRestOfLine() +{ + QString t; + + skipSpacesOnLine(); + + bool trailingSlash = false; + + do { + int begin = m_position; + + while (m_position < m_input.size() && m_input[m_position] != '\n') { + if (m_input[m_position] == '\\' && !trailingSlash) { + trailingSlash = true; + ++m_position; + while ((m_position < m_input.size()) && m_input[m_position].isSpace() + && (m_input[m_position] != '\n')) + ++m_position; + } else { + trailingSlash = false; + ++m_position; + } + } + + if (!t.isEmpty()) + t += QLatin1Char(' '); + t += m_input.mid(begin, m_position - begin).simplified(); + + if (trailingSlash) { + t.chop(1); + t = t.simplified(); + } + if (m_position < m_input.size()) + ++m_position; + } while (m_position < m_input.size() && trailingSlash); + + return t; +} + +/*! + The metacommand argument is normally the remaining text to + the right of the metacommand itself. The extra blanks are + stripped and the argument string is returned. + */ +QString DocParser::getMetaCommandArgument(const QString &cmdStr) +{ + skipSpacesOnLine(); + + int begin = m_position; + int parenDepth = 0; + + while (m_position < m_input.size() && (m_input[m_position] != '\n' || parenDepth > 0)) { + if (m_input.at(m_position) == '(') + ++parenDepth; + else if (m_input.at(m_position) == ')') + --parenDepth; + else if (m_input.at(m_position) == '\\' && expandMacro()) + continue; + ++m_position; + } + if (m_position == m_input.size() && parenDepth > 0) { + m_position = begin; + location().warning(QStringLiteral("Unbalanced parentheses in '%1'").arg(cmdStr)); + } + + QString t = m_input.mid(begin, m_position - begin).simplified(); + skipSpacesOnLine(); + return t; +} + +QString DocParser::getUntilEnd(int cmd) +{ + int endCmd = endCmdFor(cmd); + QRegularExpression rx("\\\\" + cmdName(endCmd) + "\\b"); + QString t; + auto match = rx.match(m_input, m_position); + + if (!match.hasMatch()) { + location().warning(QStringLiteral("Missing '\\%1'").arg(cmdName(endCmd))); + m_position = m_input.length(); + } else { + int end = match.capturedStart(); + t = m_input.mid(m_position, end - m_position); + m_position = match.capturedEnd(); + } + return t; +} + +QString DocParser::getCode(int cmd, CodeMarker *marker, const QString &argStr) +{ + QString code = untabifyEtc(getUntilEnd(cmd)); + + if (!argStr.isEmpty()) { + QStringList args = argStr.split(" ", Qt::SkipEmptyParts); + int paramNo, j = 0; + while (j < code.size()) { + if (code[j] == '\\' && j < code.size() - 1 && (paramNo = code[j + 1].digitValue()) >= 1 + && paramNo <= args.size()) { + QString p = args[paramNo - 1]; + code.replace(j, 2, p); + j += qMin(1, p.size()); + } else { + ++j; + } + } + } + + int indent = indentLevel(code); + code = dedent(indent, code); + if (marker == nullptr) + marker = CodeMarker::markerForCode(code); + return marker->markedUpCode(code, nullptr, location()); +} + +bool DocParser::isBlankLine() +{ + int i = m_position; + + while (i < m_inputLength && m_input[i].isSpace()) { + if (m_input[i] == '\n') + return true; + ++i; + } + return false; +} + +bool DocParser::isLeftBraceAhead() +{ + int numEndl = 0; + int i = m_position; + + while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) { + // ### bug with '\\' + if (m_input[i] == '\n') + numEndl++; + ++i; + } + return numEndl < 2 && i < m_inputLength && m_input[i] == '{'; +} + +bool DocParser::isLeftBracketAhead() +{ + int numEndl = 0; + int i = m_position; + + while (i < m_inputLength && m_input[i].isSpace() && numEndl < 2) { + // ### bug with '\\' + if (m_input[i] == '\n') + numEndl++; + ++i; + } + return numEndl < 2 && i < m_inputLength && m_input[i] == '['; +} + +/*! + Skips to the next non-space character or EOL. + */ +void DocParser::skipSpacesOnLine() +{ + while ((m_position < m_input.length()) && m_input[m_position].isSpace() + && (m_input[m_position].unicode() != '\n')) + ++m_position; +} + +/*! + Skips spaces and one EOL. + */ +void DocParser::skipSpacesOrOneEndl() +{ + int firstEndl = -1; + while (m_position < m_input.length() && m_input[m_position].isSpace()) { + QChar ch = m_input[m_position]; + if (ch == '\n') { + if (firstEndl == -1) { + firstEndl = m_position; + } else { + m_position = firstEndl; + break; + } + } + ++m_position; + } +} + +void DocParser::skipAllSpaces() +{ + while (m_position < m_inputLength && m_input[m_position].isSpace()) + ++m_position; +} + +void DocParser::skipToNextPreprocessorCommand() +{ + QRegularExpression rx("\\\\(?:" + cmdName(CMD_IF) + QLatin1Char('|') + cmdName(CMD_ELSE) + + QLatin1Char('|') + cmdName(CMD_ENDIF) + ")\\b"); + auto match = rx.match(m_input, m_position + 1); // ### + 1 necessary? + + if (!match.hasMatch()) + m_position = m_input.length(); + else + m_position = match.capturedStart(); +} + +int DocParser::endCmdFor(int cmd) +{ + switch (cmd) { + case CMD_BADCODE: + return CMD_ENDCODE; + case CMD_CODE: + return CMD_ENDCODE; + case CMD_DIV: + return CMD_ENDDIV; + case CMD_QML: + return CMD_ENDQML; + case CMD_QMLTEXT: + return CMD_ENDQMLTEXT; + case CMD_JS: + return CMD_ENDJS; + case CMD_FOOTNOTE: + return CMD_ENDFOOTNOTE; + case CMD_LEGALESE: + return CMD_ENDLEGALESE; + case CMD_LINK: + return CMD_ENDLINK; + case CMD_LIST: + return CMD_ENDLIST; + case CMD_NEWCODE: + return CMD_ENDCODE; + case CMD_OLDCODE: + return CMD_NEWCODE; + case CMD_OMIT: + return CMD_ENDOMIT; + case CMD_QUOTATION: + return CMD_ENDQUOTATION; + case CMD_RAW: + return CMD_ENDRAW; + case CMD_SECTION1: + return CMD_ENDSECTION1; + case CMD_SECTION2: + return CMD_ENDSECTION2; + case CMD_SECTION3: + return CMD_ENDSECTION3; + case CMD_SECTION4: + return CMD_ENDSECTION4; + case CMD_SIDEBAR: + return CMD_ENDSIDEBAR; + case CMD_TABLE: + return CMD_ENDTABLE; + default: + return cmd; + } +} + +QString DocParser::cmdName(int cmd) +{ + return *cmds[cmd].alias; +} + +QString DocParser::endCmdName(int cmd) +{ + return cmdName(endCmdFor(cmd)); +} + +QString DocParser::untabifyEtc(const QString &str) +{ + QString result; + result.reserve(str.length()); + int column = 0; + + for (const auto &character : str) { + if (character == QLatin1Char('\r')) + continue; + if (character == QLatin1Char('\t')) { + result += &" "[column % tabSize]; + column = ((column / tabSize) + 1) * tabSize; + continue; + } + if (character == QLatin1Char('\n')) { + while (result.endsWith(QLatin1Char(' '))) + result.chop(1); + result += character; + column = 0; + continue; + } + result += character; + ++column; + } + + while (result.endsWith("\n\n")) + result.truncate(result.length() - 1); + while (result.startsWith(QLatin1Char('\n'))) + result = result.mid(1); + + return result; +} + +int DocParser::indentLevel(const QString &str) +{ + int minIndent = INT_MAX; + int column = 0; + + for (const auto &character : str) { + if (character == '\n') { + column = 0; + } else { + if (character != ' ' && column < minIndent) + minIndent = column; + ++column; + } + } + return minIndent; +} + +QString DocParser::dedent(int level, const QString &str) +{ + if (level == 0) + return str; + + QString result; + int column = 0; + + for (const auto &character : str) { + if (character == QLatin1Char('\n')) { + result += '\n'; + column = 0; + } else { + if (column >= level) + result += character; + ++column; + } + } + return result; +} + +QString DocParser::slashed(const QString &str) +{ + QString result = str; + result.replace(QLatin1Char('/'), "\\/"); + return QLatin1Char('/') + result + QLatin1Char('/'); +} + +/*! + Returns \c true if \a atom represents a code snippet. + */ +bool DocParser::isCode(const Atom *atom) +{ + Atom::AtomType type = atom->type(); + return (type == Atom::Code || type == Atom::Qml || type == Atom::JavaScript); +} + +/*! + Returns \c true if \a atom represents quoting information. + */ +bool DocParser::isQuote(const Atom *atom) +{ + Atom::AtomType type = atom->type(); + return (type == Atom::CodeQuoteArgument || type == Atom::CodeQuoteCommand + || type == Atom::SnippetCommand || type == Atom::SnippetIdentifier + || type == Atom::SnippetLocation); +} + +QT_END_NAMESPACE diff --git a/src/qdoc/docparser.h b/src/qdoc/docparser.h new file mode 100644 index 0000000000..f5f9d3607f --- /dev/null +++ b/src/qdoc/docparser.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef DOCPARSER_H +#define DOCPARSER_H + +#include "atom.h" +#include "config.h" +#include "docutilities.h" +#include "location.h" +#include "openedlist.h" +#include "quoter.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Doc; +class DocPrivate; +class CodeMarker; + +class DocParser +{ +public: + void parse(const QString &source, DocPrivate *docPrivate, const QSet &metaCommandSet, + const QSet &possibleTopics); + + static void initialize(const Config &config); + static void terminate(); + static int endCmdFor(int cmd); + static QString cmdName(int cmd); + static QString endCmdName(int cmd); + static QString untabifyEtc(const QString &str); + static int indentLevel(const QString &str); + static QString dedent(int level, const QString &str); + static QString slashed(const QString &str); + + static int tabSize; + static QStringList exampleFiles; + static QStringList exampleDirs; + static QStringList sourceFiles; + static QStringList sourceDirs; + static QStringList ignoreWords; + static bool quoting; + +private: + Location &location(); + QString detailsUnknownCommand(const QSet &metaCommandSet, const QString &str); + void insertTarget(const QString &target, bool keyword); + void include(const QString &fileName, const QString &identifier); + void startFormat(const QString &format, int cmd); + bool openCommand(int cmd); + bool closeCommand(int endCmd); + void startSection(Doc::Sections unit, int cmd); + void endSection(int unit, int endCmd); + void parseAlso(); + void append(const QString &string); + void append(Atom::AtomType type, const QString &string = QString()); + void append(Atom::AtomType type, const QString &p1, const QString &p2); + void append(const QString &p1, const QString &p2); + void appendChar(QChar ch); + void appendWord(const QString &word); + void appendToCode(const QString &code); + void appendToCode(const QString &code, Atom::AtomType defaultType); + void enterPara(Atom::AtomType leftType = Atom::ParaLeft, + Atom::AtomType rightType = Atom::ParaRight, const QString &string = QString()); + void leavePara(); + void leaveValue(); + void leaveValueList(); + void leaveTableRow(); + CodeMarker *quoteFromFile(); + bool expandMacro(); + void expandMacro(const QString &name, const QString &def, int numParams); + QString expandMacroToString(const QString &name, const QString &def, int numParams, + const QString &matchExpr); + Doc::Sections getSectioningUnit(); + QString getArgument(bool verbatim = false); + QString getBracedArgument(bool verbatim); + QString getBracketedArgument(); + QString getOptionalArgument(); + QString getRestOfLine(); + QString getMetaCommandArgument(const QString &cmdStr); + QString getUntilEnd(int cmd); + QString getCode(int cmd, CodeMarker *marker, const QString &argStr = QString()); + + inline bool isAutoLinkString(const QString &word); + bool isAutoLinkString(const QString &word, int &curPos); + bool isBlankLine(); + bool isLeftBraceAhead(); + bool isLeftBracketAhead(); + void skipSpacesOnLine(); + void skipSpacesOrOneEndl(); + void skipAllSpaces(); + void skipToNextPreprocessorCommand(); + static bool isCode(const Atom *atom); + static bool isQuote(const Atom *atom); + + QStack m_openedInputs; + + QString m_input; + int m_position {}; + int m_backslashPosition {}; + int m_endPosition {}; + int m_inputLength {}; + Location m_cachedLocation; + int m_cachedPosition {}; + + DocPrivate *m_private { nullptr }; + enum ParagraphState { OutsideParagraph, InSingleLineParagraph, InMultiLineParagraph }; + ParagraphState m_paragraphState {}; + bool m_inTableHeader {}; + bool m_inTableRow {}; + bool m_inTableItem {}; + bool m_indexStartedParagraph {}; // ### rename + Atom::AtomType m_pendingParagraphLeftType {}; + Atom::AtomType m_pendingParagraphRightType {}; + QString m_pendingParagraphString; + + int m_braceDepth {}; + Doc::Sections m_currentSection {}; + QMap m_targetMap; + QMap m_pendingFormats; + QStack m_openedCommands; + QStack m_openedLists; + Quoter m_quoter; + Atom *m_lastAtom { nullptr }; + + static DocUtilities &m_utilities; +}; +QT_END_NAMESPACE + +#endif // DOCPARSER_H diff --git a/src/qdoc/docprivate.cpp b/src/qdoc/docprivate.cpp new file mode 100644 index 0000000000..14ece93da7 --- /dev/null +++ b/src/qdoc/docprivate.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "docprivate.h" + +#include "atom.h" +#include "openedlist.h" +#include "text.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + Deletes the DocPrivateExtra. + */ +DocPrivate::~DocPrivate() +{ + delete extra; +} + +void DocPrivate::addAlso(const Text &also) +{ + alsoList.append(also); +} + +void DocPrivate::constructExtra() +{ + if (extra == nullptr) + extra = new DocPrivateExtra; +} + +QT_END_NAMESPACE diff --git a/src/qdoc/docprivate.h b/src/qdoc/docprivate.h new file mode 100644 index 0000000000..1c7969f1aa --- /dev/null +++ b/src/qdoc/docprivate.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef DOCPRIVATE_H +#define DOCPRIVATE_H + +#include "atom.h" +#include "config.h" +#include "codemarker.h" +#include "doc.h" +#include "editdistance.h" +#include "generator.h" +#include "utilities.h" +#include "openedlist.h" +#include "quoter.h" +#include "text.h" +#include "tokenizer.h" + +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +typedef QPair ArgLocPair; +typedef QMap CommandMap; + +class DocPrivateExtra +{ +public: + Doc::Sections granularity_; + Doc::Sections section_; + QList tableOfContents_; + QList tableOfContentsLevels_; + QList keywords_; + QList targets_; + QStringMultiMap metaMap_; + + DocPrivateExtra() : granularity_(Doc::Part), section_(Doc::NoSection) {} +}; + +class DocPrivate +{ +public: + explicit DocPrivate(const Location &start = Location(), const Location &end = Location(), + const QString &source = QString()) + : start_loc(start), + end_loc(end), + src(source), + hasLegalese(false), + hasSectioningUnits(false) {}; + ~DocPrivate(); + + void addAlso(const Text &also); + void constructExtra(); + void ref() { ++count; } + bool deref() { return (--count == 0); } + + int count { 1 }; + // ### move some of this in DocPrivateExtra + Location start_loc; + Location end_loc; + QString src; + Text text; + QSet params; + QList alsoList; + QStringList enumItemList; + QStringList omitEnumItemList; + QSet metacommandsUsed; + CommandMap metaCommandMap; + DocPrivateExtra *extra { nullptr }; + TopicList topics_; + + bool hasLegalese : 1; + bool hasSectioningUnits : 1; +}; + +QT_END_NAMESPACE + +#endif // DOCPRIVATE_H diff --git a/src/qdoc/docutilities.h b/src/qdoc/docutilities.h new file mode 100644 index 0000000000..28ba0e6090 --- /dev/null +++ b/src/qdoc/docutilities.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef DOCUTILITIES_H +#define DOCUTILITIES_H + +#include "macro.h" +#include "singleton.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +typedef QMap QStringMap; +typedef QHash QHash_QString_int; +typedef QHash QHash_QString_Macro; + +struct DocUtilities : public Singleton +{ +public: + QStringMap aliasMap; + QHash_QString_int cmdHash; + QHash_QString_Macro macroHash; +}; + +QT_END_NAMESPACE + +#endif // DOCUTILITIES_H diff --git a/src/qdoc/editdistance.cpp b/src/qdoc/editdistance.cpp index aa7e16b3f6..841f5f48d4 100644 --- a/src/qdoc/editdistance.cpp +++ b/src/qdoc/editdistance.cpp @@ -34,9 +34,9 @@ QT_BEGIN_NAMESPACE -int editDistance( const QString& s, const QString& t ) +int editDistance(const QString &s, const QString &t) { -#define D( i, j ) d[(i) * n + (j)] +#define D(i, j) d[(i)*n + (j)] int i; int j; int m = s.length() + 1; @@ -44,29 +44,29 @@ int editDistance( const QString& s, const QString& t ) int *d = new int[m * n]; int result; - for ( i = 0; i < m; i++ ) - D( i, 0 ) = i; - for ( j = 0; j < n; j++ ) - D( 0, j ) = j; - for ( i = 1; i < m; i++ ) { - for ( j = 1; j < n; j++ ) { - if ( s[i - 1] == t[j - 1] ) { - D( i, j ) = D( i - 1, j - 1 ); + for (i = 0; i < m; ++i) + D(i, 0) = i; + for (j = 0; j < n; ++j) + D(0, j) = j; + for (i = 1; i < m; ++i) { + for (j = 1; j < n; ++j) { + if (s[i - 1] == t[j - 1]) { + D(i, j) = D(i - 1, j - 1); } else { - int x = D( i - 1, j ); - int y = D( i - 1, j - 1 ); - int z = D( i, j - 1 ); - D( i, j ) = 1 + qMin( qMin(x, y), z ); + int x = D(i - 1, j); + int y = D(i - 1, j - 1); + int z = D(i, j - 1); + D(i, j) = 1 + qMin(qMin(x, y), z); } } } - result = D( m - 1, n - 1 ); + result = D(m - 1, n - 1); delete[] d; return result; #undef D } -QString nearestName( const QString& actual, const QSet& candidates ) +QString nearestName(const QString &actual, const QSet &candidates) { if (actual.isEmpty()) return QString(); @@ -75,27 +75,23 @@ QString nearestName( const QString& actual, const QSet& candidates ) int numBest = 0; QString best; - QSet::ConstIterator c = candidates.constBegin(); - while ( c != candidates.constEnd() ) { - if ( (*c)[0] == actual[0] ) { - int delta = editDistance( actual, *c ); - if ( delta < deltaBest ) { + for (const auto &candidate : candidates) { + if (candidate[0] == actual[0]) { + int delta = editDistance(actual, candidate); + if (delta < deltaBest) { deltaBest = delta; numBest = 1; - best = *c; - } else if ( delta == deltaBest ) { - numBest++; + best = candidate; + } else if (delta == deltaBest) { + ++numBest; } } - ++c; } - if ( numBest == 1 && deltaBest <= 2 && - actual.length() + best.length() >= 5 ) { + if (numBest == 1 && deltaBest <= 2 && actual.length() + best.length() >= 5) return best; - } else { - return QString(); - } + + return QString(); } QT_END_NAMESPACE diff --git a/src/qdoc/editdistance.h b/src/qdoc/editdistance.h index e67095fdd9..c7ea080cdd 100644 --- a/src/qdoc/editdistance.h +++ b/src/qdoc/editdistance.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -33,13 +33,13 @@ #ifndef EDITDISTANCE_H #define EDITDISTANCE_H -#include -#include +#include +#include QT_BEGIN_NAMESPACE -int editDistance( const QString& s, const QString& t ); -QString nearestName( const QString& actual, const QSet& candidates ); +int editDistance(const QString &s, const QString &t); +QString nearestName(const QString &actual, const QSet &candidates); QT_END_NAMESPACE diff --git a/src/qdoc/enumitem.h b/src/qdoc/enumitem.h new file mode 100644 index 0000000000..6755d7c409 --- /dev/null +++ b/src/qdoc/enumitem.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ENUMITEM_H +#define ENUMITEM_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class EnumItem +{ +public: + EnumItem() = default; + EnumItem(const QString &name, const QString &value) : m_name(name), m_value(value) {} + + const QString &name() const { return m_name; } + const QString &value() const { return m_value; } + +private: + QString m_name {}; + QString m_value {}; +}; + +QT_END_NAMESPACE + +#endif // ENUMITEM_H diff --git a/src/qdoc/enumnode.cpp b/src/qdoc/enumnode.cpp new file mode 100644 index 0000000000..2e4b823076 --- /dev/null +++ b/src/qdoc/enumnode.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "enumnode.h" + +#include "aggregate.h" +#include "typedefnode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class EnumNode + */ + +/*! + Add \a item to the enum type's item list. + */ +void EnumNode::addItem(const EnumItem &item) +{ + m_items.append(item); + m_names.insert(item.name()); +} + +/*! + Returns the access level of the enumeration item named \a name. + Apparently it is private if it has been omitted by qdoc's + omitvalue command. Otherwise it is public. + */ +Access EnumNode::itemAccess(const QString &name) const +{ + if (doc().omitEnumItemNames().contains(name)) + return Access::Private; + return Access::Public; +} + +/*! + Returns the enum value associated with the enum \a name. + */ +QString EnumNode::itemValue(const QString &name) const +{ + for (const auto &item : qAsConst(m_items)) { + if (item.name() == name) + return item.value(); + } + return QString(); +} + +/*! + Clone this node on the heap and make the clone a child of + \a parent. + + Returns a pointer to the clone. + */ +Node *EnumNode::clone(Aggregate *parent) +{ + auto *en = new EnumNode(*this); // shallow copy + en->setParent(nullptr); + parent->addChild(en); + + return en; +} + +void EnumNode::setFlagsType(TypedefNode *typedefNode) +{ + m_flagsType = typedefNode; + typedefNode->setAssociatedEnum(this); +} + +QT_END_NAMESPACE diff --git a/src/qdoc/enumnode.h b/src/qdoc/enumnode.h new file mode 100644 index 0000000000..84a074d10b --- /dev/null +++ b/src/qdoc/enumnode.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ENUMNODE_H +#define ENUMNODE_H + +#include "access.h" +#include "node.h" +#include "typedefnode.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Aggregate; + +class EnumNode : public Node +{ +public: + EnumNode(Aggregate *parent, const QString &name, bool isScoped = false) + : Node(Enum, parent, name), m_isScoped(isScoped) + { + } + + void addItem(const EnumItem &item); + void setFlagsType(TypedefNode *typedefNode); + bool hasItem(const QString &name) const { return m_names.contains(name); } + bool isScoped() const { return m_isScoped; } + + const QList &items() const { return m_items; } + Access itemAccess(const QString &name) const; + const TypedefNode *flagsType() const { return m_flagsType; } + QString itemValue(const QString &name) const; + Node *clone(Aggregate *parent) override; + +private: + QList m_items {}; + QSet m_names {}; + const TypedefNode *m_flagsType { nullptr }; + bool m_isScoped { false }; +}; + +QT_END_NAMESPACE + +#endif // ENUMNODE_H diff --git a/src/qdoc/examplenode.h b/src/qdoc/examplenode.h new file mode 100644 index 0000000000..22fb364d9f --- /dev/null +++ b/src/qdoc/examplenode.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXAMPLENODE_H +#define EXAMPLENODE_H + +#include "pagenode.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class ExampleNode : public PageNode +{ +public: + ExampleNode(Aggregate *parent, const QString &name) : PageNode(Node::Example, parent, name) {} + QString imageFileName() const override { return m_imageFileName; } + void setImageFileName(const QString &ifn) override { m_imageFileName = ifn; } + const QStringList &files() const { return m_files; } + const QStringList &images() const { return m_images; } + const QString &projectFile() const { return m_projectFile; } + void setFiles(const QStringList files, const QString &projectFile) + { + m_files = files; + m_projectFile = projectFile; + } + void setImages(const QStringList images) { m_images = images; } + void appendFile(QString &file) { m_files.append(file); } + void appendImage(QString &image) { m_images.append(image); } + +private: + QString m_imageFileName {}; + QString m_projectFile {}; + QStringList m_files {}; + QStringList m_images {}; +}; + +QT_END_NAMESPACE + +#endif // EXAMPLENODE_H diff --git a/src/qdoc/externalpagenode.cpp b/src/qdoc/externalpagenode.cpp new file mode 100644 index 0000000000..8882ed8f79 --- /dev/null +++ b/src/qdoc/externalpagenode.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "externalpagenode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class ExternalPageNode + + \brief The ExternalPageNode represents an external documentation page. + + Qdoc can generate links to pages that are not part of the documentation + being generated. 3rd party software pages are often referenced by links + from the QT documentation. Qdoc creates an ExternalPageNode when it sees + an \c {\\externalpage} command. The HTML generator can then use the node + when it needs to create links to the external page. + + ExternalPageNode inherits PageNode. +*/ + +/*! \fn ExternalPageNode::ExternalPageNode(Aggregate *parent, const QString &name) + The constructor creates an ExternalPageNode as a child node of \a parent. + It's \a name is the argument from the \c {\\externalpage} command. The node + type is Node::ExternalPage, and the page type is Node::ArticlePage. + */ + +QT_END_NAMESPACE diff --git a/src/qdoc/externalpagenode.h b/src/qdoc/externalpagenode.h new file mode 100644 index 0000000000..91abd9ca94 --- /dev/null +++ b/src/qdoc/externalpagenode.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTERNALPAGENODE_H +#define EXTERNALPAGENODE_H + +#include "pagenode.h" + +#include + +QT_BEGIN_NAMESPACE + +class ExternalPageNode : public PageNode +{ +public: + ExternalPageNode(Aggregate *parent, const QString &url) + : PageNode(Node::ExternalPage, parent, url) + { + setPageType(Node::ArticlePage); + setUrl(url); + } +}; + +QT_END_NAMESPACE + +#endif // EXTERNALPAGENODE_H diff --git a/src/qdoc/functionnode.cpp b/src/qdoc/functionnode.cpp new file mode 100644 index 0000000000..53694e5b56 --- /dev/null +++ b/src/qdoc/functionnode.cpp @@ -0,0 +1,631 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "functionnode.h" + +#include "propertynode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class FunctionNode + + This node is used to represent any kind of function being + documented. It can represent a C++ class member function, + a C++ global function, a QML method, a javascript method, + or a macro, with or without parameters. + + A C++ function can be a signal a slot, a constructor of any + kind, a destructor, a copy or move assignment operator, or + just a plain old member function or global function. + + A QML or javascript method can be a plain old method, or a + signal or signal handler. + + If the function is not an overload, its overload flag is + false. If it is an overload, its overload flag is true. + If it is not an overload but it has overloads, its next + overload pointer will point to an overload function. If it + is an overload function, its overload flag is true, and it + may or may not have a non-null next overload pointer. + + So all the overloads of a function are in a linked list + using the next overload pointer. If a function has no + overloads, its overload flag is false and its overload + pointer is null. + + The function node also has an overload number. If the + node's overload flag is set, this overload number is + positive; otherwise, the overload number is 0. + */ + +/*! + Construct a function node for a C++ function. It's parent + is \a parent, and it's name is \a name. + + \note The function node's overload flag is set to false, and + its overload number is set to 0. These data members are set + in normalizeOverloads(), when all the overloads are known. + */ +FunctionNode::FunctionNode(Aggregate *parent, const QString &name) + : Node(Function, parent, name), + m_const(false), + m_default(false), + m_static(false), + m_reimpFlag(false), + m_attached(false), + m_overloadFlag(false), + m_isFinal(false), + m_isOverride(false), + m_isRef(false), + m_isRefRef(false), + m_isInvokable(false), + m_metaness(Plain), + m_virtualness(NonVirtual), + m_overloadNumber(0), + m_nextOverload(nullptr) +{ + // nothing +} + +/*! + Construct a function node for a QML method or signal, specified + by ther Metaness value \a type. It's parent is \a parent, and + it's name is \a name. If \a attached is true, it is an attached + method or signal. + + \note The function node's overload flag is set to false, and + its overload number is set to 0. These data members are set + in normalizeOverloads(), when all the overloads are known. + */ +FunctionNode::FunctionNode(Metaness kind, Aggregate *parent, const QString &name, bool attached) + : Node(Function, parent, name), + m_const(false), + m_default(false), + m_static(false), + m_reimpFlag(false), + m_attached(attached), + m_overloadFlag(false), + m_isFinal(false), + m_isOverride(false), + m_isRef(false), + m_isRefRef(false), + m_isInvokable(false), + m_metaness(kind), + m_virtualness(NonVirtual), + m_overloadNumber(0), + m_nextOverload(nullptr) +{ + setGenus(getGenus(m_metaness)); + if (!isCppNode() && name.startsWith("__")) + setStatus(Internal); +} + +/*! + Clone this node on the heap and make the clone a child of + \a parent. Return the pointer to the clone. + */ +Node *FunctionNode::clone(Aggregate *parent) +{ + FunctionNode *fn = new FunctionNode(*this); // shallow copy + fn->setParent(nullptr); + fn->setNextOverload(nullptr); + parent->addChild(fn); + return fn; +} + +/*! + Returns this function's virtualness value as a string + for use as an attribute value in index files. + */ +QString FunctionNode::virtualness() const +{ + switch (m_virtualness) { + case FunctionNode::NormalVirtual: + return QLatin1String("virtual"); + case FunctionNode::PureVirtual: + return QLatin1String("pure"); + case FunctionNode::NonVirtual: + default: + break; + } + return QLatin1String("non"); +} + +/*! + Sets the function node's virtualness value based on the value + of string \a value, which is the value of the function's \e{virtual} + attribute in an index file. If \a value is \e{pure}, and if the + parent() is a C++ class, set the parent's \e abstract flag to + \c {true}. + */ +void FunctionNode::setVirtualness(const QString &value) +{ + if (value == QLatin1String("non")) + m_virtualness = NonVirtual; + else if (value == QLatin1String("virtual")) + m_virtualness = NormalVirtual; + else if (value == QLatin1String("pure")) { + m_virtualness = PureVirtual; + if (parent() && parent()->isClassNode()) + parent()->setAbstract(true); + } +} + +static QMap metanessMap_; +static void buildMetanessMap() +{ + metanessMap_["plain"] = FunctionNode::Plain; + metanessMap_["signal"] = FunctionNode::Signal; + metanessMap_["slot"] = FunctionNode::Slot; + metanessMap_["constructor"] = FunctionNode::Ctor; + metanessMap_["copy-constructor"] = FunctionNode::CCtor; + metanessMap_["move-constructor"] = FunctionNode::MCtor; + metanessMap_["destructor"] = FunctionNode::Dtor; + metanessMap_["macro"] = FunctionNode::MacroWithParams; + metanessMap_["macrowithparams"] = FunctionNode::MacroWithParams; + metanessMap_["macrowithoutparams"] = FunctionNode::MacroWithoutParams; + metanessMap_["copy-assign"] = FunctionNode::CAssign; + metanessMap_["move-assign"] = FunctionNode::MAssign; + metanessMap_["native"] = FunctionNode::Native; + metanessMap_["qmlsignal"] = FunctionNode::QmlSignal; + metanessMap_["qmlsignalhandler"] = FunctionNode::QmlSignalHandler; + metanessMap_["qmlmethod"] = FunctionNode::QmlMethod; + metanessMap_["jssignal"] = FunctionNode::JsSignal; + metanessMap_["jssignalhandler"] = FunctionNode::JsSignalHandler; + metanessMap_["jsmethos"] = FunctionNode::JsMethod; +} + +static QMap topicMetanessMap_; +static void buildTopicMetanessMap() +{ + topicMetanessMap_["fn"] = FunctionNode::Plain; + topicMetanessMap_["qmlsignal"] = FunctionNode::QmlSignal; + topicMetanessMap_["qmlattachedsignal"] = FunctionNode::QmlSignal; + topicMetanessMap_["qmlmethod"] = FunctionNode::QmlMethod; + topicMetanessMap_["qmlattachedmethod"] = FunctionNode::QmlMethod; + topicMetanessMap_["jssignal"] = FunctionNode::JsSignal; + topicMetanessMap_["jsattachedsignal"] = FunctionNode::JsSignal; + topicMetanessMap_["jsmethod"] = FunctionNode::JsMethod; + topicMetanessMap_["jsattachedmethod"] = FunctionNode::JsMethod; +} + +/*! + Determines the Genus value for this FunctionNode given the + Metaness value \a metaness. Returns the Genus value. \a metaness must be + one of the values of Metaness. If not, Node::DontCare is + returned. + */ +Node::Genus FunctionNode::getGenus(FunctionNode::Metaness metaness) +{ + switch (metaness) { + case FunctionNode::Plain: + case FunctionNode::Signal: + case FunctionNode::Slot: + case FunctionNode::Ctor: + case FunctionNode::Dtor: + case FunctionNode::CCtor: + case FunctionNode::MCtor: + case FunctionNode::MacroWithParams: + case FunctionNode::MacroWithoutParams: + case FunctionNode::Native: + case FunctionNode::CAssign: + case FunctionNode::MAssign: + return Node::CPP; + case FunctionNode::QmlSignal: + case FunctionNode::QmlSignalHandler: + case FunctionNode::QmlMethod: + return Node::QML; + case FunctionNode::JsSignal: + case FunctionNode::JsSignalHandler: + case FunctionNode::JsMethod: + return Node::JS; + } + return Node::DontCare; +} + +/*! + This static function converts the string \a value to an enum + value for the kind of function named by \a value. + */ +FunctionNode::Metaness FunctionNode::getMetaness(const QString &value) +{ + if (metanessMap_.isEmpty()) + buildMetanessMap(); + return metanessMap_[value]; +} + +/*! + This static function converts the topic string \a topic to an enum + value for the kind of function this FunctionNode represents. + */ +FunctionNode::Metaness FunctionNode::getMetanessFromTopic(const QString &topic) +{ + if (topicMetanessMap_.isEmpty()) + buildTopicMetanessMap(); + return topicMetanessMap_[topic]; +} + +/*! + Sets the function node's Metaness value based on the value + of string \a metaness, which is the value of the function's "meta" + attribute in an index file. Returns the Metaness value + */ +FunctionNode::Metaness FunctionNode::setMetaness(const QString &metaness) +{ + m_metaness = getMetaness(metaness); + return m_metaness; +} + +/*! + If this function node's metaness is \a from, change the + metaness to \a to and return \c true. Otherwise return + false. This function is used to change Qml function node + metaness values to Javascript function node metaness, + values because these nodes are created as Qml function + nodes before it is discovered that what the function node + represents is not a Qml function but a javascript function. + + Note that if the function returns true, which means the node + type was indeed changed, then the node's Genus is also changed + from QML to JS. + + The function also works in the other direction, but there is + no use case for that. + */ +bool FunctionNode::changeMetaness(Metaness from, Metaness to) +{ + if (m_metaness == from) { + m_metaness = to; + switch (to) { + case QmlSignal: + case QmlSignalHandler: + case QmlMethod: + setGenus(Node::QML); + break; + case JsSignal: + case JsSignalHandler: + case JsMethod: + setGenus(Node::JS); + break; + default: + setGenus(Node::CPP); + break; + } + return true; + } + return false; +} + +/*! + Sets the function node's overload number to \a number. If \a number + is 0, the function node's overload flag is set to false. If + \a number is greater than 0, the overload flag is set to true. + */ +void FunctionNode::setOverloadNumber(signed short number) +{ + m_overloadNumber = number; + m_overloadFlag = (number > 0) ? true : false; +} + +/*! + Appends \a functionNode to the linked list of overloads for this function. + + \note Although this function appends an overload function to the list of + overloads for this function's name, it does not set the function's + overload number or it's overload flag. If the function has the + \c{\\overload} in its QDoc comment, that will set the overload + flag. But qdoc treats the \c{\\overload} command as a hint that the + function should be documented as an overload. The hint is almost + always correct, but QDoc reserves the right to decide which function + should be the primary function and which functions are the overloads. + These decisions are made in Aggregate::normalizeOverloads(). + */ +void FunctionNode::appendOverload(FunctionNode *functionNode) +{ + auto current = this; + while (current->m_nextOverload) + current = current->m_nextOverload; + current->m_nextOverload = functionNode; + functionNode->m_nextOverload = nullptr; +} + +/*! + Removes \a functionNode from the linked list of function overloads. +*/ +void FunctionNode::removeOverload(FunctionNode *functionNode) +{ + auto head = this; + auto **indirect = &head; + while ((*indirect) != functionNode) { + if (!(*indirect)->m_nextOverload) + return; + indirect = &(*indirect)->m_nextOverload; + } + *indirect = functionNode->m_nextOverload; +} + +/*! + Returns the primary function - the first function + from the linked list of overloads that is \e not + marked as an overload. If found, the primary function + is removed from the list and returned. Otherwise + returns \c nullptr. + */ +FunctionNode *FunctionNode::findPrimaryFunction() +{ + auto current = this; + while (current->m_nextOverload && current->m_nextOverload->isOverload()) + current = current->m_nextOverload; + + auto primary = current->m_nextOverload; + if (primary) + current->m_nextOverload = primary->m_nextOverload; + + return primary; +} + +/*! + \fn void FunctionNode::setReimpFlag() + + Sets the function node's reimp flag to \c true, which means + the \e {\\reimp} command was used in the qdoc comment. It is + supposed to mean that the function reimplements a virtual + function in a base class. + */ + +/*! + Returns a string representing the kind of function this + Function node represents, which depends on the Metaness + value. + */ +QString FunctionNode::kindString() const +{ + switch (m_metaness) { + case FunctionNode::QmlSignal: + return "QML signal"; + case FunctionNode::QmlSignalHandler: + return "QML signal handler"; + case FunctionNode::QmlMethod: + return "QML method"; + case FunctionNode::JsSignal: + return "JS signal"; + case FunctionNode::JsSignalHandler: + return "JS signal handler"; + case FunctionNode::JsMethod: + return "JS method"; + default: + return "function"; + } +} + +/*! + Returns a string representing the Metaness enum value for + this function. It is used in index files. + */ +QString FunctionNode::metanessString() const +{ + switch (m_metaness) { + case FunctionNode::Plain: + return "plain"; + case FunctionNode::Signal: + return "signal"; + case FunctionNode::Slot: + return "slot"; + case FunctionNode::Ctor: + return "constructor"; + case FunctionNode::CCtor: + return "copy-constructor"; + case FunctionNode::MCtor: + return "move-constructor"; + case FunctionNode::Dtor: + return "destructor"; + case FunctionNode::MacroWithParams: + return "macrowithparams"; + case FunctionNode::MacroWithoutParams: + return "macrowithoutparams"; + case FunctionNode::Native: + return "native"; + case FunctionNode::CAssign: + return "copy-assign"; + case FunctionNode::MAssign: + return "move-assign"; + case FunctionNode::QmlSignal: + return "qmlsignal"; + case FunctionNode::QmlSignalHandler: + return "qmlsignalhandler"; + case FunctionNode::QmlMethod: + return "qmlmethod"; + case FunctionNode::JsSignal: + return "jssignal"; + case FunctionNode::JsSignalHandler: + return "jssignalhandler"; + case FunctionNode::JsMethod: + return "jsmethod"; + default: + return "plain"; + } +} + +/*! + Adds the "associated" property \a p to this function node. + The function might be the setter or getter for a property, + for example. + */ +void FunctionNode::addAssociatedProperty(PropertyNode *p) +{ + m_associatedProperties.append(p); +} + +/*! + \reimp + + Returns \c true if this is an access function for an obsolete property, + otherwise calls the base implementation of isObsolete(). +*/ +bool FunctionNode::isObsolete() const +{ + auto it = std::find_if_not(m_associatedProperties.begin(), m_associatedProperties.end(), + [](const Node *p) -> bool { return p->isObsolete(); }); + + if (!m_associatedProperties.isEmpty() && it == m_associatedProperties.end()) + return true; + + return Node::isObsolete(); +} + +/*! \fn unsigned char FunctionNode::overloadNumber() const + Returns the overload number for this function. + */ + +/*! + Reconstructs and returns the function's signature. If \a values + is \c true, the default values of the parameters are included. + The return type is included unless \a noReturnType is \c true. + Function templates are prefixed with \c {template } + if \a templateParams is \c true. + */ +QString FunctionNode::signature(bool values, bool noReturnType, bool templateParams) const +{ + QStringList elements; + + if (templateParams) + elements << templateDecl(); + if (!noReturnType) + elements << m_returnType; + elements.removeAll(QString()); + + if (!isMacroWithoutParams()) { + elements << name() + QLatin1Char('(') + m_parameters.signature(values) + QLatin1Char(')'); + if (!isMacro()) { + if (isConst()) + elements << QStringLiteral("const"); + if (isRef()) + elements << QStringLiteral("&"); + else if (isRefRef()) + elements << QStringLiteral("&&"); + } + } else { + elements << name(); + } + return elements.join(QLatin1Char(' ')); +} + +/*! + Print some information used for debugging qdoc. Only used when debugging. + */ +void FunctionNode::debug() const +{ + qDebug("QML METHOD %s m_returnType %s m_parentPath %s", qPrintable(name()), + qPrintable(m_returnType), qPrintable(m_parentPath.join(' '))); +} + +/*! + Compares this FunctionNode to \a node. If \a sameParent is \c true, compares + also the parent of the two nodes. Returns \c true if they describe + the same function. + */ +bool FunctionNode::compare(const Node *node, bool sameParent) const +{ + if (!node || !node->isFunction()) + return false; + + const auto *functionNode = static_cast(node); + if (metaness() != functionNode->metaness()) + return false; + if (sameParent && parent() != functionNode->parent()) + return false; + if (m_returnType != functionNode->returnType()) + return false; + if (isConst() != functionNode->isConst()) + return false; + if (isAttached() != functionNode->isAttached()) + return false; + const Parameters &p = functionNode->parameters(); + if (m_parameters.count() != p.count()) + return false; + if (!p.isEmpty()) { + for (int i = 0; i < p.count(); ++i) { + if (m_parameters.at(i).type() != p.at(i).type()) + return false; + } + } + return true; +} + +/*! + In some cases, it is ok for a public function to be not documented. + For example, the macro Q_OBJECT adds several functions to the API of + a class, but these functions are normally not meant to be documented. + So if a function node doesn't have documentation, then if its name is + in the list of functions that it is ok not to document, this function + returns true. Otherwise, it returns false. + + These are the member function names added by macros. Usually they + are not documented, but they can be documented, so this test avoids + reporting an error if they are not documented. + + But maybe we should generate a standard text for each of them? + */ +bool FunctionNode::isIgnored() const +{ + if (!hasDoc() && !hasSharedDoc()) { + if (name().startsWith(QLatin1String("qt_")) || name() == QLatin1String("metaObject") + || name() == QLatin1String("tr") || name() == QLatin1String("trUtf8") + || name() == QLatin1String("d_func")) { + return true; + } + QString s = signature(false, false); + if (s.contains(QLatin1String("enum_type")) && s.contains(QLatin1String("operator|"))) + return true; + } + return false; +} + +/*! + Returns true if this function has overloads. Otherwise false. + First, if this function node's overload pointer is not nullptr, + return true. Next, if this function node's overload flag is true + return true. Finally, if this function's parent Aggregate has a + function by the same name as this one in its function map and + that function has overloads, return true. Otherwise return false. + + There is a failsafe way to test it under any circumstances. + */ +bool FunctionNode::hasOverloads() const +{ + if (m_nextOverload != nullptr) + return true; + if (m_overloadFlag) + return true; + if (parent()) + return parent()->hasOverloads(this); + return false; +} + +QT_END_NAMESPACE diff --git a/src/qdoc/functionnode.h b/src/qdoc/functionnode.h new file mode 100644 index 0000000000..55870b1ccd --- /dev/null +++ b/src/qdoc/functionnode.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FUNCTIONNODE_H +#define FUNCTIONNODE_H + +#include "aggregate.h" +#include "node.h" +#include "parameters.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class FunctionNode : public Node +{ +public: + enum Virtualness { NonVirtual, NormalVirtual, PureVirtual }; + + enum Metaness { + Plain, + Signal, + Slot, + Ctor, + Dtor, + CCtor, // copy constructor + MCtor, // move-copy constructor + MacroWithParams, + MacroWithoutParams, + Native, + CAssign, // copy-assignment operator + MAssign, // move-assignment operator + QmlSignal, + QmlSignalHandler, + QmlMethod, + JsSignal, + JsSignalHandler, + JsMethod + }; + + FunctionNode(Aggregate *parent, const QString &name); // C++ function (Plain) + FunctionNode(Metaness type, Aggregate *parent, const QString &name, bool attached = false); + + Node *clone(Aggregate *parent) override; + Metaness metaness() const { return m_metaness; } + QString metanessString() const; + bool changeMetaness(Metaness from, Metaness to); + void setMetaness(Metaness metaness) { m_metaness = metaness; } + Metaness setMetaness(const QString &metaness); + QString kindString() const; + static Metaness getMetaness(const QString &value); + static Metaness getMetanessFromTopic(const QString &topic); + static Genus getGenus(Metaness metaness); + + void setReturnType(const QString &type) { m_returnType = type; } + void setParentPath(const QStringList &path) { m_parentPath = path; } + void setVirtualness(const QString &value); + void setVirtualness(Virtualness virtualness) { m_virtualness = virtualness; } + void setVirtual() { m_virtualness = NormalVirtual; } + void setConst(bool b) { m_const = b; } + void setDefault(bool b) { m_default = b; } + void setStatic(bool b) { m_static = b; } + void setReimpFlag() { m_reimpFlag = true; } + void setOverridesThis(const QString &path) { m_overridesThis = path; } + + const QString &returnType() const { return m_returnType; } + QString virtualness() const; + bool isConst() const { return m_const; } + bool isDefault() const override { return m_default; } + bool isStatic() const override { return m_static; } + bool isOverload() const { return m_overloadFlag; } + bool isMarkedReimp() const override { return m_reimpFlag; } + bool isSomeCtor() const { return isCtor() || isCCtor() || isMCtor(); } + bool isMacroWithParams() const { return (m_metaness == MacroWithParams); } + bool isMacroWithoutParams() const { return (m_metaness == MacroWithoutParams); } + bool isMacro() const override { return (isMacroWithParams() || isMacroWithoutParams()); } + bool isObsolete() const override; + + bool isCppFunction() const { return m_metaness == Plain; } // Is this correct? + bool isSignal() const { return (m_metaness == Signal); } + bool isSlot() const { return (m_metaness == Slot); } + bool isCtor() const { return (m_metaness == Ctor); } + bool isDtor() const { return (m_metaness == Dtor); } + bool isCCtor() const { return (m_metaness == CCtor); } + bool isMCtor() const { return (m_metaness == MCtor); } + bool isCAssign() const { return (m_metaness == CAssign); } + bool isMAssign() const { return (m_metaness == MAssign); } + + bool isJsMethod() const { return (m_metaness == JsMethod); } + bool isJsSignal() const { return (m_metaness == JsSignal); } + bool isJsSignalHandler() const { return (m_metaness == JsSignalHandler); } + + bool isQmlMethod() const { return (m_metaness == QmlMethod); } + bool isQmlSignal() const { return (m_metaness == QmlSignal); } + bool isQmlSignalHandler() const { return (m_metaness == QmlSignalHandler); } + + bool isSpecialMemberFunction() const + { + return (isCtor() || isDtor() || isCCtor() || isMCtor() || isCAssign() || isMAssign()); + } + bool isNonvirtual() const { return (m_virtualness == NonVirtual); } + bool isVirtual() const { return (m_virtualness == NormalVirtual); } + bool isPureVirtual() const { return (m_virtualness == PureVirtual); } + bool returnsBool() const { return (m_returnType == QLatin1String("bool")); } + + Parameters ¶meters() { return m_parameters; } + const Parameters ¶meters() const { return m_parameters; } + bool isPrivateSignal() const { return m_parameters.isPrivateSignal(); } + void setParameters(const QString &signature) { m_parameters.set(signature); } + QString signature(bool values, bool noReturnType, bool templateParams = false) const override; + + const QString &overridesThis() const { return m_overridesThis; } + const NodeList &associatedProperties() const { return m_associatedProperties; } + const QStringList &parentPath() const { return m_parentPath; } + bool hasAssociatedProperties() const { return !m_associatedProperties.isEmpty(); } + bool hasOneAssociatedProperty() const { return (m_associatedProperties.size() == 1); } + Node *firstAssociatedProperty() const { return m_associatedProperties[0]; } + + QString element() const override { return parent()->name(); } + bool isAttached() const override { return m_attached; } + bool isQtQuickNode() const override { return parent()->isQtQuickNode(); } + QString qmlTypeName() const override { return parent()->qmlTypeName(); } + QString logicalModuleName() const override { return parent()->logicalModuleName(); } + QString logicalModuleVersion() const override { return parent()->logicalModuleVersion(); } + QString logicalModuleIdentifier() const override { return parent()->logicalModuleIdentifier(); } + + void debug() const; + + void setFinal(bool b) { m_isFinal = b; } + bool isFinal() const { return m_isFinal; } + + void setOverride(bool b) { m_isOverride = b; } + bool isOverride() const { return m_isOverride; } + + void setRef(bool b) { m_isRef = b; } + bool isRef() const { return m_isRef; } + + void setRefRef(bool b) { m_isRefRef = b; } + bool isRefRef() const { return m_isRefRef; } + + void setInvokable(bool b) { m_isInvokable = b; } + bool isInvokable() const { return m_isInvokable; } + + bool hasTag(const QString &tag) const override { return (m_tag == tag); } + void setTag(const QString &tag) { m_tag = tag; } + const QString &tag() const { return m_tag; } + bool compare(const Node *node, bool sameParent = true) const; + bool isIgnored() const; + bool hasOverloads() const; + void clearOverloadFlag() { m_overloadFlag = false; } + void setOverloadFlag() { m_overloadFlag = true; } + void setOverloadNumber(signed short number); + void appendOverload(FunctionNode *functionNode); + void removeOverload(FunctionNode *functionNode); + signed short overloadNumber() const { return m_overloadNumber; } + FunctionNode *nextOverload() { return m_nextOverload; } + void setNextOverload(FunctionNode *functionNode) { m_nextOverload = functionNode; } + FunctionNode *findPrimaryFunction(); + +private: + void addAssociatedProperty(PropertyNode *property); + + friend class Aggregate; + friend class PropertyNode; + + bool m_const : 1; + bool m_default : 1; + bool m_static : 1; + bool m_reimpFlag : 1; + bool m_attached : 1; + bool m_overloadFlag : 1; + bool m_isFinal : 1; + bool m_isOverride : 1; + bool m_isRef : 1; + bool m_isRefRef : 1; + bool m_isInvokable : 1; + Metaness m_metaness {}; + Virtualness m_virtualness {}; + signed short m_overloadNumber {}; + FunctionNode *m_nextOverload { nullptr }; + QString m_returnType {}; + QStringList m_parentPath {}; + QString m_overridesThis {}; + QString m_tag {}; + NodeList m_associatedProperties {}; + Parameters m_parameters {}; +}; + +QT_END_NAMESPACE + +#endif // FUNCTIONNODE_H diff --git a/src/qdoc/generator.cpp b/src/qdoc/generator.cpp index fc44fdbc50..5eaa7fbe9a 100644 --- a/src/qdoc/generator.cpp +++ b/src/qdoc/generator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -29,30 +29,45 @@ /* generator.cpp */ -#include -#include +#include "generator.h" + +#include "access.h" +#include "aggregate.h" +#include "classnode.h" #include "codemarker.h" +#include "collectionnode.h" #include "config.h" #include "doc.h" #include "editdistance.h" -#include "generator.h" -#include "loggingcategory.h" +#include "enumnode.h" +#include "examplenode.h" +#include "functionnode.h" +#include "node.h" #include "openedlist.h" +#include "propertynode.h" +#include "qdocdatabase.h" +#include "qmltypenode.h" #include "quoter.h" -#include "separator.h" +#include "sharedcommentnode.h" #include "tokenizer.h" -#include "qdocdatabase.h" +#include "typedefnode.h" +#include "utilities.h" + +#include +#include +#include + #ifndef QT_BOOTSTRAPPED -# include "QtCore/qurl.h" +# include "QtCore/qurl.h" #endif QT_BEGIN_NAMESPACE -Generator* Generator::currentGenerator_; +Generator *Generator::currentGenerator_; QStringList Generator::exampleDirs; QStringList Generator::exampleImgExts; -QMap > Generator::fmtLeftMaps; -QMap > Generator::fmtRightMaps; +QMap> Generator::fmtLeftMaps; +QMap> Generator::fmtRightMaps; QList Generator::generators; QStringList Generator::imageDirs; QStringList Generator::imageFiles; @@ -64,48 +79,18 @@ QSet Generator::outputFormats; QHash Generator::outputPrefixes; QHash Generator::outputSuffixes; QString Generator::project_; -QStringList Generator::scriptDirs; -QStringList Generator::scriptFiles; -QStringList Generator::styleDirs; -QStringList Generator::styleFiles; bool Generator::noLinkErrors_ = false; bool Generator::autolinkErrors_ = false; bool Generator::redirectDocumentationToDevNull_ = false; -Generator::QDocPass Generator::qdocPass_ = Generator::Neither; -bool Generator::qdocSingleExec_ = false; -bool Generator::qdocWriteQaPages_ = false; bool Generator::useOutputSubdirs_ = true; -bool Generator::useTimestamps_ = false; -QmlTypeNode* Generator::qmlTypeContext_ = nullptr; +QmlTypeNode *Generator::qmlTypeContext_ = nullptr; -static QRegExp tag("]*>"); +static QRegularExpression tag("]*>"); static QLatin1String amp("&"); static QLatin1String gt(">"); static QLatin1String lt("<"); static QLatin1String quot("""); -static inline void setDebugEnabled(bool v) -{ - const_cast(lcQdoc()).setEnabled(QtDebugMsg, v); -} - -void Generator::startDebugging(const QString& message) -{ - setDebugEnabled(true); - qCDebug(lcQdoc, "START DEBUGGING: %s", qPrintable(message)); -} - -void Generator::stopDebugging(const QString& message) -{ - qCDebug(lcQdoc, "STOP DEBUGGING: %s", qPrintable(message)); - setDebugEnabled(false); -} - -bool Generator::debugging() -{ - return lcQdoc().isEnabled(QtDebugMsg); -} - /*! Constructs the generator base class. Prepends the newly constructed generator to the list of output generators. @@ -113,16 +98,8 @@ bool Generator::debugging() available to the generator subclasses. */ Generator::Generator() - : inLink_(false), - inContents_(false), - inSectionHeading_(false), - inTableHeader_(false), - threeColumnEnumValueTable_(true), - showInternal_(false), - singleExec_(false), - numTableRows_(0) -{ - qdb_ = QDocDatabase::qdocDB(); +{ + m_qdb = QDocDatabase::qdocDB(); generators.prepend(this); } @@ -135,9 +112,7 @@ Generator::~Generator() generators.removeAll(this); } -void Generator::appendFullName(Text& text, - const Node *apparentNode, - const Node *relative, +void Generator::appendFullName(Text &text, const Node *apparentNode, const Node *relative, const Node *actualNode) { if (actualNode == nullptr) @@ -148,27 +123,22 @@ void Generator::appendFullName(Text& text, << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); } -void Generator::appendFullName(Text& text, - const Node *apparentNode, - const QString& fullName, +void Generator::appendFullName(Text &text, const Node *apparentNode, const QString &fullName, const Node *actualNode) { if (actualNode == nullptr) actualNode = apparentNode; text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, fullName) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, fullName) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); } -void Generator::appendFullNames(Text& text, const NodeList& nodes, const Node* relative) +void Generator::appendFullNames(Text &text, const NodeList &nodes, const Node *relative) { - NodeList::ConstIterator n = nodes.constBegin(); int index = 0; - while (n != nodes.constEnd()) { - appendFullName(text,*n,relative); - text << comma(index++,nodes.count()); - ++n; + for (const auto &node : nodes) { + appendFullName(text, node, relative); + text << Utilities::comma(index++, nodes.count()); } } @@ -177,7 +147,7 @@ void Generator::appendFullNames(Text& text, const NodeList& nodes, const Node* r \a text, so that is is a link to the documentation for that function. */ -void Generator::appendSignature(Text& text, const Node* node) +void Generator::appendSignature(Text &text, const Node *node) { text << Atom(Atom::LinkNode, CodeMarker::stringForNode(node)) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) @@ -190,87 +160,95 @@ void Generator::appendSignature(Text& text, const Node* node) nodes are in \a nodes. It uses the \a relative node and the \a marker for the generation. */ -void Generator::signatureList(const NodeList& nodes, const Node* relative, CodeMarker* marker) +void Generator::signatureList(const NodeList &nodes, const Node *relative, CodeMarker *marker) { Text text; int count = 0; text << Atom(Atom::ListLeft, QString("bullet")); - NodeList::ConstIterator n = nodes.constBegin(); - while (n != nodes.constEnd()) { + for (const auto &node : nodes) { text << Atom(Atom::ListItemNumber, QString::number(++count)); text << Atom(Atom::ListItemLeft, QString("bullet")); - appendSignature(text, *n); + appendSignature(text, node); text << Atom(Atom::ListItemRight, QString("bullet")); - ++n; } text << Atom(Atom::ListRight, QString("bullet")); generateText(text, relative, marker); } -int Generator::appendSortedNames(Text& text, const ClassNode* cn, const QList& rc) +int Generator::appendSortedNames(Text &text, const ClassNode *cn, const QList &rc) { - QList::ConstIterator r; - QMap classMap; - int index = 0; - - r = rc.constBegin(); - while (r != rc.constEnd()) { - ClassNode* rcn = (*r).node_; - if (rcn && rcn->access() == Node::Public && - !rcn->isInternal() && !rcn->doc().isEmpty()) { + QMap classMap; + for (const auto &relatedClass : rc) { + ClassNode *rcn = relatedClass.m_node; + if (rcn && rcn->isInAPI()) { Text className; appendFullName(className, rcn, cn); classMap[className.toString().toLower()] = className; } - ++r; } - QStringList classNames = classMap.keys(); - classNames.sort(); - - foreach (const QString &className, classNames) { + int index = 0; + const QStringList classNames = classMap.keys(); + for (const auto &className : classNames) { text << classMap[className]; - text << comma(index++, classNames.count()); + text << Utilities::comma(index++, classNames.count()); } return index; } -int Generator::appendSortedQmlNames(Text& text, const Node* base, const NodeList& subs) +int Generator::appendSortedQmlNames(Text &text, const Node *base, const NodeList &subs) { - QMap classMap; - int index = 0; + QMap classMap; - for (int i = 0; i < subs.size(); ++i) { - Text t; - if (!base->isQtQuickNode() || !subs[i]->isQtQuickNode() || - (base->logicalModuleName() == subs[i]->logicalModuleName())) { - appendFullName(t, subs[i], base); - classMap[t.toString().toLower()] = t; + for (const auto sub : subs) { + Text text; + if (!base->isQtQuickNode() || !sub->isQtQuickNode() + || (base->logicalModuleName() == sub->logicalModuleName())) { + appendFullName(text, sub, base); + classMap[text.toString().toLower()] = text; } } - QStringList names = classMap.keys(); - names.sort(); - - foreach (const QString &name, names) { + int index = 0; + const QStringList names = classMap.keys(); + for (const auto &name : names) { text << classMap[name]; - text << comma(index++, names.count()); + text << Utilities::comma(index++, names.count()); } return index; } /*! - For debugging qdoc. + Creates the file named \a fileName in the output directory + and returns a QFile pointing to this file. In particular, + this method deals with errors when opening the file: + the returned QFile is always valid and can be written to. + + \sa beginFilePage() */ -void Generator::writeOutFileNames() +QFile *Generator::openSubPageFile(const Node *node, const QString &fileName) { - QFile files("outputlist.txt"); - if (!files.open(QFile::WriteOnly)) - return; - QTextStream filesout(&files); - foreach (const QString &file, outFileNames_) { - filesout << file << "\n"; + QString path = outputDir() + QLatin1Char('/'); + if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty() + && !outputDir().endsWith(node->outputSubdirectory())) { + path += node->outputSubdirectory() + QLatin1Char('/'); } + path += fileName; + + auto outPath = redirectDocumentationToDevNull_ ? QStringLiteral("/dev/null") : path; + auto outFile = new QFile(outPath); + + if (!redirectDocumentationToDevNull_ && outFile->exists()) + qCDebug(lcQdoc) << "Output file already exists; overwriting" << qPrintable(outFile->fileName()); + + if (!outFile->open(QFile::WriteOnly)) { + node->location().fatal( + QStringLiteral("Cannot open output file '%1'").arg(outFile->fileName())); + } + + qCDebug(lcQdoc, "Writing: %s", qPrintable(path)); + outFileNames_ << fileName; + return outFile; } /*! @@ -281,45 +259,28 @@ void Generator::writeOutFileNames() \sa beginSubPage() */ -void Generator::beginFilePage(const Node* node, const QString& fileName) +void Generator::beginFilePage(const Node *node, const QString &fileName) { - QString path = outputDir() + QLatin1Char('/'); - if (Generator::useOutputSubdirs() && !node->outputSubdirectory().isEmpty() && - !outputDir().endsWith(node->outputSubdirectory())) - path += node->outputSubdirectory() + QLatin1Char('/'); - path += fileName; - - QFile* outFile = new QFile(redirectDocumentationToDevNull_ ? QStringLiteral("/dev/null") : path); - if (!redirectDocumentationToDevNull_ && outFile->exists()) - node->location().error(tr("Output file already exists; overwriting %1").arg(outFile->fileName())); - if (!outFile->open(QFile::WriteOnly)) - node->location().fatal(tr("Cannot open output file '%1'").arg(outFile->fileName())); - qCDebug(lcQdoc, "Writing: %s", qPrintable(path)); - outFileNames_ << fileName; - QTextStream* out = new QTextStream(outFile); - -#ifndef QT_NO_TEXTCODEC - if (outputCodec) - out->setCodec(outputCodec); -#endif + QFile *outFile = openSubPageFile(node, fileName); + QTextStream *out = new QTextStream(outFile); outStreamStack.push(out); } - /*! - Creates the file named \a fileName in the output directory. - Attaches a QTextStream to the created file, which is written - to all over the place using out(). This function calls another - function, \c beginFilePage(), which is really just most of what - this function used to contain. We needed a different version - that doesn't store the \a fileName in the \a node as the output - file name. - - \sa beginFilePage() - */ -void Generator::beginSubPage(const Node* node, const QString& fileName) +/*! + Creates the file named \a fileName in the output directory. + Attaches a QTextStream to the created file, which is written + to all over the place using out(). This function calls another + function, \c beginFilePage(), which is really just most of what + this function used to contain. We needed a different version + that doesn't store the \a fileName in the \a node as the output + file name. + + \sa beginFilePage() +*/ +void Generator::beginSubPage(const Node *node, const QString &fileName) { beginFilePage(node, fileName); - const_cast(node)->setOutputFileName(fileName); + const_cast(node)->setOutputFileName(fileName); } /*! @@ -336,7 +297,7 @@ void Generator::endSubPage() /* the code below is effectively equivalent to: - input.replace(QRegExp("[^A-Za-z0-9]+"), " "); + input.replace(QRegularExpression("[^A-Za-z0-9]+"), " "); input = input.trimmed(); input.replace(QLatin1Char(' '), QLatin1Char('-')); input = input.toLower(); @@ -353,11 +314,10 @@ static void transmogrify(QString &input, QString &output) uint u = c.unicode(); if (u >= 'A' && u <= 'Z') u += 'a' - 'A'; - if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) { + if ((u >= 'a' && u <= 'z') || (u >= '0' && u <= '9')) { output += QLatin1Char(u); begun = true; - } - else if (begun) { + } else if (begun) { output += QLatin1Char('-'); begun = false; } @@ -402,8 +362,8 @@ QString Generator::fileBase(const Node *node) const if (node->isExample()) { base.append(QLatin1String("-example")); } - } else if (node->isQmlType() || node->isQmlBasicType() || - node->isJsType() || node->isJsBasicType()) { + } else if (node->isQmlType() || node->isQmlBasicType() || node->isJsType() + || node->isJsBasicType()) { base = node->name(); /* To avoid file name conflicts in the html directory, @@ -411,11 +371,10 @@ QString Generator::fileBase(const Node *node) const to the file name. The suffix, if one exists, is appended to the module name. */ - if (!node->logicalModuleName().isEmpty()) { - base.prepend(node->logicalModuleName() - + outputSuffix(node) - + QLatin1Char('-')); - } + if (!node->logicalModuleName().isEmpty() + && (!node->logicalModule()->isInternal() || m_showInternal)) + base.prepend(node->logicalModuleName() + outputSuffix(node) + QLatin1Char('-')); + base.prepend(outputPrefix(node)); } else if (node->isProxyNode()) { base = node->name(); @@ -431,7 +390,7 @@ QString Generator::fileBase(const Node *node) const p = pp; } if (node->isNamespace() && !node->name().isEmpty()) { - const NamespaceNode* ns = static_cast(node); + const NamespaceNode *ns = static_cast(node); if (!ns->isDocumentedHere()) { base.append(QLatin1String("-sub-")); base.append(ns->tree()->camelCaseModuleName()); @@ -441,16 +400,19 @@ QString Generator::fileBase(const Node *node) const QString res; transmogrify(base, res); - Node* n = const_cast(node); + Node *n = const_cast(node); n->setFileNameBase(res); return res; } /*! Constructs an href link from an example file name, which - is a path to the example file. + is a path to the example file. If \a fileExtension is + empty (default value), retrieve the file extension from + the generator. */ -QString Generator::linkForExampleFile(const QString &path, const Node *parent) +QString Generator::linkForExampleFile(const QString &path, const Node *parent, + const QString &fileExt) { QString link = path; QString modPrefix(parent->physicalModuleName()); @@ -461,17 +423,36 @@ QString Generator::linkForExampleFile(const QString &path, const Node *parent) QString res; transmogrify(link, res); res.append(QLatin1Char('.')); - res.append(fileExtension()); + res.append(fileExt); + if (fileExt.isEmpty()) + res.append(fileExtension()); return res; } +/*! + Helper function to construct a title for a file or image page + included in an example. +*/ +QString Generator::exampleFileTitle(const ExampleNode *relative, const QString &fileName) +{ + QString suffix; + if (relative->files().contains(fileName)) + suffix = QLatin1String(" Example File"); + else if (relative->images().contains(fileName)) + suffix = QLatin1String(" Image File"); + else + return suffix; + + return fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1) + suffix; +} + /*! If the \a node has a URL, return the URL as the file name. Otherwise, construct the file name from the fileBase() and either the provided \a extension or fileExtension(), and return the constructed name. */ -QString Generator::fileName(const Node* node, const QString &extension) const +QString Generator::fileName(const Node *node, const QString &extension) const { if (!node->url().isEmpty()) return node->url(); @@ -480,7 +461,7 @@ QString Generator::fileName(const Node* node, const QString &extension) const return extension.isNull() ? name + fileExtension() : name + extension; } -QString Generator::cleanRef(const QString& ref) +QString Generator::cleanRef(const QString &ref) { QString clean; @@ -491,9 +472,7 @@ QString Generator::cleanRef(const QString& ref) const QChar c = ref[0]; const uint u = c.unicode(); - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9')) { + if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9')) { clean += c; } else if (u == '~') { clean += "dtor."; @@ -503,13 +482,11 @@ QString Generator::cleanRef(const QString& ref) clean += QLatin1Char('A'); } - for (int i = 1; i < (int) ref.length(); i++) { + for (int i = 1; i < ref.length(); i++) { const QChar c = ref[i]; const uint u = c.unicode(); - if ((u >= 'a' && u <= 'z') || - (u >= 'A' && u <= 'Z') || - (u >= '0' && u <= '9') || u == '-' || - u == '_' || u == ':' || u == '.') { + if ((u >= 'a' && u <= 'z') || (u >= 'A' && u <= 'Z') || (u >= '0' && u <= '9') || u == '-' + || u == '_' || u == ':' || u == '.') { clean += c; } else if (c.isSpace()) { clean += QLatin1Char('-'); @@ -527,18 +504,18 @@ QString Generator::cleanRef(const QString& ref) clean += QLatin1Char('#'); } else { clean += QLatin1Char('-'); - clean += QString::number((int)u, 16); + clean += QString::number(static_cast(u), 16); } } return clean; } -QMap& Generator::formattingLeftMap() +QMap &Generator::formattingLeftMap() { return fmtLeftMaps[format()]; } -QMap& Generator::formattingRightMap() +QMap &Generator::formattingRightMap() { return fmtRightMaps[format()]; } @@ -576,26 +553,23 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension(); else return QString(); - } - else if (node->isQmlType() || node->isQmlBasicType() || - node->isJsType() || node->isJsBasicType()) { + } else if (node->isQmlType() || node->isQmlBasicType() || node->isJsType() + || node->isJsBasicType()) { QString fb = fileBase(node); if (fb.startsWith(outputPrefix(node))) return fb + QLatin1Char('.') + currentGenerator()->fileExtension(); else { QString mq; if (!node->logicalModuleName().isEmpty()) { - mq = node->logicalModuleName().replace(QChar('.'),QChar('-')); + mq = node->logicalModuleName().replace(QChar('.'), QChar('-')); mq = mq.toLower() + QLatin1Char('-'); } - return fdl + outputPrefix(node) + mq + fileBase(node) + - QLatin1Char('.') + currentGenerator()->fileExtension(); + return fdl + outputPrefix(node) + mq + fileBase(node) + QLatin1Char('.') + + currentGenerator()->fileExtension(); } - } - else if (node->isTextPageNode() || node->isCollectionNode()) { + } else if (node->isTextPageNode() || node->isCollectionNode()) { parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension(); - } - else if (fileBase(node).isEmpty()) + } else if (fileBase(node).isEmpty()) return QString(); Node *parentNode = nullptr; @@ -614,8 +588,7 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) case Node::Proxy: parentName = fileBase(node) + QLatin1Char('.') + currentGenerator()->fileExtension(); break; - case Node::Function: - { + case Node::Function: { const FunctionNode *fn = static_cast(node); switch (fn->metaness()) { case FunctionNode::JsSignal: @@ -636,8 +609,8 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) else if (fn->hasOneAssociatedProperty() && fn->doc().isEmpty()) return fullDocumentLocation(fn->firstAssociatedProperty()); else if (fn->overloadNumber() > 0) - anchorRef = QLatin1Char('#') + cleanRef(fn->name()) - + QLatin1Char('-') + QString::number(fn->overloadNumber()); + anchorRef = QLatin1Char('#') + cleanRef(fn->name()) + QLatin1Char('-') + + QString::number(fn->overloadNumber()); else anchorRef = QLatin1Char('#') + cleanRef(fn->name()); break; @@ -652,18 +625,21 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) case Node::Enum: anchorRef = QLatin1Char('#') + node->name() + "-enum"; break; - case Node::Typedef: - { - const TypedefNode *tdef = static_cast(node); - if (tdef->associatedEnum()) { + case Node::Typedef: { + const auto *tdef = static_cast(node); + if (tdef->associatedEnum()) return fullDocumentLocation(tdef->associatedEnum()); - } + } Q_FALLTHROUGH(); + case Node::TypeAlias: anchorRef = QLatin1Char('#') + node->name() + "-typedef"; break; - } case Node::Property: anchorRef = QLatin1Char('#') + node->name() + "-prop"; break; + case Node::SharedComment: { + if (!node->isPropertyGroup()) + break; + } Q_FALLTHROUGH(); case Node::JsProperty: case Node::QmlProperty: if (node->isAttached()) @@ -678,15 +654,15 @@ QString Generator::fullDocumentLocation(const Node *node, bool useSubdir) case Node::QmlType: case Node::Page: case Node::Group: + case Node::HeaderFile: case Node::Module: case Node::JsModule: - case Node::QmlModule: - { + case Node::QmlModule: { parentName = fileBase(node); - parentName.replace(QLatin1Char('/'), QLatin1Char('-')).replace(QLatin1Char('.'), QLatin1Char('-')); + parentName.replace(QLatin1Char('/'), QLatin1Char('-')) + .replace(QLatin1Char('.'), QLatin1Char('-')); parentName += QLatin1Char('.') + currentGenerator()->fileExtension(); - } - break; + } break; default: break; } @@ -707,43 +683,32 @@ void Generator::generateAlsoList(const Node *node, CodeMarker *marker) if (!alsoList.isEmpty()) { Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "See also " - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD); + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "See also " + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); for (int i = 0; i < alsoList.size(); ++i) - text << alsoList.at(i) << separator(i, alsoList.size()); + text << alsoList.at(i) << Utilities::separator(i, alsoList.size()); text << Atom::ParaRight; generateText(text, node, marker); } } -const Atom *Generator::generateAtomList(const Atom *atom, - const Node *relative, - CodeMarker *marker, - bool generate, - int &numAtoms) +const Atom *Generator::generateAtomList(const Atom *atom, const Node *relative, CodeMarker *marker, + bool generate, int &numAtoms) { while (atom != nullptr) { if (atom->type() == Atom::FormatIf) { int numAtoms0 = numAtoms; bool rightFormat = canHandleFormat(atom->string()); - atom = generateAtomList(atom->next(), - relative, - marker, - generate && rightFormat, + atom = generateAtomList(atom->next(), relative, marker, generate && rightFormat, numAtoms); if (atom == nullptr) return nullptr; if (atom->type() == Atom::FormatElse) { ++numAtoms; - atom = generateAtomList(atom->next(), - relative, - marker, - generate && !rightFormat, + atom = generateAtomList(atom->next(), relative, marker, generate && !rightFormat, numAtoms); if (atom == nullptr) return nullptr; @@ -751,23 +716,17 @@ const Atom *Generator::generateAtomList(const Atom *atom, if (atom->type() == Atom::FormatEndif) { if (generate && numAtoms0 == numAtoms) { - relative->location().warning(tr("Output format %1 not handled %2") - .arg(format()).arg(outFileName())); + relative->location().warning(QStringLiteral("Output format %1 not handled %2") + .arg(format()) + .arg(outFileName())); Atom unhandledFormatAtom(Atom::UnhandledFormat, format()); - generateAtomList(&unhandledFormatAtom, - relative, - marker, - generate, - numAtoms); + generateAtomList(&unhandledFormatAtom, relative, marker, generate, numAtoms); } atom = atom->next(); } - } - else if (atom->type() == Atom::FormatElse || - atom->type() == Atom::FormatEndif) { + } else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) { return atom; - } - else { + } else { int n = 1; if (generate) { n += generateAtom(atom, relative, marker); @@ -786,74 +745,71 @@ const Atom *Generator::generateAtomList(const Atom *atom, */ void Generator::generateBody(const Node *node, CodeMarker *marker) { + const FunctionNode *fn = node->isFunction() ? static_cast(node) : nullptr; if (!node->hasDoc() && !node->hasSharedDoc()) { /* Test for special function, like a destructor or copy constructor, that has no documentation. */ - if (node->isFunction()) { - const FunctionNode* func = static_cast(node); - if (func->isDtor()) { + if (fn) { + if (fn->isDtor()) { Text text; text << "Destroys the instance of "; - text << func->parent()->name() << "."; - if (func->isVirtual()) + text << fn->parent()->name() << "."; + if (fn->isVirtual()) text << " The destructor is virtual."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (func->isCtor()) { + } else if (fn->isCtor()) { Text text; text << "Default constructs an instance of "; - text << func->parent()->name() << "."; + text << fn->parent()->name() << "."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (func->isCCtor()) { + } else if (fn->isCCtor()) { Text text; text << "Copy constructor."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (func->isMCtor()) { + } else if (fn->isMCtor()) { Text text; text << "Move-copy constructor."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (func->isCAssign()) { + } else if (fn->isCAssign()) { Text text; text << "Copy-assignment operator."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (func->isMAssign()) { + } else if (fn->isMAssign()) { Text text; text << "Move-assignment operator."; out() << "

"; generateText(text, node, marker); out() << "

"; - } - else if (!node->isWrapper() && !node->isMarkedReimp()) { - if (!func->isIgnored()) // undocumented functions added by Q_OBJECT - node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); + } else if (!node->isWrapper() && !node->isMarkedReimp()) { + if (!fn->isIgnored()) // undocumented functions added by Q_OBJECT + node->location().warning(QStringLiteral("No documentation for '%1'") + .arg(node->plainSignature())); } } else if (!node->isWrapper() && !node->isMarkedReimp()) { // Don't require documentation of things defined in Q_GADGET if (node->name() != QLatin1String("QtGadgetHelper")) - node->location().warning(tr("No documentation for '%1'").arg(node->plainSignature())); + node->location().warning( + QStringLiteral("No documentation for '%1'").arg(node->plainSignature())); } - } - else if (!node->isSharingComment()) { - if (node->isFunction()) { - const FunctionNode *fn = static_cast(node); - if (!fn->overridesThis().isEmpty()) - generateReimplementsClause(fn, marker); + } else if (!node->isSharingComment()) { + // Reimplements clause and type alias info precede body text + if (fn && !fn->overridesThis().isEmpty()) + generateReimplementsClause(fn, marker); + else if (node->isProperty()) { + if (static_cast(node)->propertyType() != PropertyNode::Standard) + generateAddendum(node, BindableProperty, marker); } if (!generateText(node->doc().body(), node, marker)) { @@ -861,70 +817,78 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) return; } + if (fn) { + if (fn->isQmlSignal()) + generateAddendum(node, QmlSignalHandler, marker); + if (fn->isPrivateSignal()) + generateAddendum(node, PrivateSignal, marker); + if (fn->isInvokable()) + generateAddendum(node, Invokable, marker); + if (fn->hasAssociatedProperties()) + generateAddendum(node, AssociatedProperties, marker); + } + + // Generate warnings if (node->isEnumType()) { - const EnumNode *enume = (const EnumNode *) node; + const EnumNode *enume = static_cast(node); QSet definedItems; - QList::ConstIterator it = enume->items().constBegin(); - while (it != enume->items().constEnd()) { - definedItems.insert((*it).name()); - ++it; - } + const QList &items = enume->items(); + for (const auto &item : items) + definedItems.insert(item.name()); const auto &documentedItemList = enume->doc().enumItemNames(); QSet documentedItems(documentedItemList.cbegin(), documentedItemList.cend()); - QSet allItems = definedItems + documentedItems; - if (allItems.count() > definedItems.count() || - allItems.count() > documentedItems.count()) { - QSet::ConstIterator a = allItems.constBegin(); - while (a != allItems.constEnd()) { - if (!definedItems.contains(*a)) { + const QSet allItems = definedItems + documentedItems; + if (allItems.count() > definedItems.count() + || allItems.count() > documentedItems.count()) { + for (const auto &it : allItems) { + if (!definedItems.contains(it)) { QString details; - QString best = nearestName(*a, definedItems); + QString best = nearestName(it, definedItems); if (!best.isEmpty() && !documentedItems.contains(best)) - details = tr("Maybe you meant '%1'?").arg(best); - - node->doc().location().warning(tr("No such enum item '%1' in %2") - .arg(*a).arg(node->plainFullName()), details); + details = QStringLiteral("Maybe you meant '%1'?").arg(best); + + node->doc().location().warning( + QStringLiteral("No such enum item '%1' in %2") + .arg(it) + .arg(node->plainFullName()), + details); + } else if (!documentedItems.contains(it)) { + node->doc().location().warning( + QStringLiteral("Undocumented enum item '%1' in %2") + .arg(it) + .arg(node->plainFullName())); } - else if (!documentedItems.contains(*a)) { - node->doc().location().warning(tr("Undocumented enum item '%1' in %2") - .arg(*a).arg(node->plainFullName())); - } - ++a; } } - } else if (node->isFunction()) { - const FunctionNode *fn = static_cast(node); - QSet declaredNames; - fn->parameters().getNames(declaredNames); - QSet documentedNames = fn->doc().parameterNames(); + } else if (fn) { + const QSet declaredNames = fn->parameters().getNames(); + const QSet documentedNames = fn->doc().parameterNames(); if (declaredNames != documentedNames) { - QSet::const_iterator i = declaredNames.constBegin(); - while (i != declaredNames.constEnd()) { - if (!documentedNames.contains(*i)) { + for (const auto &name : declaredNames) { + if (!documentedNames.contains(name)) { if (fn->isActive() || fn->isPreliminary()) { if (!fn->isMarkedReimp() && !fn->isOverload()) { fn->doc().location().warning( - tr("Undocumented parameter '%1' in %2") - .arg(*i).arg(node->plainFullName())); + QStringLiteral("Undocumented parameter '%1' in %2") + .arg(name) + .arg(node->plainFullName())); } } } - ++i; } - i = documentedNames.constBegin(); - while (i != documentedNames.constEnd()) { - if (!declaredNames.contains(*i)) { - QString best = nearestName(*i, declaredNames); + for (const auto &name : documentedNames) { + if (!declaredNames.contains(name)) { + QString best = nearestName(name, declaredNames); QString details; if (!best.isEmpty()) - details = tr("Maybe you meant '%1'?").arg(best); - fn->doc().location().warning(tr("No such parameter '%1' in %2") - .arg(*i).arg(fn->plainFullName()), + details = QStringLiteral("Maybe you meant '%1'?").arg(best); + fn->doc().location().warning(QStringLiteral("No such parameter '%1' in %2") + .arg(name) + .arg(fn->plainFullName()), details); } - ++i; } } /* @@ -932,70 +896,101 @@ void Generator::generateBody(const Node *node, CodeMarker *marker) for all functions with a return type. mws 13/12/2018 */ - if (!fn->isObsolete() && fn->returnsBool() && - !fn->isMarkedReimp() && !fn->isOverload()) { + if (!fn->isObsolete() && fn->returnsBool() && !fn->isMarkedReimp() + && !fn->isOverload()) { if (!fn->doc().body().contains("return")) - node->doc().location().warning(tr("Undocumented return value " + node->doc().location().warning( + QStringLiteral("Undocumented return value " "(hint: use 'return' or 'returns' in the text")); } } } + generateRequiredLinks(node, marker); +} + +/*! + Generates either a link to the project folder for example \a node, or a list + of links files/images if 'url.examples config' variable is not defined. - // For examples, generate either a link to the project directory - // (if url.examples is defined), or a list of files/images. - if (node->isExample()) { - const ExampleNode* en = static_cast(node); - QString exampleUrl = config()->getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES); - if (!exampleUrl.isEmpty()) { - generateLinkToExample(en, marker, exampleUrl); - } else if (!en->noAutoList()) { - generateFileList(en, marker, false); - generateFileList(en, marker, true); + Does nothing for non-example nodes. +*/ +void Generator::generateRequiredLinks(const Node *node, CodeMarker *marker) +{ + if (!node->isExample()) + return; + + const ExampleNode *en = static_cast(node); + QString exampleUrl = Config::instance().getString(CONFIG_URL + Config::dot + CONFIG_EXAMPLES); + + if (exampleUrl.isEmpty()) { + if (!en->noAutoList()) { + generateFileList(en, marker, false); // files + generateFileList(en, marker, true); // images } + } else { + generateLinkToExample(en, marker, exampleUrl); } } /*! - Generates a link to the project folder for example node \a en. - \a baseUrl is the base URL - path information is available in - the example node's name() and 'examplesinstallpath' configuration - variable. + Generates an external link to the project folder for example \a node. + The path to the example replaces a placeholder '\1' character if + one is found in the \a baseUrl string. If no such placeholder is found, + the path is appended to \a baseUrl, after a '/' character if \a baseUrl did + not already end in one. */ -void Generator::generateLinkToExample(const ExampleNode *en, - CodeMarker *marker, +void Generator::generateLinkToExample(const ExampleNode *en, CodeMarker *marker, const QString &baseUrl) { - Text text; - QString exampleUrl(baseUrl); - - if (!exampleUrl.contains("\1")) { - if (!exampleUrl.endsWith("/")) - exampleUrl += "/"; - exampleUrl += "\1"; - } - - // Name of the example node is the path, relative to install path - QStringList path = QStringList() - << config()->getString(CONFIG_EXAMPLESINSTALLPATH) - << en->name(); - path.removeAll({}); - - QString link; + QString exampleUrl(baseUrl); + QString link; #ifndef QT_BOOTSTRAPPED - link = QUrl(baseUrl).host(); + link = QUrl(exampleUrl).host(); #endif - if (!link.isEmpty()) - link.prepend(" @ "); - link.prepend("Example project"); + if (!link.isEmpty()) + link.prepend(" @ "); + link.prepend("Example project"); + + const QLatin1Char separator('/'); + const QLatin1Char placeholder('\1'); + if (!exampleUrl.contains(placeholder)) { + if (!exampleUrl.endsWith(separator)) + exampleUrl += separator; + exampleUrl += placeholder; + } - text << Atom::ParaLeft - << Atom(Atom::Link, exampleUrl.replace("\1", path.join("/"))) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, link) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom::ParaRight; + // Construct a path to the example; / + QString pathRoot; + QStringMultiMap *metaTagMap = en->doc().metaTagMap(); + if (metaTagMap) + pathRoot = metaTagMap->value(QLatin1String("installpath")); + if (pathRoot.isEmpty()) + pathRoot = Config::instance().getString(CONFIG_EXAMPLESINSTALLPATH); + QStringList path = QStringList() << pathRoot << en->name(); + path.removeAll(QString()); - generateText(text, 0, marker); + Text text; + text << Atom::ParaLeft + << Atom(Atom::Link, exampleUrl.replace(placeholder, path.join(separator))) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, link) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom::ParaRight; + + generateText(text, nullptr, marker); +} + +void Generator::addImageToCopy(const ExampleNode *en, const QString &file) +{ + QDir dirInfo; + QString userFriendlyFilePath; + const QString prefix("/images/used-in-examples/"); + QString srcPath = Config::findFile(en->location(), QStringList(), exampleDirs, file, + exampleImgExts, &userFriendlyFilePath); + outFileNames_ << prefix.mid(1) + userFriendlyFilePath; + userFriendlyFilePath.truncate(userFriendlyFilePath.lastIndexOf('/')); + QString imgOutDir = outDir_ + prefix + userFriendlyFilePath; + if (!dirInfo.mkpath(imgOutDir)) + en->location().fatal(QStringLiteral("Cannot create output directory '%1'").arg(imgOutDir)); + Config::copyFile(en->location(), srcPath, file, imgOutDir); } /*! @@ -1005,7 +1000,7 @@ void Generator::generateLinkToExample(const ExampleNode *en, example. The images are copied into a subtree of \c{...doc/html/images/used-in-examples/...} */ -void Generator::generateFileList(const ExampleNode* en, CodeMarker* marker, bool images) +void Generator::generateFileList(const ExampleNode *en, CodeMarker *marker, bool images) { Text text; OpenedList openedList(OpenedList::Bullet); @@ -1017,7 +1012,7 @@ void Generator::generateFileList(const ExampleNode* en, CodeMarker* marker, bool paths = en->images(); tag = "Images:"; atomType = Atom::ExampleImageLink; - } else { //files + } else { // files paths = en->files(); tag = "Files:"; } @@ -1027,40 +1022,19 @@ void Generator::generateFileList(const ExampleNode* en, CodeMarker* marker, bool text << Atom(Atom::ListLeft, openedList.styleString()); QString path; - foreach (QString file, paths) { + for (const auto &file : qAsConst(paths)) { if (images) { - if (!file.isEmpty()) { - QDir dirInfo; - QString userFriendlyFilePath; - const QString prefix("/images/used-in-examples/"); - QString srcPath = Config::findFile(en->location(), - QStringList(), - exampleDirs, - file, - exampleImgExts, - &userFriendlyFilePath); - outFileNames_ << prefix.mid(1) + userFriendlyFilePath; - userFriendlyFilePath.truncate(userFriendlyFilePath.lastIndexOf('/')); - QString imgOutDir = outDir_ + prefix + userFriendlyFilePath; - if (!dirInfo.mkpath(imgOutDir)) - en->location().fatal(tr("Cannot create output directory '%1'").arg(imgOutDir)); - Config::copyFile(en->location(), srcPath, file, imgOutDir); - } - - } - else { + if (!file.isEmpty()) + addImageToCopy(en, file); + } else { generateExampleFilePage(en, file, marker); } openedList.next(); text << Atom(Atom::ListItemNumber, openedList.numberString()) - << Atom(Atom::ListItemLeft, openedList.styleString()) - << Atom::ParaLeft - << Atom(atomType, file) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << file - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom::ParaRight + << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft + << Atom(atomType, file) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << file + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString()); path = file; } @@ -1069,48 +1043,26 @@ void Generator::generateFileList(const ExampleNode* en, CodeMarker* marker, bool generateText(text, en, marker); } -void Generator::generateInheritedBy(const ClassNode *classe, CodeMarker *marker) -{ - if (!classe->derivedClasses().isEmpty()) { - Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Inherited by: " - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD); - - appendSortedNames(text, classe, classe->derivedClasses()); - text << Atom::ParaRight; - generateText(text, classe, marker); - } -} - void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) { - QList::ConstIterator r; - int index; - if (!classe->baseClasses().isEmpty()) { Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Inherits: " - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD); - - r = classe->baseClasses().constBegin(); - index = 0; - while (r != classe->baseClasses().constEnd()) { - if ((*r).node_) { - appendFullName(text, (*r).node_, classe); - - if ((*r).access_ == Node::Protected) { + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Inherits: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + + int index = 0; + const QList &baseClasses = classe->baseClasses(); + for (const auto &cls : baseClasses) { + if (cls.m_node) { + appendFullName(text, cls.m_node, classe); + + if (cls.m_access == Access::Protected) { text << " (protected)"; - } - else if ((*r).access_ == Node::Private) { + } else if (cls.m_access == Access::Private) { text << " (private)"; } - text << separator(index++, classe->baseClasses().count()); + text << Utilities::separator(index++, classe->baseClasses().count()); } - ++r; } text << Atom::ParaRight; generateText(text, classe, marker); @@ -1120,13 +1072,13 @@ void Generator::generateInherits(const ClassNode *classe, CodeMarker *marker) /*! Recursive writing of HTML files from the root \a node. */ -void Generator::generateDocumentation(Node* node) +void Generator::generateDocumentation(Node *node) { if (!node->url().isNull()) return; if (node->isIndexNode()) return; - if (node->isInternal() && !showInternal_) + if (node->isInternal() && !m_showInternal) return; if (node->isExternalPage()) return; @@ -1160,9 +1112,9 @@ void Generator::generateDocumentation(Node* node) members of cn in the other modules and add them to the members list. */ - CollectionNode* cn = static_cast(node); + CollectionNode *cn = static_cast(node); if (cn->wasSeen()) { - qdb_->mergeCollections(cn); + m_qdb->mergeCollections(cn); beginSubPage(node, fileName(node)); generateCollectionNode(cn, marker); endSubPage(); @@ -1172,45 +1124,46 @@ void Generator::generateDocumentation(Node* node) // other use cases pop up. QString name = cn->name().toLower(); name.replace(QChar(' '), QString("-")); - QString filename = cn->tree()->physicalModuleName() + "-" + name + "." + fileExtension(); + QString filename = + cn->tree()->physicalModuleName() + "-" + name + "." + fileExtension(); beginSubPage(node, filename); generateGenericCollectionPage(cn, marker); endSubPage(); } } else if (node->isTextPageNode()) { beginSubPage(node, fileName(node)); - generatePageNode(static_cast(node), marker); + generatePageNode(static_cast(node), marker); endSubPage(); } else if (node->isAggregate()) { - if ((node->isClassNode() || node->isHeader() || node->isNamespace()) && - node->docMustBeGenerated()) { + if ((node->isClassNode() || node->isHeader() || node->isNamespace()) + && node->docMustBeGenerated()) { beginSubPage(node, fileName(node)); - generateCppReferencePage(static_cast(node), marker); + generateCppReferencePage(static_cast(node), marker); endSubPage(); } else if (node->isQmlType() || node->isJsType()) { beginSubPage(node, fileName(node)); - QmlTypeNode* qcn = static_cast(node); + QmlTypeNode *qcn = static_cast(node); generateQmlTypePage(qcn, marker); endSubPage(); } else if (node->isQmlBasicType() || node->isJsBasicType()) { beginSubPage(node, fileName(node)); - QmlBasicTypeNode* qbtn = static_cast(node); + QmlBasicTypeNode *qbtn = static_cast(node); generateQmlBasicTypePage(qbtn, marker); endSubPage(); } else if (node->isProxyNode()) { beginSubPage(node, fileName(node)); - generateProxyPage(static_cast(node), marker); + generateProxyPage(static_cast(node), marker); endSubPage(); } } } if (node->isAggregate()) { - Aggregate* aggregate = static_cast(node); + Aggregate *aggregate = static_cast(node); const NodeList &children = aggregate->childNodes(); - foreach (Node *n, children) { - if (n->isPageNode() && !n->isPrivate()) - generateDocumentation(n); + for (auto *node : children) { + if (node->isPageNode() && !node->isPrivate()) + generateDocumentation(node); } } } @@ -1218,19 +1171,17 @@ void Generator::generateDocumentation(Node* node) /*! Generate a list of maintainers in the output */ -void Generator::generateMaintainerList(const Aggregate* node, CodeMarker* marker) +void Generator::generateMaintainerList(const Aggregate *node, CodeMarker *marker) { - QStringList sl = getMetadataElements(node,"maintainer"); + QStringList sl = getMetadataElements(node, "maintainer"); if (!sl.isEmpty()) { Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Maintained by: " - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD); + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Maintained by: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); for (int i = 0; i < sl.size(); ++i) - text << sl.at(i) << separator(i, sl.size()); + text << sl.at(i) << Utilities::separator(i, sl.size()); text << Atom::ParaRight; generateText(text, node, marker); @@ -1241,8 +1192,7 @@ void Generator::generateMaintainerList(const Aggregate* node, CodeMarker* marker Output the "Inherit by" list for the QML element, if it is inherited by any other elements. */ -void Generator::generateQmlInheritedBy(const QmlTypeNode* qcn, - CodeMarker* marker) +void Generator::generateQmlInheritedBy(const QmlTypeNode *qcn, CodeMarker *marker) { if (qcn) { NodeList subs; @@ -1261,12 +1211,10 @@ void Generator::generateQmlInheritedBy(const QmlTypeNode* qcn, Extract sections of markup text surrounded by \e qmltext and \e endqmltext and output them. */ -bool Generator::generateQmlText(const Text& text, - const Node *relative, - CodeMarker *marker, - const QString& /* qmlName */ ) +bool Generator::generateQmlText(const Text &text, const Node *relative, CodeMarker *marker, + const QString & /* qmlName */) { - const Atom* atom = text.firstAtom(); + const Atom *atom = text.firstAtom(); bool result = false; if (atom != nullptr) { @@ -1292,13 +1240,30 @@ void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *m { if (!fn->overridesThis().isEmpty()) { if (fn->parent()->isClassNode()) { - ClassNode* cn = static_cast(fn->parent()); + ClassNode *cn = static_cast(fn->parent()); const FunctionNode *overrides = cn->findOverriddenFunction(fn); if (overrides && !overrides->isPrivate() && !overrides->parent()->isPrivate()) { + if (overrides->hasDoc()) { + Text text; + text << Atom::ParaLeft << "Reimplements: "; + QString fullName = + overrides->parent()->name() + "::" + overrides->signature(false, true); + appendFullName(text, overrides->parent(), fullName, overrides); + text << "." << Atom::ParaRight; + generateText(text, fn, marker); + } else { + fn->doc().location().warning( + QStringLiteral("Illegal \\reimp; no documented virtual function for %1") + .arg(overrides->plainSignature())); + } + return; + } + const PropertyNode *sameName = cn->findOverriddenProperty(fn); + if (sameName && sameName->hasDoc()) { Text text; - text << Atom::ParaLeft << "Reimplements: "; - QString fullName = overrides->parent()->name() + "::" + overrides->signature(false, true); - appendFullName(text, overrides->parent(), fullName, overrides); + text << Atom::ParaLeft << "Reimplements an access function for property: "; + QString fullName = sameName->parent()->name() + "::" + sameName->name(); + appendFullName(text, sameName->parent(), fullName, sameName); text << "." << Atom::ParaRight; generateText(text, fn, marker); } @@ -1306,28 +1271,26 @@ void Generator::generateReimplementsClause(const FunctionNode *fn, CodeMarker *m } } +QString Generator::formatSince(const Node *node) +{ + QStringList since = node->since().split(QLatin1Char(' ')); + + // If there is only one argument, assume it is the Qt version number. + if (since.count() == 1) + return "Qt " + since[0]; + + // Otherwise, use the original string. + return node->since(); +} + void Generator::generateSince(const Node *node, CodeMarker *marker) { if (!node->since().isEmpty()) { Text text; - text << Atom::ParaLeft - << "This " - << typeString(node); + text << Atom::ParaLeft << "This " << typeString(node) << " was introduced "; if (node->isEnumType()) - text << " was introduced or modified in "; - else - text << " was introduced in "; - - QStringList since = node->since().split(QLatin1Char(' ')); - if (since.count() == 1) { - // If there is only one argument, assume it is the Qt version number. - text << " Qt " << since[0]; - } else { - // Otherwise, reconstruct the string. - text << " " << since.join(' '); - } - - text << "." << Atom::ParaRight; + text << "or modified "; + text << "in " << formatSince(node) << "." << Atom::ParaRight; generateText(text, node, marker); } } @@ -1341,13 +1304,9 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) // Do nothing. break; case Node::Preliminary: - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "This " - << typeString(node) - << " is under development and is subject to change." - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << Atom::ParaRight; + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This " + << typeString(node) << " is under development and is subject to change." + << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight; break; case Node::Deprecated: text << Atom::ParaLeft; @@ -1377,61 +1336,106 @@ void Generator::generateStatus(const Node *node, CodeMarker *marker) } /*! - Generates a bold line that says: - "The signal is private, not emitted by the user. - The function is public so the user can pass it to connect()." - */ -void Generator::generatePrivateSignalNote(const Node* node, CodeMarker* marker) + Generates an addendum note of type \a type for \a node, using \a marker + as the code marker. +*/ +void Generator::generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote) { + Q_ASSERT(node && !node->name().isEmpty()); Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note: " - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << "This is a private signal. It can be used in signal connections but cannot be emitted by the user." - << Atom::ParaRight; - generateText(text, node, marker); -} + text << Atom::ParaLeft; -/*! - Generates a bold line that says: - "This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE." - */ -void Generator::generateInvokableNote(const Node* node, CodeMarker* marker) -{ - Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note: " - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << "This function can be invoked via the meta-object system and from QML. See " - << Atom(Atom::Link,"Q_INVOKABLE") - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << "Q_INVOKABLE" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << "." - << Atom::ParaRight; + if (generateNote) { + text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note: " << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD); + } + + switch (type) { + case Invokable: + text << "This function can be invoked via the meta-object system and from QML. See " + << Atom(Atom::Link, "Q_INVOKABLE") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << "Q_INVOKABLE" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << "."; + break; + case PrivateSignal: + text << "This is a private signal. It can be used in signal connections " + "but cannot be emitted by the user."; + break; + case QmlSignalHandler: + { + QString handler(node->name()); + int prefixLocation = handler.lastIndexOf('.', -2) + 1; + handler[prefixLocation] = handler[prefixLocation].toTitleCase(); + handler.insert(prefixLocation, QLatin1String("on")); + text << "The corresponding handler is " + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_TELETYPE) << handler + << Atom(Atom::FormattingRight, ATOM_FORMATTING_TELETYPE) << "."; + break; + } + case AssociatedProperties: + { + if (!node->isFunction()) + return; + const FunctionNode *fn = static_cast(node); + NodeList nodes = fn->associatedProperties(); + if (nodes.isEmpty()) + return; + std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); + for (const auto *n : qAsConst(nodes)) { + QString msg; + const PropertyNode *pn = static_cast(n); + switch (pn->role(fn)) { + case PropertyNode::Getter: + msg = QStringLiteral("Getter function"); + break; + case PropertyNode::Setter: + msg = QStringLiteral("Setter function"); + break; + case PropertyNode::Resetter: + msg = QStringLiteral("Resetter function"); + break; + case PropertyNode::Notifier: + msg = QStringLiteral("Notifier signal"); + break; + default: + continue; + } + text << msg << " for property " << Atom(Atom::Link, pn->name()) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << pn->name() + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << ". "; + } + break; + } + case BindableProperty: + { + text << "This property supports " + << Atom(Atom::Link, "QProperty") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << "QProperty" + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + text << " bindings."; + break; + } + default: + return; + } + + text << Atom::ParaRight; generateText(text, node, marker); } /*! Generate the documentation for \a relative. i.e. \a relative - is the node that reporesentas the entity where a qdoc comment + is the node that represents the entity where a qdoc comment was found, and \a text represents the qdoc comment. */ -bool Generator::generateText(const Text& text, - const Node *relative, - CodeMarker *marker) +bool Generator::generateText(const Text &text, const Node *relative, CodeMarker *marker) { bool result = false; if (text.firstAtom() != nullptr) { int numAtoms = 0; initializeTextOutput(); - generateAtomList(text.firstAtom(), - relative, - marker, - true, - numAtoms); + generateAtomList(text.firstAtom(), relative, marker, true, numAtoms); result = true; } return result; @@ -1446,29 +1450,27 @@ bool Generator::generateText(const Text& text, nonreentrant, and true is returned. If there are no exceptions, the three node lists remain empty and false is returned. */ -static bool hasExceptions(const Node* node, - NodeList& reentrant, - NodeList& threadsafe, - NodeList& nonreentrant) +bool Generator::hasExceptions(const Node *node, NodeList &reentrant, NodeList &threadsafe, + NodeList &nonreentrant) { bool result = false; Node::ThreadSafeness ts = node->threadSafeness(); - const NodeList &children = static_cast(node)->childNodes(); - foreach (Node *n, children) { - if (!n->isObsolete()){ - switch (n->threadSafeness()) { + const NodeList &children = static_cast(node)->childNodes(); + for (auto child : children) { + if (!child->isObsolete()) { + switch (child->threadSafeness()) { case Node::Reentrant: - reentrant.append(n); + reentrant.append(child); if (ts == Node::ThreadSafe) result = true; break; case Node::ThreadSafe: - threadsafe.append(n); + threadsafe.append(child); if (ts == Node::Reentrant) result = true; break; case Node::NonReentrant: - nonreentrant.append(n); + nonreentrant.append(child); result = true; break; default: @@ -1479,13 +1481,10 @@ static bool hasExceptions(const Node* node, return result; } -static void startNote(Text& text) +static void startNote(Text &text) { - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) - << "Note:" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) - << " "; + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note:" << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " "; } /*! @@ -1501,30 +1500,19 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) Node::ThreadSafeness ts = node->threadSafeness(); bool exceptions = false; - rlink << Atom(Atom::Link,"reentrant") - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << "reentrant" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + rlink << Atom(Atom::Link, "reentrant") << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "reentrant" << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - tlink << Atom(Atom::Link,"thread-safe") - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << "thread-safe" - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + tlink << Atom(Atom::Link, "thread-safe") << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << "thread-safe" << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); switch (ts) { case Node::UnspecifiedSafeness: break; case Node::NonReentrant: - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Warning:" - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) - << " This " - << typeString(node) - << " is not " - << rlink - << "." - << Atom::ParaRight; + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Warning:" << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This " + << typeString(node) << " is not " << rlink << "." << Atom::ParaRight; break; case Node::Reentrant: case Node::ThreadSafe: @@ -1541,8 +1529,7 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) text << "."; else text << " with the following exceptions:"; - } - else { + } else { text << "This " << typeString(node) << " is "; if (ts == Node::ThreadSafe) text << tlink; @@ -1555,46 +1542,33 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) default: break; } - generateText(text,node,marker); + generateText(text, node, marker); if (exceptions) { text.clear(); if (ts == Node::Reentrant) { if (!nonreentrant.isEmpty()) { startNote(text); - text << "These functions are not " - << rlink - << ":" - << Atom::ParaRight; + text << "These functions are not " << rlink << ":" << Atom::ParaRight; signatureList(nonreentrant, node, marker); } if (!threadsafe.isEmpty()) { text.clear(); startNote(text); - text << "These functions are also " - << tlink - << ":" - << Atom::ParaRight; + text << "These functions are also " << tlink << ":" << Atom::ParaRight; generateText(text, node, marker); signatureList(threadsafe, node, marker); } - } - else { // thread-safe + } else { // thread-safe if (!reentrant.isEmpty()) { startNote(text); - text << "These functions are only " - << rlink - << ":" - << Atom::ParaRight; + text << "These functions are only " << rlink << ":" << Atom::ParaRight; signatureList(reentrant, node, marker); } if (!nonreentrant.isEmpty()) { text.clear(); startNote(text); - text << "These functions are not " - << rlink - << ":" - << Atom::ParaRight; + text << "These functions are not " << rlink << ":" << Atom::ParaRight; signatureList(nonreentrant, node, marker); } } @@ -1602,19 +1576,16 @@ void Generator::generateThreadSafeness(const Node *node, CodeMarker *marker) } /*! - If the node is an overloaded signal, and a node with an example on how to connect to it - - Someone didn't finish writing this comment, and I don't know what this - function is supposed to do, so I have not tried to complete the comment - yet. + Returns the string containing an example code of the input node, + if it is an overloaded signal. Otherwise, returns an empty string. */ -void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker) +QString Generator::getOverloadedSignalCode(const Node *node) { if (!node->isFunction()) - return; - const FunctionNode *func = static_cast(node); + return QString(); + const auto func = static_cast(node); if (!func->isSignal() || !func->hasOverloads()) - return; + return QString(); // Compute a friendly name for the object of that instance. // e.g: "QAbstractSocket" -> "abstractSocket" @@ -1626,76 +1597,59 @@ void Generator::generateOverloadedSignal(const Node* node, CodeMarker* marker) } // We have an overloaded signal, show an example. Note, for const - // overloaded signals one should use Q{Const,NonConst}Overload, but + // overloaded signals, one should use Q{Const,NonConst}Overload, but // it is very unlikely that we will ever have public API overloading // signals by const. QString code = "connect(" + objectName + ", QOverload<"; - func->parameters().getTypeList(code); + code += func->parameters().generateTypeList(); code += ">::of(&" + func->parent()->name() + "::" + func->name() + "),\n [=]("; - func->parameters().getTypeAndNameList(code); - + code += func->parameters().generateTypeAndNameList(); code += "){ /* ... */ });"; + return code; +} + +/*! + If the node is an overloaded signal, add a node with an example on how to connect to it + */ +void Generator::generateOverloadedSignal(const Node *node, CodeMarker *marker) +{ + QString code = getOverloadedSignalCode(node); + if (code.isEmpty()) + return; + Text text; - text << Atom::ParaLeft - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD) - << "Note:" - << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD) - << " Signal " - << Atom(Atom::FormattingLeft,ATOM_FORMATTING_ITALIC) - << node->name() - << Atom(Atom::FormattingRight,ATOM_FORMATTING_ITALIC) + text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) + << "Note:" << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " Signal " + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_ITALIC) << node->name() + << Atom(Atom::FormattingRight, ATOM_FORMATTING_ITALIC) << " is overloaded in this class. " "To connect to this signal by using the function pointer syntax, Qt " "provides a convenient helper for obtaining the function pointer as " "shown in this example:" - << Atom(Atom::Code, marker->markedUpCode(code, node, func->location())); + << Atom(Atom::Code, marker->markedUpCode(code, node, node->location())); generateText(text, node, marker); } - /*! - Traverses the database recursivly to generate all the documentation. + Traverses the database recursively to generate all the documentation. */ void Generator::generateDocs() { currentGenerator_ = this; - generateDocumentation(qdb_->primaryTreeRoot()); + generateDocumentation(m_qdb->primaryTreeRoot()); } -Generator *Generator::generatorForFormat(const QString& format) +Generator *Generator::generatorForFormat(const QString &format) { - QList::ConstIterator g = generators.constBegin(); - while (g != generators.constEnd()) { - if ((*g)->format() == format) - return *g; - ++g; + for (const auto &generator : qAsConst(generators)) { + if (generator->format() == format) + return generator; } return nullptr; } -/*! - Looks up the tag \a t in the map of metadata values for the - current topic in \a inner. If a value for the tag is found, - the value is returned. - - \note If \a t is found in the metadata map, it is erased. - i.e. Once you call this function for a particular \a t, - you consume \a t. - */ -QString Generator::getMetadataElement(const Aggregate* inner, const QString& t) -{ - QString s; - QStringMultiMap& metaTagMap = const_cast(inner->doc().metaTagMap()); - QStringMultiMap::iterator i = metaTagMap.find(t); - if (i != metaTagMap.end()) { - s = i.value(); - metaTagMap.erase(i); - } - return s; -} - /*! Looks up the tag \a t in the map of metadata values for the current topic in \a inner. If values for the tag are found, @@ -1705,35 +1659,30 @@ QString Generator::getMetadataElement(const Aggregate* inner, const QString& t) having the key \a t are erased. i.e. Once you call this function for a particular \a t, you consume \a t. */ -QStringList Generator::getMetadataElements(const Aggregate* inner, const QString& t) -{ - QStringList s; - QStringMultiMap& metaTagMap = const_cast(inner->doc().metaTagMap()); - s = metaTagMap.values(t); - if (!s.isEmpty()) - metaTagMap.remove(t); - return s; +QStringList Generator::getMetadataElements(const Aggregate *inner, const QString &t) +{ + QStringList result; + QStringMultiMap *metaTagMap = inner->doc().metaTagMap(); + if (metaTagMap) + result = metaTagMap->values(t); + if (!result.isEmpty()) + metaTagMap->remove(t); + return result; } /*! Returns a relative path name for an image. */ -QString Generator::imageFileName(const Node *relative, const QString& fileBase) +QString Generator::imageFileName(const Node *relative, const QString &fileBase) { QString userFriendlyFilePath; - QString filePath = Config::findFile(relative->doc().location(), - imageFiles, - imageDirs, - fileBase, - imgFileExts[format()], - &userFriendlyFilePath); + QString filePath = Config::findFile(relative->doc().location(), imageFiles, imageDirs, fileBase, + imgFileExts[format()], &userFriendlyFilePath); if (filePath.isEmpty()) return QString(); - QString path = Config::copyFile(relative->doc().location(), - filePath, - userFriendlyFilePath, + QString path = Config::copyFile(relative->doc().location(), filePath, userFriendlyFilePath, outputDir() + QLatin1String("/images")); int images_slash = path.lastIndexOf("images/"); QString relImagePath; @@ -1742,7 +1691,7 @@ QString Generator::imageFileName(const Node *relative, const QString& fileBase) return relImagePath; } -QString Generator::indent(int level, const QString& markedCode) +QString Generator::indent(int level, const QString &markedCode) { if (level == 0) return markedCode; @@ -1751,11 +1700,10 @@ QString Generator::indent(int level, const QString& markedCode) int column = 0; int i = 0; - while (i < (int) markedCode.length()) { + while (i < markedCode.length()) { if (markedCode.at(i) == QLatin1Char('\n')) { column = 0; - } - else { + } else { if (column == 0) { for (int j = 0; j < level; j++) t += QLatin1Char(' '); @@ -1767,19 +1715,14 @@ QString Generator::indent(int level, const QString& markedCode) return t; } - - -void Generator::initialize(const Config &config) +void Generator::initialize() { + Config &config = Config::instance(); outputFormats = config.getOutputFormats(); redirectDocumentationToDevNull_ = config.getBool(CONFIG_REDIRECTDOCUMENTATIONTODEVNULL); imageFiles = config.getCanonicalPathList(CONFIG_IMAGES); imageDirs = config.getCanonicalPathList(CONFIG_IMAGEDIRS); - scriptFiles = config.getCanonicalPathList(CONFIG_SCRIPTS); - scriptDirs = config.getCanonicalPathList(CONFIG_SCRIPTDIRS); - styleFiles = config.getCanonicalPathList(CONFIG_STYLES); - styleDirs = config.getCanonicalPathList(CONFIG_STYLEDIRS); exampleDirs = config.getCanonicalPathList(CONFIG_EXAMPLEDIRS); exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot + CONFIG_IMAGEEXTENSIONS); @@ -1790,7 +1733,7 @@ void Generator::initialize(const Config &config) for (auto &g : generators) { if (outputFormats.contains(g->format())) { currentGenerator_ = g; - g->initializeGenerator(config); + g->initializeGenerator(); } } @@ -1802,16 +1745,18 @@ void Generator::initialize(const Config &config) int numParams = Config::numParams(def); int numOccs = def.count("\1"); if (numParams != 1) { - config.lastLocation().warning(tr("Formatting '%1' must " - "have exactly one " - "parameter (found %2)") - .arg(n).arg(numParams)); + config.lastLocation().warning(QStringLiteral("Formatting '%1' must " + "have exactly one " + "parameter (found %2)") + .arg(n) + .arg(numParams)); } else if (numOccs > 1) { - config.lastLocation().fatal(tr("Formatting '%1' must " - "contain exactly one " - "occurrence of '\\1' " - "(found %2)") - .arg(n).arg(numOccs)); + config.lastLocation().fatal(QStringLiteral("Formatting '%1' must " + "contain exactly one " + "occurrence of '\\1' " + "(found %2)") + .arg(n) + .arg(numOccs)); } else { int paramPos = def.indexOf("\1"); fmtLeftMaps[f].insert(n, def.left(paramPos)); @@ -1847,15 +1792,16 @@ void Generator::initialize(const Config &config) Creates template-specific subdirs (e.g. /styles and /scripts for HTML) and copies the files to them. */ -void Generator::copyTemplateFiles(const Config &config, const QString &configVar, const QString &subDir) +void Generator::copyTemplateFiles(const QString &configVar, const QString &subDir) { + Config &config = Config::instance(); QStringList files = config.getCanonicalPathList(configVar, true); if (!files.isEmpty()) { QDir dirInfo; QString templateDir = outDir_ + QLatin1Char('/') + subDir; if (!dirInfo.exists(templateDir) && !dirInfo.mkdir(templateDir)) { - config.lastLocation().fatal(tr("Cannot create %1 directory '%2'") - .arg(subDir, templateDir)); + config.lastLocation().fatal( + QStringLiteral("Cannot create %1 directory '%2'").arg(subDir, templateDir)); } else { for (const auto &file : files) { if (!file.isEmpty()) @@ -1866,12 +1812,13 @@ void Generator::copyTemplateFiles(const Config &config, const QString &configVar } /*! - Reads format-specific variables from \a config, sets output + Reads format-specific variables from config, sets output (sub)directories, creates them on the filesystem and copies the template-specific files. */ -void Generator::initializeFormat(const Config &config) +void Generator::initializeFormat() { + Config &config = Config::instance(); outFileNames_.clear(); useOutputSubdirs_ = true; if (config.getBool(format() + Config::dot + "nosubdirs")) @@ -1882,68 +1829,67 @@ void Generator::initializeFormat(const Config &config) outDir_ = config.getOutputDir(format()); if (outDir_.isEmpty()) { - config.lastLocation().fatal(tr("No output directory specified in " - "configuration file or on the command line")); + config.lastLocation().fatal(QStringLiteral("No output directory specified in " + "configuration file or on the command line")); } else { outSubdir_ = outDir_.mid(outDir_.lastIndexOf('/') + 1); } - QDir dirInfo; - if (dirInfo.exists(outDir_)) { - if (!generating() && Generator::useOutputSubdirs()) { - if (!Config::removeDirContents(outDir_)) - config.lastLocation().error(tr("Cannot empty output directory '%1'").arg(outDir_)); + QDir outputDir(outDir_); + if (outputDir.exists()) { + if (!config.generating() && Generator::useOutputSubdirs()) { + if (!outputDir.isEmpty()) + config.lastLocation().error( + QStringLiteral("Output directory '%1' exists but is not empty").arg(outDir_)); } - } else if (!dirInfo.mkpath(outDir_)) { - config.lastLocation().fatal(tr("Cannot create output directory '%1'").arg(outDir_)); + } else if (!outputDir.mkpath(QStringLiteral("."))) { + config.lastLocation().fatal( + QStringLiteral("Cannot create output directory '%1'").arg(outDir_)); } // Output directory exists, which is enough for prepare phase. - if (preparing()) + if (config.preparing()) return; - if (!dirInfo.exists(outDir_ + "/images") && !dirInfo.mkdir(outDir_ + "/images")) - config.lastLocation().fatal(tr("Cannot create images directory '%1'").arg(outDir_ + "/images")); + const QLatin1String imagesDir("images"); + if (!outputDir.exists(imagesDir) && !outputDir.mkdir(imagesDir)) + config.lastLocation().fatal( + QStringLiteral("Cannot create images directory '%1'").arg(outputDir.filePath(imagesDir))); - copyTemplateFiles(config, format() + Config::dot + CONFIG_STYLESHEETS, "style"); - copyTemplateFiles(config, format() + Config::dot + CONFIG_SCRIPTS, "scripts"); - copyTemplateFiles(config, format() + Config::dot + CONFIG_EXTRAIMAGES, "images"); + copyTemplateFiles(format() + Config::dot + CONFIG_STYLESHEETS, "style"); + copyTemplateFiles(format() + Config::dot + CONFIG_SCRIPTS, "scripts"); + copyTemplateFiles(format() + Config::dot + CONFIG_EXTRAIMAGES, "images"); // Use a format-specific .quotinginformation if defined, otherwise a global value if (config.subVars(format()).contains(CONFIG_QUOTINGINFORMATION)) - quoting_ = config.getBool(format() + Config::dot + CONFIG_QUOTINGINFORMATION); + m_quoting = config.getBool(format() + Config::dot + CONFIG_QUOTINGINFORMATION); else - quoting_ = config.getBool(CONFIG_QUOTINGINFORMATION); + m_quoting = config.getBool(CONFIG_QUOTINGINFORMATION); } /*! Appends each directory path in \a moreImageDirs to the list of image directories. */ -void Generator::augmentImageDirs(QSet& moreImageDirs) +void Generator::augmentImageDirs(QSet &moreImageDirs) { if (moreImageDirs.isEmpty()) return; - QSet::const_iterator i = moreImageDirs.begin(); - while (i != moreImageDirs.end()) { - imageDirs.append(*i); - ++i; - } + for (const auto &it : moreImageDirs) + imageDirs.append(it); } /*! - Sets the generator's pointer to the Config instance. + Updates the generator's m_showInternal from the Config. */ -void Generator::initializeGenerator(const Config& config) +void Generator::initializeGenerator() { - config_ = &config; - showInternal_ = config.getBool(CONFIG_SHOWINTERNAL); - singleExec_ = config.getBool(CONFIG_SINGLEEXEC); + m_showInternal = Config::instance().showInternal(); } bool Generator::matchAhead(const Atom *atom, Atom::AtomType expectedAtomType) { - return atom->next() != nullptr && atom->next()->type() == expectedAtomType; + return atom->next() && atom->next()->type() == expectedAtomType; } /*! @@ -1958,7 +1904,7 @@ QTextStream &Generator::out() QString Generator::outFileName() { - return QFileInfo(static_cast(out().device())->fileName()).fileName(); + return QFileInfo(static_cast(out().device())->fileName()).fileName(); } QString Generator::outputPrefix(const Node *node) @@ -1982,44 +1928,36 @@ QString Generator::outputSuffix(const Node *node) return QString(); } -bool Generator::parseArg(const QString& src, - const QString& tag, - int* pos, - int n, - QStringRef* contents, - QStringRef* par1, - bool debug) -{ -#define SKIP_CHAR(c) \ - if (debug) \ - qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ - if (i >= n || src[i] != c) { \ - if (debug) \ - qDebug() << " char '" << c << "' not found"; \ - return false; \ -} \ +bool Generator::parseArg(const QString &src, const QString &tag, int *pos, int n, + QStringView *contents, QStringView *par1, bool debug) +{ +#define SKIP_CHAR(c) \ + if (debug) \ + qDebug() << "looking for " << c << " at " << QString(src.data() + i, n - i); \ + if (i >= n || src[i] != c) { \ + if (debug) \ + qDebug() << " char '" << c << "' not found"; \ + return false; \ + } \ ++i; - -#define SKIP_SPACE \ - while (i < n && src[i] == ' ') \ - ++i; +#define SKIP_SPACE \ + while (i < n && src[i] == ' ') \ + ++i; int i = *pos; int j = i; // assume "<@" has been parsed outside - //SKIP_CHAR('<'); - //SKIP_CHAR('@'); + // SKIP_CHAR('<'); + // SKIP_CHAR('@'); - if (tag != QStringRef(&src, i, tag.length())) { - if (0 && debug) - qDebug() << "tag " << tag << " not found at " << i; + if (tag != QStringView(src).mid(i, tag.length())) { return false; } if (debug) - qDebug() << "haystack:" << src << "needle:" << tag << "i:" <next(); - while (atom != nullptr && atom->type() != type) { + while (atom && atom->type() != type) { skipAhead++; atom = atom->next(); } @@ -2120,20 +2058,20 @@ int Generator::skipAtoms(const Atom *atom, Atom::AtomType type) const */ void Generator::initializeTextOutput() { - inLink_ = false; - inContents_ = false; - inSectionHeading_ = false; - inTableHeader_ = false; - numTableRows_ = 0; - threeColumnEnumValueTable_ = true; - link_.clear(); - sectionNumber_.clear(); + m_inLink = false; + m_inContents = false; + m_inSectionHeading = false; + m_inTableHeader = false; + m_numTableRows = 0; + m_threeColumnEnumValueTable = true; + m_link.clear(); + m_sectionNumber.clear(); } void Generator::supplementAlsoList(const Node *node, QList &alsoList) { if (node->isFunction() && !node->isMacro()) { - const FunctionNode *fn = static_cast(node); + const auto fn = static_cast(node); if (fn->overloadNumber() == 0) { QString alternateName; const FunctionNode *alternateFunc = nullptr; @@ -2151,15 +2089,14 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList) alternateFunc = fn->parent()->findFunctionChild(alternateName, QString()); } } - } - else if (!fn->name().isEmpty()) { + } else if (!fn->name().isEmpty()) { alternateName = "set"; alternateName += fn->name()[0].toUpper(); alternateName += fn->name().mid(1); alternateFunc = fn->parent()->findFunctionChild(alternateName, QString()); } - if (alternateFunc && alternateFunc->access() != Node::Private) { + if (alternateFunc && alternateFunc->access() != Access::Private) { int i; for (i = 0; i < alsoList.size(); ++i) { if (alsoList.at(i).toString().contains(alternateName)) @@ -2171,8 +2108,7 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList) Text also; also << Atom(Atom::Link, alternateName) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << alternateName + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << alternateName << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); alsoList.prepend(also); } @@ -2183,11 +2119,9 @@ void Generator::supplementAlsoList(const Node *node, QList &alsoList) void Generator::terminate() { - QList::ConstIterator g = generators.constBegin(); - while (g != generators.constEnd()) { - if (outputFormats.contains((*g)->format())) - (*g)->terminateGenerator(); - ++g; + for (const auto &generator : qAsConst(generators)) { + if (outputFormats.contains(generator->format())) + generator->terminateGenerator(); } fmtLeftMaps.clear(); @@ -2198,15 +2132,14 @@ void Generator::terminate() outDir_.clear(); } -void Generator::terminateGenerator() -{ -} +void Generator::terminateGenerator() {} /*! Trims trailing whitespace off the \a string and returns the trimmed string. */ -QString Generator::trimmedTrailing(const QString& string, const QString &prefix, const QString &suffix) +QString Generator::trimmedTrailing(const QString &string, const QString &prefix, + const QString &suffix) { QString trimmed = string; while (trimmed.length() > 0 && trimmed[trimmed.length() - 1].isSpace()) @@ -2229,17 +2162,18 @@ QString Generator::typeString(const Node *node) case Node::Union: return "union"; case Node::QmlType: - return "type"; case Node::QmlBasicType: + case Node::JsBasicType: return "type"; case Node::Page: return "documentation"; case Node::Enum: return "enum"; case Node::Typedef: + case Node::TypeAlias: return "typedef"; case Node::Function: { - const FunctionNode *fn = static_cast(node); + const auto fn = static_cast(node); switch (fn->metaness()) { case FunctionNode::JsSignal: case FunctionNode::QmlSignal: @@ -2262,6 +2196,10 @@ QString Generator::typeString(const Node *node) case Node::JsModule: case Node::QmlModule: return "module"; + case Node::SharedComment: { + const auto &collective = static_cast(node)->collective(); + return collective.first()->nodeTypeString(); + } default: return "documentation"; } @@ -2269,8 +2207,9 @@ QString Generator::typeString(const Node *node) void Generator::unknownAtom(const Atom *atom) { - Location::internalError(tr("unknown atom type '%1' in %2 generator") - .arg(atom->typeString()).arg(format())); + Location::internalError(QStringLiteral("unknown atom type '%1' in %2 generator") + .arg(atom->typeString()) + .arg(format())); } QT_END_NAMESPACE diff --git a/src/qdoc/generator.h b/src/qdoc/generator.h index d02c59f440..3892617cf1 100644 --- a/src/qdoc/generator.h +++ b/src/qdoc/generator.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -29,90 +29,83 @@ #ifndef GENERATOR_H #define GENERATOR_H -#include -#include -#include -#include -#include -#include -#include -#include -#include "config.h" -#include "node.h" #include "text.h" +#include "utilities.h" + +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE -typedef QMultiMap NodeMultiMap; -typedef QMap ParentMaps; +typedef QMultiMap NodeMultiMap; +typedef QMap ParentMaps; -class Config; +class Aggregate; class CodeMarker; +class ExampleNode; +class FunctionNode; class Location; +class Node; class QDocDatabase; +class QmlBasicTypeNode; class Generator { - Q_DECLARE_TR_FUNCTIONS(QDoc::Generator) - public: - enum QDocPass { Neither, Prepare, Generate }; enum ListType { Generic, Obsolete }; + enum Addendum { + Invokable, + PrivateSignal, + QmlSignalHandler, + AssociatedProperties, + BindableProperty + }; + Generator(); virtual ~Generator(); virtual bool canHandleFormat(const QString &format) { return format == this->format(); } virtual QString format() = 0; virtual void generateDocs(); - virtual void initializeGenerator(const Config &config); - virtual void initializeFormat(const Config &config); + virtual void initializeGenerator(); + virtual void initializeFormat(); virtual void terminateGenerator(); + virtual QString typeString(const Node *node); QString fullDocumentLocation(const Node *node, bool useSubdir = false); - const Config* config() { return config_; } - QString linkForExampleFile(const QString &path, const Node *parent); - + QString linkForExampleFile(const QString &path, const Node *parent, + const QString &fileExt = QString()); + static QString exampleFileTitle(const ExampleNode *relative, const QString &fileName); static Generator *currentGenerator() { return currentGenerator_; } - static Generator *generatorForFormat(const QString& format); - static void initialize(const Config& config); - static const QString& outputDir() { return outDir_; } - static const QString& outputSubdir() { return outSubdir_; } + static Generator *generatorForFormat(const QString &format); + static void initialize(); + static const QString &outputDir() { return outDir_; } + static const QString &outputSubdir() { return outSubdir_; } static void terminate(); - static const QStringList& outputFileNames() { return outFileNames_; } - static void writeOutFileNames(); - static void augmentImageDirs(QSet& moreImageDirs); - static void startDebugging(const QString& message); - static void stopDebugging(const QString& message); - static bool debugging(); + static const QStringList &outputFileNames() { return outFileNames_; } + static void augmentImageDirs(QSet &moreImageDirs); static bool noLinkErrors() { return noLinkErrors_; } static bool autolinkErrors() { return autolinkErrors_; } - static void setQDocPass(QDocPass t) { qdocPass_ = t; } - static void setUseTimestamps() { useTimestamps_ = true; } - static bool preparing() { return (qdocPass_ == Prepare); } - static bool generating() { return (qdocPass_ == Generate); } - static bool singleExec() { return qdocSingleExec_; } - static bool dualExec() { return !qdocSingleExec_; } - static bool writeQaPages() { return qdocWriteQaPages_; } - static void setSingleExec() { qdocSingleExec_ = true; } - static void setWriteQaPages() { qdocWriteQaPages_ = true; } static QString defaultModuleName() { return project_; } static void resetUseOutputSubdirs() { useOutputSubdirs_ = false; } static bool useOutputSubdirs() { return useOutputSubdirs_; } - static void setQmlTypeContext(QmlTypeNode* t) { qmlTypeContext_ = t; } - static QmlTypeNode* qmlTypeContext() { return qmlTypeContext_; } - static QString cleanRef(const QString& ref); - static QString plainCode(const QString& markedCode); - static bool useTimestamps() { return useTimestamps_; } + static void setQmlTypeContext(QmlTypeNode *t) { qmlTypeContext_ = t; } + static QmlTypeNode *qmlTypeContext() { return qmlTypeContext_; } + static QString cleanRef(const QString &ref); + static QString plainCode(const QString &markedCode); + virtual QString fileBase(const Node *node) const; protected: - void beginFilePage(const Node* node, const QString& fileName); + static QFile *openSubPageFile(const Node *node, const QString &fileName); + void beginFilePage(const Node *node, const QString &fileName); void endFilePage() { endSubPage(); } // for symmetry - void beginSubPage(const Node* node, const QString& fileName); + void beginSubPage(const Node *node, const QString &fileName); void endSubPage(); - virtual QString fileBase(const Node* node) const; virtual QString fileExtension() const = 0; - virtual void generateQAPage() { } virtual void generateExampleFilePage(const Node *, const QString &, CodeMarker *) {} virtual void generateAlsoList(const Node *node, CodeMarker *marker); virtual int generateAtom(const Atom *, const Node *, CodeMarker *) { return 0; } @@ -124,93 +117,79 @@ class Generator virtual void generatePageNode(PageNode *, CodeMarker *) {} virtual void generateCollectionNode(CollectionNode *, CodeMarker *) {} virtual void generateGenericCollectionPage(CollectionNode *, CodeMarker *) {} - virtual void generateInheritedBy(const ClassNode *classe, CodeMarker *marker); virtual void generateInherits(const ClassNode *classe, CodeMarker *marker); - virtual void generateDocumentation(Node* node); - virtual void generateMaintainerList(const Aggregate* node, CodeMarker* marker); - virtual void generateQmlInheritedBy(const QmlTypeNode* qcn, CodeMarker* marker); + virtual void generateDocumentation(Node *node); + virtual void generateMaintainerList(const Aggregate *node, CodeMarker *marker); + virtual void generateQmlInheritedBy(const QmlTypeNode *qcn, CodeMarker *marker); virtual void generateQmlInherits(QmlTypeNode *, CodeMarker *) {} - virtual bool generateQmlText(const Text& text, - const Node *relative, - CodeMarker *marker, - const QString& qmlName); - virtual bool generateText(const Text& text, const Node *relative, CodeMarker *marker); - virtual QString imageFileName(const Node *relative, const QString& fileBase); + virtual bool generateQmlText(const Text &text, const Node *relative, CodeMarker *marker, + const QString &qmlName); + virtual bool generateText(const Text &text, const Node *relative, CodeMarker *marker); + virtual QString imageFileName(const Node *relative, const QString &fileBase); virtual int skipAtoms(const Atom *atom, Atom::AtomType type) const; - virtual QString typeString(const Node *node); static bool matchAhead(const Atom *atom, Atom::AtomType expectedAtomType); - static QString outputPrefix(const Node* node); - static QString outputSuffix(const Node* node); - static void singularPlural(Text& text, const NodeList& nodes); + static QString outputPrefix(const Node *node); + static QString outputSuffix(const Node *node); + static void singularPlural(Text &text, const NodeList &nodes); static void supplementAlsoList(const Node *node, QList &alsoList); - static QString trimmedTrailing(const QString &string, - const QString &prefix, + static QString trimmedTrailing(const QString &string, const QString &prefix, const QString &suffix); void initializeTextOutput(); - QString fileName(const Node* node, const QString &extension = QString()) const; + QString fileName(const Node *node, const QString &extension = QString()) const; QMap &formattingLeftMap(); QMap &formattingRightMap(); - const Atom* generateAtomList(const Atom *atom, - const Node *relative, - CodeMarker *marker, - bool generate, - int& numGeneratedAtoms); - void generateLinkToExample(const ExampleNode *en, - CodeMarker *marker, - const QString &baseUrl); - void generateFileList(const ExampleNode* en, CodeMarker* marker, bool images); + const Atom *generateAtomList(const Atom *atom, const Node *relative, CodeMarker *marker, + bool generate, int &numGeneratedAtoms); + void generateRequiredLinks(const Node *node, CodeMarker *marker); + void generateLinkToExample(const ExampleNode *en, CodeMarker *marker, + const QString &exampleUrl); + virtual void generateFileList(const ExampleNode *en, CodeMarker *marker, bool images); + static QString formatSince(const Node *node); void generateSince(const Node *node, CodeMarker *marker); void generateStatus(const Node *node, CodeMarker *marker); - void generatePrivateSignalNote(const Node* node, CodeMarker* marker); - void generateInvokableNote(const Node* node, CodeMarker* marker); + virtual void generateAddendum(const Node *node, Addendum type, CodeMarker *marker, + bool generateNote = true); void generateThreadSafeness(const Node *node, CodeMarker *marker); - QString getMetadataElement(const Aggregate* inner, const QString& t); - QStringList getMetadataElements(const Aggregate* inner, const QString& t); + QStringList getMetadataElements(const Aggregate *inner, const QString &t); void generateOverloadedSignal(const Node *node, CodeMarker *marker); - QString indent(int level, const QString& markedCode); - QTextStream& out(); + static QString getOverloadedSignalCode(const Node *node); + QString indent(int level, const QString &markedCode); + QTextStream &out(); QString outFileName(); - bool parseArg(const QString& src, - const QString& tag, - int* pos, - int n, - QStringRef* contents, - QStringRef* par1 = nullptr, - bool debug = false); - void setImageFileExtensions(const QStringList& extensions); + bool parseArg(const QString &src, const QString &tag, int *pos, int n, QStringView *contents, + QStringView *par1 = nullptr, bool debug = false); + void setImageFileExtensions(const QStringList &extensions); void unknownAtom(const Atom *atom); - int appendSortedQmlNames(Text& text, const Node* base, const NodeList& subs); + int appendSortedQmlNames(Text &text, const Node *base, const NodeList &subs); + + static bool hasExceptions(const Node *node, NodeList &reentrant, NodeList &threadsafe, + NodeList &nonreentrant); - QMap editionGroupMap; - QMap editionModuleMap; QString naturalLanguage; -#ifndef QT_NO_TEXTCODEC - QTextCodec* outputCodec; - QString outputEncoding; -#endif QString tagFile_; - QStack outStreamStack; + QStack outStreamStack; - void appendFullName(Text& text, - const Node *apparentNode, - const Node *relative, + void appendFullName(Text &text, const Node *apparentNode, const Node *relative, const Node *actualNode = nullptr); - void appendFullName(Text& text, - const Node *apparentNode, - const QString& fullName, + void appendFullName(Text &text, const Node *apparentNode, const QString &fullName, const Node *actualNode); - void appendFullNames(Text& text, const NodeList& nodes, const Node* relative); - int appendSortedNames(Text& text, const ClassNode *classe, const QList &classes); - void appendSignature(Text& text, const Node* node); - void signatureList(const NodeList& nodes, const Node* relative, CodeMarker* marker); + void appendFullNames(Text &text, const NodeList &nodes, const Node *relative); + int appendSortedNames(Text &text, const ClassNode *classe, + const QList &classes); + void appendSignature(Text &text, const Node *node); + void signatureList(const NodeList &nodes, const Node *relative, CodeMarker *marker); + + void addImageToCopy(const ExampleNode *en, const QString &file); + static bool compareNodes(const Node *a, const Node *b) { return (a->name() < b->name()); } + static bool comparePaths(const QString &a, const QString &b) { return (a < b); } private: - static Generator* currentGenerator_; + static Generator *currentGenerator_; static QStringList exampleDirs; static QStringList exampleImgExts; - static QMap > fmtLeftMaps; - static QMap > fmtRightMaps; + static QMap> fmtLeftMaps; + static QMap> fmtRightMaps; static QList generators; static QStringList imageDirs; static QStringList imageFiles; @@ -222,41 +201,27 @@ class Generator static QSet outputFormats; static QHash outputPrefixes; static QHash outputSuffixes; - static QStringList scriptDirs; - static QStringList scriptFiles; - static QStringList styleDirs; - static QStringList styleFiles; static bool noLinkErrors_; static bool autolinkErrors_; static bool redirectDocumentationToDevNull_; - static QDocPass qdocPass_; - static bool qdocSingleExec_; - static bool qdocWriteQaPages_; static bool useOutputSubdirs_; - static bool useTimestamps_; - static QmlTypeNode* qmlTypeContext_; + static QmlTypeNode *qmlTypeContext_; void generateReimplementsClause(const FunctionNode *fn, CodeMarker *marker); - static bool compareNodes(Node *a, Node *b) { return (a->name() < b->name()); } - static bool comparePaths(QString a, QString b) { return (a < b); } - static void copyTemplateFiles(const Config &config, - const QString &configVar, - const QString &subDir); + static void copyTemplateFiles(const QString &configVar, const QString &subDir); - protected: - const Config* config_; - QDocDatabase* qdb_; - bool inLink_; - bool inContents_; - bool inSectionHeading_; - bool inTableHeader_; - bool threeColumnEnumValueTable_; - bool showInternal_; - bool singleExec_; - bool quoting_; - int numTableRows_; - QString link_; - QString sectionNumber_; +protected: + QDocDatabase *m_qdb { nullptr }; + bool m_inLink { false }; + bool m_inContents { false }; + bool m_inSectionHeading { false }; + bool m_inTableHeader { false }; + bool m_threeColumnEnumValueTable { true }; + bool m_showInternal { false }; + bool m_quoting { false }; + int m_numTableRows { 0 }; + QString m_link {}; + QString m_sectionNumber {}; }; QT_END_NAMESPACE diff --git a/src/qdoc/headernode.cpp b/src/qdoc/headernode.cpp new file mode 100644 index 0000000000..230b562a64 --- /dev/null +++ b/src/qdoc/headernode.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "headernode.h" + +QT_BEGIN_NAMESPACE + +/*! + \class Headernode + \brief This class represents a C++ header file. + */ + +HeaderNode::HeaderNode(Aggregate *parent, const QString &name) : Aggregate(HeaderFile, parent, name) +{ + // Add the include file with enclosing angle brackets removed + if (name.startsWith(QChar('<')) && name.length() > 2) + Aggregate::addIncludeFile(name.mid(1).chopped(1)); + else + Aggregate::addIncludeFile(name); +} + +/*! + Returns true if this header file node is not private and + contains at least one public child node with documentation. + */ +bool HeaderNode::docMustBeGenerated() const +{ + if (isInAPI()) + return true; + return (hasDocumentedChildren() ? true : false); +} + +/*! + Returns true if this header file node contains at least one + child that has documentation and is not private or internal. + */ +bool HeaderNode::hasDocumentedChildren() const +{ + for (const auto *node : qAsConst(m_children)) { + if (node->isInAPI()) + return true; + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/qdoc/headernode.h b/src/qdoc/headernode.h new file mode 100644 index 0000000000..e50e23c558 --- /dev/null +++ b/src/qdoc/headernode.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HEADERNODE_H +#define HEADERNODE_H + +#include "aggregate.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class HeaderNode : public Aggregate +{ +public: + HeaderNode(Aggregate *parent, const QString &name); + bool docMustBeGenerated() const override; + bool isFirstClassAggregate() const override { return true; } + bool isRelatableType() const override { return true; } + QString title() const override { return (m_title.isEmpty() ? name() : m_title); } + QString subtitle() const override { return m_subtitle; } + QString fullTitle() const override + { + return (m_title.isEmpty() ? name() : name() + " - " + m_title); + } + bool setTitle(const QString &title) override + { + m_title = title; + return true; + } + bool setSubtitle(const QString &subtitle) override + { + m_subtitle = subtitle; + return true; + } + QString nameForLists() const override { return title(); } + bool hasDocumentedChildren() const; + +private: + QString m_title; + QString m_subtitle; +}; + +QT_END_NAMESPACE + +#endif // HEADERNODE_H diff --git a/src/qdoc/helpprojectwriter.cpp b/src/qdoc/helpprojectwriter.cpp index e7d877993a..64f76fb201 100644 --- a/src/qdoc/helpprojectwriter.cpp +++ b/src/qdoc/helpprojectwriter.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,31 +26,34 @@ ** ****************************************************************************/ -#include -#include -#include -#include +#include "helpprojectwriter.h" +#include "access.h" +#include "aggregate.h" #include "atom.h" -#include "helpprojectwriter.h" -#include "htmlgenerator.h" +#include "classnode.h" +#include "collectionnode.h" #include "config.h" +#include "enumnode.h" +#include "functionnode.h" +#include "htmlgenerator.h" #include "node.h" #include "qdocdatabase.h" -#include +#include "typedefnode.h" + +#include +#include +#include +#include QT_BEGIN_NAMESPACE -HelpProjectWriter::HelpProjectWriter(const Config &config, - const QString &defaultFileName, - Generator* g) +HelpProjectWriter::HelpProjectWriter(const QString &defaultFileName, Generator *g) { - reset(config, defaultFileName, g); + reset(defaultFileName, g); } -void HelpProjectWriter::reset(const Config &config, - const QString &defaultFileName, - Generator* g) +void HelpProjectWriter::reset(const QString &defaultFileName, Generator *g) { projects.clear(); gen_ = g; @@ -63,11 +66,12 @@ void HelpProjectWriter::reset(const Config &config, // The output directory should already have been checked by the calling // generator. + Config &config = Config::instance(); outputDir = config.getOutputDir(); - QStringList names = config.getStringList(CONFIG_QHP + Config::dot + "projects"); + const QStringList names = config.getStringList(CONFIG_QHP + Config::dot + "projects"); - foreach (const QString &projectName, names) { + for (const auto &projectName : names) { HelpProject project; project.name = projectName; @@ -83,23 +87,30 @@ void HelpProjectWriter::reset(const Config &config, project.indexTitle = config.getString(prefix + "indexTitle"); project.indexRoot = config.getString(prefix + "indexRoot"); const auto &filterAttributes = config.getStringList(prefix + "filterAttributes"); - project.filterAttributes = QSet(filterAttributes.cbegin(), filterAttributes.cend()); + project.filterAttributes = + QSet(filterAttributes.cbegin(), filterAttributes.cend()); project.includeIndexNodes = config.getBool(prefix + "includeIndexNodes"); - QSet customFilterNames = config.subVars(prefix + "customFilters"); - foreach (const QString &filterName, customFilterNames) { - QString name = config.getString(prefix + "customFilters" + Config::dot + filterName + Config::dot + "name"); - const auto &filters = config.getStringList(prefix + "customFilters" + Config::dot + filterName + Config::dot + "filterAttributes"); + const QSet customFilterNames = config.subVars(prefix + "customFilters"); + for (const auto &filterName : customFilterNames) { + QString name = config.getString(prefix + "customFilters" + Config::dot + filterName + + Config::dot + "name"); + const auto &filters = + config.getStringList(prefix + "customFilters" + Config::dot + filterName + + Config::dot + "filterAttributes"); project.customFilters[name] = QSet(filters.cbegin(), filters.cend()); } - //customFilters = config.defs. - foreach (QString name, config.getStringSet(prefix + "excluded")) + const auto excludedPrefixes = config.getStringSet(prefix + "excluded"); + for (auto name : excludedPrefixes) project.excluded.insert(name.replace(QLatin1Char('\\'), QLatin1Char('/'))); - foreach (const QString &name, config.getStringList(prefix + "subprojects")) { + const auto subprojectPrefixes = config.getStringList(prefix + "subprojects"); + for (const auto &name : subprojectPrefixes) { SubProject subproject; QString subprefix = prefix + "subprojects" + Config::dot + name + Config::dot; subproject.title = config.getString(subprefix + "title"); + if (subproject.title.isEmpty()) + continue; subproject.indexTitle = config.getString(subprefix + "indexTitle"); subproject.sortPages = config.getBool(subprefix + "sortPages"); subproject.type = config.getString(subprefix + "type"); @@ -126,13 +137,14 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["union"] = Node::Union; typeHash["header"] = Node::HeaderFile; typeHash["headerfile"] = Node::HeaderFile; - typeHash["doc"] = Node::Page; // to be removed from qdocconf files - typeHash["fake"] = Node::Page; // to be removed from qdocconf files + typeHash["doc"] = Node::Page; // Unused (supported but ignored as a prefix) + typeHash["fake"] = Node::Page; // Unused (supported but ignored as a prefix) typeHash["page"] = Node::Page; typeHash["enum"] = Node::Enum; typeHash["example"] = Node::Example; typeHash["externalpage"] = Node::ExternalPage; typeHash["typedef"] = Node::Typedef; + typeHash["typealias"] = Node::TypeAlias; typeHash["function"] = Node::Function; typeHash["property"] = Node::Property; typeHash["variable"] = Node::Variable; @@ -146,42 +158,26 @@ void HelpProjectWriter::readSelectors(SubProject &subproject, const QStringList typeHash["qmltype"] = Node::QmlType; typeHash["qmlbasictype"] = Node::QmlBasicType; - QHash pageTypeHash; - pageTypeHash["example"] = Node::Example; - pageTypeHash["headerfile"] = Node::HeaderFile; - pageTypeHash["header"] = Node::HeaderFile; - pageTypeHash["page"] = Node::Page; - pageTypeHash["externalpage"] = Node::ExternalPage; - - - NodeTypeSet fullSubset; - for (auto it = pageTypeHash.cbegin(), end = pageTypeHash.cend(); it != end; ++it) - fullSubset.insert(it.value()); - - foreach (const QString &selector, selectors) { + for (const QString &selector : selectors) { QStringList pieces = selector.split(QLatin1Char(':')); - if (pieces.size() == 1) { - QString lower = selector.toLower(); - if (typeHash.contains(lower)) - subproject.selectors[typeHash[lower]] = fullSubset; - } else if (pieces.size() >= 2) { - QString pageTypeStr = pieces[0].toLower(); - pieces = pieces[1].split(QLatin1Char(',')); - if (typeHash.contains(pageTypeStr)) { - NodeTypeSet nodeTypeSet; - for (int i = 0; i < pieces.size(); ++i) { - QString piece = pieces[i].toLower(); - if (typeHash[pageTypeStr] == Node::Group - || typeHash[pageTypeStr] == Node::Module - || typeHash[pageTypeStr] == Node::QmlModule - || typeHash[pageTypeStr] == Node::JsModule) { - subproject.groups << piece; - continue; - } - if (pageTypeHash.contains(piece)) - nodeTypeSet.insert(pageTypeHash[piece]); + // Remove doc: or fake: prefix + if (pieces.size() > 1 && typeHash.value(pieces[0].toLower()) == Node::Page) + pieces.takeFirst(); + + QString typeName = pieces.takeFirst().toLower(); + if (!typeHash.contains(typeName)) + continue; + + subproject.selectors << typeHash.value(typeName); + if (!pieces.isEmpty()) { + pieces = pieces[0].split(QLatin1Char(',')); + for (const auto &piece : qAsConst(pieces)) { + if (typeHash[typeName] == Node::Group + || typeHash[typeName] == Node::Module + || typeHash[typeName] == Node::QmlModule + || typeHash[typeName] == Node::JsModule) { + subproject.groups << piece.toLower(); } - subproject.selectors[typeHash[pageTypeStr]] = nodeTypeSet; } } } @@ -199,55 +195,46 @@ void HelpProjectWriter::addExtraFiles(const QSet &files) projects[i].extraFiles.unite(files); } -/*! - Returns a list of strings describing the keyword details for a given node. - - The first string is the human-readable name to be shown in Assistant. - The second string is a unique identifier. - The third string is the location of the documentation for the keyword. - */ -QStringList HelpProjectWriter::keywordDetails(const Node *node) const +Keyword HelpProjectWriter::keywordDetails(const Node *node) const { - QStringList details; + QString ref = gen_->fullDocumentLocation(node, false); if (node->parent() && !node->parent()->name().isEmpty()) { - // "name" - if (node->isEnumType() || node->isTypedef()) - details << node->parent()->name()+"::"+node->name(); - else - details << node->name(); - // "id" - details << node->parent()->name()+"::"+node->name(); - } - else if (node->isQmlType() || node->isQmlBasicType()) { - details << node->name(); - details << "QML." + node->name(); - } - else if (node->isJsType() || node->isJsBasicType()) { - details << node->name(); - details << "JS." + node->name(); - } - else if (node->isTextPageNode()) { - const PageNode *fake = static_cast(node); - details << fake->fullTitle(); - details << fake->fullTitle(); - } - else { - details << node->name(); - details << node->name(); + QString name = (node->isEnumType() || node->isTypedef()) + ? node->parent()->name()+"::"+node->name() + : node->name(); + QString id = (!node->isRelatedNonmember()) + ? node->parent()->name()+"::"+node->name() + : node->name(); + return Keyword(name, id, ref); + } else if (node->isQmlType() || node->isQmlBasicType()) { + QString name = node->name(); + QString moduleName = node->logicalModuleName(); + QStringList ids("QML." + name); + if (!moduleName.isEmpty()) { + QString majorVersion = node->logicalModule() + ? node->logicalModule()->logicalModuleVersion().split('.')[0] + : QString(); + ids << "QML." + moduleName + majorVersion + "." + name; + } + return Keyword(name, ids, ref); + } else if (node->isJsType() || node->isJsBasicType()) { + return Keyword(node->name(), "JS." + node->name(), ref); + } else if (node->isTextPageNode()) { + const auto *pageNode = static_cast(node); + return Keyword(pageNode->fullTitle(), pageNode->fullTitle(), ref); + } else { + return Keyword(node->name(), node->name(), ref); } - details << gen_->fullDocumentLocation(node, false); - return details; } -bool HelpProjectWriter::generateSection(HelpProject &project, - QXmlStreamWriter & /* writer */, +bool HelpProjectWriter::generateSection(HelpProject &project, QXmlStreamWriter & /* writer */, const Node *node) { if (!node->url().isEmpty() && !(project.includeIndexNodes && !node->url().startsWith("http"))) return false; - if (node->isPrivate() || node->isInternal()) + if (node->isPrivate() || node->isInternal() || node->isDontDocument()) return false; if (node->name().isEmpty()) @@ -266,31 +253,28 @@ bool HelpProjectWriter::generateSection(HelpProject &project, // No selectors: accept all nodes. if (subproject.selectors.isEmpty()) { project.subprojects[i].nodes[objName] = node; - } - else if (subproject.selectors.contains(node->nodeType())) { + } else if (subproject.selectors.contains(node->nodeType())) { // Add all group members for '[group|module|qmlmodule]:name' selector - if (node->isGroup() || node->isModule() || node->isQmlModule()) { + if (node->isCollectionNode()) { if (project.subprojects[i].groups.contains(node->name().toLower())) { - const CollectionNode* cn = static_cast(node); - foreach (const Node* m, cn->members()) { - QString memberName = m->isTextPageNode() - ? m->fullTitle() : m->fullDocumentName(); + const CollectionNode *cn = static_cast(node); + const auto members = cn->members(); + for (const Node *m : members) { + if (!m->isInAPI()) + continue; + QString memberName = + m->isTextPageNode() ? m->fullTitle() : m->fullDocumentName(); project.subprojects[i].nodes[memberName] = m; } + continue; + } else if (!project.subprojects[i].groups.isEmpty()) { + continue; // Node does not represent specified group(s) } + } else if (node->isTextPageNode()) { + if (node->isExternalPage() || node->fullTitle().isEmpty()) + continue; } - // Accept only the node types in the selectors hash. - else if (!node->isTextPageNode()) - project.subprojects[i].nodes[objName] = node; - else { - // Accept only doc nodes with subtypes contained in the selector's - // mask. - if (subproject.selectors[node->nodeType()].contains(node->nodeType()) && - !node->isExternalPage() && !node->fullTitle().isEmpty()) { - - project.subprojects[i].nodes[objName] = node; - } - } + project.subprojects[i].nodes[objName] = node; } } @@ -306,16 +290,17 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::JsType: case Node::JsBasicType: if (node->doc().hasKeywords()) { - foreach (const Atom* keyword, node->doc().keywords()) { + const auto keywords = node->doc().keywords(); + for (const Atom *keyword : keywords) { if (!keyword->string().isEmpty()) { - QStringList details; - details << keyword->string() - << keyword->string() - << gen_->fullDocumentLocation(node, false); - project.keywords.append(details); + project.keywords.append(Keyword(keyword->string(), + keyword->string(), + gen_->fullDocumentLocation(node, false))); } else - node->doc().location().warning(tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node, false))); + node->doc().location().warning( + QStringLiteral("Bad keyword in %1") + .arg(gen_->fullDocumentLocation(node, false))); } } project.keywords.append(keywordDetails(node)); @@ -327,53 +312,50 @@ bool HelpProjectWriter::generateSection(HelpProject &project, case Node::Enum: project.keywords.append(keywordDetails(node)); - { - const EnumNode *enumNode = static_cast(node); - foreach (const EnumItem &item, enumNode->items()) { - QStringList details; + { + const EnumNode *enumNode = static_cast(node); + const auto items = enumNode->items(); + for (const auto &item : items) { + QStringList details; - if (enumNode->itemAccess(item.name()) == Node::Private) - continue; + if (enumNode->itemAccess(item.name()) == Access::Private) + continue; - if (!node->parent()->name().isEmpty()) { - details << node->parent()->name()+"::"+item.name(); // "name" - details << node->parent()->name()+"::"+item.name(); // "id" - } else { - details << item.name(); // "name" - details << item.name(); // "id" + QString name; + QString id; + if (!node->parent()->name().isEmpty()) { + name = id = node->parent()->name() + "::" + item.name(); + } else { + name = id = item.name(); + } + QString ref = gen_->fullDocumentLocation(node, false); + project.keywords.append(Keyword(name, id, ref)); } - details << gen_->fullDocumentLocation(node, false); - project.keywords.append(details); } - } break; case Node::Group: case Node::Module: case Node::QmlModule: - case Node::JsModule: - { - const CollectionNode* cn = static_cast(node); - if (!cn->fullTitle().isEmpty()) { - if (cn->doc().hasKeywords()) { - foreach (const Atom* keyword, cn->doc().keywords()) { - if (!keyword->string().isEmpty()) { - QStringList details; - details << keyword->string() - << keyword->string() - << gen_->fullDocumentLocation(node, false); - project.keywords.append(details); - } - else - cn->doc().location().warning( - tr("Bad keyword in %1").arg(gen_->fullDocumentLocation(node, false)) - ); - } + case Node::JsModule: { + const auto *cn = static_cast(node); + if (!cn->fullTitle().isEmpty()) { + if (cn->doc().hasKeywords()) { + const auto keywords = cn->doc().keywords(); + for (const Atom *keyword : keywords) { + if (!keyword->string().isEmpty()) { + project.keywords.append(Keyword(keyword->string(), + keyword->string(), + gen_->fullDocumentLocation(node, false))); + } else + cn->doc().location().warning( + QStringLiteral("Bad keyword in %1") + .arg(gen_->fullDocumentLocation(node, false))); } - project.keywords.append(keywordDetails(node)); } + project.keywords.append(keywordDetails(node)); } - break; + } break; case Node::Property: case Node::QmlProperty: @@ -381,8 +363,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, project.keywords.append(keywordDetails(node)); break; - case Node::Function: - { + case Node::Function: { const FunctionNode *funcNode = static_cast(node); /* @@ -410,45 +391,39 @@ bool HelpProjectWriter::generateSection(HelpProject &project, if (node->parent()) project.memberStatus[node->parent()].insert(node->status()); - } - break; - - case Node::Typedef: - { + } break; + case Node::TypeAlias: + case Node::Typedef: { const TypedefNode *typedefNode = static_cast(node); - QStringList typedefDetails = keywordDetails(node); + Keyword typedefDetails = keywordDetails(node); const EnumNode *enumNode = typedefNode->associatedEnum(); // Use the location of any associated enum node in preference // to that of the typedef. if (enumNode) - typedefDetails[2] = gen_->fullDocumentLocation(enumNode, false); + typedefDetails.ref = gen_->fullDocumentLocation(enumNode, false); project.keywords.append(typedefDetails); - } - break; + } break; - case Node::Variable: - { + case Node::Variable: { project.keywords.append(keywordDetails(node)); - } - break; + } break; // Page nodes (such as manual pages) contain subtypes, titles and other // attributes. case Node::Page: { - const PageNode *pn = static_cast(node); + const auto *pn = static_cast(node); if (!pn->fullTitle().isEmpty()) { if (pn->doc().hasKeywords()) { - foreach (const Atom *keyword, pn->doc().keywords()) { + const auto keywords = pn->doc().keywords(); + for (const Atom *keyword : keywords) { if (!keyword->string().isEmpty()) { - QStringList details; - details << keyword->string() - << keyword->string() - << gen_->fullDocumentLocation(node, false); - project.keywords.append(details); + project.keywords.append(Keyword(keyword->string(), + keyword->string(), + gen_->fullDocumentLocation(node, false))); } else { QString loc = gen_->fullDocumentLocation(node, false); - pn->doc().location().warning(tr("Bad keyword in %1").arg(loc)); + pn->doc().location().warning(QStringLiteral("Bad keyword in %1").arg(loc)); } } } @@ -456,8 +431,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project, } break; } - default: - ; + default:; } // Add all images referenced in the page to the set of files to include. @@ -475,7 +449,8 @@ bool HelpProjectWriter::generateSection(HelpProject &project, return true; } -void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter &writer, const Node *node) +void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter &writer, + const Node *node) { /* Don't include index nodes in the help file. @@ -489,9 +464,12 @@ void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter const Aggregate *aggregate = static_cast(node); // Ensure that we don't visit nodes more than once. - QSet childSet; + QSet childSet; const NodeList &children = aggregate->childNodes(); - foreach (const Node *child, children) { + for (const auto *child : children) { + // Skip related non-members adopted by some other aggregate + if (child->parent() != aggregate) + continue; if (child->isIndexNode() || child->isPrivate()) continue; if (child->isTextPageNode()) { @@ -499,12 +477,12 @@ void HelpProjectWriter::generateSections(HelpProject &project, QXmlStreamWriter } else { // Store member status of children project.memberStatus[node].insert(child->status()); - if (child->isFunction() && static_cast(child)->isOverload()) + if (child->isFunction() && static_cast(child)->isOverload()) continue; childSet << child; } } - foreach (const Node *child, childSet) + for (const auto *child : qAsConst(childSet)) generateSections(project, writer, child); } } @@ -529,7 +507,7 @@ void HelpProjectWriter::writeHashFile(QFile &file) } void HelpProjectWriter::writeSection(QXmlStreamWriter &writer, const QString &path, - const QString &value) + const QString &value) { writer.writeStartElement(QStringLiteral("section")); writer.writeAttribute(QStringLiteral("ref"), path); @@ -540,11 +518,13 @@ void HelpProjectWriter::writeSection(QXmlStreamWriter &writer, const QString &pa /*! Write subsections for all members, compatibility members and obsolete members. */ -void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &writer, - const Node *node) +void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { + if (node->isQmlBasicType() || node->isJsBasicType()) + return; + QString href = gen_->fullDocumentLocation(node, false); - href = href.left(href.size()-5); + href = href.left(href.size() - 5); if (href.isEmpty()) return; @@ -554,20 +534,19 @@ void HelpProjectWriter::addMembers(HelpProject &project, QXmlStreamWriter &write // Do not generate a 'List of all members' for namespaces or header files, // but always generate it for derived classes and QML classes - if (!node->isNamespace() && !node->isHeader() && - (derivedClass || node->isQmlType() || node->isJsType() || - !project.memberStatus[node].isEmpty())) { + if (!node->isNamespace() && !node->isHeader() + && (derivedClass || node->isQmlType() || node->isJsType() + || !project.memberStatus[node].isEmpty())) { QString membersPath = href + QStringLiteral("-members.html"); - writeSection(writer, membersPath, tr("List of all members")); + writeSection(writer, membersPath, QStringLiteral("List of all members")); } if (project.memberStatus[node].contains(Node::Obsolete)) { QString obsoletePath = href + QStringLiteral("-obsolete.html"); - writeSection(writer, obsoletePath, tr("Obsolete members")); + writeSection(writer, obsoletePath, QStringLiteral("Obsolete members")); } } -void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer, - const Node *node) +void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node) { QString href = gen_->fullDocumentLocation(node, false); QString objName = node->name(); @@ -577,64 +556,48 @@ void HelpProjectWriter::writeNode(HelpProject &project, QXmlStreamWriter &writer case Node::Class: case Node::Struct: case Node::Union: + case Node::QmlType: + case Node::JsType: + case Node::QmlBasicType: + case Node::JsBasicType: { + QString typeStr = gen_->typeString(node); + if (!typeStr.isEmpty()) + typeStr[0] = typeStr[0].toTitleCase(); writer.writeStartElement("section"); writer.writeAttribute("ref", href); if (node->parent() && !node->parent()->name().isEmpty()) - writer.writeAttribute("title", tr("%1::%2 Class Reference").arg(node->parent()->name()).arg(objName)); + writer.writeAttribute("title", + QStringLiteral("%1::%2 %3 Reference") + .arg(node->parent()->name()) + .arg(objName) + .arg(typeStr)); else - writer.writeAttribute("title", tr("%1 Class Reference").arg(objName)); + writer.writeAttribute("title", + QStringLiteral("%1 %2 Reference").arg(objName).arg(typeStr)); addMembers(project, writer, node); writer.writeEndElement(); // section - break; + } break; case Node::Namespace: writeSection(writer, href, objName); break; + case Node::Example: case Node::HeaderFile: + case Node::Page: + case Node::Group: + case Node::Module: + case Node::JsModule: + case Node::QmlModule: { writer.writeStartElement("section"); writer.writeAttribute("ref", href); writer.writeAttribute("title", node->fullTitle()); - addMembers(project, writer, node); - writer.writeEndElement(); // section - break; - - case Node::JsType: - case Node::QmlType: - writer.writeStartElement("section"); - writer.writeAttribute("ref", href); - writer.writeAttribute("title", tr("%1 Type Reference").arg(node->fullTitle())); - addMembers(project, writer, node); - writer.writeEndElement(); // section - break; - - case Node::Page: { - // Page nodes (such as manual pages) contain subtypes, titles and other - // attributes. - const PageNode *pn = static_cast(node); - - writer.writeStartElement("section"); - writer.writeAttribute("ref", href); - writer.writeAttribute("title", pn->fullTitle()); - + if (node->nodeType() == Node::HeaderFile) + addMembers(project, writer, node); writer.writeEndElement(); // section - } - break; - case Node::Group: - case Node::Module: - case Node::JsModule: - case Node::QmlModule: - { - const CollectionNode* cn = static_cast(node); - writer.writeStartElement("section"); - writer.writeAttribute("ref", href); - writer.writeAttribute("title", cn->fullTitle()); - writer.writeEndElement(); // section - } - break; - default: - ; + } break; + default:; } } @@ -643,7 +606,7 @@ void HelpProjectWriter::generateProject(HelpProject &project) const Node *rootNode; // Restrict searching only to the local (primary) tree - QVector searchOrder = qdb_->searchOrder(); + QList searchOrder = qdb_->searchOrder(); qdb_->setLocalSearch(); if (!project.indexRoot.isEmpty()) @@ -676,13 +639,13 @@ void HelpProjectWriter::generateProject(HelpProject &project) writer.writeEndElement(); // Write customFilter elements. - QHash >::ConstIterator it; - for (it = project.customFilters.constBegin(); it != project.customFilters.constEnd(); ++it) { + for (auto it = project.customFilters.constBegin(); it != project.customFilters.constEnd(); + ++it) { writer.writeStartElement("customFilter"); writer.writeAttribute("name", it.key()); QStringList sortedAttributes = it.value().values(); sortedAttributes.sort(); - foreach (const QString &filter, sortedAttributes) + for (const auto &filter : qAsConst(sortedAttributes)) writer.writeTextElement("filterAttribute", filter); writer.writeEndElement(); // customFilter } @@ -693,13 +656,15 @@ void HelpProjectWriter::generateProject(HelpProject &project) // Write filterAttribute elements. QStringList sortedFilterAttributes = project.filterAttributes.values(); sortedFilterAttributes.sort(); - foreach (const QString &filterName, sortedFilterAttributes) + for (const auto &filterName : qAsConst(sortedFilterAttributes)) writer.writeTextElement("filterAttribute", filterName); writer.writeStartElement("toc"); writer.writeStartElement("section"); - const Node* node = qdb_->findPageNodeByTitle(project.indexTitle); - if (node == nullptr) + const Node *node = qdb_->findPageNodeByTitle(project.indexTitle); + if (!node) + node = qdb_->findNodeByNameAndType(QStringList(project.indexTitle), &Node::isPageNode); + if (!node) node = qdb_->findNodeByNameAndType(QStringList("index.html"), &Node::isPageNode); QString indexPath; if (node) @@ -747,17 +712,12 @@ void HelpProjectWriter::generateProject(HelpProject &project) writer.writeStartElement("section"); QString indexPath = gen_->fullDocumentLocation(page, false); writer.writeAttribute("ref", indexPath); - QString title = atom->string(); - if (atom->next() && atom->next()->string() == ATOM_FORMATTING_LINK) - if (atom->next()->next()) - title = atom->next()->next()->string(); - writer.writeAttribute("title", title); + writer.writeAttribute("title", atom->linkText()); sectionStack.top() += 1; } break; - default: - ; + default:; } if (atom == indexBody.lastAtom()) @@ -766,31 +726,30 @@ void HelpProjectWriter::generateProject(HelpProject &project) } } else rootNode->doc().location().warning( - tr("Failed to find index: %1").arg(subproject.indexTitle) - ); + QStringLiteral("Failed to find index: %1").arg(subproject.indexTitle)); } else { writer.writeStartElement("section"); - QString indexPath = gen_->fullDocumentLocation(qdb_->findNodeForTarget(subproject.indexTitle, nullptr), - false); + QString indexPath = gen_->fullDocumentLocation( + qdb_->findNodeForTarget(subproject.indexTitle, nullptr), false); writer.writeAttribute("ref", indexPath); writer.writeAttribute("title", subproject.title); if (subproject.sortPages) { QStringList titles = subproject.nodes.keys(); titles.sort(); - foreach (const QString &title, titles) { + for (const auto &title : qAsConst(titles)) { writeNode(project, writer, subproject.nodes[title]); } } else { // Find a contents node and navigate from there, using the NextLink values. QSet visited; bool contentsFound = false; - foreach (const Node *node, subproject.nodes) { + for (const auto *node : qAsConst(subproject.nodes)) { QString nextTitle = node->links().value(Node::NextLink).first; - if (!nextTitle.isEmpty() && - node->links().value(Node::ContentsLink).first.isEmpty()) { + if (!nextTitle.isEmpty() + && node->links().value(Node::ContentsLink).first.isEmpty()) { const Node *nextPage = qdb_->findNodeForTarget(nextTitle, nullptr); @@ -811,11 +770,11 @@ void HelpProjectWriter::generateProject(HelpProject &project) } // No contents/nextpage links found, write all nodes unsorted if (!contentsFound) { - QList subnodes = subproject.nodes.values(); + QList subnodes = subproject.nodes.values(); std::sort(subnodes.begin(), subnodes.end(), Node::nodeNameLessThan); - foreach (const Node *node, subnodes) + for (const auto *node : qAsConst(subnodes)) writeNode(project, writer, node); } } @@ -832,12 +791,14 @@ void HelpProjectWriter::generateProject(HelpProject &project) writer.writeStartElement("keywords"); std::sort(project.keywords.begin(), project.keywords.end()); - foreach (const QStringList &details, project.keywords) { - writer.writeStartElement("keyword"); - writer.writeAttribute("name", details[0]); - writer.writeAttribute("id", details[1]); - writer.writeAttribute("ref", details[2]); - writer.writeEndElement(); //keyword + for (const auto &k : qAsConst(project.keywords)) { + for (const auto &id : qAsConst(k.ids)) { + writer.writeStartElement("keyword"); + writer.writeAttribute("name", k.name); + writer.writeAttribute("id", id); + writer.writeAttribute("ref", k.ref); + writer.writeEndElement(); //keyword + } } writer.writeEndElement(); // keywords @@ -845,12 +806,13 @@ void HelpProjectWriter::generateProject(HelpProject &project) // The list of files to write is the union of generated files and // other files (images and extras) included in the project - QSet files = QSet(gen_->outputFileNames().cbegin(), gen_->outputFileNames().cend()); + QSet files = + QSet(gen_->outputFileNames().cbegin(), gen_->outputFileNames().cend()); files.unite(project.files); files.unite(project.extraFiles); QStringList sortedFiles = files.values(); sortedFiles.sort(); - foreach (const QString &usedFile, sortedFiles) { + for (const auto &usedFile : qAsConst(sortedFiles)) { if (!usedFile.isEmpty()) writer.writeTextElement("file", usedFile); } diff --git a/src/qdoc/helpprojectwriter.h b/src/qdoc/helpprojectwriter.h index bee6620ecc..1f465e8e20 100644 --- a/src/qdoc/helpprojectwriter.h +++ b/src/qdoc/helpprojectwriter.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -29,33 +29,48 @@ #ifndef HELPPROJECTWRITER_H #define HELPPROJECTWRITER_H -#include -#include - -#include "config.h" #include "node.h" +#include +#include + QT_BEGIN_NAMESPACE class QDocDatabase; class Generator; -typedef QPair QStringNodePair; +typedef QPair QStringNodePair; using NodeTypeSet = QSet; struct SubProject { - using NodeTypeToSet = QHash; - QString title; QString indexTitle; - NodeTypeToSet selectors; + NodeTypeSet selectors; bool sortPages; QString type; QHash nodes; QStringList groups; }; +/* + * Name is the human-readable name to be shown in Assistant. + * Ids is a list of unique identifiers. + * Ref is the location of the documentation for the keyword. + */ +struct Keyword { + QString name; + QStringList ids; + QString ref; + Keyword(QString name, QString id, QString ref) : name(name), ids(QStringList(id)), ref(ref) {} + Keyword(QString name, QStringList ids, QString ref) : name(name), ids(ids), ref(ref) {} + bool operator<(const Keyword &o) const + { + // Order by name; use ref as a secondary sort key + return (name == o.name) ? ref < o.ref : name < o.name; + } +}; + struct HelpProject { using NodeStatusSet = QSet; @@ -67,49 +82,40 @@ struct HelpProject QString fileName; QString indexRoot; QString indexTitle; - QList keywords; + QList keywords; QSet files; QSet extraFiles; QSet filterAttributes; - QHash > customFilters; + QHash> customFilters; QSet excluded; QList subprojects; QHash memberStatus; bool includeIndexNodes; }; + class HelpProjectWriter { - Q_DECLARE_TR_FUNCTIONS(QDoc::HelpProjectWriter) - public: - HelpProjectWriter(const Config &config, - const QString &defaultFileName, - Generator* g); - void reset(const Config &config, - const QString &defaultFileName, - Generator* g); + HelpProjectWriter(const QString &defaultFileName, Generator *g); + void reset(const QString &defaultFileName, Generator *g); void addExtraFile(const QString &file); void addExtraFiles(const QSet &files); void generate(); private: void generateProject(HelpProject &project); - void generateSections(HelpProject &project, QXmlStreamWriter &writer, - const Node *node); - bool generateSection(HelpProject &project, QXmlStreamWriter &writer, - const Node *node); - QStringList keywordDetails(const Node *node) const; + void generateSections(HelpProject &project, QXmlStreamWriter &writer, const Node *node); + bool generateSection(HelpProject &project, QXmlStreamWriter &writer, const Node *node); + Keyword keywordDetails(const Node *node) const; void writeHashFile(QFile &file); void writeNode(HelpProject &project, QXmlStreamWriter &writer, const Node *node); void readSelectors(SubProject &subproject, const QStringList &selectors); - void addMembers(HelpProject &project, QXmlStreamWriter &writer, - const Node *node); - void writeSection(QXmlStreamWriter &writer, const QString &path, - const QString &value); + void addMembers(HelpProject &project, QXmlStreamWriter &writer, const Node *node); + void writeSection(QXmlStreamWriter &writer, const QString &path, const QString &value); - QDocDatabase* qdb_; - Generator* gen_; + QDocDatabase *qdb_; + Generator *gen_; QString outputDir; QList projects; diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index 61df391564..80abcad143 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,45 +26,45 @@ ** ****************************************************************************/ -/* - htmlgenerator.cpp -*/ +#include "htmlgenerator.h" +#include "access.h" +#include "aggregate.h" +#include "classnode.h" +#include "collectionnode.h" +#include "config.h" #include "codemarker.h" #include "codeparser.h" +#include "enumnode.h" +#include "functionnode.h" #include "helpprojectwriter.h" -#include "htmlgenerator.h" +#include "manifestwriter.h" #include "node.h" +#include "propertynode.h" #include "qdocdatabase.h" -#include "separator.h" +#include "qmlpropertynode.h" +#include "sharedcommentnode.h" +#include "tagfilewriter.h" #include "tree.h" #include "quoter.h" -#include -#include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include + +#include QT_BEGIN_NAMESPACE int HtmlGenerator::id = 0; -bool HtmlGenerator::debugging_on = false; QString HtmlGenerator::divNavTop; static bool showBrokenLinks = false; -static QRegExp linkTag("(<@link node=\"([^\"]+)\">).*()"); -static QRegExp funcTag("(<@func target=\"([^\"]*)\">)(.*)()"); -static QRegExp typeTag("(<@(type|headerfile|func)(?: +[^>]*)?>)(.*)()"); -static QRegExp spanTag(""); -static QRegExp unknownTag("]*>"); - -static void addLink(const QString &linkTarget, - const QStringRef &nestedStuff, - QString *res) +static void addLink(const QString &linkTarget, QStringView nestedStuff, QString *res) { if (!linkTarget.isEmpty()) { *res += QLatin1String(""); *res += nestedStuff; *res += QLatin1String(""); - } - else { + } else { *res += nestedStuff; } } -/*! - Constructs the HTML output generator. - */ -HtmlGenerator::HtmlGenerator() - : codeIndent(0), - helpProjectWriter(nullptr), - inObsoleteLink(false), - funcLeftParen("\\S(\\()"), - obsoleteLinks(false) -{ -} - /*! Destroys the HTML output generator. Deletes the singleton - instance of HelpProjectWriter. + instance of HelpProjectWriter and the ManifestWriter instance. */ HtmlGenerator::~HtmlGenerator() { - if (helpProjectWriter) { - delete helpProjectWriter; - helpProjectWriter = nullptr; + if (m_helpProjectWriter) { + delete m_helpProjectWriter; + m_helpProjectWriter = nullptr; + } + + if (m_manifestWriter) { + delete m_manifestWriter; + m_manifestWriter = nullptr; } } /*! Initializes the HTML output generator's data structures - from the configuration class \a config. + from the configuration (Config) singleton. */ -void HtmlGenerator::initializeGenerator(const Config &config) +void HtmlGenerator::initializeGenerator() { - static const struct { + static const struct + { const char *key; const char *left; const char *right; - } defaults[] = { - { ATOM_FORMATTING_BOLD, "", "" }, - { ATOM_FORMATTING_INDEX, "" }, - { ATOM_FORMATTING_ITALIC, "", "" }, - { ATOM_FORMATTING_PARAMETER, "", "" }, - { ATOM_FORMATTING_SUBSCRIPT, "", "" }, - { ATOM_FORMATTING_SUPERSCRIPT, "", "" }, - { ATOM_FORMATTING_TELETYPE, "", "" }, // tag is not supported in HTML5 - { ATOM_FORMATTING_UICONTROL, "", "" }, - { ATOM_FORMATTING_UNDERLINE, "", "" }, - { nullptr, nullptr, nullptr } - }; - - Generator::initializeGenerator(config); - obsoleteLinks = config.getBool(CONFIG_OBSOLETELINKS); - setImageFileExtensions(QStringList() << "png" << "jpg" << "jpeg" << "gif"); + } defaults[] = { { ATOM_FORMATTING_BOLD, "", "" }, + { ATOM_FORMATTING_INDEX, "" }, + { ATOM_FORMATTING_ITALIC, "", "" }, + { ATOM_FORMATTING_PARAMETER, "", "" }, + { ATOM_FORMATTING_SUBSCRIPT, "", "" }, + { ATOM_FORMATTING_SUPERSCRIPT, "", "" }, + { ATOM_FORMATTING_TELETYPE, "", + "" }, // tag is not supported in HTML5 + { ATOM_FORMATTING_UICONTROL, "", "" }, + { ATOM_FORMATTING_UNDERLINE, "", "" }, + { nullptr, nullptr, nullptr } }; + + Generator::initializeGenerator(); + config = &Config::instance(); + setImageFileExtensions(QStringList() << "png" + << "jpg" + << "jpeg" + << "gif"); /* The formatting maps are owned by Generator. They are cleared in @@ -136,149 +131,81 @@ void HtmlGenerator::initializeGenerator(const Config &config) int i = 0; while (defaults[i].key) { formattingLeftMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].left)); - formattingRightMap().insert(QLatin1String(defaults[i].key), QLatin1String(defaults[i].right)); + formattingRightMap().insert(QLatin1String(defaults[i].key), + QLatin1String(defaults[i].right)); i++; } - style = config.getString(HtmlGenerator::format() + - Config::dot + - CONFIG_STYLE); - endHeader = config.getString(HtmlGenerator::format() + - Config::dot + - CONFIG_ENDHEADER); - postHeader = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_POSTHEADER); - postPostHeader = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_POSTPOSTHEADER); - prologue = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_PROLOGUE); - - footer = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_FOOTER); - address = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_ADDRESS); - pleaseGenerateMacRef = config.getBool(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_GENERATEMACREFS); - noNavigationBar = config.getBool(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_NONAVIGATIONBAR); - navigationSeparator = config.getString(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_NAVIGATIONSEPARATOR); - tocDepth = config.getInt(HtmlGenerator::format() + - Config::dot + - HTMLGENERATOR_TOCDEPTH); - - project = config.getString(CONFIG_PROJECT); - - projectDescription = config.getString(CONFIG_DESCRIPTION); - if (projectDescription.isEmpty() && !project.isEmpty()) - projectDescription = project + QLatin1String(" Reference Documentation"); - - projectUrl = config.getString(CONFIG_URL); - tagFile_ = config.getString(CONFIG_TAGFILE); - -#ifndef QT_NO_TEXTCODEC - outputEncoding = config.getString(CONFIG_OUTPUTENCODING); - if (outputEncoding.isEmpty()) - outputEncoding = QLatin1String("UTF-8"); - outputCodec = QTextCodec::codecForName(outputEncoding.toLocal8Bit()); -#endif - - naturalLanguage = config.getString(CONFIG_NATURALLANGUAGE); + m_endHeader = config->getString(HtmlGenerator::format() + Config::dot + CONFIG_ENDHEADER); + m_postHeader = + config->getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTHEADER); + m_postPostHeader = + config->getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_POSTPOSTHEADER); + m_prologue = config->getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_PROLOGUE); + + m_footer = config->getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_FOOTER); + m_address = config->getString(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_ADDRESS); + m_noNavigationBar = + config->getBool(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_NONAVIGATIONBAR); + m_navigationSeparator = config->getString(HtmlGenerator::format() + Config::dot + + HTMLGENERATOR_NAVIGATIONSEPARATOR); + tocDepth = config->getInt(HtmlGenerator::format() + Config::dot + HTMLGENERATOR_TOCDEPTH); + + m_project = config->getString(CONFIG_PROJECT); + + m_projectDescription = config->getString(CONFIG_DESCRIPTION); + if (m_projectDescription.isEmpty() && !m_project.isEmpty()) + m_projectDescription = m_project + QLatin1String(" Reference Documentation"); + + m_projectUrl = config->getString(CONFIG_URL); + tagFile_ = config->getString(CONFIG_TAGFILE); + + naturalLanguage = config->getString(CONFIG_NATURALLANGUAGE); if (naturalLanguage.isEmpty()) naturalLanguage = QLatin1String("en"); - QSet editionNames = config.subVars(CONFIG_EDITION); - QSet::ConstIterator edition = editionNames.constBegin(); - while (edition != editionNames.constEnd()) { - QString editionName = *edition; - QStringList editionModules = config.getStringList(CONFIG_EDITION + - Config::dot + - editionName + - Config::dot + - "modules"); - QStringList editionGroups = config.getStringList(CONFIG_EDITION + - Config::dot + - editionName + - Config::dot + - "groups"); - - if (!editionModules.isEmpty()) - editionModuleMap[editionName] = editionModules; - if (!editionGroups.isEmpty()) - editionGroupMap[editionName] = editionGroups; - - ++edition; - } - - codeIndent = config.getInt(CONFIG_CODEINDENT); // QTBUG-27798 - codePrefix = config.getString(CONFIG_CODEPREFIX); - codeSuffix = config.getString(CONFIG_CODESUFFIX); + m_codeIndent = config->getInt(CONFIG_CODEINDENT); // QTBUG-27798 + m_codePrefix = config->getString(CONFIG_CODEPREFIX); + m_codeSuffix = config->getString(CONFIG_CODESUFFIX); /* The help file write should be allocated once and only once per qdoc execution. */ - if (helpProjectWriter) - helpProjectWriter->reset(config, project.toLower() + ".qhp", this); + if (m_helpProjectWriter) + m_helpProjectWriter->reset(m_project.toLower() + ".qhp", this); else - helpProjectWriter = new HelpProjectWriter(config, project.toLower() + ".qhp", this); + m_helpProjectWriter = new HelpProjectWriter(m_project.toLower() + ".qhp", this); - // Documentation template handling - headerScripts = config.getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSCRIPTS); - headerStyles = config.getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSTYLES); + if (!m_manifestWriter) + m_manifestWriter = new ManifestWriter(); - QString prefix = CONFIG_QHP + Config::dot + project + Config::dot; - manifestDir = QLatin1String("qthelp://") + config.getString(prefix + QLatin1String("namespace")); - manifestDir += QLatin1Char('/') + config.getString(prefix + QLatin1String("virtualFolder")) + QLatin1Char('/'); - readManifestMetaContent(config); - examplesPath = config.getString(CONFIG_EXAMPLESINSTALLPATH); - if (!examplesPath.isEmpty()) - examplesPath += QLatin1Char('/'); + // Documentation template handling + m_headerScripts = + config->getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSCRIPTS); + m_headerStyles = config->getString(HtmlGenerator::format() + Config::dot + CONFIG_HEADERSTYLES); // Retrieve the config for the navigation bar - homepage = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_HOMEPAGE); + m_homepage = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_HOMEPAGE); - hometitle = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_HOMETITLE, homepage); + m_hometitle = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_HOMETITLE, m_homepage); - landingpage = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_LANDINGPAGE); + m_landingpage = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_LANDINGPAGE); - landingtitle = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_LANDINGTITLE, landingpage); + m_landingtitle = + config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_LANDINGTITLE, m_landingpage); - cppclassespage = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_CPPCLASSESPAGE); + m_cppclassespage = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_CPPCLASSESPAGE); - cppclassestitle = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_CPPCLASSESTITLE, - QLatin1String("C++ Classes")); + m_cppclassestitle = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_CPPCLASSESTITLE, + QLatin1String("C++ Classes")); - qmltypespage = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_QMLTYPESPAGE); + m_qmltypespage = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_QMLTYPESPAGE); - qmltypestitle = config.getString(CONFIG_NAVIGATION - + Config::dot - + CONFIG_QMLTYPESTITLE, - QLatin1String("QML Types")); + m_qmltypestitle = config->getString(CONFIG_NAVIGATION + Config::dot + CONFIG_QMLTYPESTITLE, + QLatin1String("QML Types")); - buildversion = config.getString(CONFIG_BUILDVERSION); + m_buildversion = config->getString(CONFIG_BUILDVERSION); } /*! @@ -298,19 +225,11 @@ QString HtmlGenerator::format() Generate targets for any \keyword commands that were seen in the qdoc comment for the \a node. */ -void HtmlGenerator::generateKeywordAnchors(const Node* node) +void HtmlGenerator::generateKeywordAnchors(const Node *node) { Q_UNUSED(node); // Disabled: keywords always link to the top of the QDoc // comment they appear in, and do not use a dedicated anchor. -#if 0 - if (!node->doc().isEmpty()) { - const QList& keywords = node->doc().keywords(); - foreach (Atom* a, keywords) { - out() << QLatin1String("string()) << QLatin1String("\">"); - } - } -#endif } /*! @@ -323,105 +242,43 @@ void HtmlGenerator::generateKeywordAnchors(const Node* node) */ void HtmlGenerator::generateDocs() { - Node* qflags = qdb_->findClassNode(QStringList("QFlags")); + Node *qflags = m_qdb->findClassNode(QStringList("QFlags")); if (qflags) - qflagsHref_ = linkForNode(qflags, nullptr); - if (!preparing()) + m_qflagsHref = linkForNode(qflags, nullptr); + if (!config->preparing()) Generator::generateDocs(); - if (Generator::generating() && Generator::writeQaPages()) - generateQAPage(); - - if (!generating()) { - QString fileBase = project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-')); - qdb_->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", - projectUrl, - projectDescription, - this); + + if (!config->generating()) { + QString fileBase = + m_project.toLower().simplified().replace(QLatin1Char(' '), QLatin1Char('-')); + m_qdb->generateIndex(outputDir() + QLatin1Char('/') + fileBase + ".index", m_projectUrl, + m_projectDescription, this); } - if (!preparing()) { - helpProjectWriter->generate(); - generateManifestFiles(); + if (!config->preparing()) { + m_helpProjectWriter->generate(); + m_manifestWriter->generateManifestFiles(); /* Generate the XML tag file, if it was requested. */ - qdb_->generateTagFile(tagFile_, this); - } -} - -/*! - Output the module's Quality Assurance page. - */ -void HtmlGenerator::generateQAPage() -{ - NamespaceNode* node = qdb_->primaryTreeRoot(); - beginSubPage(node, "aaa-" + defaultModuleName().toLower() + "-qa-page.html"); - CodeMarker* marker = CodeMarker::markerForFileName(node->location().filePath()); - QString title = "Quality Assurance Page for " + defaultModuleName(); - QString t = "Quality assurance information for checking the " + defaultModuleName() + " documentation."; - generateHeader(title, node, marker); - generateTitle(title, Text() << t, LargeSubTitle, node, marker); - - QStringList strings; - QVector counts; - QString depends = qdb_->getLinkCounts(strings, counts); - if (!strings.isEmpty()) { - t = "Intermodule Link Counts"; - QString ref = registerRef(t); - out() << "" << divNavTop << '\n'; - out() << "

" << protectEnc(t) << "

\n"; - out() << "
- QAbstractSocket + QAbstractSocket The base functionality common to all socket types
- QFtp - - Implementation of the FTP protocol -
... ...
" - << "\n"; - QString fileName; - for (int i = 0; i< strings.size(); ++i) { - fileName = generateLinksToLinksPage(strings.at(i), marker); - out() << "\n"; - } - int count = 0; - fileName = generateLinksToBrokenLinksPage(marker, count); - if (count != 0) { - out() << "\n"; - + if (!tagFile_.isEmpty()) { + TagFileWriter tagFileWriter; + tagFileWriter.generateTagFile(tagFile_, this); } - - out() << "
Destination ModuleLink Count
" - << "" - << strings.at(i) << "" - << "" << counts.at(i) - << "
" - << "" - << "Broken Links" << "" - << "" << count - << "
\n"; - t = "The Optimal \"depends\" Variable"; - out() << "

" << protectEnc(t) << "

\n"; - t = "Consider replacing the depends variable in " + defaultModuleName().toLower() + - ".qdocconf with this one, if the two are not identical:"; - out() << "

" << protectEnc(t) << "

\n"; - out() << "

" << protectEnc(depends) << "

\n"; } - generateFooter(); - endSubPage(); } /*! Generate an html file with the contents of a C++ or QML source file. */ -void HtmlGenerator::generateExampleFilePage(const Node *en, - const QString &file, - CodeMarker *marker) +void HtmlGenerator::generateExampleFilePage(const Node *en, const QString &file, CodeMarker *marker) { SubTitleSize subTitleSize = LargeSubTitle; QString fullTitle = en->fullTitle(); beginFilePage(en, linkForExampleFile(file, en)); generateHeader(fullTitle, en, marker); - generateTitle(fullTitle, - Text() << en->subtitle(), - subTitleSize, - en, - marker); + generateTitle(fullTitle, Text() << en->subtitle(), subTitleSize, en, marker); Text text; Quoter quoter; @@ -435,88 +292,6 @@ void HtmlGenerator::generateExampleFilePage(const Node *en, endFilePage(); } -/*! - This function writes an html file containing a list of - links to links that originate in the current module and - go to targets in the specified \a module. The \a marker - is used for the same thing the marker is always used for. - */ -QString HtmlGenerator::generateLinksToLinksPage(const QString& module, CodeMarker* marker) -{ - NamespaceNode* node = qdb_->primaryTreeRoot(); - QString fileName = "aaa-links-to-" + module + ".html"; - beginSubPage(node, fileName); - QString title = "Links from " + defaultModuleName() + " to " + module; - generateHeader(title, node, marker); - generateTitle(title, Text(), SmallSubTitle, node, marker); - out() << "

This is a list of links from " << defaultModuleName() - << " to " << module << ". "; - out() << "Click on a link to go to the location of the link. The link is marked "; - out() << "with red asterisks. "; - out() << "Click on the marked link to see if it goes to the right place.

\n"; - TargetList* tlist = qdb_->getTargetList(module); - if (tlist) { - out() << "\n"; - foreach (TargetLoc* t, *tlist) { - // e.g.: Layout Management - out() << ""; - out() << ""; - out() << "\n"; - } - out() << "
Link to link...In file...Somewhere after line number...
"; - out() << "fileName_ << "#" << t->target_ << "\">"; - out() << t->text_ << ""; - QString f = t->loc_->doc().location().filePath(); - out() << f << ""; - out() << t->loc_->doc().location().lineNo() << "
\n"; - } - generateFooter(); - endSubPage(); - return fileName; -} - -/*! - This function writes an html file containing a list of - links to broken links that originate in the current - module and go nowwhere. It returns the name of the file - it generates, and it sets \a count to the number of - broken links that were found. The \a marker is used for - the same thing the marker is always used for. - */ -QString HtmlGenerator::generateLinksToBrokenLinksPage(CodeMarker* marker, int& count) -{ - QString fileName; - NamespaceNode* node = qdb_->primaryTreeRoot(); - TargetList* tlist = qdb_->getTargetList("broken"); - if (tlist && !tlist->isEmpty()) { - count = tlist->size(); - fileName = "aaa-links-to-broken-links.html"; - beginSubPage(node, fileName); - QString title = "Broken links in " + defaultModuleName(); - generateHeader(title, node, marker); - generateTitle(title, Text(), SmallSubTitle, node, marker); - out() << "

This is a list of broken links in " << defaultModuleName() << ". "; - out() << "Click on a link to go to the broken link. "; - out() << "The link's target could not be found.

\n"; - out() << "\n"; - foreach (TargetLoc* t, *tlist) { - // e.g.: Layout Management - out() << ""; - out() << ""; - out() << "\n"; - } - out() << "
Link to broken link...In file...Somewhere after line number...
"; - out() << "fileName_ << "#" << t->target_ << "\">"; - out() << t->text_ << ""; - QString f = t->loc_->doc().location().filePath(); - out() << f << ""; - out() << t->loc_->doc().location().lineNo() << "
\n"; - generateFooter(); - endSubPage(); - } - return fileName; -} - /*! Generate html from an instance of Atom. */ @@ -524,36 +299,39 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark { int idx, skipAhead = 0; static bool in_para = false; + Node::Genus genus = Node::DontCare; switch (atom->type()) { - case Atom::AutoLink: + case Atom::AutoLink: { + QString name = atom->string(); + if (relative && relative->name() == name.replace(QLatin1String("()"), QLatin1String())) { + out() << protectEnc(atom->string()); + break; + } + // Allow auto-linking to nodes in API reference + genus = Node::API; + } + Q_FALLTHROUGH(); case Atom::NavAutoLink: - if (!inLink_ && !inContents_ && !inSectionHeading_) { + if (!m_inLink && !m_inContents && !m_inSectionHeading) { const Node *node = nullptr; - QString link = getAutoLink(atom, relative, &node); + QString link = getAutoLink(atom, relative, &node, genus); if (link.isEmpty()) { if (autolinkErrors()) - relative->doc().location().warning(tr("Can't autolink to '%1'").arg(atom->string())); - } - else if (node && node->isObsolete()) { + relative->doc().location().warning( + QStringLiteral("Can't autolink to '%1'").arg(atom->string())); + } else if (node && node->isObsolete()) { if ((relative->parent() != node) && !relative->isObsolete()) link.clear(); } if (link.isEmpty()) { out() << protectEnc(atom->string()); - } - else { - if (Generator::writeQaPages() && node && (atom->type() != Atom::NavAutoLink)) { - QString text = atom->string(); - QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text); - out() << ""; - } + } else { beginLink(link, node, relative); generateLink(atom, marker); endLink(); } - } - else { + } else { out() << protectEnc(atom->string()); } break; @@ -565,25 +343,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark break; } out() << "

"; - if (relative->isProperty() || relative->isVariable()) { - atom = atom->next(); - if (atom != nullptr && atom->type() == Atom::String) { - QString firstWord = atom->string().toLower().section(' ', 0, 0, QString::SectionSkipEmpty); - if (firstWord == QLatin1String("the") - || firstWord == QLatin1String("a") - || firstWord == QLatin1String("an") - || firstWord == QLatin1String("whether") - || firstWord == QLatin1String("which")) { - QString str = "This "; - if (relative->isProperty()) - str += "property holds "; - else - str += "variable holds "; - str += atom->string().left(1).toLower() + atom->string().mid(1); - const_cast(atom)->setString(str); - } - } - } + rewritePropertyBrief(atom, relative); break; case Atom::BriefRight: if (hasBrief(relative)) @@ -594,12 +354,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark // now widely used to write teletype text. As a result, text marked // with the \c command is not passed to a code marker. out() << formattingLeftMap()[ATOM_FORMATTING_TELETYPE]; - if (inLink_) { - out() << protectEnc(plainCode(atom->string())); - } - else { - out() << protectEnc(plainCode(atom->string())); - } + out() << protectEnc(plainCode(atom->string())); out() << formattingRightMap()[ATOM_FORMATTING_TELETYPE]; break; case Atom::CaptionLeft: @@ -615,12 +370,16 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark break; case Atom::Qml: out() << "

"
-              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative, false, Node::QML), codePrefix, codeSuffix)
+              << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
+                                                 false, Node::QML),
+                                 m_codePrefix, m_codeSuffix)
               << "
\n"; break; case Atom::JavaScript: out() << "
"
-              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative, false, Node::JS), codePrefix, codeSuffix)
+              << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative,
+                                                 false, Node::JS),
+                                 m_codePrefix, m_codeSuffix)
               << "
\n"; break; case Atom::CodeNew: @@ -628,7 +387,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark Q_FALLTHROUGH(); case Atom::Code: out() << "
"
-              << trimmedTrailing(highlightedCode(indent(codeIndent,atom->string()),relative), codePrefix, codeSuffix)
+              << trimmedTrailing(highlightedCode(indent(m_codeIndent, atom->string()), relative),
+                                 m_codePrefix, m_codeSuffix)
               << "
\n"; break; case Atom::CodeOld: @@ -636,7 +396,8 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark Q_FALLTHROUGH(); case Atom::CodeBad: out() << "
"
-              << trimmedTrailing(protectEnc(plainCode(indent(codeIndent,atom->string()))), codePrefix, codeSuffix)
+              << trimmedTrailing(protectEnc(plainCode(indent(m_codeIndent, atom->string()))),
+                                 m_codePrefix, m_codeSuffix)
               << "
\n"; break; case Atom::DivLeft: @@ -658,7 +419,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark break; case Atom::FootnoteRight: // ### For now - out() << "-->"; + out() << "-->\n"; break; case Atom::FormatElse: case Atom::FormatEndif: @@ -667,15 +428,15 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::FormattingLeft: if (atom->string().startsWith("span ")) { out() << '<' + atom->string() << '>'; - } - else + } else out() << formattingLeftMap()[atom->string()]; if (atom->string() == ATOM_FORMATTING_PARAMETER) { if (atom->next() != nullptr && atom->next()->type() == Atom::String) { - QRegExp subscriptRegExp("([a-z]+)_([0-9n])"); - if (subscriptRegExp.exactMatch(atom->next()->string())) { - out() << subscriptRegExp.cap(1) << "" - << subscriptRegExp.cap(2) << ""; + QRegularExpression subscriptRegExp("^([a-z]+)_([0-9n])$"); + auto match = subscriptRegExp.match(atom->next()->string()); + if (match.hasMatch()) { + out() << match.captured(1) << "" << match.captured(2) + << ""; skipAhead = 1; } } @@ -684,213 +445,160 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::FormattingRight: if (atom->string() == ATOM_FORMATTING_LINK) { endLink(); - } - else if (atom->string().startsWith("span ")) { + } else if (atom->string().startsWith("span ")) { out() << ""; - } - else { + } else { out() << formattingRightMap()[atom->string()]; } break; - case Atom::AnnotatedList: - { - const CollectionNode* cn = qdb_->getCollectionNode(atom->string(), Node::Group); - if (cn) - generateList(cn, marker, atom->string()); - } - break; + case Atom::AnnotatedList: { + const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), Node::Group); + if (cn) + generateList(cn, marker, atom->string()); + } break; case Atom::GeneratedList: if (atom->string() == QLatin1String("annotatedclasses")) { - generateAnnotatedList(relative, marker, qdb_->getCppClasses()); - } - else if (atom->string() == QLatin1String("annotatedexamples")) { - generateAnnotatedLists(relative, marker, qdb_->getExamples()); - } - else if (atom->string() == QLatin1String("annotatedattributions")) { - generateAnnotatedLists(relative, marker, qdb_->getAttributions()); - } - else if (atom->string() == QLatin1String("classes")) { - generateCompactList(Generic, relative, qdb_->getCppClasses(), true, QStringLiteral("")); - } - else if (atom->string().contains("classes ")) { + generateAnnotatedList(relative, marker, m_qdb->getCppClasses().values()); + } else if (atom->string() == QLatin1String("annotatedexamples")) { + generateAnnotatedLists(relative, marker, m_qdb->getExamples()); + } else if (atom->string() == QLatin1String("annotatedattributions")) { + generateAnnotatedLists(relative, marker, m_qdb->getAttributions()); + } else if (atom->string() == QLatin1String("classes")) { + generateCompactList(Generic, relative, m_qdb->getCppClasses(), true, + QStringLiteral("")); + } else if (atom->string().contains("classes ")) { QString rootName = atom->string().mid(atom->string().indexOf("classes") + 7).trimmed(); - generateCompactList(Generic, relative, qdb_->getCppClasses(), true, rootName); - } - else if (atom->string() == QLatin1String("qmlbasictypes")) { - generateCompactList(Generic, relative, qdb_->getQmlBasicTypes(), true, QStringLiteral("")); - } - else if (atom->string() == QLatin1String("qmltypes")) { - generateCompactList(Generic, relative, qdb_->getQmlTypes(), true, QStringLiteral("")); - } - else if ((idx = atom->string().indexOf(QStringLiteral("bymodule"))) != -1) { + generateCompactList(Generic, relative, m_qdb->getCppClasses(), true, rootName); + } else if (atom->string() == QLatin1String("qmlbasictypes")) { + generateCompactList(Generic, relative, m_qdb->getQmlBasicTypes(), true, + QStringLiteral("")); + } else if (atom->string() == QLatin1String("qmltypes")) { + generateCompactList(Generic, relative, m_qdb->getQmlTypes(), true, QStringLiteral("")); + } else if ((idx = atom->string().indexOf(QStringLiteral("bymodule"))) != -1) { QString moduleName = atom->string().mid(idx + 8).trimmed(); - Node::NodeType type = Node::Module; - if (atom->string().startsWith(QLatin1String("qml"))) - type = Node::QmlModule; - else if (atom->string().startsWith(QLatin1String("js"))) - type = Node::JsModule; - else if (atom->string().startsWith(QLatin1String("groups"))) - type = Node::Group; - QDocDatabase* qdb = QDocDatabase::qdocDB(); - const CollectionNode* cn = qdb->getCollectionNode(moduleName, type); + Node::NodeType type = typeFromString(atom); + QDocDatabase *qdb = QDocDatabase::qdocDB(); + const CollectionNode *cn = qdb->getCollectionNode(moduleName, type); if (cn) { if (type == Node::Module) { NodeMap m; cn->getMemberClasses(m); if (!m.isEmpty()) { - generateAnnotatedList(relative, marker, m); + generateAnnotatedList(relative, marker, m.values()); } - } - else + } else generateAnnotatedList(relative, marker, cn->members()); } - } - else if (atom->string().startsWith("examplefiles") || - atom->string().startsWith("exampleimages")) { + } else if (atom->string().startsWith("examplefiles") + || atom->string().startsWith("exampleimages")) { if (relative->isExample()) { -#if 0 - /* - The removed code will be physically removed if and - when this update is determined to be successful. - This overload of generateFileList() should no longer - be needed, so there is a qDebug() there to tell me - if it would have been called. So far, it hasn't - happened. mws 18/08/2018 - */ - Node::NodeSubtype subType = (atom->string().mid(7,5) == "image") ? Node::Image : Node::File; - QString regExp; - int secondArg = atom->string().indexOf(" "); - if (secondArg != -1) - regExp = atom->string().mid(++secondArg); - generateFileList(static_cast(relative), marker, subType, regExp); -#endif qDebug() << "GENERATE FILE LIST CALLED" << relative->name() << atom->string(); - } - else - relative->location().warning(QString("'\\generatelist \1' can only be used with '\\example' topic command").arg(atom->string())); - } - else if (atom->string() == QLatin1String("classhierarchy")) { - generateClassHierarchy(relative, qdb_->getCppClasses()); - } - else if (atom->string() == QLatin1String("obsoleteclasses")) { - generateCompactList(Generic, relative, qdb_->getObsoleteClasses(), false, QStringLiteral("Q")); - } - else if (atom->string() == QLatin1String("obsoleteqmltypes")) { - generateCompactList(Generic, relative, qdb_->getObsoleteQmlTypes(), false, QStringLiteral("")); - } - else if (atom->string() == QLatin1String("obsoletecppmembers")) { - generateCompactList(Obsolete, relative, qdb_->getClassesWithObsoleteMembers(), false, QStringLiteral("Q")); - } - else if (atom->string() == QLatin1String("obsoleteqmlmembers")) { - generateCompactList(Obsolete, relative, qdb_->getQmlTypesWithObsoleteMembers(), false, QStringLiteral("")); - } - else if (atom->string() == QLatin1String("functionindex")) { + } else + relative->location().warning(QString("'\\generatelist \1' can only be used with " + "'\\example' topic command") + .arg(atom->string())); + } else if (atom->string() == QLatin1String("classhierarchy")) { + generateClassHierarchy(relative, m_qdb->getCppClasses()); + } else if (atom->string() == QLatin1String("obsoleteclasses")) { + generateCompactList(Generic, relative, m_qdb->getObsoleteClasses(), false, + QStringLiteral("Q")); + } else if (atom->string() == QLatin1String("obsoleteqmltypes")) { + generateCompactList(Generic, relative, m_qdb->getObsoleteQmlTypes(), false, + QStringLiteral("")); + } else if (atom->string() == QLatin1String("obsoletecppmembers")) { + generateCompactList(Obsolete, relative, m_qdb->getClassesWithObsoleteMembers(), false, + QStringLiteral("Q")); + } else if (atom->string() == QLatin1String("obsoleteqmlmembers")) { + generateCompactList(Obsolete, relative, m_qdb->getQmlTypesWithObsoleteMembers(), false, + QStringLiteral("")); + } else if (atom->string() == QLatin1String("functionindex")) { generateFunctionIndex(relative); - } - else if (atom->string() == QLatin1String("attributions")) { - generateAnnotatedList(relative, marker, qdb_->getAttributions()); - } - else if (atom->string() == QLatin1String("legalese")) { + } else if (atom->string() == QLatin1String("attributions")) { + generateAnnotatedList(relative, marker, m_qdb->getAttributions().values()); + } else if (atom->string() == QLatin1String("legalese")) { generateLegaleseList(relative, marker); - } - else if (atom->string() == QLatin1String("overviews")) { + } else if (atom->string() == QLatin1String("overviews")) { generateList(relative, marker, "overviews"); - } - else if (atom->string() == QLatin1String("cpp-modules")) { + } else if (atom->string() == QLatin1String("cpp-modules")) { generateList(relative, marker, "cpp-modules"); - } - else if (atom->string() == QLatin1String("qml-modules")) { + } else if (atom->string() == QLatin1String("qml-modules")) { generateList(relative, marker, "qml-modules"); - } - else if (atom->string() == QLatin1String("namespaces")) { - generateAnnotatedList(relative, marker, qdb_->getNamespaces()); - } - else if (atom->string() == QLatin1String("related")) { + } else if (atom->string() == QLatin1String("namespaces")) { + generateAnnotatedList(relative, marker, m_qdb->getNamespaces().values()); + } else if (atom->string() == QLatin1String("related")) { generateList(relative, marker, "related"); } else { - const CollectionNode* cn = qdb_->getCollectionNode(atom->string(), Node::Group); + const CollectionNode *cn = m_qdb->getCollectionNode(atom->string(), Node::Group); if (cn) { - if (!generateGroupList(const_cast(cn))) - relative->location().warning(QString("'\\generatelist \1' group is empty").arg(atom->string())); + if (!generateGroupList(const_cast(cn))) + relative->location().warning( + QString("'\\generatelist \1' group is empty").arg(atom->string())); } else { - relative->location().warning(QString("'\\generatelist \1' no such group").arg(atom->string())); + relative->location().warning( + QString("'\\generatelist \1' no such group").arg(atom->string())); } } break; - case Atom::SinceList: - { - const NodeMultiMap& nsmap = qdb_->getSinceMap(atom->string()); - if (nsmap.isEmpty()) - break; + case Atom::SinceList: { + const NodeMultiMap &nsmap = m_qdb->getSinceMap(atom->string()); + if (nsmap.isEmpty()) + break; - const NodeMap& ncmap = qdb_->getClassMap(atom->string()); - const NodeMap& nqcmap = qdb_->getQmlTypeMap(atom->string()); + const NodeMultiMap &ncmap = m_qdb->getClassMap(atom->string()); + const NodeMultiMap &nqcmap = m_qdb->getQmlTypeMap(atom->string()); - Sections sections(nsmap); - out() << "
    \n"; - QVector
    ::ConstIterator s = sections.sinceSections().constBegin(); - while (s != sections.sinceSections().constEnd()) { - if (!s->members().isEmpty()) { - out() << "
  • " - << "title()) - << "\">" - << s->title() - << "
  • \n"; - } - ++s; + Sections sections(nsmap); + out() << "
      \n"; + const QList
      sinceSections = sections.sinceSections(); + for (const auto §ion : sinceSections) { + if (!section.members().isEmpty()) { + out() << "
    • " + << "" + << section.title() << "
    • \n"; } - out() << "
    \n"; + } + out() << "
\n"; - int idx = 0; - s = sections.sinceSections().constBegin(); - while (s != sections.sinceSections().constEnd()) { - if (!s->members().isEmpty()) { - out() << "title()) - << "\">\n"; - out() << "

" << protectEnc(s->title()) << "

\n"; - if (idx == Sections::SinceClasses) - generateCompactList(Generic, nullptr, ncmap, false, QStringLiteral("Q")); - else if (idx == Sections::SinceQmlTypes) - generateCompactList(Generic, nullptr, nqcmap, false, QStringLiteral("")); - else if (idx == Sections::SinceMemberFunctions) { - ParentMaps parentmaps; - ParentMaps::iterator pmap; - NodeVector::const_iterator i = s->members().constBegin(); - while (i != s->members().constEnd()) { - Node* p = (*i)->parent(); - pmap = parentmaps.find(p); - if (pmap == parentmaps.end()) - pmap = parentmaps.insert(p,NodeMultiMap()); - pmap->insert((*i)->name(),(*i)); - ++i; - } - pmap = parentmaps.begin(); - while (pmap != parentmaps.end()) { - NodeVector nv = pmap->values().toVector(); - out() << "

Class "; - - out() << ""; - QStringList pieces = pmap.key()->fullName().split("::"); - out() << protectEnc(pieces.last()); - out() << "" << ":

\n"; - - generateSection(nv, nullptr, marker); - out() << "
"; - ++pmap; - } + int index = 0; + for (const auto §ion : sinceSections) { + if (!section.members().isEmpty()) { + out() << "\n"; + out() << "

" << protectEnc(section.title()) << "

\n"; + if (index == Sections::SinceClasses) + generateCompactList(Generic, relative, ncmap, false, QStringLiteral("Q")); + else if (index == Sections::SinceQmlTypes) + generateCompactList(Generic, relative, nqcmap, false, QStringLiteral("")); + else if (index == Sections::SinceMemberFunctions) { + ParentMaps parentmaps; + ParentMaps::iterator pmap; + const QList &members = section.members(); + for (const auto &member : members) { + Node *parent = (*member).parent(); + pmap = parentmaps.find(parent); + if (pmap == parentmaps.end()) + pmap = parentmaps.insert(parent, NodeMultiMap()); + pmap->insert(member->name(), member); } - else - generateSection(s->members(), nullptr, marker); + for (auto map = parentmaps.begin(); map != parentmaps.end(); ++map) { + NodeVector nv = map->values().toVector(); + out() << "

Class "; + + out() << ""; + QStringList pieces = map.key()->fullName().split("::"); + out() << protectEnc(pieces.last()); + out() << "" + << ":

\n"; + + generateSection(nv, relative, marker); + out() << "
"; + } + } else { + generateSection(section.members(), relative, marker); } - ++idx; - ++s; } + ++index; } - break; + } break; case Atom::BR: out() << "
\n"; break; @@ -898,8 +606,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "
\n"; break; case Atom::Image: - case Atom::InlineImage: - { + case Atom::InlineImage: { QString fileName = imageFileName(relative, atom->string()); QString text; if (atom->next() != nullptr) @@ -907,11 +614,11 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark if (atom->type() == Atom::Image) out() << "

"; if (fileName.isEmpty()) { - relative->location().warning(tr("Missing image: %1").arg(protectEnc(atom->string()))); - out() << "[Missing image " - << protectEnc(atom->string()) << "]"; - } - else { + relative->location().warning( + QStringLiteral("Missing image: %1").arg(protectEnc(atom->string()))); + out() << "[Missing image " << protectEnc(atom->string()) + << "]"; + } else { QString prefix; out() << "\"\"";"; - helpProjectWriter->addExtraFile(fileName); - if (relative->isExample()) { - const ExampleNode* cen = static_cast(relative); - if (cen->imageFileName().isEmpty()) { - ExampleNode* en = const_cast(cen); - en->setImageFileName(fileName); - } - } + m_helpProjectWriter->addExtraFile(fileName); + setImageFileName(relative, fileName); } if (atom->type() == Atom::Image) out() << "

"; - } - break; + } break; case Atom::ImageText: break; case Atom::ImportantLeft: @@ -950,7 +650,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << formattingRightMap()[ATOM_FORMATTING_BOLD]; break; case Atom::NoteRight: - out() << "

"; + out() << "

\n"; break; case Atom::LegaleseLeft: out() << "
"; @@ -962,73 +662,40 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "
"; break; case Atom::Link: - case Atom::NavLink: - { - inObsoleteLink = false; + case Atom::NavLink: { const Node *node = nullptr; QString link = getLink(atom, relative, &node); if (link.isEmpty() && (node != relative) && !noLinkErrors()) { - relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string())); - if (Generator::writeQaPages() && (atom->type() != Atom::NavAutoLink)) { - QString text = atom->next()->next()->string(); - QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text, true); - out() << ""; - } - } - else { - if (Generator::writeQaPages() && node && (atom->type() != Atom::NavLink)) { - QString text = atom->next()->next()->string(); - QString target = qdb_->getNewLinkTarget(relative, node, outFileName(), text); - out() << ""; - } - /* - mws saw this on 17/10/2014. - Is this correct? Setting node to 0 means the - following test always fails. Did we decide to - no longer warn about linking to obsolete things? - */ + relative->doc().location().warning( + QStringLiteral("Can't link to '%1'").arg(atom->string())); + } else { node = nullptr; - if (node && node->isObsolete()) { - if ((relative->parent() != node) && !relative->isObsolete()) { - inObsoleteLink = true; - if (obsoleteLinks) { - relative->doc().location().warning(tr("Link to obsolete item '%1' in %2") - .arg(atom->string()) - .arg(relative->plainFullName())); - } - } - } } beginLink(link, node, relative); skipAhead = 1; - } - break; - case Atom::ExampleFileLink: - { + } break; + case Atom::ExampleFileLink: { QString link = linkForExampleFile(atom->string(), relative); if (link.isEmpty() && !noLinkErrors()) - relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string())); + relative->doc().location().warning( + QStringLiteral("Can't link to '%1'").arg(atom->string())); beginLink(link); skipAhead = 1; - } - break; - case Atom::ExampleImageLink: - { + } break; + case Atom::ExampleImageLink: { QString link = atom->string(); if (link.isEmpty() && !noLinkErrors()) - relative->doc().location().warning(tr("Can't link to '%1'").arg(atom->string())); + relative->doc().location().warning( + QStringLiteral("Can't link to '%1'").arg(atom->string())); link = "images/used-in-examples/" + link; beginLink(link); skipAhead = 1; - } - break; - case Atom::LinkNode: - { + } break; + case Atom::LinkNode: { const Node *node = CodeMarker::nodeForString(atom->string()); beginLink(linkForNode(node, relative), node, relative); skipAhead = 1; - } - break; + } break; case Atom::ListLeft: if (in_para) { out() << "

\n"; @@ -1036,18 +703,16 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark } if (atom->string() == ATOM_LIST_BULLET) { out() << "
    \n"; - } - else if (atom->string() == ATOM_LIST_TAG) { + } else if (atom->string() == ATOM_LIST_TAG) { out() << "
    \n"; - } - else if (atom->string() == ATOM_LIST_VALUE) { - out() << "
    "; - threeColumnEnumValueTable_ = isThreeColumnEnumValueTable(atom); - if (threeColumnEnumValueTable_) { - if (++numTableRows_ % 2 == 1) - out() << ""; + } else if (atom->string() == ATOM_LIST_VALUE) { + out() << R"(
    )"; + m_threeColumnEnumValueTable = isThreeColumnEnumValueTable(atom); + if (m_threeColumnEnumValueTable) { + if (++m_numTableRows % 2 == 1) + out() << R"()"; else - out() << ""; + out() << R"()"; out() << ""; @@ -1056,35 +721,30 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << ""; out() << "\n"; + } else { + out() << "\n"; } - else { - out() << "\n"; - } - } - else { + } else { QString olType; if (atom->string() == ATOM_LIST_UPPERALPHA) { olType = "A"; - } - else if (atom->string() == ATOM_LIST_LOWERALPHA) { + } else if (atom->string() == ATOM_LIST_LOWERALPHA) { olType = "a"; - } - else if (atom->string() == ATOM_LIST_UPPERROMAN) { + } else if (atom->string() == ATOM_LIST_UPPERROMAN) { olType = "I"; - } - else if (atom->string() == ATOM_LIST_LOWERROMAN) { + } else if (atom->string() == ATOM_LIST_LOWERROMAN) { olType = "i"; - } - else { // (atom->string() == ATOM_LIST_NUMERIC) + } else { // (atom->string() == ATOM_LIST_NUMERIC) olType = "1"; } if (atom->next() != nullptr && atom->next()->string().toInt() > 1) { - out() << QString("
      ").arg(olType) - .arg(atom->next()->string()); - } - else - out() << QString("
        ").arg(olType); + out() << QString(R"(
          )") + .arg(olType) + .arg(atom->next()->string()); + } else + out() << QString(R"(
            )").arg(olType); } break; case Atom::ListItemNumber: @@ -1092,31 +752,15 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::ListTagLeft: if (atom->string() == ATOM_LIST_TAG) { out() << "
            "; - } - else { // (atom->string() == ATOM_LIST_VALUE) - const Atom* lookAhead = atom->next(); - QString t = lookAhead->string(); - lookAhead = lookAhead->next(); - Q_ASSERT(lookAhead->type() == Atom::ListTagRight); - lookAhead = lookAhead->next(); - if (lookAhead && lookAhead->type() == Atom::SinceTagLeft) { - lookAhead = lookAhead->next(); - Q_ASSERT(lookAhead && lookAhead->type() == Atom::String); - t = t + QLatin1String(" (since "); - if (lookAhead->string().at(0).isDigit()) - t = t + QLatin1String("Qt "); - t = t + lookAhead->string() + QLatin1String(")"); - skipAhead = 4; - } - else { - skipAhead = 1; - } - t = protectEnc(plainCode(marker->markedUpEnumValue(t, relative))); + } else { // (atom->string() == ATOM_LIST_VALUE) + QPair pair = getAtomListValue(atom); + skipAhead = pair.second; + QString t = protectEnc(plainCode(marker->markedUpEnumValue(pair.first, relative))); out() << "
    \n"; - } - else { + } else { out() << "\n"; } break; case Atom::ListRight: if (atom->string() == ATOM_LIST_BULLET) { out() << "\n"; - } - else if (atom->string() == ATOM_LIST_TAG) { + } else if (atom->string() == ATOM_LIST_TAG) { out() << "\n"; - } - else if (atom->string() == ATOM_LIST_VALUE) { + } else if (atom->string() == ATOM_LIST_VALUE) { out() << "
    ConstantValueDescription
    ConstantValue
    ConstantValue
    " << t << ""; if (relative->isEnumType()) { out() << ""; - const EnumNode *enume = static_cast(relative); + const auto *enume = static_cast(relative); QString itemValue = enume->itemValue(atom->next()->string()); if (itemValue.isEmpty()) out() << '?'; @@ -1133,15 +777,13 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::ListItemLeft: if (atom->string() == ATOM_LIST_TAG) { out() << "
    "; - } - else if (atom->string() == ATOM_LIST_VALUE) { - if (threeColumnEnumValueTable_) { + } else if (atom->string() == ATOM_LIST_VALUE) { + if (m_threeColumnEnumValueTable) { out() << "
    "; if (matchAhead(atom, Atom::ListItemRight)) out() << " "; } - } - else { + } else { out() << "
  • "; } if (matchAhead(atom, Atom::ParaLeft)) @@ -1150,25 +792,20 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark case Atom::ListItemRight: if (atom->string() == ATOM_LIST_TAG) { out() << "\n"; - } - else if (atom->string() == ATOM_LIST_VALUE) { + } else if (atom->string() == ATOM_LIST_VALUE) { out() << "
  • \n"; - } - else { + } else { out() << "\n"; } break; @@ -1184,7 +821,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "

    \n"; in_para = false; } - //if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight)) + // if (!matchAhead(atom, Atom::ListItemRight) && !matchAhead(atom, Atom::TableItemRight)) // out() << "

    \n"; break; case Atom::QuotationLeft: @@ -1204,104 +841,83 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark break; case Atom::SectionHeadingLeft: { int unit = atom->string().toInt() + hOffset(relative); - out() << ""; - inSectionHeading_ = true; + out() << ""; + m_inSectionHeading = true; break; } case Atom::SectionHeadingRight: out() << "string().toInt() + hOffset(relative)) + ">\n"; - inSectionHeading_ = false; + m_inSectionHeading = false; break; case Atom::SidebarLeft: - break; + Q_FALLTHROUGH(); case Atom::SidebarRight: break; case Atom::String: - if (inLink_ && !inContents_ && !inSectionHeading_) { + if (m_inLink && !m_inContents && !m_inSectionHeading) { generateLink(atom, marker); - } - else { + } else { out() << protectEnc(atom->string()); } break; - case Atom::TableLeft: - { - QString p1, p2; - QString attr = "generic"; - QString width; + case Atom::TableLeft: { + QPair pair = getTableWidthAttr(atom); + QString attr = pair.second; + QString width = pair.first; + if (in_para) { out() << "

    \n"; in_para = false; } - if (atom->count() > 0) { - p1 = atom->string(0); - if (atom->count() > 1) - p2 = atom->string(1); - } - if (!p1.isEmpty()) { - if (p1 == QLatin1String("borderless")) - attr = p1; - else if (p1.contains(QLatin1Char('%'))) - width = p1; - } - if (!p2.isEmpty()) { - if (p2 == QLatin1String("borderless")) - attr = p2; - else if (p2.contains(QLatin1Char('%'))) - width = p2; - } - out() << "
    \n "; - numTableRows_ = 0; - } - break; + m_numTableRows = 0; + } break; case Atom::TableRight: out() << "
    \n"; break; case Atom::TableHeaderLeft: out() << ""; - inTableHeader_ = true; + m_inTableHeader = true; break; case Atom::TableHeaderRight: out() << ""; if (matchAhead(atom, Atom::TableHeaderLeft)) { skipAhead = 1; out() << "\n"; - } - else { + } else { out() << "\n"; - inTableHeader_ = false; + m_inTableHeader = false; } break; case Atom::TableRowLeft: if (!atom->string().isEmpty()) out() << "string() << '>'; - else if (++numTableRows_ % 2 == 1) - out() << ""; + else if (++m_numTableRows % 2 == 1) + out() << R"()"; else - out() << ""; + out() << R"()"; break; case Atom::TableRowRight: out() << "\n"; break; - case Atom::TableItemLeft: - { - if (inTableHeader_) + case Atom::TableItemLeft: { + if (m_inTableHeader) out() << "count(); ++i) { + for (int i = 0; i < atom->count(); ++i) { if (i > 0) out() << ' '; - QString p = atom->string(i); + const QString &p = atom->string(i); if (p.contains('=')) { out() << p; - } - else { + } else { QStringList spans = p.split(QLatin1Char(',')); if (spans.size() == 2) { if (spans.at(0) != "1") @@ -1311,28 +927,21 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark } } } - if (inTableHeader_) - out() << '>'; - else { - out() << '>'; - //out() << ">

    "; - } + out() << '>'; if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; - } - break; + } break; case Atom::TableItemRight: - if (inTableHeader_) + if (m_inTableHeader) out() << ""; else { out() << ""; - //out() << "

    "; } if (matchAhead(atom, Atom::ParaLeft)) skipAhead = 1; break; case Atom::TableOfContents: - break; + Q_FALLTHROUGH(); case Atom::Keyword: break; case Atom::Target: @@ -1342,8 +951,7 @@ int HtmlGenerator::generateAtom(const Atom *atom, const Node *relative, CodeMark out() << "<Missing HTML>"; break; case Atom::UnknownCommand: - out() << "\\" << protectEnc(atom->string()) - << ""; + out() << R"(\)" << protectEnc(atom->string()) << ""; break; case Atom::QmlText: case Atom::EndQmlText: @@ -1372,46 +980,49 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m QString title; QString rawTitle; QString fullTitle; - NamespaceNode* ns = nullptr; + NamespaceNode *ns = nullptr; SectionVector *summarySections = nullptr; SectionVector *detailsSections = nullptr; Sections sections(aggregate); QString word = aggregate->typeWord(true); + QString templateDecl = aggregate->templateDecl(); if (aggregate->isNamespace()) { rawTitle = aggregate->plainName(); fullTitle = aggregate->plainFullName(); title = rawTitle + " Namespace"; - ns = static_cast(aggregate); + ns = static_cast(aggregate); summarySections = §ions.stdSummarySections(); detailsSections = §ions.stdDetailsSections(); - } - else if (aggregate->isClassNode()) { + } else if (aggregate->isClassNode()) { rawTitle = aggregate->plainName(); fullTitle = aggregate->plainFullName(); - if (aggregate->isStruct()) - word = QLatin1String("Struct"); - else if (aggregate->isUnion()) - word = QLatin1String("Union"); - title = rawTitle + " " + word; + title = rawTitle + QLatin1Char(' ') + word; summarySections = §ions.stdCppClassSummarySections(); detailsSections = §ions.stdCppClassDetailsSections(); - } - else if (aggregate->isHeader()) { + } else if (aggregate->isHeader()) { title = fullTitle = rawTitle = aggregate->fullTitle(); summarySections = §ions.stdSummarySections(); detailsSections = §ions.stdDetailsSections(); } Text subtitleText; - if (rawTitle != fullTitle) { - if (aggregate->parent()->isClassNode()) { - QString word2 = aggregate->parent()->typeWord(false); - subtitleText << word << " " << rawTitle << " is declared in " << word2 - << " " << Atom(Atom::AutoLink, aggregate->parent()->plainName()) - << "." << Atom(Atom::LineBreak); + if (rawTitle != fullTitle || !templateDecl.isEmpty()) { + if (aggregate->isClassNode()) { + if (!templateDecl.isEmpty()) + subtitleText << templateDecl + QLatin1Char(' '); + subtitleText << aggregate->typeWord(false) + QLatin1Char(' '); + const QStringList ancestors = fullTitle.split(QLatin1String("::")); + for (const auto &a : ancestors) { + if (a == rawTitle) { + subtitleText << a; + break; + } else { + subtitleText << Atom(Atom::AutoLink, a) << "::"; + } + } } else { - subtitleText << "(" << Atom(Atom::AutoLink, fullTitle) << ")" << Atom(Atom::LineBreak); + subtitleText << fullTitle; } } @@ -1420,25 +1031,27 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m generateKeywordAnchors(aggregate); generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker); if (ns && !ns->hasDoc() && ns->docNode()) { - NamespaceNode* NS = ns->docNode(); + NamespaceNode *NS = ns->docNode(); Text brief; brief << "The " << ns->name() << " namespace includes the following elements from module " << ns->tree()->camelCaseModuleName() << ". The full namespace is " << "documented in module " << NS->tree()->camelCaseModuleName() << Atom(Atom::LinkNode, CodeMarker::stringForNode(NS)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, " here.") + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, " here.") << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); out() << "

    "; generateText(brief, ns, marker); out() << "

    \n"; - } - else + } else generateBrief(aggregate, marker); - if (!aggregate->parent()->isClassNode()) + + const auto parentIsClass = aggregate->parent()->isClassNode(); + + if (!parentIsClass) generateRequisites(aggregate, marker); generateStatus(aggregate, marker); - generateSince(aggregate, marker); + if (parentIsClass) + generateSince(aggregate, marker); out() << "
      \n"; @@ -1458,45 +1071,40 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m bool needOtherSection = false; - SectionVector::ConstIterator s = summarySections->constBegin(); - while (s != summarySections->constEnd()) { - if (s->members().isEmpty() && s->reimplementedMembers().isEmpty()) { - if (!s->inheritedMembers().isEmpty()) + for (const auto §ion : qAsConst(*summarySections)) { + if (section.members().isEmpty() && section.reimplementedMembers().isEmpty()) { + if (!section.inheritedMembers().isEmpty()) needOtherSection = true; - } - else { - if (!s->members().isEmpty()) { - QString ref = registerRef(s->title().toLower()); + } else { + if (!section.members().isEmpty()) { + QString ref = registerRef(section.title().toLower()); out() << "" << divNavTop << "\n"; - out() << "

      " << protectEnc(s->title()) << "

      \n"; - generateSection(s->members(), aggregate, marker); + out() << "

      " << protectEnc(section.title()) << "

      \n"; + generateSection(section.members(), aggregate, marker); } - if (!s->reimplementedMembers().isEmpty()) { - QString name = QString("Reimplemented ") + s->title(); + if (!section.reimplementedMembers().isEmpty()) { + QString name = QString("Reimplemented ") + section.title(); QString ref = registerRef(name.toLower()); out() << "" << divNavTop << "\n"; out() << "

      " << protectEnc(name) << "

      \n"; - generateSection(s->reimplementedMembers(), aggregate, marker); + generateSection(section.reimplementedMembers(), aggregate, marker); } - if (!s->inheritedMembers().isEmpty()) { + if (!section.inheritedMembers().isEmpty()) { out() << "
        \n"; - generateSectionInheritedList(*s, aggregate); + generateSectionInheritedList(section, aggregate); out() << "
      \n"; } } - ++s; } if (needOtherSection) { out() << "

      Additional Inherited Members

      \n" "
        \n"; - s = summarySections->constBegin(); - while (s != summarySections->constEnd()) { - if (s->members().isEmpty() && !s->inheritedMembers().isEmpty()) - generateSectionInheritedList(*s, aggregate); - ++s; + for (const auto §ion : qAsConst(*summarySections)) { + if (section.members().isEmpty() && !section.inheritedMembers().isEmpty()) + generateSectionInheritedList(section, aggregate); } out() << "
      \n"; } @@ -1507,12 +1115,19 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m if (aggregate->doc().isEmpty()) { QString command = "documentation"; if (aggregate->isClassNode()) - command = "\'\\class\' comment"; - aggregate->location().warning(tr("No %1 for '%2'").arg(command).arg(aggregate->plainSignature())); + command = R"('\class' comment)"; + if (!ns || ns->isDocumentedHere()) { + aggregate->location().warning( + QStringLiteral("No %1 for '%2'") + .arg(command) + .arg(aggregate->plainSignature())); + } } else { generateExtractionMark(aggregate, DetailedDescriptionMark); out() << "
      \n" // QTBUG-9504 - << "

      " << "Detailed Description" << "

      \n"; + << "

      " + << "Detailed Description" + << "

      \n"; generateBody(aggregate, marker); out() << "
      \n"; // QTBUG-9504 generateAlsoList(aggregate, marker); @@ -1520,44 +1135,39 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m generateExtractionMark(aggregate, EndMark); } - s = detailsSections->constBegin(); - while (s != detailsSections->constEnd()) { + for (const auto §ion : qAsConst(*detailsSections)) { bool headerGenerated = false; - if (s->isEmpty()) { - ++s; + if (section.isEmpty()) continue; - } - NodeVector::ConstIterator m = s->members().constBegin(); - while (m != s->members().constEnd()) { - if ((*m)->access() == Node::Private) { // ### check necessary? - ++m; + + const QList &members = section.members(); + for (const auto &member : members) { + if (member->access() == Access::Private) // ### check necessary? continue; - } if (!headerGenerated) { - if (!s->divClass().isEmpty()) - out() << "
      divClass() << "\">\n"; // QTBUG-9504 - out() << "

      " << protectEnc(s->title()) << "

      \n"; + if (!section.divClass().isEmpty()) + out() << "
      \n"; // QTBUG-9504 + out() << "

      " << protectEnc(section.title()) << "

      \n"; headerGenerated = true; } - if (!(*m)->isClassNode()) - generateDetailedMember(*m, aggregate, marker); + if (!member->isClassNode()) + generateDetailedMember(member, aggregate, marker); else { out() << "

      class "; - generateFullName(*m, aggregate); + generateFullName(member, aggregate); out() << "

      "; - generateBrief(*m, marker, aggregate); + generateBrief(member, marker, aggregate); } QStringList names; - names << (*m)->name(); - if ((*m)->isFunction()) { - const FunctionNode *func = reinterpret_cast(*m); + names << member->name(); + if (member->isFunction()) { + const auto *func = reinterpret_cast(member); if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0) names.clear(); - } else if ((*m)->isProperty()) { - const PropertyNode *prop = reinterpret_cast(*m); - if (!prop->getters().isEmpty() && - !names.contains(prop->getters().first()->name())) + } else if (member->isProperty()) { + const auto *prop = reinterpret_cast(member); + if (!prop->getters().isEmpty() && !names.contains(prop->getters().first()->name())) names << prop->getters().first()->name(); if (!prop->setters().isEmpty()) names << prop->setters().first()->name(); @@ -1565,24 +1175,21 @@ void HtmlGenerator::generateCppReferencePage(Aggregate *aggregate, CodeMarker *m names << prop->resetters().first()->name(); if (!prop->notifiers().isEmpty()) names << prop->notifiers().first()->name(); - } else if ((*m)->isEnumType()) { - const EnumNode *enume = reinterpret_cast(*m); + } else if (member->isEnumType()) { + const auto *enume = reinterpret_cast(member); if (enume->flagsType()) names << enume->flagsType()->name(); const auto &enumItemNameList = enume->doc().enumItemNames(); const auto &omitEnumItemNameList = enume->doc().omitEnumItemNames(); const auto items = QSet(enumItemNameList.cbegin(), enumItemNameList.cend()) - - QSet(omitEnumItemNameList.cbegin(), omitEnumItemNameList.cend()); + - QSet(omitEnumItemNameList.cbegin(), omitEnumItemNameList.cend()); for (const QString &enumName : items) { - names << plainCode(marker->markedUpEnumValue(enumName, - enume)); + names << plainCode(marker->markedUpEnumValue(enumName, enume)); } } - ++m; } - if (headerGenerated && !s->divClass().isEmpty()) + if (headerGenerated && !section.divClass().isEmpty()) out() << "
      \n"; // QTBUG-9504 - ++s; } generateFooter(aggregate); } @@ -1607,16 +1214,13 @@ void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker) generateHeader(title, aggregate, marker); generateTitle(title, subtitleText, SmallSubTitle, aggregate, marker); generateBrief(aggregate, marker); - SectionVector::ConstIterator s = summarySections->constBegin(); - while (s != summarySections->constEnd()) { - if (!s->members().isEmpty()) { - // out() << "
      \n"; - QString ref = registerRef(s->title().toLower()); + for (auto it = summarySections->constBegin(); it != summarySections->constEnd(); ++it) { + if (!it->members().isEmpty()) { + QString ref = registerRef(it->title().toLower()); out() << "" << divNavTop << "\n"; - out() << "

      " << protectEnc(s->title()) << "

      \n"; - generateSection(s->members(), aggregate, marker); + out() << "

      " << protectEnc(it->title()) << "

      \n"; + generateSection(it->members(), aggregate, marker); } - ++s; } QString detailsRef = registerRef("details"); @@ -1624,9 +1228,10 @@ void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker) if (!aggregate->doc().isEmpty()) { generateExtractionMark(aggregate, DetailedDescriptionMark); - //out() << "
      \n" out() << "
      \n" // QTBUG-9504 - << "

      " << "Detailed Description" << "

      \n"; + << "

      " + << "Detailed Description" + << "

      \n"; generateBody(aggregate, marker); out() << "
      \n"; // QTBUG-9504 generateAlsoList(aggregate, marker); @@ -1634,54 +1239,49 @@ void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker) generateExtractionMark(aggregate, EndMark); } - s = detailsSections->constBegin(); - while (s != detailsSections->constEnd()) { - if (s->isEmpty()) { - ++s; + for (const auto §ion : qAsConst(*detailsSections)) { + if (section.isEmpty()) continue; - } - //out() << "
      \n"; - if (!s->divClass().isEmpty()) - out() << "
      divClass() << "\">\n"; // QTBUG-9504 - out() << "

      " << protectEnc(s->title()) << "

      \n"; - - NodeVector::ConstIterator m = s->members().constBegin(); - while (m != s->members().constEnd()) { - if (!(*m)->isPrivate()) { // ### check necessary? - if (!(*m)->isClassNode()) - generateDetailedMember(*m, aggregate, marker); + + if (!section.divClass().isEmpty()) + out() << "
      \n"; // QTBUG-9504 + out() << "

      " << protectEnc(section.title()) << "

      \n"; + + const QList &members = section.members(); + for (const auto &member : members) { + if (!member->isPrivate()) { // ### check necessary? + if (!member->isClassNode()) + generateDetailedMember(member, aggregate, marker); else { out() << "

      class "; - generateFullName(*m, aggregate); + generateFullName(member, aggregate); out() << "

      "; - generateBrief(*m, marker, aggregate); + generateBrief(member, marker, aggregate); } QStringList names; - names << (*m)->name(); - if ((*m)->isFunction()) { - const FunctionNode *func = reinterpret_cast(*m); + names << member->name(); + if (member->isFunction()) { + const auto *func = reinterpret_cast(member); if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0) names.clear(); - } else if ((*m)->isEnumType()) { - const EnumNode *enume = reinterpret_cast(*m); + } else if (member->isEnumType()) { + const auto *enume = reinterpret_cast(member); if (enume->flagsType()) names << enume->flagsType()->name(); const auto &enumItemNameList = enume->doc().enumItemNames(); const auto &omitEnumItemNameList = enume->doc().omitEnumItemNames(); - const auto items = QSet(enumItemNameList.cbegin(), enumItemNameList.cend()) - - QSet(omitEnumItemNameList.cbegin(), omitEnumItemNameList.cend()); - for (const QString &enumName : items) { - names << plainCode(marker->markedUpEnumValue(enumName, - enume)); - } + const auto items = + QSet(enumItemNameList.cbegin(), enumItemNameList.cend()) + - QSet(omitEnumItemNameList.cbegin(), + omitEnumItemNameList.cend()); + for (const QString &enumName : items) + names << plainCode(marker->markedUpEnumValue(enumName, enume)); } } - ++m; } - if (!s->divClass().isEmpty()) + if (!section.divClass().isEmpty()) out() << "
      \n"; // QTBUG-9504 - ++s; } generateFooter(aggregate); } @@ -1690,7 +1290,7 @@ void HtmlGenerator::generateProxyPage(Aggregate *aggregate, CodeMarker *marker) Generate the HTML page for a QML type. \qcn is the QML type. \marker is the code markeup object. */ -void HtmlGenerator::generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker) +void HtmlGenerator::generateQmlTypePage(QmlTypeNode *qcn, CodeMarker *marker) { Generator::setQmlTypeContext(qcn); SubTitleSize subTitleSize = LargeSubTitle; @@ -1724,42 +1324,39 @@ void HtmlGenerator::generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker) out() << "
    \n"; } - SectionVector::ConstIterator s = sections.stdQmlTypeSummarySections().constBegin(); - while (s != sections.stdQmlTypeSummarySections().constEnd()) { - if (!s->isEmpty()) { - QString ref = registerRef(s->title().toLower()); - out() << "" << divNavTop << '\n'; - out() << "

    " << protectEnc(s->title()) << "

    \n"; - generateQmlSummary(*s, qcn, marker); + const QList
    &stdQmlTypeSummarySections = sections.stdQmlTypeSummarySections(); + for (const auto §ion : stdQmlTypeSummarySections) { + if (!section.isEmpty()) { + QString ref = registerRef(section.title().toLower()); + out() << "" << divNavTop << '\n'; + out() << "

    " << protectEnc(section.title()) << "

    \n"; + generateQmlSummary(section.members(), qcn, marker); } - ++s; } generateExtractionMark(qcn, DetailedDescriptionMark); QString detailsRef = registerRef("details"); out() << "" << divNavTop << '\n'; - out() << "

    " << "Detailed Description" << "

    \n"; + out() << "

    " + << "Detailed Description" + << "

    \n"; generateBody(qcn, marker); - ClassNode* cn = qcn->classNode(); + ClassNode *cn = qcn->classNode(); if (cn) generateQmlText(cn->doc().body(), cn, marker, qcn->name()); generateAlsoList(qcn, marker); generateExtractionMark(qcn, EndMark); - //out() << "
    \n"; - - s = sections.stdQmlTypeDetailsSections().constBegin(); - while (s != sections.stdQmlTypeDetailsSections().constEnd()) { - if (!s->isEmpty()) { - out() << "

    " << protectEnc(s->title()) << "

    \n"; - NodeVector::ConstIterator m = s->members().constBegin(); - while (m != s->members().constEnd()) { - generateDetailedQmlMember(*m, qcn, marker); + + const QList
    &stdQmlTypeDetailsSections = sections.stdQmlTypeDetailsSections(); + for (const auto §ion : stdQmlTypeDetailsSections) { + if (!section.isEmpty()) { + out() << "

    " << protectEnc(section.title()) << "

    \n"; + const QList &members = section.members(); + for (const auto member : members) { + generateDetailedQmlMember(member, qcn, marker); out() << "
    \n"; - ++m; } } - ++s; } generateFooter(qcn); Generator::setQmlTypeContext(nullptr); @@ -1769,7 +1366,7 @@ void HtmlGenerator::generateQmlTypePage(QmlTypeNode* qcn, CodeMarker* marker) Generate the HTML page for the QML basic type represented by the QML basic type node \a qbtn. */ -void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* marker) +void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode *qbtn, CodeMarker *marker) { SubTitleSize subTitleSize = LargeSubTitle; QString htmlTitle = qbtn->fullTitle(); @@ -1782,46 +1379,39 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* generateHeader(htmlTitle, qbtn, marker); Sections sections(qbtn); - generateTableOfContents(qbtn,marker,§ions.stdQmlTypeSummarySections()); + generateTableOfContents(qbtn, marker, §ions.stdQmlTypeSummarySections()); generateKeywordAnchors(qbtn); - generateTitle(htmlTitle, - Text() << qbtn->subtitle(), - subTitleSize, - qbtn, - marker); - - SectionVector::const_iterator s = sections.stdQmlTypeSummarySections().constBegin(); - while (s != sections.stdQmlTypeSummarySections().constEnd()) { - if (!s->isEmpty()) { - QString ref = registerRef(s->title().toLower()); - out() << "" << divNavTop << '\n'; - out() << "

    " << protectEnc(s->title()) << "

    \n"; - generateQmlSummary(*s, qbtn, marker); + generateTitle(htmlTitle, Text() << qbtn->subtitle(), subTitleSize, qbtn, marker); + + const QList
    &stdQmlTypeSummarySections = sections.stdQmlTypeSummarySections(); + for (const auto §ion : stdQmlTypeSummarySections) { + if (!section.isEmpty()) { + QString ref = registerRef(section.title().toLower()); + out() << "" << divNavTop << '\n'; + out() << "

    " << protectEnc(section.title()) << "

    \n"; + generateQmlSummary(section.members(), qbtn, marker); } - ++s; } generateExtractionMark(qbtn, DetailedDescriptionMark); - out() << "
    \n"; // QTBUG-9504 + out() << R"(
    \n"; // QTBUG-9504 generateBody(qbtn, marker); out() << "
    \n"; // QTBUG-9504 generateAlsoList(qbtn, marker); generateExtractionMark(qbtn, EndMark); - s = sections.stdQmlTypeDetailsSections().constBegin(); - while (s != sections.stdQmlTypeDetailsSections().constEnd()) { - if (!s->isEmpty()) { - out() << "

    " << protectEnc(s->title()) << "

    \n"; - NodeVector::ConstIterator m = s->members().constBegin(); - while (m != s->members().constEnd()) { - generateDetailedQmlMember(*m, qbtn, marker); + const QList
    &stdQmlTypeDetailsSections = sections.stdQmlTypeDetailsSections(); + for (const auto §ion : stdQmlTypeDetailsSections) { + if (!section.isEmpty()) { + out() << "

    " << protectEnc(section.title()) << "

    \n"; + const QList &members = section.members(); + for (const auto member : members) { + generateDetailedQmlMember(member, qbtn, marker); out() << "
    \n"; - ++m; } } - ++s; } generateFooter(qbtn); } @@ -1830,7 +1420,7 @@ void HtmlGenerator::generateQmlBasicTypePage(QmlBasicTypeNode* qbtn, CodeMarker* Generate the HTML page for an entity that doesn't map to any underlying parsable C++, QML, or Javascript element. */ -void HtmlGenerator::generatePageNode(PageNode* pn, CodeMarker* marker) +void HtmlGenerator::generatePageNode(PageNode *pn, CodeMarker *marker) { SubTitleSize subTitleSize = LargeSubTitle; QString fullTitle = pn->fullTitle(); @@ -1841,20 +1431,17 @@ void HtmlGenerator::generatePageNode(PageNode* pn, CodeMarker* marker) Don't generate a TOC for the home page. */ if ((pn->name() != QLatin1String("index.html"))) - generateTableOfContents(pn,marker,nullptr); + generateTableOfContents(pn, marker, nullptr); generateKeywordAnchors(pn); - generateTitle(fullTitle, - Text() << pn->subtitle(), - subTitleSize, - pn, - marker); + generateTitle(fullTitle, Text() << pn->subtitle(), subTitleSize, pn, marker); if (pn->isExample()) { generateBrief(pn, marker, nullptr, false); } generateExtractionMark(pn, DetailedDescriptionMark); - out() << "
    \n"; // QTBUG-9504 + out() << R"(
    \n"; // QTBUG-9504 generateBody(pn, marker); out() << "
    \n"; // QTBUG-9504 @@ -1867,53 +1454,58 @@ void HtmlGenerator::generatePageNode(PageNode* pn, CodeMarker* marker) /*! Generate the HTML page for a group, module, or QML module. */ -void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marker) +void HtmlGenerator::generateCollectionNode(CollectionNode *cn, CodeMarker *marker) { SubTitleSize subTitleSize = LargeSubTitle; QString fullTitle = cn->fullTitle(); QString ref; generateHeader(fullTitle, cn, marker); - generateTableOfContents(cn,marker, nullptr); + generateTableOfContents(cn, marker, nullptr); generateKeywordAnchors(cn); generateTitle(fullTitle, Text() << cn->subtitle(), subTitleSize, cn, marker); - if (cn->isModule()) { - // Generate brief text and status for modules. - generateBrief(cn, marker); + // Generate brief for C++ modules, status for all modules. + if (cn->genus() != Node::DOC && cn->genus() != Node::DontCare) { + if (cn->isModule()) + generateBrief(cn, marker); generateStatus(cn, marker); generateSince(cn, marker); + } - NodeMultiMap nmm; - cn->getMemberNamespaces(nmm); - if (!nmm.isEmpty()) { - ref = registerRef("namespaces"); - out() << "" << divNavTop << '\n'; - out() << "

    Namespaces

    \n"; - generateAnnotatedList(cn, marker, nmm); - } - nmm.clear(); - cn->getMemberClasses(nmm); - if (!nmm.isEmpty()) { - ref = registerRef("classes"); - out() << "" << divNavTop << '\n'; - out() << "

    Classes

    \n"; - generateAnnotatedList(cn, marker, nmm); + if (cn->isModule()) { + if (!cn->noAutoList()) { + NodeMap nmm; + cn->getMemberNamespaces(nmm); + if (!nmm.isEmpty()) { + ref = registerRef("namespaces"); + out() << "" << divNavTop << '\n'; + out() << "

    Namespaces

    \n"; + generateAnnotatedList(cn, marker, nmm.values()); + } + nmm.clear(); + cn->getMemberClasses(nmm); + if (!nmm.isEmpty()) { + ref = registerRef("classes"); + out() << "" << divNavTop << '\n'; + out() << "

    Classes

    \n"; + generateAnnotatedList(cn, marker, nmm.values()); + } } - nmm.clear(); } - Text brief = cn->doc().briefText(); - if (cn->isModule() && !brief.isEmpty()) { + if (cn->isModule() && !cn->doc().briefText().isEmpty()) { generateExtractionMark(cn, DetailedDescriptionMark); ref = registerRef("details"); out() << "" << divNavTop << '\n'; out() << "
    \n"; // QTBUG-9504 - out() << "

    " << "Detailed Description" << "

    \n"; - } - else { + out() << "

    " + << "Detailed Description" + << "

    \n"; + } else { generateExtractionMark(cn, DetailedDescriptionMark); - out() << "
    \n"; // QTBUG-9504 + out() << R"(
    \n"; // QTBUG-9504 } generateBody(cn, marker); @@ -1922,9 +1514,7 @@ void HtmlGenerator::generateCollectionNode(CollectionNode* cn, CodeMarker* marke generateExtractionMark(cn, EndMark); if (!cn->noAutoList()) { - if (cn->isGroup()) - generateAnnotatedList(cn, marker, cn->members()); - else if (cn->isQmlModule() || cn->isJsModule()) + if (cn->isGroup() || cn->isQmlModule() || cn->isJsModule()) generateAnnotatedList(cn, marker, cn->members()); } generateFooter(cn); @@ -1950,23 +1540,14 @@ void HtmlGenerator::generateGenericCollectionPage(CollectionNode *cn, CodeMarker << "namespace that is documented in a different module. The reference " << "page for that class or namespace will link to the function or type " << "on this page."; -#if 0 - << Atom(Atom::LinkNode, CodeMarker::stringForNode(NS)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, " here.") - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); -#endif out() << "

    "; generateText(brief, cn, marker); out() << "

    \n"; - NodeList::ConstIterator m = cn->members().constBegin(); - while (m != cn->members().constEnd()) { - generateDetailedMember(*m, cn, marker); - ++m; - } + const QList members = cn->members(); + for (const auto &member : members) + generateDetailedMember(member, cn, marker); - // generateAnnotatedList(cn, marker, cn->members()); generateFooter(cn); } @@ -1981,75 +1562,57 @@ QString HtmlGenerator::fileExtension() const /*! Output navigation list in the html file. */ -void HtmlGenerator::generateNavigationBar(const QString &title, - const Node *node, - CodeMarker *marker, - const QString &buildversion, +void HtmlGenerator::generateNavigationBar(const QString &title, const Node *node, + CodeMarker *marker, const QString &buildversion, bool tableItems) { - if (noNavigationBar) + if (m_noNavigationBar || node == nullptr) return; Text navigationbar; // Set list item types based on the navigation bar type - Atom::AtomType itemLeft = tableItems ? - Atom::TableItemLeft : Atom::ListItemLeft; - Atom::AtomType itemRight = tableItems ? - Atom::TableItemRight : Atom::ListItemRight; + Atom::AtomType itemLeft = tableItems ? Atom::TableItemLeft : Atom::ListItemLeft; + Atom::AtomType itemRight = tableItems ? Atom::TableItemRight : Atom::ListItemRight; - if (hometitle == title) + if (m_hometitle == title) return; - if (!homepage.isEmpty()) - navigationbar << Atom(itemLeft) - << Atom(Atom::NavLink, homepage) + if (!m_homepage.isEmpty()) + navigationbar << Atom(itemLeft) << Atom(Atom::NavLink, m_homepage) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, m_hometitle) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(itemRight); + if (!m_landingpage.isEmpty() && m_landingtitle != title) + navigationbar << Atom(itemLeft) << Atom(Atom::NavLink, m_landingpage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, hometitle) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(itemRight); - if (!landingpage.isEmpty() && landingtitle != title) - navigationbar << Atom(itemLeft) - << Atom(Atom::NavLink, landingpage) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, landingtitle) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(itemRight); + << Atom(Atom::String, m_landingtitle) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(itemRight); if (node->isClassNode()) { - if (!cppclassespage.isEmpty() && !cppclassestitle.isEmpty()) - navigationbar << Atom(itemLeft) - << Atom(Atom::NavLink, cppclassespage) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, cppclassestitle) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(itemRight); + if (!m_cppclassespage.isEmpty() && !m_cppclassestitle.isEmpty()) + navigationbar << Atom(itemLeft) << Atom(Atom::NavLink, m_cppclassespage) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, m_cppclassestitle) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(itemRight); if (!node->name().isEmpty()) - navigationbar << Atom(itemLeft) - << Atom(Atom::String, node->name()) - << Atom(itemRight); - } - else if (node->isQmlType() || node->isQmlBasicType() || - node->isJsType() || node->isJsBasicType()) { - if (!qmltypespage.isEmpty() && !qmltypestitle.isEmpty()) - navigationbar << Atom(itemLeft) - << Atom(Atom::NavLink, qmltypespage) + navigationbar << Atom(itemLeft) << Atom(Atom::String, node->name()) << Atom(itemRight); + } else if (node->isQmlType() || node->isQmlBasicType() || node->isJsType() + || node->isJsBasicType()) { + if (!m_qmltypespage.isEmpty() && !m_qmltypestitle.isEmpty()) + navigationbar << Atom(itemLeft) << Atom(Atom::NavLink, m_qmltypespage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, qmltypestitle) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom(itemRight) - << Atom(itemLeft) - << Atom(Atom::String, title) - << Atom(itemRight); - } - else { - if (node->isAggregate()) { - QStringList groups = static_cast(node)->groupNames(); + << Atom(Atom::String, m_qmltypestitle) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom(itemRight) + << Atom(itemLeft) << Atom(Atom::String, title) << Atom(itemRight); + } else { + if (node->isPageNode()) { + QStringList groups = static_cast(node)->groupNames(); if (groups.length() == 1) { - const Node *groupNode = qdb_->findNodeByNameAndType(QStringList(groups[0]), &Node::isGroup); + const Node *groupNode = + m_qdb->findNodeByNameAndType(QStringList(groups[0]), &Node::isGroup); if (groupNode && !groupNode->title().isEmpty()) { - navigationbar << Atom(itemLeft) - << Atom(Atom::NavLink, groupNode->name()) + navigationbar << Atom(itemLeft) << Atom(Atom::NavLink, groupNode->name()) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, groupNode->title()) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) @@ -2058,9 +1621,7 @@ void HtmlGenerator::generateNavigationBar(const QString &title, } } if (!navigationbar.isEmpty()) { - navigationbar << Atom(itemLeft) - << Atom(Atom::String, title) - << Atom(itemRight); + navigationbar << Atom(itemLeft) << Atom(Atom::String, title) << Atom(itemRight); } } @@ -2071,16 +1632,16 @@ void HtmlGenerator::generateNavigationBar(const QString &title, navigationbar.clear(); - if (tableItems) { + if (tableItems) { out() << "\n" - << "")); - generateNavigationBar(title, node, marker, buildversion, usingTable); - out() << QString(postPostHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); + out() << QString(m_postHeader).replace("\\" + COMMAND_VERSION, m_qdb->version()); + bool usingTable = m_postHeader.trimmed().endsWith(QLatin1String("")); + generateNavigationBar(title, node, marker, m_buildversion, usingTable); + out() << QString(m_postPostHeader).replace("\\" + COMMAND_VERSION, m_qdb->version()); - navigationLinks.clear(); + m_navigationLinks.clear(); refMap.clear(); if (node && !node->links().empty()) { - QPair linkPair; - QPair anchorPair; + QPair linkPair; + QPair anchorPair; const Node *linkNode; bool useSeparator = false; if (node->links().contains(Node::PreviousLink)) { linkPair = node->links()[Node::PreviousLink]; - linkNode = qdb_->findNodeForTarget(linkPair.first, node); - if (linkNode == nullptr) - node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first)); + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (linkNode == nullptr && !noLinkErrors()) + node->doc().location().warning( + QStringLiteral("Cannot link to '%1'").arg(linkPair.first)); if (linkNode == nullptr || linkNode == node) anchorPair = linkPair; else anchorPair = anchorForNode(linkNode); - out() << " \n"; + out() << R"( \n"; - navigationLinks += ""; + m_navigationLinks += R"("; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + m_navigationLinks += protect(anchorPair.second); else - navigationLinks += protect(linkPair.second); - navigationLinks += "\n"; - useSeparator = !navigationSeparator.isEmpty(); + m_navigationLinks += protect(linkPair.second); + m_navigationLinks += "\n"; + useSeparator = !m_navigationSeparator.isEmpty(); } if (node->links().contains(Node::NextLink)) { linkPair = node->links()[Node::NextLink]; - linkNode = qdb_->findNodeForTarget(linkPair.first, node); - if (linkNode == nullptr) - node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first)); + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (linkNode == nullptr && !noLinkErrors()) + node->doc().location().warning( + QStringLiteral("Cannot link to '%1'").arg(linkPair.first)); if (linkNode == nullptr || linkNode == node) anchorPair = linkPair; else anchorPair = anchorForNode(linkNode); - out() << " \n"; + out() << R"( \n"; if (useSeparator) - navigationLinks += navigationSeparator; + m_navigationLinks += m_navigationSeparator; - navigationLinks += ""; + m_navigationLinks += R"("; if (linkPair.first == linkPair.second && !anchorPair.second.isEmpty()) - navigationLinks += protect(anchorPair.second); + m_navigationLinks += protect(anchorPair.second); else - navigationLinks += protect(linkPair.second); - navigationLinks += "\n"; + m_navigationLinks += protect(linkPair.second); + m_navigationLinks += "\n"; } if (node->links().contains(Node::StartLink)) { linkPair = node->links()[Node::StartLink]; - linkNode = qdb_->findNodeForTarget(linkPair.first, node); - if (linkNode == nullptr) - node->doc().location().warning(tr("Cannot link to '%1'").arg(linkPair.first)); + linkNode = m_qdb->findNodeForTarget(linkPair.first, node); + if (linkNode == nullptr && !noLinkErrors()) + node->doc().location().warning( + QStringLiteral("Cannot link to '%1'").arg(linkPair.first)); if (linkNode == nullptr || linkNode == node) anchorPair = linkPair; else anchorPair = anchorForNode(linkNode); - out() << " \n"; + out() << R"( \n"; } } if (node && !node->links().empty()) - out() << "

    \n" << navigationLinks << "

    \n"; + out() << "

    \n" << m_navigationLinks << "

    \n"; } -void HtmlGenerator::generateTitle(const QString& title, - const Text &subtitle, - SubTitleSize subTitleSize, - const Node *relative, +void HtmlGenerator::generateTitle(const QString &title, const Text &subtitle, + SubTitleSize subTitleSize, const Node *relative, CodeMarker *marker) { - out() << QString(prologue).replace("\\" + COMMAND_VERSION, qdb_->version()); + out() << QString(m_prologue).replace("\\" + COMMAND_VERSION, m_qdb->version()); if (!title.isEmpty()) out() << "

    " << protectEnc(title) << "

    \n"; if (!subtitle.isEmpty()) { @@ -2269,10 +1812,10 @@ void HtmlGenerator::generateTitle(const QString& title, void HtmlGenerator::generateFooter(const Node *node) { if (node && !node->links().empty()) - out() << "

    \n" << navigationLinks << "

    \n"; + out() << "

    \n" << m_navigationLinks << "

    \n"; - out() << QString(footer).replace("\\" + COMMAND_VERSION, qdb_->version()) - << QString(address).replace("\\" + COMMAND_VERSION, qdb_->version()); + out() << QString(m_footer).replace("\\" + COMMAND_VERSION, m_qdb->version()) + << QString(m_address).replace("\\" + COMMAND_VERSION, m_qdb->version()); out() << "\n"; out() << "\n"; @@ -2293,122 +1836,203 @@ void HtmlGenerator::generateRequisites(Aggregate *aggregate, CodeMarker *marker) const QString inheritsText = "Inherits"; const QString instantiatedByText = "Instantiated By"; const QString qtVariableText = "qmake"; + const QString cmakeText = "CMake"; - //add the include files to the map - if (!aggregate->includeFiles().isEmpty()) { - text.clear(); - text << highlightedCode(indent(codeIndent, marker->markedUpIncludes(aggregate->includeFiles())), - aggregate); - requisites.insert(headerText, text); - } + // The order of the requisites matter + const QStringList requisiteorder { headerText, cmakeText, qtVariableText, sinceText, + instantiatedByText, inheritsText, inheritedBytext }; - //The order of the requisites matter - QStringList requisiteorder; - requisiteorder << headerText - << qtVariableText - << sinceText - << instantiatedByText - << inheritsText - << inheritedBytext; - - //add the since and project into the map - if (!aggregate->since().isEmpty()) { - text.clear(); - QStringList since = aggregate->since().split(QLatin1Char(' ')); - if (since.count() == 1) { - // If there is only one argument, assume it is the Qt version number. - text << " Qt " << since[0]; - } - else { - //Otherwise, reconstruct the string. - text << " " << since.join(' '); - } - text << Atom::ParaRight; - requisites.insert(sinceText, text); - } + addIncludeFilesToMap(aggregate, marker, requisites, &text, headerText); + addSinceToMap(aggregate, requisites, &text, sinceText); if (aggregate->isClassNode() || aggregate->isNamespace()) { - //add the QT variable to the map - if (!aggregate->physicalModuleName().isEmpty()) { - const CollectionNode* cn = qdb_->getCollectionNode(aggregate->physicalModuleName(), Node::Module); - if (cn && !cn->qtVariable().isEmpty()) { - text.clear(); - text << "QT += " + cn->qtVariable(); - requisites.insert(qtVariableText, text); - } - } + addCMakeInfoToMap(aggregate, requisites, &text, cmakeText); + addQtVariableToMap(aggregate, requisites, &text, qtVariableText); } if (aggregate->isClassNode()) { - ClassNode* classe = static_cast(aggregate); - if (classe->qmlElement() != nullptr && !classe->isInternal()) { - text.clear(); - text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement())) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, classe->qmlElement()->name()) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - requisites.insert(instantiatedByText, text); + auto *classe = dynamic_cast(aggregate); + if (classe->qmlElement() != nullptr && !classe->isInternal()) + addInstantiatedByToMap(requisites, &text, instantiatedByText, classe); + + addInheritsToMap(requisites, &text, inheritsText, classe); + addInheritedByToMap(requisites, &text, inheritedBytext, classe); + } + if (!requisites.isEmpty()) { + // generate the table + generateTheTable(requisiteorder, requisites, headerText, aggregate, marker); + } +} + +/*! + * \internal + */ +void HtmlGenerator::generateTheTable(const QStringList &requisiteOrder, + const QMap &requisites, + const QString &headerText, const Aggregate *aggregate, + CodeMarker *marker) +{ + out() << "
    "; + << R"()"; } else { out() << "
  • "; } // Link buildversion string to navigation.landingpage - if (!landingpage.isEmpty() && landingtitle != title) { - navigationbar << Atom(Atom::NavLink, landingpage) + if (!m_landingpage.isEmpty() && m_landingtitle != title) { + navigationbar << Atom(Atom::NavLink, m_landingpage) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, buildversion) << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); @@ -2094,165 +1655,147 @@ void HtmlGenerator::generateNavigationBar(const QString &title, out() << "
  • \n"; } -void HtmlGenerator::generateHeader(const QString& title, - const Node *node, - CodeMarker *marker) +void HtmlGenerator::generateHeader(const QString &title, const Node *node, CodeMarker *marker) { -#ifndef QT_NO_TEXTCODEC - out() << QString("\n").arg(outputEncoding); -#else - out() << QString("\n"); -#endif out() << "\n"; out() << QString("\n").arg(naturalLanguage); out() << "\n"; - out() << " \n"; + out() << " \n"; if (node && !node->doc().location().isEmpty()) out() << "\n"; - QString projectVersion = qdb_->version(); - - //determine the rest of the element content: "title | titleSuffix version" + // determine the rest of the <title> element content: "title | titleSuffix version" QString titleSuffix; - if (!landingtitle.isEmpty()) { - //for normal pages: "title | landingtitle version" - titleSuffix = landingtitle; - } - else if (!hometitle.isEmpty()) { + if (!m_landingtitle.isEmpty()) { + // for normal pages: "title | landingtitle version" + titleSuffix = m_landingtitle; + } else if (!m_hometitle.isEmpty()) { // for pages that set the homepage title but not landing page title: // "title | hometitle version" - if (title != hometitle) - titleSuffix = hometitle; - } - else if (!project.isEmpty()) { - //for projects outside of Qt or Qt 5: "title | project version" - if (title != project) - titleSuffix = project; - } - else - //default: "title | Qt version" + if (title != m_hometitle) + titleSuffix = m_hometitle; + } else if (!m_project.isEmpty()) { + // for projects outside of Qt or Qt 5: "title | project version" + if (title != m_project) + titleSuffix = m_project; + } else + // default: "title | Qt version" titleSuffix = QLatin1String("Qt "); - //for pages that duplicate the title and suffix (landing pages, home pages, - // and module landing pages, clear the duplicate if (title == titleSuffix) titleSuffix.clear(); - //for pages that duplicate the version, clear the duplicate - if (title.contains(projectVersion) || titleSuffix.contains(projectVersion)) - projectVersion.clear(); - QString divider; if (!titleSuffix.isEmpty() && !title.isEmpty()) divider = QLatin1String(" | "); // Generating page title - out() << " <title>" - << protectEnc(title) - << divider - << titleSuffix; - - if (!projectVersion.isEmpty()) - out() << QLatin1Char(' ') << projectVersion; - + out() << " <title>" << protectEnc(title) << divider << titleSuffix; + + // append a full version to the suffix if neither suffix nor title + // include (a prefix of) version information + QVersionNumber projectVersion = QVersionNumber::fromString(m_qdb->version()); + if (!projectVersion.isNull()) { + QVersionNumber titleVersion; + QRegularExpression re(QLatin1String(R"(\d+\.\d+)")); + const QString &versionedTitle = titleSuffix.isEmpty() ? title : titleSuffix; + auto match = re.match(versionedTitle); + if (match.hasMatch()) + titleVersion = QVersionNumber::fromString(match.captured()); + if (titleVersion.isNull() || !titleVersion.isPrefixOf(projectVersion)) + out() << QLatin1Char(' ') << projectVersion.toString(); + } out() << "\n"; // Include style sheet and script links. - out() << headerStyles; - out() << headerScripts; - if (endHeader.isEmpty()) + out() << m_headerStyles; + out() << m_headerScripts; + if (m_endHeader.isEmpty()) out() << "\n\n"; else - out() << endHeader; - -#ifdef GENERATE_MAC_REFS - if (mainPage) - generateMacRef(node, marker); -#endif + out() << m_endHeader; - out() << QString(postHeader).replace("\\" + COMMAND_VERSION, qdb_->version()); - bool usingTable = postHeader.trimmed().endsWith(QLatin1String("
    \n"; + + for (auto it = requisiteOrder.constBegin(); it != requisiteOrder.constEnd(); ++it) { + + if (requisites.contains(*it)) { + out() << "" + << ""; } + } + out() << "
    " << *it + << ":" + " "; + + if (*it == headerText) + out() << requisites.value(*it).toString(); + else + generateText(requisites.value(*it), aggregate, marker); + out() << "
    "; +} - //add the inherits to the map - QList::ConstIterator r; - int index; - if (!classe->baseClasses().isEmpty()) { - text.clear(); - r = classe->baseClasses().constBegin(); - index = 0; - while (r != classe->baseClasses().constEnd()) { - if ((*r).node_) { - appendFullName(text, (*r).node_, classe); - - if ((*r).access_ == Node::Protected) { - text << " (protected)"; - } - else if ((*r).access_ == Node::Private) { - text << " (private)"; - } - text << comma(index++, classe->baseClasses().count()); +/*! + * \internal + * Adds inherited by information to the map. + */ +void HtmlGenerator::addInheritedByToMap(QMap &requisites, Text *text, + const QString &inheritedBytext, ClassNode *classe) +{ + if (!classe->derivedClasses().isEmpty()) { + text->clear(); + *text << Atom::ParaLeft; + int count = appendSortedNames(*text, classe, classe->derivedClasses()); + *text << Atom::ParaRight; + if (count > 0) + requisites.insert(inheritedBytext, *text); + } +} + +/*! + * \internal + * Adds base classes to the map. + */ +void HtmlGenerator::addInheritsToMap(QMap &requisites, Text *text, + const QString &inheritsText, ClassNode *classe) +{ + if (!classe->baseClasses().isEmpty()) { + int index = 0; + text->clear(); + const auto baseClasses = classe->baseClasses(); + for (const auto &cls : baseClasses) { + if (cls.m_node) { + appendFullName(*text, cls.m_node, classe); + + if (cls.m_access == Access::Protected) { + *text << " (protected)"; + } else if (cls.m_access == Access::Private) { + *text << " (private)"; } - ++r; + *text << Utilities::comma(index++, classe->baseClasses().count()); } - text << Atom::ParaRight; - if (index > 0) - requisites.insert(inheritsText, text); } + *text << Atom::ParaRight; + if (index > 0) + requisites.insert(inheritsText, *text); + } +} + +/*! + * \internal + * Add the instantiated by information to the map. + */ +void HtmlGenerator::addInstantiatedByToMap(QMap &requisites, Text *text, + const QString &instantiatedByText, + ClassNode *classe) const +{ + if (text != nullptr) { + text->clear(); + *text << Atom(Atom::LinkNode, CodeMarker::stringForNode(classe->qmlElement())) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) + << Atom(Atom::String, classe->qmlElement()->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); + requisites.insert(instantiatedByText, *text); + } +} - //add the inherited-by to the map - if (!classe->derivedClasses().isEmpty()) { - text.clear(); - text << Atom::ParaLeft; - int count = appendSortedNames(text, classe, classe->derivedClasses()); - text << Atom::ParaRight; - if (count > 0) - requisites.insert(inheritedBytext, text); +/*! + * \internal + * Adds the CMake package and link library information to the map. + */ +void HtmlGenerator::addCMakeInfoToMap(const Aggregate *aggregate, QMap &requisites, + Text *text, const QString &CMakeInfo) const +{ + if (!aggregate->physicalModuleName().isEmpty() && text != nullptr) { + const CollectionNode *cn = + m_qdb->getCollectionNode(aggregate->physicalModuleName(), Node::Module); + if (cn && !cn->qtCMakeComponent().isEmpty()) { + text->clear(); + const QString qtComponent = "Qt" + QString::number(QT_VERSION_MAJOR); + const QString findPackageText = "find_package(" + qtComponent + " COMPONENTS " + + cn->qtCMakeComponent() + " REQUIRED)"; + const QString targetLinkLibrariesText = "target_link_libraries(mytarget PRIVATE " + + qtComponent + "::" + cn->qtCMakeComponent() + ")"; + const Atom lineBreak = Atom(Atom::RawString, "
    \n"); + *text << findPackageText << lineBreak << targetLinkLibrariesText; + requisites.insert(CMakeInfo, *text); } } +} - if (!requisites.isEmpty()) { - //generate the table - out() << "
    \n"; +/*! + * \internal + * Adds the Qt variable (from the \\qtvariable command) to the map. + */ +void HtmlGenerator::addQtVariableToMap(const Aggregate *aggregate, QMap &requisites, + Text *text, const QString &qtVariableText) const +{ + if (!aggregate->physicalModuleName().isEmpty()) { + const CollectionNode *cn = + m_qdb->getCollectionNode(aggregate->physicalModuleName(), Node::Module); - QStringList::ConstIterator i; - for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) { + if (cn && !cn->qtVariable().isEmpty()) { + text->clear(); + *text << "QT += " + cn->qtVariable(); + requisites.insert(qtVariableText, *text); + } + } +} - if (requisites.contains(*i)) { - out() << "" - << ""; - } - } - out() << "
    " - << *i << ":" - " "; +/*! + * \internal + * Adds the since information (from the \\since command) to the map. + * + */ +void HtmlGenerator::addSinceToMap(const Aggregate *aggregate, QMap &requisites, + Text *text, const QString &sinceText) const +{ + if (!aggregate->since().isEmpty() && text != nullptr) { + text->clear(); + *text << formatSince(aggregate) << Atom::ParaRight; + requisites.insert(sinceText, *text); + } +} - if (*i == headerText) - out() << requisites.value(*i).toString(); - else - generateText(requisites.value(*i), aggregate, marker); - out() << "
    "; +/*! + * \internal + * Adds the includes (from the \\includefile command) to the map. + */ +void HtmlGenerator::addIncludeFilesToMap(const Aggregate *aggregate, CodeMarker *marker, + QMap &requisites, Text *text, + const QString &headerText) +{ + QStringList includeFiles = aggregate->includeFiles(); + includeFiles.erase(std::remove_if(includeFiles.begin(), includeFiles.end(), + [](auto includeFile) { return includeFile.isEmpty(); }), includeFiles.end()); + + if (!includeFiles.isEmpty() && text != nullptr) { + text->clear(); + *text << highlightedCode( + indent(m_codeIndent, marker->markedUpIncludes(includeFiles)), + aggregate); + requisites.insert(headerText, *text); } } @@ -2429,71 +2053,62 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) const QString inheritsText = "Inherits:"; const QString instantiatesText = "Instantiates:"; - //The order of the requisites matter - QStringList requisiteorder; - requisiteorder << importText - << sinceText - << instantiatesText - << inheritsText - << inheritedBytext; - - //add the module name and version to the map + // add the module name and version to the map QString logicalModuleVersion; - const CollectionNode* collection = qdb_->getCollectionNode(qcn->logicalModuleName(), qcn->nodeType()); - if (collection != nullptr) - logicalModuleVersion = collection->logicalModuleVersion(); - else - logicalModuleVersion = qcn->logicalModuleVersion(); - text.clear(); - text << "import " + qcn->logicalModuleName() + QLatin1Char(' ') + logicalModuleVersion; - requisites.insert(importText, text); + const CollectionNode *collection = qcn->logicalModule(); - //add the since and project into the map + // skip import statement of \internal collections + if (!collection || !collection->isInternal() || m_showInternal) { + logicalModuleVersion = + collection ? collection->logicalModuleVersion() : qcn->logicalModuleVersion(); + + if (logicalModuleVersion.isEmpty() || qcn->logicalModuleName().isEmpty()) + qcn->doc().location().warning(QStringLiteral("Could not resolve QML import " + "statement for type '%1'") + .arg(qcn->name()), + QStringLiteral("Maybe you forgot to use the " + "'\\%1' command?") + .arg(COMMAND_INQMLMODULE)); + + text.clear(); + text << "import " + qcn->logicalModuleName() + QLatin1Char(' ') + logicalModuleVersion; + requisites.insert(importText, text); + } + + // add the since and project into the map if (!qcn->since().isEmpty()) { text.clear(); - QStringList since = qcn->since().split(QLatin1Char(' ')); - if (since.count() == 1) { - // If there is only one argument, assume it is the Qt version number. - text << " Qt " << since[0]; - } - else { - //Otherwise, reconstruct the string. - text << " " << since.join(' '); - } - text << Atom::ParaRight; + text << formatSince(qcn) << Atom::ParaRight; requisites.insert(sinceText, text); } - //add the instantiates to the map - ClassNode* cn = qcn->classNode(); + // add the instantiates to the map + ClassNode *cn = qcn->classNode(); if (cn && !cn->isInternal()) { text.clear(); - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(qcn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(cn)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, cn->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); requisites.insert(instantiatesText, text); } - //add the inherits to the map - QmlTypeNode* base = qcn->qmlBaseNode(); + // add the inherits to the map + QmlTypeNode *base = qcn->qmlBaseNode(); while (base && base->isInternal()) { base = base->qmlBaseNode(); } if (base) { text.clear(); - text << Atom::ParaLeft - << Atom(Atom::LinkNode,CodeMarker::stringForNode(base)) - << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) - << Atom(Atom::String, base->name()) - << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) - << Atom::ParaRight; + text << Atom::ParaLeft << Atom(Atom::LinkNode, CodeMarker::stringForNode(base)) + << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK) << Atom(Atom::String, base->name()) + << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK) << Atom::ParaRight; requisites.insert(inheritsText, text); } - //add the inherited-by to the map + // add the inherited-by to the map NodeList subs; QmlTypeNode::subclasses(qcn, subs); if (!subs.isEmpty()) { @@ -2505,23 +2120,24 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) requisites.insert(inheritedBytext, text); } + // The order of the requisites matter + const QStringList requisiteorder { importText, sinceText, instantiatesText, inheritsText, + inheritedBytext }; + if (!requisites.isEmpty()) { - //generate the table + // generate the table out() << "
    \n"; + for (const auto &requisite : requisiteorder) { - QStringList::ConstIterator i; - for (i = requisiteorder.constBegin(); i != requisiteorder.constEnd(); ++i) { - - if (requisites.contains(*i)) { + if (requisites.contains(requisite)) { out() << "" - << ""; } } @@ -2529,15 +2145,16 @@ void HtmlGenerator::generateQmlRequisites(QmlTypeNode *qcn, CodeMarker *marker) } } -void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, - const Node *relative, bool addLink) +void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, const Node *relative, + bool addLink) { Text brief = node->doc().briefText(); if (!brief.isEmpty()) { if (!brief.lastAtom()->string().endsWith('.')) { brief << Atom(Atom::String, "."); - node->doc().location().warning(tr("'\\brief' statement does not end with a full stop.")); + node->doc().location().warning( + QStringLiteral("'\\brief' statement does not end with a full stop.")); } generateExtractionMark(node, BriefMark); out() << "

    "; @@ -2560,11 +2177,10 @@ void HtmlGenerator::generateBrief(const Node *node, CodeMarker *marker, Revised for the new doc format. Generates a table of contents beginning at \a node. */ -void HtmlGenerator::generateTableOfContents(const Node *node, - CodeMarker *marker, - QVector

    * sections) +void HtmlGenerator::generateTableOfContents(const Node *node, CodeMarker *marker, + QList
    *sections) { - QList toc; + QList toc; if (node->doc().hasTableOfContents()) toc = node->doc().tableOfContents(); if (tocDepth == 0 || (toc.isEmpty() && !sections && !node->isModule())) { @@ -2576,8 +2192,8 @@ void HtmlGenerator::generateTableOfContents(const Node *node, int detailsBase = 0; // disable nested links in table of contents - inContents_ = true; - inLink_ = true; + m_inContents = true; + m_inLink = true; out() << "
    \n"; out() << "
    \n"; @@ -2585,106 +2201,80 @@ void HtmlGenerator::generateTableOfContents(const Node *node, out() << "
      \n"; if (node->isModule()) { - if (node->hasNamespaces()) { - out() << "
    • Namespaces
    • \n"; - } - if (node->hasClasses()) { - out() << "
    • Classes
    • \n"; + if (!static_cast(node)->noAutoList()) { + if (node->hasNamespaces()) { + out() << "
    • Namespaces
    • \n"; + } + if (node->hasClasses()) { + out() << "
    • Classes
    • \n"; + } } - out() << "
    • Detailed Description
    • \n"; - for (int i = 0; i < toc.size(); ++i) { - if (toc.at(i)->string().toInt() == 1) { + for (const auto &entry : qAsConst(toc)) { + if (entry->string().toInt() == 1) { detailsBase = 1; break; } } - } - else if (sections && (node->isClassNode() || - node->isNamespace() || - node->isQmlType() || - node->isJsType())) { - SectionVector::ConstIterator s = sections->constBegin(); - while (s != sections->constEnd()) { - if (!s->members().isEmpty()) { - out() << "
    • plural()) - << "\">" << s->title() - << "
    • \n"; + } else if (sections + && (node->isClassNode() || node->isNamespace() || node->isQmlType() || + node->isJsType() || node->isQmlBasicType() || node->isJsBasicType())) { + for (const auto §ion : qAsConst(*sections)) { + if (!section.members().isEmpty()) { + out() << "
    • " << section.title() << "
    • \n"; } - if (!s->reimplementedMembers().isEmpty()) { - QString ref = QString("Reimplemented ") + s->plural(); - out() << "
    • " << QString("Reimplemented ") + s->title() - << "
    • \n"; + if (!section.reimplementedMembers().isEmpty()) { + QString ref = QString("Reimplemented ") + section.plural(); + out() << "
    • " + << QString("Reimplemented ") + section.title() << "
    • \n"; } - ++s; } if (!node->isNamespace() || node->hasDoc()) { - out() << "
    • Detailed Description
    • \n"; + out() << "
    • Detailed Description
    • \n"; } - for (int i = 0; i < toc.size(); ++i) { - if (toc.at(i)->string().toInt() == 1) { + for (const auto &entry : toc) { + if (entry->string().toInt() == 1) { detailsBase = 1; break; } } } - for (int i = 0; i < toc.size(); ++i) { - const Atom *atom = toc.at(i); + for (const auto &atom : toc) { sectionNumber = atom->string().toInt() + detailsBase; - //restrict the ToC depth to the one set by the HTML.tocdepth variable or - //print all levels if tocDepth is not set. + // restrict the ToC depth to the one set by the HTML.tocdepth variable or + // print all levels if tocDepth is not set. if (sectionNumber <= tocDepth || tocDepth < 0) { int numAtoms; Text headingText = Text::sectionHeading(atom); QString s = headingText.toString(); - out() << "
    • "; - out() << ""; + out() << "
    • "; + out() << ""; generateAtomList(headingText.firstAtom(), node, marker, true, numAtoms); out() << "
    • \n"; } } out() << "
    \n"; out() << "
    \n"; - out() << "
    "; + out() << R"()"; out() << "
    \n"; - inContents_ = false; - inLink_ = false; + m_inContents = false; + m_inLink = false; } /*! Outputs a placeholder div where the style can add customized sidebar content. */ -void HtmlGenerator::generateSidebar() { +void HtmlGenerator::generateSidebar() +{ out() << "
    "; - out() << "
    "; + out() << R"()"; out() << "
    \n"; } @@ -2717,7 +2307,7 @@ QString HtmlGenerator::generateAllMembersFile(const Section §ion, CodeMarker including the inherited members. The \a marker is used for formatting stuff. */ -QString HtmlGenerator::generateAllQmlMembersFile(const Sections §ions, CodeMarker* marker) +QString HtmlGenerator::generateAllQmlMembersFile(const Sections §ions, CodeMarker *marker) { if (sections.allMembersSection().isEmpty()) @@ -2734,14 +2324,14 @@ QString HtmlGenerator::generateAllQmlMembersFile(const Sections §ions, CodeM generateFullName(aggregate, nullptr); out() << ", including inherited members.

    \n"; - ClassKeysNodesList& cknl = sections.allMembersSection().classKeysNodesList(); + ClassKeysNodesList &cknl = sections.allMembersSection().classKeysNodesList(); if (!cknl.isEmpty()) { - for (int i=0; ifirst; - KeysAndNodes& kn = ckn->second; - QStringList& keys = kn.first; - NodeVector& nodes = kn.second; + for (int i = 0; i < cknl.size(); i++) { + ClassKeysNodes *ckn = cknl[i]; + const QmlTypeNode *qcn = ckn->first; + KeysAndNodes &kn = ckn->second; + QStringList &keys = kn.first; + NodeVector &nodes = kn.second; if (nodes.isEmpty()) continue; if (i != 0) { @@ -2750,21 +2340,31 @@ QString HtmlGenerator::generateAllQmlMembersFile(const Sections §ions, CodeM out() << ".

    \n"; } out() << "
      \n"; - for (int j=0; jaccess() == Node::Private || nodes[j]->isInternal()) { + for (int j = 0; j < keys.size(); j++) { + Node *node = nodes[j]; + if (node->access() == Access::Private || node->isInternal()) continue; - } - out() << "
    • "; - QString prefix; - if (!keys.isEmpty()) { - prefix = keys.at(j).mid(1); - prefix = prefix.left(keys.at(j).indexOf("::")+1); - } - generateQmlItem(nodes[j], aggregate, marker, true); - if (nodes[j]->isAttached()) - out() << " [attached]"; - //generateSynopsis(nodes[j], qcn, marker, Section::AllMembers, false, &prefix); - out() << "
    • \n"; + if (node->isSharingComment() && node->sharedCommentNode()->isPropertyGroup()) + continue; + + std::function generate = [&](Node *n) { + out() << "
    • "; + generateQmlItem(n, aggregate, marker, true); + if (n->isDefault()) + out() << " [default]"; + else if (n->isAttached()) + out() << " [attached]"; + // Indent property group members + if (n->isPropertyGroup()) { + out() << "
        \n"; + const QList &collective = + static_cast(n)->collective(); + std::for_each(collective.begin(), collective.end(), generate); + out() << "
      \n"; + } + out() << "
    • \n"; + }; + generate(node); } out() << "
    \n"; } @@ -2803,22 +2403,18 @@ QString HtmlGenerator::generateObsoleteMembersFile(const Sections §ions, Cod << "They are provided to keep old source code working. " << "We strongly advise against using them in new code.

    \n"; - for (int i = 0; i < summary_spv.size(); ++i) { - out() << "

    " << protectEnc(summary_spv.at(i)->title()) << "

    \n"; - const Section §ion = *summary_spv.at(i); - generateSectionList(section, aggregate, marker, Section::Obsolete); + for (const auto §ion : summary_spv) { + out() << "

    " << protectEnc(section->title()) << "

    \n"; + generateSectionList(*section, aggregate, marker, Section::Obsolete); } - for (int i = 0; i < details_spv.size(); ++i) { - //out() << "
    \n"; - out() << "

    " << protectEnc(details_spv.at(i)->title()) << "

    \n"; + for (const auto §ion : details_spv) { + out() << "

    " << protectEnc(section->title()) << "

    \n"; - const NodeVector &members = details_spv.at(i)->obsoleteMembers(); - NodeVector::ConstIterator m = members.constBegin(); - while (m != members.constEnd()) { - if ((*m)->access() != Node::Private) - generateDetailedMember(*m, aggregate, marker); - ++m; + const NodeVector &members = section->obsoleteMembers(); + for (const auto &member : members) { + if (member->access() != Access::Private) + generateDetailedMember(member, aggregate, marker); } } @@ -2863,22 +2459,19 @@ QString HtmlGenerator::generateObsoleteQmlMembersFile(const Sections §ions, << "They are provided to keep old source code working. " << "We strongly advise against using them in new code.

    \n"; - for (int i = 0; i < summary_spv.size(); ++i) { - QString ref = registerRef(summary_spv.at(i)->title().toLower()); - out() << "" << divNavTop << '\n'; - out() << "

    " << protectEnc(summary_spv.at(i)->title()) << "

    \n"; - generateQmlSummary(*(summary_spv.at(i)), aggregate, marker); + for (const auto §ion : summary_spv) { + QString ref = registerRef(section->title().toLower()); + out() << "" << divNavTop << '\n'; + out() << "

    " << protectEnc(section->title()) << "

    \n"; + generateQmlSummary(section->obsoleteMembers(), aggregate, marker); } - for (int i = 0; i < details_spv.size(); ++i) { - out() << "

    " << protectEnc(details_spv.at(i)->title()) << "

    \n"; - const NodeVector &members = details_spv.at(i)->obsoleteMembers(); - NodeVector::ConstIterator m = members.constBegin(); - while (m != members.constEnd()) { - generateDetailedQmlMember(*m, aggregate, marker); + for (const auto §ion : details_spv) { + out() << "

    " << protectEnc(section->title()) << "

    \n"; + const NodeVector &members = section->obsoleteMembers(); + for (const auto &member : members) { + generateDetailedQmlMember(member, aggregate, marker); out() << "
    \n"; - ++m; } } @@ -2887,21 +2480,19 @@ QString HtmlGenerator::generateObsoleteQmlMembersFile(const Sections §ions, return fileName; } -void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classMap) +void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMultiMap &classMap) { if (classMap.isEmpty()) return; NodeMap topLevel; - NodeMap::Iterator c = classMap.begin(); - while (c != classMap.end()) { - ClassNode *classe = static_cast(*c); + for (const auto &it : classMap) { + auto *classe = static_cast(it); if (classe->baseClasses().isEmpty()) topLevel.insert(classe->name(), classe); - ++c; } - QStack stack; + QStack stack; stack.push(topLevel); out() << "
      \n"; @@ -2909,18 +2500,18 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classM if (stack.top().isEmpty()) { stack.pop(); out() << "
    \n"; - } - else { - ClassNode* child = static_cast(*stack.top().begin()); + } else { + ClassNode *child = static_cast(*stack.top().begin()); out() << "
  • "; generateFullName(child, relative); out() << "
  • \n"; stack.top().erase(stack.top().begin()); NodeMap newTop; - foreach (const RelatedClass &d, child->derivedClasses()) { - if (d.node_ && !d.isPrivate() && !d.node_->isInternal() && d.node_->hasDoc()) - newTop.insert(d.node_->name(), d.node_); + const auto derivedClasses = child->derivedClasses(); + for (const RelatedClass &d : derivedClasses) { + if (d.m_node && d.m_node->isInAPI()) + newTop.insert(d.m_node->name(), d.m_node); } if (!newTop.isEmpty()) { stack.push(newTop); @@ -2931,27 +2522,18 @@ void HtmlGenerator::generateClassHierarchy(const Node *relative, NodeMap& classM } /*! - Output an annotated list of the nodes in \a nodeMap. + Outputs an annotated list of the nodes in \a unsortedNodes. A two-column table is output. */ -void HtmlGenerator::generateAnnotatedList(const Node* relative, - CodeMarker* marker, - const NodeMultiMap& nmm) +void HtmlGenerator::generateAnnotatedList(const Node *relative, CodeMarker *marker, + const NodeList &unsortedNodes) { - if (nmm.isEmpty()) + if (unsortedNodes.isEmpty() || relative == nullptr) return; - generateAnnotatedList(relative, marker, nmm.values()); -} -/*! - */ -void HtmlGenerator::generateAnnotatedList(const Node *relative, - CodeMarker *marker, - const NodeList& unsortedNodes) -{ NodeMultiMap nmm; bool allInternal = true; - foreach (Node* node, unsortedNodes) { + for (auto *node : unsortedNodes) { if (!node->isInternal() && !node->isObsolete()) { allInternal = false; nmm.insert(node->fullName(relative), node); @@ -2964,7 +2546,7 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, NodeList nodes = nmm.values(); std::sort(nodes.begin(), nodes.end(), Node::nodeNameLessThan); - foreach (const Node* node, nodes) { + for (const auto *node : qAsConst(nodes)) { if (++row % 2 == 1) out() << "
    "; else @@ -2979,19 +2561,16 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, out() << ""; - } - else if (!node->reconstitutedBrief().isEmpty()) { + } else if (!node->reconstitutedBrief().isEmpty()) { out() << ""; } - } - else { + } else { out() << ""; } @@ -3004,14 +2583,14 @@ void HtmlGenerator::generateAnnotatedList(const Node *relative, Outputs a series of annotated lists from the nodes in \a nmm, divided into sections based by the key names in the multimap. */ -void HtmlGenerator::generateAnnotatedLists(const Node* relative, - CodeMarker* marker, - const NodeMultiMap& nmm) +void HtmlGenerator::generateAnnotatedLists(const Node *relative, CodeMarker *marker, + const NodeMultiMap &nmm) { - foreach (const QString &name, nmm.uniqueKeys()) { + const auto &uniqueKeys = nmm.uniqueKeys(); + for (const QString &name : uniqueKeys) { if (!name.isEmpty()) { - out() << "

    " << protectEnc(name) << "

    \n"; + out() << "

    " << protectEnc(name) + << "

    \n"; } generateAnnotatedList(relative, marker, nmm.values(name)); } @@ -3022,16 +2601,14 @@ void HtmlGenerator::generateAnnotatedLists(const Node* relative, the classes in the class map \a nmm and then generates a compact list of the class names alphabetized on the part of the name not including the common prefix. You can tell - the function to use \a comonPrefix as the common prefix, + the function to use \a commonPrefix as the common prefix, but normally you let it figure it out itself by looking at the name of the first and last classes in the class map \a nmm. */ -void HtmlGenerator::generateCompactList(ListType listType, - const Node *relative, - const NodeMultiMap &nmm, - bool includeAlphabet, - QString commonPrefix) +void HtmlGenerator::generateCompactList(ListType listType, const Node *relative, + const NodeMultiMap &nmm, bool includeAlphabet, + const QString &commonPrefix) { if (nmm.isEmpty()) return; @@ -3045,32 +2622,29 @@ void HtmlGenerator::generateCompactList(ListType listType, QXtWidget in paragraph 33 (X). This is the only place where we assume that NumParagraphs is 37. Each paragraph is a NodeMultiMap. */ - NodeMultiMap paragraph[NumParagraphs+1]; - QString paragraphName[NumParagraphs+1]; + NodeMultiMap paragraph[NumParagraphs + 1]; + QString paragraphName[NumParagraphs + 1]; QSet usedParagraphNames; - NodeMultiMap::ConstIterator c = nmm.constBegin(); - while (c != nmm.constEnd()) { + for (auto c = nmm.constBegin(); c != nmm.constEnd(); ++c) { QStringList pieces = c.key().split("::"); - QString key; int idx = commonPrefixLen; if (idx > 0 && !pieces.last().startsWith(commonPrefix, Qt::CaseInsensitive)) idx = 0; - key = pieces.last().mid(idx).toLower(); + QString last = pieces.last().toLower(); + QString key = last.mid(idx); int paragraphNr = NumParagraphs - 1; if (key[0].digitValue() != -1) { paragraphNr = key[0].digitValue(); - } - else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { + } else if (key[0] >= QLatin1Char('a') && key[0] <= QLatin1Char('z')) { paragraphNr = 10 + key[0].unicode() - 'a'; } paragraphName[paragraphNr] = key[0].toUpper(); usedParagraphNames.insert(key[0].toLower().cell()); - paragraph[paragraphNr].insert(c.key(), c.value()); - ++c; + paragraph[paragraphNr].insert(last, c.value()); } /* @@ -3081,10 +2655,10 @@ void HtmlGenerator::generateCompactList(ListType listType, We now want to compute the paragraph offset. Paragraphs 0 to 6 start at offsets 0, 3, 4, 8, 9, 14, 23. */ - int paragraphOffset[NumParagraphs + 1]; // 37 + 1 + int paragraphOffset[NumParagraphs + 1]; // 37 + 1 paragraphOffset[0] = 0; - for (int i=0; i element to contain all the
    elements. */ out() << "
    \n"; - numTableRows_ = 0; + m_numTableRows = 0; int curParNr = 0; int curParOffset = 0; QString previousName; bool multipleOccurrences = false; - for (int i=0; i 0) out() << "
    \n"; - if (++numTableRows_ % 2 == 1) + if (++m_numTableRows % 2 == 1) out() << "
    "; else out() << "
    "; @@ -3132,9 +2705,7 @@ void HtmlGenerator::generateCompactList(ListType listType, QChar c = paragraphName[curParNr][0].toLower(); out() << QString("").arg(c); } - out() << "" - << paragraphName[curParNr] - << ""; + out() << "" << paragraphName[curParNr] << ""; out() << "\n"; } @@ -3142,12 +2713,11 @@ void HtmlGenerator::generateCompactList(ListType listType, Output a
    for the current offset in the current paragraph. */ out() << "
    "; - if ((curParNr < NumParagraphs) && - !paragraphName[curParNr].isEmpty()) { + if ((curParNr < NumParagraphs) && !paragraphName[curParNr].isEmpty()) { NodeMultiMap::Iterator it; NodeMultiMap::Iterator next; it = paragraph[curParNr].begin(); - for (int i=0; i"; - } - else if (listType == Obsolete) { + } else if (listType == Obsolete) { QString fileName = fileBase(it.value()) + "-obsolete." + fileExtension(); QString link; if (useOutputSubdirs()) { @@ -3181,8 +2750,7 @@ void HtmlGenerator::generateCompactList(ListType listType, if (multipleOccurrences) name += ": " + it.value()->tree()->camelCaseModuleName(); pieces << name; - } - else + } else pieces = it.value()->fullName(relative).split("::"); out() << protectEnc(pieces.last()); out() << ""; @@ -3214,38 +2782,32 @@ void HtmlGenerator::generateFunctionIndex(const Node *relative) char currentLetter; out() << "
      \n"; - NodeMapMap& funcIndex = qdb_->getFunctionIndex(); - QMap::ConstIterator f = funcIndex.constBegin(); - while (f != funcIndex.constEnd()) { + NodeMapMap &funcIndex = m_qdb->getFunctionIndex(); + for (auto fnMap = funcIndex.constBegin(); fnMap != funcIndex.constEnd(); ++fnMap) { out() << "
    • "; - out() << protectEnc(f.key()) << ':'; + out() << protectEnc(fnMap.key()) << ':'; - currentLetter = f.key()[0].unicode(); + currentLetter = fnMap.key()[0].unicode(); while (islower(currentLetter) && currentLetter >= nextLetter) { out() << QString("").arg(nextLetter); nextLetter++; } - NodeMap::ConstIterator s = (*f).constBegin(); - while (s != (*f).constEnd()) { + for (auto it = (*fnMap).constBegin(); it != (*fnMap).constEnd(); ++it) { out() << ' '; - generateFullName((*s)->parent(), relative, *s); - ++s; + generateFullName((*it)->parent(), relative, *it); } out() << "
    • "; out() << '\n'; - ++f; } out() << "
    \n"; } void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marker) { - TextToNodeMap& legaleseTexts = qdb_->getLegaleseTexts(); - QMap::ConstIterator it = legaleseTexts.constBegin(); - while (it != legaleseTexts.constEnd()) { + TextToNodeMap &legaleseTexts = m_qdb->getLegaleseTexts(); + for (auto it = legaleseTexts.cbegin(), end = legaleseTexts.cend(); it != end; ++it) { Text text = it.key(); - //out() << "
    \n"; generateText(text, relative, marker); out() << "
      \n"; do { @@ -3258,29 +2820,27 @@ void HtmlGenerator::generateLegaleseList(const Node *relative, CodeMarker *marke } } -void HtmlGenerator::generateQmlItem(const Node *node, - const Node *relative, - CodeMarker *marker, +void HtmlGenerator::generateQmlItem(const Node *node, const Node *relative, CodeMarker *marker, bool summary) { - QString marked = marker->markedUpQmlItem(node,summary); - QRegExp templateTag("(<[^@>]*>)"); - if (marked.indexOf(templateTag) != -1) { - QString contents = protectEnc(marked.mid(templateTag.pos(1), - templateTag.cap(1).length())); - marked.replace(templateTag.pos(1), templateTag.cap(1).length(), - contents); + QString marked = marker->markedUpQmlItem(node, summary); + QRegularExpression templateTag("(<[^@>]*>)"); + auto match = templateTag.match(marked); + if (match.hasMatch()) { + QString contents = protectEnc(match.captured(1)); + marked.replace(match.capturedStart(1), match.capturedLength(1), contents); } - marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])"), - "\\1\\2"); - marked.replace("<@param>", ""); - marked.replace("", ""); + // Look for the _ character in the member name followed by a number (or n): + // this is intended to be rendered as a subscript. + marked.replace(QRegularExpression("<@param>([a-z]+)_([0-9]+|n)"), "\\1\\2"); + + // Replace some markup by HTML tags. Do both the opening and the closing tag + // in one go (instead of <@param> and separately, for instance). + marked.replace("@param>", "i>"); if (summary) marked.replace("@name>", "b>"); - - marked.replace("<@extra>", ""); - marked.replace("", ""); + marked.replace("@extra>", "code>"); if (summary) { marked.remove("<@type>"); @@ -3295,25 +2855,23 @@ void HtmlGenerator::generateQmlItem(const Node *node, and must not be empty. If it is empty, nothing is output, and false is returned. Otherewise, the list is generated and true is returned. */ -bool HtmlGenerator::generateGroupList(CollectionNode* cn) +bool HtmlGenerator::generateGroupList(CollectionNode *cn) { - qdb_->mergeCollections(cn); + m_qdb->mergeCollections(cn); if (cn->members().isEmpty()) return false; out() << "\n"; return true; } -void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const QString& selector) +void HtmlGenerator::generateList(const Node *relative, CodeMarker *marker, const QString &selector) { CNMap cnm; Node::NodeType type = Node::NoType; @@ -3326,32 +2884,34 @@ void HtmlGenerator::generateList(const Node* relative, CodeMarker* marker, const else if (selector == QLatin1String("js-modules")) type = Node::JsModule; if (type != Node::NoType) { - NodeList nl; - qdb_->mergeCollections(type, cnm, relative); - CollectionList cl = cnm.values(); - foreach (CollectionNode* cn, cl) - nl.append(cn); - generateAnnotatedList(relative, marker, nl); - } - else { + NodeList nodeList; + m_qdb->mergeCollections(type, cnm, relative); + const auto collectionList = cnm.values(); + nodeList.reserve(collectionList.size()); + for (auto *collectionNode : collectionList) + nodeList.append(collectionNode); + generateAnnotatedList(relative, marker, nodeList); + } else { /* \generatelist {selector} is only allowed in a comment where the topic is \group, \module, \qmlmodule, or \jsmodule */ if (relative && !relative->isCollectionNode()) { - relative->doc().location().warning(tr("\\generatelist {%1} is only allowed in \\group, " - "\\module, \\qmlmodule, and \\jsmodule comments.").arg(selector)); + relative->doc().location().warning( + QStringLiteral("\\generatelist {%1} is only allowed in \\group, " + "\\module, \\qmlmodule, and \\jsmodule comments.") + .arg(selector)); return; } - Node* n = const_cast(relative); - CollectionNode* cn = static_cast(n); - qdb_->mergeCollections(cn); - generateAnnotatedList(cn, marker, cn->members()); + auto *node = const_cast(relative); + auto *collectionNode = static_cast(node); + m_qdb->mergeCollections(collectionNode); + generateAnnotatedList(collectionNode, marker, collectionNode->members()); } } -void HtmlGenerator::generateSection(const NodeVector& nv, const Node *relative, CodeMarker *marker) +void HtmlGenerator::generateSection(const NodeVector &nv, const Node *relative, CodeMarker *marker) { bool alignNames = true; if (!nv.isEmpty()) { @@ -3362,8 +2922,7 @@ void HtmlGenerator::generateSection(const NodeVector& nv, const Node *relative, } if (alignNames) { out() << "
    " - << *i - << " "; + << " " << requisite + << " "; - if (*i == importText) - out()<

    "; generateText(brief, node, marker); out() << "

    "; out() << node->reconstitutedBrief(); out() << "

    "; if (!node->reconstitutedBrief().isEmpty()) { out() << node->reconstitutedBrief(); - } - else + } else out() << protectEnc(node->doc().briefText().toString()); out() << "

    \n"; - } - else { + } else { if (twoColumn) out() << "
    \n" << "\n"; else out() << "\n"; i++; - ++m; } if (alignNames) out() << "
    "; @@ -3371,29 +2930,24 @@ void HtmlGenerator::generateSection(const NodeVector& nv, const Node *relative, } int i = 0; - NodeVector::ConstIterator m = nv.constBegin(); - while (m != nv.constEnd()) { - if ((*m)->access() == Node::Private) { - ++m; + for (const auto &member : nv) { + if (member->access() == Access::Private) continue; - } if (alignNames) { out() << "
    "; - } - else { - if (twoColumn && i == (int) (nv.count() + 1) / 2) + } else { + if (twoColumn && i == (nv.count() + 1) / 2) out() << "
      \n"; out() << "
    • "; } - generateSynopsis(*m, relative, marker, Section::Summary, alignNames); + generateSynopsis(member, relative, marker, Section::Summary, alignNames); if (alignNames) out() << "
    \n"; @@ -3405,13 +2959,12 @@ void HtmlGenerator::generateSection(const NodeVector& nv, const Node *relative, } } -void HtmlGenerator::generateSectionList(const Section& section, - const Node *relative, - CodeMarker *marker, - Section::Status status) +void HtmlGenerator::generateSectionList(const Section §ion, const Node *relative, + CodeMarker *marker, Section::Status status) { bool alignNames = true; - const NodeVector &members = (status == Section::Obsolete ? section.obsoleteMembers() : section.members()); + const NodeVector &members = + (status == Section::Obsolete ? section.obsoleteMembers() : section.members()); if (!members.isEmpty()) { bool hasPrivateSignals = false; bool isInvokable = false; @@ -3425,8 +2978,7 @@ void HtmlGenerator::generateSectionList(const Section& section, } if (alignNames) { out() << "
    \n"; - } - else { + } else { if (twoColumn) out() << "
    \n" << "
    "; @@ -3434,37 +2986,32 @@ void HtmlGenerator::generateSectionList(const Section& section, } int i = 0; - NodeVector::ConstIterator m = members.constBegin(); - while (m != members.constEnd()) { - if ((*m)->access() == Node::Private) { - ++m; + for (const auto &member : members) { + if (member->access() == Access::Private) continue; - } if (alignNames) { out() << "
    "; - } - else { - if (twoColumn && i == (int) (members.count() + 1) / 2) + } else { + if (twoColumn && i == (members.count() + 1) / 2) out() << "
      \n"; out() << "
    • "; } QString prefix; - const QStringList& keys = section.keys(status); + const QStringList &keys = section.keys(status); if (!keys.isEmpty()) { prefix = keys.at(i).mid(1); prefix = prefix.left(keys.at(i).indexOf("::") + 1); } - generateSynopsis(*m, relative, marker, section.style(), alignNames, &prefix); - if ((*m)->isFunction()) { - const FunctionNode* fn = static_cast(*m); + generateSynopsis(member, relative, marker, section.style(), alignNames, &prefix); + if (member->isFunction()) { + const auto *fn = static_cast(member); if (fn->isPrivateSignal()) { hasPrivateSignals = true; if (alignNames) out() << "
    [see note below]"; - } - else if (fn->isInvokable()) { + } else if (fn->isInvokable()) { isInvokable = true; if (alignNames) out() << "[see note below]"; @@ -3475,7 +3022,6 @@ void HtmlGenerator::generateSectionList(const Section& section, else out() << "\n"; i++; - ++m; } if (alignNames) out() << "
    \n"; @@ -3484,71 +3030,64 @@ void HtmlGenerator::generateSectionList(const Section& section, if (twoColumn) out() << "\n
    \n"; } - if (hasPrivateSignals && alignNames) - generatePrivateSignalNote(relative, marker); - if (isInvokable && alignNames) - generateInvokableNote(relative, marker); + if (alignNames) { + if (hasPrivateSignals) + generateAddendum(relative, Generator::PrivateSignal, marker); + if (isInvokable) + generateAddendum(relative, Generator::Invokable, marker); + } } - if (status != Section::Obsolete && section.style() == Section::Summary && !section.inheritedMembers().isEmpty()) { + if (status != Section::Obsolete && section.style() == Section::Summary + && !section.inheritedMembers().isEmpty()) { out() << "
      \n"; generateSectionInheritedList(section, relative); out() << "
    \n"; } } -void HtmlGenerator::generateSectionInheritedList(const Section& section, const Node *relative) +void HtmlGenerator::generateSectionInheritedList(const Section §ion, const Node *relative) { - QList >::ConstIterator p = section.inheritedMembers().constBegin(); - while (p != section.inheritedMembers().constEnd()) { + const QList> &inheritedMembers = section.inheritedMembers(); + for (const auto &member : inheritedMembers) { out() << "
  • "; - out() << (*p).second << ' '; - if ((*p).second == 1) { + out() << member.second << ' '; + if (member.second == 1) { out() << section.singular(); - } - else { + } else { out() << section.plural(); } - out() << " inherited from " - << protectEnc((*p).first->plainFullName(relative)) - << "
  • \n"; - ++p; + out() << " inherited from " + << protectEnc(member.first->plainFullName(relative)) << "\n"; } } -// generateSynopsis(*m, relative, marker, Section::Summary, alignNames); -void HtmlGenerator::generateSynopsis(const Node *node, - const Node *relative, - CodeMarker *marker, - Section::Style style, - bool alignNames, - const QString* prefix) +void HtmlGenerator::generateSynopsis(const Node *node, const Node *relative, CodeMarker *marker, + Section::Style style, bool alignNames, const QString *prefix) { QString marked = marker->markedUpSynopsis(node, relative, style); if (prefix) marked.prepend(*prefix); - QRegExp templateTag("(<[^@>]*>)"); - if (marked.indexOf(templateTag) != -1) { - QString contents = protectEnc(marked.mid(templateTag.pos(1), - templateTag.cap(1).length())); - marked.replace(templateTag.pos(1), templateTag.cap(1).length(), - contents); + QRegularExpression templateTag("(<[^@>]*>)"); + auto match = templateTag.match(marked); + if (match.hasMatch()) { + QString contents = protectEnc(match.captured(1)); + marked.replace(match.capturedStart(1), match.capturedLength(1), contents); } - marked.replace(QRegExp("<@param>([a-z]+)_([1-9n])"), - "\\1\\2"); + + marked.replace(QRegularExpression("<@param>([a-z]+)_([1-9n])"), "\\1\\2"); marked.replace("<@param>", ""); marked.replace("", ""); if (style == Section::Summary) { - marked.remove("<@name>"); // was "" - marked.remove(""); // was "" + marked.remove("<@name>"); // was "" + marked.remove(""); // was "" } if (style == Section::AllMembers) { - QRegExp extraRegExp("<@extra>.*"); - extraRegExp.setMinimal(true); + QRegularExpression extraRegExp("<@extra>.*", QRegularExpression::InvertedGreedinessOption); marked.remove(extraRegExp); } else { marked.replace("<@extra>", ""); @@ -3563,15 +3102,14 @@ void HtmlGenerator::generateSynopsis(const Node *node, out() << highlightedCode(marked, relative, alignNames); } -QString HtmlGenerator::highlightedCode(const QString& markedCode, - const Node* relative, +QString HtmlGenerator::highlightedCode(const QString &markedCode, const Node *relative, bool alignNames, Node::Genus genus) { QString src = markedCode; QString html; html.reserve(src.size()); - QStringRef arg; - QStringRef par1; + QStringView arg; + QStringView par1; const QChar charLangle = '<'; const QChar charAt = '@'; @@ -3594,49 +3132,43 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, i += 2; if (parseArg(src, linkTag, &i, srcSize, &arg, &par1)) { html += QLatin1String(""); - const Node* n = CodeMarker::nodeForString(par1.toString()); + const Node *n = CodeMarker::nodeForString(par1.toString()); QString link = linkForNode(n, relative); addLink(link, arg, &html); html += QLatin1String(""); - } - else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) { - const FunctionNode *fn = qdb_->findFunctionNode(par1.toString(), relative, genus); + } else if (parseArg(src, funcTag, &i, srcSize, &arg, &par1)) { + const FunctionNode *fn = m_qdb->findFunctionNode(par1.toString(), relative, genus); QString link = linkForNode(fn, relative); addLink(link, arg, &html); - par1 = QStringRef(); - } - else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) { - par1 = QStringRef(); - const Node* n = qdb_->findTypeNode(arg.toString(), relative, genus); + par1 = QStringView(); + } else if (parseArg(src, typeTag, &i, srcSize, &arg, &par1)) { + par1 = QStringView(); + const Node *n = m_qdb->findTypeNode(arg.toString(), relative, genus); html += QLatin1String(""); if (n && (n->isQmlBasicType() || n->isJsBasicType())) { if (relative && (relative->genus() == n->genus() || genus == n->genus())) - addLink(linkForNode(n,relative), arg, &html); + addLink(linkForNode(n, relative), arg, &html); else html += arg; - } - else - addLink(linkForNode(n,relative), arg, &html); + } else + addLink(linkForNode(n, relative), arg, &html); html += QLatin1String(""); - } - else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) { - par1 = QStringRef(); + } else if (parseArg(src, headerTag, &i, srcSize, &arg, &par1)) { + par1 = QStringView(); if (arg.startsWith(QLatin1Char('&'))) html += arg; else { - const Node* n = qdb_->findNodeForInclude(QStringList(arg.toString())); + const Node *n = m_qdb->findNodeForInclude(QStringList(arg.toString())); if (n && n != relative) - addLink(linkForNode(n,relative), arg, &html); + addLink(linkForNode(n, relative), arg, &html); else html += arg; } - } - else { + } else { html += charLangle; html += charAt; } - } - else { + } else { html += src.at(i++); } } @@ -3656,15 +3188,15 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, html = QString(); html.reserve(src.size()); static const QLatin1String spanTags[] = { - QLatin1String("comment>"), QLatin1String(""), - QLatin1String("preprocessor>"), QLatin1String(""), - QLatin1String("string>"), QLatin1String(""), - QLatin1String("char>"), QLatin1String(""), - QLatin1String("number>"), QLatin1String(""), - QLatin1String("op>"), QLatin1String(""), - QLatin1String("type>"), QLatin1String(""), - QLatin1String("name>"), QLatin1String(""), - QLatin1String("keyword>"), QLatin1String("") + QLatin1String("comment>"), QLatin1String(""), + QLatin1String("preprocessor>"), QLatin1String(""), + QLatin1String("string>"), QLatin1String(""), + QLatin1String("char>"), QLatin1String(""), + QLatin1String("number>"), QLatin1String(""), + QLatin1String("op>"), QLatin1String(""), + QLatin1String("type>"), QLatin1String(""), + QLatin1String("name>"), QLatin1String(""), + QLatin1String("keyword>"), QLatin1String("") }; int nTags = 9; // Update the upper bound of k in the following code to match the length @@ -3675,9 +3207,8 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, i += 2; bool handled = false; for (int k = 0; k != nTags; ++k) { - const QLatin1String& tag = spanTags[2 * k]; - if (i + tag.size() <= src.length() && - tag == QStringRef(&src, i, tag.size())) { + const QLatin1String &tag = spanTags[2 * k]; + if (i + tag.size() <= src.length() && tag == QStringView(src).mid(i, tag.size())) { html += spanTags[2 * k + 1]; i += tag.size(); handled = true; @@ -3691,14 +3222,12 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, ++i; } continue; - } - else if (src.at(i + 1) == QLatin1Char('/') && src.at(i + 2) == QLatin1Char('@')) { + } else if (src.at(i + 1) == QLatin1Char('/') && src.at(i + 2) == QLatin1Char('@')) { i += 3; bool handled = false; for (int k = 0; k != nTags; ++k) { - const QLatin1String& tag = spanTags[2 * k]; - if (i + tag.size() <= src.length() && - tag == QStringRef(&src, i, tag.size())) { + const QLatin1String &tag = spanTags[2 * k]; + if (i + tag.size() <= src.length() && tag == QStringView(src).mid(i, tag.size())) { html += QLatin1String(""); i += tag.size(); handled = true; @@ -3720,60 +3249,38 @@ QString HtmlGenerator::highlightedCode(const QString& markedCode, return html; } -void HtmlGenerator::generateLink(const Atom* atom, CodeMarker* marker) +void HtmlGenerator::generateLink(const Atom *atom, CodeMarker *marker) { - static QRegExp camelCase("[A-Z][A-Z][a-z]|[a-z][A-Z0-9]|_"); - - if (funcLeftParen.indexIn(atom->string()) != -1 && marker->recognizeLanguage("Cpp")) { + auto match = m_funcLeftParen.match(atom->string()); + if (match.hasMatch() && marker->recognizeLanguage("Cpp")) { // hack for C++: move () outside of link - int k = funcLeftParen.pos(1); + int k = match.capturedStart(1); out() << protectEnc(atom->string().left(k)); - if (link_.isEmpty()) { + if (m_link.isEmpty()) { if (showBrokenLinks) out() << ""; } else { out() << ""; } - inLink_ = false; + m_inLink = false; out() << protectEnc(atom->string().mid(k)); } else { out() << protectEnc(atom->string()); } } -QString HtmlGenerator::registerRef(const QString& ref) -{ - QString clean = Generator::cleanRef(ref); - - for (;;) { - QString& prevRef = refMap[clean.toLower()]; - if (prevRef.isEmpty()) { - prevRef = ref; - break; - } else if (prevRef == ref) { - break; - } - clean += QLatin1Char('x'); - } - return clean; -} - QString HtmlGenerator::protectEnc(const QString &string) { -#ifndef QT_NO_TEXTCODEC - return protect(string, outputEncoding); -#else return protect(string); -#endif } -QString HtmlGenerator::protect(const QString &string, const QString &outputEncoding) +QString HtmlGenerator::protect(const QString &string) { -#define APPEND(x) \ - if (html.isEmpty()) { \ - html = string; \ - html.truncate(i); \ -} \ +#define APPEND(x) \ + if (html.isEmpty()) { \ + html = string; \ + html.truncate(i); \ + } \ html += (x); QString html; @@ -3790,8 +3297,7 @@ QString HtmlGenerator::protect(const QString &string, const QString &outputEncod APPEND(">"); } else if (ch == QLatin1Char('"')) { APPEND("""); - } else if ((outputEncoding == QLatin1String("ISO-8859-1") && ch.unicode() > 0x007F) - || (ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) + } else if ((ch == QLatin1Char('*') && i + 1 < n && string.at(i) == QLatin1Char('/')) || (ch == QLatin1Char('.') && i > 2 && string.at(i - 2) == QLatin1Char('.'))) { // we escape '*/' and the last dot in 'e.g.' and 'i.e.' for the Javadoc generator APPEND("&#x"); @@ -3825,200 +3331,8 @@ QString HtmlGenerator::fileName(const Node *node) return Generator::fileName(node); } -QString HtmlGenerator::refForNode(const Node *node) -{ - QString ref; - switch (node->nodeType()) { - case Node::Enum: - ref = node->name() + "-enum"; - break; - case Node::Typedef: - { - const TypedefNode* tdn = static_cast(node); - if (tdn->associatedEnum()) - return refForNode(tdn->associatedEnum()); - else - ref = node->name() + "-typedef"; - } - break; - case Node::Function: - { - const FunctionNode *fn = static_cast(node); - switch (fn->metaness()) { - case FunctionNode::JsSignal: - case FunctionNode::QmlSignal: - ref = fn->name() + "-signal"; - break; - case FunctionNode::JsSignalHandler: - case FunctionNode::QmlSignalHandler: - ref = fn->name() + "-signal-handler"; - break; - case FunctionNode::JsMethod: - case FunctionNode::QmlMethod: - ref = fn->name() + "-method"; - if (fn->overloadNumber() != 0) - ref += QLatin1Char('-') + QString::number(fn->overloadNumber()); - break; - default: - if (fn->hasOneAssociatedProperty() && fn->doc().isEmpty()) { - return refForNode(fn->firstAssociatedProperty()); - } else { - ref = fn->name(); - if (fn->overloadNumber() != 0) - ref += QLatin1Char('-') + QString::number(fn->overloadNumber()); - } - break; - } - } - break; - case Node::JsProperty: - case Node::QmlProperty: - if (node->isAttached()) - ref = node->name() + "-attached-prop"; - else - ref = node->name() + "-prop"; - break; - case Node::Property: - ref = node->name() + "-prop"; - break; - case Node::Variable: - ref = node->name() + "-var"; - break; - case Node::SharedComment: - if (node->isPropertyGroup()) - ref = node->name() + "-prop"; - break; - default: - break; - } - return registerRef(ref); -} - -/*! - This function is called for links, i.e. for words that - are marked with the qdoc link command. For autolinks - that are not marked with the qdoc link command, the - getAutoLink() function is called - - It returns the string for a link found by using the data - in the \a atom to search the database. It also sets \a node - to point to the target node for that link. \a relative points - to the node holding the qdoc comment where the link command - was found. - */ -QString HtmlGenerator::getLink(const Atom *atom, const Node *relative, const Node** node) -{ - const QString& t = atom->string(); - if (t.at(0) == QChar('h')) { - if (t.startsWith("http:") || t.startsWith("https:")) - return t; - } - else if (t.at(0) == QChar('f')) { - if (t.startsWith("file:") || t.startsWith("ftp:")) - return t; - } - else if (t.at(0) == QChar('m')) { - if (t.startsWith("mailto:")) - return t; - } - return getAutoLink(atom, relative, node); -} - -/*! - This function is called for autolinks, i.e. for words that - are not marked with the qdoc link command that qdoc has - reason to believe should be links. For links marked with - the qdoc link command, the getLink() function is called. - - It returns the string for a link found by using the data - in the \a atom to search the database. It also sets \a node - to point to the target node for that link. \a relative points - to the node holding the qdoc comment where the link command - was found. - */ -QString HtmlGenerator::getAutoLink(const Atom *atom, const Node *relative, const Node** node) -{ - QString ref; - - *node = qdb_->findNodeForAtom(atom, relative, ref); - if (!(*node)) { - return QString(); - } - - QString link = (*node)->url(); - if (link.isEmpty()) - link = linkForNode(*node, relative); - if (!ref.isEmpty()) { - int hashtag = link.lastIndexOf(QChar('#')); - if (hashtag != -1) - link.truncate(hashtag); - link += QLatin1Char('#') + ref; - } - return link; -} - -/*! - Construct the link string for the \a node and return it. - The \a relative node is use to decide the link we are - generating is in the same file as the target. Note the - relative node can be 0, which pretty much guarantees - that the link and the target aren't in the same file. - */ -QString HtmlGenerator::linkForNode(const Node *node, const Node *relative) -{ - if (node == nullptr) - return QString(); - if (!node->url().isEmpty()) - return node->url(); - if (fileBase(node).isEmpty()) - return QString(); - if (node->isPrivate()) - return QString(); - QString fn = fileName(node); - if (node && node->parent() && - (node->parent()->isQmlType() || node->parent()->isJsType()) - && node->parent()->isAbstract()) { - if (Generator::qmlTypeContext()) { - if (Generator::qmlTypeContext()->inherits(node->parent())) { - fn = fileName(Generator::qmlTypeContext()); - } - else if (node->parent()->isInternal()) { - node->doc().location().warning(tr("Cannot link to property in internal type '%1'").arg(node->parent()->name())); - return QString(); - } - } - } - QString link = fn; - - if ((!node->isAggregate() && !node->isCollectionNode()) || node->isPropertyGroup()) { - QString ref = refForNode(node); - if (relative && fn == fileName(relative) && ref == refForNode(relative)) - return QString(); - - link += QLatin1Char('#'); - link += ref; - } - /* - If the output is going to subdirectories, then if the - two nodes will be output to different directories, then - the link must go up to the parent directory and then - back down into the other subdirectory. - */ - if (node && relative && (node != relative)) { - if (useOutputSubdirs() && !node->isExternalPage() && - node->outputSubdirectory() != relative->outputSubdirectory()) { - if (link.startsWith(QString(node->outputSubdirectory() + QLatin1Char('/')))) { - link.prepend(QString("../")); - } - else { - link.prepend(QString("../" + node->outputSubdirectory() + QLatin1Char('/'))); - } - } - } - return link; -} - -void HtmlGenerator::generateFullName(const Node *apparentNode, const Node *relative, const Node *actualNode) +void HtmlGenerator::generateFullName(const Node *apparentNode, const Node *relative, + const Node *actualNode) { if (actualNode == nullptr) actualNode = apparentNode; @@ -4030,50 +3344,39 @@ void HtmlGenerator::generateFullName(const Node *apparentNode, const Node *relat out() << ""; } -void HtmlGenerator::generateDetailedMember(const Node *node, - const PageNode *relative, +void HtmlGenerator::generateDetailedMember(const Node *node, const PageNode *relative, CodeMarker *marker) { const EnumNode *etn; -#ifdef GENERATE_MAC_REFS - generateMacRef(node, marker); -#endif generateExtractionMark(node, MemberMark); generateKeywordAnchors(node); QString nodeRef = nullptr; if (node->isSharedCommentNode()) { - const SharedCommentNode *scn = reinterpret_cast(node); - const QVector& collective = scn->collective(); + const auto *scn = reinterpret_cast(node); + const QList &collective = scn->collective(); if (collective.size() > 1) out() << "
    \n"; - foreach (const Node* n, collective) { - if (n->isFunction()) { - nodeRef = refForNode(n); - out() << "

    "; - out() << ""; - generateSynopsis(n, relative, marker, Section::Details); - out() << "

    "; - } + for (const auto *sharedNode : collective) { + nodeRef = refForNode(sharedNode); + out() << R"(

    "; + out() << ""; + generateSynopsis(sharedNode, relative, marker, Section::Details); + out() << "

    "; } if (collective.size() > 1) out() << "
    "; out() << divNavTop << '\n'; - } - else { + } else { nodeRef = refForNode(node); if (node->isEnumType() && (etn = static_cast(node))->flagsType()) { -#ifdef GENERATE_MAC_REFS - generateMacRef(etn->flagsType(), marker); -#endif - out() << "

    "; + out() << R"(

    "; out() << ""; generateSynopsis(etn, relative, marker, Section::Details); out() << "
    "; generateSynopsis(etn->flagsType(), relative, marker, Section::Details); out() << "

    \n"; - } - else { - out() << "

    "; + } else { + out() << R"(

    "; out() << ""; generateSynopsis(node, relative, marker, Section::Details); out() << "

    " << divNavTop << '\n'; @@ -4087,113 +3390,41 @@ void HtmlGenerator::generateDetailedMember(const Node *node, generateSince(node, marker); if (node->isProperty()) { - const PropertyNode *property = static_cast(node); - Section section(Section::Accessors, Section::Active); + const auto property = static_cast(node); + if (property->propertyType() == PropertyNode::Standard) { + Section section(Section::Accessors, Section::Active); - section.appendMembers(property->getters().toVector()); - section.appendMembers(property->setters().toVector()); - section.appendMembers(property->resetters().toVector()); + section.appendMembers(property->getters().toVector()); + section.appendMembers(property->setters().toVector()); + section.appendMembers(property->resetters().toVector()); - if (!section.members().isEmpty()) { - out() << "

    Access functions:

    \n"; - generateSectionList(section, node, marker); - } + if (!section.members().isEmpty()) { + out() << "

    Access functions:

    \n"; + generateSectionList(section, node, marker); + } - Section notifiers(Section::Accessors, Section::Active); - notifiers.appendMembers(property->notifiers().toVector()); + Section notifiers(Section::Accessors, Section::Active); + notifiers.appendMembers(property->notifiers().toVector()); - if (!notifiers.members().isEmpty()) { - out() << "

    Notifier signal:

    \n"; - //out() << "

    This signal is emitted when the property value is changed.

    \n"; - generateSectionList(notifiers, node, marker); + if (!notifiers.members().isEmpty()) { + out() << "

    Notifier signal:

    \n"; + generateSectionList(notifiers, node, marker); + } } - } - else if (node->isFunction()) { - const FunctionNode* fn = static_cast(node); - if (fn->isPrivateSignal()) - generatePrivateSignalNote(node, marker); - if (fn->isInvokable()) - generateInvokableNote(node, marker); - generateAssociatedPropertyNotes(const_cast(fn)); - } - else if (node->isEnumType()) { - const EnumNode *etn = static_cast(node); - if (etn->flagsType()) { - out() << "

    The " << protectEnc(etn->flagsType()->name()) + } else if (node->isEnumType()) { + const auto *enumTypeNode = static_cast(node); + if (enumTypeNode->flagsType()) { + out() << "

    The " << protectEnc(enumTypeNode->flagsType()->name()) << " type is a typedef for " - << "QFlags<" - << protectEnc(etn->name()) - << ">. It stores an OR combination of " - << protectEnc(etn->name()) - << " values.

    \n"; + << "QFlags<" + << protectEnc(enumTypeNode->name()) << ">. It stores an OR combination of " + << protectEnc(enumTypeNode->name()) << " values.

    \n"; } } generateAlsoList(node, marker); generateExtractionMark(node, EndMark); } -int HtmlGenerator::hOffset(const Node *node) -{ - switch (node->nodeType()) { - case Node::Namespace: - case Node::Class: - case Node::Struct: - case Node::Union: - case Node::Module: - return 2; - case Node::QmlModule: - case Node::QmlBasicType: - case Node::QmlType: - case Node::Page: - return 1; - case Node::Enum: - case Node::Typedef: - case Node::Function: - case Node::Property: - default: - return 3; - } -} - -bool HtmlGenerator::isThreeColumnEnumValueTable(const Atom *atom) -{ - while (atom != nullptr && !(atom->type() == Atom::ListRight && atom->string() == ATOM_LIST_VALUE)) { - if (atom->type() == Atom::ListItemLeft && !matchAhead(atom, Atom::ListItemRight)) - return true; - atom = atom->next(); - } - return false; -} - - -const QPair HtmlGenerator::anchorForNode(const Node *node) -{ - QPair anchorPair; - - anchorPair.first = Generator::fileName(node); - if (node->isPageNode()) { - const PageNode *pn = static_cast(node); - anchorPair.second = pn->title(); - } - - return anchorPair; -} - -#ifdef GENERATE_MAC_REFS -/* - No longer valid. - */ -void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker) -{ - if (!pleaseGenerateMacRef || marker == 0) - return; - - QStringList macRefs = marker->macRefsForNode(node); - foreach (const QString &macRef, macRefs) - out() << "\n"; -} -#endif - /*! This version of the function is called when outputting the link to an example file or example image, where the \a link is known @@ -4201,81 +3432,70 @@ void HtmlGenerator::generateMacRef(const Node *node, CodeMarker *marker) */ void HtmlGenerator::beginLink(const QString &link) { - link_ = link; - if (link_.isEmpty()) { + m_link = link; + if (m_link.isEmpty()) { if (showBrokenLinks) out() << ""; } - out() << ""; - inLink_ = true; + out() << ""; + m_inLink = true; } void HtmlGenerator::beginLink(const QString &link, const Node *node, const Node *relative) { - link_ = link; - if (link_.isEmpty()) { + m_link = link; + if (m_link.isEmpty()) { if (showBrokenLinks) out() << ""; - } - else if (node == nullptr || (relative != nullptr && node->status() == relative->status())) - out() << ""; + } else if (node == nullptr || (relative != nullptr && node->status() == relative->status())) + out() << ""; else if (node->isObsolete()) - out() << ""; + out() << ""; else - out() << ""; - inLink_ = true; + out() << ""; + m_inLink = true; } void HtmlGenerator::endLink() { - if (inLink_) { - if (link_.isEmpty()) { - if (showBrokenLinks) - out() << ""; - } - else { - if (inObsoleteLink) { - out() << "(obsolete)"; - } + if (m_inLink) { + if (m_link.isEmpty() && showBrokenLinks) { + out() << ""; + } else { out() << ""; } } - inLink_ = false; - inObsoleteLink = false; + m_inLink = false; } /*! - Generates the summary for the \a section. Only used for + Generates the summary list for the \a members. Only used for sections of QML element documentation. */ -void HtmlGenerator::generateQmlSummary(const Section& section, - const Node *relative, +void HtmlGenerator::generateQmlSummary(const NodeVector &members, const Node *relative, CodeMarker *marker) { - if (!section.members().isEmpty()) { + if (!members.isEmpty()) { out() << "
      \n"; - NodeVector::const_iterator m = section.members().constBegin(); - while (m != section.members().constEnd()) { + for (const auto &member : members) { out() << "
    • "; - generateQmlItem(*m, relative, marker, true); - if ((*m)->isPropertyGroup()) { - const SharedCommentNode* scn = static_cast(*m); + generateQmlItem(member, relative, marker, true); + if (member->isPropertyGroup()) { + const auto *scn = static_cast(member); if (scn->count() > 0) { - QVector::ConstIterator p = scn->collective().constBegin(); out() << "
        \n"; - while (p != scn->collective().constEnd()) { - if ((*p)->isQmlProperty() || (*p)->isJsProperty()) { + const QList &sharedNodes = scn->collective(); + for (const auto &node : sharedNodes) { + if (node->isQmlProperty() || node->isJsProperty()) { out() << "
      • "; - generateQmlItem(*p, relative, marker, true); + generateQmlItem(node, relative, marker, true); out() << "
      • \n"; } - ++p; } out() << "
      \n"; } } out() << "
    • \n"; - ++m; } out() << "
    \n"; } @@ -4285,14 +3505,9 @@ void HtmlGenerator::generateQmlSummary(const Section& section, Outputs the html detailed documentation for a section on a QML element reference page. */ -void HtmlGenerator::generateDetailedQmlMember(Node *node, - const Aggregate *relative, +void HtmlGenerator::generateDetailedQmlMember(Node *node, const Aggregate *relative, CodeMarker *marker) { - QmlPropertyNode* qpn = nullptr; -#ifdef GENERATE_MAC_REFS - generateMacRef(node, marker); -#endif generateExtractionMark(node, MemberMark); generateKeywordAnchors(node); @@ -4300,82 +3515,85 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, "
    \n"); QString qmlItemStart("\n" - "\n"); - QString qmlItemFooter("

    \n"); + "

    \n"); QString qmlItemEnd("

    \n
    "); + QString qmlItemFooter("
    \n"); + + std::function generateQmlProperty = [&](QmlPropertyNode *n) { + out() << qmlItemStart.arg(refForNode(n), "tblQmlPropNode"); + + if (!n->isReadOnlySet() && n->declarativeCppNode()) + n->markReadOnly(!n->isWritable()); + + QStringList extra; + if (n->isDefault()) + extra << "default"; + else if (n->isReadOnly()) + extra << "read-only"; + else if (n->isRequired()) + extra << "required"; + + if (!n->since().isEmpty()) { + if (!extra.isEmpty()) + extra.last().append(','); + extra << "since " + n->since(); + } + + if (!extra.isEmpty()) + out() << QString("[%1] ") + .arg(extra.join(QLatin1Char(' '))); + + generateQmlItem(n, relative, marker, false); + out() << qmlItemEnd; + }; + + std::function generateQmlMethod = [&](Node *n) { + out() << qmlItemStart.arg(refForNode(n), "tblQmlFuncNode"); + generateSynopsis(n, relative, marker, Section::Details, false); + out() << qmlItemEnd; + }; out() << "
    "; - QString nodeRef = refForNode(node); if (node->isPropertyGroup()) { - const SharedCommentNode* scn = static_cast(node); - QVector::ConstIterator p = scn->collective().constBegin(); - out() << "
    "; - out() << "
    "; - - QString heading = scn->name() + " group"; - out() << ""; - out() << ""; - while (p != scn->collective().constEnd()) { - if ((*p)->isQmlProperty() || (*p)->isJsProperty()) { - qpn = static_cast(*p); - nodeRef = refForNode(qpn); - out() << ""; - out() << ""; - } - ++p; + const auto *scn = static_cast(node); + out() << qmlItemHeader; + if (!scn->name().isEmpty()) { + const QString nodeRef = refForNode(scn); + out() << R"("; + out() << "\n"; } - out() << "

    "; - out() << ""; - out() << "" << heading << ""; - out() << "

    "; - out() << ""; - - if (!qpn->isWritable()) - out() << "[read-only] "; - if (qpn->isDefault()) - out() << "[default] "; - generateQmlItem(qpn, relative, marker, false); - out() << "

    "; + out() << ""; + out() << "" << scn->name() << " group"; + out() << "

    "; - out() << "
    "; + const QList sharedNodes = scn->collective(); + for (const auto &sharedNode : sharedNodes) { + if (sharedNode->isQmlProperty() || sharedNode->isJsProperty()) + generateQmlProperty(static_cast(sharedNode)); + } + out() << qmlItemFooter; } else if (node->isQmlProperty() || node->isJsProperty()) { - qpn = static_cast(node); out() << qmlItemHeader; - out() << qmlItemStart.arg(nodeRef, "tblQmlPropNode", refForNode(qpn)); - - if (!qpn->isReadOnlySet()) { - if (qpn->declarativeCppNode()) - qpn->markReadOnly(!qpn->isWritable()); - } - if (qpn->isReadOnly()) - out() << "[read-only] "; - if (qpn->isDefault()) - out() << "[default] "; - - generateQmlItem(qpn, relative, marker, false); - out() << qmlItemEnd; + generateQmlProperty(static_cast(node)); out() << qmlItemFooter; } else if (node->isSharedCommentNode()) { - const SharedCommentNode *scn = reinterpret_cast(node); - const QVector& collective = scn->collective(); - if (collective.size() > 1) + const auto *scn = reinterpret_cast(node); + const QList &sharedNodes = scn->collective(); + if (sharedNodes.size() > 1) out() << "
    \n"; out() << qmlItemHeader; - for (const auto m : collective) { - if (m->isFunction(Node::CPP) || m->isFunction(Node::JS)) { - out() << qmlItemStart.arg(nodeRef, "tblQmlFuncNode", refForNode(m)); - generateSynopsis(m, relative, marker, Section::Details, false); - out() << qmlItemEnd; - } + for (const auto &sharedNode : sharedNodes) { + if (sharedNode->isFunction(Node::QML) || sharedNode->isFunction(Node::JS)) + generateQmlMethod(sharedNode); + else if (sharedNode->isQmlProperty() || sharedNode->isJsProperty()) + generateQmlProperty(static_cast(sharedNode)); } out() << qmlItemFooter; - if (collective.size() > 1) - out() << "
    "; + if (sharedNodes.size() > 1) + out() << "
    "; // fngroup } else { // assume the node is a method/signal handler out() << qmlItemHeader; - out() << qmlItemStart.arg(nodeRef, "tblQmlFuncNode", refForNode(node)); - generateSynopsis(node, relative, marker, Section::Details, false); - out() << qmlItemEnd; + generateQmlMethod(node); out() << qmlItemFooter; } @@ -4393,18 +3611,18 @@ void HtmlGenerator::generateDetailedQmlMember(Node *node, Output the "Inherits" line for the QML element, if there should be one. */ -void HtmlGenerator::generateQmlInherits(QmlTypeNode* qcn, CodeMarker* marker) +void HtmlGenerator::generateQmlInherits(QmlTypeNode *qcn, CodeMarker *marker) { if (!qcn) return; - QmlTypeNode* base = qcn->qmlBaseNode(); + QmlTypeNode *base = qcn->qmlBaseNode(); while (base && base->isInternal()) { base = base->qmlBaseNode(); } if (base) { Text text; text << Atom::ParaLeft << "Inherits "; - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(base)); + text << Atom(Atom::LinkNode, CodeMarker::stringForNode(base)); text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); text << Atom(Atom::String, base->name()); text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); @@ -4413,77 +3631,13 @@ void HtmlGenerator::generateQmlInherits(QmlTypeNode* qcn, CodeMarker* marker) } } -/*! - Output the "[Xxx instantiates the C++ class QmlGraphicsXxx]" - line for the QML element, if there should be one. - - If there is no class node, or if the class node status - is set to Node::Internal, do nothing. - */ -void HtmlGenerator::generateQmlInstantiates(QmlTypeNode* qcn, CodeMarker* marker) -{ - ClassNode* cn = qcn->classNode(); - if (cn && !cn->isInternal()) { - Text text; - text << Atom::ParaLeft; - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); - text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - QString name = qcn->name(); - /* - Remove the "QML:" prefix, if present. - It shouldn't be present anymore. - */ - if (name.startsWith(QLatin1String("QML:"))) - name = name.mid(4); // remove the "QML:" prefix - text << Atom(Atom::String, name); - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - text << " instantiates the C++ class "; - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); - text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - text << Atom(Atom::String, cn->name()); - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - text << Atom::ParaRight; - generateText(text, qcn, marker); - } -} - -/*! - Output the "[QmlGraphicsXxx is instantiated by QML Type Xxx]" - line for the class, if there should be one. - - If there is no QML element, or if the class node status - is set to Node::Internal, do nothing. - */ -void HtmlGenerator::generateInstantiatedBy(ClassNode* cn, CodeMarker* marker) -{ - if (cn && !cn->isInternal() && cn->qmlElement() != nullptr) { - const QmlTypeNode* qcn = cn->qmlElement(); - Text text; - text << Atom::ParaLeft; - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(cn)); - text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - text << Atom(Atom::String, cn->name()); - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - if (qcn->isQmlType()) - text << " is instantiated by QML Type "; - else - text << " is instantiated by Javascript Type "; - text << Atom(Atom::LinkNode,CodeMarker::stringForNode(qcn)); - text << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK); - text << Atom(Atom::String, qcn->name()); - text << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK); - text << Atom::ParaRight; - generateText(text, cn, marker); - } -} - void HtmlGenerator::generateExtractionMark(const Node *node, ExtractionMarkType markType) { if (markType != EndMark) { out() << " */ if (!commentHash.size()) { @@ -125,7 +124,6 @@ Quoter::Quoter() commentHash["qrc"] = " + Autolinking | TestCPP + + + +

    Autolinking

    + + +
    + +

    TestQDoc

    +

    The string TestQDoc links to the C++ namespace unless linking explicitly, like this, or this. Also,

    +

    Autolinks:

    + +

    Explicit links:

    + +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html new file mode 100644 index 0000000000..0a32e4e60b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype-members.html @@ -0,0 +1,28 @@ + + + + + + List of All Members for TestType | CrossModule + + +
  • TestType
  • + +

    List of All Members for TestType

    +

    This is the complete list of members for TestType, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype.html b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype.html new file mode 100644 index 0000000000..19e7ce1256 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/crossmodule/testtype.html @@ -0,0 +1,67 @@ + + + + + + TestType Class | CrossModule + + +
  • TestType
  • + +

    TestType Class

    + +

    A class inheriting another class that lives in an external doc module. More...

    + +
    +
    Header: #include <TestType> +
    Inherits: TestQDoc::TestDerived
    + +

    Public Functions

    +
    + +
    void nothing()
    + + +
    +

    Detailed Description

    + +

    Linking

    +

    These links go to the parent class:

    + + +

    Generated Lists

    +

    This is an annotated list of entries in a group:

    +

    +
    +

    See also someFunction().

    + +
    +

    Member Function Documentation

    + +

    void TestType::nothing()

    +

    Nothing to see here.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/demos-manifest.xml b/tests/auto/qdoc/generatedoutput/expected_output/demos-manifest.xml new file mode 100644 index 0000000000..60da1bca7c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/demos-manifest.xml @@ -0,0 +1,9 @@ + + + + + + demo,test + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoc-test-qmlmodule.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoc-test-qmlmodule.xml new file mode 100644 index 0000000000..8d514bad1f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoc-test-qmlmodule.xml @@ -0,0 +1,54 @@ + + + + +Test +A test project for QDoc build artifacts + +QML Types for the Test module. +This module is under development and is subject to change. +This module was introduced in Qt 1.1. + + +This module is under development and is subject to change. +This module was introduced in Qt 1.1. + + + +DocTest + +Represents a doc test case. + + + +AbstractParent + +Abstract base QML type. + + + +Child + +A Child inheriting its parent. + + + +int + +An integer basic type. + + + +YetAnotherChild + +A type inheriting from internal abstract parent. + + + +Type + +A QML type documented in a .cpp file. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-exhaustive.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-exhaustive.xml new file mode 100644 index 0000000000..af2fdd955e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-exhaustive.xml @@ -0,0 +1,65 @@ + + + +Exhaustive testing of QDoc commands +OutputFromQDocFiles +OutputFromQDocFiles - A test project for QDoc build artifacts +A test project for QDoc build artifacts + +This page is a dumping ground for QDoc commands under test. + + + +This is a section1 + +This is a section2 + +This is a section3 + +This is a section4 +This is bad code + +This text should have a line break riiiiight noooow. +All your text belong to bold ...And this is an examble of only bold being, well, bold. + ... + +<@comment>// If I knew JavaScript, this is where I would write it.</@comment> + +And if I knew qmltext, I guess this is where that would go. +This a caption +Lorem legal ipsum +This is a quotation. + + <html><body>This is <b>raw</b>. Like the <h1>Eddie Murphy</h1> movie. Just not as funny.</body></html> + Look, ma! I made a sidebar! + + + + +Table item in a table row + + + + +Another item in a different row + + + + +This is really important. + +For example, if you have code like +This is old code<@op>.</@op> + +you can rewrite it as +This is <@keyword>new</@keyword> and shiny<@op>!</@op> + + +The code above doesn't compile + +Warning: The following commands have yet to be tested: footnote link sincelist header index topicref // or just don’t care, remove it image inlineimage printline printto printuntil // what’s the difference between printto and printuntil??? quotefile quotefromfile quotefunction skipline skipto skipuntil span snippet codeline overload sub sup tableofcontents tt uicontrol endmapref endomit underline unicode + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-linking.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-linking.xml new file mode 100644 index 0000000000..90c76d8ee7 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput-linking.xml @@ -0,0 +1,17 @@ + + + +Testing QDoc's link command +OutputFromQDocFiles +OutputFromQDocFiles - A test project for QDoc build artifacts +A test project for QDoc build artifacts + +This is a page for testing QDoc's link command. + + + + +Link targets +Valid parameters for the link command (\l) are page and section titles, targets defined with \target or \keyword commands, and API reference keywords (types, methods, namespaces, and so on). + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput.xml new file mode 100644 index 0000000000..1e230d3b7a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qdoctests-qdocfileoutput.xml @@ -0,0 +1,68 @@ + + + +Testing QDoc output from .qdoc files +OutputFromQDocFiles +OutputFromQDocFiles - A test project for QDoc build artifacts +A test project for QDoc build artifacts + +This is a simple page for testing purposes only. + + +QDoc generates documentation for software projects. It does this by extracting QDoc comments from project source files. QDoc comments are signified by a C-style-like comment tag followed by an exclamation point, like this: /*! This text is contained within QDoc comment tags. */. + +Supported file types +QDoc parses .cpp and .qdoc files. It does extract comments from header (.h) files. + + +Further information +This test document is written with the purpose of testing the output QDoc generates when parsing .qdoc files. It is fairly simple and makes use of a limited subset of QDoc's command. Those commands are: + + +\page + + +\title + + +\brief + + +\e (for emphasizing "QDoc comments") + + +\c (for multiple monospace-formatted entries) + + +\section1 + + +\list + + +\li + + +\endlist + + + + +Linking +There are multiple ways to create hyperlinks to other topics: + + +Linking to a page title + + +Linking to a section title + + +Linking using a \target string + + +Linking using a \keyword string + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-int.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-int.xml new file mode 100644 index 0000000000..00ef9ec39c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-int.xml @@ -0,0 +1,21 @@ + + + +int QML Basic Type +Test +A test project for QDoc build artifacts + +An integer basic type. + + + +Detailed Description + + +Method Documentation + +int abs() +Returns the absolute value of this integer. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-abstractparent.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-abstractparent.xml new file mode 100644 index 0000000000..81c6be1b3f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-abstractparent.xml @@ -0,0 +1,74 @@ + + + +AbstractParent QML Type +Test +A test project for QDoc build artifacts + +Abstract base QML type. + + + + +Import Statement + +import QDoc.Test 1.1 + + + +Inherited By: + +Child + + + + +Detailed Description + + +Property Documentation + +[default] children : list<Child> + +list<Child> +children +writable +[default] + +public +active +unspecified +Test + +Children of the type. + + +name : string + +string +name +writable +public +active +unspecified +Test + +Name of this parent. + + + +Method Documentation + +void name() +Name all children with random names. + + +void name(Child child, name) +Name a child using name. + + +void rear(Child child, var method = Strict) +Do some abstract parenting on child using a specific method. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-child.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-child.xml new file mode 100644 index 0000000000..f5acb0729c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-child.xml @@ -0,0 +1,74 @@ + + + +Child QML Type +Test +A test project for QDoc build artifacts + +A Child inheriting its parent. + + + + +Import Statement + +import QDoc.Test 1.1 + + + +Inherits: + +AbstractParent + + + + +Detailed Description + + +Property Documentation + +[default] children : list<Child> + +list<Child> +children +writable +[default] + +public +active +unspecified +Test + +Children of the type. + + +name : string + +string +name +writable +public +active +unspecified +Test + +Name of this child. + + + +Method Documentation + +void name() +Name all children with random names. + + +void name(Child child, name) +Name a child of this child using name. + + +void rear(Child child, var method = Strict) +Do some abstract parenting on child using a specific method. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-doctest.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-doctest.xml new file mode 100644 index 0000000000..5953866a1f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-doctest.xml @@ -0,0 +1,105 @@ + + + +DocTest QML Type +Test +A test project for QDoc build artifacts + +Represents a doc test case. +This type was introduced in QDoc.Test 0.9. + + + + +Import Statement + +import QDoc.Test 1.1 + + + +Since: + +QDoc.Test 0.9 + + + + +Detailed Description + +Introduction +A documentation test case, itself documented inline in DocTest.qml. + + + +Property Documentation + +active : bool + +bool +active +writable +public +active +unspecified + +Whether the test is active. +See also +name + + + +[required] name : string + +string +name +writable +required +public +active +unspecified + +Name of the test. +<@type>DocTest</@type> { + <@name>name</@name>: <@string>&quot;test&quot;</@string> + <@comment>// ...</@comment> +} + + + + +Signal Documentation + +completed() + +The corresponding handler is onCompleted. + + + +foo(var bar) +Signal with parameter bar. + +The corresponding handler is onFoo. + + + + +Method Documentation + +[since QDoc.Test 1.0] fail(message = "oops") +Fails the current test case, with the optional message. +This method was introduced in QDoc.Test 1.0. + + +fail_hard(msg = "facepalm", option = 123) +Fails the current test case, hard. + + +Prints out msg. + + +Accepts a random option. + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-type.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-type.xml new file mode 100644 index 0000000000..0afcb00454 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-type.xml @@ -0,0 +1,169 @@ + + + +Type QML Type +Test +A test project for QDoc build artifacts + +A QML type documented in a .cpp file. + + + + +Import Statement + +import QDoc.Test 1.1 + + + +Instantiates: + +Test + + + + +Detailed Description + + +Property Documentation +A group of properties sharing a documentation comment. + +group group +group.first : int + +int +group.first +writable +public +active +unspecified +Test + +group.second : int + +int +group.second +writable +public +active +unspecified +Test + +group.third : int + +int +group.third +writable +public +active +unspecified +Test + +A property group. + + +[read-only] id : int + +int +id +[read-only] + +public +active +unspecified +Test + +A read-only property. + + +[required] name : string + +string +name +writable +required +public +active +unspecified +Test + +Name of the Test. + + + +Attached Property Documentation + +Type.type : enumeration + +enumeration +Type.type +attached +writable +public +active +unspecified +Test + + + + +Constant +Description + + + + +Type.NoType + + +Nothing + + + + +Type.SomeType + + +Something + + + + + + +Signal Documentation + +completed(int status) +This signal is emitted when the operation completed with status. + +The corresponding handler is onCompleted. + + + +group.created() +This signal is prefixed with group. + +The corresponding handler is group.onCreated. + + + + +Attached Signal Documentation + +configured() +This attached signal is emitted when the type was configured. + +The corresponding handler is onConfigured. + + + + +Method Documentation +Enables or disables this type. + +Type copy(a) +Returns another Type based on a. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-yetanotherchild.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-yetanotherchild.xml new file mode 100644 index 0000000000..487043376b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-qdoc-test-yetanotherchild.xml @@ -0,0 +1,38 @@ + + + +YetAnotherChild QML Type +Test +A test project for QDoc build artifacts + +A type inheriting from internal abstract parent. + + + + +Import Statement + +import QDoc.Test 1.1 + + + + +Detailed Description + + +Property Documentation + +prop : int + +int +prop +writable +public +active +unspecified +Test + +Propagated to inheriting type docs. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-progressbar.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-progressbar.xml new file mode 100644 index 0000000000..3f162e8a4f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-progressbar.xml @@ -0,0 +1,94 @@ + + + +ProgressBar QML Type +Test +A test project for QDoc build artifacts + +A component that shows the progress of an event. + + + + +Import Statement + +import UIComponents 1.0 + + + + +Detailed Description +A ProgressBar shows the linear progress of an event as its value. The range is specified using the minimum and the maximum values. +The ProgressBar component is part of the UI Components module. +This documentation is part of the UIComponents example. + + +Property Documentation + +color : color + +color +color +writable +public +active +unspecified + +The color of the ProgressBar's gradient. Must bind to a color type. +See also +secondColor + + + +maximum : int + +int +maximum +writable +public +active +unspecified + +The maximum value of the ProgressBar range. The value must not be more than this value. + + +minimum : int + +int +minimum +writable +public +active +unspecified + +The minimum value of the ProgressBar range. The value must not be less than this value. + + +secondColor : color + +color +secondColor +writable +public +active +unspecified + +The second color of the ProgressBar's gradient. Must bind to a color type. +See also +color + + + +value : int + +int +value +writable +public +active +unspecified + +The value of the progress. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-switch.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-switch.xml new file mode 100644 index 0000000000..7b1e169ef9 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-switch.xml @@ -0,0 +1,47 @@ + + + +Switch QML Type +Test +A test project for QDoc build artifacts + +A component that can be turned on or off. + + + + +Import Statement + +import UIComponents 1.0 + + + + +Detailed Description +A toggle switch has two states: an on and an off state. The off state is when the on property is set to false. +The ToggleSwitch component is part of the UI Components module. +This documentation is part of the UIComponents example. + + +Property Documentation + +on : bool + +bool +on +writable +public +active +unspecified + +Indicates the state of the switch. If false, then the switch is in the off state. + + + +Method Documentation + +toggle() +A method to toggle the switch. If the switch is on, the toggling it will turn it off. Toggling a switch in the off position will turn it on. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-tabwidget.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-tabwidget.xml new file mode 100644 index 0000000000..0232dbe275 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/qml-uicomponents-tabwidget.xml @@ -0,0 +1,77 @@ + + + +TabWidget QML Type +Test +A test project for QDoc build artifacts + +A widget that places its children as tabs. + + + + +Import Statement + +import UIComponents 1.0 + + + + +Detailed Description +A TabWidget places its children as tabs in a view. Selecting a tab involves selecting the tab at the top. +The TabWidget component is part of the UI Components module. +This documentation is part of the UIComponents example. + +Adding Tabs +To add a tab, declare the tab as a child of the TabWidget. +TabWidget { + id: tabwidget + + Rectangle { + id: tab1 + color: <@string>&quot;red&quot;</@string> + <@comment>//... omitted</@comment> + } + Rectangle { + id: tab2 + color: <@string>&quot;blue&quot;</@string> + <@comment>//... omitted</@comment> + } + +} + + + + +Property Documentation + +current : int + +int +current +writable +public +active +unspecified + +The currently active tab in the TabWidget. + + +[read-only] sampleReadOnlyProperty : int + +int +sampleReadOnlyProperty +[read-only] + +public +active +unspecified + +A sample read-only property. A contrived property to demonstrate QDoc's ability to detect read-only properties. +The signature is: +readonly property <@type>int</@type> sampleReadOnlyProperty: <@number>0</@number> + +Note that the property must be initialized to a value. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/test-componentset-example.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/test-componentset-example.xml new file mode 100644 index 0000000000..5806fc557a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/test-componentset-example.xml @@ -0,0 +1,49 @@ + + + +QML Documentation Example +Test +A test project for QDoc build artifacts + +Example for documenting QML types. + + +This example demonstrates one of the ways to document QML types. It also generates a warning about a missing example image, on purpose. +In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the UI Components module. +The uicomponents.qdoc file generates the overview page for the UI Components module page. +The generated documentation is available in the UI Components module. + +QML Class +The QML types use the \qmltype to document the type. In addition, they have the \inmodule command in order for QDoc to associate them to the UIComponents module. +QDoc uses the \brief command to place a basic description when listing the types. + + +Properties, Signals, Handlers, and Methods +The types have their properties, signals, handlers, and methods defined in their respective QML files. QDoc associates the properties and methods to the types, therefore, you only need to place the documentation above the property, method, or signal. +To document the type of a property alias, you must use the \qmlproperty command to specify the data type. +\qmlproperty <@type>int</@type> anAliasedProperty +An aliased property of type <@type>int</@type><@op>.</@op> + + +Internal Documentation +You may declare that a documentation is for internal use by placing the \internal command after the beginning QDoc comment /*. QDoc will prevent the internal documentation from appearing in the public API. +If you wish to omit certain parts of the documentation, you may use the \omit and \endomit command. + + + +QML Types with C++ Implementation +This example only demonstrates the documentation for types in QML files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type. + +Files: + +componentset/ProgressBar.qml + +componentset/Switch.qml + +componentset/TabWidget.qml + +componentset/componentset.pro + +componentset/componentset.qml + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testcpp-module.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testcpp-module.xml new file mode 100644 index 0000000000..065421b2df --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testcpp-module.xml @@ -0,0 +1,46 @@ + + + +QDoc Test C++ Classes +TestCPP +TestCPP Reference Documentation + +A test module page. + + +A test module page. + +Namespaces + + +TestQDoc + +A namespace. + + + + + +Classes + + +TestQDoc::Test + +A class in a namespace. + + + +TestQDoc::TestDerived + +A derived class in a namespace. + + + + + +Detailed Description + +This is just a test. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml new file mode 100644 index 0000000000..724e827f99 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-test.xml @@ -0,0 +1,298 @@ + + + +Test Class +TestQDoc::Test +TestCPP +TestCPP Reference Documentation + +A class in a namespace. + + + + +Header + +Test + + + +CMake + +find_package(Qt6 COMPONENTS QDocTest REQUIRED) +target_link_libraries(mytarget PRIVATE Qt6::QDocTest) + + + +qmake + +QT += testcpp + + + +Inherited By + +TestQDoc::TestDerived + + + + +Detailed Description + + +Member Type Documentation + +Test::SomeType + +SomeTypepublic +active +unspecified +TestCPP + +A typedef. + + + +Member Function Documentation + +[protected] Test::void overload() +[protected, since Test 1.2] Test::void overload(bool b) +Overloads that share a documentation comment, optionally taking a parameter b. + + +[default] Test::Test() + + +Test +default + +constructor +Test() = default +public +active +unspecified +TestCPP + +Default constructor. + + +[default] Test::TestQDoc::Test &operator=(TestQDoc::Test &&other) + +TestQDoc::Test & +operator= +default + +TestQDoc::Test && +other + +move-assign +TestQDoc::Test & operator=(TestQDoc::Test &&other) = default +public +active +unspecified +TestCPP + +Move-assigns other. + + +Test::void (*)(bool) funcPtr(bool b, const char *s) + +void (*)(bool) +funcPtr + +bool +b + + +const char * +s + +plain +void (*)(bool) funcPtr(bool b, const char *s) +public +active +unspecified +TestCPP + +Returns a pointer to a function that takes a boolean. Uses b and s. + + +Test::void inlineFunction() + + +inlineFunction + +plain +void inlineFunction() +public +active +unspecified +TestCPP + +An inline function, documented using the \fn QDoc command. + + +Test::int someFunction(int, int v = 0) + +int +someFunction + +int + + + +int +v +0 + +plain +int someFunction(int, int v) +public +active +unspecified +TestCPP + +Function that takes a parameter v. Also returns the value of v. + + +Test::void someFunctionDefaultArg(int i, bool b = false) + + +someFunctionDefaultArg + +int +i + + +bool +b +false + +plain +void someFunctionDefaultArg(int i, bool b) +public +active +unspecified +TestCPP + +Function that takes a parameter i and b. + + +[virtual] Test::void virtualFun() + +virtual + +virtualFun + +plain +void virtualFun() +public +active +unspecified +TestCPP + +Function that must be reimplemented. + + + +Related Non-Members + +bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs) + +bool +operator== + +const TestQDoc::Test & +lhs + + +const TestQDoc::Test & +rhs + +plain +bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs) +public +active +unspecified +TestCPP + +Returns true if lhs and rhs are equal. + + + +Macro Documentation + +[since Test 1.1] QDOCTEST_MACRO2(int &x) + +QDOCTEST_MACR + +int & +x + +macrowithparams +QDOCTEST_MACRO2(int &x) +public +active +unspecified +TestCPP + +A macro with argument x. +This function was introduced in Test 1.1. + + + +Obsolete Members for Test +The following members of class Test are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code. + +Member Function Documentation + +Test::void anotherObsoleteMember() + + +anotherObsoleteMember + +plain +void anotherObsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use obsoleteMember() instead. + + +Test::void deprecatedMember() + + +deprecatedMember + +plain +void deprecatedMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use someFunction() instead. + + +Test::void obsoleteMember() + + +obsoleteMember + +plain +void obsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use someFunction() instead. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml new file mode 100644 index 0000000000..c0846867d1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc-testderived.xml @@ -0,0 +1,108 @@ + + + +TestDerived Class +TestQDoc::TestDerived +TestCPP +TestCPP Reference Documentation + +A derived class in a namespace. + + + + +Header + +TestDerived + + + +CMake + +find_package(Qt6 COMPONENTS QDocTest REQUIRED) +target_link_libraries(mytarget PRIVATE Qt6::QDocTest) + + + +qmake + +QT += testcpp + + + +Inherits + +TestQDoc::Test + + + + +Detailed Description + + +Member Type Documentation + +[alias] TestDerived::DerivedType + +DerivedTypepublic +active +unspecified +TestCPP + +An aliased typedef. + + +[alias] TestDerived::NotTypedef + +NotTypedefpublic +active +unspecified +TestCPP + +I'm an alias, not a typedef. + + + +Member Function Documentation + +[override virtual] TestDerived::void virtualFun() + +virtual + +virtualFun +override + +plain +void virtualFun() override +public +active +unspecified +TestCPP + +Reimplements: Test::virtualFun(). + + +Obsolete Members for TestDerived +The following members of class TestDerived are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code. + +Member Function Documentation + +[static] TestDerived::void staticObsoleteMember() + +static + +staticObsoleteMember + +plain +void staticObsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Static obsolete method. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc.xml new file mode 100644 index 0000000000..da531f8cf1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/testqdoc.xml @@ -0,0 +1,65 @@ + + + +TestQDoc Namespace +TestCPP +TestCPP Reference Documentation + +A namespace. + + + + +Header + +TestCPP + + + +CMake + +find_package(Qt6 COMPONENTS QDocTest REQUIRED) +target_link_libraries(mytarget PRIVATE Qt6::QDocTest) + + + +qmake + +QT += testcpp + + + + +Detailed Description + +Usage +This namespace is for testing QDoc output. + + + +Classes + +class Test +A class in a namespace. + + +class TestDerived +A derived class in a namespace. + + + +Macro Documentation + +QDOCTEST_MACRO + +QDOCTEST_MAC +macrowithoutparams +QDOCTEST_MACRO +public +active +unspecified +TestCPP + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/docbook/uicomponents-qmlmodule.xml b/tests/auto/qdoc/generatedoutput/expected_output/docbook/uicomponents-qmlmodule.xml new file mode 100644 index 0000000000..f00b3d3f72 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/docbook/uicomponents-qmlmodule.xml @@ -0,0 +1,34 @@ + + + +UI Components +Test +A test project for QDoc build artifacts + +Basic set of UI components. + + + +This is a listing of a list of UI components implemented by QML types. These files are available for general import and they are based on the Qt Quick Code Samples. +This module is part of the UIComponents example. + + +ProgressBar + +A component that shows the progress of an event. + + + +Switch + +A component that can be turned on or off. + + + +TabWidget + +A widget that places its children as tabs. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/classes.html b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/classes.html new file mode 100644 index 0000000000..f5bae610ad --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/classes.html @@ -0,0 +1,22 @@ + + + + + + Classes | TestCPP + + + +

    Classes

    + + +
    +
    + + + +

    SeenClass

    A public but undocumented class

    TestQDoc::Test

    A class in a namespace

    TestQDoc::TestDerived

    A derived class in a namespace

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/dontdocument.qhp b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/dontdocument.qhp new file mode 100644 index 0000000000..c834404617 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/dontdocument.qhp @@ -0,0 +1,65 @@ + + + org.qt-project.dontdocument.001 + test + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + autolinking.html + classes.html + obsolete-classes.html + seenclass.html + testcpp-module.html + testqdoc-test-members.html + testqdoc-test-obsolete.html + testqdoc-test.html + testqdoc-testderived-members.html + testqdoc-testderived-obsolete.html + testqdoc-testderived.html + testqdoc.html + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/seenclass.html b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/seenclass.html new file mode 100644 index 0000000000..d2dfade45a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/dontdocument/seenclass.html @@ -0,0 +1,34 @@ + + + + + + SeenClass Class | TestCPP + + +
  • SeenClass
  • + +

    SeenClass Class

    + +

    A public but undocumented class. More...

    + +
    +
    Header: #include <SeenClass> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/examples-manifest.xml b/tests/auto/qdoc/generatedoutput/expected_output/examples-manifest.xml new file mode 100644 index 0000000000..4d8a61cfbf --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/examples-manifest.xml @@ -0,0 +1,15 @@ + + + + + + cmake,project,test + test/cmaketest/main.cpp + + + + documentation,qml,sample,test + tutorials/componentset/componentset.qml + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/first.html b/tests/auto/qdoc/generatedoutput/expected_output/first.html new file mode 100644 index 0000000000..566374eff5 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/first.html @@ -0,0 +1,38 @@ + + + + + + First Struct | TestModule + + +
  • First
  • + +

    First Struct

    +
    +
    Header: #include <First> +
    + +

    Public Types

    +
    + +
    class Nested
    + + +
    +

    Detailed Description

    +

    This is a first class

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/globals.html b/tests/auto/qdoc/generatedoutput/expected_output/globals.html new file mode 100644 index 0000000000..90f9272324 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/globals.html @@ -0,0 +1,48 @@ + + + + + + Globals Class | TestGlobals + + +
  • Globals
  • + +

    Globals Class

    +
    +
    Header: #include <Globals> +
      +
    + + +
    + + +
    int foo(int a)
    int foo(int a, bool b)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Related Non-Members

    + +

    int foo(int a)

    +

    Params: a

    + + +

    int foo(int a, bool b)

    +

    Params: b, b

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/headers.xml b/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/headers.xml new file mode 100644 index 0000000000..052108b2aa --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/headers.xml @@ -0,0 +1,19 @@ + + + +Headers +HeaderFile +HeaderFile Reference Documentation + +HeaderFile Reference Documentation. + + + + +<TestHeader> + +A header file. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/testheader.xml b/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/testheader.xml new file mode 100644 index 0000000000..afa0b20a38 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/headerfile-docbook/testheader.xml @@ -0,0 +1,90 @@ + + + +<TestHeader> - Test Header +HeaderFile +HeaderFile Reference Documentation + +A header file. + + + + +Header + +TestHeader + + + + +Detailed Description + + +Type Documentation + +enum Globals + +Globals +public +active +unspecified +HeaderFile + + + + + + +Constant +Description + + + + +Glo + +0 + + + +Bal + +1 + + + + + +Variable Documentation + +const int globalVar + +const int +globalVar +public +active +unspecified +HeaderFile + +Global variable. + + + +Function Documentation + +void globalFunc() + + +globalFunc + +plain +void globalFunc() +public +active +unspecified +HeaderFile + +Global function. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/headerfile/headers.html b/tests/auto/qdoc/generatedoutput/expected_output/headerfile/headers.html new file mode 100644 index 0000000000..65b88eca49 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/headerfile/headers.html @@ -0,0 +1,20 @@ + + + + + + Headers | HeaderFile + + + +

    Headers

    + + +
    +
    + +
    + +

    <TestHeader>

    A header file

    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/headerfile/testheader.html b/tests/auto/qdoc/generatedoutput/expected_output/headerfile/testheader.html new file mode 100644 index 0000000000..f67de8a3fd --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/headerfile/testheader.html @@ -0,0 +1,72 @@ + + + + + + <TestHeader> - Test Header | HeaderFile + + +
  • Headers
  • +
  • <TestHeader> - Test Header
  • + +

    <TestHeader> - Test Header

    + +

    A header file. More...

    + +
    +
    Header: #include <TestHeader> +
      +
    + +

    Types

    +
    + +
    enum Globals { Glo, Bal }
    + +

    Variables

    +
    + +
    const int globalVar
    + +

    Functions

    +
    + +
    void globalFunc()
    + + +
    +

    Detailed Description

    +
    + +
    +

    Type Documentation

    + +

    enum Globals

    +
    + + +
    ConstantValue
    Glo0
    Bal1
    + +
    +
    +

    Variable Documentation

    + +

    const int globalVar

    +

    Global variable.

    + +
    +
    +

    Function Documentation

    + +

    void globalFunc()

    +

    Global function.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/first.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/first.webxml new file mode 100644 index 0000000000..526bbbe73e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/first.webxml @@ -0,0 +1,15 @@ + + + + + + This is a first class + + + + This is a nested class + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/index.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/index.webxml new file mode 100644 index 0000000000..c2235e69d3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/index.webxml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-exhaustive.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-exhaustive.webxml new file mode 100644 index 0000000000..673675bd11 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-exhaustive.webxml @@ -0,0 +1,62 @@ + + + + + + + + + + This page is a dumping ground for QDoc commands under test. +
    + This is a section1 +
    +
    + This is a section2 +
    +
    + This is a section3 +
    +
    + This is a section4 +
    +
    +
    +
    + This is bad code + This text should have a line break riiiiight noooow. + + All your text belong to bold ...And this is an examble of only bold being, well, bold. + ... + And if I knew qmltext, I guess this is where that would go. This a caption + Lorem legal ipsum + + + This is a quotation. + + <html><body>This is <b>raw</b>. Like the <h1>Eddie Murphy</h1> movie. Just not as funny.</body></html> + + Look, ma! I made a sidebar! + + + + Table item in a table row + + + + + Another item in a different row + + +
    + + Important: This is really important. + For example, if you have code like + This is old code. + you can rewrite it as + This is new and shiny! + + Note: The code above doesn't compile + + Warning: The following commands have yet to be tested: footnote link sincelist header index topicref // or just don’t care, remove it image inlineimage printline printto printuntil // what’s the difference between printto and printuntil??? quotefile quotefromfile quotefunction skipline skipto skipuntil span snippet codeline overload sub sup tableofcontents tt uicontrol endmapref endomit underline unicode +
    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-linking.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-linking.webxml new file mode 100644 index 0000000000..b3ad4ee3ba --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput-linking.webxml @@ -0,0 +1,20 @@ + + + + + + + + + + + This is a page for testing QDoc's link command. + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput.webxml new file mode 100644 index 0000000000..2d9c786d89 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/qdoctests-qdocfileoutput.webxml @@ -0,0 +1,83 @@ + + + + + + + + + + This is a simple page for testing purposes only. + QDoc generates documentation for software projects. It does this by extracting QDoc comments from project source files. QDoc comments are signified by a C-style-like comment tag followed by an exclamation point, like this: /*! This text is contained within QDoc comment tags. */. +
    + Supported file types + QDoc parses .cpp and .qdoc files. It does extract comments from header (.h) files. +
    +
    + Further information + This test document is written with the purpose of testing the output QDoc generates when parsing .qdoc files. It is fairly simple and makes use of a limited subset of QDoc's command. Those commands are: + + + + \page + + + + \title + + + + \brief + + + + \e (for emphasizing "QDoc comments") + + + + \c (for multiple monospace-formatted entries) + + + + \section1 + + + + \list + + + + \li + + + + \endlist + + +
    +
    + Linking + There are multiple ways to create hyperlinks to other topics: + + + + Linking to a page title + + + + Linking to a section title + + + + Linking using a \target string + + + + Linking using a \keyword string + + +
    +
    +
    +
    +
    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/second.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/second.webxml new file mode 100644 index 0000000000..9ecd3c2fe3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/second.webxml @@ -0,0 +1,10 @@ + + + + + + This is a second class + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/test-componentset-example.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/test-componentset-example.webxml new file mode 100644 index 0000000000..56e42e88ef --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/test-componentset-example.webxml @@ -0,0 +1,67 @@ + + + + + + + + + + Example for documenting QML types. + This example demonstrates one of the ways to document QML types. It also generates a warning about a missing example image, on purpose. + In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the UI Components module. + The uicomponents.qdoc file generates the overview page for the UI Components module page. + The generated documentation is available in the UI Components module. +
    + QML Class + The QML types use the \qmltype to document the type. In addition, they have the \inmodule command in order for QDoc to associate them to the UIComponents module. + QDoc uses the \brief command to place a basic description when listing the types. +
    +
    + Properties, Signals, Handlers, and Methods + The types have their properties, signals, handlers, and methods defined in their respective QML files. QDoc associates the properties and methods to the types, therefore, you only need to place the documentation above the property, method, or signal. + To document the type of a property alias, you must use the \qmlproperty command to specify the data type. + \qmlproperty int anAliasedProperty +An aliased property of type int. +
    +
    + Internal Documentation + You may declare that a documentation is for internal use by placing the \internal command after the beginning QDoc comment /*. QDoc will prevent the internal documentation from appearing in the public API. + If you wish to omit certain parts of the documentation, you may use the \omit and \endomit command. +
    +
    + QML Types with C++ Implementation + This example only demonstrates the documentation for types in QML files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type. +
    + Files: + + + + componentset/ProgressBar.qml + + + + + componentset/Switch.qml + + + + + componentset/TabWidget.qml + + + + + componentset/componentset.pro + + + + + componentset/componentset.qml + + + +
    +
    +
    +
    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testcpp-module.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testcpp-module.webxml new file mode 100644 index 0000000000..5d24b3077d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testcpp-module.webxml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml new file mode 100644 index 0000000000..949949ee9a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-test.webxml @@ -0,0 +1,92 @@ + + + + + + A class in a namespace. + + + + + A macro with argument x. + + + + + Default constructor. + + + + + Use obsoleteMember() instead. + + + + + Use someFunction() instead. + + + + + + + Returns a pointer to a function that takes a boolean. Uses b and s. + + + + + An inline function, documented using the \fn QDoc command. + + + + + Use someFunction() instead. + + + + + + Move-assigns other. + + + + + + + Returns true if lhs and rhs are equal. + + + + + + + + + + + + + + Function that takes a parameter v. Also returns the value of v. + + + + + + + Function that takes a parameter i and b. + + + + + Function that must be reimplemented. + + + + + A typedef. + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml new file mode 100644 index 0000000000..099f20dcec --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc-testderived.webxml @@ -0,0 +1,28 @@ + + + + + + A derived class in a namespace. + + + + Static obsolete method. + + + + + + + + An aliased typedef. + + + + + I'm an alias, not a typedef. + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc.webxml new file mode 100644 index 0000000000..a8cbb951ac --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/testqdoc.webxml @@ -0,0 +1,75 @@ + + + + + + + A namespace. +
    + Usage + This namespace is for testing QDoc output. +
    +
    + + + + + + A class in a namespace. + + + + + A macro with argument x. + + + + + Use obsoleteMember() instead. + + + + + Use someFunction() instead. + + + + + An inline function, documented using the \fn QDoc command. + + + + + Use someFunction() instead. + + + + + + Function that takes a parameter v. Also returns the value of v. + + + + + + + Function that takes a parameter i and b. + + + + + Function that must be reimplemented. + + + + + + A derived class in a namespace. + + + + + +
    +
    +
    diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/third.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/third.webxml new file mode 100644 index 0000000000..529ffd8968 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/third.webxml @@ -0,0 +1,10 @@ + + + + + + This is a third class + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/html/uicomponents-qmlmodule.webxml b/tests/auto/qdoc/generatedoutput/expected_output/html/uicomponents-qmlmodule.webxml new file mode 100644 index 0000000000..5d24b3077d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/html/uicomponents-qmlmodule.webxml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html new file mode 100644 index 0000000000..529f74a3b6 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc-test.html @@ -0,0 +1,135 @@ + + + + + + Test Class | TestCPP + + +
  • Test
  • + +

    Test Class

    +class TestQDoc::Test + +

    A class in a namespace. More...

    + +
    +
    Header: #include <Test> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherited By:

    TestQDoc::TestDerived

    +
    + +

    Public Types

    + + +

    Public Functions

    +
    + + + + + + + +
    Test()
    TestQDoc::Test &operator=(TestQDoc::Test &&other)
    void (*)(bool) funcPtr(bool b, const char *s)
    void inlineFunction()
    int someFunction(int, int v = 0)
    void someFunctionDefaultArg(int i, bool b = false)
    virtual void virtualFun()
    + +

    Protected Functions

    +
    + + +
    void overload()
    void overload(bool b)
    + + +
    + +
    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)
    + +

    Macros

    +
    + +
    QDOCTEST_MACRO2(int &x)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    Test::SomeType

    +

    A typedef.

    + +
    +
    +

    Member Function Documentation

    + +
    +

    [protected] void Test::overload()

    [protected, since Test 1.2] void Test::overload(bool b)

    +

    Overloads that share a documentation comment, optionally taking a parameter b.

    + + +

    [default] Test::Test()

    +

    Default constructor.

    + + +

    [default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&other)

    +

    Move-assigns other.

    + + +

    void (*)(bool) Test::funcPtr(bool b, const char *s)

    +

    Returns a pointer to a function that takes a boolean. Uses b and s.

    + + +

    void Test::inlineFunction()

    +

    An inline function, documented using the \fn QDoc command.

    + + +

    [since Test 1.0] int Test::someFunction(int, int v = 0)

    +

    Function that takes a parameter v. Also returns the value of v.

    +

    This function was introduced in Test 1.0.

    + + +

    [since 2.0] void Test::someFunctionDefaultArg(int i, bool b = false)

    +

    Function that takes a parameter i and b.

    +

    This function was introduced in Qt 2.0.

    + + +

    [virtual] void Test::virtualFun()

    +

    Function that must be reimplemented.

    + +
    +
    +

    Related Non-Members

    + +

    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)

    +

    Returns true if lhs and rhs are equal.

    + +
    +
    +

    Macro Documentation

    + +

    [since Test 1.1] QDOCTEST_MACRO2(int &x)

    +

    A macro with argument x.

    +

    This function was introduced in Test 1.1.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc.html b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc.html new file mode 100644 index 0000000000..237a0188f2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/ignoresince/testqdoc.html @@ -0,0 +1,65 @@ + + + + + + TestQDoc Namespace | TestCPP + + + +

    TestQDoc Namespace

    + +

    A namespace. More...

    + +
    +
    Header: #include <TestCPP> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + +

    Classes

    +
    + + +
    class Test
    class TestDerived
    + +

    Macros

    + + + +
    +

    Detailed Description

    + +

    Usage

    +

    This namespace is for testing QDoc output.

    +
    + +
    +

    Classes

    +

    class Test

    +

    A class in a namespace. More...

    + +

    class TestDerived

    +

    A derived class in a namespace. More...

    + +
    +
    +

    Macro Documentation

    + +

    QDOCTEST_MACRO

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/index.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/index.html new file mode 100644 index 0000000000..fd9fdd50af --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/index.html @@ -0,0 +1,30 @@ + + + + + + doc index | Test + + +

    doc index

    + + +
    + +

    C++ Classes

    +
    + + +

    TestQDoc::Test

    A class in a namespace

    TestQDoc::TestDerived

    A derived class in a namespace

    + +

    QML Types

    +
    + + + +

    AbstractParent

    Abstract base QML type

    Child

    A Child inheriting its parent

    int

    An integer basic type

    +

    Test include file that is part of the sourcedirs.

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qdoc-test-qmlmodule.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qdoc-test-qmlmodule.html new file mode 100644 index 0000000000..6a513e987d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qdoc-test-qmlmodule.html @@ -0,0 +1,23 @@ + + + + + + Test + + + + + +
    +
    + +
    + + + + + +

    AbstractParent

    Abstract base QML type

    Child

    A Child inheriting its parent

    DocTest

    Represents a doc test case

    Type

    A QML type documented in a .cpp file

    int

    An integer basic type

    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-int.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-int.html new file mode 100644 index 0000000000..651f840cbd --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-int.html @@ -0,0 +1,23 @@ + + + + + + int QML Basic Type | Test + + + +

    int QML Basic Type

    + + +
    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent-members.html new file mode 100644 index 0000000000..e8ecfbb697 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent-members.html @@ -0,0 +1,17 @@ + + + + + + List of All Members for AbstractParent | Test + + + +

    List of All Members for AbstractParent

    +

    This is the complete list of members for AbstractParent, including inherited members.

    +
      +
    • children : list<Child> [default]
    • +
    • void rear(Child child)
    • +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent.html new file mode 100644 index 0000000000..1f49ca4cc7 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-abstractparent.html @@ -0,0 +1,69 @@ + + + + + + AbstractParent QML Type | Test + + + +

    AbstractParent QML Type

    + + +

    Abstract base QML type. More...

    + +
    +
    Import Statement: import QDoc.Test 1.1
    Inherited By:

    Child

    +
    + +

    Properties

    + + +

    Methods

    +
      +
    • void rear(Child child)
    • +
    + + +

    Detailed Description

    +

    Test include file that is part of the sourcedirs.

    + +

    Property Documentation

    + +
    +
    + + +

    +[default] children : list<Child>

    +

    Children of the type.

    +

    Test include file that is part of the sourcedirs.

    +
    +
    +

    Method Documentation

    + +
    +
    + + +

    +void rear(Child child)

    +

    Do some abstract parenting on child.

    +

    Test include file that is part of the sourcedirs.

    +
    +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child-members.html new file mode 100644 index 0000000000..cedbad6bc8 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child-members.html @@ -0,0 +1,18 @@ + + + + + + List of All Members for Child | Test + + + +

    List of All Members for Child

    +

    This is the complete list of members for Child, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child.html new file mode 100644 index 0000000000..b1775faa31 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-child.html @@ -0,0 +1,79 @@ + + + + + + Child QML Type | Test + + + +

    Child QML Type

    + + +

    A Child inheriting its parent. More...

    + +
    +
    Import Statement: import QDoc.Test 1.1
    Inherits:

    AbstractParent

    +
    + +

    Properties

    + + +

    Methods

    + + + +

    Detailed Description

    + +

    Property Documentation

    + +
    +
    + + +

    +[default] children : list<Child>

    +

    Children of the type.

    +

    Test include file that is part of the sourcedirs.

    +
    +
    +

    Method Documentation

    + +
    +
    + + +

    +void rear(child)

    +

    Do some abstract parenting on child.

    +
    +
    + +
    +
    + + +

    +void rear(child)

    +

    Do some abstract parenting on child.

    +

    Test include file that is part of the sourcedirs.

    +
    +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest-members.html new file mode 100644 index 0000000000..3048f97018 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest-members.html @@ -0,0 +1,18 @@ + + + + + + List of All Members for DocTest | Test + + + +

    List of All Members for DocTest

    +

    This is the complete list of members for DocTest, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest.html new file mode 100644 index 0000000000..e1475d5fbb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-doctest.html @@ -0,0 +1,86 @@ + + + + + + DocTest QML Type | Test + + + +

    DocTest QML Type

    + + +

    Represents a doc test case. More...

    + +
    +
    Import Statement: import QDoc.Test 1.1
    Since: QDoc.Test 0.9
    + +

    Properties

    + + +

    Methods

    + + + +

    Detailed Description

    + +

    Introduction

    +

    A documentation test case, itself documented inline in DocTest.qml.

    + +

    Property Documentation

    + +
    +
    + + +

    +active : bool

    +

    Whether the test is active.

    +

    See also name.

    +
    +
    + +
    +
    + + +

    +name : string

    +

    Name of the test.

    +
    DocTest {
    +    name: "test"
    +    // ...
    +}
    +
    +
    +

    Method Documentation

    + +
    +
    + + +

    +fail(message = "oops")

    +

    Fails the current test case, with the optional message.

    +

    This method was introduced in QDoc.Test 1.0.

    +
    +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type-members.html new file mode 100644 index 0000000000..91cfa86438 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type-members.html @@ -0,0 +1,31 @@ + + + + + + List of All Members for Type | Test + + + +

    List of All Members for Type

    +

    This is the complete list of members for Type, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type.html new file mode 100644 index 0000000000..166cbee815 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/qml-qdoc-test-type.html @@ -0,0 +1,185 @@ + + + + + + Type QML Type | Test + + + +

    Type QML Type

    + + +

    A QML type documented in a .cpp file. More...

    + +
    +
    Import Statement: import QDoc.Test 1.1
    Instantiates: Test
    + +

    Properties

    + + +

    Attached Properties

    +
      +
    • type : enumeration
    • +
    + +

    Signals

    + + +

    Attached Signals

    + + +

    Methods

    + + + +

    Detailed Description

    + +

    Property Documentation

    + +
    +
    +
    + + + + +

    +fifth : int

    +fourth : int

    +

    A group of properties sharing a documentation comment.

    +
    +
    + +
    +
    + + + + + + + +

    group group

    +group.first : int

    +group.second : int

    +group.third : int

    +

    A property group.

    +
    +
    + +
    +
    + + +

    +[read-only] id : int

    +

    A read-only property.

    +
    +
    + +
    +
    + + +

    +name : string

    +

    Name of the Test.

    +
    +
    +

    Attached Property Documentation

    + +
    +
    + + +

    +Type.type : enumeration

    +
    + + +
    ConstantDescription
    Type.NoTypeNothing
    Type.SomeTypeSomething
    +
    +
    +

    Signal Documentation

    + +
    +
    + + +

    +completed(status)

    +

    This signal is emitted when the operation completed with status.

    +
    +
    +

    Attached Signal Documentation

    + +
    +
    + + +

    +configured()

    +

    This attached signal is emitted when the type was configured.

    +
    +
    +

    Method Documentation

    + +
    +
    +
    + + + + +

    +disable()

    +enable()

    +

    Enables or disables this type.

    +
    +
    + +
    +
    + + +

    +Type copy(a)

    +

    Returns another Type based on a.

    +
    +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/test.index b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/test.index new file mode 100644 index 0000000000..f45b331142 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/test.index @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testcpp-module.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testcpp-module.html new file mode 100644 index 0000000000..b1301b5d04 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testcpp-module.html @@ -0,0 +1,42 @@ + + + + + + QDoc Test C++ Classes | Test + + + +

    QDoc Test C++ Classes

    + + +

    A test module page. More...

    + + +

    Namespaces

    +
    + +

    TestQDoc

    A namespace

    + +

    Classes

    +
    + + +

    TestQDoc::Test

    A class in a namespace

    TestQDoc::TestDerived

    A derived class in a namespace

    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-members.html new file mode 100644 index 0000000000..6f3ca0ff5f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-members.html @@ -0,0 +1,22 @@ + + + + + + List of All Members for Test | Test + + +
  • Test
  • + +

    List of All Members for Test

    +

    This is the complete list of members for TestQDoc::Test, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-obsolete.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-obsolete.html new file mode 100644 index 0000000000..088c2ee99f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test-obsolete.html @@ -0,0 +1,36 @@ + + + + + + Obsolete Members for Test | Test + + +
  • Test
  • + +

    Obsolete Members for Test

    +

    The following members of class Test are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code.

    +

    Public Functions

    +
    + + + +
    (obsolete) void anotherObsoleteMember()
    (obsolete) void deprecatedMember()
    (obsolete) void obsoleteMember()
    +

    Member Function Documentation

    + +

    void Test::anotherObsoleteMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use obsoleteMember() instead.

    + + +

    void Test::deprecatedMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use someFunction() instead.

    + + +

    void Test::obsoleteMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use someFunction() instead.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test.html new file mode 100644 index 0000000000..53db066852 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-test.html @@ -0,0 +1,91 @@ + + + + + + Test Class | Test + + +
  • Test
  • + +

    Test Class

    +(TestQDoc::Test)
    + +

    A class in a namespace. More...

    + +
    +
    Header: #include <Test> +
    qmake: QT += testcpp
    Instantiated By: Type
    Inherited By:

    TestQDoc::TestDerived

    +
    + +

    Public Functions

    +
    + + + + +
    void inlineFunction()
    int someFunction(int v)
    void someFunctionDefaultArg(int i, bool b = false)
    virtual void virtualFun()
    + +

    Protected Functions

    +
    + + +
    void overload()
    void overload(bool b)
    + +

    Macros

    + + + +
    +

    Detailed Description

    +
    + +
    +

    Member Function Documentation

    + +
    +

    [protected] void Test::overload()

    [protected] void Test::overload(bool b)

    +

    Overloads that share a documentation comment, optionally taking a parameter b.

    + + +

    void Test::inlineFunction()

    +

    An inline function, documented using the \fn QDoc command.

    + + +

    int Test::someFunction(int v)

    +

    Function that takes a parameter v. Also returns the value of v.

    + + +

    void Test::someFunctionDefaultArg(int i, bool b = false)

    +

    Function that takes a parameter i and b.

    + + +

    [virtual] void Test::virtualFun()

    +

    Function that must be reimplemented.

    + +
    +
    +

    Macro Documentation

    + +

    QDOCTEST_MACRO2(x)

    +

    A macro with argument x.

    +

    This function was introduced in Test 1.1.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived-members.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived-members.html new file mode 100644 index 0000000000..0babbbd5fd --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived-members.html @@ -0,0 +1,22 @@ + + + + + + List of All Members for TestDerived | Test + + +
  • TestDerived
  • + +

    List of All Members for TestDerived

    +

    This is the complete list of members for TestQDoc::TestDerived, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived.html new file mode 100644 index 0000000000..8f7517cd38 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc-testderived.html @@ -0,0 +1,48 @@ + + + + + + TestDerived Class | Test + + +
  • TestDerived
  • + +

    TestDerived Class

    +(TestQDoc::TestDerived)
    + +

    A derived class in a namespace. More...

    + +
    +
    Header: #include <TestDerived> +
    qmake: QT += testcpp
    Inherits: TestQDoc::Test
    + +

    Reimplemented Public Functions

    +
    + +
    virtual void virtualFun() override
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Function Documentation

    + +

    [override virtual] void TestDerived::virtualFun()

    +

    Reimplements: Test::virtualFun().

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc.html b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc.html new file mode 100644 index 0000000000..9c6f5b6aed --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/includefromexampledirs/testqdoc.html @@ -0,0 +1,64 @@ + + + + + + TestQDoc Namespace | Test + + + +

    TestQDoc Namespace

    + +

    A namespace. More...

    + +
    +
    Header: #include <TestCPP> +
    qmake: QT += testcpp
      +
    + +

    Classes

    +
    + + +
    class Test
    class TestDerived
    + +

    Macros

    + + + +
    +

    Detailed Description

    + +

    Usage

    +

    This namespace is for testing QDoc output.

    +
    + +
    +

    Classes

    +

    class Test

    +

    A class in a namespace. More...

    + +

    class TestDerived

    +

    A derived class in a namespace. More...

    + +
    +
    +

    Macro Documentation

    + +

    QDOCTEST_MACRO

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/index-linking.html b/tests/auto/qdoc/generatedoutput/expected_output/index-linking.html new file mode 100644 index 0000000000..6f7ffe810f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/index-linking.html @@ -0,0 +1,29 @@ + + + + + + Linking | IndexLinking + + + +

    Linking

    + + +
    + +

    QML properties

    +
    1. Property group: Parent::group.
    2. +
    3. Property in a group: QDoc.Test::Parent::group.c.
    4. +
    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/index.html b/tests/auto/qdoc/generatedoutput/expected_output/index.html new file mode 100644 index 0000000000..435f3d5571 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/index.html @@ -0,0 +1,22 @@ + + + + + + doc index | TestModule + + +

    doc index

    + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/nestedmacro/testcpp-module.html b/tests/auto/qdoc/generatedoutput/expected_output/nestedmacro/testcpp-module.html new file mode 100644 index 0000000000..3c49781e46 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/nestedmacro/testcpp-module.html @@ -0,0 +1,44 @@ + + + + + + QDoc Test C++ Classes | TestCPP + + + +

    QDoc Test C++ Classes

    + + +

    A test module page. More...

    + + +

    Namespaces

    +
    + +

    TestQDoc

    A namespace

    + +

    Classes

    +
    + + +

    TestQDoc::Test

    A class in a namespace

    TestQDoc::TestDerived

    A derived class in a namespace

    + + +
    +

    Detailed Description

    +

    Note: This is just a test.

    +

    This module was introduced in version 5.15.

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/qdoc-test-qmlmodule.xml b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/qdoc-test-qmlmodule.xml new file mode 100644 index 0000000000..8934e47297 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/qdoc-test-qmlmodule.xml @@ -0,0 +1,16 @@ + + + + +Test +A test project for QDoc build artifacts + +QML Types for the Test module. +This module is under development and is subject to change. +This module was introduced in Qt 1.1. + + +This module is under development and is subject to change. +This module was introduced in Qt 1.1. + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/test-componentset-example.xml b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/test-componentset-example.xml new file mode 100644 index 0000000000..062d7cdf01 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/test-componentset-example.xml @@ -0,0 +1,37 @@ + + + +QML Documentation Example +Test +A test project for QDoc build artifacts + +Example for documenting QML types. + + +This example demonstrates one of the ways to document QML types. It also generates a warning about a missing example image, on purpose. +In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the UI Components module. +The uicomponents.qdoc file generates the overview page for the UI Components module page. +The generated documentation is available in the UI Components module. + +QML Class +The QML types use the \qmltype to document the type. In addition, they have the \inmodule command in order for QDoc to associate them to the UIComponents module. +QDoc uses the \brief command to place a basic description when listing the types. + + +Properties, Signals, Handlers, and Methods +The types have their properties, signals, handlers, and methods defined in their respective QML files. QDoc associates the properties and methods to the types, therefore, you only need to place the documentation above the property, method, or signal. +To document the type of a property alias, you must use the \qmlproperty command to specify the data type. +\qmlproperty <@type>int</@type> anAliasedProperty +An aliased property of type <@type>int</@type><@op>.</@op> + + +Internal Documentation +You may declare that a documentation is for internal use by placing the \internal command after the beginning QDoc comment /*. QDoc will prevent the internal documentation from appearing in the public API. +If you wish to omit certain parts of the documentation, you may use the \omit and \endomit command. + + + +QML Types with C++ Implementation +This example only demonstrates the documentation for types in QML files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type. + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/testcpp-module.xml b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/testcpp-module.xml new file mode 100644 index 0000000000..33ceec53ca --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist-docbook/testcpp-module.xml @@ -0,0 +1,18 @@ + + + +QDoc Test C++ Classes +Test +A test project for QDoc build artifacts + +A test module page. + + +A test module page. + +Detailed Description + +This is just a test. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist/qdoc-test-qmlmodule.html b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/qdoc-test-qmlmodule.html new file mode 100644 index 0000000000..9a1d8b329b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/qdoc-test-qmlmodule.html @@ -0,0 +1,18 @@ + + + + + + Test + + + + +

    This module is under development and is subject to change.

    +

    This module was introduced in Qt 1.1.

    + +
    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist/test-componentset-example.html b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/test-componentset-example.html new file mode 100644 index 0000000000..385f284fcb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/test-componentset-example.html @@ -0,0 +1,51 @@ + + + + + + QML Documentation Example | Test + + + +

    QML Documentation Example

    + + +

    Example for documenting QML types.

    + + +
    +

    This example demonstrates one of the ways to document QML types. It also generates a warning about a missing example image, on purpose.

    +

    In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the UI Components module.

    +

    The uicomponents.qdoc file generates the overview page for the UI Components module page.

    +

    The generated documentation is available in the UI Components module.

    + +

    QML Class

    +

    The QML types use the \qmltype to document the type. In addition, they have the \inmodule command in order for QDoc to associate them to the UIComponents module.

    +

    QDoc uses the \brief command to place a basic description when listing the types.

    + +

    Properties, Signals, Handlers, and Methods

    +

    The types have their properties, signals, handlers, and methods defined in their respective QML files. QDoc associates the properties and methods to the types, therefore, you only need to place the documentation above the property, method, or signal.

    +

    To document the type of a property alias, you must use the \qmlproperty command to specify the data type.

    +
    \qmlproperty int anAliasedProperty
    +An aliased property of type int.
    + +
    Internal Documentation
    +

    You may declare that a documentation is for internal use by placing the \internal command after the beginning QDoc comment /*. QDoc will prevent the internal documentation from appearing in the public API.

    +

    If you wish to omit certain parts of the documentation, you may use the \omit and \endomit command.

    + +

    QML Types with C++ Implementation

    +

    This example only demonstrates the documentation for types in QML files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type.

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/noautolist/testcpp-module.html b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/testcpp-module.html new file mode 100644 index 0000000000..f273e6f712 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/noautolist/testcpp-module.html @@ -0,0 +1,30 @@ + + + + + + QDoc Test C++ Classes | Test + + + +

    QDoc Test C++ Classes

    + + +

    A test module page. More...

    + + + +
    +

    Detailed Description

    +

    Note: This is just a test.

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/obsolete-classes.html b/tests/auto/qdoc/generatedoutput/expected_output/obsolete-classes.html new file mode 100644 index 0000000000..e8e4c4e3a8 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/obsolete-classes.html @@ -0,0 +1,35 @@ + + + + + + Obsolete Classes | TestCPP + + + +

    Obsolete Classes

    + + +
    + +

    Classes with obsolete members

    + + +

    TestQDoc

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml b/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml new file mode 100644 index 0000000000..fde032de04 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties-docbook/testqdoc-testderived.xml @@ -0,0 +1,266 @@ + + + +TestDerived Class +TestQDoc::TestDerived +TestCPP +TestCPP Reference Documentation + +A derived class in a namespace. + + + + +Header + +TestDerived + + + +CMake + +find_package(Qt6 COMPONENTS QDocTest REQUIRED) +target_link_libraries(mytarget PRIVATE Qt6::QDocTest) + + + +qmake + +QT += testcpp + + + +Inherits + +TestQDoc::Test + + + + +Detailed Description + + +Member Type Documentation + +[alias] TestDerived::DerivedType + +DerivedTypepublic +active +unspecified +TestCPP + +An aliased typedef. + + +[alias] TestDerived::NotTypedef + +NotTypedefpublic +active +unspecified +TestCPP + +I'm an alias, not a typedef. + + + +Property Documentation + +[bindable] bindableProp : QString + +(Qt property) +QString +bindableProp +public +active +unspecified +TestCPP +bindableProp +setBindableProp +bindablePropChanged + +This property supports QProperty bindings. +Some property. + + +boolProp : bool + +(Qt property) +bool +boolProp +public +active +unspecified +TestCPP +boolProp +setBoolProp +resetBoolProp +boolPropChanged + +A boolean property. + +Access functions: + + + + +bool boolProp() + + +void setBoolProp(bool b) + + +void resetBoolProp() + + + +Notifier signal: + + + + +void boolPropChanged() + + + + +[read-only] intProp : int* const + +(Qt property) +int* +intProp +public +active +unspecified +TestCPP +getInt + +An integer property. + +Access functions: + + + + +int *getInt() + + + + +[read-only] name : const QString* + +(Qt property) +const QString* +name +public +active +unspecified +TestCPP +name + +This property holds a name. + +Access functions: + + + + +const QString *name() const + + + + +[bindable read-only] someProp : QString + +(Qt property) +QString +someProp +public +active +unspecified +TestCPP +someProp + +This property supports QProperty bindings. +Another property. + + + +Member Function Documentation + +[private signal] TestDerived::void emitSomething() + + +emitSomething + +signal +void emitSomething() +public +active +unspecified +TestCPP + +Emitted when things happen. + +This is a private signal. It can be used in signal connections but cannot be emitted by the user. + + +[invokable] TestDerived::void invokeMe() const + +const + +invokeMe + +plain +void invokeMe() const +public +active +unspecified +TestCPP + +Something invokable. + +This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE. + + + +[override virtual] TestDerived::void virtualFun() + +virtual + +virtualFun +override + +plain +void virtualFun() override +public +active +unspecified +TestCPP + +Reimplements: Test::virtualFun(). + + +Obsolete Members for TestDerived +The following members of class TestDerived are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code. + +Member Function Documentation + +[static] TestDerived::void staticObsoleteMember() + +static + +staticObsoleteMember + +plain +void staticObsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Static obsolete method. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index b/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index new file mode 100644 index 0000000000..9f2bfacde1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/testcpp.index @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived-members.html b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived-members.html new file mode 100644 index 0000000000..44ac132beb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived-members.html @@ -0,0 +1,43 @@ + + + + + + List of All Members for TestDerived | TestCPP + + +
  • TestDerived
  • + +

    List of All Members for TestDerived

    +

    This is the complete list of members for TestQDoc::TestDerived, including inherited members.

    +
    + +
    +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html new file mode 100644 index 0000000000..a0704e9d82 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/properties/testqdoc-testderived.html @@ -0,0 +1,162 @@ + + + + + + TestDerived Class | TestCPP + + +
  • TestDerived
  • + +

    TestDerived Class

    +class TestQDoc::TestDerived + +

    A derived class in a namespace. More...

    + +
    +
    Header: #include <TestDerived> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherits: TestQDoc::Test
    + +

    Public Types

    + + +

    Properties

    +
    + +
    +
    + +

    Public Functions

    +
    + + + + + + +
    QBindable<QString> bindableProp()
    bool boolProp()
    int *getInt()
    void invokeMe() const
    const QString *name() const
    const QString &someProp()
    + +

    Reimplemented Public Functions

    +
    + +
    virtual void virtualFun() override
    + +

    Public Slots

    +
    + + + +
    void resetBoolProp()
    void setBindableProp(const QString &s)
    void setBoolProp(bool b)
    + +

    Signals

    +
    + + + +
    void bindablePropChanged()
    void boolPropChanged()
    void emitSomething()
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    [alias] TestDerived::DerivedType

    +

    An aliased typedef.

    + + +

    [alias] TestDerived::NotTypedef

    +

    I'm an alias, not a typedef.

    + +
    +
    +

    Property Documentation

    + +

    [bindable] bindableProp : QString

    +

    Note: This property supports QProperty bindings.

    +

    Some property.

    + + +

    boolProp : bool

    +

    A boolean property.

    +

    Access functions:

    +
    + + + +
    bool boolProp()
    void setBoolProp(bool b)
    void resetBoolProp()
    +

    Notifier signal:

    +
    + +
    void boolPropChanged()
    + + +

    [read-only] intProp : int* const

    +

    An integer property.

    +

    Access functions:

    +
    + +
    int *getInt()
    + + +

    [read-only] name : const QString*

    +

    This property holds a name.

    +

    Access functions:

    +
    + +
    const QString *name() const
    + + +

    [bindable read-only] someProp : QString

    +

    Note: This property supports QProperty bindings.

    +

    Another property.

    + +
    +
    +

    Member Function Documentation

    + +

    [private signal] void TestDerived::emitSomething()

    +

    Emitted when things happen.

    +

    Note: This is a private signal. It can be used in signal connections but cannot be emitted by the user.

    + + +

    [invokable] void TestDerived::invokeMe() const

    +

    Something invokable.

    +

    Note: This function can be invoked via the meta-object system and from QML. See Q_INVOKABLE.

    + + +

    [override virtual] void TestDerived::virtualFun()

    +

    Reimplements: Test::virtualFun().

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qdoc-test-qmlmodule.html b/tests/auto/qdoc/generatedoutput/expected_output/qdoc-test-qmlmodule.html new file mode 100644 index 0000000000..16df6ff0d9 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qdoc-test-qmlmodule.html @@ -0,0 +1,26 @@ + + + + + + Test + + + + +

    This module is under development and is subject to change.

    +

    This module was introduced in Qt 1.1.

    + +
    +
    + +
    + + + + + + +

    AbstractParent

    Abstract base QML type

    Child

    A Child inheriting its parent

    DocTest

    Represents a doc test case

    Type

    A QML type documented in a .cpp file

    YetAnotherChild

    A type inheriting from internal abstract parent

    int

    An integer basic type

    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-exhaustive.html b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-exhaustive.html new file mode 100644 index 0000000000..8dcfe94524 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-exhaustive.html @@ -0,0 +1,60 @@ + + + + + + Exhaustive testing of QDoc commands | OutputFromQDocFiles + + +
  • OutputFromQDocFiles - A test project for QDoc build artifacts
  • + +

    Exhaustive testing of QDoc commands

    + + +
    + +

    This is a section1

    + +

    This is a section2

    + +

    This is a section3

    + +
    This is a section4
    +
    This is bad code
    +

    This text should have a line break riiiiight
    + noooow.

    +

    All your text belong to bold ...And this is an examble of only bold being, well, bold.

    +
        ...
    +
    // If I knew JavaScript, this is where I would write it.
    +

    And if I knew qmltext, I guess this is where that would go.

    +

    This a caption

    +

    Lorem legal ipsum

    +

    This is a quotation.

    +
    + This is raw. Like the

    Eddie Murphy

    movie. Just not as funny. +

    Look, ma! I made a sidebar!

    +
    + + +
    Table item in a table row
    Another item in a different row
    +

    Important: This is really important.

    For example, if you have code like

    +
    This is old code.
    +

    you can rewrite it as

    +
    This is new and shiny!
    +

    Note: The code above doesn't compile

    +
    +

    Warning: The following commands have yet to be tested: footnote link sincelist header index topicref // or just don’t care, remove it image inlineimage printline printto printuntil // what’s the difference between printto and printuntil??? quotefile quotefromfile quotefunction skipline skipto skipuntil span snippet codeline overload sub sup tableofcontents tt uicontrol endmapref endomit underline unicode

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-linking.html b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-linking.html new file mode 100644 index 0000000000..4da717b701 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput-linking.html @@ -0,0 +1,38 @@ + + + + + + Testing QDoc's link command | OutputFromQDocFiles + + +
  • OutputFromQDocFiles - A test project for QDoc build artifacts
  • + + +

    +

    +

    Testing QDoc's link command

    + + +
    + + +

    Valid parameters for the link command (\l) are page and section titles, targets defined with \target or \keyword commands, and API reference keywords (types, methods, namespaces, and so on).

    +
    + + + + diff --git a/tests/auto/qdoc/qdocfileoutput/expected_output/qdoctests-qdocfileoutput.html b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput.html similarity index 63% rename from tests/auto/qdoc/qdocfileoutput/expected_output/qdoctests-qdocfileoutput.html rename to tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput.html index 199d63ef15..273b0110ef 100644 --- a/tests/auto/qdoc/qdocfileoutput/expected_output/qdoctests-qdocfileoutput.html +++ b/tests/auto/qdoc/generatedoutput/expected_output/qdoctests-qdocfileoutput.html @@ -1,18 +1,23 @@ - - + - Testing QDoc output from .qdoc files | Test + Testing QDoc output from .qdoc files | OutputFromQDocFiles +
  • OutputFromQDocFiles - A test project for QDoc build artifacts
  • + +

    @@ -38,7 +43,19 @@

    Further information

  • \li
  • \endlist
+ +

Linking

+

There are multiple ways to create hyperlinks to other topics:

+
+ diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-int.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-int.html new file mode 100644 index 0000000000..16603af4bd --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-int.html @@ -0,0 +1,41 @@ + + + + + + int QML Basic Type | Test + + + +

int QML Basic Type

+ + +

Methods

+ + +
+
+ +

Method Documentation

+ +
+
+ + +

+int abs()

+

Returns the absolute value of this integer.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-linkmodule-grandchild-members.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-linkmodule-grandchild-members.html new file mode 100644 index 0000000000..e0f8fdcae3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-linkmodule-grandchild-members.html @@ -0,0 +1,24 @@ + + + + + + List of All Members for GrandChild | IndexLinking + + + +

List of All Members for GrandChild

+

This is the complete list of members for GrandChild, including inherited members.

+

The following members are inherited from AnotherChild.

+ +

The following members are inherited from Parent.

+ + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-abstractparent.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-abstractparent.html new file mode 100644 index 0000000000..418798f82d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-abstractparent.html @@ -0,0 +1,99 @@ + + + + + + AbstractParent QML Type | Test + + + +

AbstractParent QML Type

+ + +

Abstract base QML type. More...

+ +
+
Import Statement: import QDoc.Test 1.1
Inherited By:

Child

+
+ +

Properties

+ + +

Methods

+
    +
  • void name()
  • +
  • void name(Child child, name)
  • +
  • void rear(Child child, var method)
  • +
+ + +

Detailed Description

+ +

Property Documentation

+ +
+
+ + +

+[default] children : list<Child>

+

Children of the type.

+
+
+ +
+
+ + +

+name : string

+

Name of this parent.

+
+
+

Method Documentation

+ +
+
+ + +

+void name()

+

Name all children with random names.

+
+
+ +
+
+ + +

+void name(Child child, name)

+

Name a child using name.

+
+
+ +
+
+ + +

+void rear(Child child, var method = Strict)

+

Do some abstract parenting on child using a specific method.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-child.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-child.html new file mode 100644 index 0000000000..f1668b4285 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-child.html @@ -0,0 +1,99 @@ + + + + + + Child QML Type | Test + + + +

Child QML Type

+ + +

A Child inheriting its parent. More...

+ +
+
Import Statement: import QDoc.Test 1.1
Inherits:

AbstractParent

+
+ +

Properties

+ + +

Methods

+
    +
  • void name()
  • +
  • void name(Child child, name)
  • +
  • void rear(Child child, var method)
  • +
+ + +

Detailed Description

+ +

Property Documentation

+ +
+
+ + +

+[default] children : list<Child>

+

Children of the type.

+
+
+ +
+
+ + +

+name : string

+

Name of this child.

+
+
+

Method Documentation

+ +
+
+ + +

+void name()

+

Name all children with random names.

+
+
+ +
+
+ + +

+void name(Child child, name)

+

Name a child of this child using name.

+
+
+ +
+
+ + +

+void rear(Child child, var method = Strict)

+

Do some abstract parenting on child using a specific method.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-doctest.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-doctest.html new file mode 100644 index 0000000000..637605f0d3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-doctest.html @@ -0,0 +1,130 @@ + + + + + + DocTest QML Type | Test + + + +

DocTest QML Type

+ + +

Represents a doc test case. More...

+ +
+
Import Statement: import QDoc.Test 1.1
Since: QDoc.Test 0.9
+ +

Properties

+ + +

Signals

+ + +

Methods

+ + + +

Detailed Description

+ +

Introduction

+

A documentation test case, itself documented inline in DocTest.qml.

+ +

Property Documentation

+ +
+
+ + +

+active : bool

+

Whether the test is active.

+

See also name.

+
+
+ +
+
+ + +

+[required] name : string

+

Name of the test.

+
DocTest {
+    name: "test"
+    // ...
+}
+
+
+

Signal Documentation

+ +
+
+ + +

+completed()

+

Note: The corresponding handler is onCompleted.

+
+
+ +
+
+ + +

+foo(var bar)

+

Signal with parameter bar.

+

Note: The corresponding handler is onFoo.

+
+
+

Method Documentation

+ +
+
+ + +

+[since QDoc.Test 1.0] fail(message = "oops")

+

Fails the current test case, with the optional message.

+

This method was introduced in QDoc.Test 1.0.

+
+
+ +
+
+ + +

+fail_hard(msg = "facepalm", option = 123)

+

Fails the current test case, hard.

+
    +
  • Prints out msg.
  • +
  • Accepts a random option.
  • +
+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type-members.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type-members.html new file mode 100644 index 0000000000..368bd367d7 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type-members.html @@ -0,0 +1,32 @@ + + + + + + List of All Members for Type | Test + + + +

List of All Members for Type

+

This is the complete list of members for Type, including inherited members.

+ + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type.html new file mode 100644 index 0000000000..8d603703ff --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-type.html @@ -0,0 +1,199 @@ + + + + + + Type QML Type | Test + + + +

Type QML Type

+ + +

A QML type documented in a .cpp file. More...

+ +
+
Import Statement: import QDoc.Test 1.1
Instantiates: Test
+ +

Properties

+ + +

Attached Properties

+
    +
  • type : enumeration
  • +
+ +

Signals

+ + +

Attached Signals

+ + +

Methods

+ + + +

Detailed Description

+ +

Property Documentation

+ +
+
+
+ + + + +

+fifth : int

+fourth : int

+

A group of properties sharing a documentation comment.

+
+
+ +
+
+ + + + + + + +

group group

+group.first : int

+group.second : int

+group.third : int

+

A property group.

+
+
+ +
+
+ + +

+[read-only] id : int

+

A read-only property.

+
+
+ +
+
+ + +

+[required] name : string

+

Name of the Test.

+
+
+

Attached Property Documentation

+ +
+
+ + +

+Type.type : enumeration

+
+ + +
ConstantDescription
Type.NoTypeNothing
Type.SomeTypeSomething
+
+
+

Signal Documentation

+ +
+
+ + +

+completed(int status)

+

This signal is emitted when the operation completed with status.

+

Note: The corresponding handler is onCompleted.

+
+
+ +
+
+ + +

+group.created()

+

This signal is prefixed with group.

+

Note: The corresponding handler is group.onCreated.

+
+
+

Attached Signal Documentation

+ +
+
+ + +

+configured()

+

This attached signal is emitted when the type was configured.

+

Note: The corresponding handler is onConfigured.

+
+
+

Method Documentation

+ +
+
+
+ + + + +

+disable()

+enable()

+

Enables or disables this type.

+
+
+ +
+
+ + +

+Type copy(a)

+

Returns another Type based on a.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-yetanotherchild.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-yetanotherchild.html new file mode 100644 index 0000000000..a79c759af0 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-qdoc-test-yetanotherchild.html @@ -0,0 +1,48 @@ + + + + + + YetAnotherChild QML Type | Test + + + +

YetAnotherChild QML Type

+ + +

A type inheriting from internal abstract parent. More...

+ +
+
Import Statement: import QDoc.Test 1.1
+ +

Properties

+ + + +

Detailed Description

+ +

Property Documentation

+ +
+
+ + +

+prop : int

+

Propagated to inheriting type docs.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-progressbar.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-progressbar.html new file mode 100644 index 0000000000..a1b43ea9d1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-progressbar.html @@ -0,0 +1,97 @@ + + + + + + ProgressBar QML Type | Test + + + +

ProgressBar QML Type

+ + +

A component that shows the progress of an event. More...

+ +
+
Import Statement: import UIComponents 1.0
+ +

Properties

+ + + +

Detailed Description

+

A ProgressBar shows the linear progress of an event as its value. The range is specified using the minimum and the maximum values.

+

The ProgressBar component is part of the UI Components module.

+

This documentation is part of the UIComponents example.

+ +

Property Documentation

+ +
+
+ + +

+color : color

+

The color of the ProgressBar's gradient. Must bind to a color type.

+

See also secondColor.

+
+
+ +
+
+ + +

+maximum : int

+

The maximum value of the ProgressBar range. The value must not be more than this value.

+
+
+ +
+
+ + +

+minimum : int

+

The minimum value of the ProgressBar range. The value must not be less than this value.

+
+
+ +
+
+ + +

+secondColor : color

+

The second color of the ProgressBar's gradient. Must bind to a color type.

+

See also color.

+
+
+ +
+
+ + +

+value : int

+

The value of the progress.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-switch.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-switch.html new file mode 100644 index 0000000000..fadb1a5319 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-switch.html @@ -0,0 +1,68 @@ + + + + + + Switch QML Type | Test + + + +

Switch QML Type

+ + +

A component that can be turned on or off. More...

+ +
+
Import Statement: import UIComponents 1.0
+ +

Properties

+
    +
  • on : bool
  • +
+ +

Methods

+ + + +

Detailed Description

+

A toggle switch has two states: an on and an off state. The off state is when the on property is set to false.

+

The ToggleSwitch component is part of the UI Components module.

+

This documentation is part of the UIComponents example.

+ +

Property Documentation

+ +
+
+ + +

+on : bool

+

Indicates the state of the switch. If false, then the switch is in the off state.

+
+
+

Method Documentation

+ +
+
+ + +

+toggle()

+

A method to toggle the switch. If the switch is on, the toggling it will turn it off. Toggling a switch in the off position will turn it on.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-tabwidget.html b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-tabwidget.html new file mode 100644 index 0000000000..4122bd5533 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qml-uicomponents-tabwidget.html @@ -0,0 +1,84 @@ + + + + + + TabWidget QML Type | Test + + + +

TabWidget QML Type

+ + +

A widget that places its children as tabs. More...

+ +
+
Import Statement: import UIComponents 1.0
+ +

Properties

+ + + +

Detailed Description

+

A TabWidget places its children as tabs in a view. Selecting a tab involves selecting the tab at the top.

+

The TabWidget component is part of the UI Components module.

+

This documentation is part of the UIComponents example.

+ +

Adding Tabs

+

To add a tab, declare the tab as a child of the TabWidget.

+
TabWidget {
+    id: tabwidget
+
+    Rectangle {
+        id: tab1
+        color: "red"
+        //... omitted
+    }
+    Rectangle {
+        id: tab2
+        color: "blue"
+        //... omitted
+    }
+
+}
+ +

Property Documentation

+ +
+
+ + +

+current : int

+

The currently active tab in the TabWidget.

+
+
+ +
+
+ + +

+[read-only] sampleReadOnlyProperty : int

+

A sample read-only property. A contrived property to demonstrate QDoc's ability to detect read-only properties.

+

The signature is:

+
readonly property int sampleReadOnlyProperty: 0
+

Note that the property must be initialized to a value.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qmlmodules.html b/tests/auto/qdoc/generatedoutput/expected_output/qmlmodules.html new file mode 100644 index 0000000000..befdc8924d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qmlmodules.html @@ -0,0 +1,22 @@ + + + + + + QML Modules | Test + + + +

QML Modules

+ + +
+
+ + + +

No QML Types Here

A QML module with no member types.

QDoc.Test

QML Types for the Test module.

UI Components

Basic set of UI components.

+
+ + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups-docbook/qml-qdoc-test-parent.xml b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups-docbook/qml-qdoc-test-parent.xml new file mode 100644 index 0000000000..fd07da33a3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups-docbook/qml-qdoc-test-parent.xml @@ -0,0 +1,66 @@ + + + +Parent QML Type +QmlPropertyGroups +A test project for QDoc build artifacts + +Base QML type. + + + + +Import Statement + +import QDoc.Test 1.1 + + + +Inherited By: + +AnotherChild + + + + +Detailed Description + + +Property Documentation + +group group +group.a : int + +int +group.a +writable +public +active +unspecified +QmlPropertyGroups + +[read-only] group.b : int + +int +group.b +[read-only] + +public +active +unspecified +QmlPropertyGroups + +[since 2.0] group.c : int + +int +group.c +writable +public +active +unspecified +QmlPropertyGroups + +Property group. + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-anotherchild-members.html b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-anotherchild-members.html new file mode 100644 index 0000000000..2919a79882 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-anotherchild-members.html @@ -0,0 +1,25 @@ + + + + + + List of All Members for AnotherChild | QmlPropertyGroups + + + +

List of All Members for AnotherChild

+

This is the complete list of members for AnotherChild, including inherited members.

+ +

The following members are inherited from Parent.

+ + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-parent.html b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-parent.html new file mode 100644 index 0000000000..86a53afc58 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/qmlpropertygroups/qml-qdoc-test-parent.html @@ -0,0 +1,61 @@ + + + + + + Parent QML Type | QmlPropertyGroups + + + +

Parent QML Type

+ + +

Base QML type. More...

+ +
+
Import Statement: import QDoc.Test 1.1
Inherited By:

AnotherChild

+
+ +

Properties

+ + + +

Detailed Description

+ +

Property Documentation

+ +
+
+ + + + + + + +

group group

+group.a : int

+[read-only] group.b : int

+[since 2.0] group.c : int

+

Property group.

+
+
+ + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/scoped-enum-linking.xml b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/scoped-enum-linking.xml new file mode 100644 index 0000000000..f5c4a05cd9 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/scoped-enum-linking.xml @@ -0,0 +1,12 @@ + + + +Enum Linking +TestCPP +TestCPP Reference Documentation + +TestCPP Reference Documentation. + +Linking to All. +TestQDoc::Test::ClassicEnum::Howdy does not link, but TestQDoc::Test::Howdy might. + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/testqdoc-test.xml b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/testqdoc-test.xml new file mode 100644 index 0000000000..f7cee45132 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum-docbook/testqdoc-test.xml @@ -0,0 +1,394 @@ + + + +Test Class +TestQDoc::Test +TestCPP +TestCPP Reference Documentation + +A class in a namespace. + + + + +Header + +Test + + + +CMake + +find_package(Qt6 COMPONENTS QDocTest REQUIRED) +target_link_libraries(mytarget PRIVATE Qt6::QDocTest) + + + +qmake + +QT += testcpp + + + +Inherited By + +TestQDoc::TestDerived + + + + +Detailed Description + + +Member Type Documentation + +Test::enum ClassicEnum + +ClassicEnum +public +active +unspecified +TestCPP + + + + + + + + +Constant +Description + + + + +TestQDoc::Test::Yee + +0 + + + +TestQDoc::Test::Haw + +1 + + + +TestQDoc::Test::Howdy + +2 + + + +TestQDoc::Test::Partner + +3 + + + + +Test::enum ScopedEnum + +ScopedEnum +public +active +unspecified +TestCPP + + + + + + + + +Constant +Value +Description + + + + +TestQDoc::Test::ScopedEnum::This + +0x01 + +Something + + + + +TestQDoc::Test::ScopedEnum::That + +0x02 + +Something else + + + + +TestQDoc::Test::ScopedEnum::All + +This | That + +Everything + + + + + +Test::SomeType + +SomeTypepublic +active +unspecified +TestCPP + +A typedef. + + + +Member Function Documentation + +[protected] Test::void overload() +[protected, since Test 1.2] Test::void overload(bool b) +Overloads that share a documentation comment, optionally taking a parameter b. + + +[default] Test::Test() + + +Test +default + +constructor +Test() = default +public +active +unspecified +TestCPP + +Default constructor. + + +[default] Test::TestQDoc::Test &operator=(TestQDoc::Test &&other) + +TestQDoc::Test & +operator= +default + +TestQDoc::Test && +other + +move-assign +TestQDoc::Test & operator=(TestQDoc::Test &&other) = default +public +active +unspecified +TestCPP + +Move-assigns other. + + +Test::void (*)(bool) funcPtr(bool b, const char *s) + +void (*)(bool) +funcPtr + +bool +b + + +const char * +s + +plain +void (*)(bool) funcPtr(bool b, const char *s) +public +active +unspecified +TestCPP + +Returns a pointer to a function that takes a boolean. Uses b and s. + + +Test::void inlineFunction() + + +inlineFunction + +plain +void inlineFunction() +public +active +unspecified +TestCPP + +An inline function, documented using the \fn QDoc command. + + +Test::int someFunction(int, int v = 0) + +int +someFunction + +int + + + +int +v +0 + +plain +int someFunction(int, int v) +public +active +unspecified +TestCPP + +Function that takes a parameter v. Also returns the value of v. + + +Test::void someFunctionDefaultArg(int i, bool b = false) + + +someFunctionDefaultArg + +int +i + + +bool +b +false + +plain +void someFunctionDefaultArg(int i, bool b) +public +active +unspecified +TestCPP + +Function that takes a parameter i and b. + + +[virtual] Test::void virtualFun() + +virtual + +virtualFun + +plain +void virtualFun() +public +active +unspecified +TestCPP + +Function that must be reimplemented. + + + +Related Non-Members + +bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs) + +bool +operator== + +const TestQDoc::Test & +lhs + + +const TestQDoc::Test & +rhs + +plain +bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs) +public +active +unspecified +TestCPP + +Returns true if lhs and rhs are equal. + + + +Macro Documentation + +[since Test 1.1] QDOCTEST_MACRO2(int &x) + +QDOCTEST_MACR + +int & +x + +macrowithparams +QDOCTEST_MACRO2(int &x) +public +active +unspecified +TestCPP + +A macro with argument x. +This function was introduced in Test 1.1. + + + +Obsolete Members for Test +The following members of class Test are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code. + +Member Function Documentation + +Test::void anotherObsoleteMember() + + +anotherObsoleteMember + +plain +void anotherObsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use obsoleteMember() instead. + + +Test::void deprecatedMember() + + +deprecatedMember + +plain +void deprecatedMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use someFunction() instead. + + +Test::void obsoleteMember() + + +obsoleteMember + +plain +void obsoleteMember() +public +obsolete +unspecified +TestCPP + +This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code. +Use someFunction() instead. + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/scoped-enum-linking.html b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/scoped-enum-linking.html new file mode 100644 index 0000000000..f07306f1e3 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/scoped-enum-linking.html @@ -0,0 +1,19 @@ + + + + + + Enum Linking | TestCPP + + + +

Enum Linking

+ + +
+

Linking to All.

+

TestQDoc::Test::ClassicEnum::Howdy does not link, but TestQDoc::Test::Howdy might.

+
+ + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html new file mode 100644 index 0000000000..69dd5eb158 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/scopedenum/testqdoc-test.html @@ -0,0 +1,152 @@ + + + + + + Test Class | TestCPP + + +
  • Test
  • + +

    Test Class

    +class TestQDoc::Test + +

    A class in a namespace. More...

    + +
    +
    Header: #include <Test> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherited By:

    TestQDoc::TestDerived

    +
    + +

    Public Types

    +
    + + + +
    enum ClassicEnum { Yee, Haw, Howdy, Partner }
    enum class ScopedEnum { This, That, All }
    SomeType
    + +

    Public Functions

    +
    + + + + + + + +
    Test()
    TestQDoc::Test &operator=(TestQDoc::Test &&other)
    void (*)(bool) funcPtr(bool b, const char *s)
    void inlineFunction()
    int someFunction(int, int v = 0)
    void someFunctionDefaultArg(int i, bool b = false)
    virtual void virtualFun()
    + +

    Protected Functions

    +
    + + +
    void overload()
    void overload(bool b)
    + + +
    + +
    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)
    + +

    Macros

    +
    + +
    QDOCTEST_MACRO2(int &x)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    enum Test::ClassicEnum

    +
    + + + + +
    ConstantValue
    TestQDoc::Test::Yee0
    TestQDoc::Test::Haw1
    TestQDoc::Test::Howdy2
    TestQDoc::Test::Partner3
    + + +

    enum class Test::ScopedEnum

    +
    + + + +
    ConstantValueDescription
    TestQDoc::Test::ScopedEnum::This0x01Something
    TestQDoc::Test::ScopedEnum::That0x02Something else
    TestQDoc::Test::ScopedEnum::AllThis | ThatEverything
    + + +

    Test::SomeType

    +

    A typedef.

    + +
    +
    +

    Member Function Documentation

    + +
    +

    [protected] void Test::overload()

    [protected, since Test 1.2] void Test::overload(bool b)

    +

    Overloads that share a documentation comment, optionally taking a parameter b.

    + + +

    [default] Test::Test()

    +

    Default constructor.

    + + +

    [default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&other)

    +

    Move-assigns other.

    + + +

    void (*)(bool) Test::funcPtr(bool b, const char *s)

    +

    Returns a pointer to a function that takes a boolean. Uses b and s.

    + + +

    void Test::inlineFunction()

    +

    An inline function, documented using the \fn QDoc command.

    + + +

    int Test::someFunction(int, int v = 0)

    +

    Function that takes a parameter v. Also returns the value of v.

    + + +

    void Test::someFunctionDefaultArg(int i, bool b = false)

    +

    Function that takes a parameter i and b.

    + + +

    [virtual] void Test::virtualFun()

    +

    Function that must be reimplemented.

    + +
    +
    +

    Related Non-Members

    + +

    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)

    +

    Returns true if lhs and rhs are equal.

    + +
    +
    +

    Macro Documentation

    + +

    [since Test 1.1] QDOCTEST_MACRO2(int &x)

    +

    A macro with argument x.

    +

    This function was introduced in Test 1.1.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/second.html b/tests/auto/qdoc/generatedoutput/expected_output/second.html new file mode 100644 index 0000000000..04a4862cd2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/second.html @@ -0,0 +1,31 @@ + + + + + + Second Class | TestModule + + +
  • Second
  • + +

    Second Class

    +
    +
    Header: #include <Second> +
      +
    + + +
    +

    Detailed Description

    +

    This is a second class

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/space.html b/tests/auto/qdoc/generatedoutput/expected_output/space.html new file mode 100644 index 0000000000..b40932b2fb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/space.html @@ -0,0 +1,45 @@ + + + + + + Space Namespace | UsingDirective + + + +

    Space Namespace

    + +

    A namespace...in space. More...

    + +
    +
    Header: #include <Space> +
      +
    + +

    Functions

    +
    + +
    void spaceFun(Space::spacename space)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Function Documentation

    + +

    void spaceFun(Space::spacename space)

    +

    A space function.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html b/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html new file mode 100644 index 0000000000..4b264a8761 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/bar.html @@ -0,0 +1,35 @@ + + + + + + Bar Class | TestCPP + + +
  • Bar
  • + +

    Bar Class

    +template <typename T, typename D> class Bar + +

    Another class template. More...

    + +
    +
    Header: #include <Bar> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html b/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html new file mode 100644 index 0000000000..21b40f4708 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/baz.html @@ -0,0 +1,35 @@ + + + + + + Baz Struct | TestCPP + + +
  • Baz
  • + +

    Baz Struct

    +template <template <typename> class X, typename Y> struct Baz + +

    Class template template. More...

    + +
    +
    Header: #include <Baz> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html b/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html new file mode 100644 index 0000000000..a449114937 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/foo.html @@ -0,0 +1,35 @@ + + + + + + Foo Class | TestCPP + + +
  • Foo
  • + +

    Foo Class

    +template <typename T> class Foo + +

    Class template. More...

    + +
    +
    Header: #include <Foo> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test-struct.html b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test-struct.html new file mode 100644 index 0000000000..1624e4fd2f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test-struct.html @@ -0,0 +1,32 @@ + + + + + + Struct Struct | TestCPP + + +
  • Struct
  • + +

    Struct Struct

    +template <typename D, typename T> struct TestQDoc::Test::Struct + +

    Templated struct. More...

    + +
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html new file mode 100644 index 0000000000..5bb920f78d --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-test.html @@ -0,0 +1,143 @@ + + + + + + Test Class | TestCPP + + +
  • Test
  • + +

    Test Class

    +class TestQDoc::Test + +

    A class in a namespace. More...

    + +
    +
    Header: #include <Test> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherited By:

    TestQDoc::TestDerived

    +
    + +

    Public Types

    +
    + + + +
    struct Struct
    SomeType
    Specialized
    + +

    Public Functions

    +
    + + + + + + + +
    Test()
    TestQDoc::Test &operator=(TestQDoc::Test &&other)
    void (*)(bool) funcPtr(bool b, const char *s)
    void inlineFunction()
    int someFunction(int, int v = 0)
    void someFunctionDefaultArg(int i, bool b = false)
    virtual void virtualFun()
    + +

    Protected Functions

    +
    + + + +
    void funcTemplate(T1 a, T2 b)
    void overload()
    void overload(bool b)
    + + +
    + +
    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)
    + +

    Macros

    +
    + +
    QDOCTEST_MACRO2(int &x)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    Test::SomeType

    +

    A typedef.

    + + +

    [alias] template<typename T> Test::Specialized

    + +
    +
    +

    Member Function Documentation

    + +
    +

    [protected] void Test::overload()

    [protected, since Test 1.2] void Test::overload(bool b)

    +

    Overloads that share a documentation comment, optionally taking a parameter b.

    + + +

    [default] Test::Test()

    +

    Default constructor.

    + + +

    [default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&other)

    +

    Move-assigns other.

    + + +

    void (*)(bool) Test::funcPtr(bool b, const char *s)

    +

    Returns a pointer to a function that takes a boolean. Uses b and s.

    + + +

    [protected] template <typename T1, typename T2> void Test::funcTemplate(T1 a, T2 b)

    +

    Function template with two parameters, a and b.

    + + +

    void Test::inlineFunction()

    +

    An inline function, documented using the \fn QDoc command.

    + + +

    int Test::someFunction(int, int v = 0)

    +

    Function that takes a parameter v. Also returns the value of v.

    + + +

    void Test::someFunctionDefaultArg(int i, bool b = false)

    +

    Function that takes a parameter i and b.

    + + +

    [virtual] void Test::virtualFun()

    +

    Function that must be reimplemented.

    + +
    +
    +

    Related Non-Members

    + +

    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)

    +

    Returns true if lhs and rhs are equal.

    + +
    +
    +

    Macro Documentation

    + +

    [since Test 1.1] QDOCTEST_MACRO2(int &x)

    +

    A macro with argument x.

    +

    This function was introduced in Test 1.1.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-vec.html b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-vec.html new file mode 100644 index 0000000000..f88ceb7fc6 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/template/testqdoc-vec.html @@ -0,0 +1,35 @@ + + + + + + Vec Class | TestCPP + + +
  • Vec
  • + +

    Vec Class

    +template <typename T> class TestQDoc::Vec + +

    Type alias that has its own reference. More...

    + +
    +
    Header: #include <Vec> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + + +
    +

    Detailed Description

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/test-cmaketest-example.html b/tests/auto/qdoc/generatedoutput/expected_output/test-cmaketest-example.html new file mode 100644 index 0000000000..3c3987041a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/test-cmaketest-example.html @@ -0,0 +1,22 @@ + + + + + + CMake Example Project | Test + + + +

    CMake Example Project

    + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/test-componentset-example.html b/tests/auto/qdoc/generatedoutput/expected_output/test-componentset-example.html new file mode 100644 index 0000000000..b3a2b37053 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/test-componentset-example.html @@ -0,0 +1,59 @@ + + + + + + QML Documentation Example | Test + + + +

    QML Documentation Example

    + + +

    Example for documenting QML types.

    + + +
    +

    This example demonstrates one of the ways to document QML types. It also generates a warning about a missing example image, on purpose.

    +

    In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the UI Components module.

    +

    The uicomponents.qdoc file generates the overview page for the UI Components module page.

    +

    The generated documentation is available in the UI Components module.

    + +

    QML Class

    +

    The QML types use the \qmltype to document the type. In addition, they have the \inmodule command in order for QDoc to associate them to the UIComponents module.

    +

    QDoc uses the \brief command to place a basic description when listing the types.

    + +

    Properties, Signals, Handlers, and Methods

    +

    The types have their properties, signals, handlers, and methods defined in their respective QML files. QDoc associates the properties and methods to the types, therefore, you only need to place the documentation above the property, method, or signal.

    +

    To document the type of a property alias, you must use the \qmlproperty command to specify the data type.

    +
    \qmlproperty int anAliasedProperty
    +An aliased property of type int.
    + +
    Internal Documentation
    +

    You may declare that a documentation is for internal use by placing the \internal command after the beginning QDoc comment /*. QDoc will prevent the internal documentation from appearing in the public API.

    +

    If you wish to omit certain parts of the documentation, you may use the \omit and \endomit command.

    + +

    QML Types with C++ Implementation

    +

    This example only demonstrates the documentation for types in QML files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type.

    +

    Files:

    + +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/test.qhp b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp new file mode 100644 index 0000000000..4fffda5138 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/test.qhp @@ -0,0 +1,190 @@ + + + org.qt-project.test.001 + test + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + autolinking.html + images/leonardo-da-vinci.png + obsolete-classes.html + qdoc-test-qmlmodule.html + qml-int.html + qml-qdoc-test-abstractparent-members.html + qml-qdoc-test-abstractparent.html + qml-qdoc-test-child-members.html + qml-qdoc-test-child.html + qml-qdoc-test-doctest-members.html + qml-qdoc-test-doctest.html + qml-qdoc-test-type-members.html + qml-qdoc-test-type.html + qml-qdoc-test-yetanotherchild-members.html + qml-qdoc-test-yetanotherchild.html + qml-uicomponents-progressbar-members.html + qml-uicomponents-progressbar.html + qml-uicomponents-switch-members.html + qml-uicomponents-switch.html + qml-uicomponents-tabwidget-members.html + qml-uicomponents-tabwidget.html + qmlmodules.html + test-cmaketest-cmakelists-txt.html + test-cmaketest-example.html + test-cmaketest-main-cpp.html + test-componentset-componentset-pro.html + test-componentset-componentset-qml.html + test-componentset-example.html + test-componentset-progressbar-qml.html + test-componentset-switch-qml.html + test-componentset-tabwidget-qml.html + test-demos-demo-example.html + test-demos-hidden-example.html + test-empty-qmlmodule.html + testcpp-module.html + testqdoc-test-members.html + testqdoc-test-obsolete.html + testqdoc-test.html + testqdoc-testderived-members.html + testqdoc-testderived-obsolete.html + testqdoc-testderived.html + testqdoc.html + uicomponents-qmlmodule.html + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testcpp-module.html b/tests/auto/qdoc/generatedoutput/expected_output/testcpp-module.html new file mode 100644 index 0000000000..5a7f6a941a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testcpp-module.html @@ -0,0 +1,43 @@ + + + + + + QDoc Test C++ Classes | TestCPP + + + +

    QDoc Test C++ Classes

    + + +

    A test module page. More...

    + + +

    Namespaces

    +
    + +

    TestQDoc

    A namespace

    + +

    Classes

    +
    + + +

    TestQDoc::Test

    A class in a namespace

    TestQDoc::TestDerived

    A derived class in a namespace

    + + +
    +

    Detailed Description

    +

    Note: This is just a test.

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index b/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index new file mode 100644 index 0000000000..f81a3fc09a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testcpp.index @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html new file mode 100644 index 0000000000..df0da43860 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-members.html @@ -0,0 +1,26 @@ + + + + + + List of All Members for Test | TestCPP + + +
  • Test
  • + +

    List of All Members for Test

    +

    This is the complete list of members for TestQDoc::Test, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-obsolete.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-obsolete.html new file mode 100644 index 0000000000..ef0e7bcace --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test-obsolete.html @@ -0,0 +1,36 @@ + + + + + + Obsolete Members for Test | TestCPP + + +
  • Test
  • + +

    Obsolete Members for Test

    +

    The following members of class Test are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code.

    +

    Public Functions

    +
    + + + +
    (obsolete) void anotherObsoleteMember()
    (obsolete) void deprecatedMember()
    (obsolete) void obsoleteMember()
    +

    Member Function Documentation

    + +

    void Test::anotherObsoleteMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use obsoleteMember() instead.

    + + +

    void Test::deprecatedMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use someFunction() instead.

    + + +

    void Test::obsoleteMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Use someFunction() instead.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html new file mode 100644 index 0000000000..7aafddfe6a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-test.html @@ -0,0 +1,133 @@ + + + + + + Test Class | TestCPP + + +
  • Test
  • + +

    Test Class

    +class TestQDoc::Test + +

    A class in a namespace. More...

    + +
    +
    Header: #include <Test> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherited By:

    TestQDoc::TestDerived

    +
    + +

    Public Types

    + + +

    Public Functions

    +
    + + + + + + + +
    Test()
    TestQDoc::Test &operator=(TestQDoc::Test &&other)
    void (*)(bool) funcPtr(bool b, const char *s)
    void inlineFunction()
    int someFunction(int, int v = 0)
    void someFunctionDefaultArg(int i, bool b = false)
    virtual void virtualFun()
    + +

    Protected Functions

    +
    + + +
    void overload()
    void overload(bool b)
    + + +
    + +
    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)
    + +

    Macros

    +
    + +
    QDOCTEST_MACRO2(int &x)
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    Test::SomeType

    +

    A typedef.

    + +
    +
    +

    Member Function Documentation

    + +
    +

    [protected] void Test::overload()

    [protected, since Test 1.2] void Test::overload(bool b)

    +

    Overloads that share a documentation comment, optionally taking a parameter b.

    + + +

    [default] Test::Test()

    +

    Default constructor.

    + + +

    [default] TestQDoc::Test &Test::operator=(TestQDoc::Test &&other)

    +

    Move-assigns other.

    + + +

    void (*)(bool) Test::funcPtr(bool b, const char *s)

    +

    Returns a pointer to a function that takes a boolean. Uses b and s.

    + + +

    void Test::inlineFunction()

    +

    An inline function, documented using the \fn QDoc command.

    + + +

    int Test::someFunction(int, int v = 0)

    +

    Function that takes a parameter v. Also returns the value of v.

    + + +

    void Test::someFunctionDefaultArg(int i, bool b = false)

    +

    Function that takes a parameter i and b.

    + + +

    [virtual] void Test::virtualFun()

    +

    Function that must be reimplemented.

    + +
    +
    +

    Related Non-Members

    + +

    bool operator==(const TestQDoc::Test &lhs, const TestQDoc::Test &rhs)

    +

    Returns true if lhs and rhs are equal.

    + +
    +
    +

    Macro Documentation

    + +

    [since Test 1.1] QDOCTEST_MACRO2(int &x)

    +

    A macro with argument x.

    +

    This function was introduced in Test 1.1.

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html new file mode 100644 index 0000000000..f8f9cd8f71 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-members.html @@ -0,0 +1,27 @@ + + + + + + List of All Members for TestDerived | TestCPP + + +
  • TestDerived
  • + +

    List of All Members for TestDerived

    +

    This is the complete list of members for TestQDoc::TestDerived, including inherited members.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-obsolete.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-obsolete.html new file mode 100644 index 0000000000..d35dd5837a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived-obsolete.html @@ -0,0 +1,24 @@ + + + + + + Obsolete Members for TestDerived | TestCPP + + +
  • TestDerived
  • + +

    Obsolete Members for TestDerived

    +

    The following members of class TestDerived are obsolete. They are provided to keep old source code working. We strongly advise against using them in new code.

    +

    Static Public Members

    +
    + +
    (obsolete) void staticObsoleteMember()
    +

    Member Function Documentation

    + +

    [static] void TestDerived::staticObsoleteMember()

    +

    This function is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

    +

    Static obsolete method.

    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived.html new file mode 100644 index 0000000000..e81391d5c2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc-testderived.html @@ -0,0 +1,68 @@ + + + + + + TestDerived Class | TestCPP + + +
  • TestDerived
  • + +

    TestDerived Class

    +class TestQDoc::TestDerived + +

    A derived class in a namespace. More...

    + +
    +
    Header: #include <TestDerived> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
    Inherits: TestQDoc::Test
    + +

    Public Types

    + + +

    Reimplemented Public Functions

    +
    + +
    virtual void virtualFun() override
    + + +
    +

    Detailed Description

    +
    + +
    +

    Member Type Documentation

    + +

    [alias] TestDerived::DerivedType

    +

    An aliased typedef.

    + + +

    [alias] TestDerived::NotTypedef

    +

    I'm an alias, not a typedef.

    + +
    +
    +

    Member Function Documentation

    + +

    [override virtual] void TestDerived::virtualFun()

    +

    Reimplements: Test::virtualFun().

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testqdoc.html b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc.html new file mode 100644 index 0000000000..237a0188f2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testqdoc.html @@ -0,0 +1,65 @@ + + + + + + TestQDoc Namespace | TestCPP + + + +

    TestQDoc Namespace

    + +

    A namespace. More...

    + +
    +
    Header: #include <TestCPP> +
    CMake: find_package(Qt6 COMPONENTS QDocTest REQUIRED)
    +target_link_libraries(mytarget PRIVATE Qt6::QDocTest)
    qmake: QT += testcpp
      +
    + +

    Classes

    +
    + + +
    class Test
    class TestDerived
    + +

    Macros

    + + + +
    +

    Detailed Description

    + +

    Usage

    +

    This namespace is for testing QDoc output.

    +
    + +
    +

    Classes

    +

    class Test

    +

    A class in a namespace. More...

    + +

    class TestDerived

    +

    A derived class in a namespace. More...

    + +
    +
    +

    Macro Documentation

    + +

    QDOCTEST_MACRO

    + +
    + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags b/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags new file mode 100644 index 0000000000..c5912acbec --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/testtagfile.tags @@ -0,0 +1,292 @@ + + + + QDoc.Test.AbstractParent + qml-qdoc-test-abstractparent.html + + void + rear + qml-qdoc-test-abstractparent.html + rear-method + (Child child, var method) + + + void + name + qml-qdoc-test-abstractparent.html + name-method + (Child child, name) + + + void + name + qml-qdoc-test-abstractparent.html + name-method + () + + + + QDoc.Test.Child + qml-qdoc-test-child.html + + void + name + qml-qdoc-test-child.html + name-method + (Child child, name) + + + + QDoc.Test.DocTest + qml-qdoc-test-doctest.html + + + completed + qml-qdoc-test-doctest.html + completed-signal + () + + + + foo + qml-qdoc-test-doctest.html + foo-signal + (var bar) + + + + fail + qml-qdoc-test-doctest.html + fail-method + (message) + + + + fail_hard + qml-qdoc-test-doctest.html + fail_hard-method + (msg, option) + + + + UIComponents.ProgressBar + qml-uicomponents-progressbar.html + + + UIComponents.Switch + qml-uicomponents-switch.html + + + toggle + qml-uicomponents-switch.html + toggle-method + () + + + + UIComponents.TabWidget + qml-uicomponents-tabwidget.html + + + TestQDoc + testqdoc.html + TestQDoc::Test + TestQDoc::TestDerived + + + QDOCTEST_MACRO + testqdoc.html + QDOCTEST_MACRO + QDOCTEST_MACRO + + + + TestQDoc::Test + testqdoc-test.html + + SomeType + testqdoc-test.html + SomeType-typedef + + + + int + someFunction + testqdoc-test.html + someFunction + (int, int v) + + + void + someFunctionDefaultArg + testqdoc-test.html + someFunctionDefaultArg + (int i, bool b) + + + void + obsoleteMember + testqdoc-test-obsolete.html + obsoleteMember + () + + + void + anotherObsoleteMember + testqdoc-test-obsolete.html + anotherObsoleteMember + () + + + void + deprecatedMember + testqdoc-test-obsolete.html + deprecatedMember + () + + + void (*)(bool) + funcPtr + testqdoc-test.html + funcPtr + (*)(bool) funcPtr(bool b, const char *s) + + + void + inlineFunction + testqdoc-test.html + inlineFunction + () + + + virtual void + virtualFun + testqdoc-test.html + virtualFun + () + + + bool + operator== + testqdoc-test.html + operator-eq-eq + (const TestQDoc::Test &lhs, const TestQDoc::Test &rhs) + + + void + overload + testqdoc-test.html + overload + () + + + void + overload + testqdoc-test.html + overload-1 + (bool b) + + + + Test + testqdoc-test.html + Test + () + + + TestQDoc::Test & + operator= + testqdoc-test.html + operator-eq + (TestQDoc::Test &&other) + + + + QDOCTEST_MACRO2 + testqdoc-test.html + QDOCTEST_MACRO2 + (int &x) + + + + TestQDoc::TestDerived + testqdoc-testderived.html + Test + + DerivedType + testqdoc-testderived.html + DerivedType-typedef + + + + NotTypedef + testqdoc-testderived.html + NotTypedef-typedef + + + + virtual void + virtualFun + testqdoc-testderived.html + virtualFun + () override + + + void + staticObsoleteMember + testqdoc-testderived-obsolete.html + staticObsoleteMember + () + + + + QDoc.Test.Type + qml-qdoc-test-type.html + + + group.created + qml-qdoc-test-type.html + group.created-signal + () + + + Type + copy + qml-qdoc-test-type.html + copy-method + (a) + + + + enable + qml-qdoc-test-type.html + enable-method + () + + + + disable + qml-qdoc-test-type.html + disable-method + () + + + + completed + qml-qdoc-test-type.html + completed-signal + (int status) + + + + configured + qml-qdoc-test-type.html + configured-signal + () + + + + QDoc.Test.YetAnotherChild + qml-qdoc-test-yetanotherchild.html + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/third.html b/tests/auto/qdoc/generatedoutput/expected_output/third.html new file mode 100644 index 0000000000..ee69a1689e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/third.html @@ -0,0 +1,31 @@ + + + + + + Third Class | TestModule + + +
  • Third
  • + +

    Third Class

    +
    +
    Header: #include <Third> +
      +
    + + +
    +

    Detailed Description

    +

    This is a third class

    +
    + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/toc.html b/tests/auto/qdoc/generatedoutput/expected_output/toc.html new file mode 100644 index 0000000000..cd4a503281 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/toc.html @@ -0,0 +1,30 @@ + + + + + + Table of Contents | OutputFromQDocFiles + + +
  • OutputFromQDocFiles - A test project for QDoc build artifacts
  • + +

    +

    +

    Table of Contents

    + + + + + + + diff --git a/tests/auto/qdoc/generatedoutput/expected_output/uicomponents-qmlmodule.html b/tests/auto/qdoc/generatedoutput/expected_output/uicomponents-qmlmodule.html new file mode 100644 index 0000000000..baba2c57af --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/expected_output/uicomponents-qmlmodule.html @@ -0,0 +1,24 @@ + + + + + + UI Components | Test + + + +

    UI Components

    + + +
    +

    This is a listing of a list of UI components implemented by QML types. These files are available for general import and they are based on the Qt Quick Code Samples.

    +

    This module is part of the UIComponents example.

    +
    + +
    + + + +

    ProgressBar

    A component that shows the progress of an event

    Switch

    A component that can be turned on or off

    TabWidget

    A widget that places its children as tabs

    + + diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/TestModule.h b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/TestModule.h new file mode 100644 index 0000000000..06f046a71b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/TestModule.h @@ -0,0 +1,3 @@ +#include "aaa.h" +#include "bbb.h" +#include "ccc.h" diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/aaa.h b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/aaa.h new file mode 100644 index 0000000000..dea5c18411 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/aaa.h @@ -0,0 +1,4 @@ +#pragma once +class Third +{ +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/bbb.h b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/bbb.h new file mode 100644 index 0000000000..ac3706e557 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/bbb.h @@ -0,0 +1,5 @@ +#pragma once +struct First +{ + class Nested {}; +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/ccc.h b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/ccc.h new file mode 100644 index 0000000000..d3a1557e1e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/inc/testmodule/ccc.h @@ -0,0 +1,4 @@ +#pragma once +class Second +{ +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/main.cpp b/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/main.cpp new file mode 100644 index 0000000000..a8991e18f5 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/main.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! +\class First +\inmodule TestModule + +This is a first class +*/ + +/*! +\class First::Nested +\inmodule TestModule + +This is a nested class +*/ + +/*! +\class Second +\inmodule TestModule + +This is a second class +*/ + +/*! +\class Third +\inmodule TestModule + +This is a third class +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/qdoc/index.qdoc b/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/qdoc/index.qdoc new file mode 100644 index 0000000000..35ef7e0872 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/src/qdoc/index.qdoc @@ -0,0 +1,7 @@ +/*! + \page index.html + \title doc index + + \generatelist {classesbymodule TestModule} + +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/testmodule.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/bug80259/testmodule.qdocconf new file mode 100644 index 0000000000..97599d0be1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/testmodule.qdocconf @@ -0,0 +1,14 @@ +include(../configs/config.qdocconf) +project = TestModule + +moduleheader = TestModule.h + +headerdirs = ./inc +sourcedirs = ./src +includepaths += ./inc/testmodule + +sources.fileextensions = "*.cpp *.qdoc" +headers.fileextensions = "*.h" + +outputdir = doc +outputformats = HTML diff --git a/tests/auto/qdoc/generatedoutput/testdata/bug80259/webxml_testmodule.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/bug80259/webxml_testmodule.qdocconf new file mode 100644 index 0000000000..dc9234fbb2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/bug80259/webxml_testmodule.qdocconf @@ -0,0 +1,2 @@ +include(testmodule.qdocconf) +include(../configs/webxml.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/config.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/config.qdocconf new file mode 100644 index 0000000000..70129901c1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/config.qdocconf @@ -0,0 +1,14 @@ +# Shared configuration for all tests + +sources.fileextensions = "*.qml *.cpp *.qdoc" +headers.fileextensions = "*.h" + +# images +imagedirs = ../images + +# zero warning policy +warninglimit = 0 +warninglimit.enabled = true + +# don't write host system-specific paths to index files +locationinfo = false diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/docbook.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook.qdocconf new file mode 100644 index 0000000000..68afd29e8b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook.qdocconf @@ -0,0 +1,7 @@ +outputformats = DocBook +DocBook.nosubdirs = true +DocBook.outputsubdir = docbook + +# TODO: DocBook generator has trouble handling shared comment nodes +# allow two warnings related to these +warninglimit = 2 diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_test.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_test.qdocconf new file mode 100644 index 0000000000..cf98800781 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_test.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +include(test.qdocconf) +include(docbook.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testcpp.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testcpp.qdocconf new file mode 100644 index 0000000000..f2b714e005 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testcpp.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +include(docbook.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testqml.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testqml.qdocconf new file mode 100644 index 0000000000..0286908348 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/docbook_testqml.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +include(testqml.qdocconf) +include(docbook.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/examples-qhp.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/examples-qhp.qdocconf new file mode 100644 index 0000000000..4b9f869384 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/examples-qhp.qdocconf @@ -0,0 +1,40 @@ +# QML test includes a documented example +include(config.qdocconf) +include(testqml.qdocconf) +version = 0.0.1 + +examplesinstallpath = test + +exampledirs += ../examples + +# Configure .qhp generation +qhp.projects = Test + +qhp.Test.file = test.qhp +qhp.Test.namespace = org.qt-project.test.001 +qhp.Test.virtualFolder = test +qhp.Test.indexTitle = UI Components +qhp.Test.indexRoot = + +qhp.Test.subprojects = test classes qmltypes undefined +qhp.Test.subprojects.test.title = Test +qhp.Test.subprojects.test.indexTitle = UI Components +qhp.Test.subprojects.test.selectors = doc:page fake:example module qmlmodule +qhp.Test.subprojects.test.sortPages = true + +qhp.Test.subprojects.classes.title = Classes +qhp.Test.subprojects.classes.indexTitle = QDoc Test C++ Classes +qhp.Test.subprojects.classes.selectors = class namespace doc:headerfile boop:whatever +qhp.Test.subprojects.classes.sortPages = true + +qhp.Test.subprojects.qmltypes.title = QML Types +qhp.Test.subprojects.qmltypes.indexTitle = UI Components +qhp.Test.subprojects.qmltypes.selectors = qmlmodule:UIComponents,QDoc.Test +qhp.Test.subprojects.qmltypes.sortPages = true + +# Add some meta-data to the example +manifestmeta.filters = test + +manifestmeta.test.names = * +manifestmeta.test.attributes = isTest:true +manifestmeta.test.tags = test diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/headerfile.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/headerfile.qdocconf new file mode 100644 index 0000000000..9fa359b90b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/headerfile.qdocconf @@ -0,0 +1,11 @@ +include(config.qdocconf) +project = HeaderFile +moduleheader = testheader.h + +{includepaths,sourcedirs,headerdirs} += ../headerfile + +outputformats = HTML DocBook +HTML.nosubdirs = true +HTML.outputsubdir = headerfile +DocBook.nosubdirs = true +DocBook.outputsubdir = headerfile-docbook diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/ignoresince.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/ignoresince.qdocconf new file mode 100644 index 0000000000..019b15b3a5 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/ignoresince.qdocconf @@ -0,0 +1,9 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +defines += test_ignoresince + +ignoresince = 2.0 +ignoresince.Test = 1.0 + +HTML.nosubdirs = true +HTML.outputsubdir = ignoresince diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/nestedmacro.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/nestedmacro.qdocconf new file mode 100644 index 0000000000..056b304527 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/nestedmacro.qdocconf @@ -0,0 +1,10 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +defines += test_nestedmacro + +macro.ver = "5.15.0" +macro.ver.match = "^(\\d+\\.\\d+)" +macro.versionnote.HTML = "

    This \1 was introduced in version \2.

    \n" + +HTML.nosubdirs = true +HTML.outputsubdir = nestedmacro diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/noautolist.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/noautolist.qdocconf new file mode 100644 index 0000000000..16824db0ec --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/noautolist.qdocconf @@ -0,0 +1,14 @@ +include(config.qdocconf) +include(testqml.qdocconf) +defines += test_noautolist + +outputformats = HTML DocBook + +HTML.nosubdirs = true +DocBook.nosubdirs = true +HTML.outputsubdir = noautolist +DocBook.outputsubdir = noautolist-docbook + +# TODO: DocBook generator has trouble handling shared comment nodes +# - allow two warnings related to these +warninglimit = 2 diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/properties.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/properties.qdocconf new file mode 100644 index 0000000000..3fbdbef22f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/properties.qdocconf @@ -0,0 +1,13 @@ +include(testcpp.qdocconf) + +defines += test_properties + +sources += ../testcpp/properties.qdoc + +outputformats = HTML DocBook +{HTML.nosubdirs,DocBook.nosubdirs} = true +HTML.outputsubdir = properties +DocBook.outputsubdir = properties-docbook + +# Allow link warning to Q_INVOKABLE +warninglimit += 1 diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/scopedenum.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/scopedenum.qdocconf new file mode 100644 index 0000000000..d142e07fea --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/scopedenum.qdocconf @@ -0,0 +1,11 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +defines += test_scopedenum + +sources += ../scopedenum/scopedenum.qdoc + +outputformats = HTML DocBook + +{HTML.nosubdirs,DocBook.nosubdirs} = true +HTML.outputsubdir = scopedenum +DocBook.outputsubdir = scopedenum-docbook diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/tagfiles.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/tagfiles.qdocconf new file mode 100644 index 0000000000..5e13825889 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/tagfiles.qdocconf @@ -0,0 +1,2 @@ +include(testqml.qdocconf) +tagfile = testtagfile.tags diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/test.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/test.qdocconf new file mode 100644 index 0000000000..80e7c2fee5 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/test.qdocconf @@ -0,0 +1,13 @@ +include(config.qdocconf) +project = OutputFromQDocFiles +description = "A test project for QDoc build artifacts" +buildversion = "$project - $description" +moduleheader = + +sources = ../outputfromqdocfiles/qdoctests-outputfromqdocfiles.qdoc + +macro.beginqdoc = "\\c {/*!}" +macro.endqdoc = "\\c */" +macro.PROD = QDoc + +defines = test_navigation diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp.qdocconf new file mode 100644 index 0000000000..b1d26f27e5 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp.qdocconf @@ -0,0 +1,12 @@ +include(config.qdocconf) +project = TestCPP +includepaths += -I../testcpp + +headers = ../testcpp/testcpp.h +sources = ../testcpp/testcpp.cpp \ + ../testcpp/classlists.qdoc +exampledirs = ../testcpp/snippets + +macro.CMDFN = \\\\fn +macro.nothing = \\dontdocument () +macro.testnoautolist = \\if defined(test_noautolist)\n\\noautolist\n\\endif diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp_singleexec.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp_singleexec.qdocconf new file mode 100644 index 0000000000..2ca75ea0ac --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/testcpp_singleexec.qdocconf @@ -0,0 +1,6 @@ +include(testcpp.qdocconf) + +# Config::getOutputDir() forces a subdir in single-exec mode (why?), +# disable it here explicitly +HTML.nosubdirs = true +HTML.outputsubdir = . diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/testglobals.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/testglobals.qdocconf new file mode 100644 index 0000000000..c69ffe2390 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/testglobals.qdocconf @@ -0,0 +1,6 @@ +include(config.qdocconf) +project = TestGlobals +includepaths += -I../globalfunc + +headers = ../globalfunc/global.h +sources = ../globalfunc/global.qdoc diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/testqml.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/testqml.qdocconf new file mode 100644 index 0000000000..1c4d29a137 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/testqml.qdocconf @@ -0,0 +1,22 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +moduleheader = TestCPP + +project = Test +description = "A test project for QDoc build artifacts" +outputdir = ./html + +exampledirs = ../qml + +headerdirs += ../ +sourcedirs += ../qml + +# Exclude source files from other tests' subdirs +excludedirs = ../bug80259 + +examples.fileextensions = "*.qml *.cpp" + +macro.begincomment = "\\c{/*}" +macro.QDocTestVer = "1.1" + +warninglimit += 1 diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/testtemplate.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/testtemplate.qdocconf new file mode 100644 index 0000000000..575a30d8de --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/testtemplate.qdocconf @@ -0,0 +1,9 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +defines += test_template + +headers += ../testtemplate/testtemplate.h +sources += ../testtemplate/testtemplate.cpp + +HTML.nosubdirs = true +HTML.outputsubdir = template diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/tocnavigation.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/tocnavigation.qdocconf new file mode 100644 index 0000000000..ba950532b1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/tocnavigation.qdocconf @@ -0,0 +1,5 @@ +include(config.qdocconf) +include(test.qdocconf) + +defines = +navigation.toctitles = "Table of Contents" diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/usingdirective.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/usingdirective.qdocconf new file mode 100644 index 0000000000..d5a925b582 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/usingdirective.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +project = UsingDirective +{includepaths,headerdirs,sourcedirs} = ../usingdirective diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/webxml.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml.qdocconf new file mode 100644 index 0000000000..d6e6290b88 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml.qdocconf @@ -0,0 +1,3 @@ +outputformats = WebXML +WebXML.quotinginformation = true +WebXML.nosubdirs = true diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_test.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_test.qdocconf new file mode 100644 index 0000000000..468bc42b58 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_test.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +include(test.qdocconf) +include(webxml.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testcpp.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testcpp.qdocconf new file mode 100644 index 0000000000..dee1f4dcc2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testcpp.qdocconf @@ -0,0 +1,3 @@ +include(config.qdocconf) +include(testcpp.qdocconf) +include(webxml.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testqml.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testqml.qdocconf new file mode 100644 index 0000000000..537685700c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/configs/webxml_testqml.qdocconf @@ -0,0 +1,2 @@ +include(testqml.qdocconf) +include(webxml.qdocconf) diff --git a/tests/auto/qdoc/generatedoutput/testdata/crossmodule/CrossModule b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/CrossModule new file mode 100644 index 0000000000..50bea93abc --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/CrossModule @@ -0,0 +1,2 @@ +#include "../testcpp/TestCPP" +#include "testtype.h" diff --git a/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule.qdocconf new file mode 100644 index 0000000000..359063f348 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule.qdocconf @@ -0,0 +1,11 @@ +include(../configs/config.qdocconf) +project = CrossModule +includepaths += -I. + +depends = testcpp + +headers = testtype.h +sources = testtype.cpp + +HTML.nosubdirs = true +HTML.outputsubdir = crossmodule diff --git a/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule_singleexec.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule_singleexec.qdocconf new file mode 100644 index 0000000000..d49498ec05 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/crossmodule_singleexec.qdocconf @@ -0,0 +1,4 @@ +include(crossmodule.qdocconf) + +HTML.nosubdirs = true +HTML.outputsubdir = crossmodule diff --git a/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.cpp b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.cpp new file mode 100644 index 0000000000..98d3a1c8e2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testtype.h" + +/*! + \module CrossModule +*/ +/*! + \class TestType + \inmodule CrossModule + \brief A class inheriting another class that lives in an external doc + module. + + \section1 Linking + + These links go to the parent class: + \list + \li \l {TestQDoc::TestDerived} + \li \l {TestQDoc::}{Test} class \l Usage. + \li QDOCTEST_MACRO + \li DontLinkToMe + \endlist + + \section1 Generated Lists + + This is an annotated list of entries in a group: + \annotatedlist testgroup + + \sa {TestQDoc::Test::}{someFunction()} +*/ + +/*! + Nothing to see here. +*/ +void TestType::nothing() +{ +} diff --git a/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.h b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.h new file mode 100644 index 0000000000..4ffb0c80bb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/crossmodule/testtype.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#pragma once + +#include "../testcpp/testcpp.h" + +class TestType : public TestQDoc::TestDerived +{ +public: + TestType() {} + void nothing() {} +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/dontdocument/TestCPP b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/TestCPP new file mode 100644 index 0000000000..7291e6d8f7 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/TestCPP @@ -0,0 +1,2 @@ +#include "../TestCPP" +#include "dont.h" diff --git a/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.cpp b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.cpp new file mode 100644 index 0000000000..33e2084593 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dont.h" + +/*! + \class UnseenClass + \inmodule TestCPP + \brief A public but undocumented class. +*/ +UnseenClass::UnseenClass() +{ +} + +/*! + \class SeenClass + \inmodule TestCPP + \brief A public but undocumented class. +*/ +SeenClass::SeenClass() +{ +} diff --git a/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.h b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.h new file mode 100644 index 0000000000..5ef436b5c8 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dont.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +class UnseenClass +{ +public: + UnseenClass(); +}; + +class SeenClass : public UnseenClass +{ +public: + SeenClass(); +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dontdocument.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dontdocument.qdocconf new file mode 100644 index 0000000000..ef45f50a69 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/dontdocument.qdocconf @@ -0,0 +1,21 @@ +include(../configs/testcpp.qdocconf) + +headers += dont.h +sources += dont.cpp test.qdoc + +qhp.projects = DontDocument + +qhp.DontDocument.file = dontdocument.qhp +qhp.DontDocument.namespace = org.qt-project.dontdocument.001 +qhp.DontDocument.virtualFolder = test +qhp.DontDocument.indexTitle = QDoc Test C++ Classes +qhp.DontDocument.indexRoot = + +qhp.DontDocument.subprojects = classes +qhp.DontDocument.subprojects.classes.title = Classes +qhp.DontDocument.subprojects.classes.indexTitle = QDoc Test C++ Classes +qhp.DontDocument.subprojects.classes.selectors = class +qhp.DontDocument.subprojects.classes.sortPages = true + +HTML.nosubdirs = true +HTML.outputsubdir = dontdocument diff --git a/src/qdoc/separator.h b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/test.qdoc similarity index 83% rename from src/qdoc/separator.h rename to tests/auto/qdoc/generatedoutput/testdata/dontdocument/test.qdoc index a8637ddd78..3f6e0be30e 100644 --- a/src/qdoc/separator.h +++ b/tests/auto/qdoc/generatedoutput/testdata/dontdocument/test.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. @@ -26,20 +26,11 @@ ** ****************************************************************************/ -/* - separator.h +/*! + \dontdocument (UnseenClass) */ -#ifndef SEPARATOR_H -#define SEPARATOR_H - -#include - -QT_BEGIN_NAMESPACE - -QString separator( int index, int count ); -QString comma( int index, int count ); - -QT_END_NAMESPACE - -#endif +/*! \page classes.html + \title Classes + \generatelist annotatedclasses +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/demo.pro b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/demo.pro new file mode 100644 index 0000000000..dbe8ff3c05 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/demo.pro @@ -0,0 +1,2 @@ +TEMPLATE = aux +message("Nothing to see here.") diff --git a/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/doc/src/demo.qdoc b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/doc/src/demo.qdoc new file mode 100644 index 0000000000..de7160ee4a --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/demo/doc/src/demo.qdoc @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example demos/demo + \title Demo + \image leonardo-da-vinci.png + //! Icon made by Smashicons from www.flaticon.com +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/doc/src/hidden.qdoc b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/doc/src/hidden.qdoc new file mode 100644 index 0000000000..00518731f0 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/doc/src/hidden.qdoc @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example demos/hidden + \title Hidden Demo + \meta tag broken + \brief Tagged 'broken', does not appear in demos-manifest.xml. + + Also missing an image, but that's OK as it's broken anyway. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/hidden.pro b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/hidden.pro new file mode 100644 index 0000000000..dbe8ff3c05 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/examples/demos/hidden/hidden.pro @@ -0,0 +1,2 @@ +TEMPLATE = aux +message("Nothing to see here.") diff --git a/tests/auto/qdoc/generatedoutput/testdata/globalfunc/TestGlobals b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/TestGlobals new file mode 100644 index 0000000000..dc4f98a6ef --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/TestGlobals @@ -0,0 +1 @@ +#include "global.h" diff --git a/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.h b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.h new file mode 100644 index 0000000000..16d3a89cd7 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.h @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +class Globals {}; +inline int foo(int a) { return a; } +inline int foo(int a, bool b) { return b ? a : -a; } diff --git a/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.qdoc b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.qdoc new file mode 100644 index 0000000000..a68a55abdb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/globalfunc/global.qdoc @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module TestGlobals +*/ + +/*! + \class Globals + \inmodule TestGlobals +*/ + +/*! + \fn int foo(int a) + \relates Globals + Params: \a a +*/ + +/*! + \fn int foo(int a, bool b) + \relates Globals + Params: \a b, \a b +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.cpp b/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.cpp new file mode 100644 index 0000000000..3a85b169cf --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testheader.h" + +/*! + \headerfile + \title Test Header + \inmodule TestCPP + \brief A header file. + \ingroup headers +*/ + +/*! + \group headers + \title Headers +*/ + +/*! + \fn void globalFunc() + \brief Global function. + \relates +*/ + +/*! + \variable globalVar + \brief Global variable. + \relates +*/ + +/*! + \enum Globals + \relates + \value Glo + \value Bal +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.h b/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.h new file mode 100644 index 0000000000..94c6251576 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/headerfile/testheader.h @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +void globalFunc() {}; +enum Globals { Glo, Bal }; +const int globalVar; diff --git a/tests/auto/qdoc/generatedoutput/testdata/images/leonardo-da-vinci.png b/tests/auto/qdoc/generatedoutput/testdata/images/leonardo-da-vinci.png new file mode 100644 index 0000000000..854acb4ca9 Binary files /dev/null and b/tests/auto/qdoc/generatedoutput/testdata/images/leonardo-da-vinci.png differ diff --git a/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/anotherindex.qdoc b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/anotherindex.qdoc new file mode 100644 index 0000000000..75dd9197d1 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/anotherindex.qdoc @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +//! exampledirs-include + \page index.html + \title doc index + + \section1 C++ Classes + \generatelist {classesbymodule TestCPP} + \section1 QML Types + \annotatedlist qmltypes +//! exampledirs-include +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/parentinclude.qdoc b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/parentinclude.qdoc new file mode 100644 index 0000000000..4933bc4bde --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/excludes/parentinclude.qdoc @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +//! abstract-type + \qmltype AbstractParent + \inqmlmodule QDoc.Test + \ingroup qmltypes + \qmlabstract + \brief Abstract base QML type. +//! abstract-type +*/ + +/*! +//! children-qmlproperty + \qmlproperty list AbstractParent::children + \default + \brief Children of the type. +//! children-qmlproperty +*/ + +/*! +//! rear-qmlmethod + \qmlmethod void AbstractParent::rear(Child child) + \brief Do some abstract parenting on \a child. +//! rear-qmlmethod +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/includefromexampledirs.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/includefromexampledirs.qdocconf new file mode 100644 index 0000000000..d64985942f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/includefromexampledirs.qdocconf @@ -0,0 +1,13 @@ +include(../configs/testqml.qdocconf) + +sourcedirs += src + +excludedirs += excludes \ + ../qml/componentset + +excludefiles += ../qml/parent.qdoc + +exampledirs += excludes + +HTML.nosubdirs = true +HTML.outputsubdir = includefromexampledirs diff --git a/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/includefromparent.qdoc b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/includefromparent.qdoc new file mode 100644 index 0000000000..a9a526c643 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/includefromparent.qdoc @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\include anotherindex.qdoc exampledirs-include + +\include parent.qdocinc +*/ + +/*! +\include parentinclude.qdoc abstract-type + +\include parent.qdocinc +*/ + +/*! +\include parentinclude.qdoc children-qmlproperty + +\include parent.qdocinc +*/ + +/*! +\include parentinclude.qdoc rear-qmlmethod + +\include parent.qdocinc +*/ + +/*! + \qmltype Child + \inqmlmodule QDoc.Test + \ingroup qmltypes + \inherits AbstractParent + \brief A Child inheriting its parent. +*/ + +/*! + \qmlbasictype int + \inqmlmodule QDoc.Test + \ingroup qmltypes + \brief An integer basic type. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/parent.qdocinc b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/parent.qdocinc new file mode 100644 index 0000000000..307c39dbdf --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/includefromexampledirs/src/parent.qdocinc @@ -0,0 +1 @@ +Test include file that is part of the sourcedirs. diff --git a/tests/auto/qdoc/generatedoutput/testdata/indexlinking/indexlinking.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/indexlinking/indexlinking.qdocconf new file mode 100644 index 0000000000..4f5fe22b06 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/indexlinking/indexlinking.qdocconf @@ -0,0 +1,7 @@ +# test linking to entities loaded from index +project = IndexLinking + +depends = \ + qmlpropertygroups + +sources = linking.qdoc diff --git a/tests/auto/qdoc/generatedoutput/testdata/indexlinking/linking.qdoc b/tests/auto/qdoc/generatedoutput/testdata/indexlinking/linking.qdoc new file mode 100644 index 0000000000..1cbf1e4246 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/indexlinking/linking.qdoc @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page index-linking.html + \title Linking + + \section1 QML properties + \list A + \li Property group: \l [QML] {Parent::group}. + \li Property in a group: \l [QmlPropertyGroups] + QDoc.Test::Parent::group.c. + \endlist +*/ + +/*! + \qmlmodule LinkModule 1.0 +*/ + +/*! + \qmltype GrandChild + \inqmlmodule LinkModule + \inherits AnotherChild +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/outputfromqdocfiles/qdoctests-outputfromqdocfiles.qdoc b/tests/auto/qdoc/generatedoutput/testdata/outputfromqdocfiles/qdoctests-outputfromqdocfiles.qdoc new file mode 100644 index 0000000000..e421ed1fbf --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/outputfromqdocfiles/qdoctests-outputfromqdocfiles.qdoc @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\if defined(test_navigation) + \nextpage {qdoctests-qdocfileoutput-linking.html}{QDoc Linking Test} +\endif + + \page qdoctests-qdocfileoutput.html + \title Testing \PROD output from .qdoc files + \brief This is a simple page for testing purposes only. + + QDoc generates documentation for software projects. It does this by + extracting \e {QDoc comments} from project source files. QDoc comments are + signified by a C-style-like comment tag followed by an exclamation point, + like this: + \beginqdoc \c {This text is contained within QDoc comment tags.} \endqdoc. + + \section1 Supported file types + QDoc parses \c .cpp and \c .qdoc files. It does extract comments from + header (\c {.h}) files. + + \section1 Further information + This test document is written with the purpose of testing the output QDoc + generates when parsing \c .qdoc files. It is fairly simple and makes use of + a limited subset of QDoc's command. Those commands are: + \list + \li \c {\page} + \li \c {\title} + \li \c {\brief} + \li \c {\e} (for emphasizing "QDoc comments") + \li \c {\c} (for multiple monospace-formatted entries) + \li \c {\section1} + \li \c {\list} + \li \c {\li} + \li \c {\endlist} + \endlist + + \section1 Linking + + There are multiple ways to create hyperlinks to other topics: + + \list + \li \l {Testing QDoc's link command}{Linking to a page title} + \li \l {Link targets}{Linking to a section title} + \li \l {link-test-target}{Linking using a \\target string} + \li \l {QDoc Linking Test}{Linking using a \\keyword string} + \endlist +*/ + +/*! +\if defined(test_navigation) + \previouspage qdoctests-qdocfileoutput.html \PROD Testing + \nextpage Table of Contents +\endif + + \keyword QDoc Linking Test + \page qdoctests-qdocfileoutput-linking.html + \title Testing QDoc's link command + \brief This is a page for testing QDoc's link command. + + \target link-test-target + \section1 Link targets + + Valid parameters for the link command (\c {\l}) are page and section + titles, targets defined with \\target or \\keyword commands, and API + reference keywords (types, methods, namespaces, and so on). +*/ + +/*! +\if defined(test_navigation) + \previouspage {Testing QDoc's link command}{QDoc Linking Test} +\endif + + \page toc.html + \title Table of Contents + + \list + \li \l {Testing \PROD output from .qdoc files}{\PROD Testing} + \li \l {QDoc Linking Test} + \li \l {Table of Contents} + \endlist +*/ + +/*! + \page qdoctests-qdocfileoutput-exhaustive.html + \title Exhaustive testing of QDoc commands + \brief This page is a dumping ground for QDoc commands under test. + + \section1 This is a section1 + \section2 This is a section2 + \section3 This is a section3 + \section4 This is a section4 + \endsection4 + \endsection3 + \endsection2 + \endsection1 + + \badcode + This is bad code + \endcode + + This text should have a line break riiiiight \br noooow. + + \b{All your text belong to bold} + ...And this is an examble of only \b bold being, well, bold. + + \dots + + \js + // If I knew JavaScript, this is where I would write it. + \endjs + + \qmltext + And if I knew qmltext, I guess this is where that would go. + \endqmltext + + \caption This a caption + + \legalese + Lorem legal ipsum + \endlegalese + + \quotation + This is a quotation. + \endquotation + + \raw HTML + This is raw. Like the

    Eddie Murphy

    movie. Just not as funny. + \endraw + + \sidebar + Look, ma! I made a sidebar! + \endsidebar + + \table + \row \li Table item in a table row + \row \li Another item in a different row + \endtable + + \granularity + + \important This is really important. + + \oldcode + This is old code. + \newcode + This is new and shiny! + \endcode + + \note The code above doesn't compile + + \hr + + \warning The following commands have yet to be tested: + footnote + link + //! Check why above two (when used in this order) cause missing linefeeds on Windows/webxml + sincelist + header + index + topicref // or just don’t care, remove it + image + inlineimage + printline + printto + printuntil // what’s the difference between printto and printuntil??? + quotefile + quotefromfile + quotefunction + skipline + skipto + skipuntil + span + snippet + codeline + overload + sub + sup + tableofcontents + tt + uicontrol + endmapref + endomit + underline + unicode + +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/DocTest.qml b/tests/auto/qdoc/generatedoutput/testdata/qml/DocTest.qml new file mode 100644 index 0000000000..9b4c975f22 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/DocTest.qml @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 + +/*! + \qmltype DocTest + \inherits Test + \inqmlmodule QDoc.Test + \brief Represents a doc test case. + \since QDoc.Test 0.9 + + \section1 Introduction + + A documentation test case, itself documented inline in DocTest.qml. +*/ +Item { + id: testCase + + /*! + \qmlsignal QDocTest::completed + */ + signal completed + + /*! + \qmlsignal DocTest::test(var bar) + Signal with parameter \a bar. + */ + signal foo(var bar) + + /*! + \qmlproperty string DocTest::name + + Name of the test. + \qml + DocTest { + name: "test" + // ... + } + \endqml + */ + required property string name + + /*! + Whether the test is active. + + \sa name + */ + property bool active: true + + /*! \internal */ + property int doctest_internal: -1 + + /*! + \qmlmethod DocTest::fail(message = "oops") + \since QDoc.Test 1.0 + + Fails the current test case, with the optional \a message. + */ + function fail(msg) { + if (msg === undefined) + msg = "oops"; + } + + /*! \internal */ + function doctest_fail(msg) { + if (msg === undefined) + msg = ""; + } + + /*! + \brief Fails the current test case, hard. + \list + \li Prints out \a msg. + \li Accepts a random \a option. + \endlist + */ + function fail_hard(msg = "facepalm", option = 123) { + } +} diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/CMakeLists.txt b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/CMakeLists.txt new file mode 100644 index 0000000000..c6a5c654b4 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/CMakeLists.txt @@ -0,0 +1,2 @@ +cmake_minimum_required (VERSION 2.8.11) +project (QDOCTEST) diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/doc/src/cmaketest.qdoc b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/doc/src/cmaketest.qdoc new file mode 100644 index 0000000000..e60f3b9e86 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/doc/src/cmaketest.qdoc @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example cmaketest + \title CMake Example Project + \image leonardo-da-vinci.png + //! Icon made by Smashicons from www.flaticon.com +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/main.cpp b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/main.cpp new file mode 100644 index 0000000000..68d71eb71c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/cmaketest/main.cpp @@ -0,0 +1 @@ +void main(){} diff --git a/tests/auto/qdoc/qmlcomponentoutput/componentset/ProgressBar.qml b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/ProgressBar.qml similarity index 100% rename from tests/auto/qdoc/qmlcomponentoutput/componentset/ProgressBar.qml rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/ProgressBar.qml diff --git a/tests/auto/qdoc/qmlcomponentoutput/componentset/Switch.qml b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/Switch.qml similarity index 100% rename from tests/auto/qdoc/qmlcomponentoutput/componentset/Switch.qml rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/Switch.qml diff --git a/tests/auto/qdoc/qmlcomponentoutput/componentset/TabWidget.qml b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/TabWidget.qml similarity index 100% rename from tests/auto/qdoc/qmlcomponentoutput/componentset/TabWidget.qml rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/TabWidget.qml diff --git a/tests/auto/qdoc/qmlcomponentoutput/componentset/componentset.pro b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/componentset.pro similarity index 100% rename from tests/auto/qdoc/qmlcomponentoutput/componentset/componentset.pro rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/componentset.pro diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/componentset.qml b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/componentset.qml new file mode 100644 index 0000000000..459c82afbb --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/componentset.qml @@ -0,0 +1,4 @@ +import QtQuick 2.0 + +Item { +} diff --git a/tests/auto/qdoc/qmlcomponentoutput/examples.qdoc b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/examples.qdoc similarity index 81% rename from tests/auto/qdoc/qmlcomponentoutput/examples.qdoc rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/examples.qdoc index 7c780eca88..9c499713da 100644 --- a/tests/auto/qdoc/qmlcomponentoutput/examples.qdoc +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/examples.qdoc @@ -28,26 +28,33 @@ /*! \example componentset \title QML Documentation Example + \brief Example for documenting QML types. - This example demonstrates one of the ways to document QML types. + \testnoautolist + + \meta tag {test,sample,(Qt)} + \meta installpath tutorials + + This example demonstrates one of the ways to document QML types. It also + generates a warning about a missing example image, on purpose. In particular, there are sample types that are documented with QDoc commands comments. There are documentation comments for the QML types and their public interfaces. The types are grouped into a module, the \l{UI Components} module. - The \l{componentset/uicomponents.qdoc.sample}{uicomponents.qdoc} file generates + The uicomponents.qdoc file generates the overview page for the \l{UI Components} module page. The generated documentation is available in the \l{UI Components} module. \section1 QML Class - The QML types use the \l{qmltype-command}{\\qmltype} to document the - type. In addition, they have the \l{inmodule-command}{\\inmodule} + The QML types use the \\qmltype to document the + type. In addition, they have the \\inmodule command in order for QDoc to associate them to the \c UIComponents module. - QDoc uses the \l{brief-command}{\\brief} command to place a basic + QDoc uses the \\brief command to place a basic description when listing the types. \section1 Properties, Signals, Handlers, and Methods @@ -58,7 +65,7 @@ documentation above the property, method, or signal. To document the type of a \e {property alias}, you must use the - \l{qmlproperty-command}{\\qmlproperty} command to specify the data type. + \\qmlproperty command to specify the data type. \code \qmlproperty int anAliasedProperty @@ -68,17 +75,17 @@ \section2 Internal Documentation You may declare that a documentation is for internal use by placing the - \l{internal-command}{\\internal} command after the beginning QDoc comment + \\internal command after the beginning QDoc comment \begincomment. QDoc will prevent the internal documentation from appearing in the public API. If you wish to omit certain parts of the documentation, you may use the - \l{omit-command}{\\omit} and \l{omit-command}{\\endomit} command. + \\omit and \\endomit command. \section1 QML Types with C++ Implementation This example only demonstrates the documentation for types in QML - files, but the regular \l{qml-documentation}{QML commands} may be placed + files, but the regular QML commands may be placed inside C++ classes to define the public API of the QML type. */ @@ -87,11 +94,11 @@ /*! \qmlmodule UIComponents 1.0 \title UI Components - \brief Basic set of UI components + \brief Basic set of UI components. This is a listing of a list of UI components implemented by QML types. These files are available for general import and they are based on the - \l{Qt Quick Examples and Tutorials}{Qt Quick Code Samples}. + Qt Quick Code Samples. This module is part of the \l{componentset}{UIComponents} example. */ diff --git a/tests/auto/qdoc/qmlcomponentoutput/componentset/uicomponents.qdoc.sample b/tests/auto/qdoc/generatedoutput/testdata/qml/componentset/uicomponents.qdoc.sample similarity index 100% rename from tests/auto/qdoc/qmlcomponentoutput/componentset/uicomponents.qdoc.sample rename to tests/auto/qdoc/generatedoutput/testdata/qml/componentset/uicomponents.qdoc.sample diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/modules.qdoc b/tests/auto/qdoc/generatedoutput/testdata/qml/modules.qdoc new file mode 100644 index 0000000000..12db2a0c1e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/modules.qdoc @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qmlmodules.html + \title QML Modules + + \generatelist qml-modules +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/parent.qdoc b/tests/auto/qdoc/generatedoutput/testdata/qml/parent.qdoc new file mode 100644 index 0000000000..78bf1e033e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/parent.qdoc @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmltype AbstractParent + \inqmlmodule QDoc.Test + \qmlabstract + \brief Abstract base QML type. +*/ + +/*! + \qmlproperty list AbstractParent::children + \default + \brief Children of the type. +*/ + +/*! + \qmlmethod void AbstractParent::rear(Child child, var method = Strict) + \brief Do some abstract parenting on \a child using a specific \a method. +*/ + +/*! + \qmlproperty string AbstractParent::name + \brief Name of this parent. +*/ + +/*! + \qmlmethod void AbstractParent::name(Child child, name) + \brief Name a \a child using \a name. + +*/ + +/*! + \qmlmethod void AbstractParent::name() + \brief Name all children with random names. +*/ + +/*! + \qmltype Child + \inqmlmodule QDoc.Test + \inherits AbstractParent + \brief A Child inheriting its parent. +*/ + +/*! + //! override from abstract base + \qmlproperty string Child::name + \brief Name of this child. +*/ + +/*! + //! override from abstract base + \qmlmethod void Child::name(Child child, name) + \brief Name a \a child of this child using \a name. +*/ + +/*! + \qmlbasictype int + \inqmlmodule QDoc.Test + + \brief An integer basic type. +*/ + +/*! + \qmlmethod int int::abs() + Returns the absolute value of this integer. +*/ + +/*! + \qmltype InternParent + \inqmlmodule QDoc.Test + \internal + \qmlabstract + \brief Internal abstract base QML type. +*/ + +/*! + \qmlproperty int InternParent::prop + \brief Propagated to inheriting type docs. +*/ + +/*! + \qmltype YetAnotherChild + \inherits InternParent + \inqmlmodule QDoc.Test + \brief A type inheriting from internal abstract parent. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp b/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp new file mode 100644 index 0000000000..de3929140b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qml/type.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testcpp.h" + +/*! + \qmlmodule QDoc.Test \QDocTestVer + \brief QML Types for the Test module. + \since 1.1 + \preliminary + + \testnoautolist +*/ + +/*! + \qmlmodule Test.Empty 1.0 + \title No QML Types Here + \brief A QML module with no member types. +*/ + +/*! + \qmltype Type + \instantiates TestQDoc::Test + \inqmlmodule QDoc.Test + \brief A QML type documented in a .cpp file. +*/ + +/*! + \qmlproperty int Type::id + \readonly + \brief A read-only property. +*/ + +/*! + \qmlproperty string QDoc.Test::Type::name + \required + \brief Name of the Test. +*/ + +/*! + \qmlattachedproperty enumeration Type::type + + \value Type.NoType + Nothing + \value Type.SomeType + Something +*/ + +/*! + \qmlproperty int Type::group.first + \qmlproperty int Type::group.second + \qmlproperty int Type::group.third + + \brief A property group. +*/ + +/*! + \qmlsignal Type::group.created + + This signal is prefixed with \e group. +*/ + +/*! + \qmlproperty int Type::fourth + \qmlproperty int Type::fifth + + \brief A group of properties sharing a documentation comment. +*/ + +/*! + \qmlmethod Type Type::copy(a) + + Returns another Type based on \a a. +*/ + +/*! + \qmlmethod Type::enable() + \qmlmethod Type::disable() + + Enables or disables this type. +*/ + +/*! + \qmlsignal Type::completed(int status) + + This signal is emitted when the operation completed with \a status. +*/ + +/*! + \qmlattachedsignal Type::configured() + + This attached signal is emitted when the type was configured. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/parent.qdoc b/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/parent.qdoc new file mode 100644 index 0000000000..e0d7162256 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/parent.qdoc @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmltype Parent + \inqmlmodule QDoc.Test + \brief Base QML type. +*/ + +/*! + \qmlproperty int Parent::group.c + \qmlproperty int Parent::group.a + \qmlproperty int Parent::group.b + \brief Property group. +*/ + +/*! + \qmlproperty int Parent::group.b + \readonly +*/ + +/*! + \qmlproperty int Parent::group.c + \since 2.0 +*/ + +/*! + \qmltype AnotherChild + \inqmlmodule QDoc.Test + \inherits Parent + \brief Just another child inheriting a parent. +*/ + +/*! + \qmlproperty string AnotherChild::name + \brief Name of this child. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/qmlpropertygroups.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/qmlpropertygroups.qdocconf new file mode 100644 index 0000000000..1f876d030f --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/qmlpropertygroups/qmlpropertygroups.qdocconf @@ -0,0 +1,11 @@ +include(../configs/testqml.qdocconf) + +project = QmlPropertyGroups + +sourcedirs += . + +outputformats = HTML DocBook + +{HTML.nosubdirs,DocBook.nosubdirs} = true +HTML.outputsubdir = qmlpropertygroups +DocBook.outputsubdir = qmlpropertygroups-docbook diff --git a/tests/auto/qdoc/qdocfileoutput/qdoctests-outputfromqdocfiles.qdoc b/tests/auto/qdoc/generatedoutput/testdata/scopedenum/scopedenum.qdoc similarity index 50% rename from tests/auto/qdoc/qdocfileoutput/qdoctests-outputfromqdocfiles.qdoc rename to tests/auto/qdoc/generatedoutput/testdata/scopedenum/scopedenum.qdoc index fc3a5d8701..1b1363db47 100644 --- a/tests/auto/qdoc/qdocfileoutput/qdoctests-outputfromqdocfiles.qdoc +++ b/tests/auto/qdoc/generatedoutput/testdata/scopedenum/scopedenum.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -26,33 +26,30 @@ ****************************************************************************/ /*! - \page qdoctests-qdocfileoutput.html - \title Testing QDoc output from .qdoc files - \brief This is a simple page for testing purposes only. + \enum TestQDoc::Test::ClassicEnum - QDoc generates documentation for software projects. It does this by - extracting \e {QDoc comments} from project source files. QDoc comments are - signified by a C-style-like comment tag followed by an exclamation point, - like this: - \beginqdoc \c {This text is contained within QDoc comment tags.} \endqdoc. + \value Yee + \value Haw + \value Howdy + \value Partner +*/ + +/*! + \enum TestQDoc::Test::ScopedEnum + + \value This Something + \value That Something else + \omitvalue OmittedValue + This decription is omitted + \value All Everything +*/ + +/*! + \page scoped-enum-linking.html + \title Enum Linking - \section1 Supported file types - QDoc parses \c .cpp and \c .qdoc files. It does extract comments from - header (\c {.h}) files. + Linking to \l {TestQDoc::Test::ScopedEnum::}{All}. - \section1 Further information - This test document is written with the purpose of testing the output QDoc - generates when parsing \c .qdoc files. It is fairly simple and makes use of - a limited subset of QDoc's command. Those commands are: - \list - \li \c {\page} - \li \c {\title} - \li \c {\brief} - \li \c {\e} (for emphasizing "QDoc comments") - \li \c {\c} (for multiple monospace-formatted entries) - \li \c {\section1} - \li \c {\list} - \li \c {\li} - \li \c {\endlist} - \endlist + TestQDoc::Test::ClassicEnum::Howdy does not link, + but TestQDoc::Test::Howdy might. */ diff --git a/tests/auto/qdoc/generatedoutput/testdata/singleexec/singleexec.qdocconf b/tests/auto/qdoc/generatedoutput/testdata/singleexec/singleexec.qdocconf new file mode 100644 index 0000000000..037cfc74a2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/singleexec/singleexec.qdocconf @@ -0,0 +1,2 @@ +../configs/testcpp_singleexec.qdocconf +../crossmodule/crossmodule_singleexec.qdocconf diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/TestCPP b/tests/auto/qdoc/generatedoutput/testdata/testcpp/TestCPP new file mode 100644 index 0000000000..4ed786108b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/TestCPP @@ -0,0 +1,5 @@ +#include "testcpp.h" + +#ifdef test_template +# include "testtemplate.h" +#endif diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/classlists.qdoc b/tests/auto/qdoc/generatedoutput/testdata/testcpp/classlists.qdoc new file mode 100644 index 0000000000..188676c054 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/classlists.qdoc @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page obsolete-classes.html + \title Obsolete Classes + + \section1 Classes with obsolete members + \generatelist obsoletecppmembers + + \section2 TestQDoc +*/ + +/*! + \page autolinking.html + \title Autolinking + + //! a section title that qualifies for autolinking + \section1 TestQDoc + + The string TestQDoc links to the C++ namespace unless linking explicitly, + \l {#TestQDoc}{like this}, or \l {TestQDoc}{this}. Also, + + Autolinks: + + \list + \li TestQDoc::TestDerived + \endlist + + Explicit links: + + \list + \li \l [CPP] {TestQDoc::TestDerived} + \li \l {Obsolete Classes#TestQDoc} + \endlist +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc b/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc new file mode 100644 index 0000000000..0ef6f4ea70 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/properties.qdoc @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \property TestQDoc::TestDerived::bindableProp + Some property. +*/ + +/*! + \property TestQDoc::TestDerived::someProp + Another property. +*/ + +/*! + \property TestQDoc::TestDerived::name + \brief a name. +*/ + +/*! + \property TestQDoc::TestDerived::intProp + An integer property. +*/ + +/*! + \property TestQDoc::TestDerived::boolProp + A boolean property. +*/ + +/*! + \fn TestQDoc::TestDerived::invokeMe() const + \brief Something invokable. +*/ + +/*! + //! avoid link warnings for auto-generated links to QProperty + \externalpage https://wiki.qt.io/QProperty + \title QProperty +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/snippets/snippet_testcpp.cpp b/tests/auto/qdoc/generatedoutput/testdata/testcpp/snippets/snippet_testcpp.cpp new file mode 100644 index 0000000000..1660fbc2b2 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/snippets/snippet_testcpp.cpp @@ -0,0 +1,3 @@ +//! [random tag] +You're not supposed to see this. +//! [random tag] diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp new file mode 100644 index 0000000000..0cdbf8f6fc --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testcpp.h" + +namespace TestQDoc { + +/* +//! [random tag] +\note This is just a test. +//! [random tag] +*/ + +/*! + \module TestCPP + \qtvariable testcpp + \qtcmakepackage QDocTest + \title QDoc Test C++ Classes + \brief A test module page. + + \testnoautolist + + \include testcpp.cpp random tag + +\if defined(test_nestedmacro) + \versionnote {module} {\ver} +\endif +*/ + +/*! + \namespace TestQDoc + \inheaderfile TestCPP + \inmodule TestCPP + \brief A namespace. + + \section1 Usage + This namespace is for testing QDoc output. +*/ + +/*! + \class TestQDoc::Test + \inmodule TestCPP + \brief A class in a namespace. + +\if defined(test_ignoresince) + //! omitted by ignoresince + \since 1.1 +\endif + \ingroup testgroup +*/ + +/*! + \fn TestQDoc::Test::Test() + + Default constructor. +*/ + +/*! + \fn Test &Test::operator=(Test &&other) + + Move-assigns \a other. +*/ + +/*! + \class TestQDoc::TestDerived + \inmodule TestCPP + \brief A derived class in a namespace. +*/ + +/*! + \macro QDOCTEST_MACRO + \relates TestQDoc +\if defined(test_ignoresince) + //! omitted by ignoresince.Test + \since Test 0.9 +\endif +*/ + +/*! + \macro QDOCTEST_MACRO2(int &x) + \relates TestQDoc::Test + \since Test 1.1 + \brief A macro with argument \a x. + \ingroup testgroup +*/ + +/*! + \deprecated + + Use someFunction() instead. +*/ +void Test::deprecatedMember() +{ + return; +} + +/*! + \obsolete + + Use someFunction() instead. +*/ +void Test::obsoleteMember() +{ + return; +} + +/*! + \obsolete Use obsoleteMember() instead. +*/ +void Test::anotherObsoleteMember() +{ + return; +} + +/*! + Function that takes a parameter \a i and \a b. +\if defined(test_ignoresince) + \since 2.0 +\endif + \ingroup testgroup +*/ +void Test::someFunctionDefaultArg(int i, bool b = false) +{ + return; +} + +/*! + \fn void Test::func(bool) + \internal +*/ + +/*! + \fn [funcPtr] void (*funcPtr(bool b, const char *s))(bool) + + Returns a pointer to a function that takes a boolean. Uses \a b and \a s. +*/ + +// Documented below with an \fn command. Unnecessary but we support it, and it's used. +int Test::someFunction(int, int v) +{ + return v; +} + +/*! + \fn void TestQDoc::Test::inlineFunction() + + \brief An inline function, documented using the \CMDFN QDoc command. +*/ + +/*! + \fn int Test::someFunction(int, int v = 0) + + Function that takes a parameter \a v. + Also returns the value of \a v. +\if defined(test_ignoresince) + \since Test 1.0 +\endif +*/ + +/*! + Function that must be reimplemented. +*/ +void Test::virtualFun() +{ + return; +} + +/*! + \fn bool Test::operator==(const Test &lhs, const Test &rhs) + + Returns true if \a lhs and \a rhs are equal. +*/ + +/*! + \typedef Test::SomeType + \brief A typedef. +*/ + +/*! + \reimp +*/ +void TestDerived::virtualFun() +{ + return; +} + +/*! + \fn TestQDoc::Test::overload() + \fn Test::overload(bool b) + //! The second overload should match even without the fully qualified path + + Overloads that share a documentation comment, optionally taking + a parameter \a b. +*/ + +/*! + \fn Test::overload(bool b) + \since Test 1.2 +*/ + +/*! + \typealias TestDerived::DerivedType + An aliased typedef. +*/ + +/*! + \typedef TestDerived::NotTypedef + I'm an alias, not a typedef. +*/ + +/*! + \obsolete + + Static obsolete method. +*/ +void TestDerived::staticObsoleteMember() +{ + return; +} + +/*! +\if defined(test_properties) + \fn void TestDerived::emitSomething() + Emitted when things happen. +\else + \nothing +\endif +*/ + +/*! +\if defined(test_template) + \fn template void TestQDoc::Test::funcTemplate(T1 a, T2 b) + \brief Function template with two parameters, \a a and \a b. +\else + \nothing +\endif +*/ + +/*! +\if defined(test_template) + \struct TestQDoc::Test::Struct + \inmodule TestCPP + \brief Templated struct. +\else + \nothing +\endif +*/ + +/*! +\if defined(test_template) + \typealias TestQDoc::Test::Specialized +\else + \nothing +\endif +*/ + +/*! +\if defined(test_template) + \class TestQDoc::Vec + \inmodule TestCPP + \brief Type alias that has its own reference. +\else + \nothing +\endif +*/ +} // namespace TestQDoc + +/*! + \class DontLinkToMe + \inmodule TestCPP + \brief Class that does not generate documentation. +*/ + +/*! + \dontdocument (DontLinkToMe) +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h new file mode 100644 index 0000000000..3556965284 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testcpp/testcpp.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#pragma once + +#ifdef test_properties +#include +#include +#include +#endif + +#define QDOCTEST_MACRO test +#define QDOCTEST_MACRO2(x) (x) < 0 ? 0 : (x)) + +namespace TestQDoc { + +class Test { +public: + +#ifdef test_template +template struct Struct {}; +template +using Specialized = Struct; +#endif + +#ifdef test_scopedenum + enum ClassicEnum { Yee, Haw, Howdy, Partner }; + + enum class ScopedEnum : unsigned char { + This = 0x01, + That = 0x02, + All = This | That, + OmittedValue = 99 + }; +#endif + typedef struct { + int data; + } SomeType; + int someFunction(int, int v = 0); + void someFunctionDefaultArg(int i, bool b); + void obsoleteMember(); + void anotherObsoleteMember(); + void deprecatedMember(); + void func(bool) {}; + //! [funcPtr] + void (*funcPtr(bool b, const char *s))(bool) { + return func; + } + inline void inlineFunction() {}; + virtual void virtualFun(); + + friend bool operator==(const Test &lhs, const Test &rhs) { return false; } + +protected: + void overload() {} + void overload(bool b) { if (!b) return; } +#ifdef test_template + template void funcTemplate(T1 a, T2 b) { + a = b; + } +#endif +}; + +class TestDerived : public Test { +#ifdef test_properties + Q_OBJECT + + Q_PROPERTY(QString bindableProp READ bindableProp WRITE setBindableProp NOTIFY bindablePropChanged BINDABLE bindableProp) + Q_PROPERTY(QString someProp READ someProp BINDABLE somBindableProp) + Q_PROPERTY(int *intProp READ getInt STORED false CONSTANT FINAL) + Q_PROPERTY(const QString *name READ name) + QDOC_PROPERTY(bool boolProp READ boolProp WRITE setBoolProp NOTIFY boolPropChanged RESET resetBoolProp REVISION 1) +#endif + +public: + using DerivedType = Test::SomeType; + using NotTypedef = int; + void virtualFun() override; + static void staticObsoleteMember(); +#ifdef test_properties + QBindable bindableProp(); + QBindable someBindableProp(); + const QString &someProp(); + int *getInt(); + bool boolProp(); + const QString *name() const; + + Q_INVOKABLE void invokeMe() const {} + +Q_SIGNALS: + void emitSomething(QPrivateSignal); + void bindablePropChanged(); + Q_REVISION(1) void boolPropChanged(); + +public Q_SLOTS: + void setBindableProp(const QString &s); + void setBoolProp(bool b); + void resetBoolProp(); +#endif +}; + +#ifdef test_template +template +struct BaseVec {}; +template +using Vec = BaseVec; +#endif + +} // namespace TestQDoc + +class DontLinkToMe {}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.cpp b/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.cpp new file mode 100644 index 0000000000..3214f4061b --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testtemplate.h" + +/*! + \class Foo + \inmodule TestCPP + \brief Class template. +*/ + +/*! + \class Bar + \inmodule TestCPP + \brief Another class template. +*/ + +/*! + //! Baz is a struct, QDoc auto-converts this to the correct type + \class Baz + \inmodule TestCPP + \brief Class template template. +*/ diff --git a/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.h b/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.h new file mode 100644 index 0000000000..d60ab0da45 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/testtemplate/testtemplate.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +template +class Foo { +public: + Foo() {} +private: + T t; +}; + +template +class Bar { +public: + Bar() {} +private: + T t; + D d; +}; + +template class X, typename Y> +struct Baz +{ + X z; + Baz() : z() {} +}; diff --git a/tests/auto/qdoc/generatedoutput/testdata/usingdirective/UsingDirective b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/UsingDirective new file mode 100644 index 0000000000..422d01e91c --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/UsingDirective @@ -0,0 +1,2 @@ +#include "alias.h" +#include "space.h" diff --git a/tests/auto/qdoc/generatedoutput/testdata/usingdirective/alias.h b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/alias.h new file mode 100644 index 0000000000..1fb9ee4710 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/alias.h @@ -0,0 +1,7 @@ +#pragma once + +#include "space.h" + +namespace Alias { + using spacename = Space::spacename; +} diff --git a/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.cpp b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.cpp new file mode 100644 index 0000000000..4a4962550e --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.cpp @@ -0,0 +1,18 @@ +#include "space.h" + +/*! + \namespace Space + \inmodule UsingDirective + \brief A namespace...in space. +*/ + +using namespace Alias; +using namespace Space; + +/*! + \relates Space + A \a space function. +*/ +void spaceFun(spacename space) +{ +} diff --git a/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.h b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.h new file mode 100644 index 0000000000..9ac01fba66 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/testdata/usingdirective/space.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Space { + typedef int spacename; +} + +void spaceFun(Space::spacename space); diff --git a/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp new file mode 100644 index 0000000000..9bfe6ed355 --- /dev/null +++ b/tests/auto/qdoc/generatedoutput/tst_generatedoutput.cpp @@ -0,0 +1,535 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include + +class tst_generatedOutput : public QObject +{ + Q_OBJECT + +public: + void setRegenerate() { m_regen = true; } + +private slots: + void initTestCase(); + void init(); + + // HTML generator + void htmlFromQDocFile(); + void htmlFromCpp(); + void htmlFromQml(); + void htmlFromCppBug80259(); + + // WebXML generator + void webXmlFromQDocFile(); + void webXmlFromCpp(); + void webXmlFromQml(); + void webXmlFromCppBug80259(); + + // DocBook generator + void docBookFromQDocFile(); + void docBookFromCpp(); + void docBookFromQml(); + + // Output format independent tests + void autoNavigation(); + void examplesManifestXmlAndQhp(); + void ignoresinceVariable(); + void templateParameters(); + void scopedEnum(); + void dontDocument(); + void inheritedQmlPropertyGroups(); + void crossModuleLinking(); + void indexLinking(); + void includeFromExampleDirs(); + void singleExec(); + void preparePhase(); + void generatePhase(); + void noAutoList(); + void nestedMacro(); + void headerFile(); + void usingDirective(); + void properties(); + void testTagFile(); + void testGlobalFunctions(); + +private: + QScopedPointer m_outputDir; + QString m_qdoc; + QDir m_expectedDir; + QString m_extraParams; + bool m_regen = false; + + void runQDocProcess(const QStringList &arguments); + void compareLineByLine(const QStringList &expectedFiles); + void testAndCompare(const char *input, const char *outNames, const char *extraParams = nullptr, + const char *outputPathPrefix = nullptr); + void copyIndexFiles(); +}; + +void tst_generatedOutput::initTestCase() +{ + // Build the path to the QDoc binary the same way moc tests do for moc. + const auto binpath = QLibraryInfo::path(QLibraryInfo::BinariesPath); + const auto extension = QSysInfo::productType() == "windows" ? ".exe" : ""; + m_qdoc = binpath + QLatin1String("/qdoc") + extension; + m_expectedDir.setPath(QFINDTESTDATA("expected_output")); + + // Resolve the path to the file containing extra parameters + m_extraParams = QFileInfo(QTest::currentAppName()).dir().filePath("qdocincludepaths.inc"); + if (!QFileInfo::exists(m_extraParams)) { + const QString warningMessage = "Cannot locate " + m_extraParams; + QWARN(qPrintable(warningMessage)); + m_extraParams.clear(); + } else { + m_extraParams.insert(0, '@'); + } +} + +void tst_generatedOutput::init() +{ + m_outputDir.reset(new QTemporaryDir()); + if (!m_outputDir->isValid()) { + const QString errorMessage = + "Couldn't create temporary directory: " + m_outputDir->errorString(); + QFAIL(qPrintable(errorMessage)); + } +} + +void tst_generatedOutput::runQDocProcess(const QStringList &arguments) +{ + QProcess qdocProcess; + qdocProcess.setProgram(m_qdoc); + qdocProcess.setArguments(arguments); + qdocProcess.start(); + qdocProcess.waitForFinished(); + + if (qdocProcess.exitCode() == 0) + return; + + QString output = qdocProcess.readAllStandardOutput(); + QString errors = qdocProcess.readAllStandardError(); + + qInfo() << "QDoc exited with exit code" << qdocProcess.exitCode(); + if (output.size() > 0) + qInfo().nospace() << "Received output:\n" << qUtf8Printable(output); + if (errors.size() > 0) + qInfo().nospace() << "Received errors:\n" << qUtf8Printable(errors); + + QFAIL("Running QDoc failed. See output above."); +} + +void tst_generatedOutput::compareLineByLine(const QStringList &expectedFiles) +{ + for (const auto &file : expectedFiles) { + QString expected(m_expectedDir.filePath(file)); + QString actual(m_outputDir->filePath(file)); + + QFile expectedFile(expected); + if (!expectedFile.open(QIODevice::ReadOnly)) + QFAIL("Cannot open expected data file!"); + QTextStream expectedIn(&expectedFile); + + QFile actualFile(actual); + if (!actualFile.open(QIODevice::ReadOnly)) + QFAIL("Cannot open actual data file!"); + QTextStream actualIn(&actualFile); + + const QLatin1String delim(": "); + int lineNumber = 0; + while (!expectedIn.atEnd() && !actualIn.atEnd()) { + lineNumber++; + QString prefix = file + delim + QString::number(lineNumber) + delim; + QString expectedLine = prefix + expectedIn.readLine(); + QString actualLine = prefix + actualIn.readLine(); + QCOMPARE(actualLine, expectedLine); + } + } +} + +void tst_generatedOutput::testAndCompare(const char *input, const char *outNames, + const char *extraParams, const char *outputPathPrefix) +{ + QStringList args { "-outputdir", m_outputDir->path() + "/" + outputPathPrefix, + QFINDTESTDATA(input) }; + if (extraParams) + args << QString(QLatin1String(extraParams)).split(QChar(' ')); + + runQDocProcess(args); + + if (QTest::currentTestFailed()) + return; + + QStringList expectedOuts(QString(QLatin1String(outNames)).split(QChar(' '))); + if (outputPathPrefix) + for (auto &expectedOut : expectedOuts) + expectedOut = QString(outputPathPrefix) + "/" + expectedOut; + + if (m_regen) { + QVERIFY(m_expectedDir.mkpath(m_expectedDir.path())); + for (const auto &file : qAsConst(expectedOuts)) { + QFileInfo fileInfo(m_expectedDir.filePath(file)); + fileInfo.dir().remove(fileInfo.fileName()); // Allowed to fail + QVERIFY(m_expectedDir.mkpath(fileInfo.dir().path())); + QVERIFY(QFile::copy(m_outputDir->filePath(file), + fileInfo.filePath())); + } + QSKIP("Regenerated expected output only."); + } + + compareLineByLine(expectedOuts); +} + +// Copy .index to /.index in the outputdir +void tst_generatedOutput::copyIndexFiles() +{ + QDirIterator it(m_outputDir->path(), QStringList("*.index"), QDir::Files, QDirIterator::Subdirectories); + while (it.hasNext()) { + QFileInfo fileInfo(it.next()); + QDir indexDir(m_outputDir->path()); + QVERIFY(indexDir.mkpath(fileInfo.baseName())); + QVERIFY(indexDir.cd(fileInfo.baseName())); + if (!indexDir.exists(fileInfo.fileName())) + QVERIFY(QFile::copy(fileInfo.filePath(), indexDir.filePath(fileInfo.fileName()))); + } +} + +void tst_generatedOutput::htmlFromQDocFile() +{ + testAndCompare("testdata/configs/test.qdocconf", + "qdoctests-qdocfileoutput.html " + "qdoctests-qdocfileoutput-linking.html " + "qdoctests-qdocfileoutput-exhaustive.html " + "toc.html"); +} + +void tst_generatedOutput::htmlFromCpp() +{ + testAndCompare("testdata/configs/testcpp.qdocconf", + "testcpp-module.html " + "testqdoc-test.html " + "testqdoc-test-members.html " + "testqdoc-testderived.html " + "testqdoc-testderived-members.html " + "testqdoc-testderived-obsolete.html " + "obsolete-classes.html " + "autolinking.html " + "testqdoc.html"); +} + +void tst_generatedOutput::htmlFromQml() +{ + testAndCompare("testdata/configs/testqml.qdocconf", + "qmlmodules.html " + "test-componentset-example.html " + "test-cmaketest-example.html " + "uicomponents-qmlmodule.html " + "qdoc-test-qmlmodule.html " + "qml-qdoc-test-abstractparent.html " + "qml-qdoc-test-child.html " + "qml-qdoc-test-yetanotherchild.html " + "qml-qdoc-test-doctest.html " + "qml-qdoc-test-type-members.html " + "qml-qdoc-test-type.html " + "qml-uicomponents-progressbar.html " + "qml-uicomponents-switch.html " + "qml-uicomponents-tabwidget.html " + "qml-int.html"); +} + +void tst_generatedOutput::htmlFromCppBug80259() +{ + testAndCompare("testdata/bug80259/testmodule.qdocconf", + "first.html " + "second.html " + "third.html " + "index.html"); +} + +void tst_generatedOutput::webXmlFromQDocFile() +{ + testAndCompare("testdata/configs/webxml_test.qdocconf", + "html/qdoctests-qdocfileoutput.webxml " + "html/qdoctests-qdocfileoutput-linking.webxml " + "html/qdoctests-qdocfileoutput-exhaustive.webxml"); +} + +void tst_generatedOutput::webXmlFromCpp() +{ + testAndCompare("testdata/configs/webxml_testcpp.qdocconf", + "html/testcpp-module.webxml " + "html/testqdoc-test.webxml " + "html/testqdoc-testderived.webxml"); +} + +void tst_generatedOutput::webXmlFromQml() +{ + testAndCompare("testdata/configs/webxml_testqml.qdocconf", + "html/test-componentset-example.webxml " + "html/uicomponents-qmlmodule.webxml"); +} + +void tst_generatedOutput::webXmlFromCppBug80259() +{ + testAndCompare("testdata/bug80259/webxml_testmodule.qdocconf", + "html/first.webxml " + "html/second.webxml " + "html/third.webxml " + "html/index.webxml"); +} + +void tst_generatedOutput::docBookFromQDocFile() +{ + testAndCompare("testdata/configs/docbook_test.qdocconf", + "docbook/qdoctests-qdocfileoutput.xml " + "docbook/qdoctests-qdocfileoutput-linking.xml " + "docbook/qdoctests-qdocfileoutput-exhaustive.xml"); +} + +void tst_generatedOutput::docBookFromCpp() +{ + testAndCompare("testdata/configs/docbook_testcpp.qdocconf", + "docbook/testcpp-module.xml " + "docbook/testqdoc-test.xml " + "docbook/testqdoc-testderived.xml " + "docbook/testqdoc.xml"); +} + +void tst_generatedOutput::docBookFromQml() +{ + testAndCompare("testdata/configs/docbook_testqml.qdocconf", + "docbook/test-componentset-example.xml " + "docbook/uicomponents-qmlmodule.xml " + "docbook/qdoc-test-qmlmodule.xml " + "docbook/qml-qdoc-test-abstractparent.xml " + "docbook/qml-qdoc-test-child.xml " + "docbook/qml-qdoc-test-yetanotherchild.xml " + "docbook/qml-qdoc-test-doctest.xml " + "docbook/qml-qdoc-test-type.xml " + "docbook/qml-uicomponents-progressbar.xml " + "docbook/qml-uicomponents-switch.xml " + "docbook/qml-uicomponents-tabwidget.xml " + "docbook/qml-int.xml"); +} + +void tst_generatedOutput::autoNavigation() +{ + // Same expected files as htmlFromQdocFile, but with auto-generated navigation links + testAndCompare("testdata/configs/tocnavigation.qdocconf", + "qdoctests-qdocfileoutput.html " + "qdoctests-qdocfileoutput-linking.html " + "qdoctests-qdocfileoutput-exhaustive.html " + "toc.html"); +} + +void tst_generatedOutput::examplesManifestXmlAndQhp() +{ + testAndCompare("testdata/configs/examples-qhp.qdocconf", + "examples-manifest.xml " + "demos-manifest.xml " + "test.qhp"); +} + +void tst_generatedOutput::ignoresinceVariable() +{ + testAndCompare("testdata/configs/ignoresince.qdocconf", + "ignoresince/testqdoc.html " + "ignoresince/testqdoc-test.html"); +} + +void tst_generatedOutput::templateParameters() +{ + testAndCompare("testdata/configs/testtemplate.qdocconf", + "template/testqdoc-test.html " + "template/testqdoc-test-struct.html " + "template/testqdoc-vec.html " + "template/foo.html " + "template/bar.html " + "template/baz.html"); +} + +void tst_generatedOutput::scopedEnum() +{ + testAndCompare("testdata/configs/scopedenum.qdocconf", + "scopedenum/testqdoc-test.html " + "scopedenum/scoped-enum-linking.html " + "scopedenum-docbook/scoped-enum-linking.xml " + "scopedenum-docbook/testqdoc-test.xml"); +} + +void tst_generatedOutput::dontDocument() +{ + testAndCompare("testdata/dontdocument/dontdocument.qdocconf", + "dontdocument/classes.html " + "dontdocument/seenclass.html " + "dontdocument/dontdocument.qhp"); +} + +void tst_generatedOutput::inheritedQmlPropertyGroups() +{ + testAndCompare("testdata/qmlpropertygroups/qmlpropertygroups.qdocconf", + "qmlpropertygroups/qml-qdoc-test-anotherchild-members.html " + "qmlpropertygroups/qml-qdoc-test-parent.html " + "qmlpropertygroups-docbook/qml-qdoc-test-parent.xml"); +} + +void tst_generatedOutput::indexLinking() +{ + { + QScopedValueRollback skipRegen(m_regen, false); + inheritedQmlPropertyGroups(); + } + copyIndexFiles(); + QString indexDir = QLatin1String("-indexdir ") + m_outputDir->path(); + testAndCompare("testdata/indexlinking/indexlinking.qdocconf", + "index-linking.html " + "qml-linkmodule-grandchild-members.html", + indexDir.toLatin1().data()); +} + +void tst_generatedOutput::crossModuleLinking() +{ + { + QScopedValueRollback skipRegen(m_regen, false); + htmlFromCpp(); + } + copyIndexFiles(); + QString indexDir = QLatin1String("-indexdir ") + m_outputDir->path(); + testAndCompare("testdata/crossmodule/crossmodule.qdocconf", + "crossmodule/testtype.html " + "crossmodule/testtype-members.html", + indexDir.toLatin1().data()); +} + +void tst_generatedOutput::includeFromExampleDirs() +{ + testAndCompare("testdata/includefromexampledirs/includefromexampledirs.qdocconf", + "includefromexampledirs/index.html " + "includefromexampledirs/qml-qdoc-test-abstractparent.html " + "includefromexampledirs/qml-qdoc-test-abstractparent-members.html"); +} + +void tst_generatedOutput::singleExec() +{ + // Build both testcpp and crossmodule projects in single-exec mode + testAndCompare("testdata/singleexec/singleexec.qdocconf", + "testcpp-module.html " + "testqdoc-test.html " + "testqdoc-test-members.html " + "testqdoc.html " + "crossmodule/testtype.html " + "crossmodule/testtype-members.html", + "-single-exec"); +} + +void tst_generatedOutput::preparePhase() +{ + testAndCompare("testdata/configs/testcpp.qdocconf", + "testcpp.index", + "-prepare"); +} + +void tst_generatedOutput::generatePhase() +{ + testAndCompare("testdata/configs/testcpp.qdocconf", + "testcpp-module.html " + "testqdoc-test.html " + "testqdoc-test-members.html " + "testqdoc.html", + "-generate"); +} + +void tst_generatedOutput::noAutoList() +{ + testAndCompare("testdata/configs/noautolist.qdocconf", + "noautolist/testcpp-module.html " + "noautolist/test-componentset-example.html " + "noautolist/qdoc-test-qmlmodule.html " + "noautolist-docbook/testcpp-module.xml " + "noautolist-docbook/test-componentset-example.xml " + "noautolist-docbook/qdoc-test-qmlmodule.xml"); +} + +void tst_generatedOutput::nestedMacro() +{ + testAndCompare("testdata/configs/nestedmacro.qdocconf", + "nestedmacro/testcpp-module.html"); +} + +void tst_generatedOutput::headerFile() +{ + testAndCompare("testdata/configs/headerfile.qdocconf", + "headerfile/testheader.html " + "headerfile/headers.html " + "headerfile-docbook/testheader.xml " + "headerfile-docbook/headers.xml"); +} + +void tst_generatedOutput::usingDirective() +{ + testAndCompare("testdata/configs/usingdirective.qdocconf", "space.html"); +} + +void tst_generatedOutput::properties() +{ + if (m_extraParams.isEmpty() && !m_regen) { + QSKIP("Required include paths not available"); + } + + testAndCompare("testdata/configs/properties.qdocconf", + "properties/testqdoc-testderived.html " + "properties/testqdoc-testderived-members.html " + "properties/testcpp.index " + "properties-docbook/testqdoc-testderived.xml", + m_extraParams.toLatin1().data()); +} + +void tst_generatedOutput::testTagFile() +{ + testAndCompare("testdata/configs/tagfiles.qdocconf", "testtagfile.tags"); +} + +void tst_generatedOutput::testGlobalFunctions() +{ + testAndCompare("testdata/configs/testglobals.qdocconf", "globals.html"); +} + +int main(int argc, char *argv[]) +{ + tst_generatedOutput tc; + // Re-populate expected data and skip tests if option -regenerate is set + if (argc == 2 && QByteArray(argv[1]) == "-regenerate") { + tc.setRegenerate(); + --argc; + } + return QTest::qExec(&tc, argc, argv); +} + +#include "tst_generatedoutput.moc" diff --git a/tests/auto/qdoc/qdoc.pro b/tests/auto/qdoc/qdoc.pro deleted file mode 100644 index fd4953df89..0000000000 --- a/tests/auto/qdoc/qdoc.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = \ - qdocfileoutput \ - qdocglobals - diff --git a/tests/auto/qdoc/qdoccommandlineparser/CMakeLists.txt b/tests/auto/qdoc/qdoccommandlineparser/CMakeLists.txt new file mode 100644 index 0000000000..46aed69a51 --- /dev/null +++ b/tests/auto/qdoc/qdoccommandlineparser/CMakeLists.txt @@ -0,0 +1,27 @@ +# Generated from qdoccommandlineparser.pro. + +##################################################################### +## tst_qdoccommandlineparser Test: +##################################################################### + +qt_internal_add_test(tst_qdoccommandlineparser + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" # special case + SOURCES + ../../../../src/qdoc/qdoccommandlineparser.cpp ../../../../src/qdoc/qdoccommandlineparser.h + tst_qdoccommandlineparser.cpp + INCLUDE_DIRECTORIES + ../../../../src/qdoc +) + +# Resources: +set(tst_qdoccommandlineparser_resource_files + "tst_arguments.txt" +) + +qt_internal_add_resource(tst_qdoccommandlineparser "tst_qdoccommandlineparser" + PREFIX + "/" + FILES + ${tst_qdoccommandlineparser_resource_files} +) + diff --git a/tests/auto/qdoc/qdoccommandlineparser/tst_arguments.txt b/tests/auto/qdoc/qdoccommandlineparser/tst_arguments.txt new file mode 100644 index 0000000000..5797de394a --- /dev/null +++ b/tests/auto/qdoc/qdoccommandlineparser/tst_arguments.txt @@ -0,0 +1,22 @@ +-outputdir +/src/qt5/qtbase/doc/qtgamepad +-installdir +/src/qt5/qtbase/doc +/src/qt5/qtgamepad/src/gamepad/doc/qtgamepad.qdocconf +-prepare +-indexdir +/src/qt5/qtbase/doc +-no-link-errors +-I. +-I/src/qt5/qtbase/include +-I/src/qt5/qtbase/include/QtGamepad +-I/src/qt5/qtbase/include/QtGamepad/5.14.0 +-I/src/qt5/qtbase/include/QtGamepad/5.14.0/QtGamepad +-I/src/qt5/qtbase/include/QtCore/5.14.0 +-I/src/qt5/qtbase/include/QtCore/5.14.0/QtCore +-I/src/qt5/qtbase/include/QtGui +-I/src/qt5/qtbase/include/QtCore +-I.moc +-isystem +/usr/include/libdrm +-I/src/qt5/qtbase/mkspecs/linux-g++ diff --git a/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.cpp b/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.cpp new file mode 100644 index 0000000000..ae228cd5d5 --- /dev/null +++ b/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdoccommandlineparser.h" + +#include +#include + +class tst_QDocCommandLineParser : public QObject +{ + Q_OBJECT + +private slots: + void defaultConstructor(); + void process(); + void argumentsFromCommandLineAndFile(); +}; + +void tst_QDocCommandLineParser::defaultConstructor() +{ + QDocCommandLineParser parser; + + QVERIFY2(parser.applicationDescription() == QStringLiteral("Qt documentation generator"), + "The application description is incorrect."); +} + +void tst_QDocCommandLineParser::process() +{ + const QStringList arguments = + QStringLiteral("/src/qt5/qtbase/bin/qdoc " + "-outputdir " + "/src/qt5/qtbase/doc/qtgamepad " + "-installdir " + "/src/qt5/qtbase/doc " + "/src/qt5/qtgamepad/src/gamepad/doc/qtgamepad.qdocconf " + "-prepare " + "-indexdir " + "/src/qt5/qtbase/doc " + "-no-link-errors " + "-I. " + "-I/src/qt5/qtbase/include " + "-I/src/qt5/qtbase/include/QtGamepad " + "-I/src/qt5/qtbase/include/QtGamepad/5.14.0 " + "-I/src/qt5/qtbase/include/QtGamepad/5.14.0/QtGamepad " + "-I/src/qt5/qtbase/include/QtCore/5.14.0 " + "-I/src/qt5/qtbase/include/QtCore/5.14.0/QtCore " + "-I/src/qt5/qtbase/include/QtGui " + "-I/src/qt5/qtbase/include/QtCore " + "-I.moc " + "-isystem " + "/usr/include/libdrm " + "-I/src/qt5/qtbase/mkspecs/linux-g++" + ).split(QString(" ")); + const QStringList expectedIncludePaths = + QStringLiteral(". " + "/src/qt5/qtbase/include " + "/src/qt5/qtbase/include/QtGamepad " + "/src/qt5/qtbase/include/QtGamepad/5.14.0 " + "/src/qt5/qtbase/include/QtGamepad/5.14.0/QtGamepad " + "/src/qt5/qtbase/include/QtCore/5.14.0 " + "/src/qt5/qtbase/include/QtCore/5.14.0/QtCore " + "/src/qt5/qtbase/include/QtGui " + "/src/qt5/qtbase/include/QtCore " + ".moc " + "/src/qt5/qtbase/mkspecs/linux-g++" + ).split(QString(" ")); + const QStringList expectedSystemIncludePath(QStringLiteral("/usr/include/libdrm")); + + QDocCommandLineParser parser; + parser.process(arguments); + + QVERIFY(parser.isSet(parser.outputDirOption)); + QCOMPARE(parser.value(parser.outputDirOption), QStringLiteral("/src/qt5/qtbase/doc/qtgamepad")); + QVERIFY(parser.isSet(parser.installDirOption)); + QCOMPARE(parser.value(parser.installDirOption), QStringLiteral("/src/qt5/qtbase/doc")); + QVERIFY(parser.isSet(parser.prepareOption)); + QVERIFY(parser.isSet(parser.indexDirOption)); + QCOMPARE(parser.value(parser.indexDirOption), QStringLiteral("/src/qt5/qtbase/doc")); + QVERIFY(parser.isSet(parser.noLinkErrorsOption)); + QVERIFY(parser.isSet(parser.includePathOption)); + QCOMPARE(parser.values(parser.includePathOption), expectedIncludePaths); + QVERIFY(parser.isSet(parser.includePathSystemOption)); + QCOMPARE(parser.values(parser.includePathSystemOption), expectedSystemIncludePath); + + QVERIFY(!parser.isSet(parser.timestampsOption)); + QVERIFY(!parser.isSet(parser.dependsOption)); + QVERIFY(!parser.isSet(parser.highlightingOption)); + QVERIFY(!parser.isSet(parser.showInternalOption)); + QVERIFY(!parser.isSet(parser.redirectDocumentationToDevNullOption)); + QVERIFY(!parser.isSet(parser.noExamplesOption)); + QVERIFY(!parser.isSet(parser.autoLinkErrorsOption)); + QVERIFY(!parser.isSet(parser.debugOption)); + QVERIFY(!parser.isSet(parser.generateOption)); + QVERIFY(!parser.isSet(parser.logProgressOption)); + QVERIFY(!parser.isSet(parser.singleExecOption)); + QVERIFY(!parser.isSet(parser.frameworkOption)); + + const QStringList expectedPositionalArgument = { + QStringLiteral("/src/qt5/qtgamepad/src/gamepad/doc/qtgamepad.qdocconf") + }; + QCOMPARE(parser.positionalArguments(), expectedPositionalArgument); +} + +void tst_QDocCommandLineParser::argumentsFromCommandLineAndFile() +{ + const QString atFilePath("@" + QFINDTESTDATA("tst_arguments.txt")); + const QStringList arguments { "/src/qt5/qtbase/bin/qdoc", atFilePath }; + + QDocCommandLineParser parser; + parser.process(arguments); + + const QStringList expectedIncludePaths = + QStringLiteral(". " + "/src/qt5/qtbase/include " + "/src/qt5/qtbase/include/QtGamepad " + "/src/qt5/qtbase/include/QtGamepad/5.14.0 " + "/src/qt5/qtbase/include/QtGamepad/5.14.0/QtGamepad " + "/src/qt5/qtbase/include/QtCore/5.14.0 " + "/src/qt5/qtbase/include/QtCore/5.14.0/QtCore " + "/src/qt5/qtbase/include/QtGui " + "/src/qt5/qtbase/include/QtCore " + ".moc " + "/src/qt5/qtbase/mkspecs/linux-g++" + ).split(QString(" ")); + const QStringList expectedSystemIncludePath(QStringLiteral("/usr/include/libdrm")); + const QStringList expectedPositionalArgument = { + QStringLiteral("/src/qt5/qtgamepad/src/gamepad/doc/qtgamepad.qdocconf") + }; + + QVERIFY(parser.isSet(parser.outputDirOption)); + QCOMPARE(parser.value(parser.outputDirOption), QStringLiteral("/src/qt5/qtbase/doc/qtgamepad")); + QVERIFY(parser.isSet(parser.installDirOption)); + QCOMPARE(parser.value(parser.installDirOption), QStringLiteral("/src/qt5/qtbase/doc")); + QVERIFY(parser.isSet(parser.prepareOption)); + QVERIFY(parser.isSet(parser.indexDirOption)); + QCOMPARE(parser.value(parser.indexDirOption), QStringLiteral("/src/qt5/qtbase/doc")); + QVERIFY(parser.isSet(parser.noLinkErrorsOption)); + QVERIFY(parser.isSet(parser.includePathOption)); + QCOMPARE(parser.values(parser.includePathOption), expectedIncludePaths); + QVERIFY(parser.isSet(parser.includePathSystemOption)); + QCOMPARE(parser.values(parser.includePathSystemOption), expectedSystemIncludePath); + + QVERIFY(!parser.isSet(parser.timestampsOption)); + QVERIFY(!parser.isSet(parser.dependsOption)); + QVERIFY(!parser.isSet(parser.highlightingOption)); + QVERIFY(!parser.isSet(parser.showInternalOption)); + QVERIFY(!parser.isSet(parser.redirectDocumentationToDevNullOption)); + QVERIFY(!parser.isSet(parser.noExamplesOption)); + QVERIFY(!parser.isSet(parser.autoLinkErrorsOption)); + QVERIFY(!parser.isSet(parser.debugOption)); + QVERIFY(!parser.isSet(parser.generateOption)); + QVERIFY(!parser.isSet(parser.logProgressOption)); + QVERIFY(!parser.isSet(parser.singleExecOption)); + QVERIFY(!parser.isSet(parser.frameworkOption)); + + QCOMPARE(parser.positionalArguments(), expectedPositionalArgument); +} + +QTEST_APPLESS_MAIN(tst_QDocCommandLineParser) + +#include "tst_qdoccommandlineparser.moc" diff --git a/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.qrc b/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.qrc new file mode 100644 index 0000000000..9a45cf68c5 --- /dev/null +++ b/tests/auto/qdoc/qdoccommandlineparser/tst_qdoccommandlineparser.qrc @@ -0,0 +1,5 @@ + + + tst_arguments.txt + + diff --git a/tests/auto/qdoc/qdocfileoutput/qdocfileoutput.pro b/tests/auto/qdoc/qdocfileoutput/qdocfileoutput.pro deleted file mode 100644 index a03f5ab6e6..0000000000 --- a/tests/auto/qdoc/qdocfileoutput/qdocfileoutput.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -QT = core testlib - -TARGET = tst_qdocfileoutput - -SOURCES += \ - tst_qdocfileoutput.cpp - -QMAKE_DOCS = $$PWD/test.qdocconf diff --git a/tests/auto/qdoc/qdocfileoutput/test.qdocconf b/tests/auto/qdoc/qdocfileoutput/test.qdocconf deleted file mode 100644 index 47ed6a919d..0000000000 --- a/tests/auto/qdoc/qdocfileoutput/test.qdocconf +++ /dev/null @@ -1,11 +0,0 @@ -project = Test -description = "A test project for QDoc build artifacts" -moduleheader = - -headerdirs = . -sourcedirs = . - -sources.fileextensions = *.qdoc - -macro.beginqdoc = "\\c {/*!}" -macro.endqdoc = "\\c */" diff --git a/tests/auto/qdoc/qdocfileoutput/tst_qdocfileoutput.cpp b/tests/auto/qdoc/qdocfileoutput/tst_qdocfileoutput.cpp deleted file mode 100644 index 1be5197861..0000000000 --- a/tests/auto/qdoc/qdocfileoutput/tst_qdocfileoutput.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include -#include -#include - -class tstQDocFileOutput : public QObject -{ - Q_OBJECT - -private slots: - void initTestCase(); - void compareQDocOutputWithExpectedData(); - -private: - QTemporaryDir m_outputDir; -}; - -void tstQDocFileOutput::initTestCase() -{ - if (!m_outputDir.isValid()) { - const QString errorMessage = - "Couldn't create temporary directory:" + m_outputDir.errorString(); - QFAIL(qPrintable(errorMessage)); - } -} - -void tstQDocFileOutput::compareQDocOutputWithExpectedData() -{ - // Build the path to the QDoc binary the same way moc tests do for moc. - QString binpath = QLibraryInfo::location(QLibraryInfo::BinariesPath); - QString extension; - if (QSysInfo::productType() == "windows") - extension += ".exe"; - const QString qdoc = QString("%1/qdoc" + extension).arg(binpath); - - const QStringList arguments = { - "--outputdir", - m_outputDir.path(), - QFINDTESTDATA("test.qdocconf") - }; - - QProcess qdocProcess; - qdocProcess.setProgram(qdoc); - qdocProcess.setArguments(arguments); - qdocProcess.start(); - qdocProcess.waitForFinished(); - QString output(qdocProcess.readAllStandardOutput()); - QString errors(qdocProcess.readAllStandardError()); - - if (qdocProcess.exitCode() != 0) { - qInfo() << "QDoc exited with exit code" << qdocProcess.exitCode(); - if (output.size() > 0) - qInfo() << "Received output:\n" << output; - if (errors.size() > 0) - qInfo() << "Received errors:\n" << errors; - QFAIL("Running QDoc failed. See output above."); - } - - QFile expected(QFINDTESTDATA("/expected_output/qdoctests-qdocfileoutput.html")); - QFile actual(m_outputDir.path() + "/qdoctests-qdocfileoutput.html"); - - if (!expected.open(QIODevice::ReadOnly)) - QFAIL("Cannot open expected data file!"); - QTextStream expectedIn(&expected); - - if (!actual.open(QIODevice::ReadOnly)) - QFAIL("Cannot open actual data file!"); - QTextStream actualIn(&actual); - - int lineNumber = 0; - while (!expectedIn.atEnd()) { - while (!actualIn.atEnd()) { - lineNumber++; - QString expectedLine = - QString::number(lineNumber) + ": " + expectedIn.readLine(); - QString actualLine = - QString::number(lineNumber) + ": " + actualIn.readLine(); - QCOMPARE(expectedLine, actualLine); - } - } -} - -QTEST_APPLESS_MAIN(tstQDocFileOutput) - -#include "tst_qdocfileoutput.moc" diff --git a/tests/auto/qdoc/qdocglobals/qdocglobals.pro b/tests/auto/qdoc/qdocglobals/qdocglobals.pro deleted file mode 100644 index fa7ddb8e0c..0000000000 --- a/tests/auto/qdoc/qdocglobals/qdocglobals.pro +++ /dev/null @@ -1,9 +0,0 @@ -CONFIG += testcase -QT = core testlib -TARGET = tst_qdocglobals -INCLUDEPATH += $$PWD/../../../../src/qdoc - -HEADERS += $$PWD/../../../../src/qdoc/qdocglobals.h - -SOURCES += $$PWD/../../../../src/qdoc/qdocglobals.cpp \ - tst_qdocglobals.cpp diff --git a/tests/auto/qdoc/qdocglobals/tst_qdocglobals.cpp b/tests/auto/qdoc/qdocglobals/tst_qdocglobals.cpp deleted file mode 100644 index 286363500f..0000000000 --- a/tests/auto/qdoc/qdocglobals/tst_qdocglobals.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdocglobals.h" - -#include -#include -#include - -class testQDocGlobals : public QObject -{ - Q_OBJECT - -private slots: - void testClassMembersInitializeToFalseOrEmpty(); - void testEnableHighlighting(); - void testSetShowInternal(); - void testSetSingleExec(); - void testSetWriteQaPages(); - void testRedirectDocumentationToDevNull(); - void testSetNoLinkErrors(); - void testSetAutoLinkErrors(); - void testSetObsoleteLinks(); - - void testAddDefine(); - void testAddIncludePath(); - void testDependModules(); - void testAppendToIndexDirs(); - void testSetCurrentDir(); - void testPreviousCurrentDir(); - void testDefaults(); -}; - -void testQDocGlobals::testClassMembersInitializeToFalseOrEmpty() -{ - QDocGlobals qdocTestGlobals; - QCOMPARE(qdocTestGlobals.highlighting(), false); - QCOMPARE(qdocTestGlobals.showInternal(), false); - QCOMPARE(qdocTestGlobals.singleExec(), false); - QCOMPARE(qdocTestGlobals.writeQaPages(), false); - QCOMPARE(qdocTestGlobals.redirectDocumentationToDevNull(), false); - QCOMPARE(qdocTestGlobals.noLinkErrors(), false); - QCOMPARE(qdocTestGlobals.autolinkErrors(), false); - QCOMPARE(qdocTestGlobals.obsoleteLinks(), false); - - QVERIFY(qdocTestGlobals.defines().isEmpty()); - QVERIFY(qdocTestGlobals.includesPaths().isEmpty()); - QVERIFY(qdocTestGlobals.dependModules().isEmpty()); - QVERIFY(qdocTestGlobals.indexDirs().isEmpty()); - QVERIFY(qdocTestGlobals.currentDir().isEmpty()); - QVERIFY(qdocTestGlobals.previousCurrentDir().isEmpty()); - QVERIFY(qdocTestGlobals.defaults().isEmpty()); -} - -void testQDocGlobals::testEnableHighlighting() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.enableHighlighting(true); - QVERIFY(qdocTestGlobals.highlighting()); -} - -void testQDocGlobals::testSetShowInternal() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setShowInternal(true); - QVERIFY(qdocTestGlobals.showInternal()); -} - -void testQDocGlobals::testSetSingleExec() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setSingleExec(true); - QVERIFY(qdocTestGlobals.singleExec()); -} - -void testQDocGlobals::testSetWriteQaPages() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setWriteQaPages(true); - QVERIFY(qdocTestGlobals.writeQaPages()); -} - -void testQDocGlobals::testRedirectDocumentationToDevNull() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setRedirectDocumentationToDevNull(true); - QVERIFY(qdocTestGlobals.redirectDocumentationToDevNull()); -} - -void testQDocGlobals::testSetNoLinkErrors() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setNoLinkErrors(true); - QVERIFY(qdocTestGlobals.noLinkErrors()); -} - -void testQDocGlobals::testSetAutoLinkErrors() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setAutolinkErrors(true); - QVERIFY(qdocTestGlobals.autolinkErrors()); -} - -void testQDocGlobals::testSetObsoleteLinks() -{ - QDocGlobals qdocTestGlobals; - qdocTestGlobals.setObsoleteLinks(true); - QVERIFY(qdocTestGlobals.obsoleteLinks()); -} - -void testQDocGlobals::testAddDefine() -{ - QDocGlobals qdocTestGlobals; - QStringList defineTestList1 = { QStringLiteral("qtforpython") }; - QStringList defineTestList2 = { QStringLiteral("example") }; - QStringList expected; - expected << defineTestList1 << defineTestList2; - - qdocTestGlobals.addDefine(defineTestList1); - QCOMPARE(qdocTestGlobals.defines().size(), 1); - qdocTestGlobals.addDefine(defineTestList2); - QCOMPARE(qdocTestGlobals.defines().size(), 2); - QCOMPARE(qdocTestGlobals.defines(), expected); -} - -void testQDocGlobals::testAddIncludePath() -{ - QDocGlobals qdocTestGlobals; - QString testFlag = "-I"; - QString testPath0 = "/qt5/qtdoc/doc/."; - QString testPath1 = "/qt5/qtbase/mkspecs/linux-g++"; - QStringList expected = { "-I/qt5/qtdoc/doc/.", - "-I/qt5/qtbase/mkspecs/linux-g++" }; - - qdocTestGlobals.addIncludePath(testFlag, testPath0); - qdocTestGlobals.addIncludePath(testFlag, testPath1); - QStringList result = qdocTestGlobals.includesPaths(); - QCOMPARE(result, expected); -} - -void testQDocGlobals::testDependModules() -{ - QDocGlobals qdocTestGlobals; - QStringList expected = { "qdoc", "qmake", "qtcore", "qthelp", "qtqml" }; - - qdocTestGlobals.dependModules() = expected; - QCOMPARE(qdocTestGlobals.dependModules().size(), 5); - QCOMPARE(qdocTestGlobals.dependModules(), expected); -} - -void testQDocGlobals::testAppendToIndexDirs() -{ - QDocGlobals qdocTestGlobals; - QString testPath = "/qt5/qtbase/doc"; - QStringList expected; - expected << testPath; - - qdocTestGlobals.appendToIndexDirs(testPath); - QCOMPARE(qdocTestGlobals.indexDirs(), expected); -} - -void testQDocGlobals::testSetCurrentDir() -{ - QDocGlobals qdocTestGlobals; - QString expected = "/qt5/qtdoc/doc/config"; - - qdocTestGlobals.setCurrentDir(expected); - QCOMPARE(qdocTestGlobals.currentDir(), expected); -} - -void testQDocGlobals::testPreviousCurrentDir() -{ - QDocGlobals qdocTestGlobals; - QString expected = "/qt5/qtdoc/doc"; - - qdocTestGlobals.setCurrentDir(expected); - QCOMPARE(qdocTestGlobals.currentDir(), expected); -} - -void testQDocGlobals::testDefaults() -{ - QDocGlobals qdocTestGlobals; - - QHash expected = { - {"codeindent", "0"}, {"falsehoods", "0"}, - {"fileextensions", "*.cpp *.h *.qdoc *.qml"}, {"language", "Cpp"}, - {"outputformats", "HTML"}, {"tabsize", "8"}}; - - qdocTestGlobals.defaults().insert(QStringLiteral("codeindent"), - QLatin1String("0")); - qdocTestGlobals.defaults().insert(QStringLiteral("falsehoods"), - QLatin1String("0")); - qdocTestGlobals.defaults().insert(QStringLiteral("fileextensions"), - QLatin1String("*.cpp *.h *.qdoc *.qml")); - qdocTestGlobals.defaults().insert(QStringLiteral("language"), - QLatin1String("Cpp")); - qdocTestGlobals.defaults().insert(QStringLiteral("outputformats"), - QLatin1String("HTML")); - qdocTestGlobals.defaults().insert(QStringLiteral("tabsize"), - QLatin1String("8")); - - QHash result = qdocTestGlobals.defaults(); - QCOMPARE(result, expected); -} - -QTEST_APPLESS_MAIN(testQDocGlobals) - -#include "tst_qdocglobals.moc" diff --git a/tests/auto/qdoc/utilities/CMakeLists.txt b/tests/auto/qdoc/utilities/CMakeLists.txt new file mode 100644 index 0000000000..a424023f9e --- /dev/null +++ b/tests/auto/qdoc/utilities/CMakeLists.txt @@ -0,0 +1,13 @@ +# Generated from utilities.pro. + +##################################################################### +## tst_utilities Test: +##################################################################### + +qt_internal_add_test(tst_utilities + SOURCES + ../../../../src/qdoc/utilities.cpp ../../../../src/qdoc/utilities.h + tst_utilities.cpp + INCLUDE_DIRECTORIES + ../../../../src/qdoc +) diff --git a/tests/auto/qdoc/utilities/tst_utilities.cpp b/tests/auto/qdoc/utilities/tst_utilities.cpp new file mode 100644 index 0000000000..2cf19c56ca --- /dev/null +++ b/tests/auto/qdoc/utilities/tst_utilities.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "utilities.h" + +#include + +class tst_Utilities : public QObject +{ + Q_OBJECT + +private slots: + void loggingCategoryName(); + void loggingCategoryDefaults(); + void startDebugging(); + void stopDebugging(); + void debugging(); + void callSeparatorForOneWord(); + void callSeparatorForMoreThanOneWord(); + void callCommaForOneWord(); + void callCommaForTwoWords(); + void callCommaForThreeWords(); +}; + +void tst_Utilities::loggingCategoryName() +{ + const QString expected = "qt.qdoc"; + QCOMPARE(lcQdoc().categoryName(), expected); +} + +void tst_Utilities::loggingCategoryDefaults() +{ + QVERIFY(lcQdoc().isCriticalEnabled()); + QVERIFY(lcQdoc().isWarningEnabled()); + QVERIFY(!lcQdoc().isDebugEnabled()); + QVERIFY(lcQdoc().isInfoEnabled()); +} + +void tst_Utilities::startDebugging() +{ + QVERIFY(!lcQdoc().isDebugEnabled()); + Utilities::startDebugging("test"); + QVERIFY(lcQdoc().isDebugEnabled()); +} + +void tst_Utilities::stopDebugging() +{ + Utilities::startDebugging("test"); + QVERIFY(lcQdoc().isDebugEnabled()); + Utilities::stopDebugging("test"); + QVERIFY(!lcQdoc().isDebugEnabled()); +} + +void tst_Utilities::debugging() +{ + QVERIFY(!lcQdoc().isDebugEnabled()); + QVERIFY(!Utilities::debugging()); + Utilities::startDebugging("test"); + QVERIFY(lcQdoc().isDebugEnabled()); + QVERIFY(Utilities::debugging()); +} + +void tst_Utilities::callSeparatorForOneWord() +{ + const QStringList listOfWords { "one" }; + const QString expected = QStringLiteral("one."); + + int index = 0; + QString result; + for (const auto &word : listOfWords) { + result.append(word); + result.append(Utilities::separator(index++, listOfWords.size())); + } + QCOMPARE(result, expected); +} + +void tst_Utilities::callSeparatorForMoreThanOneWord() +{ + const QStringList listOfWords { "one", "two" }; + const QString expected = QStringLiteral("one and two."); + + int index = 0; + QString result; + for (const auto &word : listOfWords) { + result.append(word); + result.append(Utilities::separator(index++, listOfWords.size())); + } + QCOMPARE(result, expected); +} + +void tst_Utilities::callCommaForOneWord() +{ + const QStringList listOfWords { "one" }; + const QString expected = QStringLiteral("one"); + + int index = 0; + QString result; + for (const auto &word : listOfWords) { + result.append(word); + result.append(Utilities::comma(index++, listOfWords.size())); + } + QCOMPARE(result, expected); +} +void tst_Utilities::callCommaForTwoWords() +{ + const QStringList listOfWords { "one", "two" }; + const QString expected = QStringLiteral("one and two"); + + int index = 0; + QString result; + for (const auto &word : listOfWords) { + result.append(word); + result.append(Utilities::comma(index++, listOfWords.size())); + } + QCOMPARE(result, expected); +} + +void tst_Utilities::callCommaForThreeWords() +{ + const QStringList listOfWords { "one", "two", "three" }; + const QString expected = QStringLiteral("one, two, and three"); + + int index = 0; + QString result; + for (const auto &word : listOfWords) { + result.append(word); + result.append(Utilities::comma(index++, listOfWords.size())); + } + QCOMPARE(result, expected); +} + +QTEST_APPLESS_MAIN(tst_Utilities) + +#include "tst_utilities.moc" diff --git a/tests/auto/qhelpcontentmodel/CMakeLists.txt b/tests/auto/qhelpcontentmodel/CMakeLists.txt new file mode 100644 index 0000000000..920ac2ca27 --- /dev/null +++ b/tests/auto/qhelpcontentmodel/CMakeLists.txt @@ -0,0 +1,16 @@ +# Generated from qhelpcontentmodel.pro. + +##################################################################### +## tst_qhelpcontentmodel Test: +##################################################################### + +qt_internal_add_test(tst_qhelpcontentmodel + SOURCES + tst_qhelpcontentmodel.cpp + DEFINES + QT_USE_USING_NAMESPACE + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" + PUBLIC_LIBRARIES + Qt::Gui + Qt::Help +) diff --git a/tests/auto/qhelpcontentmodel/qhelpcontentmodel.pro b/tests/auto/qhelpcontentmodel/qhelpcontentmodel.pro deleted file mode 100644 index 7fb9f6585c..0000000000 --- a/tests/auto/qhelpcontentmodel/qhelpcontentmodel.pro +++ /dev/null @@ -1,6 +0,0 @@ -TARGET = tst_qhelpcontentmodel -CONFIG += testcase -QT += help testlib -SOURCES += tst_qhelpcontentmodel.cpp - -DEFINES += QT_USE_USING_NAMESPACE SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/qhelpcontentmodel/tst_qhelpcontentmodel.cpp b/tests/auto/qhelpcontentmodel/tst_qhelpcontentmodel.cpp index 039ea2f9ae..5480168d3b 100644 --- a/tests/auto/qhelpcontentmodel/tst_qhelpcontentmodel.cpp +++ b/tests/auto/qhelpcontentmodel/tst_qhelpcontentmodel.cpp @@ -98,6 +98,7 @@ void tst_QHelpContentModel::init() void tst_QHelpContentModel::setupContents() { QHelpEngine h(m_colFile, 0); + h.setReadOnly(false); QHelpContentModel *m = h.contentModel(); SignalWaiter w; connect(m, SIGNAL(contentsCreated()), @@ -123,6 +124,7 @@ void tst_QHelpContentModel::setupContents() void tst_QHelpContentModel::contentItemAt() { QHelpEngine h(m_colFile, 0); + h.setReadOnly(false); QHelpContentModel *m = h.contentModel(); SignalWaiter w; connect(m, SIGNAL(contentsCreated()), diff --git a/tests/auto/qhelpenginecore/CMakeLists.txt b/tests/auto/qhelpenginecore/CMakeLists.txt new file mode 100644 index 0000000000..548f2068c2 --- /dev/null +++ b/tests/auto/qhelpenginecore/CMakeLists.txt @@ -0,0 +1,17 @@ +# Generated from qhelpenginecore.pro. + +##################################################################### +## tst_qhelpenginecore Test: +##################################################################### + +qt_internal_add_test(tst_qhelpenginecore + SOURCES + tst_qhelpenginecore.cpp + DEFINES + QT_USE_USING_NAMESPACE + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" + PUBLIC_LIBRARIES + Qt::Gui + Qt::Help + Qt::Sql +) diff --git a/tests/auto/qhelpenginecore/qhelpenginecore.pro b/tests/auto/qhelpenginecore/qhelpenginecore.pro deleted file mode 100644 index e6fc350749..0000000000 --- a/tests/auto/qhelpenginecore/qhelpenginecore.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = tst_qhelpenginecore -CONFIG += testcase -SOURCES += tst_qhelpenginecore.cpp -QT += help sql testlib help - - -DEFINES += QT_USE_USING_NAMESPACE SRCDIR=\\\"$$PWD\\\" diff --git a/tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp b/tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp index ddadda10bb..3ca299b26d 100644 --- a/tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp +++ b/tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp @@ -64,8 +64,6 @@ private slots: void files(); void fileData(); - void linksForIdentifier(); - void customValue(); void setCustomValue(); void removeCustomValue(); @@ -206,6 +204,7 @@ void tst_QHelpEngineCore::registerDocumentation() QDir::current().remove(m_colFile); { QHelpEngineCore c(m_colFile); + c.setReadOnly(false); QCOMPARE(c.setupData(), true); c.registerDocumentation(m_path + "/data/qmake-3.3.8.qch"); QCOMPARE(c.registeredDocumentations().count(), 1); @@ -237,6 +236,7 @@ void tst_QHelpEngineCore::registerDocumentation() void tst_QHelpEngineCore::unregisterDocumentation() { QHelpEngineCore c(m_colFile); + c.setReadOnly(false); QCOMPARE(c.setupData(), true); QCOMPARE(c.registeredDocumentations().count(), 3); c.unregisterDocumentation("trolltech.com.3-3-8.qmake"); @@ -324,6 +324,7 @@ void tst_QHelpEngineCore::setCurrentFilter() void tst_QHelpEngineCore::filterAttributeSets() { QHelpEngineCore help(m_colFile, 0); + help.setReadOnly(false); QCOMPARE(help.setupData(), true); QList lst = help.filterAttributeSets("trolltech.com.1.0.0.test"); QCOMPARE(lst.count(), 2); @@ -335,6 +336,7 @@ void tst_QHelpEngineCore::filterAttributeSets() void tst_QHelpEngineCore::files() { QHelpEngineCore help(m_colFile, 0); + help.setReadOnly(false); QCOMPARE(help.setupData(), true); QList lst = help.files("trolltech.com.4-3-0.qmake", QStringList()); @@ -365,6 +367,7 @@ void tst_QHelpEngineCore::files() void tst_QHelpEngineCore::fileData() { QHelpEngineCore help(m_colFile, 0); + help.setReadOnly(false); QCOMPARE(help.setupData(), true); QByteArray ba = help.fileData(QUrl("NotExisting")); QCOMPARE(ba.size(), 0); @@ -377,27 +380,6 @@ void tst_QHelpEngineCore::fileData() QCOMPARE(s.readAll(), ts.readAll()); } -void tst_QHelpEngineCore::linksForIdentifier() -{ - QHelpEngineCore help(m_colFile, 0); - QCOMPARE(help.setupData(), true); - QMap map; - map = help.linksForIdentifier("Test::foo"); - QCOMPARE(map.contains("Test Manual"), true); - QCOMPARE(map.count(), 1); - QCOMPARE(map.value("Test Manual"), - QUrl("qthelp://trolltech.com.1.0.0.test/testFolder/test.html#foo")); - - help.setCurrentFilter("Custom Filter 2"); - map = help.linksForIdentifier("People::newton"); - QCOMPARE(map.isEmpty(), true); - map = help.linksForIdentifier("Fancy::foobar"); - QCOMPARE(map.contains("Fancy"), true); - QCOMPARE(map.count(), 1); - QCOMPARE(map.value("Fancy"), - QUrl("qthelp://trolltech.com.1.0.0.test/testFolder/fancy.html#foobar")); -} - void tst_QHelpEngineCore::customValue() { QHelpEngineCore help(m_colFile, 0); diff --git a/tests/auto/qhelpgenerator/CMakeLists.txt b/tests/auto/qhelpgenerator/CMakeLists.txt new file mode 100644 index 0000000000..609c20e595 --- /dev/null +++ b/tests/auto/qhelpgenerator/CMakeLists.txt @@ -0,0 +1,20 @@ +# Generated from qhelpgenerator.pro. + +##################################################################### +## tst_qhelpgenerator Test: +##################################################################### + +qt_internal_add_test(tst_qhelpgenerator + SOURCES + ../../../src/assistant/qhelpgenerator/helpgenerator.cpp ../../../src/assistant/qhelpgenerator/helpgenerator.h + ../../../src/assistant/qhelpgenerator/qhelpdatainterface.cpp ../../../src/assistant/qhelpgenerator/qhelpdatainterface_p.h + ../../../src/assistant/qhelpgenerator/qhelpprojectdata.cpp ../../../src/assistant/qhelpgenerator/qhelpprojectdata_p.h + tst_qhelpgenerator.cpp + DEFINES + QT_USE_USING_NAMESPACE + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" + PUBLIC_LIBRARIES + Qt::Gui + Qt::HelpPrivate + Qt::Sql +) diff --git a/tests/auto/qhelpgenerator/qhelpgenerator.pro b/tests/auto/qhelpgenerator/qhelpgenerator.pro deleted file mode 100644 index da38268444..0000000000 --- a/tests/auto/qhelpgenerator/qhelpgenerator.pro +++ /dev/null @@ -1,14 +0,0 @@ -TARGET = tst_qhelpgenerator -CONFIG += testcase - -HEADERS += ../../../src/assistant/qhelpgenerator/helpgenerator.h \ - ../../../src/assistant/qhelpgenerator/qhelpdatainterface_p.h \ - ../../../src/assistant/qhelpgenerator/qhelpprojectdata_p.h -SOURCES += tst_qhelpgenerator.cpp \ - ../../../src/assistant/qhelpgenerator/helpgenerator.cpp \ - ../../../src/assistant/qhelpgenerator/qhelpdatainterface.cpp \ - ../../../src/assistant/qhelpgenerator/qhelpprojectdata.cpp -QT += help-private sql testlib - -DEFINES += SRCDIR=\\\"$$PWD\\\" -DEFINES += QT_USE_USING_NAMESPACE diff --git a/tests/auto/qhelpindexmodel/CMakeLists.txt b/tests/auto/qhelpindexmodel/CMakeLists.txt new file mode 100644 index 0000000000..10061d84f7 --- /dev/null +++ b/tests/auto/qhelpindexmodel/CMakeLists.txt @@ -0,0 +1,17 @@ +# Generated from qhelpindexmodel.pro. + +##################################################################### +## tst_qhelpindexmodel Test: +##################################################################### + +qt_internal_add_test(tst_qhelpindexmodel + SOURCES + tst_qhelpindexmodel.cpp + DEFINES + QT_USE_USING_NAMESPACE + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" + PUBLIC_LIBRARIES + Qt::Gui + Qt::Help + Qt::Sql +) diff --git a/tests/auto/qhelpindexmodel/qhelpindexmodel.pro b/tests/auto/qhelpindexmodel/qhelpindexmodel.pro deleted file mode 100644 index 18c118f2da..0000000000 --- a/tests/auto/qhelpindexmodel/qhelpindexmodel.pro +++ /dev/null @@ -1,8 +0,0 @@ -TARGET = tst_qhelpindexmodel -CONFIG += testcase - -SOURCES += tst_qhelpindexmodel.cpp -QT += help sql testlib - -DEFINES += SRCDIR=\\\"$$PWD\\\" -DEFINES += QT_USE_USING_NAMESPACE diff --git a/tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp b/tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp index d304c3f3b4..ce8889efec 100644 --- a/tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp +++ b/tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp @@ -76,7 +76,6 @@ private slots: void setupIndex(); void filter(); - void linksForIndex(); private: QString m_colFile; @@ -98,6 +97,7 @@ void tst_QHelpIndexModel::init() void tst_QHelpIndexModel::setupIndex() { QHelpEngine h(m_colFile, 0); + h.setReadOnly(false); QHelpIndexModel *m = h.indexModel(); SignalWaiter w; connect(m, SIGNAL(indexCreated()), @@ -129,6 +129,7 @@ void tst_QHelpIndexModel::setupIndex() void tst_QHelpIndexModel::filter() { QHelpEngine h(m_colFile, 0); + h.setReadOnly(false); QHelpIndexModel *m = h.indexModel(); SignalWaiter w; connect(m, SIGNAL(indexCreated()), @@ -152,50 +153,5 @@ void tst_QHelpIndexModel::filter() QCOMPARE(m->stringList().count(), 11); } -void tst_QHelpIndexModel::linksForIndex() -{ - QHelpEngine h(m_colFile, 0); - QHelpIndexModel *m = h.indexModel(); - SignalWaiter w; - connect(m, SIGNAL(indexCreated()), - &w, SLOT(stopWaiting())); - w.start(); - h.setupData(); - int i = 0; - while (w.isRunning() && i++ < 10) - QTest::qWait(500); - - QCOMPARE(h.currentFilter(), QString("unfiltered")); - QMap map; - map = m->linksForKeyword("foo"); - QCOMPARE(map.count(), 2); - QCOMPARE(map.contains("Test Manual"), true); - QCOMPARE(map.value("Test Manual"), - QUrl("qthelp://trolltech.com.1-0-0.test/testFolder/test.html#foo")); - - QCOMPARE(map.contains("Fancy"), true); - QCOMPARE(map.value("Fancy"), - QUrl("qthelp://trolltech.com.1-0-0.test/testFolder/fancy.html#foo")); - - map = m->linksForKeyword("foobar"); - QCOMPARE(map.count(), 1); - QCOMPARE(map.contains("Fancy"), true); - - map = m->linksForKeyword("notexisting"); - QCOMPARE(map.count(), 0); - - w.start(); - h.setCurrentFilter("Custom Filter 1"); - i = 0; - while (w.isRunning() && i++ < 10) - QTest::qWait(500); - - map = m->linksForKeyword("foo"); - QCOMPARE(map.count(), 1); - QCOMPARE(map.contains("Test Manual"), true); - QCOMPARE(map.value("Test Manual"), - QUrl("qthelp://trolltech.com.1-0-0.test/testFolder/test.html#foo")); -} - QTEST_MAIN(tst_QHelpIndexModel) #include "tst_qhelpindexmodel.moc" diff --git a/tests/auto/qhelpprojectdata/CMakeLists.txt b/tests/auto/qhelpprojectdata/CMakeLists.txt new file mode 100644 index 0000000000..d48ae592f8 --- /dev/null +++ b/tests/auto/qhelpprojectdata/CMakeLists.txt @@ -0,0 +1,18 @@ +# Generated from qhelpprojectdata.pro. + +##################################################################### +## tst_qhelpprojectdata Test: +##################################################################### + +qt_internal_add_test(tst_qhelpprojectdata + SOURCES + ../../../src/assistant/qhelpgenerator/qhelpdatainterface.cpp ../../../src/assistant/qhelpgenerator/qhelpdatainterface_p.h + ../../../src/assistant/qhelpgenerator/qhelpprojectdata.cpp ../../../src/assistant/qhelpgenerator/qhelpprojectdata_p.h + tst_qhelpprojectdata.cpp + DEFINES + QT_USE_USING_NAMESPACE + SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" + PUBLIC_LIBRARIES + Qt::Gui + Qt::HelpPrivate +) diff --git a/tests/auto/qhelpprojectdata/qhelpprojectdata.pro b/tests/auto/qhelpprojectdata/qhelpprojectdata.pro deleted file mode 100644 index 51d127ac09..0000000000 --- a/tests/auto/qhelpprojectdata/qhelpprojectdata.pro +++ /dev/null @@ -1,15 +0,0 @@ -TARGET = tst_qhelpprojectdata -CONFIG += testcase - -HEADERS += ../../../src/assistant/qhelpgenerator/qhelpdatainterface_p.h \ - ../../../src/assistant/qhelpgenerator/qhelpprojectdata_p.h - -SOURCES += tst_qhelpprojectdata.cpp \ - ../../../src/assistant/qhelpgenerator/qhelpdatainterface.cpp \ - ../../../src/assistant/qhelpgenerator/qhelpprojectdata.cpp - -QT += help-private testlib - -DEFINES += SRCDIR=\\\"$$PWD\\\" -DEFINES += QT_USE_USING_NAMESPACE - diff --git a/tests/auto/qtattributionsscanner/CMakeLists.txt b/tests/auto/qtattributionsscanner/CMakeLists.txt new file mode 100644 index 0000000000..24d512afe8 --- /dev/null +++ b/tests/auto/qtattributionsscanner/CMakeLists.txt @@ -0,0 +1,13 @@ +# Generated from qtattributionsscanner.pro. + +##################################################################### +## tst_qtattributionsscanner Test: +##################################################################### + +qt_internal_add_test(tst_qtattributionsscanner + SOURCES + tst_qtattributionsscanner.cpp +) + +#### Keys ignored in scope 1:.:.:qtattributionsscanner.pro:: +# DISTFILES = "testdata/good/expected.json" "testdata/good/expected.error" "testdata/good/minimal/qt_attribution_test.json" "testdata/good/minimal/expected.json" "testdata/good/minimal/expected.error" "testdata/good/complete/qt_attribution_test.json" "testdata/good/complete/expected.json" "testdata/good/complete/expected.error" "testdata/good/variants/qt_attribution_test.json" "testdata/good/variants/expected.json" "testdata/good/variants/expected.error" "testdata/warnings/incomplete/qt_attribution_test.json" "testdata/warnings/incomplete/expected.json" "testdata/warnings/incomplete/expected.error" "testdata/warnings/unknown/qt_attribution_test.json" "testdata/warnings/unknown/expected.json" "testdata/warnings/unknown/expected.error" diff --git a/tests/auto/qtattributionsscanner/qtattributionsscanner.pro b/tests/auto/qtattributionsscanner/qtattributionsscanner.pro deleted file mode 100644 index aa8442a887..0000000000 --- a/tests/auto/qtattributionsscanner/qtattributionsscanner.pro +++ /dev/null @@ -1,18 +0,0 @@ -CONFIG += testcase -QT = core testlib - -DISTFILES += \ - testdata/good/minimal/qt_attribution.json \ - testdata/good/complete/qt_attribution.json \ - testdata/good/expected.json \ - testdata/good/expected.error \ - testdata/warnings/incomplete/qt_attribution.json \ - testdata/warnings/incomplete/expected.json \ - testdata/warnings/incomplete/expected.error \ - testdata/warnings/unknown/qt_attribution.json \ - testdata/warnings/unknown/expected.json \ - testdata/warnings/unknown/expected.error - -TARGET = tst_qtattributionsscanner - -SOURCES += tst_qtattributionsscanner.cpp diff --git a/tests/auto/qtattributionsscanner/testdata/good/expected.json b/tests/auto/qtattributionsscanner/testdata/good/expected.json index 1f54c13e6a..d910e61659 100644 --- a/tests/auto/qtattributionsscanner/testdata/good/expected.json +++ b/tests/auto/qtattributionsscanner/testdata/good/expected.json @@ -1,6 +1,7 @@ [ { "Copyright": "", + "CopyrightFile": "", "Description": "Hello world!\nLine 2", "DownloadLocation": "", "Files": "", @@ -10,7 +11,7 @@ "LicenseFile": "", "LicenseId": "", "Name": "Test", - "PackageComment":"", + "PackageComment": "", "Path": "%{PWD}/chromium", "QDocModule": "qtwebengine", "QtParts": [ @@ -21,40 +22,68 @@ }, { "Copyright": "Copyright", + "CopyrightFile": "", "Description": "Multi\nLine\nDescription", + "DownloadLocation": "www.qt.io/1.0", + "Files": "", "Homepage": "www.qt.io", "Id": "complete", "License": "License", "LicenseFile": "%{PWD}/complete/LICENSE", "LicenseId": "xxx", "Name": "Complete", - "PackageComment":"just a test package", + "PackageComment": "just a test package", "Path": "%{PWD}/complete", - "Files": "", "QDocModule": "qtest", - "QtParts": [ "examples" ], + "QtParts": [ + "examples" + ], "QtUsage": "Multi\nLine\nUsage", - "Version": "1.0", - "DownloadLocation": "www.qt.io/1.0" + "Version": "1.0" }, { "Copyright": "Copyright", + "CopyrightFile": "", "Description": "", + "DownloadLocation": "", + "Files": "", "Homepage": "", "Id": "minimal", "License": "License", "LicenseFile": "", "LicenseId": "", "Name": "Minimal", - "PackageComment":"", + "PackageComment": "", "Path": "%{PWD}/minimal", + "QDocModule": "qtest", + "QtParts": [ + "libs" + ], + "QtUsage": "Usage", + "Version": "" + }, + { + "Copyright": "", + "CopyrightFile": "%{PWD}/variants/COPYRIGHT.txt", + "Description": "", + "DownloadLocation": "", "Files": "", + "Homepage": "", + "Id": "variants", + "License": "License", + "LicenseFiles": [ + "%{PWD}/variants/LICENSE1.txt", + "%{PWD}/variants/LICENSE2.txt" + ], + "LicenseId": "", + "Name": "Variants Test", + "PackageComment": "", + "Path": "%{PWD}/variants", "QDocModule": "qtest", "QtParts": [ "libs" ], "QtUsage": "Usage", - "Version": "", - "DownloadLocation": "" + "Version": "" } ] diff --git a/tests/auto/qtattributionsscanner/testdata/good/minimal/expected.json b/tests/auto/qtattributionsscanner/testdata/good/minimal/expected.json index 8d9a5a31fe..fcde8f0842 100644 --- a/tests/auto/qtattributionsscanner/testdata/good/minimal/expected.json +++ b/tests/auto/qtattributionsscanner/testdata/good/minimal/expected.json @@ -1,7 +1,10 @@ [ { "Copyright": "Copyright", + "CopyrightFile": "", "Description": "", + "DownloadLocation": "", + "Files": "", "Homepage": "", "Id": "minimal", "License": "License", @@ -10,13 +13,11 @@ "Name": "Minimal", "PackageComment": "", "Path": "%{PWD}", - "Files": "", "QDocModule": "qtest", "QtParts": [ "libs" ], "QtUsage": "Usage", - "Version": "", - "DownloadLocation": "" + "Version": "" } ] diff --git a/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE1.txt b/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE1.txt new file mode 100644 index 0000000000..716287c924 --- /dev/null +++ b/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE1.txt @@ -0,0 +1 @@ +LICENSE1 \ No newline at end of file diff --git a/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE2.txt b/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE2.txt new file mode 100644 index 0000000000..3671b8928d --- /dev/null +++ b/tests/auto/qtattributionsscanner/testdata/good/variants/LICENSE2.txt @@ -0,0 +1 @@ +LICENSE2 \ No newline at end of file diff --git a/tests/auto/qtattributionsscanner/testdata/good/variants/expected.error b/tests/auto/qtattributionsscanner/testdata/good/variants/expected.error new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/auto/qtattributionsscanner/testdata/good/variants/expected.json b/tests/auto/qtattributionsscanner/testdata/good/variants/expected.json new file mode 100644 index 0000000000..10a3391751 --- /dev/null +++ b/tests/auto/qtattributionsscanner/testdata/good/variants/expected.json @@ -0,0 +1,26 @@ +[ + { + "Copyright": "", + "CopyrightFile": "%{PWD}/COPYRIGHT.txt", + "Description": "", + "DownloadLocation": "", + "Files": "", + "Homepage": "", + "Id": "variants", + "License": "License", + "LicenseFiles": [ + "%{PWD}/LICENSE1.txt", + "%{PWD}/LICENSE2.txt" + ], + "LicenseId": "", + "Name": "Variants Test", + "PackageComment": "", + "Path": "%{PWD}", + "QDocModule": "qtest", + "QtParts": [ + "libs" + ], + "QtUsage": "Usage", + "Version": "" + } +] diff --git a/tests/auto/qtattributionsscanner/testdata/good/variants/qt_attribution_test.json b/tests/auto/qtattributionsscanner/testdata/good/variants/qt_attribution_test.json new file mode 100644 index 0000000000..1d8b587d90 --- /dev/null +++ b/tests/auto/qtattributionsscanner/testdata/good/variants/qt_attribution_test.json @@ -0,0 +1,11 @@ +{ + "Id": "variants", + "Name": "Variants Test", + + "QDocModule": "qtest", + "QtUsage": "Usage", + "License": "License", + + "CopyrightFile": "COPYRIGHT.txt", + "LicenseFiles": [ "LICENSE1.txt", "LICENSE2.txt" ] +} diff --git a/tests/auto/qtattributionsscanner/testdata/warnings/incomplete/expected.json b/tests/auto/qtattributionsscanner/testdata/warnings/incomplete/expected.json index fa56f29764..77b77b44c5 100644 --- a/tests/auto/qtattributionsscanner/testdata/warnings/incomplete/expected.json +++ b/tests/auto/qtattributionsscanner/testdata/warnings/incomplete/expected.json @@ -1,7 +1,10 @@ [ { "Copyright": "", + "CopyrightFile": "", "Description": "", + "DownloadLocation": "", + "Files": "", "Homepage": "", "Id": "", "License": "", @@ -10,11 +13,11 @@ "Name": "", "PackageComment": "", "Path": "%{PWD}", - "Files": "", "QDocModule": "", - "QtParts": [ "libs" ], + "QtParts": [ + "libs" + ], "QtUsage": "", - "Version": "", - "DownloadLocation": "" + "Version": "" } ] diff --git a/tests/auto/qtattributionsscanner/testdata/warnings/unknown/expected.json b/tests/auto/qtattributionsscanner/testdata/warnings/unknown/expected.json index 18c1055f26..a87917eba2 100644 --- a/tests/auto/qtattributionsscanner/testdata/warnings/unknown/expected.json +++ b/tests/auto/qtattributionsscanner/testdata/warnings/unknown/expected.json @@ -1,7 +1,10 @@ [ { "Copyright": "Copyright", + "CopyrightFile": "", "Description": "", + "DownloadLocation": "", + "Files": "", "Homepage": "", "Id": "unknown", "License": "License", @@ -10,11 +13,11 @@ "Name": "Unknown", "PackageComment": "", "Path": "%{PWD}", - "Files": "", "QDocModule": "qtest", - "QtParts": [ "libs" ], + "QtParts": [ + "libs" + ], "QtUsage": "Usage", - "Version": "", - "DownloadLocation": "" + "Version": "" } ] diff --git a/tests/auto/qtattributionsscanner/tst_qtattributionsscanner.cpp b/tests/auto/qtattributionsscanner/tst_qtattributionsscanner.cpp index 7789ad5f75..017d6a255c 100644 --- a/tests/auto/qtattributionsscanner/tst_qtattributionsscanner.cpp +++ b/tests/auto/qtattributionsscanner/tst_qtattributionsscanner.cpp @@ -56,7 +56,7 @@ private slots: tst_qtattributionsscanner::tst_qtattributionsscanner() { - QString binPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); + QString binPath = QLibraryInfo::path(QLibraryInfo::BinariesPath); m_cmd = binPath + QLatin1String("/qtattributionsscanner"); m_basePath = QFINDTESTDATA("testdata"); } @@ -84,6 +84,9 @@ void tst_qtattributionsscanner::test_data() << QStringLiteral("good/minimal/qt_attribution_test.json") << QStringLiteral("good/minimal/expected.json") << QStringLiteral("good/minimal/expected.error"); + QTest::newRow("variants") << QStringLiteral("good/variants/qt_attribution_test.json") + << QStringLiteral("good/variants/expected.json") + << QStringLiteral("good/variants/expected.error"); } void tst_qtattributionsscanner::readExpectedFile(const QString &baseDir, const QString &fileName, QByteArray *content) @@ -105,11 +108,12 @@ void tst_qtattributionsscanner::test() dir = QFileInfo(dir).absolutePath(); QProcess proc; - QString command = m_cmd + " " + dir + " --output-format json"; + const QStringList arguments{dir, "--output-format", "json"}; + QString command = m_cmd + ' ' + arguments.join(' '); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert("QT_ATTRIBUTIONSSCANNER_TEST", "1"); proc.setProcessEnvironment(env); - proc.start(command, QIODevice::ReadWrite | QIODevice::Text); + proc.start(m_cmd, arguments, QIODevice::ReadWrite | QIODevice::Text); QVERIFY2(proc.waitForStarted(), qPrintable(command + QLatin1String(" :") + proc.errorString())); QVERIFY2(proc.waitForFinished(30000), qPrintable(command)); @@ -122,7 +126,7 @@ void tst_qtattributionsscanner::test() { // compare error output QByteArray stdErr = proc.readAllStandardError(); - stdErr.replace(QDir::separator(), "/"); + stdErr.replace(QDir::separator().toLatin1(), "/"); QByteArray expectedErrorOutput; readExpectedFile(dir, stderr_file, &expectedErrorOutput); diff --git a/tests/auto/qtdiag/CMakeLists.txt b/tests/auto/qtdiag/CMakeLists.txt new file mode 100644 index 0000000000..a796f606f1 --- /dev/null +++ b/tests/auto/qtdiag/CMakeLists.txt @@ -0,0 +1,12 @@ +# Generated from qtdiag.pro. + +##################################################################### +## tst_tdiag Test: +##################################################################### + +qt_internal_add_test(tst_tdiag + SOURCES + tst_qtdiag.cpp + DEFINES + QT_USE_USING_NAMESPACE +) diff --git a/tests/auto/qtdiag/qtdiag.pro b/tests/auto/qtdiag/qtdiag.pro deleted file mode 100644 index 5f2f224c6b..0000000000 --- a/tests/auto/qtdiag/qtdiag.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = tst_tdiag -CONFIG += testcase -QT = core testlib - -SOURCES += tst_qtdiag.cpp - -DEFINES += QT_USE_USING_NAMESPACE diff --git a/tests/auto/qtdiag/tst_qtdiag.cpp b/tests/auto/qtdiag/tst_qtdiag.cpp index 207c450c21..dfda13221f 100644 --- a/tests/auto/qtdiag/tst_qtdiag.cpp +++ b/tests/auto/qtdiag/tst_qtdiag.cpp @@ -46,7 +46,7 @@ private slots: void tst_QtDiag::initTestCase() { - QString binary = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QStringLiteral("/qtdiag"); + QString binary = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QStringLiteral("/qtdiag"); # ifdef Q_OS_WIN binary += QStringLiteral(".exe"); # endif @@ -67,7 +67,7 @@ void tst_QtDiag::run() QSKIP("Binary could not be found"); QProcess process; qDebug() << "Launching " << QDir::toNativeSeparators(m_binary); - process.start(m_binary); + process.start(m_binary, QStringList{}); QVERIFY2(process.waitForStarted(), qPrintable(process.errorString())); QVERIFY(process.waitForFinished()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); diff --git a/tests/auto/windeployqt/CMakeLists.txt b/tests/auto/windeployqt/CMakeLists.txt new file mode 100644 index 0000000000..5eae1ca164 --- /dev/null +++ b/tests/auto/windeployqt/CMakeLists.txt @@ -0,0 +1,4 @@ +# Generated from windeployqt.pro. + +add_subdirectory(testapp) +add_subdirectory(test) diff --git a/tests/auto/windeployqt/test/CMakeLists.txt b/tests/auto/windeployqt/test/CMakeLists.txt new file mode 100644 index 0000000000..d412249a7f --- /dev/null +++ b/tests/auto/windeployqt/test/CMakeLists.txt @@ -0,0 +1,11 @@ +# Generated from test.pro. + +##################################################################### +## tst_windeployqt Test: +##################################################################### + +qt_internal_add_test(tst_windeployqt + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" # special case + SOURCES + ../tst_windeployqt.cpp +) diff --git a/tests/auto/windeployqt/test/test.pro b/tests/auto/windeployqt/test/test.pro deleted file mode 100644 index 7aac19a0d3..0000000000 --- a/tests/auto/windeployqt/test/test.pro +++ /dev/null @@ -1,5 +0,0 @@ -CONFIG += testcase -QT = core testlib -DESTDIR = .. -TARGET = tst_windeployqt -SOURCES += ../tst_windeployqt.cpp diff --git a/tests/auto/windeployqt/testapp/CMakeLists.txt b/tests/auto/windeployqt/testapp/CMakeLists.txt new file mode 100644 index 0000000000..83851dae65 --- /dev/null +++ b/tests/auto/windeployqt/testapp/CMakeLists.txt @@ -0,0 +1,21 @@ +# Generated from testapp.pro. + +##################################################################### +## testapp Binary: +##################################################################### + +qt_internal_add_executable(windeploy_testapp # special case + GUI + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + SOURCES + main.cpp + PUBLIC_LIBRARIES + Qt::Gui +) + +# special case begin +set_target_properties(windeploy_testapp + PROPERTIES + OUTPUT_NAME testapp +) +# special case end diff --git a/tests/auto/windeployqt/tst_windeployqt.cpp b/tests/auto/windeployqt/tst_windeployqt.cpp index f20e591803..04aece287e 100644 --- a/tests/auto/windeployqt/tst_windeployqt.cpp +++ b/tests/auto/windeployqt/tst_windeployqt.cpp @@ -152,7 +152,7 @@ void tst_windeployqt::deploy() const QChar pathSeparator(QLatin1Char(';')); // ### fixme: Qt 5.6: QDir::listSeparator() const QString origPath = env.value(pathKey); QString newPath; - const QStringList pathElements = origPath.split(pathSeparator, QString::SkipEmptyParts); + const QStringList pathElements = origPath.split(pathSeparator, Qt::SkipEmptyParts); for (const QString &pathElement : pathElements) { if (pathElement.compare(qtBinDir, Qt::CaseInsensitive) && !pathElement.contains(QLatin1String("\\lib"), Qt::CaseInsensitive)) { diff --git a/tests/auto/windeployqt/windeployqt.pro b/tests/auto/windeployqt/windeployqt.pro deleted file mode 100644 index 0ae9b2babc..0000000000 --- a/tests/auto/windeployqt/windeployqt.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = testapp test -CONFIG += ordered diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt new file mode 100644 index 0000000000..f9eb933df1 --- /dev/null +++ b/tests/manual/CMakeLists.txt @@ -0,0 +1,3 @@ +# Generated from manual.pro. + +add_subdirectory(qtattributionsscanner) diff --git a/tests/manual/qtattributionsscanner/CMakeLists.txt b/tests/manual/qtattributionsscanner/CMakeLists.txt new file mode 100644 index 0000000000..878f96a6dd --- /dev/null +++ b/tests/manual/qtattributionsscanner/CMakeLists.txt @@ -0,0 +1,2 @@ +# Generated from qtattributionsscanner.pro. + diff --git a/tests/manual/qtattributionsscanner/data/qt_attribution.json b/tests/manual/qtattributionsscanner/data/qt_attribution.json index d44985d35f..adc97d3b66 100644 --- a/tests/manual/qtattributionsscanner/data/qt_attribution.json +++ b/tests/manual/qtattributionsscanner/data/qt_attribution.json @@ -3,7 +3,7 @@ "Name": "Example Attribution", "QDocModule": "somemodule", "Description": "Does nothing specific.", - "QtUsage": "Optionally compiled into Some Qt Module. To avoid, pass \c -no-somemodule or \c -system-somemodule to \c configure.", + "QtUsage": "Optionally compiled into Some Qt Module. To avoid, pass \\c -no-somemodule or \\c -system-somemodule to \\c configure.", "License": "GNU General Public License v3.0 only", "LicenseId": "GPL-3.0", "LicenseFile": "LICENSE", diff --git a/tests/tests.pro b/tests/tests.pro deleted file mode 100644 index 85e4f3a53d..0000000000 --- a/tests/tests.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += auto