diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index d98d5dd35d4..a65437bdd4c 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -9,7 +9,7 @@ env: CMAKE_VERSION: 3.18.3 NINJA_VERSION: 1.10.1 BUILD_TYPE: Release - CCACHE_VERSION: 3.7.7 + CCACHE_VERSION: 4.2.1 QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject jobs: @@ -485,6 +485,19 @@ jobs: message(FATAL_ERROR "Build failed") endif() + - name: ccache statistics + shell: cmake -P {0} + run: | + file(TO_CMAKE_PATH "$ENV{GITHUB_WORKSPACE}" ccache_basedir) + set(ENV{CCACHE_BASEDIR} "${ccache_basedir}") + set(ENV{CCACHE_DIR} "${ccache_basedir}/.ccache") + set(ENV{CCACHE_SLOPPINESS} "pch_defines,time_macros") + set(ENV{CCACHE_COMPRESS} "true") + set(ENV{CCACHE_COMPRESSLEVEL} "6") + set(ENV{CCACHE_MAXSIZE} "800M") + if ("${{ matrix.config.cxx }}" STREQUAL "cl") + set(ENV{CCACHE_MAXSIZE} "1200M") + endif() execute_process(COMMAND ccache -s) - name: Run tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d1b2a39d3d..cc1b3be88bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,7 @@ install( qtcreator.pri qtcreatordata.pri qtcreator_ide_branding.pri - DESTINATION include + DESTINATION ${IDE_HEADER_INSTALL_PATH} COMPONENT Devel EXCLUDE_FROM_ALL ) install( @@ -171,7 +171,7 @@ install( src/qtcreatorplugin.pri src/qtcreatortool.pri src/rpath.pri - DESTINATION include/src + DESTINATION ${IDE_HEADER_INSTALL_PATH}/src COMPONENT Devel EXCLUDE_FROM_ALL ) diff --git a/cmake/FindCrashpad.cmake b/cmake/FindCrashpad.cmake index 919ec93cd8f..8b16fd83be2 100644 --- a/cmake/FindCrashpad.cmake +++ b/cmake/FindCrashpad.cmake @@ -49,6 +49,14 @@ find_path(CRASHPAD_LIB_DIR "${CMAKE_PREFIX_PATH}" ) +find_path(CRASHPAD_GEN_DIR + NAMES build/chromeos_buildflags.h + PATH_SUFFIXES gen + HINTS + "${CRASHPAD_BIN_DIR}" + "${CMAKE_PREFIX_PATH}" +) + if(APPLE) find_path(CRASHPAD_OBJ_DIR NAMES mig_output.child_portServer.o @@ -58,13 +66,6 @@ if(APPLE) "${CRASHPAD_LIB_DIR}/out/Default" "${CMAKE_PREFIX_PATH}" ) - find_path(CRASHPAD_GEN_DIR - NAMES build/chromeos_buildflags.h - PATH_SUFFIXES gen - HINTS - "${CRASHPAD_BIN_DIR}" - "${CMAKE_PREFIX_PATH}" - ) set(CRASHPAD_APPLE_VARS CRASHPAD_OBJ_DIR CRASHPAD_GEN_DIR) find_library(FWbsm bsm) find_library(FWAppKit AppKit) @@ -81,7 +82,8 @@ if(Crashpad_FOUND) add_library(Crashpad::Crashpad UNKNOWN IMPORTED) target_include_directories(Crashpad::Crashpad INTERFACE "${CRASHPAD_INCLUDE_DIR}" - "${CRASHPAD_INCLUDE_DIR}/third_party/mini_chromium/mini_chromium") + "${CRASHPAD_INCLUDE_DIR}/third_party/mini_chromium/mini_chromium" + "${CRASHPAD_GEN_DIR}") if(WIN32) target_link_libraries(Crashpad::Crashpad INTERFACE "${CRASHPAD_LIB_DIR}/third_party/mini_chromium/mini_chromium/base/base.lib" @@ -106,7 +108,6 @@ if(Crashpad_FOUND) ${FWbsm} ${FWAppKit} ${FWIOKit} ${FWSecurity}) set_target_properties(Crashpad::Crashpad PROPERTIES IMPORTED_LOCATION "${CRASHPAD_LIB_DIR}/client/libclient.a") - target_include_directories(Crashpad::Crashpad INTERFACE "${CRASHPAD_GEN_DIR}") elseif(UNIX) # TODO: Crashpad is not well supported on linux currently target_link_libraries(Crashpad::Crashpad INTERFACE diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index aefae6f7298..921106a3f6e 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -18,6 +18,9 @@ set(IDE_DATA_PATH "${_IDE_DATA_PATH}") # The IDE data path (rel set(IDE_DOC_PATH "${_IDE_DOC_PATH}") # The IDE documentation path (relative to CMAKE_INSTALL_PREFIX). set(IDE_BIN_PATH "${_IDE_BIN_PATH}") # The IDE bin path (relative to CMAKE_INSTALL_PREFIX). +set(IDE_HEADER_INSTALL_PATH "${_IDE_HEADER_INSTALL_PATH}") +set(IDE_CMAKE_INSTALL_PATH "${_IDE_CMAKE_INSTALL_PATH}") + file(RELATIVE_PATH RELATIVE_PLUGIN_PATH "/${IDE_BIN_PATH}" "/${IDE_PLUGIN_PATH}") file(RELATIVE_PATH RELATIVE_LIBEXEC_PATH "/${IDE_BIN_PATH}" "/${IDE_LIBEXEC_PATH}") file(RELATIVE_PATH RELATIVE_DATA_PATH "/${IDE_BIN_PATH}" "/${IDE_DATA_PATH}") @@ -93,6 +96,14 @@ function(qtc_output_binary_dir varName) endif() endfunction() +function(qtc_source_dir varName) + if (QTC_MERGE_BINARY_DIR) + set(${varName} ${QtCreator_SOURCE_DIR} PARENT_SCOPE) + else() + set(${varName} ${PROJECT_SOURCE_DIR} PARENT_SCOPE) + endif() +endfunction() + function(add_qtc_library name) cmake_parse_arguments(_arg "STATIC;OBJECT;SKIP_TRANSLATION;ALLOW_ASCII_CASTS;UNVERSIONED;FEATURE_INFO" "DESTINATION;COMPONENT;SOURCES_PREFIX;BUILD_DEFAULT" @@ -208,7 +219,7 @@ function(add_qtc_library name) "$" PUBLIC "$" - "$" + "$" ) endif() @@ -463,7 +474,7 @@ function(add_qtc_plugin target_name) "$" PUBLIC "$" - "$" + "$" ) set(plugin_dir "${IDE_PLUGIN_PATH}") @@ -531,18 +542,18 @@ function(add_qtc_plugin target_name) # export of external plugins install(EXPORT ${export} FILE ${export}Targets.cmake - DESTINATION lib/cmake/${export} + DESTINATION ${IDE_CMAKE_INSTALL_PATH}/${export} COMPONENT Devel EXCLUDE_FROM_ALL NAMESPACE QtCreator:: ) include(CMakePackageConfigHelpers) configure_package_config_file(${_THIS_MODULE_BASE_DIR}/Config.cmake.in "${CMAKE_BINARY_DIR}/cmake/${export}Config.cmake" - INSTALL_DESTINATION lib/cmake/${export} + INSTALL_DESTINATION ${IDE_CMAKE_INSTALL_PATH}/${export} ) install( FILES ${CMAKE_BINARY_DIR}/cmake/${export}Config.cmake - DESTINATION lib/cmake/${export} + DESTINATION ${IDE_CMAKE_INSTALL_PATH}/${export} COMPONENT Devel EXCLUDE_FROM_ALL ) export(EXPORT ${export} @@ -971,12 +982,13 @@ function(qtc_add_public_header header) set(header "${CMAKE_CURRENT_SOURCE_DIR}/${header}") endif() + qtc_source_dir(qtcreator_source_dir) get_filename_component(source_dir ${header} DIRECTORY) - file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${source_dir}) + file(RELATIVE_PATH include_dir_relative_path ${qtcreator_source_dir} ${source_dir}) install( FILES ${header} - DESTINATION "include/${include_dir_relative_path}" + DESTINATION "${IDE_HEADER_INSTALL_PATH}/${include_dir_relative_path}" COMPONENT Devel EXCLUDE_FROM_ALL ) endfunction() diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index 103fa6045a5..8335ae34578 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -1,5 +1,7 @@ -if (CMAKE_VERSION VERSION_LESS 3.16) - set(BUILD_WITH_PCH OFF) +if (CMAKE_VERSION VERSION_LESS 3.18) + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_VERSION VERSION_LESS 3.16) + set(BUILD_WITH_PCH OFF) + endif() endif() include(FeatureSummary) @@ -35,7 +37,7 @@ if (APPLE) set(_IDE_APP_PATH ".") set(_IDE_APP_TARGET "${IDE_DISPLAY_NAME}") - set(_IDE_OUTPUT_PATH "${_IDE_APP_PATH}/${_IDE_APP_TARGET}.app/Contents") + set(_IDE_OUTPUT_PATH "${_IDE_APP_TARGET}.app/Contents") set(_IDE_LIBRARY_BASE_PATH "Frameworks") set(_IDE_LIBRARY_PATH "${_IDE_OUTPUT_PATH}/${_IDE_LIBRARY_BASE_PATH}") @@ -44,6 +46,9 @@ if (APPLE) set(_IDE_DATA_PATH "${_IDE_OUTPUT_PATH}/Resources") set(_IDE_DOC_PATH "${_IDE_OUTPUT_PATH}/Resources/doc") set(_IDE_BIN_PATH "${_IDE_OUTPUT_PATH}/MacOS") + + set(_IDE_HEADER_INSTALL_PATH "${_IDE_DATA_PATH}/Headers/qtcreator") + set(_IDE_CMAKE_INSTALL_PATH "${_IDE_DATA_PATH}/lib/cmake") elseif(WIN32) set(_IDE_APP_PATH "bin") set(_IDE_APP_TARGET "${IDE_ID}") @@ -55,6 +60,9 @@ elseif(WIN32) set(_IDE_DATA_PATH "share/qtcreator") set(_IDE_DOC_PATH "share/doc/qtcreator") set(_IDE_BIN_PATH "bin") + + set(_IDE_HEADER_INSTALL_PATH "include/qtcreator") + set(_IDE_CMAKE_INSTALL_PATH "lib/cmake") else () include(GNUInstallDirs) set(_IDE_APP_PATH "${CMAKE_INSTALL_BINDIR}") @@ -67,6 +75,9 @@ else () set(_IDE_DATA_PATH "${CMAKE_INSTALL_DATAROOTDIR}/qtcreator") set(_IDE_DOC_PATH "${CMAKE_INSTALL_DATAROOTDIR}/doc/qtcreator") set(_IDE_BIN_PATH "${CMAKE_INSTALL_BINDIR}") + + set(_IDE_HEADER_INSTALL_PATH "include/qtcreator") + set(_IDE_CMAKE_INSTALL_PATH "lib/cmake") endif () file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}") @@ -190,7 +201,7 @@ function(set_public_includes target includes) file(RELATIVE_PATH include_dir_relative_path ${PROJECT_SOURCE_DIR} ${inc_dir}) target_include_directories(${target} PUBLIC $ - $ + $ ) endforeach() endfunction() diff --git a/cmake/QtCreatorDocumentation.cmake b/cmake/QtCreatorDocumentation.cmake index b2cf79224e2..49bf3d2d02d 100644 --- a/cmake/QtCreatorDocumentation.cmake +++ b/cmake/QtCreatorDocumentation.cmake @@ -219,7 +219,10 @@ function(qtc_docs_dir varName) set(${varName} "${QtCreator_SOURCE_DIR}/doc" PARENT_SCOPE) elseif(QtCreatorDocumentation_LIST_DIR MATCHES /lib/cmake/QtCreator$) # Dev package - set(${varName} "${QtCreatorDocumentation_LIST_DIR}/../../../doc" PARENT_SCOPE) + file(RELATIVE_PATH relative_header_path "/${IDE_CMAKE_INSTALL_PATH}/QtCreator" "/${IDE_HEADER_INSTALL_PATH}") + set(${varName} + "${QtCreatorDocumentation_LIST_DIR}/${relative_header_path}/doc" + PARENT_SCOPE) else() message(FATAL_ERROR "Could not find qtc_docs_dir") endif() diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 8425aa50241..077d181493d 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -53,7 +53,7 @@ if(WITH_ONLINE_DOCS) endif() install(DIRECTORY config - DESTINATION doc + DESTINATION ${IDE_HEADER_INSTALL_PATH}/doc COMPONENT Devel EXCLUDE_FROM_ALL ) diff --git a/doc/qtcreator/images/creator-qbs-build-app.png b/doc/qtcreator/images/creator-qbs-build-app.png index f6d5078fdbd..ef7ea314625 100644 Binary files a/doc/qtcreator/images/creator-qbs-build-app.png and b/doc/qtcreator/images/creator-qbs-build-app.png differ diff --git a/doc/qtcreator/images/creator-qbs-build-clean.png b/doc/qtcreator/images/creator-qbs-build-clean.png index 5a4d859a827..cc9cd9af04e 100644 Binary files a/doc/qtcreator/images/creator-qbs-build-clean.png and b/doc/qtcreator/images/creator-qbs-build-clean.png differ diff --git a/doc/qtcreator/images/qtcreator-build-configurations.png b/doc/qtcreator/images/qtcreator-build-configurations.png new file mode 100644 index 00000000000..a1c2d7de82c Binary files /dev/null and b/doc/qtcreator/images/qtcreator-build-configurations.png differ diff --git a/doc/qtcreator/images/qtcreator-build-run-options-cmake.png b/doc/qtcreator/images/qtcreator-build-run-options-cmake.png new file mode 100644 index 00000000000..f95f905883a Binary files /dev/null and b/doc/qtcreator/images/qtcreator-build-run-options-cmake.png differ diff --git a/doc/qtcreator/images/qtcreator-build-settings-default.png b/doc/qtcreator/images/qtcreator-build-settings-default.png new file mode 100644 index 00000000000..3ca79641a6b Binary files /dev/null and b/doc/qtcreator/images/qtcreator-build-settings-default.png differ diff --git a/doc/qtcreator/images/qtcreator-build-settings-qbs.png b/doc/qtcreator/images/qtcreator-build-settings-qbs.png new file mode 100644 index 00000000000..4aba9efc58d Binary files /dev/null and b/doc/qtcreator/images/qtcreator-build-settings-qbs.png differ diff --git a/doc/qtcreator/images/qtcreator-build-settings-qmake.png b/doc/qtcreator/images/qtcreator-build-settings-qmake.png new file mode 100644 index 00000000000..6371c617250 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-build-settings-qmake.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png b/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png new file mode 100644 index 00000000000..0fce3dd7116 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-build-settings.png b/doc/qtcreator/images/qtcreator-cmake-build-settings.png index e05e124f8a3..5d6968b2cf5 100644 Binary files a/doc/qtcreator/images/qtcreator-cmake-build-settings.png and b/doc/qtcreator/images/qtcreator-cmake-build-settings.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-build-steps.png b/doc/qtcreator/images/qtcreator-cmake-build-steps.png index 02784e47d20..9ecce473c5b 100644 Binary files a/doc/qtcreator/images/qtcreator-cmake-build-steps.png and b/doc/qtcreator/images/qtcreator-cmake-build-steps.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-clean-steps.png b/doc/qtcreator/images/qtcreator-cmake-clean-steps.png index e04711c3a74..9e1b9d51232 100644 Binary files a/doc/qtcreator/images/qtcreator-cmake-clean-steps.png and b/doc/qtcreator/images/qtcreator-cmake-clean-steps.png differ diff --git a/doc/qtcreator/images/qtcreator-incredibuild-build-steps-general.png b/doc/qtcreator/images/qtcreator-incredibuild-build-steps-general.png index 44be472332c..96dcf371cac 100644 Binary files a/doc/qtcreator/images/qtcreator-incredibuild-build-steps-general.png and b/doc/qtcreator/images/qtcreator-incredibuild-build-steps-general.png differ diff --git a/doc/qtcreator/images/qtcreator-incredibuild-build-steps-windows.png b/doc/qtcreator/images/qtcreator-incredibuild-build-steps-windows.png index c9767fe860e..3077759fcbc 100644 Binary files a/doc/qtcreator/images/qtcreator-incredibuild-build-steps-windows.png and b/doc/qtcreator/images/qtcreator-incredibuild-build-steps-windows.png differ diff --git a/doc/qtcreator/images/qtcreator-language-client-options-java.png b/doc/qtcreator/images/qtcreator-language-client-options-java.png new file mode 100644 index 00000000000..d70df4dd477 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-language-client-options-java.png differ diff --git a/doc/qtcreator/images/qtcreator-language-client-options.png b/doc/qtcreator/images/qtcreator-language-client-options.png index ab1a0e09d37..0ae18ec4e41 100644 Binary files a/doc/qtcreator/images/qtcreator-language-client-options.png and b/doc/qtcreator/images/qtcreator-language-client-options.png differ diff --git a/doc/qtcreator/images/qtcreator-locator.png b/doc/qtcreator/images/qtcreator-locator.png index 16b656317d2..82fff209d83 100644 Binary files a/doc/qtcreator/images/qtcreator-locator.png and b/doc/qtcreator/images/qtcreator-locator.png differ diff --git a/doc/qtcreator/images/qtcreator-projectpane.png b/doc/qtcreator/images/qtcreator-projectpane.png index b6d01fd0ca9..0112b9e8967 100644 Binary files a/doc/qtcreator/images/qtcreator-projectpane.png and b/doc/qtcreator/images/qtcreator-projectpane.png differ diff --git a/doc/qtcreator/images/qtcreator-projects-view-cmake.png b/doc/qtcreator/images/qtcreator-projects-view-cmake.png new file mode 100644 index 00000000000..c3752d345b3 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-projects-view-cmake.png differ diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index 2aa36b9f839..ed533106498 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -51,6 +51,10 @@ for such a Qt version, the minimum required Android version on devices is 5.0 (API level 21). For more information, see \l{Qt for Android}. + To enable helpful code editing features for Java, such as code completion, + highlighting, function tooltips, and navigating in code, specify settings + for a \l{Specifying Java Language Server Settings}{Java language server}. + The Android Debug Bridge (adb) command line tool is integrated to \QC to enable you to deploy applications to connected Android devices, to run them, and to read their logs. It includes a client and server that run on diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdocinc b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc similarity index 64% rename from doc/qtcreator/src/cmake/creator-projects-cmake-building.qdocinc rename to doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc index 9b6aa3f0d68..8746b0af1e6 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdocinc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -23,30 +23,34 @@ ** ****************************************************************************/ -// ********************************************************************** -// NOTE: the sections are not ordered by their logical order to avoid -// reshuffling the file each time the index order changes (i.e., often). -// Run the fixnavi.pl script to adjust the links to the index order. -// ********************************************************************** - /*! -//! [cmake build configuration] + \previouspage creator-build-settings.html + \page creator-build-settings-cmake.html + \nextpage creator-build-settings-qmake.html - \section2 CMake Build Configuration + \title CMake Build Configuration Configuring medium-sized to large CMake projects in \QC can be a challenge due to the number of options that you need to pass to - CMake to configure the project correctly. \QC creates an initial - configuration for you based on the kit settings and displays it in - the \uicontrol {Initial CMake parameters} field. + CMake to configure the project correctly. To make this easier, + \QC creates an initial configuration for you based on the kit + settings and displays it in the \uicontrol {Initial CMake parameters} + field and in a table that lists the parameter names and values. - \image qtcreator-cmake-build-settings.png + \image qtcreator-cmake-build-settings-initial.png "CMake build settings" + + Parameter names are listed in the \uicontrol Key column. Names with a + common prefix (up to the first underscore character) are grouped under + the prefix. + + \section1 Modifying Initial Parameters In the \uicontrol Value column, you can view and edit the actual values - of the parameters that are passed to CMake. Parameter names are listed - in the \uicontrol Key column. Names with a common prefix (up to the first - underscore character) are grouped under the prefix. To view all parameters, - select the \uicontrol Advanced check box. + of the parameters that are passed to CMake. + + \image qtcreator-cmake-build-settings.png "CMake parameters" + + To view all parameters, select the \uicontrol Advanced check box. To add parameters, select \uicontrol Add, and then select the type of the parameter that you are adding: \uicontrol Boolean, \uicontrol String, @@ -58,6 +62,9 @@ \uicontrol {Force to directory}, or \uicontrol {Force to string} in the context menu. + To copy the name or value of the selected parameter to the clipboard, + select \uicontrol Copy in the context menu. + To modify the value of a parameter, double-click it, or select it, and then select \uicontrol Edit. @@ -69,6 +76,9 @@ To reset all the changes that you made, select \uicontrol Reset. + To modify the environment variable values for the CMake build environment, + select \uicontrol {Batch Edit}. For more information, see \l{Batch Editing}. + To save the changes, select \uicontrol {Apply Configuration Changes}. Keep in mind that a configuration change might trigger a follow-up configuration change. @@ -78,37 +88,37 @@ that if you remove the build directory, all the custom parameters that are not part of the initial CMake parameters are also removed. - To reconfigure a project after making changes to the initial parameters, + To reconfigure a project using the modified parameters, select \uicontrol Build > \uicontrol {Clear CMake Configuration}, which removes the CMakeCache.txt file. This enables you to do a full rebuild. -//! [cmake build configuration] + \section1 Re-configuring with Initial Parameters + To reset CMake parameters to the initial ones, select + \uicontrol {Re-configure with Initial Parameters}. -//! [cmake build steps] + To be asked before \QC resets the changes, select \uicontrol Tools > + \uicontrol Options > \uicontrol {Build & Run} > \uicontrol CMake > + \uicontrol {Ask before re-configuring with initial parameters}. - \section2 CMake Build Steps + \image qtcreator-build-run-options-cmake.png "CMake Build & Run options" + + \section1 CMake Build Steps \QC builds CMake projects by running \c {cmake . --build}, which then runs the CMake generator specified in the project configuration: \c make, \c mingw32-make, \c nmake, or \c ninja, for example. The CMake generator - produces project files for \QC. + produces project files for \QC. Multi-config generators are also supported. You can add arguments to pass to CMake and the generator and targets for the build command in \uicontrol {Build Steps}. - \image qtcreator-cmake-build-steps.png + \image qtcreator-cmake-build-steps.png "CMake build steps" \note While the other CMake generators are installed together with Qt, - you usually need to install Ninja yourself. For more information, see - \l {Using Ninja as a CMake Generator}. + you usually need to install Ninja yourself. -//! [cmake build steps] - - -//! [cmake ninja] - - \section2 Using Ninja as a CMake Generator + \section1 Using Ninja as a CMake Generator To use \l {https://ninja-build.org/}{Ninja} with CMake, you must install it and select it as the CMake generator in the build and run kit: @@ -132,12 +142,18 @@ \uicontrol Build > \uicontrol {Rebuild Project}. This cleans up the build directory and performs a new build. -//! [cmake ninja] + \section1 Using CMake with Conan + \QC can automatically set up the \l {Setting Up Conan} + {Conan package manager} for use with CMake. -//! [cmake clean steps] + Select \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > + \uicontrol CMake > \uicontrol {Package manager auto setup} to set the + value of the \c CMAKE_PROJECT_INCLUDE_BEFORE variable to the path to a + CMake script that installs dependencies from a \c conanfile.txt, + \c conanfile.py, or \c vcpkg.json file in the project source directory. - \section2 CMake Clean Steps + \section1 CMake Clean Steps When building with CMake, you can add arguments to pass to CMake and the generator and targets for the clean command in \uicontrol {Clean Steps}. @@ -146,6 +162,4 @@ The build errors and warnings are parsed and displayed in the \uicontrol Issues output pane. - -//! [cmake clean steps] */ diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc index 594e7c16821..572180a1d6a 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -57,6 +57,14 @@ a \c CMakeLists.txt configuration file in a project. Project information is also automatically refreshed when you build the project. + The \uicontrol {File System} section in the sidebar \uicontrol Projects view + displays information from the file system. \QC cannot determine whether the + files are part of the project. For example, header files that \QC finds in + the project directories but that are not mentioned in the CMakeLists.txt + files are listed here. + + \image qtcreator-projects-view-cmake.png "File System section in Projects view" + \section1 Adding CMake Tools \QC requires CMake's \l{https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html} @@ -160,7 +168,7 @@ \list \li \l {Opening Projects} - \li \l {Specifying Build Settings} + \li \l {CMake Build Configuration} \li \l {Specifying Run Settings} \li \l {Deploying CMake Projects to Generic Remote Linux Devices} \endlist diff --git a/doc/qtcreator/src/conan/creator-projects-conan-building.qdocinc b/doc/qtcreator/src/conan/creator-projects-conan-building.qdoc similarity index 87% rename from doc/qtcreator/src/conan/creator-projects-conan-building.qdocinc rename to doc/qtcreator/src/conan/creator-projects-conan-building.qdoc index c4d8ff26e52..20e0c4159bd 100644 --- a/doc/qtcreator/src/conan/creator-projects-conan-building.qdocinc +++ b/doc/qtcreator/src/conan/creator-projects-conan-building.qdoc @@ -24,8 +24,17 @@ ****************************************************************************/ /*! -//! [conan build steps] - \section1 Specifying Build Settings for Conan + \previouspage creator-build-settings-incredibuild.html + \page creator-build-settings-conan.html + \nextpage creator-run-settings.html + + \title Conan Build Configuration + + You can specify build steps for Conan. + + For more information about configuring Conan, see \l{Setting Up Conan}. + + \section1 Conan Build Steps To configure a project to be built using the Conan package manager, select \uicontrol {Add Build Step} > \uicontrol {Run Conan Install}. @@ -38,7 +47,4 @@ The \uicontrol {Conan install} field displays the effective build command. You can add arguments for the command in the \uicontrol {Additional arguments} field. - - For more information about configuring Conan, see \l{Setting Up Conan}. -//! [conan build steps] */ diff --git a/doc/qtcreator/src/conan/creator-projects-conan.qdoc b/doc/qtcreator/src/conan/creator-projects-conan.qdoc index a846c252047..abaf4139393 100644 --- a/doc/qtcreator/src/conan/creator-projects-conan.qdoc +++ b/doc/qtcreator/src/conan/creator-projects-conan.qdoc @@ -62,5 +62,5 @@ {conanfile.txt} file that specifies the needed libraries and packages. Then, you must edit the build settings of the project to specify the location of the file and the contents of the Conan install command. - For more information, see \l {Specifying Build Settings for Conan}. + For more information, see \l {Conan Build Steps}. */ diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index 39a87166ac7..bdc1bda67e1 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -64,7 +64,10 @@ \list 1 - \li Debugging is enabled by default for Qt 5.0, or later. + \li If you use qmake as the build system, make sure that + debugging is enabled in the \uicontrol {Build Settings}, + \uicontrol {QML debugging and profiling} field, either + explicitly for the project or globally by default. \image qtcreator-projectpane.png "qmake general build settings pane" diff --git a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc index 23f7d690639..05d5554aed0 100644 --- a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc +++ b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc @@ -55,9 +55,9 @@ \note You can also select \uicontrol Edit > \uicontrol {Find/Replace} > \uicontrol {Advanced Find} > \uicontrol {C++ Symbols} to search for - classes, functions, enums, and declarations either from files listed as - part of the project or from all files that are used by the code, such as - include files. + classes, functions, enums, and declarations (including type aliases) either + from files listed as part of the project or from all files that are used by + the code, such as include files. \image qtcreator-search-cpp-symbols.png \endif diff --git a/doc/qtcreator/src/editors/creator-locator.qdoc b/doc/qtcreator/src/editors/creator-locator.qdoc index e351ebc746d..cfd44c19de5 100644 --- a/doc/qtcreator/src/editors/creator-locator.qdoc +++ b/doc/qtcreator/src/editors/creator-locator.qdoc @@ -113,8 +113,9 @@ \li Locating bookmarks (\c {b}). For more information, see \l{Using Bookmarks}. - \li Locating class (\c {c}), enum, and function (\c {m}) definitions in - your project or anywhere referenced from your project (\c {:}) + \li Locating class (\c {c}), enum, function (\c {m}), and type alias + definitions in your project or anywhere referenced from your + project (\c {:}) \endif \li Locating QML methods (\c {m}) diff --git a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc index 3faa85d43a9..1d668a3e07a 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-language-server.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -78,17 +78,33 @@ \section1 Specifying Settings for Language Clients - To use a language server: + You can add a generic generic stdIO language server for Python, for example. + For \l{Connecting Android Devices}{Android development}, you can add a Java + language server. + + \section2 Adding Language Servers + + To view a list of language servers, select \uicontrol Tools > + \uicontrol Options > \uicontrol {Language Client} (or + \uicontrol {Qt Creator} > \uicontrol Preferences > + \uicontrol {Language Client} > on \macos). + + \image qtcreator-language-client-options.png "Language client options page" + + To enable a language server, select the check box next to the language + server name and specify settings for the server. + + To remove language servers from the list, select \uicontrol Delete. + + \section2 Specifying Generic Settings + + To add a generic language server: \list 1 \li Select \uicontrol Tools > \uicontrol Options > - \uicontrol {Language Client} (or \uicontrol {Qt Creator} > - \uicontrol Preferences > \uicontrol {Language Client} > on - \macos) to view a list of language servers. - \image qtcreator-language-client-options.png "Language client options page" - \li Select the check box next to the language server name to enable the - language server. - \li Select \uicontrol Add to add language servers. + \uicontrol {Language Client} > \uicontrol Add > + \uicontrol {New Generic StdIO Language Server} + to add a generic language server. \li In the \uicontrol Name field, enter a name for the language server. Select the \inlineimage replace.png (\uicontrol {Variables}) button to use a variable for the server @@ -102,9 +118,8 @@ with a matching MIME type is opened. The \uicontrol {General Messages} \l{Viewing Output}{output pane} displays information about the connection to the language server. - \li In the \uicontrol Capabilities field, you can see the features - that are supported by the language server. Only some of them are - implemented by \QC. + \li In the \uicontrol Initialization field, you can add language server + specific JSON attributes to pass to an \c initialize request. \li In the \uicontrol Executable field, enter the path to the language server executable. \li In the \uicontrol Arguments field, enter any required command line @@ -112,7 +127,23 @@ arguments. \endlist - To remove language servers from the list, select \uicontrol Delete. + \section2 Specifying Java Language Server Settings + + To add a Java language server: + + \list 1 + \li Select \uicontrol Tools > \uicontrol Options > + \uicontrol {Language Client} > \uicontrol Add > + \uicontrol {New Java Language Server} to add a Java language server. + \image qtcreator-language-client-options-java.png "Java language server options" + \li In the \uicontrol Name field, enter a name for the language server. + Select the \inlineimage replace.png + (\uicontrol {Variables}) button to use a variable for the server + name. For more information, see \l{Using Qt Creator Variables}. + \li In the \uicontrol Java field, enter the path to the Java executable. + \li In the \uicontrol {Java Language Server} field, enter the path to + the Java language server \c .jar file. + \endlist \section1 Supported Locator Filters @@ -129,8 +160,8 @@ \section1 Reporting Issues - The language service client has been mostly tested with Python. - If problems arise when you try it or some other language, please select + The language service client has been mostly tested with Python and Java. + If problems arise when you try them or some other language, please select \uicontrol Help > \uicontrol {Report Bug} to report them in the \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}. The reports should include \QC console output with the environment diff --git a/doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdocinc b/doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdoc similarity index 83% rename from doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdocinc rename to doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdoc index bb7bfcd6ad9..84c754d23ab 100644 --- a/doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdocinc +++ b/doc/qtcreator/src/incredibuild/creator-projects-incredibuild-building.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -23,9 +23,18 @@ ** ****************************************************************************/ /*! -//! [incredibuild build steps] + \previouspage creator-build-settings-meson.html + \page creator-build-settings-incredibuild.html + \nextpage creator-build-settings-conan.html - \section2 IncrediBuild Build Steps + \title IncrediBuild Build Configuration + + You can specify build steps and clean steps for IncrediBuild. + + For more information about configuring IncrediBuild, see + \l{Setting Up IncrediBuild}. + + \section1 IncrediBuild Build Steps To use IncrediBuild, select \uicontrol {Add Build Step} > \uicontrol {IncrediBuild for Linux} or @@ -53,7 +62,7 @@ The distribution control settings to specify depend on whether you are using Linux or Windows. - \section3 Distribution Control Settings on Linux + \section2 Distribution Control Settings on Linux \image qtcreator-incredibuild-build-steps-linux.png @@ -66,7 +75,7 @@ \li \uicontrol {Alternate tasks preference} \endlist - \section3 Distribution Control Settings on Windows + \section2 Distribution Control Settings on Windows \image qtcreator-incredibuild-build-steps-windows.png @@ -86,8 +95,8 @@ \li \uicontrol {Maximum CPUs to utilize in the build} specifies the maximum amount of remote cores to use in the build. Overrides the corresponding global setting. - \li \uicontrol {Newest allowed Helper machine OS} and - \uicontrol {Oldest allowed Helper machine OS} specify the newest and + \li \uicontrol {Newest allowed helper machine OS} and + \uicontrol {Oldest allowed helper machine OS} specify the newest and oldest operating system installed on a Helper machine to be allowed to participate as a Helper in the build. \li \uicontrol {Build title} specifies a custom header line which will @@ -100,12 +109,12 @@ \c{.ib_mon} file is added to the end of the build output. \li \uicontrol {Suppress STDOUT} does not write anything to the standard output. - \li \uicontrol {Output log file} writes build output to a file. - \li \uicontrol {Show commands in output} shows the command-line used by + \li \uicontrol {Output Log file} writes build output to a file. + \li \uicontrol {Show Commands in output} shows the command-line used by IncrediBuild to build the file. - \li \uicontrol {Show agents in output} shows the Agent used to build + \li \uicontrol {Show Agents in output} shows the Agent used to build each file. - \li \uicontrol {Show time in output} shows the start and finish time for + \li \uicontrol {Show Time in output} shows the start and finish time for each file built. \li \uicontrol {Hide IncrediBuild Header in output} suppresses the IncrediBuild header in the build output. @@ -113,31 +122,26 @@ internal Incredibuild logging level for this build. Does not affect output or any user accessible logging. Used mainly to troubleshoot issues with the help of IncrediBuild support. - \li \uicontrol {Set an environment variable} sets or overrides + \li \uicontrol {Set an Environment Variable} sets or overrides environment variables for the context of the build. \li \uicontrol {Stop on errors} stops the execution as soon as an error is encountered. This is the default behavior in Visual Studio builds, but not for Make and Build tools or Dev Tools builds. - \li \uicontrol {Additional arguments} are concatenated to the final + \li \uicontrol {Additional Arguments} are concatenated to the final buildconsole command line. \li \uicontrol {Open Build Monitor} opens an IncrediBuild Build Monitor that graphically displays the build's progress once the build starts. \endlist -//! [incredibuild build steps] - -//! [incredibuild clean steps] - - \section2 IncrediBuild Clean Steps + \section1 IncrediBuild Clean Steps When building with IncrediBuild, you can add arguments and targets for the - clean command in \uicontrol {Clean Steps}. + clean command in \uicontrol {Clean Steps}. For more information, see + \l{Clean Steps}. For more information about the settings, see \l{IncrediBuild Build Steps}. The build errors and warnings are parsed and displayed in the \uicontrol Issues output pane. - -//! [incredibuild clean steps] */ diff --git a/doc/qtcreator/src/meson/creator-projects-meson-building.qdocinc b/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc similarity index 89% rename from doc/qtcreator/src/meson/creator-projects-meson-building.qdocinc rename to doc/qtcreator/src/meson/creator-projects-meson-building.qdoc index 40b5f929fee..852c6018fd0 100644 --- a/doc/qtcreator/src/meson/creator-projects-meson-building.qdocinc +++ b/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -23,9 +23,11 @@ ** ****************************************************************************/ /*! -//! [meson build configuration] + \previouspage creator-build-settings-qbs.html + \page creator-build-settings-meson.html + \nextpage creator-build-settings-incredibuild.html - \section2 Meson Build Configuration + \title Meson Build Configuration \image qtcreator-meson-build-settings.png @@ -43,12 +45,7 @@ \note Any modified setting will remain in bold until \uicontrol {Apply configuration changes} is selected. -//! [meson build configuration] - - -//! [meson build steps] - - \section2 Meson Build Steps + \section1 Meson Build Steps \QC builds Meson projects by running \c {ninja -v target}. @@ -60,11 +57,7 @@ The build errors and warnings are parsed and displayed in the \uicontrol Issues output pane. -//! [meson build steps] - -//! [meson clean steps] - - \section2 Meson Clean Steps + \section1 Meson Clean Steps When building with Meson, you can add arguments and targets for the clean command in \uicontrol {Clean Steps}. @@ -74,5 +67,4 @@ The build errors and warnings are parsed and displayed in the \uicontrol Issues output pane. -//! [meson clean steps] */ diff --git a/doc/qtcreator/src/meson/creator-projects-meson.qdoc b/doc/qtcreator/src/meson/creator-projects-meson.qdoc index 48a9d310d33..bffec6b41e7 100644 --- a/doc/qtcreator/src/meson/creator-projects-meson.qdoc +++ b/doc/qtcreator/src/meson/creator-projects-meson.qdoc @@ -111,7 +111,7 @@ \list \li \l {Opening Projects} - \li \l {Specifying Build Settings} + \li \l {Meson Build Configuration} \li \l {Specifying Run Settings} \endlist */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc new file mode 100644 index 00000000000..eec535a6887 --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** 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. +** +****************************************************************************/ + +/*! + \previouspage creator-build-settings-cmake.html + \page creator-build-settings-qmake.html + \nextpage creator-build-settings-qbs.html + + \title qmake Build Configuration + + \image qtcreator-projectpane.png "qmake build settings" + + By default, \QC builds qmake projects in a separate directory from the + source directory, as \l{glossary-shadow-build} {shadow builds}. This + keeps the files generated for each \l{glossary-buildandrun-kit} + {build and run kit} separate. If you only build and run with a single + \l{glossary-buildandrun-kit}{kit}, you can deselect the + \uicontrol {Shadow build} checkbox. Select the build directory in the + \uicontrol {Build Directory} field. + + To make in-source builds the default option for all projects, select + \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > + \uicontrol {Default Build Properties}, and enter a period (.) in the + \uicontrol {Default build directory} field. + + In the \uicontrol {Tooltip in target selector} field, you can enter text + that is displayed as a tooltip when you hover the mouse over the build + configuration in the \l{Building for Multiple Platforms}{kit selector}. + + You can create separate versions of project files to keep platform-dependent + code separate. You can use qmake \l{Adding Platform Specific Source Files} + {scopes} to select the file to process depending on which platform qmake is + run on. + + If debug info is being generated, you can have it placed into separate + files, rather than embedded into the binary, by selecting + \uicontrol Enable in the \uicontrol {Separate debug info} field. For + more information, see \l{Using the Performance Analyzer}. To use default + settings, select \uicontrol {Leave at Default}. + + In the \uicontrol {qmake system() behavior when parsing} field, you can + select whether processes are run via qmake's \c system() function or + ignored. Setting this option to \uicontrol Ignore might help if opening + or closing projects takes too long, but it might produce inexact parsing + results. + + \section1 Global qmake Settings + + To specify settings for all qmake builds, select \uicontrol Tools + > \uicontrol Options > \uicontrol {Build & Run} > + \uicontrol Qmake. + + \image qtcreator-build-settings-qmake.png "qmake build and run options" + + To set the default build properties, select \uicontrol Tools + > \uicontrol Options > \uicontrol {Build & Run} > + \uicontrol {Default Build Properties}. + + \image qtcreator-build-settings-default.png "default build options" + + \section1 Compiling QML + + Since Qt 5.11, you can compile QML source code into the final binary. This + improves the startup time of the application and eliminates the need to + deploy QML files together with the application. For more information, see + \l{Ahead-of-Time Compilation}. + + \QC project wizard templates create Qt Quick projects that can be compiled, + because they are set up to use the Qt Resource System. To compile QML code, + select \uicontrol Enable in the \uicontrol {Qt Quick Compiler} field. To + use default settings, select \uicontrol {Leave at Default}. + + \note In earlier Qt versions, this was a commercial feature. For more + information, see \l{http://doc.qt.io/QtQuickCompiler/}{Qt Quick Compiler}. + + \section1 qmake Build Steps + + \QC builds qmake projects by running the \c make or \c nmake command from + the Qt version defined for the current build configuration. + + \image qtcreator-build-steps.png "Build steps" + + To override the shell command that \QC constructs by default, disable or + remove the build step and add a custom build step that specifies another + shell command. + + By default, \QC uses all the CPU cores available to achieve maximum build + parallelization. On Linux and \macos, you can specify the number of parallel + jobs to use for building in the \uicontrol {Parallel jobs} field. Select the + \uicontrol {Override MAKEFLAGS} check box to override existing MAKEFLAGS + variables. + + Select \uicontrol {Add Build Step} > \uicontrol {IncrediBuild for Linux} or + \uicontrol {IncrediBuild for Windows} to accelerate builds by using + \l{IncrediBuild Build Configuration}{IncrediBuild}. + + Select \uicontrol {Add Build Step} > \uicontrol {Run Conan Install} to use + the \l{Conan Build Configuration}{Conan} package manager with qmake +*/ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc index df44ceba5e0..9c79a1c4936 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -89,7 +89,7 @@ \list \li \l {Opening Projects} - \li \l {Specifying Build Settings} + \li \l {Qbs Build Configuration} \li \l {Specifying Run Settings} \endlist */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdocinc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc similarity index 76% rename from doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdocinc rename to doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc index 54e2f3c03e5..0bffb2dffea 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdocinc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -24,11 +24,35 @@ ****************************************************************************/ /*! -//! [qbs build steps] + \previouspage creator-build-settings-qmake.html + \page creator-build-settings-qbs.html + \nextpage creator-build-settings-meson.html - \section2 Qbs Build Steps + \title Qbs Build Configuration - \image creator-qbs-build-app.png + \image qtcreator-build-settings-qbs.png "Qbs build settings" + + Qbs builds projects in the directory specified in the + \uicontrol {Build Directory} field. + + In the \uicontrol {Tooltip in target selector} field, you can enter text + that is displayed as a tooltip when you hover the mouse over the build + configuration in the \l{Building for Multiple Platforms}{kit selector}. + + You can enter a name for the build configuration in the + \uicontrol {Configuration name} field. + + If debug info is being generated, you can have it placed into separate + files, rather than embedded into the binary, by selecting + \uicontrol Enable in the \uicontrol {Separate debug info} field. For + more information, see \l{Using the Performance Analyzer}. To use default + settings, select \uicontrol {Leave at Default}. + + For more information about configuring Qbs, see \l{Setting Up Qbs}. + + \section1 Qbs Build Steps + + \image creator-qbs-build-app.png "Qbs build steps" To specify build steps for Qbs: @@ -95,16 +119,11 @@ The \uicontrol {Equivalent command line} field displays the build command that is constructed based on the selected options. -//! [qbs build steps] - - -//! [qbs clean steps] - - \section2 Qbs Clean Steps + \section1 Qbs Clean Steps When building with Qbs, you can specify flags in \uicontrol {Clean Steps}: - \image creator-qbs-build-clean.png + \image creator-qbs-build-clean.png "Qbs clean steps" \list @@ -118,6 +137,4 @@ The \uicontrol {Equivalent command line} field displays the clean command that is constructed based on the selected options. - -//! [qbs clean steps] */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build.qdoc index 1acaa51a7cc..eb4faea02c1 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -32,7 +32,7 @@ /*! \previouspage creator-debuggers.html \page creator-build-settings.html - \nextpage creator-run-settings.html + \nextpage creator-build-settings-cmake.html \title Specifying Build Settings @@ -57,6 +57,8 @@ \section1 Managing Build Configurations + \image qtcreator-build-configurations.png "Build Settings" + You specify build settings in the \uicontrol Projects mode. To add a new build configuration, click \uicontrol Add and select the type of configuration you would like to add. The options you have depend on the @@ -75,55 +77,20 @@ \uicontrol {Edit build configuration} field. The available build settings depend on the build system that you selected - for the project. + for the project: - \section2 Compiling QML + \list + \li \l{CMake Build Configuration}{CMake} + \li \l{qmake Build Configuration}{qmake} + \li \l{Qbs Build Configuration}{Qbs} + \li \l{Meson Build Configuration}{Meson} + \li \l{IncrediBuild Build Configuration}{IncrediBuild} + \endlist - Since Qt 5.11, you can compile QML source code into the final binary. This - improves the startup time of the application and eliminates the need to - deploy QML files together with the application. For more information, see - \l{Ahead-of-Time Compilation}. + This topic describes the build settings at a general level. - \QC project wizard templates create Qt Quick projects that can be compiled, - because they are set up to use the Qt Resource System. To compile Qt Quick - code, select \uicontrol Enable in the \uicontrol {Qt Quick Compiler} - field. To use default settings, select \uicontrol {Leave at Default}. - - \note In earlier Qt versions, this was a commercial feature. For more - information, see \l{http://doc.qt.io/QtQuickCompiler/}{Qt Quick Compiler}. - - \section2 qmake Build Configuration - - \image qtcreator-projectpane.png "qmake general build settings pane" - - By default, \QC builds projects in a separate directory from the source - directory, as \l{glossary-shadow-build} {shadow builds}. This keeps the - files generated for each \l{glossary-buildandrun-kit}{build and run kit} separate. - If you only build and run with a single \l{glossary-buildandrun-kit}{kit}, - you can deselect the \uicontrol {Shadow build} - checkbox. - - To make in-source builds the default option for all projects, select - \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > - \uicontrol {Default Build Properties}, and enter a period (.) in the - \uicontrol {Default build directory} field. - - You can create separate versions of project files to keep platform-dependent - code separate. You can use qmake \l{Adding Platform Specific Source Files} - {scopes} to select the file to process depending on which platform qmake is - run on. - - To generate debug symbols also for applications compiled in release mode, - select \uicontrol Enable in the \uicontrol {Separate debug info} field. For - more information, see \l{Using the Performance Analyzer}. To use default - settings, select \uicontrol {Leave at Default}. - - To set the default build properties, select \uicontrol Tools - > \uicontrol Options > \uicontrol {Build & Run} > - \uicontrol {Default Build Properties}. - - \include creator-projects-cmake-building.qdocinc cmake build configuration - \include creator-projects-meson-building.qdocinc meson build configuration + For more information about debugging Qt Quick projects, see + \l{Setting Up QML Debugging}. \section1 Starting External Processes @@ -133,11 +100,10 @@ an executable name and optional command line arguments. The executable name is specified in the executable fields: \uicontrol qmake, - \uicontrol Make, \uicontrol Command, or \uicontrol Executable. It is either derived from the - project or specified manually. When you specify executables manually, you - can reference environment variables and \QC variables. However, no - quoting rules - apply. + \uicontrol Make, \uicontrol Command, or \uicontrol Executable. It is either + derived from the project or specified manually. When you specify executables + manually, you can reference environment variables and \QC variables. + However, no quoting rules apply. You can specify command-line arguments in the arguments fields: \uicontrol Arguments, \uicontrol {Additional arguments}, @@ -157,32 +123,21 @@ \section1 Build Steps - In \uicontrol{Build Steps} you can change the settings for the build system - selected for building the project: qmake, CMake, Meson, or Qbs. You can use - Incredibuild to accelerate the build process when using qmake or CMake. + \image qtcreator-cmake-build-steps.png "CMake build steps" - \section2 qmake Build Steps + In \uicontrol{Build Steps}, you can change the settings for the build system + selected for building the project: - \QC builds qmake projects by running the \c make or \c nmake command from - the Qt version defined for the current build configuration. + \list + \li \l{CMake Build Steps}{CMake} + \li \l{qmake Build Steps}{qmake} + \li \l{Qbs Build Steps}{Qbs} + \li \l{Meson Build Steps}{Meson} + \li \l{Conan Build Steps}{Conan} + \endlist - \image qtcreator-build-steps.png "Build steps" - - To override the shell command that \QC constructs by default, disable or remove - the build step and add a custom build step that specifies another shell - command. - - By default, \QC uses all the CPU cores available to achieve maximum build - parallelization. On Linux and \macos, you can specify the number of parallel - jobs to use for building in the \uicontrol {Parallel jobs} field. Select the - \uicontrol {Override MAKEFLAGS} check box to override existing MAKEFLAGS - variables. - - \include creator-projects-cmake-building.qdocinc cmake build steps - \include creator-projects-settings-build-qbs.qdocinc qbs build steps - \include creator-projects-meson-building.qdocinc meson build steps - \include creator-projects-incredibuild-building.qdocinc incredibuild build steps - \include creator-projects-conan-building.qdocinc conan build steps + You can use \l{IncrediBuild Build Steps}{IncrediBuild} to accelerate the + build process when using qmake or CMake. \section2 Adding Custom Build Steps @@ -203,13 +158,21 @@ \section1 Clean Steps - You can use the cleaning process to remove intermediate files. This process - might help you to fix obscure issues during the process of building a - project. - \image qtcreator-clean-steps.png "Clean steps" - You can define the cleaning steps for your builds in the \uicontrol{Clean Steps}. + You can use the cleaning process to remove intermediate files. This process + might help you to fix obscure issues during the process of building a + project using: + + \list + \li \l{CMake Clean Steps}{CMake} + \li qmake + \li \l{Qbs Clean Steps}{Qbs} + \li \l{Meson Clean Steps}{Meson} + \li \l{IncrediBuild Clean Steps}{IncrediBuild} + \endlist + + You can define the clean steps for your builds in \uicontrol {Clean Steps}. \list @@ -225,10 +188,4 @@ (\uicontrol {Move Up}) and \inlineimage arrowdown.png (\uicontrol {Move Down}). \endlist - - \include creator-projects-cmake-building.qdocinc cmake clean steps - \include creator-projects-settings-build-qbs.qdocinc qbs clean steps - \include creator-projects-meson-building.qdocinc meson clean steps - \include creator-projects-incredibuild-building.qdocinc incredibuild clean steps - */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc index 515e44cdbda..109be0f8483 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-targets.qdoc @@ -175,6 +175,7 @@ with names beginning with the string \uicontrol CodeBlocks produce all the necessary data for the \QC code model. \QC displays a warning if you select a generator that is not supported. + For more information, see \l{Using Ninja as a CMake Generator}. \li In the \uicontrol {CMake configuration} field, select \uicontrol Change to edit the parameters of the CMake configuration @@ -195,8 +196,6 @@ choose the kit to use. To set the selected kit as the default kit, select \uicontrol {Make Default}. - \include creator-projects-cmake-building.qdocinc cmake ninja - \section1 Editing Qbs Profiles To view the Qbs profile associated with the kit, select \uicontrol Tools > diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 2c9d26bb34c..2c709e61477 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -75,6 +75,14 @@ \li \l{Adding Compilers} \li \l{Adding Debuggers} \li \l{Specifying Build Settings} + \list + \li \l{Cmake Build Configuration} + \li \l{qmake Build Configuration} + \li \l{Qbs Build Configuration} + \li \l{Meson Build Configuration} + \li \l{IncrediBuild Build Configuration} + \li \l{Conan Build Configuration} + \endlist \li \l{Specifying Run Settings} \li \l{Specifying Editor Settings} \li \l{Specifying Code Style Settings} diff --git a/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc b/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc index ad7c2e8c6b7..025320416ec 100644 --- a/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc +++ b/doc/qtcreator/src/qtquick/library/qtquick-data-models.qdoc @@ -236,7 +236,7 @@ \if defined(qtdesignstudio) \row \li \inlineimage icons/item-svg-16px.png - \li SvgPath + \li \l{SVG Path Item} \li Studio Components \li \li An SVG path data string that is used to draw a path as a line. diff --git a/doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc b/doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc index 8acab27e58d..6fd54606d5c 100644 --- a/doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc +++ b/doc/qtcreator/src/qtquick/library/qtquick-pathview-editor.qdocinc @@ -68,17 +68,18 @@ number of items in the model. \if defined(qtdesignstudio) - \note You can also use the \l SvgPath Studio Component to specify an SVG - path data string that draws a path. + \note You can also use the \l {SVG Path Item} Studio Component to specify an + SVG path data string that draws a path. \endif //! [pathview] //! [svgpath] - \section1 SvgPath + \section1 SVG Path Item - The Svg Path component uses an SVG path data string to draw a path as a line. + The \uicontrol {SVG Path Item} component uses an SVG path data string to + draw a path as a line. The stroke property values that specify the appearance of the path are described in \l{Strokes}. @@ -89,10 +90,5 @@ string that specifies the path. For more information, see \l{https://www.w3.org/TR/SVG/paths.html#PathData}{W3C SVG Path Data}. - \note Mixing SvgPath with other types of components is not always supported. - For example, when \l Shape is backed by \c GL_NV_path_rendering, a - \l ShapePath can contain one or more SvgPath elements, or one or more - components of other types, but not both. - //! [svgpath] */ diff --git a/doc/qtcreator/src/qtquick/qtquick-components.qdoc b/doc/qtcreator/src/qtquick/qtquick-components.qdoc index 5acd02b103e..5e76c0068f2 100644 --- a/doc/qtcreator/src/qtquick/qtquick-components.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-components.qdoc @@ -32,7 +32,7 @@ /*! \page quick-components.html \if defined(qtdesignstudio) - \previouspage studio-app-flows.html + \previouspage studio-flow-external-events.html \else \previouspage creator-using-qt-quick-designer.html \endif diff --git a/doc/qtdesignstudio/examples/doc/images/loginui1-button-styled.png b/doc/qtdesignstudio/examples/doc/images/loginui1-button-styled.png index ee8545d6ffb..ac7583de950 100644 Binary files a/doc/qtdesignstudio/examples/doc/images/loginui1-button-styled.png and b/doc/qtdesignstudio/examples/doc/images/loginui1-button-styled.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/loginui1-button.png b/doc/qtdesignstudio/examples/doc/images/loginui1-button.png index b1d9e7e532f..5ee1d3cc4bc 100644 Binary files a/doc/qtdesignstudio/examples/doc/images/loginui1-button.png and b/doc/qtdesignstudio/examples/doc/images/loginui1-button.png differ diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc index 2b9c2f9805e..210d8fe8f09 100644 --- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc @@ -360,10 +360,11 @@ \li Press \key Enter or select \uicontrol OK to save the new value. \li In the \uicontrol Radius field, enter 20 to give the button rounded corners. - \li In the \uicontrol States view, select the \e down state and modify - the background and border color as above. - \li Select the text component in \uicontrol Navigator to display its - properties in \uicontrol Properties. + \li In the \uicontrol States view, select the \e normal state and modify + the background color as above. + \li Select the \e base state, and then select the text component + in \uicontrol Navigator to display its properties in + \uicontrol Properties. \li In the \uicontrol {Text Color} field, select \uicontrol Actions > \uicontrol Reset to reset the text color to the default color, black. diff --git a/doc/qtdesignstudio/images/icons/flow-action-icon.png b/doc/qtdesignstudio/images/icons/flow-action-icon.png new file mode 100644 index 00000000000..4527e4c62f8 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/flow-action-icon.png differ diff --git a/doc/qtdesignstudio/images/icons/flow-decision-icon.png b/doc/qtdesignstudio/images/icons/flow-decision-icon.png new file mode 100644 index 00000000000..1566b07cfc6 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/flow-decision-icon.png differ diff --git a/doc/qtdesignstudio/images/icons/flow-wildcard-icon.png b/doc/qtdesignstudio/images/icons/flow-wildcard-icon.png new file mode 100644 index 00000000000..fabf663830f Binary files /dev/null and b/doc/qtdesignstudio/images/icons/flow-wildcard-icon.png differ diff --git a/doc/qtdesignstudio/images/studio-dial.png b/doc/qtdesignstudio/images/studio-dial.png new file mode 100644 index 00000000000..f440845e71f Binary files /dev/null and b/doc/qtdesignstudio/images/studio-dial.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-action-area-properties.png b/doc/qtdesignstudio/images/studio-flow-action-area-properties.png new file mode 100644 index 00000000000..efacaf237a1 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-action-area-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-action-area.png b/doc/qtdesignstudio/images/studio-flow-action-area.png new file mode 100644 index 00000000000..830985074cb Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-action-area.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-decision-preview.png b/doc/qtdesignstudio/images/studio-flow-decision-preview.png new file mode 100644 index 00000000000..c0c367d1439 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-decision-preview.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-decision-properties.png b/doc/qtdesignstudio/images/studio-flow-decision-properties.png new file mode 100644 index 00000000000..0877f728b5c Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-decision-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-decision.png b/doc/qtdesignstudio/images/studio-flow-decision.png index 47e003544c6..44f1e8f3804 100644 Binary files a/doc/qtdesignstudio/images/studio-flow-decision.png and b/doc/qtdesignstudio/images/studio-flow-decision.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-effect-properties.png b/doc/qtdesignstudio/images/studio-flow-effect-properties.png new file mode 100644 index 00000000000..ae841a00827 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-effect-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-effect-push-properties.png b/doc/qtdesignstudio/images/studio-flow-effect-push-properties.png new file mode 100644 index 00000000000..a4cac374741 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-effect-push-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-event-list-trigger.png b/doc/qtdesignstudio/images/studio-flow-event-list-trigger.png new file mode 100644 index 00000000000..68738f724ef Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-event-list-trigger.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-event-list.png b/doc/qtdesignstudio/images/studio-flow-event-list.png index 4a27d30ffcd..7be316bb8b8 100644 Binary files a/doc/qtdesignstudio/images/studio-flow-event-list.png and b/doc/qtdesignstudio/images/studio-flow-event-list.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-events-assign.png b/doc/qtdesignstudio/images/studio-flow-events-assign.png new file mode 100644 index 00000000000..c585dd80335 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-events-assign.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-item-properties.png b/doc/qtdesignstudio/images/studio-flow-item-properties.png new file mode 100644 index 00000000000..28384e22773 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-item-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-item.png b/doc/qtdesignstudio/images/studio-flow-item.png new file mode 100644 index 00000000000..bb4cf27beaf Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-item.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-steps.png b/doc/qtdesignstudio/images/studio-flow-steps.png new file mode 100644 index 00000000000..a02c7c4a4d8 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-steps.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-transition-line-properties.png b/doc/qtdesignstudio/images/studio-flow-transition-line-properties.png new file mode 100644 index 00000000000..e0d16766564 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-transition-line-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-transition-properties-question.png b/doc/qtdesignstudio/images/studio-flow-transition-properties-question.png new file mode 100644 index 00000000000..65e1f8b6ba9 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-transition-properties-question.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-transition-properties.png b/doc/qtdesignstudio/images/studio-flow-transition-properties.png new file mode 100644 index 00000000000..9a13e71f5c6 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-transition-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-view-properties-transition.png b/doc/qtdesignstudio/images/studio-flow-view-properties-transition.png new file mode 100644 index 00000000000..c4be840f6b3 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-view-properties-transition.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-view-properties.png b/doc/qtdesignstudio/images/studio-flow-view-properties.png new file mode 100644 index 00000000000..83bf37d9f50 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-view-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-view.png b/doc/qtdesignstudio/images/studio-flow-view.png index fc32482c3ca..30938d0bfe3 100644 Binary files a/doc/qtdesignstudio/images/studio-flow-view.png and b/doc/qtdesignstudio/images/studio-flow-view.png differ diff --git a/doc/qtdesignstudio/images/studio-flow-wildcard-properties.png b/doc/qtdesignstudio/images/studio-flow-wildcard-properties.png new file mode 100644 index 00000000000..21ec962071c Binary files /dev/null and b/doc/qtdesignstudio/images/studio-flow-wildcard-properties.png differ diff --git a/doc/qtdesignstudio/images/studio-project-wizards.png b/doc/qtdesignstudio/images/studio-project-wizards.png index bdfb78546af..5f625bab538 100644 Binary files a/doc/qtdesignstudio/images/studio-project-wizards.png and b/doc/qtdesignstudio/images/studio-project-wizards.png differ diff --git a/doc/qtdesignstudio/images/studio-workflow.png b/doc/qtdesignstudio/images/studio-workflow.png index a155ed0da4c..e3aa970d02f 100644 Binary files a/doc/qtdesignstudio/images/studio-workflow.png and b/doc/qtdesignstudio/images/studio-workflow.png differ diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc index c703074b95e..e654eab67e5 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc @@ -57,6 +57,14 @@ as assets. If you use functional \QDS components in Figma, you will find it easier to merge new iterations of the design to \QDS and continue to build the screens there. + \li \QBF does not support exporting changes in component instances. + If you make changes to component instances in Figma, you must + detach the instances before exporting them. Similarly, if your + Figma components contain nested components, Figma allows you to + hot swap the nested instance inside the component instance. + However, \QBF doesn't support this so you get the original + component unless you detach the component instance before + exporting it. \li Use descriptive and unique IDs to avoid duplicate IDs after exporting designs and importing them to \QDS. \endlist @@ -112,20 +120,28 @@ \li Determines how to export the group or layer: \list \li \uicontrol Child exports each asset of the selected group - or layer as a separate PNG file, with references - to the images in the component file. - \li \uicontrol Merged merges the selected groups and layers into - the parent frame or group as one component. + or layer as a separate component file. Images are exported + as separate files nested in \l{Images}{Image} components. + You select the image file format in \uicontrol Settings > + \uicontrol {Asset settings}. + + Figma rectangles are exported as \l{basic-rectangle} + {Rectangle} components. Figma vectors are exported as + \l{SVG Path Item} components from the \l{Shapes} + {Studio Components} module. + \li \uicontrol Merged merges the selected groups and layers + into one component. \li \uicontrol Skipped completely skips the selected layer. \endlist \row \li \uicontrol {Custom Component Type} \li Determines the \l{Component Types}{component type} to morph this layer into. The component that is generated during import will be - of this type. For example, if you drew a rectangle, you can export - it as a \l Rectangle component. You can provide the - \l{Learn More - Components}{import statement} of the component - set where the component is defined in the \uicontrol {Imports} field. + of this type. For example, if you drew a button, you can export + it as a \l Button component from the Qt Quick Controls module. + You can provide the import statement of the + \l{Adding and Removing Modules}{module} where the component + is defined in the \uicontrol {Imports} field. \row \li \uicontrol Properties \li Sets values of properties for the component. You can add properties @@ -133,13 +149,14 @@ \row \li \uicontrol Imports \li If you want to make additional components available in the component - file, you can enter the import statements of the component sets in - this field. For example, to use components of the Controls type from - version 2.3, you need the import statement \c {QtQuick.Controls 2.3} - and to use Studio Components from version 1.0, you need the import - statement \c {QtQuick.Studio.Components 1.0}. You can add components - from all the available component sets in \QDS later. You can also - import a component set as an \e alias. + file, you can enter the import statements of the modules that + contain the components in this field. For example, to use components + from version 2.3 of the Qt Quick Controls module, you need the + import statement \c {QtQuick.Controls 2.3} and to use version 1.0 + Studio Components, you need the import statement + \c {QtQuick.Studio.Components 1.0}. You can add components from all + the available modules in \QDS later. You can also import a module as + an \e alias. \row \li \uicontrol Alias \li Exports the component generated from this layer as an alias in the @@ -160,9 +177,13 @@ You can export assets in the selected format (JPG, PNG, or SVG). - In addition, you can export shapes as components of the type SvgPathItem. - This might not work for layers that have particular effects applied to them. - In that case, the layers are exported as images. + By default, vectors are exported as \l{SVG Path Item} components from the + Studio Components module. This might not work for layers that have + particular effects applied to them. In that case, the layers are exported + as images. + + Because MCUs only support simple images, disable the + \uicontrol {Export as shapes} check box when designing for MCUs. \table \header @@ -173,10 +194,8 @@ \li Exports assets in the selected format (JPG, PNG, or SVG). \row \li \uicontrol {Export as shapes} - \li Exports shapes as components of the type SvgPathItem. - - Because MCUs only support simple images, disable this - check box when designing for MCUs. + \li Exports vectors as components of the type \l{SVG Path Item} from the + Studio Components module. \row \li \uicontrol {Reset plugin data} \li Resets all settings for all layers and groups (also in the diff --git a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc index 9dc01844d2c..68b3e65a65f 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -26,15 +26,15 @@ /*! \page studio-app-flows.html \previouspage quick-uis.html - \nextpage quick-components.html + \nextpage studio-flow-view.html \title Designing Application Flows - You can design the application flow in the form of a \e {schematic diagram} - that shows all significant components of an application UI and their + You can design an application in the form of a \e {schematic diagram} + that shows all significant components of the application UI and their interconnections by means of symbols. This results in an interactive prototype that can be clicked through to simulate the user experience of - the application. The QML code is created in the background and can be used + the application. Code is created in the background and can be used as the base of the production version of the application. \image studio-flow-view.png "Application flow in Form Editor" @@ -44,25 +44,63 @@ lines} that connect them, thus illustrating the possible user pathways through the UI. You use \e {action areas} as starting points for transition lines. You can attach effects to transition lines, such as fade or push, - to determine what users see when one screen changes into another. + to determine what users see when one flow item changes into another. You can use \e {flow decisions} to set up alternative pathways between - screens in the UI. For example, if user input determines which screen + flow items in the UI. For example, if user input determines which flow item should open next, you can test the different scenarios in the prototype - by having a dialog pop up, where you can select which screen to show next. + by having a dialog pop up where you can select which flow item to show next. Especially on mobile and embedded platforms, the application might need to react to external events from the platform, such as notifications or other applications requiring the users' attention. You can use \e {flow wildcards} - to determine the priority of screens by whitelisting or blacklisting them. + to determine the priority of flow items by adding them to positive and + negative lists. - \section1 Creating Flows + To design application flows: + + \image studio-flow-steps.png "Designing application flows" + + \list 1 + \li Use a project wizard template to add a \uicontrol {Flow View} + component, as described in \l{Adding Flow Views}. + \li Use a project wizard template to add a \uicontrol {Flow Item} + component for each screen in the UI, as described in + \l{Adding Flow Items}. + \li Use context menu commands to add action areas and transitions, + as described in \l{Adding Action Areas and Transitions}. + \li Use context menu commands to apply effects to transitions, + as described in \l{Applying Effects to Transitions}. + \li When you are ready for production, use the event list simulator + to replace transition lines with connections to real signals + from UI controls, as described in \l{Simulating Events}. + \li To set up alternative pathways between flow items, use + \uicontrol {Flow Decision} components from \l Library, as + described in \l{Simulating Conditions}. + \li Use \l{Adding States}{states} in flows to modify the appearance + of components on screens in response to user interaction, as + described in \l{Applying States in Flows}. + \li Use \uicontrol {Flow Wildcard} components from \uicontrol Library + to prioritize events from other applications and to stop some + screens from appearing on others, as described in + \l{Reacting to External Events}. + \endlist +*/ + +/*! + \page studio-flow-view.html + \previouspage studio-app-flows.html + \nextpage studio-flow-item.html + + \title Adding Flow Views You can add a flow view to an existing project or create a new project - for it, as described in \l {Creating Projects}. To create the flow - view, select \uicontrol File > \uicontrol {New File or Project} > - \uicontrol {Files and Classes} > \uicontrol {Qt Quick Files} > - \uicontrol {Flow View} and follow the instructions of the wizard. + for it, as described in \l {Creating Projects}. + + To create the flow view, select \uicontrol File > + \uicontrol {New File or Project} > \uicontrol {Files and Classes} > + \uicontrol {Qt Quick Files} > \uicontrol {Flow View} + and follow the instructions of the wizard. You only need to select the \uicontrol {Use event simulator} check box if you want to add an event simulator to the flow view. @@ -71,26 +109,89 @@ the items in the flow: action areas, transition lines, decisions, and wildcards. You can change the global settings for all items by editing flow view properties, or you can select an individual action area or - transition line and change the appearance of just that item, including + transition line and change the appearance of just that component, including the color, line thickness, dotted or solid lines, and even the curve of - the connections. This enables you to add extra semantics to the design + the line. This enables you to add extra semantics to the design of the flow diagram itself. - \section1 Adding Flow Items + You can \l{Adding Flow Items}{add flow items} to the flow view to design + the UI. - If you imported your screen designs from a design tool as individual - components (\e {.ui.qml} files), you can use them as content for flow - items. If you are building your UI from scratch in \QDS, you must first - add components to the flow items to create the screens as you would - any QML components. For more information, see \l {Creating Components}. - The flow items that you attach the components to are listed under - \uicontrol {My QML Components}. + \section1 Flow View Properties + + You can specify basic properties for a \uicontrol {Flow View} component + in the \l {Type}{Component}, \l {2D Geometry}{Geometry}, and + \l Visibility groups. + + \image studio-flow-view-properties.png "Flow View component properties" + + To specify the \uicontrol {Flow Item} that is currently visible in the + flow view, set its index in the \uicontrol {Current index} field. + + You can use the \l{Picking Colors}{color picker} to set colors for: + + \list + \li Transition lines + \li Area outlines + \li Area fills + \li Block items + \endlist + + You can set some additional global properties for drawing transition lines: + + \image studio-flow-view-properties-transition.png "Flow View transition properties" + + \list + \li In the \uicontrol {Type} field, select \uicontrol Bezier to draw + transition lines as bezier curves. + \li In the \uicontrol {Radius} field, specify the corner radius for + default curves. + \li In the \uicontrol {Bezier factor} field, specify the factor that + modifies the positions of the control points used for bezier curves. + \endlist + + For more information about changing the appearance of a particular action + area or transition line, see \l{Flow Action Area Properties} and + \l{Flow Transition Properties}. + + In the \uicontrol Layout tab, you can use \l{Setting Anchors and Margins} + {anchors} to position the component. + + In the \uicontrol Advanced tab, you can manage the more + \l{Specifying Developer Properties}{advanced properties} + of components. +*/ + +/*! + \page studio-flow-item.html + \previouspage studio-flow-view.html + \nextpage studio-flow-action-area.html + + \title Adding Flow Items + + After you create a \l{Adding Flow Views}{Flow View} component, you can + use a project wizard template to add a \uicontrol {Flow Item} component + for each screen in the UI. + + If you \l{Importing 2D Assets}{imported} your screen designs from a + design tool as individual \l{glossary-component}{components} + (\e {.ui.qml} files), you can use them as content for flow items. + The imported components are listed in \l Library > \uicontrol Components + > \uicontrol {My Components}. + + If you are building your UI from scratch in \QDS, you must first add + components to the flow items to create the screens as you would any + components. For more information, see \l {Creating Components}. The + flow items that you attach the components to are listed under + \uicontrol {My Components}. + + \image studio-flow-item.png "Custom Flow Item in Library" \note You must use the wizard to create the flow items. After you create a flow view, the \uicontrol {Flow View} section becomes visible in - \uicontrol Library. It contains a \uicontrol {Flow Item} type that you - can use to apply states to flow items, and that you should use solely for - that purpose. + \uicontrol Library. It contains a \uicontrol {Flow Item} component that + you can use to \l{Applying States in Flows}{apply states to flow items}, + and that you should use solely for that purpose. To add flow items: @@ -101,136 +202,329 @@ to create flow items for each screen in the UI. \li Add content to the flow item in one of the following ways: \list - \li Drag and drop components to a flow item in - \uicontrol {Form Editor} or \uicontrol Navigator and - edit their properties in \uicontrol Properties. + \li Drag and drop components from \l Library to a flow + item in \l {Form Editor} or \l Navigator. \li Drag a screen from \uicontrol Library > - \uicontrol {My QML Components} to a flow item in + \uicontrol {My Components} to a flow item in \uicontrol {Form Editor} or \uicontrol Navigator. \endlist - \li In \uicontrol Properties, edit the properties globally for all - flow items, action areas, or transition lines in the flow view. + \li In \l Properties, edit the properties of each flow item. \endlist - To include another flow view into a flow view, select the \e {.ui.qml} file - that specifies the flow view in the \uicontrol {Loader source} field in - \uicontrol Properties. - You can now drag the flow items from \uicontrol Library > - \uicontrol {My QML Components} to the flow view in \uicontrol {Form Editor} - or \uicontrol Navigator. When you have all the screens in place, you can - add action areas to them to create transitions between them. + \uicontrol {My Components} to the flow view in \uicontrol {Form Editor} + or \uicontrol Navigator. When you have all the flow items in place, you can + \l{Adding Action Areas and Transitions}{add action areas} to them to create + transitions between them. - \section1 Adding Action Areas and Transitions + \section1 Flow Item Properties + + You can specify basic properties for a \uicontrol {Flow Item} component + in the \l {Type}{Component}, \l {2D Geometry}{Geometry}, and + \l Visibility groups. + + \image studio-flow-item-properties.png "Flow Item properties" + + The \uicontrol {State change target} and \uicontrol {Target state} + properties are used to \l{Applying States in Flows}{apply states} + in flows. + + To include another flow view into a flow view, select the UI file (.ui.qml) + that specifies the flow view in the \uicontrol {Loader source} field. + + By default, transitions are drawn from action areas to the target flow item. + To draw the transitions from the edges of flow items instead, select the + \uicontrol {Join lines} check box. + + In the \uicontrol Layout tab, you can use \l{Setting Anchors and Margins} + {anchors} to position the component. + + In the \uicontrol Advanced tab, you can manage the more + \l{Specifying Developer Properties}{advanced properties} of components. +*/ + +/*! + \page studio-flow-action-area.html + \previouspage studio-flow-item.html + \nextpage studio-flow-effects.html + + \title Adding Action Areas and Transitions \e {Action areas} can act as clickable areas that initiate transitions - between screens or they can create connections to any signal from any - component in a flow item. For example, you could connect an action - to the \c onPressed signal of a button in your screen. + between flow items or they can \l{Connecting Components to Signals} + {create connections} to any signal from any component in a + \l{Adding Flow Items}{flow item}. For example, you could connect an + action to the \c onPressed signal of a button in your flow item to + determine what should happen when users press the button. - Typically, a screen can be connected to several other screens in the flow, - with two-way connections. To avoid clutter, you can set an action area as - \e {go back}, instead of adding explicit transition lines to and from - every potentially connected screen. When the \uicontrol {Go back} option is - enabled, the transition will always take the user back to the previous - screen. + \image studio-flow-action-area.png "Flow Action Area in Form Editor" + + You can select the type of the mouse or touch input to use for triggering + events, such as click, double-click, flick, pinch, or press. + + Typically, a flow item can be connected to several other flow items in the + flow with two-way connections. To avoid clutter, you can set an action area + as \e {go back} instead of adding explicit transition lines to and from + every potentially connected flow item. When the \uicontrol {Go back} option + is enabled, the transition will always take the user back to the previous + flow item. + + You can specify the appearance of each action area or transition line, + including the color, line thickness, dotted or solid lines, and even + the curve of the transition lines. You can change some of these properties + globally, as instructed in \l{Flow View Properties}. To create action areas: \list 1 - \li Right-click the flow item in \uicontrol {Form Editor} and select - \uicontrol {Flow} > \uicontrol {Create Flow Action} in the context - menu. - \li Drag the action area to the screen control that you want to connect - to the other screen. For example, to a button that opens another - screen when clicked. + \li Right-click the flow item in \l {Form Editor} and select + \uicontrol {Flow} > \uicontrol {Create Flow Action} in + the context menu. + \li Drag the action area to the UI control that you want to connect + to the other flow item. For example, to a button that opens another + flow item when clicked. \li Double-click the action area and drag the transition line to the flow item you want to connect to. - \li In \uicontrol Properties, modify the properties of the action area + \li In \l Properties, modify the properties of the action area and transition line. \endlist To preview the flow, select the \inlineimage live_preview.png - (\uicontrol {Show Live Preview}) button on the \uicontrol {Form Editor} - toolbar or press \key {Alt+P}. + (\uicontrol {Show Live Preview}) button on the Design mode + \l{Summary of Main Toolbar Actions}{toolbar} or press \key {Alt+P}. - \section1 Applying Effects to Transitions + \section1 Common Properties - You can apply effects, such as fade, move, or push to transitions. A fade - effect makes the first screen appear to fade out, while the next screen - fades in. A move effect makes the second screen appear to move in over the - first screen, while the push effect appears to make a screen push out the - previous one. You can also design and use custom effects. + You can specify basic properties for \uicontrol {Flow Action Area} + and \uicontrol {Flow Transition} components in the \l {Type}{Component}, + \l {2D Geometry}{Geometry}, and \l Visibility groups. - The transition direction determines the direction the new screen appears + You can use the \l{Picking Colors}{color picker} to set line and fill + color. + + In the \uicontrol Layout tab, you can use \l{Setting Anchors and Margins} + {anchors} to position the component. + + In the \uicontrol Advanced tab, you can manage the more + \l{Specifying Developer Properties}{advanced properties} of components. + + \section1 Flow Action Area Properties + + \image studio-flow-action-area-properties.png "Flow Action Area properties" + + You can specify some additional properties for action areas: + + \list + \li Select the \uicontrol {Go back} check box to specify that the + transition will always take the user back to the previous flow item. + \li In the \uicontrol {Event IDs} field, specify the IDs of the + events to connect to, such as mouse, touch or keyboard events. + \li In the \uicontrol {Action type} field, select the type of the + mouse or touch input to use for triggering events. + \li In the \uicontrol {Line width} field, set the width of the + action area outline. + \li Select the \uicontrol {Dashed line} check box to draw a dashed + action area outline. + \li Select the \uicontrol Enabled check box to enable interaction + with the action area during preview. + \endlist + + \section1 Flow Transition Properties + + You can specify some additional properties for transitions between + \l{Adding Flow Items}{flow items}: + + \image studio-flow-transition-properties.png "Flow Transition properties" + + \list + \li Select the \uicontrol Condition checkbox to activate the + transition. You can select \inlineimage icons/action-icon.png + to \l{Adding Bindings Between Properties}{bind} a condition + to the transition. + \li In the \uicontrol Question field, enter the text that will appear + next to the transition line. If the transition represents the + connection to a \uicontrol {Flow Decision} component, the + text will also be visible in the selection dialog that opens when + the \l{Simulating Conditions}{condition} is triggered. + \li In the \uicontrol {Event IDs} field, specify the IDs of the + events to connect to, such as mouse, touch or keyboard events. + \li In the \uicontrol From and \uicontrol To fields, select the + flow item where the transition starts and the one where it + ends. + \endlist + + You can specify the following properties to change the appearance of + transition lines in \l{Form Editor}: + + \image studio-flow-transition-line-properties.png "Flow Transition Line properties" + + \list + \li In the \uicontrol {Line width} field, set the width of the + transition line. + \li In the \uicontrol {In-offset}, \uicontrol {Out-offset}, and + \uicontrol {Break-offset} fields, set the start or end point of a + transition line or a break to the specified offset. This enables + you to move them up and down or left and right. + \li Select the \uicontrol {Dashed line} check box to draw a dashed line. + \li In the \uicontrol Type field, select \uicontrol Bezier to draw + transition lines as bezier curves. + \li In the \uicontrol Radius field, specify the corner radius for + default curves. + \li In the \uicontrol {Bezier factor} field, specify the factor that + modifies the positions of the control points used for a bezier + curve. + \li In the \uicontrol {Label position} field, set the position of + the value of the \uicontrol Question field in respect to the + transition start point. + \li Select the \uicontrol {Label flip side} check box to move the + \uicontrol Question value to the opposite side of the transition + line. + \endlist +*/ + +/*! + \page studio-flow-effects.html + \previouspage studio-flow-action-area.html + \nextpage studio-flow-events.html + + \title Applying Effects to Transitions + + You can apply effects, such as fade, move, or push to + \l{Adding Action Areas and Transitions}{transitions} between + \l{Adding Flow Items}{flow items}. A fade effect makes the first + flow item appear to fade out, while the next flow item fades in. + A move effect makes the second flow item appear to move in over the + first flow item, while the push effect appears to make a flow item + push out the previous one. You can also design and use custom effects. + + The transition direction determines the direction the new flow item appears from: left, right, top, bottom. You can set the duration of the effect and \l{Editing Easing Curves}{attach an easing curve} to the effect. To add effects: \list 1 - \li Select a transition line in \uicontrol {Form Editor}. + \li Select a transition line in \l {Form Editor}. \li In the context menu, select \uicontrol {Flow} > \uicontrol {Assign Flow Effects}, and then select the effect to apply. - \li In \uicontrol Properties, modify the properties of the effect. + \li In \l Properties, modify the properties of the effect. \endlist - To edit effect properties, select a transition, and then select + To edit effect properties later, select a transition, and then select \uicontrol {Flow} > \uicontrol {Select Effect} in the context menu. - \section1 Simulating Events + \section1 Flow Effect Properties - While transition lines are useful for prototyping, in production you need to - use the real signals from UI screens to control the flow of the application. + You can specify basic properties for a \uicontrol {Flow Effect} + component in the \l Type and \l ID fields. + + \image studio-flow-effect-properties.png "Flow Effect properties" + + You can set the duration and easing curve of all flow effects: + + \list + \li In the \uicontrol Duration field, specify the duration of the + effect. + \li Select the \inlineimage curve_editor.png + button to open \uicontrol {Easing Curve Editor} for attaching an + \l{Editing Easing Curves}{easing curve} to the effect. + \endlist + + For a move or push effect, you can set some additional properties: + + \image studio-flow-effect-push-properties.png "Flow Push Effect properties" + + \list + \li In the \uicontrol Direction field, specify the direction that + the target \uicontrol {Flow Item} appears from: left, right, top, + or bottom. + \li In the \uicontrol Scale field, set scaling for the effect. + \li In the \uicontrol {Incoming opacity} and + \uicontrol {Outgoing opacity} fields, specify the opacity of + the effect as a number between 0 and 1. + \li Select the \uicontrol Reveal check box to reveal the + \uicontrol {Flow Item} where the transition starts. + \endlist +*/ + +/*! + \page studio-flow-events.html + \previouspage studio-flow-effects.html + \nextpage studio-flow-conditions.html + + \title Simulating Events + + While \l{Adding Action Areas and Transitions}{transition lines} + are useful for prototyping, in production you need to use the real + \l{Connecting Components to Signals}{signals} from UI + \l{glossary-component}{components} to control the flow of the application. For this purpose, you can use action areas in a more advanced way, by - having them listen to signals from screens or the controls in them and - by connecting these to the flow view. You can use keyboard shortcuts to - simulate these events when you preview the UI. + having them listen to signals from flow items or the controls in them and + by connecting these to the \l{Adding Flow Views}{flow view}. You can use + keyboard shortcuts to simulate these events when you preview the UI. - When you use the wizard to create a \uicontrol {Flow View} item, select the - \uicontrol {Use event simulator} check box to add an event simulator to the - flow view. + When you use the wizard to create a \uicontrol {Flow View} component, select + the \uicontrol {Use event simulator} check box to add an event simulator to + the flow view. You can create an event list where you assign keyboard shortcuts to events, and then use context-menu commands to attach the events to action areas or transition lines. + \section1 Creating Event Lists + To create an event list: \list 1 - \li In \uicontrol Navigator, select the \uicontrol EventListSimulator - type, and then select the \uicontrol Active check box in - \uicontrol Properties to activate the event simulator. \li Select the \inlineimage icons/edit.png - (\uicontrol {Show Event List}) button on the Design mode toolbar, - or press \key {Alt+E}. - \image studio-flow-event-list.png "Event List Dialog" - \li Select \inlineimage plus.png + (\uicontrol {Show Event List}) button on the Design mode + \l{Summary of Main Toolbar Actions}{toolbar}, or press \key {Alt+E}. + \li In the \uicontrol {Event List} dialog, select \inlineimage plus.png to add a keyboard shortcut for triggering an event to the list. - \li In the \uicontrol Id field, enter an identifier for the event. + \image studio-flow-event-list.png "Event List dialog" + \li In the \uicontrol {Event ID} field, enter an identifier for the + event. You can search for existing events by entering search + criteria in the \uicontrol Filter field. + \li In the \uicontrol Description field, describe the keyboard shortcut. \li In the \uicontrol Shortcut field, press the keyboard key that will trigger the event, and then select \uicontrol R to record the keyboard shortcut. The key identifier appears in the field. - \li In the \uicontrol Description field, describe the keyboard shortcut. \endlist - You can now assign the events to the action areas in the flow to use the - keyboard shortcuts to trigger events when you preview the UI. + You can now assign the events to action areas and transitions. + + \section1 Assigning Events to Actions To assign events to actions: \list 1 \li In \uicontrol Navigator, select an action area or transition line. - \li In the context menu, select \uicontrol {Flow} > - \uicontrol {Event List} > \uicontrol {Assign Events to Actions}. - \li Select an event in the list, and then select \uicontrol Accept. + \li In the context menu, select \uicontrol {Event List} > + \uicontrol {Assign Events to Actions}. + \image studio-flow-events-assign.png "Assign Events to Actions dialog" + \li In the \uicontrol ID field, select a transition or an action area + \inlineimage icons/flow-action-icon.png + . You can search for events by entering search criteria in the + \uicontrol Filter field. + \li To connect an event, select \uicontrol Connect next to an event in + the list. To release a connected event, select \uicontrol Release. \li Press \key {Alt+P} to preview the UI. - \li Double-click events in the event list or use the keyboard shortcuts - to trigger events. + \li Select action areas in the preview, double-click events in the + event list, or use the keyboard shortcuts to trigger events. + \image studio-flow-decision-preview.png "Event list in preview" \endlist - \section1 Simulating Conditions + If the event triggers a \l{Simulating Conditions}{flow decision}, you + can select the path to take to the next flow item. +*/ + +/*! + \page studio-flow-conditions.html + \previouspage studio-flow-events.html + \nextpage studio-flow-states.html + + \title Simulating Conditions Part of any complex UI is the conditional logic it uses to present its state to users or to collect and process data from various sources. Data @@ -238,88 +532,165 @@ buttons and controls, sensor readings from arrays of equipment, or general values received from backend or service APIs. - The \uicontrol {Flow Decision} type simulates conditions by displaying a + The \uicontrol {Flow Decision} component simulates conditions by displaying a list of options you can choose from when you preview the flow. This enables you to prototype complex interactions before you have access to the physical controls, backend, or sensor data that will be required for the production version. + \image studio-flow-decision.png "Flow Decision in Form Editor" + To simulate conditions: \list 1 - \li Drag a \uicontrol {Flow Decision} QML type from \uicontrol Library - to a flow view in \uicontrol Navigator or \uicontrol {Form Editor}. - \li Select the screen where you want the application to start in + \li Drag a \uicontrol {Flow Decision} component from \l Library + to a \l{Adding Flow Views}{flow view} in \l Navigator or + \l {Form Editor}. + \li Select the flow item where you want the application to start in \uicontrol Navigator or \uicontrol {Form Editor}, and then select - \uicontrol {Flow} > \uicontrol {Add Start} in the context menu. - \li Create an action area for the component that will trigger the - condition and connect it to the flow decision. - \li In \uicontrol Properties, \uicontrol Question field, enter the text - that will appear next to the transition line that represents the - connection to the flow decision type. + \uicontrol {Flow} > \uicontrol {Set Flow Start} in the context menu. + \li Create an \l{Adding Action Areas and Transitions}{action area} for + the component that will trigger the condition and connect it to the + flow decision. \li Select the flow decision, and then select \uicontrol Connect in the - context menu to create connections to the screens that will open + context menu to create connections to the flow items that will open depending on whether the condition is met. - \li In \uicontrol Properties, \uicontrol Title field, enter a title for - the selection dialog that opens when the condition is triggered. - \li Select a transition line and add a descriptive text in the - \uicontrol {Question} field to represent a choice in the selection - dialog. + \li In \uicontrol Properties, \uicontrol {Dialog title} field, enter a + title for the selection dialog that opens when the condition is + triggered. + \li Select a transition line in \uicontrol Navigator or + \uicontrol {Form Editor} and add a descriptive text in the + \uicontrol {Question} field in \uicontrol Properties to represent + a choice in the selection dialog. + \image studio-flow-transition-properties-question.png "Flow Transition properties" \li Press \key {Alt+P} to preview the UI. + \li Select action areas in the preview, double-click events in the + event list, or use the keyboard shortcuts to trigger events. \endlist - When you preview the UI, you can click the action areas to display a dialog - that you can use to select which condition is met and see the results. + Flow decisions are listed in a dialog where you can select which condition + is met to see the results. - \image studio-flow-decision.png + \image studio-flow-decision-preview.png "Selection dialog for flow decision" - \section1 Applying States in Flows + \section1 Flow Decision Properties - You can use \l{Adding States}{states} in flows to modify the appearance of - components on screens in response to user interaction, for example. For - this purpose, you use the \uicontrol {Flow Item} QML types availabe in - \uicontrol Library. + You can specify basic properties for a \uicontrol {Flow Decision} + component in the \l Type and \l ID fields. + + \image studio-flow-decision-properties.png "Flow Decision properties" + + In the \uicontrol {Dialog title} field, enter a title for the selection + dialog that opens when the condition is triggered. + + You can specify the following properties to change the appearance of the + flow decision icon \inlineimage icons/flow-decision-icon.png + : + + \list + \li Select the \uicontrol {Show label} check box to display the ID + of the \uicontrol {Flow Decision} component in \l {Form Editor}. + \li In the \uicontrol {Label position} field, select the corner of + the flow decision icon to place the label in. + \li In the \uicontrol Size field, specify the size of the flow + decision icon. + \li In the \uicontrol Radius field, specify the radius of the flow + decision icon corners. + \endlist + + You can use the \l{Picking Colors}{color picker} to set the outline and + fill color of the flow decision icon. +*/ + +/*! + \page studio-flow-states.html + \previouspage studio-flow-conditions.html + \nextpage studio-flow-external-events.html + + \title Applying States in Flows + + You can use \l{Adding States}{states} in flows to modify the appearance + of \l{glossary-component}{components} in flow items in response to user + interaction, for example. For this purpose, you use the + \uicontrol {Flow Item} components available in \l Library. \list 1 \li Select \uicontrol File > \uicontrol {New File or Project} > \uicontrol {Files and Classes} > \uicontrol {Qt Quick Files} > \uicontrol {Flow Item} to create a flow item. - \li In \uicontrol States, add states to the flow item. - \li Open the .ui.qml file that contains the flow view in - \uicontrol {Form Editor} and drag the flow item to the flow view - in \uicontrol Navigator or \uicontrol {Form Editor}. - \li Drag an empty \uicontrol {Flow Item} QML type from the - \uicontrol Library view \uicontrol {Flow View} tab to the - flow for each state that you added. - \li In \uicontrol Properties, in the \uicontrol {State change target} + \li In \l States, add states to the flow item. + \li Open the .ui.qml file that contains the \l{Adding Flow Views} + {flow view} in \l {Form Editor} and drag the flow item to the + flow view in \l Navigator or \l {Form Editor}. + \li Drag an empty \uicontrol {Flow Item} component from + \uicontrol Library > \uicontrol Components > \uicontrol {Flow View} + to the flow for each state that you added. + \li In \l Properties, in the \uicontrol {State change target} field, select the flow item that you created using the wizard. + \image studio-flow-item-properties.png "Flow Item properties" \li In the \uicontrol {Target state} field, select the state to apply to the flow item. \endlist - You can now add action areas and flow decisions to apply the different - states. + You can now add \l{Adding Action Areas and Transitions}{action areas} and + \l{Simulating Conditions}{flow decisions} to apply the different states. +*/ - \section1 Reacting to External Events +/*! + \page studio-flow-external-events.html + \previouspage studio-flow-states.html + \nextpage quick-components.html + + \title Reacting to External Events On mobile and embedded platforms, applications are usually integrated into - the platform, and therefore screens might pop-up from anywhere or at any + the platform and therefore screens might pop-up from anywhere or at any time, based on a conditional event. For example, push notifications appear on mobile devices and incoming call screens on a car's HMI. - You can use the \uicontrol {Flow Wildcard} type to model this type of - screens in your flow, using real or simulated signals and conditions. You - can whitelist or blacklist wildcard events to prioritize them and stop some - screens from appearing on others. For example, you could block the incoming - call screen from appearing on a warning screen for the engine, if you - consider the warning more important. + You can use the \uicontrol {Flow Wildcard} component to model this type of + screens in your \l{Adding Flow Views}{flow view} using real or simulated + \l{Connecting Components to Signals}{signals} and \l{Simulating Conditions} + {conditions}. You can add \l{Adding Flow Items}{flow items} to a positive + list to prioritize them or to a negative list to stop some screens from + appearing on others. For example, you could block the incoming call screen + from appearing on a warning screen for the engine if you consider the + warning more important. To use wildcards: \list 1 - \li Drag a \uicontrol {Flow Wildcard} QML type from \uicontrol Library - to a flow view in \uicontrol Navigator or \uicontrol {Form Editor}. - \li In \uicontrol Properties, add screens to the white and black list - for the screen. + \li Drag a \uicontrol {Flow Wildcard} component from \l Library + to an \l{Adding Action Areas and Transitions}{action area} in + \l Navigator or \l {Form Editor}. + \li In \l Properties, select flow items to add them to the + positive and negative list of the action area. \endlist + + \section1 Flow Wildcard Properties + + You can specify basic properties for a \uicontrol {Flow Wildcard} + component in the \l Type and \l ID fields. + + \image studio-flow-wildcard-properties.png "Flow Wildcard properties" + + In the \uicontrol {Event IDs} field, specify the IDs of the events to + connect to, such as mouse, touch or keyboard events. + + To give flow items high priority, select them in the + \uicontrol {Positive list} field. To block flow items, + select them in the \uicontrol {Negative list} field. + + You can specify the following properties to change the appearance of the + wildcard icon \inlineimage icons/flow-wildcard-icon.png + : + + \list + \li In the \uicontrol Size field, specify the size of the wildcard icon. + \li In the \uicontrol Radius field, specify the radius of the wildcard + icon corners. + \endlist + + You can use the \l{Picking Colors}{color picker} to set the outline and + fill color of the wildcard icon. */ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc index d0f7666b62b..aa0fe0f97fd 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc +++ b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc @@ -27,27 +27,46 @@ \section2 Creating Custom Controls - You can use project wizard templates to create a starting point for - a custom \l Button, \l [QtQuickControls2] {Pane}, \l {Stack Layout}, - \l [QtQuickControls2] {SwipeView}{Swipe View}, or \l Switch. + You can use project wizard templates to create stylable UI controls based + on the components in the Qt Quick Controls module: + + \list + \li \l Button + \li \l {Check Box} + \li \l {Slider and Dial}{Dial} + \li \l {Slider and Dial}{Slider} + \li \l {Spin Box} + \li \l Switch + \li \l [QtQuickControls2] {Pane} + \li \l {Stack Layout} + \li \l [QtQuickControls2] {SwipeView}{Swipe View} + \endlist + + You can edit the properties of the controls in all the preset + \l{Adding States}{states} to apply your own style to them. + + \image studio-dial.png "A stylable Dial component" + + To create stylable UI controls: \list 1 \li Select \uicontrol File > \uicontrol {New File or Project} > \uicontrol {Files and Classes} > \uicontrol {Qt Quick Controls}. \li Select the control to create, and then select \uicontrol Choose. - \note Components are listed in the \uicontrol {My Components} - tab of the \uicontrol Library only if the filename begins - with a capital letter. - \li Edit component properties in the \uicontrol Properties view. + \note Components are listed in \l Library > \uicontrol Components > + \uicontrol {My Components} only if the filename begins with a + capital letter. + \li Edit component properties in the \l Properties view. The available properties depend on the component type. You can \l{Specifying Dynamic Properties}{add properties for components} in the \uicontrol Properties tab of the \uicontrol {Connection View}. \endlist - For an example of using the \uicontrol Button template to create a button, - see \l{Creating a Push Button} in the \l{Log In UI - Part 1} tutorial. + For an example of using the \uicontrol Button template to create a button + and styling it, see \l{Creating a Push Button} in the \l{Log In UI - Part 1} + tutorial. //! [creating studio components] */ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index 3c3c64cef55..544c23a0317 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -147,10 +147,15 @@ List View. For more information, see \l{List and Grid Views}. \endlist - \li \uicontrol {Qt Quick Controls} + \li \uicontrol {Qt Quick Controls} create stylable versions of the + components in the Qt Quick Controls module: \list \li \l {Button}{Custom Button} creates a push button with a text label. + \li \l {Check Box}{Custom CheckBox} creates a check box. + \li \l {Slider and Dial}{Custom Dial} creates a dial. + \li \l {Slider and Dial}{Custom Slider} creates a slider. + \li \l {Spin Box}{Custom SpinBox} creates a spin box. \li \l {Switch}{Custom Switch} creates a switch with on and off states. \li \l [Qt Quick Controls 2] {Pane} provides a background that @@ -160,6 +165,7 @@ \li \l [Qt Quick Controls 2] {SwipeView} enables users to navigate pages by swiping sideways. \endlist + For more information, see \l{Creating Custom Controls}. \li \uicontrol ListModel adds a \l{Editing List Models}{list model} to the project. \li \uicontrol {JavaScript File} generates files that you can use to diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index f45f0908900..f0a42db9f2e 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -93,6 +93,16 @@ \li \l{Creating UIs} \list \li \l{Designing Application Flows} + \list + \li \l{Adding Flow Views} + \li \l{Adding Flow Items} + \li \l{Adding Action Areas and Transitions} + \li \l{Applying Effects to Transitions} + \li \l{Simulating Events} + \li \l{Simulating Conditions} + \li \l{Applying States in Flows} + \li \l{Reacting to External Events} + \endlist \li \l{Creating Components} \list \li \l{Shapes} diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc index dc3cf6247b6..75cb1e12753 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials-shaders.qdoc @@ -220,15 +220,13 @@ \section1 Applying Materials to Models - To apply materials to \l {Adding 3D Models}{models}: + To apply materials to models, you should first delete the default material, + and then drag-and-drop a new material from \l Library to a model component + in \l Navigator. - \list 1 - \li Drag and drop a material component from \l Library to a model - component in \l Navigator. - \li Select the Model component. - \li In the \uicontrol Properties view, select the material for the model - in the \uicontrol Materials list. - \li Select the material component to edit the properties of the material - in the \uicontrol Properties view. - \endlist + You can apply the same material to another component as well. Again, + delete the default material first. You should then select the component and + go to the \uicontrol Properties view. Find the \uicontrol Materials property, + select the \inlineimage plus.png + icon, and choose the new material in the dropdown menu. */ diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc index c0dcf127a39..f84c5e9e391 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc @@ -35,6 +35,16 @@ \QDS provides a set of pregenerated Qt Quick 3D materials that can be used to create good-looking \l {Adding 3D Models}{models} quickly and easily. + To apply 3D materials to models, you should first delete the default material, + and then drag-and-drop a new material from \l Library to a model component + in \l Navigator. + + You can apply the same material to another component as well. Again, + delete the default material first. You should then select the component and + go to the \uicontrol Properties view. Find the \uicontrol Materials property, + select the \inlineimage plus.png + icon, and choose the new material in the dropdown menu. + To apply a 3D material to a component, drag-and-drop a material from \l Library > \uicontrol Components > \uicontrol QtQuick3D > \uicontrol {Qt Quick 3D Materials} to a model component in \l Navigator. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-texture.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-texture.qdoc index b518ed20cc9..45ceaf00081 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-texture.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-texture.qdoc @@ -136,6 +136,4 @@ specify a new image to use in the \uicontrol Source field. \image studio-qtquick-3d-texture-properties.png "Texture properties" - - \endlist */ diff --git a/scripts/build.py b/scripts/build.py index 2f26b674574..d779a33d441 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -95,6 +95,8 @@ def get_arguments(): action='store_true', default=False) parser.add_argument('--with-tests', help='Enable building of tests', action='store_true', default=False) + parser.add_argument('--with-pch', help='Enable building with PCH', + action='store_true', default=False) parser.add_argument('--add-path', help='Prepends a CMAKE_PREFIX_PATH to the build', action='append', dest='prefix_paths', default=[]) parser.add_argument('--add-module-path', help='Prepends a CMAKE_MODULE_PATH to the build', @@ -139,6 +141,10 @@ def common_cmake_arguments(args): if python_library: cmake_args += ['-DPYTHON_LIBRARY=' + python_library[0], '-DPYTHON_INCLUDE_DIR=' + os.path.join(args.python_path, 'include')] + + pch_option = 'ON' if args.with_pch else 'OFF' + cmake_args += ['-DBUILD_WITH_PCH=' + pch_option] + return cmake_args def build_qtcreator(args, paths): @@ -170,9 +176,6 @@ def build_qtcreator(args, paths): '-DBUILD_EXECUTABLE_WIN64INTERRUPT=OFF', '-DBUILD_LIBRARY_QTCREATORCDBEXT=OFF'] - # TODO this works around a CMake bug https://gitlab.kitware.com/cmake/cmake/issues/20119 - cmake_args += ['-DBUILD_WITH_PCH=OFF'] - ide_revision = common.get_commit_SHA(paths.src) if ide_revision: cmake_args += ['-DIDE_REVISION=ON', diff --git a/scripts/build_plugin.py b/scripts/build_plugin.py index 8ec5eb44641..c70d6051283 100755 --- a/scripts/build_plugin.py +++ b/scripts/build_plugin.py @@ -69,6 +69,14 @@ def build(args, paths): if not os.path.exists(paths.result): os.makedirs(paths.result) prefix_paths = [os.path.abspath(fp) for fp in args.prefix_paths] + [paths.qt_creator, paths.qt] + if common.is_mac_platform(): + # --qtc-path may be + # "/path/Qt Creator.app/Contents/Resources", + # "/path/Qt Creator.app", or + # "/path", + # so add some variants to the prefix path + prefix_paths += [os.path.join(paths.qt_creator, 'Contents', 'Resources'), + os.path.join(paths.qt_creator, 'Qt Creator.app', 'Contents', 'Resources')] prefix_paths = [common.to_posix_path(fp) for fp in prefix_paths] separate_debug_info_option = 'ON' if args.with_debug_info else 'OFF' cmake_args = ['cmake', diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt b/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt index d9a268a634d..b27b902e028 100644 --- a/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/qtcreatorplugin/CMakeLists.txt @@ -1,7 +1,15 @@ cmake_minimum_required(VERSION 3.10) # Remove when sharing with others. +@if %{JS: Util.isDirectory('%{QtCreatorBuild}/Qt Creator.app/Contents/Resources')} +list(APPEND CMAKE_PREFIX_PATH "%{QtCreatorBuild}/Qt Creator.app/Contents/Resources") +@else + @if %{JS: Util.isDirectory('%{QtCreatorBuild}/Contents/Resources')} +list(APPEND CMAKE_PREFIX_PATH "%{QtCreatorBuild}/Contents/Resources") + @else list(APPEND CMAKE_PREFIX_PATH "%{QtCreatorBuild}") + @endif +@endif project(%{PluginName}) diff --git a/share/qtcreator/templates/wizards/qtcreatorplugin/README.md b/share/qtcreator/templates/wizards/qtcreatorplugin/README.md index bdd9b8a67d8..035b6c5c885 100644 --- a/share/qtcreator/templates/wizards/qtcreatorplugin/README.md +++ b/share/qtcreator/templates/wizards/qtcreatorplugin/README.md @@ -7,9 +7,10 @@ Create a build directory and run cmake -DCMAKE_PREFIX_PATH= -DCMAKE_BUILD_TYPE=RelWithDebInfo cmake --build . -where `` is the relative or absolute path to a Qt Creator build directory, or to -a combined binary and development package, and `` is the relative or absolute -path to this plugin directory. +where `` is the relative or absolute path to a Qt Creator build directory, or to a +combined binary and development package (Windows / Linux), or to the `Qt Creator.app/Contents/Resources/` +directory of a combined binary and development package (macOS), and `` is the +relative or absolute path to this plugin directory. ## How to Run diff --git a/share/share.qbs b/share/share.qbs index 9a1db42cff4..0e9fe5a5cf8 100644 --- a/share/share.qbs +++ b/share/share.qbs @@ -43,7 +43,8 @@ Product { qbs.installSourceBase: project.ide_source_tree + "/src/share/3rdparty" prefix: project.ide_source_tree + "/src/share/3rdparty/" files: [ - "fonts/**/*" + "fonts/**/*", + "package-manager/**/*", ] } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f8223319650..799d8ef68c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,7 @@ add_library(app_version INTERFACE) target_include_directories(app_version INTERFACE $ - INTERFACE $) + INTERFACE $) install(TARGETS app_version EXPORT QtCreator) add_subdirectory(libs) @@ -16,20 +16,20 @@ install( ${PROJECT_SOURCE_DIR}/HACKING ${PROJECT_SOURCE_DIR}/LICENSE.GPL3-EXCEPT ${PROJECT_SOURCE_DIR}/README.md - DESTINATION ./ + DESTINATION ${IDE_DATA_PATH} COMPONENT Devel EXCLUDE_FROM_ALL ) install( DIRECTORY ${PROJECT_SOURCE_DIR}/scripts - DESTINATION ./ + DESTINATION ${IDE_DATA_PATH} COMPONENT Devel EXCLUDE_FROM_ALL USE_SOURCE_PERMISSIONS ) install(EXPORT QtCreator - DESTINATION "lib/cmake/QtCreator" + DESTINATION ${IDE_CMAKE_INSTALL_PATH}/QtCreator COMPONENT Devel EXCLUDE_FROM_ALL NAMESPACE QtCreator:: FILE QtCreatorTargets.cmake @@ -106,6 +106,6 @@ install( ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.cmake ${PROJECT_SOURCE_DIR}/cmake/QtcSeparateDebugInfo.Info.plist.in ${CMAKE_BINARY_DIR}/cmake/QtCreatorConfig.cmake - DESTINATION lib/cmake/QtCreator + DESTINATION ${IDE_CMAKE_INSTALL_PATH}/QtCreator COMPONENT Devel EXCLUDE_FROM_ALL ) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 127e364536b..b08211cf573 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -2,7 +2,7 @@ configure_file(app_version.h.cmakein app_version.h ESCAPE_QUOTES) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/app_version.h - DESTINATION include/src/app + DESTINATION ${IDE_HEADER_INSTALL_PATH}/src/app COMPONENT Devel EXCLUDE_FROM_ALL ) @@ -89,5 +89,8 @@ extend_qtc_executable(qtcreator DEPENDS Crashpad::Crashpad ) if(BUILD_WITH_CRASHPAD) - install(FILES ${CRASHPAD_BIN_DIR}/crashpad_handler${CMAKE_EXECUTABLE_SUFFIX} DESTINATION "${IDE_LIBEXEC_PATH}") + install( + PROGRAMS ${CRASHPAD_BIN_DIR}/crashpad_handler${CMAKE_EXECUTABLE_SUFFIX} + DESTINATION "${IDE_LIBEXEC_PATH}" + ) endif() diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index bdcd9aabc9a..7907d8272af 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -28,7 +28,7 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt) set(QLITEHTML_EXPORT QtCreator) set(QLITEHTML_DEVEL_COMPONENT Devel) set(QLITEHTML_DEVEL_EXCLUDE_FROM_ALL ON) - set(QLITEHTML_HEADER_PATH "include/src/lib/qlitehtml") + set(QLITEHTML_HEADER_PATH "${IDE_HEADER_INSTALL_PATH}/src/lib/qlitehtml") add_subdirectory(qlitehtml/src) endif() if(TARGET qlitehtml) diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index 083782fec28..11c30939cd5 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -39,7 +39,8 @@ namespace ClangBackEnd { template class FilePathStorage { - using ReadStatement = typename StatementFactory::ReadStatement; + template + using ReadStatement = typename StatementFactory::template ReadStatement; using WriteStatement = typename StatementFactory::WriteStatement; using Database = typename StatementFactory::Database; @@ -84,7 +85,7 @@ public: Utils::optional readDirectoryId(Utils::SmallStringView directoryPath) { - ReadStatement &statement = m_statementFactory.selectDirectoryIdFromDirectoriesByDirectoryPath; + auto &statement = m_statementFactory.selectDirectoryIdFromDirectoriesByDirectoryPath; return statement.template value(directoryPath); } @@ -103,7 +104,7 @@ public: try { Sqlite::DeferredTransaction transaction{m_statementFactory.database}; - ReadStatement &statement = m_statementFactory.selectDirectoryPathFromDirectoriesByDirectoryId; + auto &statement = m_statementFactory.selectDirectoryPathFromDirectoriesByDirectoryId; auto optionalDirectoryPath = statement.template value(directoryPathId); @@ -123,9 +124,9 @@ public: try { Sqlite::DeferredTransaction transaction{m_statementFactory.database}; - ReadStatement &statement = m_statementFactory.selectAllDirectories; + auto &statement = m_statementFactory.selectAllDirectories; - auto directories = statement.template values(256); + auto directories = statement.template values(256); transaction.commit(); @@ -164,7 +165,7 @@ public: int writeSourceId(int directoryId, Utils::SmallStringView sourceName) { - WriteStatement &statement = m_statementFactory.insertIntoSources; + auto &statement = m_statementFactory.insertIntoSources; statement.write(directoryId, sourceName); @@ -173,7 +174,7 @@ public: Utils::optional readSourceId(int directoryId, Utils::SmallStringView sourceName) { - ReadStatement &statement = m_statementFactory.selectSourceIdFromSourcesByDirectoryIdAndSourceName; + auto &statement = m_statementFactory.selectSourceIdFromSourcesByDirectoryIdAndSourceName; return statement.template value(directoryId, sourceName); } @@ -183,9 +184,10 @@ public: try { Sqlite::DeferredTransaction transaction{m_statementFactory.database}; - ReadStatement &statement = m_statementFactory.selectSourceNameAndDirectoryIdFromSourcesBySourceId; + auto &statement = m_statementFactory.selectSourceNameAndDirectoryIdFromSourcesBySourceId; - auto optionalSourceName = statement.template value(sourceId); + auto optionalSourceName = statement.template value( + sourceId); if (!optionalSourceName) throw SourceNameIdDoesNotExists(); @@ -203,7 +205,7 @@ public: try { Sqlite::DeferredTransaction transaction{m_statementFactory.database}; - ReadStatement &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId; + auto &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId; auto optionalDirectoryId = statement.template value(sourceId); @@ -223,9 +225,9 @@ public: try { Sqlite::DeferredTransaction transaction{m_statementFactory.database}; - ReadStatement &statement = m_statementFactory.selectAllSources; + auto &statement = m_statementFactory.selectAllSources; - auto sources = statement.template values(8192); + auto sources = statement.template values(8192); transaction.commit(); diff --git a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h index f0d261dd495..1698fcf0649 100644 --- a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h +++ b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h @@ -35,8 +35,9 @@ class FilePathStorageSqliteStatementFactory { public: using Database = DatabaseType; - using ReadStatement = typename DatabaseType::ReadStatement; - using WriteStatement = typename DatabaseType::WriteStatement; + template + using ReadStatement = typename Database::template ReadStatement; + using WriteStatement = typename Database::WriteStatement; FilePathStorageSqliteStatementFactory(Database &database) : database(database) @@ -45,32 +46,28 @@ public: public: Database &database; - ReadStatement selectDirectoryIdFromDirectoriesByDirectoryPath{ - "SELECT directoryId FROM directories WHERE directoryPath = ?", - database - }; - ReadStatement selectDirectoryPathFromDirectoriesByDirectoryId{ + ReadStatement<1> selectDirectoryIdFromDirectoriesByDirectoryPath{ + "SELECT directoryId FROM directories WHERE directoryPath = ?", database}; + ReadStatement<1> selectDirectoryPathFromDirectoriesByDirectoryId{ "SELECT directoryPath FROM directories WHERE directoryId = ?", database}; - ReadStatement selectAllDirectories{"SELECT directoryPath, directoryId FROM directories", database}; + ReadStatement<2> selectAllDirectories{"SELECT directoryPath, directoryId FROM directories", + database}; WriteStatement insertIntoDirectories{ "INSERT INTO directories(directoryPath) VALUES (?)", database }; - ReadStatement selectSourceIdFromSourcesByDirectoryIdAndSourceName{ - "SELECT sourceId FROM sources WHERE directoryId = ? AND sourceName = ?", - database - }; - ReadStatement selectSourceNameAndDirectoryIdFromSourcesBySourceId{ - "SELECT sourceName, directoryId FROM sources WHERE sourceId = ?", - database - }; - ReadStatement selectDirectoryIdFromSourcesBySourceId{ + ReadStatement<1> selectSourceIdFromSourcesByDirectoryIdAndSourceName{ + "SELECT sourceId FROM sources WHERE directoryId = ? AND sourceName = ?", database}; + ReadStatement<2> selectSourceNameAndDirectoryIdFromSourcesBySourceId{ + "SELECT sourceName, directoryId FROM sources WHERE sourceId = ?", database}; + ReadStatement<1> selectDirectoryIdFromSourcesBySourceId{ "SELECT directoryId FROM sources WHERE sourceId = ?", database}; WriteStatement insertIntoSources{ "INSERT INTO sources(directoryId, sourceName) VALUES (?,?)", database }; - ReadStatement selectAllSources{"SELECT sourceName, directoryId, sourceId FROM sources", database}; + ReadStatement<3> selectAllSources{"SELECT sourceName, directoryId, sourceId FROM sources", + database}; }; } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/projectpartsstorage.h b/src/libs/clangsupport/projectpartsstorage.h index 6363ae708fa..fa211b83bc2 100644 --- a/src/libs/clangsupport/projectpartsstorage.h +++ b/src/libs/clangsupport/projectpartsstorage.h @@ -36,7 +36,8 @@ namespace ClangBackEnd { template class ProjectPartsStorage final : public ProjectPartsStorageInterface { - using ReadStatement = typename Database::ReadStatement; + template + using ReadStatement = typename Database::template ReadStatement; using WriteStatement = typename Database::WriteStatement; public: @@ -52,7 +53,7 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - auto values = fetchProjectPartsStatement.template values(4096); + auto values = fetchProjectPartsStatement.template values(4096); transaction.commit(); @@ -91,7 +92,7 @@ public: Sqlite::DeferredTransaction transaction{database}; for (ProjectPartId projectPartId : projectPartIds) { - auto value = fetchProjectPartByIdStatement.template value( + auto value = fetchProjectPartByIdStatement.template value( projectPartId.projectPathId); if (value) { value->headerPathIds = fetchHeaders(projectPartId); @@ -243,9 +244,9 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - ReadStatement &statement = getProjectPartArtefactsBySourceId; + auto &statement = getProjectPartArtefactsBySourceId; - auto value = statement.template value(sourceId.filePathId); + auto value = statement.template value(sourceId.filePathId); transaction.commit(); @@ -260,9 +261,9 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - ReadStatement &statement = getProjectPartArtefactsByProjectPartId; + auto &statement = getProjectPartArtefactsByProjectPartId; - auto value = statement.template value(projectPartId.projectPathId); + auto value = statement.template value(projectPartId.projectPathId); transaction.commit(); @@ -342,9 +343,9 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - ReadStatement &statement = fetchAllProjectPartNamesAndIdsStatement; + auto &statement = fetchAllProjectPartNamesAndIdsStatement; - auto values = statement.template values(256); + auto values = statement.template values(256); transaction.commit(); @@ -357,18 +358,18 @@ public: public: Sqlite::ImmediateNonThrowingDestructorTransaction transaction; Database &database; - mutable ReadStatement fetchProjectPartIdStatement{ + mutable ReadStatement<1> fetchProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", database}; mutable WriteStatement insertProjectPartNameStatement{ "INSERT INTO projectParts(projectPartName) VALUES (?)", database}; - mutable ReadStatement fetchProjectPartNameStatement{ + mutable ReadStatement<1> fetchProjectPartNameStatement{ "SELECT projectPartName FROM projectParts WHERE projectPartId = ?", database}; - mutable ReadStatement fetchProjectPartsStatement{ + mutable ReadStatement<8> fetchProjectPartsStatement{ "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension " "FROM projectParts", database}; - mutable ReadStatement fetchProjectPartByIdStatement{ + mutable ReadStatement<8> fetchProjectPartByIdStatement{ "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension " "FROM projectParts WHERE projectPartId = ?", @@ -378,13 +379,13 @@ public: "systemIncludeSearchPaths=?004, projectIncludeSearchPaths=?005, language=?006, " "languageVersion=?007, languageExtension=?008 WHERE projectPartId = ?001", database}; - mutable ReadStatement getProjectPartArtefactsBySourceId{ + mutable ReadStatement<8> getProjectPartArtefactsBySourceId{ "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension " "FROM projectParts WHERE projectPartId = (SELECT " "projectPartId FROM projectPartsFiles WHERE sourceId = ?)", database}; - mutable ReadStatement getProjectPartArtefactsByProjectPartId{ + mutable ReadStatement<8> getProjectPartArtefactsByProjectPartId{ "SELECT toolChainArguments, compilerMacros, systemIncludeSearchPaths, " "projectIncludeSearchPaths, projectPartId, language, languageVersion, languageExtension " "FROM projectParts WHERE projectPartId = ?", @@ -397,17 +398,17 @@ public: "INSERT INTO projectPartsHeaders(projectPartId, sourceId) VALUES (?,?)", database}; WriteStatement insertProjectPartsSourcesStatement{ "INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)", database}; - mutable ReadStatement fetchProjectPartsHeadersByIdStatement{ + mutable ReadStatement<1> fetchProjectPartsHeadersByIdStatement{ "SELECT sourceId FROM projectPartsHeaders WHERE projectPartId = ? ORDER BY sourceId", database}; - mutable ReadStatement fetchProjectPartsSourcesByIdStatement{ + mutable ReadStatement<1> fetchProjectPartsSourcesByIdStatement{ "SELECT sourceId FROM projectPartsSources WHERE projectPartId = ? ORDER BY sourceId", database}; - mutable ReadStatement fetchProjectPrecompiledHeaderBuildTimeStatement{ + mutable ReadStatement<1> fetchProjectPrecompiledHeaderBuildTimeStatement{ "SELECT projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?", database}; WriteStatement resetDependentIndexingTimeStampsStatement{ "UPDATE fileStatuses SET indexingTimeStamp = NULL WHERE sourceId = ?", database}; - mutable ReadStatement fetchAllProjectPartNamesAndIdsStatement{ + mutable ReadStatement<2> fetchAllProjectPartNamesAndIdsStatement{ "SELECT projectPartName, projectPartId FROM projectParts", database}; }; } // namespace ClangBackEnd diff --git a/src/libs/languageserverprotocol/jsonobject.h b/src/libs/languageserverprotocol/jsonobject.h index ae2843774ec..3b32ed81f58 100644 --- a/src/libs/languageserverprotocol/jsonobject.h +++ b/src/libs/languageserverprotocol/jsonobject.h @@ -150,15 +150,20 @@ Utils::optional> JsonObject::optionalClientValue(const QS template QList JsonObject::array(const QString &key) const { - return LanguageClientArray(value(key)).toList(); + const Utils::optional> &array = optionalArray(key); + if (array.has_value()) + return array.value(); + qCDebug(conversionLog) << QString("Expected array under %1 in:").arg(key) << *this; + return {}; } template Utils::optional> JsonObject::optionalArray(const QString &key) const { - using Result = Utils::optional>; - return contains(key) ? Result(LanguageClientArray(value(key)).toList()) - : Result(Utils::nullopt); + const QJsonValue &jsonValue = value(key); + if (jsonValue.isUndefined()) + return Utils::nullopt; + return Utils::transform>(jsonValue.toArray(), &fromJsonValue); } template diff --git a/src/libs/sqlite/CMakeLists.txt b/src/libs/sqlite/CMakeLists.txt index f684fa0849f..4bf3ae91df0 100644 --- a/src/libs/sqlite/CMakeLists.txt +++ b/src/libs/sqlite/CMakeLists.txt @@ -30,15 +30,15 @@ add_qtc_library(Sqlite sqliteexception.cpp sqliteexception.h sqliteglobal.cpp sqliteglobal.h sqliteindex.h - sqlitereadstatement.cpp sqlitereadstatement.h - sqlitereadwritestatement.cpp sqlitereadwritestatement.h + sqlitereadstatement.h + sqlitereadwritestatement.h sqlitesessionchangeset.cpp sqlitesessionchangeset.h sqlitesessions.cpp sqlitesessions.h sqlitetable.h sqlitetransaction.h sqlitetransaction.h sqlitevalue.h - sqlitewritestatement.cpp sqlitewritestatement.h + sqlitewritestatement.h sqlstatementbuilder.cpp sqlstatementbuilder.h sqlstatementbuilderexception.h tableconstraints.h diff --git a/src/libs/sqlite/sqlite-lib.pri b/src/libs/sqlite/sqlite-lib.pri index fd02c8801f0..87b63eb388e 100644 --- a/src/libs/sqlite/sqlite-lib.pri +++ b/src/libs/sqlite/sqlite-lib.pri @@ -15,11 +15,8 @@ SOURCES += \ $$PWD/sqlitedatabasebackend.cpp \ $$PWD/sqliteexception.cpp \ $$PWD/sqliteglobal.cpp \ - $$PWD/sqlitereadstatement.cpp \ - $$PWD/sqlitereadwritestatement.cpp \ $$PWD/sqlitesessionchangeset.cpp \ $$PWD/sqlitesessions.cpp \ - $$PWD/sqlitewritestatement.cpp \ $$PWD/sqlstatementbuilder.cpp \ $$PWD/utf8string.cpp \ $$PWD/utf8stringvector.cpp \ diff --git a/src/libs/sqlite/sqlite-source.pri b/src/libs/sqlite/sqlite-source.pri index 57292939018..e951f2e1a7a 100644 --- a/src/libs/sqlite/sqlite-source.pri +++ b/src/libs/sqlite/sqlite-source.pri @@ -10,12 +10,9 @@ SOURCES += \ sqlitedatabaseconnectionproxy.cpp \ sqliteexception.cpp \ sqliteglobal.cpp \ - sqlitereadstatement.cpp \ - sqlitereadwritestatement.cpp \ sqlitestatement.cpp \ sqlitetransaction.cpp \ sqliteworkerthread.cpp \ - sqlitewritestatement.cpp \ sqlstatementbuilder.cpp \ utf8string.cpp \ utf8stringvector.cpp \ diff --git a/src/libs/sqlite/sqlitebasestatement.cpp b/src/libs/sqlite/sqlitebasestatement.cpp index 7412473dad1..7f8cd86ab4b 100644 --- a/src/libs/sqlite/sqlitebasestatement.cpp +++ b/src/libs/sqlite/sqlitebasestatement.cpp @@ -687,7 +687,8 @@ StringType textForColumn(sqlite3_stmt *sqlStatment, int column) BlobView blobForColumn(sqlite3_stmt *sqlStatment, int column) { - const byte *blob = reinterpret_cast(sqlite3_column_blob(sqlStatment, column)); + const std::byte *blob = reinterpret_cast( + sqlite3_column_blob(sqlStatment, column)); std::size_t size = std::size_t(sqlite3_column_bytes(sqlStatment, column)); return {blob, size}; diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index d59e9adb14f..08fb7ed0ed0 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -159,7 +159,7 @@ extern template SQLITE_EXPORT Utils::SmallStringView BaseStatement::fetchValue(int column) const; extern template SQLITE_EXPORT Utils::PathString BaseStatement::fetchValue(int column) const; -template +template class StatementImplementation : public BaseStatement { @@ -173,9 +173,7 @@ public: resetter.reset(); } - void bindValues() - { - } + void bindValues() {} template void bindValues(const ValueType&... values) @@ -192,18 +190,15 @@ public: resetter.reset(); } - template + template std::vector values(std::size_t reserveSize) { - BaseStatement::checkColumnCount(ResultTypeCount); - Resetter resetter{*this}; std::vector resultValues; resultValues.reserve(std::max(reserveSize, m_maximumResultCount)); while (BaseStatement::next()) - emplaceBackValues(resultValues); + emplaceBackValues(resultValues); setMaximumResultCount(resultValues.size()); @@ -212,11 +207,9 @@ public: return resultValues; } - template + template auto values(std::size_t reserveSize, const QueryTypes &...queryValues) { - BaseStatement::checkColumnCount(ResultTypeCount); - Resetter resetter{*this}; std::vector resultValues; resultValues.reserve(std::max(reserveSize, m_maximumResultCount)); @@ -224,7 +217,7 @@ public: bindValues(queryValues...); while (BaseStatement::next()) - emplaceBackValues(resultValues); + emplaceBackValues(resultValues); setMaximumResultCount(resultValues.size()); @@ -233,66 +226,16 @@ public: return resultValues; } - template - auto values(std::size_t reserveSize, const std::vector &queryValues) - { - BaseStatement::checkColumnCount(ResultTypeCount); - - std::vector resultValues; - resultValues.reserve(std::max(reserveSize, m_maximumResultCount)); - - for (const QueryElementType &queryValue : queryValues) { - Resetter resetter{*this}; - bindValues(queryValue); - - while (BaseStatement::next()) - emplaceBackValues(resultValues); - - setMaximumResultCount(resultValues.size()); - - resetter.reset(); - } - - return resultValues; - } - - template - auto values(std::size_t reserveSize, - const std::vector> &queryTuples) - { - BaseStatement::checkColumnCount(ResultTypeCount); - - using Container = std::vector; - Container resultValues; - resultValues.reserve(std::max(reserveSize, m_maximumResultCount)); - - for (const auto &queryTuple : queryTuples) { - Resetter resetter{*this}; - bindTupleValues(queryTuple); - - while (BaseStatement::next()) - emplaceBackValues(resultValues); - - setMaximumResultCount(resultValues.size()); - - resetter.reset(); - } - - return resultValues; - } - - template + template auto value(const QueryTypes &...queryValues) { - BaseStatement::checkColumnCount(ResultTypeCount); - Resetter resetter{*this}; Utils::optional resultValue; bindValues(queryValues...); if (BaseStatement::next()) - resultValue = assignValue, ResultTypeCount>(); + resultValue = assignValue>(); resetter.reset(); @@ -311,17 +254,15 @@ public: return statement.template fetchValue(0); } - template + template void readCallback(Callable &&callable, const QueryTypes &...queryValues) { - BaseStatement::checkColumnCount(ResultTypeCount); - Resetter resetter{*this}; bindValues(queryValues...); while (BaseStatement::next()) { - auto control = callCallable(callable); + auto control = callCallable(callable); if (control == CallbackControl::Abort) break; @@ -333,14 +274,12 @@ public: template void readTo(Container &container, const QueryTypes &...queryValues) { - BaseStatement::checkColumnCount(ResultTypeCount); - Resetter resetter{*this}; bindValues(queryValues...); while (BaseStatement::next()) - emplaceBackValues(container); + emplaceBackValues(container); resetter.reset(); } @@ -399,18 +338,21 @@ private: int column; }; - template + constexpr int resultCount(int localResultCount) const + { + return ResultCount < 0 ? localResultCount : ResultCount; + } + + template void emplaceBackValues(ContainerType &container, std::integer_sequence) { container.emplace_back(ValueGetter(*this, ColumnIndices)...); } - template + template void emplaceBackValues(ContainerType &container) { - emplaceBackValues(container, std::make_integer_sequence{}); + emplaceBackValues(container, std::make_integer_sequence{}); } template + template ResultOptionalType assignValue() { - return assignValue(std::make_integer_sequence{}); + return assignValue(std::make_integer_sequence{}); } template @@ -433,10 +374,10 @@ private: return std::invoke(callable, ValueGetter(*this, ColumnIndices)...); } - template + template CallbackControl callCallable(Callable &&callable) { - return callCallable(callable, std::make_integer_sequence{}); + return callCallable(callable, std::make_integer_sequence{}); } template @@ -446,25 +387,12 @@ private: } template - void bindValuesByIndex(int index, const ValueType &value, const ValueTypes&... values) + void bindValuesByIndex(int index, const ValueType &value, const ValueTypes &...values) { BaseStatement::bind(index, value); bindValuesByIndex(index + 1, values...); } - template - void bindTupleValuesElement(const TupleType &tuple, std::index_sequence) - { - bindValues(std::get(tuple)...); - } - - template ::value>> - void bindTupleValues(const TupleType &element) - { - bindTupleValuesElement(element, ColumnIndices()); - } - void setMaximumResultCount(std::size_t count) { m_maximumResultCount = std::max(m_maximumResultCount, count); diff --git a/src/libs/sqlite/sqliteblob.h b/src/libs/sqlite/sqliteblob.h index 17d9426ad04..311380e02a5 100644 --- a/src/libs/sqlite/sqliteblob.h +++ b/src/libs/sqlite/sqliteblob.h @@ -42,22 +42,27 @@ class BlobView public: BlobView() = default; - BlobView(const byte *data, std::size_t size) + BlobView(const std::byte *data, std::size_t size) : m_data(data) , m_size(size) {} BlobView(const QByteArray &byteArray) - : m_data(reinterpret_cast(byteArray.constData())) + : m_data(reinterpret_cast(byteArray.constData())) , m_size(static_cast(byteArray.size())) {} - BlobView(const std::vector &bytes) + BlobView(const std::vector &bytes) : m_data(bytes.data()) , m_size(static_cast(bytes.size())) {} - const byte *data() const { return m_data; } + BlobView(Utils::span bytes) + : m_data(bytes.data()) + , m_size(static_cast(bytes.size())) + {} + + const std::byte *data() const { return m_data; } const char *cdata() const { return reinterpret_cast(m_data); } std::size_t size() const { return m_size; } int sisize() const { return static_cast(m_size); } @@ -71,7 +76,7 @@ public: } private: - const byte *m_data{}; + const std::byte *m_data{}; std::size_t m_size{}; }; @@ -84,7 +89,22 @@ public: std::copy_n(blobView.data(), blobView.size(), std::back_inserter(bytes)); } - std::vector bytes; + std::vector bytes; + + friend bool operator==(const Sqlite::Blob &first, const Sqlite::Blob &second) + { + return BlobView{first.bytes} == BlobView{second.bytes}; + } + + friend bool operator==(const Sqlite::Blob &first, Sqlite::BlobView second) + { + return BlobView{first.bytes} == second; + } + + friend bool operator==(Sqlite::BlobView first, const Sqlite::Blob &second) + { + return second == first; + } }; class ByteArrayBlob diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 994dfd3c036..2cae9b2fc32 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -47,11 +47,11 @@ public: public: Database &database; - ReadWriteStatement deferredBegin{"BEGIN", database}; - ReadWriteStatement immediateBegin{"BEGIN IMMEDIATE", database}; - ReadWriteStatement exclusiveBegin{"BEGIN EXCLUSIVE", database}; - ReadWriteStatement commitBegin{"COMMIT", database}; - ReadWriteStatement rollbackBegin{"ROLLBACK", database}; + ReadWriteStatement<> deferredBegin{"BEGIN", database}; + ReadWriteStatement<> immediateBegin{"BEGIN IMMEDIATE", database}; + ReadWriteStatement<> exclusiveBegin{"BEGIN EXCLUSIVE", database}; + ReadWriteStatement<> commitBegin{"COMMIT", database}; + ReadWriteStatement<> rollbackBegin{"ROLLBACK", database}; Sessions sessions{database, "main", "databaseSessions"}; }; diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 63afb6e72ec..077e2723e05 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -42,8 +42,10 @@ namespace Sqlite { using namespace std::chrono_literals; +template class ReadStatement; class WriteStatement; +template class ReadWriteStatement; class SQLITE_EXPORT Database final : public TransactionInterface, public DatabaseInterface @@ -54,9 +56,11 @@ class SQLITE_EXPORT Database final : public TransactionInterface, public Databas public: using MutexType = std::mutex; - using ReadStatement = Sqlite::ReadStatement; + template + using ReadStatement = Sqlite::ReadStatement; using WriteStatement = Sqlite::WriteStatement; - using ReadWriteStatement = Sqlite::ReadWriteStatement; + template + using ReadWriteStatement = Sqlite::ReadWriteStatement; using BusyHandler = DatabaseBackend::BusyHandler; Database(); diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp index 46097406e8c..0101e826260 100644 --- a/src/libs/sqlite/sqlitedatabasebackend.cpp +++ b/src/libs/sqlite/sqlitedatabasebackend.cpp @@ -128,7 +128,9 @@ sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const void DatabaseBackend::setPragmaValue(Utils::SmallStringView pragmaKey, Utils::SmallStringView newPragmaValue) { - execute(Utils::SmallString{"PRAGMA ", pragmaKey, "='", newPragmaValue, "'"}); + ReadWriteStatement<1>{Utils::SmallString{"PRAGMA ", pragmaKey, "='", newPragmaValue, "'"}, + m_database} + .execute(); Utils::SmallString pragmeValueInDatabase = toValue("PRAGMA " + pragmaKey); checkPragmaValue(pragmeValueInDatabase, newPragmaValue); @@ -172,7 +174,7 @@ void DatabaseBackend::setLastInsertedRowId(int64_t rowId) void DatabaseBackend::execute(Utils::SmallStringView sqlStatement) { try { - ReadWriteStatement statement(sqlStatement, m_database); + ReadWriteStatement<0> statement(sqlStatement, m_database); statement.execute(); } catch (StatementIsBusy &) { execute(sqlStatement); @@ -454,7 +456,7 @@ template Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) { try { - ReadWriteStatement statement(sqlStatement, m_database); + ReadWriteStatement<1> statement(sqlStatement, m_database); statement.next(); diff --git a/src/libs/sqlite/sqliteglobal.h b/src/libs/sqlite/sqliteglobal.h index 6f6ecba5423..0bdb3c2aef9 100644 --- a/src/libs/sqlite/sqliteglobal.h +++ b/src/libs/sqlite/sqliteglobal.h @@ -66,8 +66,6 @@ enum class OpenMode : char enum class ChangeType : int { Delete = 9, Insert = 18, Update = 23 }; -enum class byte : unsigned char {}; - enum class CallbackControl : unsigned char { Continue, Abort }; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index 236aab67f17..eb9c4e5cc5c 100644 --- a/src/libs/sqlite/sqlitereadstatement.h +++ b/src/libs/sqlite/sqlitereadstatement.h @@ -29,19 +29,37 @@ namespace Sqlite { -class SQLITE_EXPORT ReadStatement final : protected StatementImplementation +template +class ReadStatement final : protected StatementImplementation { -public: - explicit ReadStatement(Utils::SmallStringView sqlStatement, Database &database); + using Base = StatementImplementation; - using StatementImplementation::readCallback; - using StatementImplementation::readTo; - using StatementImplementation::toValue; - using StatementImplementation::value; - using StatementImplementation::values; +public: + ReadStatement(Utils::SmallStringView sqlStatement, Database &database) + : Base{sqlStatement, database} + { + checkIsReadOnlyStatement(); + Base::checkColumnCount(ResultCount); + } + + using Base::readCallback; + using Base::readTo; + using Base::toValue; + using Base::value; + using Base::values; protected: - void checkIsReadOnlyStatement(); + void checkIsReadOnlyStatement() + { + if (!Base::isReadOnlyStatement()) + throw NotReadOnlySqlStatement( + "SqliteStatement::SqliteReadStatement: is not read only statement!"); + } }; +template +ReadStatement(ReadStatement &) -> ReadStatement; +template +ReadStatement(const ReadStatement &) -> ReadStatement; + } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadwritestatement.cpp b/src/libs/sqlite/sqlitereadwritestatement.cpp deleted file mode 100644 index 8910ffd7f06..00000000000 --- a/src/libs/sqlite/sqlitereadwritestatement.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#include "sqlitereadwritestatement.h" - -namespace Sqlite { - -ReadWriteStatement::ReadWriteStatement(Utils::SmallStringView sqlStatement, - Database &database) - : StatementImplementation(sqlStatement, database) -{ -} - -} // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h index 6adc9ebb35f..4e2aecabc72 100644 --- a/src/libs/sqlite/sqlitereadwritestatement.h +++ b/src/libs/sqlite/sqlitereadwritestatement.h @@ -29,20 +29,26 @@ namespace Sqlite { -class SQLITE_EXPORT ReadWriteStatement final : protected StatementImplementation +template +class ReadWriteStatement final : protected StatementImplementation { friend class DatabaseBackend; + using Base = StatementImplementation; public: - ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database); + ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database) + : Base{sqlStatement, database} + { + Base::checkColumnCount(ResultCount); + } - using StatementImplementation::execute; - using StatementImplementation::readCallback; - using StatementImplementation::readTo; - using StatementImplementation::toValue; - using StatementImplementation::value; - using StatementImplementation::values; - using StatementImplementation::write; + using Base::execute; + using Base::readCallback; + using Base::readTo; + using Base::toValue; + using Base::value; + using Base::values; + using Base::write; }; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitesessionchangeset.cpp b/src/libs/sqlite/sqlitesessionchangeset.cpp index bc18efaed7f..76fc088f92f 100644 --- a/src/libs/sqlite/sqlitesessionchangeset.cpp +++ b/src/libs/sqlite/sqlitesessionchangeset.cpp @@ -118,7 +118,7 @@ SessionChangeSet::~SessionChangeSet() BlobView SessionChangeSet::asBlobView() const { - return {static_cast(m_data), static_cast(m_size)}; + return {static_cast(m_data), static_cast(m_size)}; } SessionChangeSetInternal::ConstIterator SessionChangeSet::begin() const diff --git a/src/libs/sqlite/sqlitesessions.cpp b/src/libs/sqlite/sqlitesessions.cpp index b1fc2361710..df668fdc593 100644 --- a/src/libs/sqlite/sqlitesessions.cpp +++ b/src/libs/sqlite/sqlitesessions.cpp @@ -127,10 +127,10 @@ void Internal::SessionsBase::createSessionTable(Database &database) void Sessions::revert() { - ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ", - sessionsTableName, - " ORDER BY id DESC"}, - database}; + ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ", + sessionsTableName, + " ORDER BY id DESC"}, + database}; auto changeSets = selectChangeSets.values(1024); @@ -151,10 +151,10 @@ void Sessions::revert() void Sessions::apply() { - ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ", - sessionsTableName, - " ORDER BY id"}, - database}; + ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ", + sessionsTableName, + " ORDER BY id"}, + database}; auto changeSets = selectChangeSets.values(1024); @@ -187,10 +187,10 @@ void Sessions::deleteAll() SessionChangeSets Sessions::changeSets() const { - ReadStatement selectChangeSets{Utils::PathString{"SELECT changeset FROM ", - sessionsTableName, - " ORDER BY id DESC"}, - database}; + ReadStatement<1> selectChangeSets{Utils::PathString{"SELECT changeset FROM ", + sessionsTableName, + " ORDER BY id DESC"}, + database}; return selectChangeSets.values(1024); } diff --git a/src/libs/sqlite/sqlitevalue.h b/src/libs/sqlite/sqlitevalue.h index 8ace8a7bf19..220d8d1e063 100644 --- a/src/libs/sqlite/sqlitevalue.h +++ b/src/libs/sqlite/sqlitevalue.h @@ -25,6 +25,7 @@ #pragma once +#include "sqliteblob.h" #include "sqliteexception.h" #include @@ -36,7 +37,7 @@ namespace Sqlite { -enum class ValueType : unsigned char { Null, Integer, Float, String }; +enum class ValueType : unsigned char { Null, Integer, Float, String, Blob }; class NullValue { @@ -47,7 +48,7 @@ template class ValueBase { public: - using VariantType = Utils::variant; + using VariantType = Utils::variant; ValueBase() = default; @@ -81,6 +82,26 @@ public: {} + explicit ValueBase(StringType &&value) + : value(std::move(value)) + + {} + + explicit ValueBase(BlobView value) + : value(value) + + {} + + explicit ValueBase(Blob &&value) + : value(std::move(value)) + + {} + + explicit ValueBase(const Blob &value) + : value(value) + + {} + bool isNull() const { return value.index() == 0; } long long toInteger() const { return Utils::get(value); } @@ -92,6 +113,12 @@ public: return Utils::get(value); } + BlobView toBlobView() const + { + const Blob &blob = Utils::get(value); + + return {blob.bytes}; + } explicit operator QVariant() const { switch (type()) { @@ -101,6 +128,10 @@ public: return QVariant(toFloat()); case ValueType::String: return QVariant(QString(toStringView())); + case ValueType::Blob: { + auto blobView = toBlobView(); + return QVariant(QByteArray(blobView.cdata(), blobView.sisize())); + } case ValueType::Null: break; } @@ -121,9 +152,9 @@ public: friend bool operator==(const ValueBase &first, double second) { - auto maybeInteger = Utils::get_if(&first.value); + auto maybeFloat = Utils::get_if(&first.value); - return maybeInteger && *maybeInteger == second; + return maybeFloat && *maybeFloat == second; } friend bool operator==(const ValueBase &first, int second) @@ -144,9 +175,9 @@ public: friend bool operator==(const ValueBase &first, Utils::SmallStringView second) { - auto maybeInteger = Utils::get_if(&first.value); + auto maybeString = Utils::get_if(&first.value); - return maybeInteger && *maybeInteger == second; + return maybeString && *maybeString == second; } friend bool operator==(Utils::SmallStringView first, const ValueBase &second) @@ -156,10 +187,9 @@ public: friend bool operator==(const ValueBase &first, const QString &second) { - auto maybeInteger = Utils::get_if(&first.value); + auto maybeString = Utils::get_if(&first.value); - return maybeInteger - && second == QLatin1String{maybeInteger->data(), int(maybeInteger->size())}; + return maybeString && second == QLatin1String{maybeString->data(), int(maybeString->size())}; } friend bool operator==(const QString &first, const ValueBase &second) @@ -184,6 +214,15 @@ public: return !(first.value == second.value); } + friend bool operator==(const ValueBase &first, BlobView second) + { + auto maybeBlob = Utils::get_if(&first.value); + + return maybeBlob && *maybeBlob == second; + } + + friend bool operator==(BlobView first, const ValueBase &second) { return second == first; } + ValueType type() const { switch (value.index()) { @@ -195,6 +234,8 @@ public: return ValueType::Float; case 3: return ValueType::String; + case 4: + return ValueType::Blob; } return {}; @@ -253,6 +294,18 @@ public: : ValueBase(VariantType{Utils::SmallString(value)}) {} + explicit Value(const Blob &value) + : ValueBase(value) + {} + + explicit Value(Blob &&value) + : ValueBase(std::move(value)) + {} + + explicit Value(BlobView value) + : ValueBase(value) + {} + friend bool operator!=(const Value &first, const Value &second) { return !(first.value == second.value); @@ -282,6 +335,8 @@ public: return first.toFloat() == second.toFloat(); case ValueType::String: return first.toStringView() == second.toStringView(); + case ValueType::Blob: + return first.toBlobView() == second.toBlobView(); case ValueType::Null: return false; } @@ -308,6 +363,8 @@ private: return VariantType{value.toFloat()}; case QVariant::String: return VariantType{value.toString()}; + case QVariant::ByteArray: + return VariantType{Blob{value.toByteArray()}}; default: throw CannotConvert("Cannot convert this QVariant to a ValueBase"); } @@ -324,6 +381,8 @@ private: return VariantType{view.toFloat()}; case ValueType::String: return VariantType{view.toStringView()}; + case ValueType::Blob: + return VariantType{view.toBlobView()}; default: throw CannotConvert("Cannot convert this QVariant to a ValueBase"); } diff --git a/src/libs/sqlite/sqlitewritestatement.cpp b/src/libs/sqlite/sqlitewritestatement.cpp deleted file mode 100644 index 89fce7abf3d..00000000000 --- a/src/libs/sqlite/sqlitewritestatement.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#include "sqlitewritestatement.h" - -namespace Sqlite { - -WriteStatement::WriteStatement(Utils::SmallStringView sqlStatement, - Database &database) - : StatementImplementation(sqlStatement, database) -{ - checkIsWritableStatement(); -} - -void WriteStatement::checkIsWritableStatement() -{ - if (isReadOnlyStatement()) - throw NotWriteSqlStatement("SqliteStatement::SqliteWriteStatement: is not a writable statement!"); -} - -} // namespace Sqlite diff --git a/src/libs/sqlite/sqlitewritestatement.h b/src/libs/sqlite/sqlitewritestatement.h index 4dbcd4f9c68..1a0bb5832ca 100644 --- a/src/libs/sqlite/sqlitewritestatement.h +++ b/src/libs/sqlite/sqlitewritestatement.h @@ -29,17 +29,28 @@ namespace Sqlite { -class SQLITE_EXPORT WriteStatement : protected StatementImplementation +class WriteStatement : protected StatementImplementation { -public: - explicit WriteStatement(Utils::SmallStringView sqlStatement, Database &database); + using Base = StatementImplementation; + +public: + WriteStatement(Utils::SmallStringView sqlStatement, Database &database) + : StatementImplementation(sqlStatement, database) + { + checkIsWritableStatement(); + } - using StatementImplementation::execute; using StatementImplementation::database; + using StatementImplementation::execute; using StatementImplementation::write; protected: - void checkIsWritableStatement(); + void checkIsWritableStatement() + { + if (Base::isReadOnlyStatement()) + throw NotWriteSqlStatement( + "SqliteStatement::SqliteWriteStatement: is not a writable statement!"); + } }; } // namespace Sqlite diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index 208d7034da4..ad6ee1df081 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -55,7 +55,7 @@ public: : std::string_view{std::addressof(*begin), static_cast(std::distance(begin, end))} {} -#ifdef Q_OS_WINDOWS +#ifdef Q_CC_MSVC constexpr SmallStringView(const char *const begin, const char *const end) noexcept : std::string_view{begin, static_cast(std::distance(begin, end))} {} diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index ecc93648da9..7338c6a6609 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -421,17 +421,17 @@ void BoostTestOutputReader::onFinished(int exitCode, QProcess::ExitStatus /*exit if (m_logLevel == LogLevel::Nothing && m_reportLevel == ReportLevel::No) { switch (exitCode) { case 0: - reportNoOutputFinish(tr("Running tests exited with ") + "boost::exit_success.", + reportNoOutputFinish(tr("Running tests exited with %1").arg("boost::exit_success."), ResultType::Pass); break; case 200: reportNoOutputFinish( - tr("Running tests exited with ") + "boost::exit_test_exception.", + tr("Running tests exited with %1").arg("boost::exit_test_exception."), ResultType::MessageFatal); break; case 201: - reportNoOutputFinish(tr("Running tests exited with ") - + "boost::exit_test_failure.", ResultType::Fail); + reportNoOutputFinish(tr("Running tests exited with %1") + .arg("boost::exit_test_failure."), ResultType::Fail); break; } } else if (exitCode != 0 && exitCode != 201 && !m_description.isEmpty()) { diff --git a/src/plugins/clangrefactoring/querysqlitestatementfactory.h b/src/plugins/clangrefactoring/querysqlitestatementfactory.h index 65d82895792..b503a72b0ac 100644 --- a/src/plugins/clangrefactoring/querysqlitestatementfactory.h +++ b/src/plugins/clangrefactoring/querysqlitestatementfactory.h @@ -27,51 +27,54 @@ namespace ClangRefactoring { -template +template class QuerySqliteStatementFactory { public: using DatabaseType = Database; - using ReadStatementType = ReadStatement; + template + using ReadStatement = typename Database::template ReadStatement; QuerySqliteStatementFactory(Database &database) : database(database) {} Database &database; - ReadStatement selectLocationsForSymbolLocation{ + ReadStatement<3> selectLocationsForSymbolLocation{ "SELECT sourceId, line, column FROM locations WHERE symbolId = " " (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND column=?) " "ORDER BY sourceId, line, column", database}; - ReadStatement selectSourceUsagesForSymbolLocation{ + ReadStatement<3> selectSourceUsagesForSymbolLocation{ "SELECT directoryPath || '/' || sourceName, line, column " "FROM locations NATURAL JOIN sources NATURAL JOIN directories " "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " "column=?)", database}; - ReadStatement selectSourceUsagesOrderedForSymbolLocation{ + ReadStatement<3> selectSourceUsagesOrderedForSymbolLocation{ "SELECT directoryPath || '/' || sourceName, line, column " "FROM locations NATURAL JOIN sources NATURAL JOIN directories " "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " "column=?) ORDER BY locationKind LIMIT 2", database}; - ReadStatement selectSourceUsagesByLocationKindForSymbolLocation{ + ReadStatement<3> selectSourceUsagesByLocationKindForSymbolLocation{ "SELECT directoryPath || '/' || sourceName, line, column " "FROM locations NATURAL JOIN sources NATURAL JOIN directories " "WHERE symbolId = (SELECT symbolId FROM locations WHERE sourceId=? AND line=? AND " "column=?) AND locationKind = ?", database}; - ReadStatement selectSymbolsForKindAndStartsWith{ - "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind = ? AND symbolName LIKE ?", + ReadStatement<3> selectSymbolsForKindAndStartsWith{ + "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind = ? AND symbolName " + "LIKE ?", database}; - ReadStatement selectSymbolsForKindAndStartsWith2{ - "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind IN (?,?) AND symbolName LIKE ?", + ReadStatement<3> selectSymbolsForKindAndStartsWith2{ + "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind IN (?,?) AND " + "symbolName LIKE ?", database}; - ReadStatement selectSymbolsForKindAndStartsWith3{ - "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind IN (?,?,?) AND symbolName LIKE ?", + ReadStatement<3> selectSymbolsForKindAndStartsWith3{ + "SELECT symbolId, symbolName, signature FROM symbols WHERE symbolKind IN (?,?,?) AND " + "symbolName LIKE ?", database}; - ReadStatement selectLocationOfSymbol{ + ReadStatement<3> selectLocationOfSymbol{ "SELECT sourceId, line, column FROM locations AS l WHERE symbolId = ? AND locationKind = ?", database}; }; diff --git a/src/plugins/clangrefactoring/symbolquery.h b/src/plugins/clangrefactoring/symbolquery.h index 2468369c828..7ceab186fdc 100644 --- a/src/plugins/clangrefactoring/symbolquery.h +++ b/src/plugins/clangrefactoring/symbolquery.h @@ -40,8 +40,6 @@ namespace ClangRefactoring { template class SymbolQuery final : public SymbolQueryInterface { - using ReadStatement = typename StatementFactory::ReadStatementType; - public: SymbolQuery(StatementFactory &statementFactory) : m_statementFactory(statementFactory) @@ -51,28 +49,28 @@ public: int line, int utf8Column) const override { - ReadStatement &locationsStatement = m_statementFactory.selectLocationsForSymbolLocation; + auto &locationsStatement = m_statementFactory.selectLocationsForSymbolLocation; const std::size_t reserveSize = 128; - return locationsStatement.template values(reserveSize, - filePathId.filePathId, - line, - utf8Column); + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column); } CppTools::Usages sourceUsagesAt(ClangBackEnd::FilePathId filePathId, int line, int utf8Column) const override { - ReadStatement &locationsStatement = m_statementFactory.selectSourceUsagesForSymbolLocation; + auto &locationsStatement = m_statementFactory.selectSourceUsagesForSymbolLocation; const std::size_t reserveSize = 128; - return locationsStatement.template values(reserveSize, - filePathId.filePathId, - line, - utf8Column); + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column); } CppTools::Usages sourceUsagesAtByLocationKind(ClangBackEnd::FilePathId filePathId, @@ -80,46 +78,46 @@ public: int utf8Column, ClangBackEnd::SourceLocationKind kind) const override { - ReadStatement &locationsStatement = m_statementFactory.selectSourceUsagesByLocationKindForSymbolLocation; + auto &locationsStatement = m_statementFactory.selectSourceUsagesByLocationKindForSymbolLocation; const std::size_t reserveSize = 128; - return locationsStatement.template values(reserveSize, - filePathId.filePathId, - line, - utf8Column, - int(kind)); + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column, + int(kind)); } CppTools::Usages declarationsAt(ClangBackEnd::FilePathId filePathId, int line, int utf8Column) const override { - ReadStatement &locationsStatement = m_statementFactory.selectSourceUsagesOrderedForSymbolLocation; + auto &locationsStatement = m_statementFactory.selectSourceUsagesOrderedForSymbolLocation; const std::size_t reserveSize = 128; - return locationsStatement.template values(reserveSize, - filePathId.filePathId, - line, - utf8Column); + return locationsStatement.template values(reserveSize, + filePathId.filePathId, + line, + utf8Column); } Symbols symbolsWithOneSymbolKinds(ClangBackEnd::SymbolKind symbolKind, Utils::SmallStringView searchTerm) const { - ReadStatement &statement = m_statementFactory.selectSymbolsForKindAndStartsWith; + auto &statement = m_statementFactory.selectSymbolsForKindAndStartsWith; - return statement.template values(100, int(symbolKind), searchTerm); + return statement.template values(100, int(symbolKind), searchTerm); } Symbols symbolsWithTwoSymbolKinds(ClangBackEnd::SymbolKind symbolKind1, ClangBackEnd::SymbolKind symbolKind2, Utils::SmallStringView searchTerm) const { - ReadStatement &statement = m_statementFactory.selectSymbolsForKindAndStartsWith2; + auto &statement = m_statementFactory.selectSymbolsForKindAndStartsWith2; - return statement.template values(100, int(symbolKind1), int(symbolKind2), searchTerm); + return statement.template values(100, int(symbolKind1), int(symbolKind2), searchTerm); } Symbols symbolsWithThreeSymbolKinds(ClangBackEnd::SymbolKind symbolKind1, @@ -127,9 +125,13 @@ public: ClangBackEnd::SymbolKind symbolKind3, Utils::SmallStringView searchTerm) const { - ReadStatement &statement = m_statementFactory.selectSymbolsForKindAndStartsWith3; + auto &statement = m_statementFactory.selectSymbolsForKindAndStartsWith3; - return statement.template values(100, int(symbolKind1), int(symbolKind2), int(symbolKind3), searchTerm); + return statement.template values(100, + int(symbolKind1), + int(symbolKind2), + int(symbolKind3), + searchTerm); } Symbols symbols(const ClangBackEnd::SymbolKinds &symbolKinds, @@ -148,9 +150,9 @@ public: Utils::optional locationForSymbolId(SymbolId symbolId, ClangBackEnd::SourceLocationKind kind) const override { - ReadStatement &statement = m_statementFactory.selectLocationOfSymbol; + auto &statement = m_statementFactory.selectLocationOfSymbol; - return statement.template value(symbolId, int(kind)); + return statement.template value(symbolId, int(kind)); } private: StatementFactory &m_statementFactory; diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 27b2fe2c219..5866103df4b 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -1155,7 +1155,7 @@ void ClangTool::updateForCurrentState() const bool hasErrorText = !m_infoBarWidget->errorText().isEmpty(); const bool hasErrors = m_filesFailed > 0; if (hasErrors && !hasErrorText) { - const QString text = makeLink( tr("Failed to analyze %1 files.").arg(m_filesFailed)); + const QString text = makeLink(tr("Failed to analyze %n file(s).", nullptr, m_filesFailed)); m_infoBarWidget->setError(InfoBarWidget::Warning, text, [this]() { showOutputPane(); }); } @@ -1171,9 +1171,8 @@ void ClangTool::updateForCurrentState() if (m_filesCount == 0) { infoText = tr("Analyzing..."); // Not yet fully started/initialized } else { - infoText = tr("Analyzing... %1 of %2 files processed.") - .arg(m_filesSucceeded + m_filesFailed) - .arg(m_filesCount); + infoText = tr("Analyzing... %1 of %n file(s) processed.", nullptr, m_filesCount) + .arg(m_filesSucceeded + m_filesFailed); } break; case State::PreparationStarted: @@ -1186,7 +1185,7 @@ void ClangTool::updateForCurrentState() infoText = tr("Analysis stopped by user."); break; case State::AnalyzerFinished: - infoText = tr("Finished processing %1 files.").arg(m_filesCount); + infoText = tr("Finished processing %n file(s).", nullptr, m_filesCount); break; case State::ImportFinished: infoText = tr("Diagnostics imported."); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index bd4ee19758c..4a8cbcfbf4b 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -418,7 +418,7 @@ void ClangToolRunWorker::finalize() { const QString toolName = tool()->name(); if (m_filesNotAnalyzed.size() != 0) { - appendMessage(tr("Error: Failed to analyze %1 files.").arg(m_filesNotAnalyzed.size()), + appendMessage(tr("Error: Failed to analyze %n files.", nullptr, m_filesNotAnalyzed.size()), ErrorMessageFormat); Target *target = runControl()->target(); if (target && target->activeBuildConfiguration() && !target->activeBuildConfiguration()->buildDirectory().exists() diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 00011d1be9d..ce37566d5c1 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -891,6 +891,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) const Kit *k = target->kit(); QStringList initialArgs = defaultInitialCMakeArguments(k, info.typeName); + setIsMultiConfig(CMakeGeneratorKitAspect::isMultiConfigGenerator(k)); // Android magic: if (DeviceTypeKitAspect::deviceTypeId(k) == Android::Constants::ANDROID_DEVICE_TYPE) { @@ -1335,7 +1336,7 @@ QString CMakeBuildConfiguration::cmakeBuildType() const config = CMakeConfigItem::itemsFromArguments(initialCMakeArguments()); } - if (!config.isEmpty()) { + if (!config.isEmpty() && !isMultiConfig()) { cmakeBuildType = QString::fromUtf8(CMakeConfigItem::valueOf("CMAKE_BUILD_TYPE", config)); const_cast(this) ->setCMakeBuildType(cmakeBuildType); @@ -1356,7 +1357,12 @@ void CMakeBuildConfiguration::setCMakeBuildType(const QString &cmakeBuildType, b bool CMakeBuildConfiguration::isMultiConfig() const { - return m_buildSystem->isMultiConfig(); + return m_isMultiConfig; +} + +void CMakeBuildConfiguration::setIsMultiConfig(bool isMultiConfig) +{ + m_isMultiConfig = isMultiConfig; } namespace Internal { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 32ced5031ef..45519c77e3a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -78,6 +78,7 @@ public: void setCMakeBuildType(const QString &cmakeBuildType, bool quiet = false); bool isMultiConfig() const; + void setIsMultiConfig(bool isMultiConfig); signals: void errorOccurred(const QString &message); @@ -115,6 +116,7 @@ private: Internal::CMakeBuildSystem *m_buildSystem = nullptr; QStringList m_extraCMakeArguments; + bool m_isMultiConfig = false; friend class Internal::CMakeBuildSettingsWidget; friend class Internal::CMakeBuildSystem; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 18550fa3308..07fdd16f057 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -530,8 +530,6 @@ void CMakeBuildStep::recreateBuildTargetsModel() if (idx != -1) m_buildTargets[idx] = QString("INSTALL"); } - - targetList.sort(); targetList.removeDuplicates(); addItem(QString(), true); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index b1486ef2f29..17551819487 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -78,26 +78,31 @@ using namespace Utils; namespace CMakeProjectManager { namespace Internal { -static void copySourcePathToClipboard(Utils::optional srcPath, const ProjectNode *node) +static void copySourcePathsToClipboard(QStringList srcPaths, const ProjectNode *node) { QClipboard *clip = QGuiApplication::clipboard(); QDir projDir{node->filePath().toFileInfo().absoluteFilePath()}; - clip->setText(QDir::cleanPath(projDir.relativeFilePath(srcPath.value()))); + QString data = Utils::transform(srcPaths, [projDir](const QString &path) { + return QDir::cleanPath(projDir.relativeFilePath(path)); + }).join(" "); + clip->setText(data); } static void noAutoAdditionNotify(const QStringList &filePaths, const ProjectNode *node) { - Utils::optional srcPath{}; + const QStringList srcPaths = Utils::filtered(filePaths, [](const QString& file) { + const auto mimeType = Utils::mimeTypeForFile(file).name(); + return mimeType == CppTools::Constants::C_SOURCE_MIMETYPE || + mimeType == CppTools::Constants::C_HEADER_MIMETYPE || + mimeType == CppTools::Constants::CPP_SOURCE_MIMETYPE || + mimeType == CppTools::Constants::CPP_HEADER_MIMETYPE || + mimeType == ProjectExplorer::Constants::FORM_MIMETYPE || + mimeType == ProjectExplorer::Constants::RESOURCE_MIMETYPE || + mimeType == ProjectExplorer::Constants::SCXML_MIMETYPE; + }); - for (const QString &file : filePaths) { - if (Utils::mimeTypeForFile(file).name() == CppTools::Constants::CPP_SOURCE_MIMETYPE) { - srcPath = file; - break; - } - } - - if (srcPath) { + if (!srcPaths.empty()) { CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings(); switch (settings->afterAddFileSetting.value()) { case AskUser: { @@ -122,13 +127,13 @@ static void noAutoAdditionNotify(const QStringList &filePaths, const ProjectNode } if (QDialogButtonBox::Yes == reply) - copySourcePathToClipboard(srcPath, node); + copySourcePathsToClipboard(srcPaths, node); break; } case CopyFilePath: { - copySourcePathToClipboard(srcPath, node); + copySourcePathsToClipboard(srcPaths, node); break; } @@ -1063,7 +1068,11 @@ const QList CMakeBuildSystem::appTargets() const QStringList CMakeBuildSystem::buildTargetTitles() const { - return transform(m_buildTargets, &CMakeBuildTarget::title); + auto nonUtilityTargets = filtered(m_buildTargets, [this](const CMakeBuildTarget &target){ + return target.targetType != UtilityType || + CMakeBuildStep::specialTargets(usesAllCapsTargets()).contains(target.title); + }); + return transform(nonUtilityTargets, &CMakeBuildTarget::title); } const QList &CMakeBuildSystem::buildTargets() const diff --git a/src/plugins/conan/Conan.json.in b/src/plugins/conan/Conan.json.in index ac2cfcd52ef..4ee078c1c90 100644 --- a/src/plugins/conan/Conan.json.in +++ b/src/plugins/conan/Conan.json.in @@ -12,7 +12,6 @@ \"\", \"Alternatively, this plugin 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 plugin. 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.\" ], - \"Category\" : \"Utilities\", \"Experimental\" : true, \"Description\" : \"Conan integration.\", \"Url\" : \"http://www.qt.io\", diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 3d557cf7050..6b98b63bf9a 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -186,16 +186,10 @@ extend_qtc_plugin(Core SOURCES progressmanager/progressmanager_x11.cpp ) -if (CRASHPAD_BACKEND_URL - AND CRASHPAD_SRC - AND EXISTS "${CRASHPAD_SRC}" - AND CRASHPAD_BUILD - AND EXISTS "${CRASHPAD_BUILD}" - AND (WIN32 OR APPLE)) # LINUX isn't supported for now - extend_qtc_plugin(Core - DEFINES ENABLE_CRASHPAD - ) -endif() +extend_qtc_plugin(Core + CONDITION BUILD_WITH_CRASHPAD + DEFINES ENABLE_CRASHPAD +) if ((NOT WIN32) AND (NOT APPLE)) # install logo diff --git a/src/plugins/coreplugin/progressmanager/progressmanager_mac.mm b/src/plugins/coreplugin/progressmanager/progressmanager_mac.mm index 0541a8441a5..3cbd811dd22 100644 --- a/src/plugins/coreplugin/progressmanager/progressmanager_mac.mm +++ b/src/plugins/coreplugin/progressmanager/progressmanager_mac.mm @@ -91,9 +91,9 @@ static ApplicationProgressView *sharedProgressView = nil; Q_UNUSED(rect) NSRect boundary = [self bounds]; [[NSApp applicationIconImage] drawInRect:boundary - fromRect:NSZeroRect - operation:NSCompositeCopy - fraction:1.0]; + fromRect:NSZeroRect + operation:NSCompositingOperationCopy + fraction:1.0]; NSRect progressBoundary = boundary; progressBoundary.size.height *= 0.13; progressBoundary.size.width *= 0.8; diff --git a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui index ec419845a13..d0c047b9b68 100644 --- a/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui +++ b/src/plugins/cppeditor/cppquickfixprojectsettingswidget.ui @@ -10,9 +10,6 @@ 345 - - Form - diff --git a/src/plugins/cppeditor/cppquickfixsettingswidget.ui b/src/plugins/cppeditor/cppquickfixsettingswidget.ui index 41b68d8ba96..44ad80f9180 100644 --- a/src/plugins/cppeditor/cppquickfixsettingswidget.ui +++ b/src/plugins/cppeditor/cppquickfixsettingswidget.ui @@ -10,9 +10,6 @@ 1074 - - Form - diff --git a/src/plugins/cpptools/stringtable.cpp b/src/plugins/cpptools/stringtable.cpp index efd186fada9..5122c3a8a93 100644 --- a/src/plugins/cpptools/stringtable.cpp +++ b/src/plugins/cpptools/stringtable.cpp @@ -28,10 +28,10 @@ #include #include +#include #include #include #include -#include #include using namespace CppTools::Internal; @@ -139,10 +139,10 @@ void StringTablePrivate::GC() QMutexLocker locker(&m_lock); int initialSize = 0; - QTime startTime; + QElapsedTimer timer; if (DebugStringTable) { initialSize = m_strings.size(); - startTime = QTime::currentTime(); + timer.start(); } // Collect all QStrings which have refcount 1. (One reference in m_strings and nowhere else.) @@ -159,7 +159,6 @@ void StringTablePrivate::GC() if (DebugStringTable) { const int currentSize = m_strings.size(); qDebug() << "StringTable::GC removed" << initialSize - currentSize - << "strings in" << startTime.msecsTo(QTime::currentTime()) - << "ms, size is now" << currentSize; + << "strings in" << timer.elapsed() << "ms, size is now" << currentSize; } } diff --git a/src/plugins/help/litehtmlhelpviewer.cpp b/src/plugins/help/litehtmlhelpviewer.cpp index 44fda661076..c33ebf62ef5 100644 --- a/src/plugins/help/litehtmlhelpviewer.cpp +++ b/src/plugins/help/litehtmlhelpviewer.cpp @@ -66,6 +66,7 @@ LiteHtmlHelpViewer::LiteHtmlHelpViewer(QWidget *parent) , m_viewer(new QLiteHtmlWidget) { m_viewer->setResourceHandler([](const QUrl &url) { return getData(url); }); + m_viewer->setFrameStyle(QFrame::NoFrame); m_viewer->viewport()->installEventFilter(this); connect(m_viewer, &QLiteHtmlWidget::linkClicked, this, &LiteHtmlHelpViewer::setSource); connect(m_viewer, diff --git a/src/plugins/help/textbrowserhelpviewer.cpp b/src/plugins/help/textbrowserhelpviewer.cpp index e5188c1d25b..fd6c36c4d4a 100644 --- a/src/plugins/help/textbrowserhelpviewer.cpp +++ b/src/plugins/help/textbrowserhelpviewer.cpp @@ -267,6 +267,7 @@ TextBrowserHelpWidget::TextBrowserHelpWidget(TextBrowserHelpViewer *parent) : QTextBrowser(parent) , m_parent(parent) { + setFrameShape(QFrame::NoFrame); installEventFilter(this); document()->setDocumentMargin(8); } diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 2f322a660a0..74d6e2f485c 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -247,7 +247,7 @@ void CompileOutputWindow::registerPositionOf(const Task &task, int linkedOutputL if (linkedOutputLines <= 0) return; - const int blocknumber = m_outputWindow->document()->blockCount() - offset - 1; + const int blocknumber = m_outputWindow->document()->blockCount() - offset; const int firstLine = blocknumber - linkedOutputLines - skipLines; const int lastLine = firstLine + linkedOutputLines - 1; diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index b6767eefcae..4f245ad5a56 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -431,9 +431,7 @@ RunConfigurationFactory::~RunConfigurationFactory() QString RunConfigurationFactory::decoratedTargetName(const QString &targetName, Target *target) { - QString displayName; - if (!targetName.isEmpty()) - displayName = QFileInfo(targetName).completeBaseName(); + QString displayName = targetName; Utils::Id devType = DeviceTypeKitAspect::deviceTypeId(target->kit()); if (devType != Constants::DESKTOP_DEVICE_TYPE) { if (IDevice::ConstPtr dev = DeviceKitAspect::device(target->kit())) { diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 34ab71154fb..2b26ad383f3 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -31,6 +31,7 @@ add_qtc_plugin(QmlDesigner shortcutmanager.cpp shortcutmanager.h designermcumanager.cpp designermcumanager.h richtexteditordialog.cpp richtexteditordialog.h + editorproxy.cpp editorproxy.h EXPLICIT_MOC components/propertyeditor/propertyeditorvalue.h components/connectioneditor/connectionviewwidget.h @@ -637,6 +638,10 @@ extend_qtc_plugin(QmlDesigner globalannotationeditordialog.cpp globalannotationeditordialog.h globalannotationeditordialog.ui annotationeditor.cpp annotationeditor.h globalannotationeditor.cpp globalannotationeditor.h + defaultannotations.cpp defaultannotations.h + annotationtableview.cpp annotationtableview.h + annotationtabwidget.cpp annotationtabwidget.h + annotationeditor.qrc ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp index 49d16cb393b..d9e9ace498f 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp @@ -34,6 +34,8 @@ #include +#include + namespace { const QHash AlignMapping{ {"AlignRight", "RIGHT"}, @@ -63,7 +65,10 @@ TextNodeDumper::TextNodeDumper(const QByteArrayList &lineage, const ModelNode &n bool TextNodeDumper::isExportable() const { - return lineage().contains("QtQuick.Text"); + const QByteArrayList &baseClasses = lineage(); + return std::any_of(baseClasses.cbegin(), baseClasses.cend(), [](const QByteArray &type) { + return type == "QtQuick.Text" || type == "QtQuick.Controls.Label"; + }); } QJsonObject TextNodeDumper::json(Component &component) const diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp index b8323bb80d2..9a930747215 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp @@ -24,12 +24,12 @@ ****************************************************************************/ #include "annotationcommenttab.h" +#include "defaultannotations.h" #include "ui_annotationcommenttab.h" #include "richtexteditor/richtexteditor.h" #include -#include "QStringListModel" #include "projectexplorer/session.h" #include "projectexplorer/target.h" @@ -40,7 +40,7 @@ namespace QmlDesigner { AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) : QWidget(parent) - , ui(new Ui::AnnotationCommentTab) + , ui(std::make_unique()) { ui->setupUi(this); @@ -57,33 +57,12 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) ui->formLayout->setWidget(3, QFormLayout::FieldRole, m_editor); - ui->titleEdit->setModel(new QStringListModel{QStringList{"Description", - "Display Condition", - "helper lines", - "position marker", - "highlight", - "project author", - "project confirmed", - "project developer", - "project distributor", - "project modified", - "project type", - "project version", - "Screen Description", - "Section", - "normalcolor", - "focuscolor", - "selectedcolor", - "pressedcolor"}}); - - connect(ui->titleEdit, &QComboBox::currentTextChanged, - this, &AnnotationCommentTab::commentTitleChanged); + connect(ui->titleEdit, &QComboBox::currentTextChanged, this, [this](QString const &text) { + emit titleChanged(text, this); + }); } -AnnotationCommentTab::~AnnotationCommentTab() -{ - delete ui; -} +AnnotationCommentTab::~AnnotationCommentTab() {} Comment AnnotationCommentTab::currentComment() const { @@ -91,7 +70,10 @@ Comment AnnotationCommentTab::currentComment() const result.setTitle(ui->titleEdit->currentText().trimmed()); result.setAuthor(ui->authorEdit->text().trimmed()); - result.setText(m_editor->richText().trimmed()); + if (defaultAnnotations() && !defaultAnnotations()->isRichText(result)) { + result.setText(m_editor->plainText().trimmed()); + } else + result.setText(m_editor->richText().trimmed()); if (m_comment.sameContent(result)) result.setTimestamp(m_comment.timestamp()); @@ -129,9 +111,15 @@ void AnnotationCommentTab::resetComment() m_comment = currentComment(); } -void AnnotationCommentTab::commentTitleChanged(const QString &text) +DefaultAnnotationsModel *AnnotationCommentTab::defaultAnnotations() const { - emit titleChanged(text, this); + return m_defaults; +} + +void AnnotationCommentTab::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + ui->titleEdit->setModel(m_defaults); } QString AnnotationCommentTab::backupFile(const QString &filePath) @@ -153,10 +141,8 @@ QString AnnotationCommentTab::backupFile(const QString &filePath) if (!newFile.exists()) { QFile(oldFile.absoluteFilePath()).copy(newFile.absoluteFilePath()); break; - } else if (compareFileChecksum(oldFile.absoluteFilePath(), - newFile.absoluteFilePath()) == 0) { + } else if (compareFileChecksum(oldFile.absoluteFilePath(), newFile.absoluteFilePath()) == 0) break; - } newFile.setFile(imgDir, newName.arg(i)); } @@ -166,9 +152,8 @@ QString AnnotationCommentTab::backupFile(const QString &filePath) void AnnotationCommentTab::ensureDir(const QDir &dir) { - if (!dir.exists()) { + if (!dir.exists()) dir.mkdir("."); - } } int AnnotationCommentTab::compareFileChecksum(const QString &firstFile, const QString &secondFile) diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h index 6fc647669d3..beb2e4c3774 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.h @@ -25,10 +25,13 @@ #pragma once -#include - #include "annotation.h" +#include +#include + +#include + QT_BEGIN_NAMESPACE class QDir; QT_END_NAMESPACE @@ -40,6 +43,7 @@ class AnnotationCommentTab; } class RichTextEditor; +class DefaultAnnotationsModel; class AnnotationCommentTab : public QWidget { @@ -57,17 +61,18 @@ public: void resetUI(); void resetComment(); + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + signals: void titleChanged(const QString &text, QWidget *widget); -private slots: - void commentTitleChanged(const QString &text); - private: - Ui::AnnotationCommentTab *ui; + std::unique_ptr ui; RichTextEditor *m_editor; Comment m_comment; + QPointer m_defaults; QString backupFile(const QString &filePath); void ensureDir(const QDir &dir); diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp index efdc727d754..448aa3c46e5 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.cpp @@ -25,8 +25,8 @@ #include "annotationeditor.h" -#include "annotationeditordialog.h" #include "annotation.h" +#include "annotationeditordialog.h" #include "qmlmodelnodeproxy.h" @@ -35,166 +35,79 @@ #include -#include -#include #include #include +#include +#include namespace QmlDesigner { AnnotationEditor::AnnotationEditor(QObject *parent) - : QObject(parent) -{ -} + : ModelNodeEditorProxy(parent) +{} -AnnotationEditor::~AnnotationEditor() +AnnotationEditor::~AnnotationEditor() {} + +QWidget *AnnotationEditor::createWidget() { - hideWidget(); + const auto &node = m_modelNode; + auto dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(), + node.id(), + node.customId()); + dialog->setAnnotation(node.annotation()); + + QObject::connect(dialog, + &AnnotationEditorDialog::acceptedDialog, + this, + &AnnotationEditor::acceptedClicked); + QObject::connect(dialog, + &AnnotationEditorDialog::rejected, + this, + &AnnotationEditor::cancelClicked); + return dialog; } void AnnotationEditor::registerDeclarativeType() { - qmlRegisterType("HelperWidgets", 2, 0, "AnnotationEditor"); -} - -void AnnotationEditor::showWidget() -{ - m_dialog = new AnnotationEditorDialog(Core::ICore::dialogParent(), - m_modelNode.id(), - m_modelNode.customId(), - m_modelNode.annotation()); - - QObject::connect(m_dialog, &AnnotationEditorDialog::acceptedDialog, - this, &AnnotationEditor::acceptedClicked); - QObject::connect(m_dialog, &AnnotationEditorDialog::rejected, - this, &AnnotationEditor::cancelClicked); - - m_dialog->setAttribute(Qt::WA_DeleteOnClose); - - m_dialog->show(); - m_dialog->raise(); -} - -void AnnotationEditor::showWidget(int x, int y) -{ - showWidget(); - m_dialog->move(x, y); -} - -void AnnotationEditor::hideWidget() -{ - if (m_dialog) - m_dialog->close(); - m_dialog = nullptr; -} - -AnnotationEditor* AnnotationEditor::showWidget(const ModelNode &modelNode) -{ - auto editor = new AnnotationEditor; - - editor->setModelNode(modelNode); - editor->showWidget(); - - connect(editor->m_dialog, &QDialog::destroyed, - [editor]() { editor->deleteLater(); } ); - - return editor; -} - -void AnnotationEditor::setModelNode(const ModelNode &modelNode) -{ - m_modelNodeBackend = {}; - m_modelNode = modelNode; -} - -ModelNode AnnotationEditor::modelNode() const -{ - return m_modelNode; -} - -void AnnotationEditor::setModelNodeBackend(const QVariant &modelNodeBackend) -{ - if (!modelNodeBackend.isNull() && modelNodeBackend.isValid()) { - m_modelNodeBackend = modelNodeBackend; - - const auto modelNodeBackendObject = modelNodeBackend.value(); - const auto backendObjectCasted = - qobject_cast(modelNodeBackendObject); - - if (backendObjectCasted) - m_modelNode = backendObjectCasted->qmlObjectNode().modelNode(); - - emit modelNodeBackendChanged(); - } -} - -QVariant AnnotationEditor::modelNodeBackend() const -{ - return m_modelNodeBackend; -} - -bool AnnotationEditor::hasCustomId() const -{ - if (m_modelNode.isValid()) - return m_modelNode.hasCustomId(); - return false; -} - -bool AnnotationEditor::hasAnnotation() const -{ - if (m_modelNode.isValid()) - return m_modelNode.hasAnnotation(); - return false; + registerType("AnnotationEditor"); } void AnnotationEditor::removeFullAnnotation() { - if (!m_modelNode.isValid()) + auto &node = this->m_modelNode; + if (!node.isValid()) return; - QString dialogTitle = tr("Annotation"); - if (!m_modelNode.customId().isNull()) { - dialogTitle = m_modelNode.customId(); + if (QMessageBox::question(Core::ICore::dialogParent(), + node.customId().isNull() ? tr("Annotation") : node.customId(), + tr("Delete this annotation?")) + == QMessageBox::Yes) { + node.removeCustomId(); + node.removeAnnotation(); + emit customIdChanged(); + emit annotationChanged(); } - QPointer deleteDialog = new QMessageBox(Core::ICore::dialogParent()); - deleteDialog->setWindowTitle(dialogTitle); - deleteDialog->setText(tr("Delete this annotation?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); - - int result = deleteDialog->exec(); - - if (deleteDialog) - deleteDialog->deleteLater(); - - if (result == QMessageBox::Yes) { - m_modelNode.removeCustomId(); - m_modelNode.removeAnnotation(); - } - - emit customIdChanged(); - emit annotationChanged(); } void AnnotationEditor::acceptedClicked() { - if (m_dialog) { + if (const auto *dialog = qobject_cast(widget())) { QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_ANNOTATION_ADDED); - QString customId = m_dialog->customId(); - Annotation annotation = m_dialog->annotation(); + const QString customId = dialog->customId(); + const Annotation annotation = dialog->annotation(); + auto &node = this->m_modelNode; - m_modelNode.setCustomId(customId); + node.setCustomId(customId); if (annotation.comments().isEmpty()) - m_modelNode.removeAnnotation(); + node.removeAnnotation(); else - m_modelNode.setAnnotation(annotation); + node.setAnnotation(annotation); } hideWidget(); emit accepted(); - emit customIdChanged(); emit annotationChanged(); } diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.h b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.h index 75fce6afe2b..3ebfd2d28b5 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.h @@ -25,65 +25,31 @@ #pragma once -#include #include -#include -#include "annotationeditordialog.h" -#include "annotation.h" - -#include "modelnode.h" +#include "editorproxy.h" namespace QmlDesigner { -class AnnotationEditor : public QObject +class AnnotationEditor : public ModelNodeEditorProxy { Q_OBJECT - - Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) - Q_PROPERTY(bool hasCustomId READ hasCustomId NOTIFY customIdChanged) - Q_PROPERTY(bool hasAnnotation READ hasAnnotation NOTIFY annotationChanged) - public: explicit AnnotationEditor(QObject *parent = nullptr); ~AnnotationEditor(); - static void registerDeclarativeType(); - - Q_INVOKABLE void showWidget(); - Q_INVOKABLE void showWidget(int x, int y); - Q_INVOKABLE void hideWidget(); - - static AnnotationEditor* showWidget(const ModelNode &modelNode); - - void setModelNode(const ModelNode &modelNode); - ModelNode modelNode() const; - - void setModelNodeBackend(const QVariant &modelNodeBackend); - QVariant modelNodeBackend() const; - - Q_INVOKABLE bool hasCustomId() const; - Q_INVOKABLE bool hasAnnotation() const; - + QWidget *createWidget() override; Q_INVOKABLE void removeFullAnnotation(); + static void registerDeclarativeType(); + signals: void accepted(); void canceled(); - void modelNodeBackendChanged(); - - void customIdChanged(); - void annotationChanged(); private slots: void acceptedClicked(); void cancelClicked(); - -private: - QPointer m_dialog; - - ModelNode m_modelNode; - QVariant m_modelNodeBackend; }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri index b1773c2dcf6..63ba86609b5 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.pri @@ -3,13 +3,23 @@ HEADERS += $$PWD/annotationeditordialog.h HEADERS += $$PWD/annotationeditor.h HEADERS += $$PWD/globalannotationeditor.h HEADERS += $$PWD/globalannotationeditordialog.h +HEADERS += $$PWD/defaultannotations.h +HEADERS += $$PWD/annotationtableview.h +HEADERS += $$PWD/annotationtabwidget.h SOURCES += $$PWD/annotationcommenttab.cpp SOURCES += $$PWD/annotationeditordialog.cpp SOURCES += $$PWD/annotationeditor.cpp SOURCES += $$PWD/globalannotationeditor.cpp SOURCES += $$PWD/globalannotationeditordialog.cpp +SOURCES += $$PWD/defaultannotations.cpp +SOURCES += $$PWD/annotationtableview.cpp +SOURCES += $$PWD/annotationtabwidget.cpp FORMS += $$PWD/annotationcommenttab.ui FORMS += $$PWD/annotationeditordialog.ui FORMS += $$PWD/globalannotationeditordialog.ui + +INCLUDEPATH += $$PWD + +RESOURCES += $$PWD/annotationeditor.qrc diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc new file mode 100644 index 00000000000..5ccf08a77fa --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditor.qrc @@ -0,0 +1,5 @@ + + + defaultannotations.json + + diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp index 29b1dc5a8b8..32695404665 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.cpp @@ -24,80 +24,65 @@ ****************************************************************************/ #include "annotationeditordialog.h" -#include "ui_annotationeditordialog.h" #include "annotation.h" #include "annotationcommenttab.h" +#include "defaultannotations.h" -#include "ui_annotationcommenttab.h" +#include "ui_annotationeditordialog.h" #include #include -#include -#include #include #include +#include +#include namespace QmlDesigner { - -AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation) +BasicAnnotationEditorDialog::BasicAnnotationEditorDialog(QWidget *parent) : QDialog(parent) - , ui(new Ui::AnnotationEditorDialog) - , m_customId(customId) - , m_annotation(annotation) + , m_defaults(std::make_unique()) { - ui->setupUi(this); - setWindowFlag(Qt::Tool, true); setModal(true); + loadDefaultAnnotations(DefaultAnnotationsModel::defaultJsonFilePath()); - connect(this, &QDialog::accepted, this, &AnnotationEditorDialog::acceptedClicked); + connect(this, &QDialog::accepted, this, &BasicAnnotationEditorDialog::acceptedClicked); +} - connect(ui->tabWidget, &QTabWidget::currentChanged, this, &AnnotationEditorDialog::tabChanged); +BasicAnnotationEditorDialog::~BasicAnnotationEditorDialog() {} - auto *commentCornerWidget = new QToolBar; +Annotation const &BasicAnnotationEditorDialog::annotation() const +{ + return m_annotation; +} - auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), tr("Add Comment")); //timeline icons? - auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), - tr("Remove Comment")); //timeline icons? +void BasicAnnotationEditorDialog::setAnnotation(const Annotation &annotation) +{ + m_annotation = annotation; + fillFields(); +} - connect(commentAddAction, &QAction::triggered, this, [this]() { - addComment(Comment()); - }); +void BasicAnnotationEditorDialog::loadDefaultAnnotations(QString const &filename) +{ + m_defaults->loadFromFile(filename); +} - connect(commentRemoveAction, &QAction::triggered, this, [this]() { +DefaultAnnotationsModel *BasicAnnotationEditorDialog::defaultAnnotations() const +{ + return m_defaults.get(); +} - if (ui->tabWidget->count() == 0) { //it is not even supposed to happen but lets be sure - QTC_ASSERT(true, return); - return; - } - - int currentIndex = ui->tabWidget->currentIndex(); - QString currentTitle = ui->tabWidget->tabText(currentIndex); - - QMessageBox *deleteDialog = new QMessageBox(this); - deleteDialog->setWindowTitle(currentTitle); - deleteDialog->setText(tr("Delete this comment?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); - - int result = deleteDialog->exec(); - - if (result == QMessageBox::Yes) { - removeComment(currentIndex); - } - - if (ui->tabWidget->count() == 0) //lets be sure that tabWidget is never empty - addComment(Comment()); - }); - - commentCornerWidget->addAction(commentAddAction); - commentCornerWidget->addAction(commentRemoveAction); - - ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); +AnnotationEditorDialog::AnnotationEditorDialog(QWidget *parent, + const QString &targetId, + const QString &customId) + : BasicAnnotationEditorDialog(parent) + , ui(new Ui::AnnotationEditorDialog) + , m_customId(customId) +{ + ui->setupUi(this); ui->targetIdEdit->setText(targetId); - fillFields(); setWindowTitle(annotationEditorTitle); } @@ -106,17 +91,6 @@ AnnotationEditorDialog::~AnnotationEditorDialog() delete ui; } -void AnnotationEditorDialog::setAnnotation(const Annotation &annotation) -{ - m_annotation = annotation; - fillFields(); -} - -Annotation AnnotationEditorDialog::annotation() const -{ - return m_annotation; -} - void AnnotationEditorDialog::setCustomId(const QString &customId) { m_customId = customId; @@ -130,117 +104,34 @@ QString AnnotationEditorDialog::customId() const void AnnotationEditorDialog::acceptedClicked() { - m_customId = ui->customIdEdit->text(); - - Annotation annotation; - - annotation.removeComments(); - - for (int i = 0; i < ui->tabWidget->count(); i++) { - AnnotationCommentTab* tab = reinterpret_cast(ui->tabWidget->widget(i)); - if (!tab) - continue; - - Comment comment = tab->currentComment(); - - if (!comment.isEmpty()) - annotation.addComment(comment); - } - - m_annotation = annotation; - + updateAnnotation(); emit AnnotationEditorDialog::acceptedDialog(); } -void AnnotationEditorDialog::commentTitleChanged(const QString &text, QWidget *tab) -{ - int tabIndex = ui->tabWidget->indexOf(tab); - if (tabIndex >= 0) - ui->tabWidget->setTabText(tabIndex, text); - - if (text.isEmpty()) - ui->tabWidget->setTabText(tabIndex, - (defaultTabName + " " + QString::number(tabIndex+1))); -} - void AnnotationEditorDialog::fillFields() { ui->customIdEdit->setText(m_customId); - setupComments(); + ui->tabWidget->setupComments(m_annotation.comments()); } -void AnnotationEditorDialog::setupComments() +void AnnotationEditorDialog::updateAnnotation() { - ui->tabWidget->setUpdatesEnabled(false); - - deleteAllTabs(); - - const QVector comments = m_annotation.comments(); - - if (comments.isEmpty()) - addComment(Comment()); - - for (const Comment &comment : comments) { - addCommentTab(comment); - } - - ui->tabWidget->setUpdatesEnabled(true); + m_customId = ui->customIdEdit->text(); + Annotation annotation; + annotation.setComments(ui->tabWidget->fetchComments()); + m_annotation = annotation; } void AnnotationEditorDialog::addComment(const Comment &comment) { m_annotation.addComment(comment); - addCommentTab(comment); + ui->tabWidget->addCommentTab(comment); } void AnnotationEditorDialog::removeComment(int index) { - if ((m_annotation.commentsSize() > index) && (index >= 0)) { - m_annotation.removeComment(index); - removeCommentTab(index); - } -} - -void AnnotationEditorDialog::addCommentTab(const Comment &comment) -{ - auto commentTab = new AnnotationCommentTab(); - commentTab->setComment(comment); - - QString tabTitle(comment.title()); - int tabIndex = ui->tabWidget->addTab(commentTab, tabTitle); - ui->tabWidget->setCurrentIndex(tabIndex); - - if (tabTitle.isEmpty()) { - const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex+1) : ""); - - tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); - - ui->tabWidget->setTabText(tabIndex, tabTitle); - } - - connect(commentTab, &AnnotationCommentTab::titleChanged, - this, &AnnotationEditorDialog::commentTitleChanged); -} - -void AnnotationEditorDialog::removeCommentTab(int index) -{ - if ((ui->tabWidget->count() > index) && (index >= 0)) { - ui->tabWidget->removeTab(index); - } -} - -void AnnotationEditorDialog::deleteAllTabs() -{ - while (ui->tabWidget->count() > 0) { - QWidget *w = ui->tabWidget->widget(0); - ui->tabWidget->removeTab(0); - delete w; - } -} - -void AnnotationEditorDialog::tabChanged(int index) -{ - (void) index; + m_annotation.removeComment(index); + ui->tabWidget->removeTab(index); } } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h index bc304c9ddd3..856eb9bb605 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.h @@ -34,46 +34,62 @@ namespace QmlDesigner { namespace Ui { class AnnotationEditorDialog; } +class DefaultAnnotationsModel; -class AnnotationEditorDialog : public QDialog +class BasicAnnotationEditorDialog : public QDialog { Q_OBJECT - public: - explicit AnnotationEditorDialog(QWidget *parent, const QString &targetId, const QString &customId, const Annotation &annotation); - ~AnnotationEditorDialog(); + explicit BasicAnnotationEditorDialog(QWidget *parent); + ~BasicAnnotationEditorDialog(); + Annotation const &annotation() const; void setAnnotation(const Annotation &annotation); - Annotation annotation() const; - void setCustomId(const QString &customId); - QString customId() const; + void loadDefaultAnnotations(QString const &filename); + + DefaultAnnotationsModel *defaultAnnotations() const; signals: void acceptedDialog(); //use instead of QDialog::accepted +protected: + virtual void fillFields() = 0; + virtual void acceptedClicked() = 0; + + Annotation m_annotation; + std::unique_ptr m_defaults; +}; + +class AnnotationEditorDialog : public BasicAnnotationEditorDialog +{ + Q_OBJECT + +public: + explicit AnnotationEditorDialog(QWidget *parent, + const QString &targetId, + const QString &customId); + ~AnnotationEditorDialog(); + + void setCustomId(const QString &customId); + QString customId() const; + private slots: - void acceptedClicked(); - void tabChanged(int index); - void commentTitleChanged(const QString &text, QWidget *tab); + void acceptedClicked() override; private: - void fillFields(); - void setupComments(); + void fillFields() override; + void updateAnnotation(); + void addComment(const Comment &comment); void removeComment(int index); - void addCommentTab(const Comment &comment); - void removeCommentTab(int index); - void deleteAllTabs(); - private: const QString annotationEditorTitle = {tr("Annotation Editor")}; - const QString defaultTabName = {tr("Annotation")}; + Ui::AnnotationEditorDialog *ui; QString m_customId; - Annotation m_annotation; }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui index 92dc5c71d50..5dd747a7dc6 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationeditordialog.ui @@ -56,7 +56,7 @@ - + 0 @@ -90,6 +90,14 @@ + + + AnnotationTabWidget + QTabWidget +
annotationtabwidget.h
+ 1 +
+
targetIdEdit customIdEdit diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp new file mode 100644 index 00000000000..8e289a344c9 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "annotationtableview.h" + +#include "defaultannotations.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +struct ColumnId +{ + enum Column { + Title = 0, + Author = 1, + Value = 2, + }; +}; + +CommentDelegate::CommentDelegate(QObject *parent) + : QItemDelegate(parent) + , m_completer(std::make_unique()) +{} + +CommentDelegate::~CommentDelegate() {} + +DefaultAnnotationsModel *CommentDelegate::defaultAnnotations() const +{ + return m_defaults; +} + +void CommentDelegate::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + m_completer->setModel(m_defaults); +} + +QCompleter *CommentDelegate::completer() const +{ + return m_completer.get(); +} + +void CommentDelegate::updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + editor->setGeometry(option.rect); +} + +Comment CommentDelegate::comment(QModelIndex const &index) +{ + auto *model = index.model(); + return model->data(model->index(index.row(), ColumnId::Title), CommentRole).value(); +} + +CommentTitleDelegate::CommentTitleDelegate(QObject *parent) + : CommentDelegate(parent) +{} + +CommentTitleDelegate::~CommentTitleDelegate() {} + +QWidget *CommentTitleDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + auto *editor = new QComboBox(parent); + editor->setEditable(true); + editor->setCompleter(completer()); + editor->setFrame(false); + editor->setFocusPolicy(Qt::StrongFocus); + + return editor; +} + +void CommentTitleDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QString text = index.model()->data(index, Qt::DisplayRole).toString(); + auto *comboBox = qobject_cast(editor); + comboBox->setModel(defaultAnnotations()); + comboBox->setCurrentText(text); +} + +void CommentTitleDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + auto *comboBox = qobject_cast(editor); + auto oldText = model->data(index, Qt::EditRole).toString(); + auto newText = comboBox->currentText(); + + if (oldText != newText) { + model->setData(index, comboBox->currentText(), Qt::EditRole); + auto comment = model->data(index, CommentRole).value(); + comment.setTitle(newText); + model->setData(index, QVariant::fromValue(comment), CommentRole); + + // Set default value to data item + auto colIdx = model->index(index.row(), ColumnId::Value); + if (defaultAnnotations()->hasDefault(comment)) + model->setData(colIdx, defaultAnnotations()->defaultValue(comment), Qt::DisplayRole); + else + // Reset to rich text when there is no default item + model->setData(colIdx, + QVariant::fromValue({comment.text()}), + Qt::DisplayRole); + } +} + +CommentValueDelegate::CommentValueDelegate(QObject *parent) + : CommentDelegate(parent) +{} + +CommentValueDelegate::~CommentValueDelegate() {} + +void CommentValueDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + auto data = index.model()->data(index, Qt::DisplayRole); + if (data.userType() == qMetaTypeId()) + drawDisplay(painter, option, option.rect, data.value().plainText()); + else if (data.userType() == QMetaType::QColor) + painter->fillRect(option.rect, data.value()); + else + QItemDelegate::paint(painter, option, index); +} + +void CommentValueDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + auto data = index.model()->data(index, Qt::DisplayRole); + if (data.userType() == qMetaTypeId()) { + auto richText = data.value(); + auto *e = qobject_cast(editor); + e->setText(richText.plainText()); + e->setupSignal(index.row(), comment(index).title()); + connect(e, + &RichTextCellEditor::richTextClicked, + this, + &CommentValueDelegate::richTextEditorRequested, + Qt::UniqueConnection); + } else if (data.userType() == QMetaType::QString) { + auto *e = qobject_cast(editor); + e->setText(data.toString()); + } else if (data.userType() == QMetaType::QColor) { + auto *e = qobject_cast(editor); + e->setColor(data.value()); + } else + QItemDelegate::setEditorData(editor, index); +} + +void CommentValueDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const +{ + auto data = model->data(index, Qt::EditRole); + if (data.userType() == qMetaTypeId()) + return; + else if (data.userType() == QMetaType::QColor) + model->setData(index, + qobject_cast(editor)->color(), + Qt::DisplayRole); + else if (data.userType() == QMetaType::QString) + model->setData(index, qobject_cast(editor)->text(), Qt::DisplayRole); + else + QItemDelegate::setModelData(editor, model, index); +} + +RichTextCellEditor::RichTextCellEditor(QWidget *parent) + : QLabel(parent) +{} + +RichTextCellEditor::~RichTextCellEditor() {} + +RichTextProxy RichTextCellEditor::richText() const +{ + return m_richText; +} + +void RichTextCellEditor::setRichText(const RichTextProxy &richText) +{ + if (richText.text == m_richText.text) + return; + + m_richText = richText; + setText(richText.plainText()); + + emit richTextChanged(); +} + +void RichTextCellEditor::setupSignal(int index, const QString &commentTitle) +{ + if (m_connection) + disconnect(m_connection); + + m_connection = connect(this, &RichTextCellEditor::clicked, this, [=]() { + emit richTextClicked(index, commentTitle); + }); +} + +void RichTextCellEditor::mouseReleaseEvent(QMouseEvent *) +{ + emit clicked(); +} + +AnnotationTableView::AnnotationTableView(QWidget *parent) + : QTableView(parent) + , m_model(std::make_unique()) + , m_editorFactory(std::make_unique()) +{ + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::ContiguousSelection); + + setModel(m_model.get()); + connect(m_model.get(), &QStandardItemModel::itemChanged, this, [this](QStandardItem *item) { + if (item->isCheckable()) + m_model->setData(item->index(), item->checkState() == Qt::Checked); + + if (this->m_modelUpdating) + return; + + auto *valueItem = m_model->item(item->row(), ColumnId::Value); + + // When comment title was edited, make value item editable + if (item->column() == ColumnId::Title && valueItem) { + valueItem->setEditable(!item->text().isEmpty()); + valueItem->setCheckable(valueItem->data(Qt::DisplayRole).userType() == QMetaType::Bool); + } + + m_modelUpdating = true; + if (!rowIsEmpty(m_model->rowCount() - 1)) + addEmptyRow(); + m_modelUpdating = false; + }); + + horizontalHeader()->setStretchLastSection(true); + horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive); + + m_editorFactory->registerEditor(qMetaTypeId(), + new QItemEditorCreator("richText")); + m_editorFactory->registerEditor(QMetaType::QColor, + new QItemEditorCreator("color")); + + m_valueDelegate.setItemEditorFactory(m_editorFactory.get()); + connect(&m_valueDelegate, + &CommentValueDelegate::richTextEditorRequested, + this, + &AnnotationTableView::richTextEditorRequested); + + verticalHeader()->hide(); +} + +AnnotationTableView::~AnnotationTableView() {} + +QVector AnnotationTableView::fetchComments() const +{ + QVector comments; + + for (int i = 0; i < m_model->rowCount(); ++i) { + Comment comment = fetchComment(i); + if (!comment.isEmpty()) + comments.push_back(comment); + } + + return comments; +} + +Comment AnnotationTableView::fetchComment(int row) const +{ + auto *item = m_model->item(row, ColumnId::Title); + if (item->text().isEmpty()) + return {}; + + Comment comment = item->data().value(); + comment.setTitle(item->text()); + comment.setAuthor(m_model->item(row, ColumnId::Author)->text()); + comment.setText(dataToCommentText(m_model->item(row, ColumnId::Value)->data(Qt::DisplayRole))); + return comment; +} + +void AnnotationTableView::setupComments(QVector const &comments) +{ + m_model->clear(); + m_modelUpdating = true; + m_model->setColumnCount(3); + m_model->setHeaderData(ColumnId::Title, Qt::Horizontal, tr("Title")); + m_model->setHeaderData(ColumnId::Author, Qt::Horizontal, tr("Author")); + m_model->setHeaderData(ColumnId::Value, Qt::Horizontal, tr("Value")); + setItemDelegateForColumn(ColumnId::Title, &m_titleDelegate); + setItemDelegateForColumn(ColumnId::Value, &m_valueDelegate); + + for (auto &comment : comments) { + if (comment.isEmpty()) + continue; + + addEmptyRow(); + changeRow(m_model->rowCount() - 1, comment); + } + + addEmptyRow(); + m_modelUpdating = false; +} + +DefaultAnnotationsModel *AnnotationTableView::defaultAnnotations() const +{ + return m_defaults; +} + +void AnnotationTableView::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + m_titleDelegate.setDefaultAnnotations(defaults); + m_valueDelegate.setDefaultAnnotations(defaults); +} + +void AnnotationTableView::changeRow(int index, Comment const &comment) +{ + auto *titleItem = m_model->item(index, ColumnId::Title); + auto *authorItem = m_model->item(index, ColumnId::Author); + auto *textItem = m_model->item(index, ColumnId::Value); + + titleItem->setText(comment.title()); + titleItem->setData(QVariant::fromValue(comment)); + + authorItem->setText(comment.author()); + + QVariant data = commentToData(comment, + m_defaults ? m_defaults->defaultType(comment) + : QMetaType::UnknownType); + + textItem->setEditable(data.isValid()); + textItem->setCheckable(data.userType() == QMetaType::Bool); + textItem->setData(data, Qt::DisplayRole); +} + +void AnnotationTableView::removeRow(int index) +{ + m_model->removeRow(index); +} + +void AnnotationTableView::removeSelectedRows() +{ + const auto selRows = selectionModel()->selectedRows(); + for (auto it = selRows.rbegin(); it != selRows.rend(); ++it) + removeRow(it->row()); +} + +void AnnotationTableView::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Delete) + removeSelectedRows(); +} + +void AnnotationTableView::addEmptyRow() +{ + auto *valueItem = new QStandardItem; + valueItem->setEditable(false); + m_model->appendRow({new QStandardItem, new QStandardItem, valueItem}); +} + +bool AnnotationTableView::rowIsEmpty(int row) const +{ + auto itemText = [&](int col) { + return m_model->item(row, col) ? m_model->item(row, col)->text() : QString(); + }; + + return QString(itemText(0) + itemText(1) + itemText(2)).isEmpty(); +} + +QString AnnotationTableView::dataToCommentText(QVariant const &data) +{ + auto type = data.userType(); + if (type == qMetaTypeId()) + return data.value().text; + + switch (type) { + case QMetaType::QColor: + return data.value().name(); + case QMetaType::Bool: + return data.toBool() ? QStringLiteral("true") : QStringLiteral("false"); + case QMetaType::QString: + return data.toString(); + } + + return {}; +} + +QVariant AnnotationTableView::commentToData(Comment const& comment, QMetaType::Type type) +{ + switch (type) { + case QMetaType::Bool: + return QVariant::fromValue(comment.deescapedText().toLower().trimmed() == "true"); + case QMetaType::QColor: + return QVariant::fromValue(QColor(comment.deescapedText().toLower().trimmed())); + break; + case QMetaType::QString: + return QVariant::fromValue(comment.text()); + break; + default: + if (type == qMetaTypeId() || type == QMetaType::UnknownType) + return QVariant::fromValue({comment.text()}); + } + return {}; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h new file mode 100644 index 00000000000..6bc6e96c77b --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtableview.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "annotation.h" +#include "defaultannotations.h" + +QT_BEGIN_NAMESPACE +class QStandardItemModel; +class QCompleter; +QT_END_NAMESPACE + +namespace QmlDesigner { +class CommentDelegate : public QItemDelegate +{ + Q_OBJECT +public: + enum Role { CommentRole = Qt::UserRole + 1 }; + + CommentDelegate(QObject *parent = nullptr); + ~CommentDelegate() override; + + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + + QCompleter *completer() const; + + void updateEditorGeometry(QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + static Comment comment(QModelIndex const &); + +private: + std::unique_ptr m_completer; + QPointer m_defaults; +}; + +class CommentTitleDelegate : public CommentDelegate +{ + Q_OBJECT +public: + CommentTitleDelegate(QObject *parent = nullptr); + ~CommentTitleDelegate() override; + + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const override; +signals: + void commentChanged(int row, Comment const &); +}; + +class CommentValueDelegate : public CommentDelegate +{ + Q_OBJECT +public: + CommentValueDelegate(QObject *parent = nullptr); + ~CommentValueDelegate(); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + + void setEditorData(QWidget *editor, const QModelIndex &index) const override; + void setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const override; +signals: + void richTextEditorRequested(int index, QString const &richText); +}; + +class RichTextCellEditor : public QLabel +{ + Q_OBJECT + Q_PROPERTY(QmlDesigner::RichTextProxy richText READ richText WRITE setRichText NOTIFY + richTextChanged USER true) +public: + RichTextCellEditor(QWidget *parent = nullptr); + ~RichTextCellEditor() override; + + RichTextProxy richText() const; + void setRichText(RichTextProxy const &); + + void setupSignal(int row, QString const &commentTitle); + +signals: + void clicked(); + void richTextChanged(); + void richTextClicked(int index, QString const &text); + +protected: + void mouseReleaseEvent(QMouseEvent *) override; + +private: + RichTextProxy m_richText; + QMetaObject::Connection m_connection; +}; + +class AnnotationTableView : public QTableView +{ + Q_OBJECT +public: + AnnotationTableView(QWidget *parent = nullptr); + ~AnnotationTableView(); + + QVector fetchComments() const; + Comment fetchComment(int row) const; + void setupComments(QVector const &comments); + + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + + void changeRow(int index, Comment const &comment); + void removeRow(int index); + void removeSelectedRows(); + +signals: + void richTextEditorRequested(int index, QString const &commentTitle); + +protected: + void keyPressEvent(QKeyEvent *) override; + +private: + void addEmptyRow(); + bool rowIsEmpty(int row) const; + static QString dataToCommentText(QVariant const &); + static QVariant commentToData(Comment const&, QMetaType::Type type); + + CommentTitleDelegate m_titleDelegate; + CommentValueDelegate m_valueDelegate; + + bool m_modelUpdating = false; + std::unique_ptr m_model; + std::unique_ptr m_editorFactory; + QPointer m_defaults; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp new file mode 100644 index 00000000000..960920284a5 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.cpp @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "annotationtabwidget.h" + +#include "annotationcommenttab.h" + +#include + +#include +#include +#include + +namespace QmlDesigner { +AnnotationTabWidget::AnnotationTabWidget(QWidget *parent) + : QTabWidget(parent) +{ + auto *commentCornerWidget = new QToolBar; + + //Making it look similar to timeline editor button: + commentCornerWidget->setStyleSheet("QToolBar { background-color: transparent; border-width: 1px; }"); + + auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), + tr("Add Comment")); //timeline icons? + auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), + tr("Remove Comment")); //timeline icons? + connect(commentAddAction, &QAction::triggered, this, [this]() { addCommentTab(); }); + + connect(commentRemoveAction, &QAction::triggered, this, [this]() { + int currentIndex = this->currentIndex(); + QString currentTitle = tabText(currentIndex); + if (QMessageBox::question(this, + currentTitle, + tr("Delete this comment?")) + == QMessageBox::Yes) { + removeTab(currentIndex); + if (count() == 0) //lets be sure that tabWidget is never empty + addCommentTab(); + } + }); + + commentCornerWidget->addAction(commentAddAction); + commentCornerWidget->addAction(commentRemoveAction); + setCornerWidget(commentCornerWidget, Qt::TopRightCorner); +} + +AnnotationTabWidget::~AnnotationTabWidget() {} + +QVector AnnotationTabWidget::fetchComments() const +{ + QVector comments; + for (int i = 0; i < count(); i++) { + auto *tab = qobject_cast(widget(i)); + if (!tab) + continue; + + Comment comment = tab->currentComment(); + + if (!comment.isEmpty()) + comments.push_back(comment); + } + + return comments; +} + +void AnnotationTabWidget::setupComments(QVector const &comments) +{ + setUpdatesEnabled(false); + + deleteAllTabs(); + if (comments.isEmpty()) + addCommentTab(); + + for (const Comment &comment : comments) + addCommentTab(comment); + + setUpdatesEnabled(true); +} + +DefaultAnnotationsModel *AnnotationTabWidget::defaultAnnotations() const +{ + return m_defaults; +} + +void AnnotationTabWidget::setDefaultAnnotations(DefaultAnnotationsModel *defaults) +{ + m_defaults = defaults; + for (int i = 0; i < count(); i++) { + // The tab widget might be contain regular QTabs initially, hence we need this qobject_cast test + if (auto *tab = qobject_cast(widget(i))) + tab->setDefaultAnnotations(defaults); + } +} + +void AnnotationTabWidget::onCommentTitleChanged(const QString &text, QWidget *tab) +{ + int tabIndex = indexOf(tab); + if (tabIndex >= 0) + setTabText(tabIndex, text); + + if (text.isEmpty()) + setTabText(tabIndex, defaultTabName + " " + QString::number(tabIndex + 1)); +} + +void AnnotationTabWidget::addCommentTab(const Comment &comment) +{ + auto *commentTab = new AnnotationCommentTab(); + commentTab->setDefaultAnnotations(m_defaults); + commentTab->setComment(comment); + + QString tabTitle(comment.title()); + int tabIndex = addTab(commentTab, tabTitle); + setCurrentIndex(tabIndex); + + if (tabTitle.isEmpty()) { + const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex + 1) : ""); + tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); + setTabText(tabIndex, tabTitle); + } + connect(commentTab, + &AnnotationCommentTab::titleChanged, + this, + &AnnotationTabWidget::onCommentTitleChanged); +} + +void AnnotationTabWidget::deleteAllTabs() +{ + while (count() > 0) { + QWidget *w = widget(0); + removeTab(0); + delete w; + } +} + +} // namespace QmlDesigner diff --git a/src/libs/sqlite/sqlitereadstatement.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h similarity index 56% rename from src/libs/sqlite/sqlitereadstatement.cpp rename to src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h index 91e672985bd..944400f5e63 100644 --- a/src/libs/sqlite/sqlitereadstatement.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationtabwidget.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -23,23 +23,38 @@ ** ****************************************************************************/ -#include "sqlitereadstatement.h" +#include +#include -#include "sqlite3.h" +#include "annotation.h" +#include "defaultannotations.h" -namespace Sqlite { +namespace QmlDesigner { +class AnnotationCommentTab; -ReadStatement::ReadStatement(Utils::SmallStringView sqlStatement, - Database &database) - : StatementImplementation(sqlStatement, database) +class AnnotationTabWidget : public QTabWidget { - checkIsReadOnlyStatement(); -} + Q_OBJECT +public: + AnnotationTabWidget(QWidget *parent = nullptr); + ~AnnotationTabWidget(); -void ReadStatement::checkIsReadOnlyStatement() -{ - if (!isReadOnlyStatement()) - throw NotReadOnlySqlStatement("SqliteStatement::SqliteReadStatement: is not read only statement!"); -} + QVector fetchComments() const; + void setupComments(QVector const &comments); -} // namespace Sqlite + DefaultAnnotationsModel *defaultAnnotations() const; + void setDefaultAnnotations(DefaultAnnotationsModel *); + +public slots: + void addCommentTab(const Comment &comment = {}); + void deleteAllTabs(); + +private slots: + void onCommentTitleChanged(const QString &text, QWidget *tab); + +private: + const QString defaultTabName = {tr("Annotation")}; + + QPointer m_defaults; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp new file mode 100644 index 00000000000..3623dceeb95 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "defaultannotations.h" + +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { +DefaultAnnotationsModel::DefaultAnnotationsModel(QObject *parent) + : QAbstractListModel(parent) +{ + qRegisterMetaType(); +} + +DefaultAnnotationsModel::~DefaultAnnotationsModel() {} + +int DefaultAnnotationsModel::rowCount(const QModelIndex &) const +{ + return static_cast(m_defaults.size()); +} + +QVariant DefaultAnnotationsModel::data(const QModelIndex &index, int role) const +{ + const auto row = static_cast(index.row()); + if (!index.isValid() || m_defaults.size() < row) + return {}; + + auto &item = m_defaults[row]; + + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + case Name: + return item.first; + case Type: + return item.second.typeName(); + case Default: + return item.second; + } + + return {}; +} + +QVariantMap DefaultAnnotationsModel::fetchData() const +{ + return m_defaultMap; +} + +bool DefaultAnnotationsModel::hasDefault(const Comment &comment) const +{ + return m_defaultMap.count(comment.title().toLower()); +} + +QMetaType::Type DefaultAnnotationsModel::defaultType(const Comment &comment) const +{ + return hasDefault(comment) ? QMetaType::Type(m_defaultMap[comment.title().toLower()].userType()) + : QMetaType::UnknownType; +} + +QVariant DefaultAnnotationsModel::defaultValue(const Comment &comment) const +{ + return hasDefault(comment) ? m_defaultMap.value(comment.title().toLower()) : QVariant(); +} + +bool DefaultAnnotationsModel::isRichText(const Comment &comment) const +{ + const auto type = defaultType(comment); + return type == QMetaType::UnknownType || type == qMetaTypeId(); +} + +void DefaultAnnotationsModel::loadFromFile(QString const &filename) +{ + QFile file(filename); + if (file.open(QFile::ReadOnly)) { + loadFromFile(&file); + } +} + +void DefaultAnnotationsModel::loadFromFile(QIODevice *io) +{ + QJsonParseError error; + auto doc = QJsonDocument::fromJson(io->readAll(), &error); + + if (error.error == QJsonParseError::NoError) + loadFromJson(doc); + else { + } // TODO: Error handling +} + +void DefaultAnnotationsModel::loadFromJson(const QJsonDocument &doc) +{ + beginResetModel(); + m_defaultMap = asVariantMapFromJson(doc); + m_defaults.clear(); + m_defaults.reserve(m_defaultMap.size()); + + for (auto &key : m_defaultMap.keys()) + m_defaults.emplace_back(key, m_defaultMap.value(key)); + + endResetModel(); +} + +QVariantMap DefaultAnnotationsModel::asVariantMapFromJson(const QJsonDocument &doc) +{ + QVariantMap map; + QJsonObject obj = doc.object(); + for (auto key : obj.keys()) { + key = key.toLower(); + auto val = obj[key]; + + switch (val.type()) { + case QJsonValue::Double: + map[key] = double{0.0}; + break; + case QJsonValue::String: + map[key] = QString{}; + break; + case QJsonValue::Bool: + map[key] = false; + break; + case QJsonValue::Object: { + auto o = val.toObject(); + auto type = o["type"].toString().toLower(); + auto val = o["value"].toVariant(); + + if (type == QStringLiteral("richtext")) + map[key] = QVariant::fromValue(RichTextProxy{val.toString()}); + else if (type == QStringLiteral("string")) + map[key] = QVariant::fromValue(val.toString()); + else if (type == QStringLiteral("bool")) + map[key] = QVariant::fromValue(val.toBool()); + else if (type == QStringLiteral("double")) + map[key] = QVariant::fromValue(val.toDouble()); + else if (type == QStringLiteral("color")) + map[key] = QVariant::fromValue(QColor(val.toString())); + } + } + } + + return map; +} + +QString DefaultAnnotationsModel::defaultJsonFilePath() +{ + return QStringLiteral(":/annotationeditor/defaultannotations.json"); +} + +QString RichTextProxy::plainText() const +{ + QString plainText(text); + plainText.remove(QRegularExpression("<.*?>")); + return plainText.mid(plainText.indexOf("}") + 1); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h new file mode 100644 index 00000000000..3553720773d --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ +#pragma once + +#include "annotation.h" + +#include + +QT_BEGIN_NAMESPACE +class QJsonDocument; +QT_END_NAMESPACE + +namespace QmlDesigner { + +// We need this proxy type to distinguish between a 'normal' QString +// and a 'richtext' string when they are stored in a QVariant +struct RichTextProxy +{ + QString text; + + QString plainText() const; +}; + +class DefaultAnnotationsModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum Role { Name = Qt::UserRole + 1, Type, Default }; + Q_ENUM(Role) + + DefaultAnnotationsModel(QObject *parent = nullptr); + ~DefaultAnnotationsModel() override; + + int rowCount(const QModelIndex & = {}) const override; + QVariant data(const QModelIndex &, int role) const override; + + QVariantMap fetchData() const; + + bool hasDefault(const Comment &comment) const; + QMetaType::Type defaultType(const Comment &comment) const; + QVariant defaultValue(const Comment &comment) const; + bool isRichText(const Comment &comment) const; + + void loadFromFile(QString const &); + void loadFromFile(QIODevice *); + void loadFromJson(const QJsonDocument &); + + static QVariantMap asVariantMapFromJson(const QJsonDocument &); + static QString defaultJsonFilePath(); + +private: + std::vector> m_defaults; + QVariantMap m_defaultMap; +}; + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::RichTextProxy); diff --git a/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json new file mode 100644 index 00000000000..aaa060a5558 --- /dev/null +++ b/src/plugins/qmldesigner/components/annotationeditor/defaultannotations.json @@ -0,0 +1,36 @@ +{ + "description" : "", + "display condition" : "", + "helper lines" : true, + "position marker" : true, + "highlight" : true, + "project author" : "", + "project confirmed" : true, + "project developer" : "", + "project distributor" : "", + "project modified" : "", + "project type" : "", + "project version" : "", + "screen description" : "", + "section" : "", + "normalcolor" : { + "type": "color", + "value": "#000000" + }, + "focuscolor" : { + "type": "color", + "value": "#000000" + }, + "selectedcolor" : { + "type": "color", + "value": "#000000" + }, + "pressedcolor" : { + "type": "color", + "value": "#000000" + }, + "overview" : { + "type": "richtext", + "value": "" + } +} diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp index f17833b0c7e..0b04ed5f1c4 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.cpp @@ -25,124 +25,74 @@ #include "globalannotationeditor.h" -#include "globalannotationeditordialog.h" #include "annotation.h" +#include "globalannotationeditordialog.h" -#include "qmlmodelnodeproxy.h" #include - -#include -#include -#include #include namespace QmlDesigner { -GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *) +GlobalAnnotationEditor::GlobalAnnotationEditor(QObject *parent) + : ModelNodeEditorProxy(parent) +{} + +GlobalAnnotationEditor::~GlobalAnnotationEditor() {} + +QWidget *GlobalAnnotationEditor::createWidget() { -} - -GlobalAnnotationEditor::~GlobalAnnotationEditor() -{ - hideWidget(); -} - -void GlobalAnnotationEditor::showWidget() -{ - m_dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(), - modelNode().globalAnnotation(), - modelNode().globalStatus()); - - QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::acceptedDialog, - this, &GlobalAnnotationEditor::acceptedClicked); - QObject::connect(m_dialog, &GlobalAnnotationEditorDialog::rejected, - this, &GlobalAnnotationEditor::cancelClicked); - - m_dialog->setAttribute(Qt::WA_DeleteOnClose); - - m_dialog->show(); - m_dialog->raise(); -} - -void GlobalAnnotationEditor::showWidget(int x, int y) -{ - showWidget(); - m_dialog->move(x, y); -} - -void GlobalAnnotationEditor::hideWidget() -{ - if (m_dialog) - m_dialog->close(); - m_dialog = nullptr; -} - -void GlobalAnnotationEditor::setModelNode(const ModelNode &modelNode) -{ - m_modelNode = modelNode; -} - -ModelNode GlobalAnnotationEditor::modelNode() const -{ - return m_modelNode; -} - -bool GlobalAnnotationEditor::hasAnnotation() const -{ - if (m_modelNode.isValid()) - return m_modelNode.hasGlobalAnnotation(); - return false; -} + auto* dialog = new GlobalAnnotationEditorDialog(Core::ICore::dialogParent(), + this->m_modelNode.globalStatus()); + dialog->setAnnotation(this->m_modelNode.globalAnnotation()); + QObject::connect(dialog, + &GlobalAnnotationEditorDialog::acceptedDialog, + this, + &GlobalAnnotationEditor::acceptedClicked); + QObject::connect(dialog, + &GlobalAnnotationEditorDialog::rejected, + this, + &GlobalAnnotationEditor::cancelClicked); + return dialog; +}; void GlobalAnnotationEditor::removeFullAnnotation() { - if (!m_modelNode.isValid()) + auto &node = this->m_modelNode; + if (!node.isValid()) return; QString dialogTitle = tr("Global Annotation"); - QMessageBox *deleteDialog = new QMessageBox(Core::ICore::dialogParent()); - deleteDialog->setWindowTitle(dialogTitle); - deleteDialog->setText(tr("Delete this annotation?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); - - int result = deleteDialog->exec(); - if (deleteDialog) deleteDialog->deleteLater(); - - if (result == QMessageBox::Yes) { - m_modelNode.removeGlobalAnnotation(); + if (QMessageBox::question(Core::ICore::dialogParent(), + tr("Global Annotation"), + tr("Delete this annotation?")) + == QMessageBox::Yes) { + node.removeGlobalAnnotation(); + emit annotationChanged(); } - - emit annotationChanged(); } void GlobalAnnotationEditor::acceptedClicked() { - if (m_dialog) { - - Annotation annotation = m_dialog->annotation(); + if (const auto *dialog = qobject_cast(widget())) { + auto &node = this->m_modelNode; + const Annotation annotation = dialog->annotation(); if (annotation.comments().isEmpty()) - m_modelNode.removeGlobalAnnotation(); + node.removeGlobalAnnotation(); else - m_modelNode.setGlobalAnnotation(annotation); + node.setGlobalAnnotation(annotation); - GlobalAnnotationStatus status = m_dialog->globalStatus(); + const GlobalAnnotationStatus status = dialog->globalStatus(); - if (status.status() == GlobalAnnotationStatus::NoStatus) { - if (m_modelNode.hasGlobalStatus()) { - m_modelNode.removeGlobalStatus(); - } - } - else { - m_modelNode.setGlobalStatus(status); - } + if (status.status() == GlobalAnnotationStatus::NoStatus) + node.removeGlobalStatus(); + else + node.setGlobalStatus(status); } hideWidget(); emit accepted(); - emit annotationChanged(); } @@ -151,7 +101,6 @@ void GlobalAnnotationEditor::cancelClicked() hideWidget(); emit canceled(); - emit annotationChanged(); } diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h index eefdaec553a..ed8973380f9 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditor.h @@ -26,32 +26,25 @@ #pragma once #include -#include #include +#include -#include "globalannotationeditordialog.h" +#include "abstractaction.h" #include "annotation.h" +#include "globalannotationeditordialog.h" +#include "editorproxy.h" #include "modelnode.h" namespace QmlDesigner { - -class GlobalAnnotationEditor : public QObject +class GlobalAnnotationEditor : public ModelNodeEditorProxy { Q_OBJECT - public: explicit GlobalAnnotationEditor(QObject *parent = nullptr); ~GlobalAnnotationEditor(); - Q_INVOKABLE void showWidget(); - Q_INVOKABLE void showWidget(int x, int y); - Q_INVOKABLE void hideWidget(); - - void setModelNode(const ModelNode &modelNode); - ModelNode modelNode() const; - - Q_INVOKABLE bool hasAnnotation() const; + QWidget *createWidget() override; Q_INVOKABLE void removeFullAnnotation(); @@ -59,17 +52,11 @@ signals: void accepted(); void canceled(); void modelNodeBackendChanged(); - void annotationChanged(); private slots: void acceptedClicked(); void cancelClicked(); - -private: - QPointer m_dialog; - - ModelNode m_modelNode; }; } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp index ecfa00baab4..3722935643b 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.cpp @@ -24,87 +24,55 @@ ****************************************************************************/ #include "globalannotationeditordialog.h" -#include "ui_globalannotationeditordialog.h" #include "annotation.h" #include "annotationcommenttab.h" - -#include "ui_annotationcommenttab.h" +#include "ui_globalannotationeditordialog.h" #include #include -#include -#include #include #include +#include +#include namespace QmlDesigner { -GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status) - : QDialog(parent) +GlobalAnnotationEditorDialog::GlobalAnnotationEditorDialog(QWidget *parent, + GlobalAnnotationStatus status) + : BasicAnnotationEditorDialog(parent) , ui(new Ui::GlobalAnnotationEditorDialog) - , m_annotation(annotation) , m_globalStatus(status) , m_statusIsActive(false) { ui->setupUi(this); + ui->tabWidget->setDefaultAnnotations(defaultAnnotations()); + ui->tableView->setDefaultAnnotations(defaultAnnotations()); - setWindowFlag(Qt::Tool, true); - setModal(true); + connect(ui->tableView, + &AnnotationTableView::richTextEditorRequested, + this, + [&](int index, QString const &) { + switchToTabView(); + ui->tabWidget->setCurrentIndex(index); + }); - connect(this, &QDialog::accepted, this, &GlobalAnnotationEditorDialog::acceptedClicked); - - connect(ui->tabWidget, &QTabWidget::currentChanged, this, &GlobalAnnotationEditorDialog::tabChanged); - - auto *commentCornerWidget = new QToolBar; - - auto *commentAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(), tr("Add Comment")); //timeline icons? - auto *commentRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(), - tr("Remove Comment")); //timeline icons? - - connect(commentAddAction, &QAction::triggered, this, [this]() { - addComment(Comment()); - }); - - connect(commentRemoveAction, &QAction::triggered, this, [this]() { - - if (ui->tabWidget->count() == 0) { //it is not even supposed to happen but lets be sure - QTC_ASSERT(false, return); - return; - } - - int currentIndex = ui->tabWidget->currentIndex(); - QString currentTitle = ui->tabWidget->tabText(currentIndex); - - QMessageBox *deleteDialog = new QMessageBox(this); - deleteDialog->setWindowTitle(currentTitle); - deleteDialog->setText(tr("Delete this comment?")); - deleteDialog->setStandardButtons(QMessageBox::Yes | QMessageBox::No); - deleteDialog->setDefaultButton(QMessageBox::Yes); - - int result = deleteDialog->exec(); - - if (result == QMessageBox::Yes) { - removeComment(currentIndex); - } - - if (ui->tabWidget->count() == 0) //lets be sure that tabWidget is never empty - addComment(Comment()); - }); - - commentCornerWidget->addAction(commentAddAction); - commentCornerWidget->addAction(commentRemoveAction); - - ui->tabWidget->setCornerWidget(commentCornerWidget, Qt::TopRightCorner); - - connect(ui->statusAddButton, &QPushButton::clicked, [&](bool){ + connect(ui->statusAddButton, &QPushButton::clicked, this, [&](bool) { setStatusVisibility(true); }); - setStatus(m_globalStatus); + connect(ui->rbTableView, + &QRadioButton::clicked, + this, + &GlobalAnnotationEditorDialog::switchToTableView); + connect(ui->rbTabView, + &QRadioButton::clicked, + this, + &GlobalAnnotationEditorDialog::switchToTabView); - fillFields(); + setStatus(m_globalStatus); setWindowTitle(globalEditorTitle); + switchToTabView(); } GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog() @@ -112,26 +80,18 @@ GlobalAnnotationEditorDialog::~GlobalAnnotationEditorDialog() delete ui; } -void GlobalAnnotationEditorDialog::setAnnotation(const Annotation &annotation) +GlobalAnnotationEditorDialog::ViewMode GlobalAnnotationEditorDialog::viewMode() const { - m_annotation = annotation; - fillFields(); -} - -Annotation GlobalAnnotationEditorDialog::annotation() const -{ - return m_annotation; + return ui->rbTableView->isChecked() ? TableView : TabsView; } void GlobalAnnotationEditorDialog::setStatus(GlobalAnnotationStatus status) { m_globalStatus = status; + bool hasStatus = status.status() != GlobalAnnotationStatus::NoStatus; - bool hasStatus = (status.status() != GlobalAnnotationStatus::NoStatus); - - if (hasStatus) { + if (hasStatus) ui->statusComboBox->setCurrentIndex(int(status.status())); - } setStatusVisibility(hasStatus); } @@ -141,117 +101,73 @@ GlobalAnnotationStatus GlobalAnnotationEditorDialog::globalStatus() const return m_globalStatus; } -void GlobalAnnotationEditorDialog::acceptedClicked() +void GlobalAnnotationEditorDialog::showStatusContainer(bool show) { - Annotation annotation; - - annotation.removeComments(); - - for (int i = 0; i < ui->tabWidget->count(); i++) { - AnnotationCommentTab* tab = reinterpret_cast(ui->tabWidget->widget(i)); - if (!tab) - continue; - - Comment comment = tab->currentComment(); - - if (!comment.isEmpty()) - annotation.addComment(comment); - } - - m_annotation = annotation; - - if (m_statusIsActive) { - m_globalStatus.setStatus(ui->statusComboBox->currentIndex()); - } - - emit GlobalAnnotationEditorDialog::acceptedDialog(); + ui->statusContainer->setVisible(show); } -void GlobalAnnotationEditorDialog::commentTitleChanged(const QString &text, QWidget *tab) +void GlobalAnnotationEditorDialog::switchToTabView() { - int tabIndex = ui->tabWidget->indexOf(tab); - if (tabIndex >= 0) - ui->tabWidget->setTabText(tabIndex, text); + m_annotation.setComments(ui->tableView->fetchComments()); + ui->rbTabView->setChecked(true); + ui->tableView->hide(); + ui->tabWidget->show(); + fillFields(); +} - if (text.isEmpty()) - ui->tabWidget->setTabText(tabIndex, - (defaultTabName + " " + QString::number(tabIndex+1))); +void GlobalAnnotationEditorDialog::switchToTableView() +{ + m_annotation.setComments(ui->tabWidget->fetchComments()); + ui->rbTableView->setChecked(true); + ui->tabWidget->hide(); + ui->tableView->show(); + fillFields(); +} + +void GlobalAnnotationEditorDialog::acceptedClicked() +{ + updateAnnotation(); + emit GlobalAnnotationEditorDialog::acceptedDialog(); } void GlobalAnnotationEditorDialog::fillFields() { - setupComments(); + ui->tabWidget->setupComments(m_annotation.comments()); + ui->tableView->setupComments(m_annotation.comments()); } -void GlobalAnnotationEditorDialog::setupComments() +void GlobalAnnotationEditorDialog::updateAnnotation() { - ui->tabWidget->setUpdatesEnabled(false); - - deleteAllTabs(); - - const QVector comments = m_annotation.comments(); - - if (comments.isEmpty()) - addComment(Comment()); - - for (const Comment &comment : comments) { - addCommentTab(comment); + Annotation annotation; + switch (viewMode()) { + case TabsView: + annotation.setComments(ui->tabWidget->fetchComments()); + break; + case TableView: + annotation.setComments(ui->tableView->fetchComments()); + break; } - ui->tabWidget->setUpdatesEnabled(true); + m_annotation = annotation; + + if (m_statusIsActive) + m_globalStatus.setStatus(ui->statusComboBox->currentIndex()); } void GlobalAnnotationEditorDialog::addComment(const Comment &comment) { m_annotation.addComment(comment); - addCommentTab(comment); + ui->tabWidget->addCommentTab(comment); } void GlobalAnnotationEditorDialog::removeComment(int index) { if ((m_annotation.commentsSize() > index) && (index >= 0)) { m_annotation.removeComment(index); - removeCommentTab(index); - } -} - -void GlobalAnnotationEditorDialog::addCommentTab(const Comment &comment) -{ - auto commentTab = new AnnotationCommentTab(); - commentTab->setComment(comment); - - QString tabTitle(comment.title()); - int tabIndex = ui->tabWidget->addTab(commentTab, tabTitle); - ui->tabWidget->setCurrentIndex(tabIndex); - - if (tabTitle.isEmpty()) { - const QString appendix = ((tabIndex > 0) ? QString::number(tabIndex+1) : ""); - - tabTitle = QString("%1 %2").arg(defaultTabName).arg(appendix); - - ui->tabWidget->setTabText(tabIndex, tabTitle); - } - - connect(commentTab, &AnnotationCommentTab::titleChanged, - this, &GlobalAnnotationEditorDialog::commentTitleChanged); -} - -void GlobalAnnotationEditorDialog::removeCommentTab(int index) -{ - if ((ui->tabWidget->count() > index) && (index >= 0)) { ui->tabWidget->removeTab(index); } } -void GlobalAnnotationEditorDialog::deleteAllTabs() -{ - while (ui->tabWidget->count() > 0) { - QWidget *w = ui->tabWidget->widget(0); - ui->tabWidget->removeTab(0); - delete w; - } -} - void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus) { ui->statusAddButton->setVisible(!hasStatus); @@ -260,9 +176,4 @@ void GlobalAnnotationEditorDialog::setStatusVisibility(bool hasStatus) m_statusIsActive = hasStatus; } -void GlobalAnnotationEditorDialog::tabChanged(int index) -{ - (void) index; -} - } //namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h index 5688c54ecfa..2f4c942809b 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.h @@ -25,9 +25,7 @@ #pragma once -#include - -#include "annotation.h" +#include "annotationeditordialog.h" namespace QmlDesigner { @@ -35,46 +33,46 @@ namespace Ui { class GlobalAnnotationEditorDialog; } -class GlobalAnnotationEditorDialog : public QDialog +class GlobalAnnotationEditorDialog : public BasicAnnotationEditorDialog { Q_OBJECT - public: - explicit GlobalAnnotationEditorDialog(QWidget *parent, const Annotation &annotation, GlobalAnnotationStatus status); + enum ViewMode { + TableView, + TabsView + }; + + explicit GlobalAnnotationEditorDialog( + QWidget *parent = nullptr, GlobalAnnotationStatus status = GlobalAnnotationStatus::NoStatus); ~GlobalAnnotationEditorDialog(); - void setAnnotation(const Annotation &annotation); - Annotation annotation() const; + ViewMode viewMode() const; void setStatus(GlobalAnnotationStatus status); GlobalAnnotationStatus globalStatus() const; -signals: - void acceptedDialog(); //use instead of QDialog::accepted +public slots: + void showStatusContainer(bool show); + void switchToTabView(); + void switchToTableView(); private slots: - void acceptedClicked(); - void tabChanged(int index); - void commentTitleChanged(const QString &text, QWidget *tab); + void acceptedClicked() override; private: - void fillFields(); - void setupComments(); + + void fillFields() override; + void updateAnnotation(); void addComment(const Comment &comment); void removeComment(int index); - void addCommentTab(const Comment &comment); - void removeCommentTab(int index); - void deleteAllTabs(); - void setStatusVisibility(bool hasStatus); private: const QString globalEditorTitle = {tr("Global Annotation Editor")}; - const QString defaultTabName = {tr("Annotation")}; + Ui::GlobalAnnotationEditorDialog *ui; - Annotation m_annotation; GlobalAnnotationStatus m_globalStatus; bool m_statusIsActive; }; diff --git a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui index bc0f3efdca2..75d99d26e0c 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui +++ b/src/plugins/qmldesigner/components/annotationeditor/globalannotationeditordialog.ui @@ -73,6 +73,23 @@
+ + + + Tab View + + + true + + + + + + + Table View + + + @@ -90,7 +107,7 @@ - + 0 @@ -109,6 +126,9 @@ + + + @@ -124,6 +144,19 @@
+ + + AnnotationTabWidget + QTabWidget +
annotationtabwidget.h
+ 1 +
+ + AnnotationTableView + QTableView +
annotationtableview.h
+
+
tabWidget diff --git a/src/plugins/qmldesigner/components/bindingeditor/signallist.cpp b/src/plugins/qmldesigner/components/bindingeditor/signallist.cpp index 5eb9ceabfaa..f87000ddbab 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/signallist.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/signallist.cpp @@ -96,8 +96,8 @@ void SignalList::prepareDialog() m_dialog = new SignalListDialog(Core::ICore::dialogParent()); m_dialog->setAttribute(Qt::WA_DeleteOnClose); m_dialog->initialize(m_model); - m_dialog->setWindowTitle(::QmlDesigner::SignalList::tr("Signal List for ") - + m_modelNode.validId()); + m_dialog->setWindowTitle(::QmlDesigner::SignalList::tr("Signal List for %1") + .arg(m_modelNode.validId())); auto *delegate = static_cast(m_dialog->tableView()->itemDelegate()); connect(delegate, &SignalListDelegate::connectClicked, this, &SignalList::connectClicked); diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index e72c61829ac..3acfa1fce42 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1556,7 +1556,7 @@ void editAnnotation(const SelectionContext &selectionContext) { ModelNode selectedNode = selectionContext.currentSingleSelectedNode(); - AnnotationEditor::showWidget(selectedNode); + ModelNodeEditorProxy::fromModelNode(selectedNode); } QVariant previewImageDataForGenericNode(const ModelNode &modelNode) diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index 865b04a453a..3f3f60d50a4 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -118,6 +118,11 @@ void CurveEditorView::nodeReparented(const ModelNode &node, updateKeyframes(); else if (QmlTimelineKeyframeGroup::checkKeyframesType(node)) updateKeyframes(); + else if (newPropertyParent.isValid() && !oldPropertyParent.isValid()) { + if (activeTimeline().hasKeyframeGroupForTarget(node)) { + updateKeyframes(); + } + } } void CurveEditorView::auxiliaryDataChanged(const ModelNode &node, diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index a51283bb543..c4dd86c44e7 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -163,8 +163,21 @@ void DebugView::nodeIdChanged(const ModelNode &node, const QString &newId, const } } -void DebugView::propertiesAboutToBeRemoved(const QList & /*propertyList*/) +void DebugView::propertiesAboutToBeRemoved(const QList &propertyList) { + if (isDebugViewEnabled()) { + QTextStream message; + QString string; + message.setString(&string); + for (const AbstractProperty &property : propertyList) { + message << property; + if (property.isNodeAbstractProperty()) + message << " is NodeAbstractProperty"; + if (property.isDefaultProperty()) + message << " is DefaultProperty"; + } + log("::propertiesAboutToBeRemoved:", string); + } } void DebugView::variantPropertiesChanged(const QList &propertyList, diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp index 997c712af6d..67bbdbbb8c3 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorannotationicon.cpp @@ -316,7 +316,7 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const const QString &author, const QString &text, const QString &date, QGraphicsItem *parent) { - static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorForegroundColor); + static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::DStextColor); static QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColorDarker); static QColor frameColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColor); QFont font; @@ -384,7 +384,7 @@ QGraphicsItem *FormEditorAnnotationIcon::createCommentBubble(QRectF rect, const QGraphicsItem *FormEditorAnnotationIcon::createTitleBubble(const QRectF &rect, const QString &text, QGraphicsItem *parent) { - static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_FormEditorForegroundColor); + static QColor textColor = Utils::creatorTheme()->color(Utils::Theme::DStextColor); static QColor backgroundColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColorDarker); static QColor frameColor = Utils::creatorTheme()->color(Utils::Theme::QmlDesigner_BackgroundColor); QFont font; @@ -426,8 +426,8 @@ void FormEditorAnnotationIcon::createAnnotationEditor() m_annotationEditor = new AnnotationEditorDialog(Core::ICore::dialogParent(), m_modelNode.displayName(), - m_modelNode.customId(), - m_modelNode.annotation()); + m_modelNode.customId()); + m_annotationEditor->setAnnotation(m_modelNode.annotation()); connect(m_annotationEditor, &AnnotationEditorDialog::acceptedDialog, this, &FormEditorAnnotationIcon::annotationDialogAccepted); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 6c395fbd686..91a930b7831 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -212,6 +212,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) QString projectName = project ? project->displayName() : ""; // create import sections + const QList usedImports = model->usedImports(); QHash importHash; for (const Import &import : model->imports()) { if (import.url() != projectName) { @@ -239,6 +240,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model) auto sectionType = isQuick3DAsset ? ItemLibraryImport::SectionType::Quick3DAssets : ItemLibraryImport::SectionType::Default; ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this, sectionType); + itemLibImport->setImportUsed(usedImports.contains(import)); importHash.insert(importUrl, itemLibImport); } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp index 288f7024554..1eef27473d9 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryresourceview.cpp @@ -75,7 +75,7 @@ ItemLibraryResourceView::ItemLibraryResourceView(AsynchronousImageCache &fontIma setSpacing(4); setViewMode(QListView::IconMode); - setMovement(QListView::Static); + setMovement(QListView::Snap); setResizeMode(QListView::Adjust); setSelectionRectVisible(false); setWrapping(true); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp index 609f4f45326..e498d20156c 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorqmlbackend.cpp @@ -669,7 +669,6 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, bool emptyTemplate = true; const QString anchorLeftRight = "anchors.left: parent.left\nanchors.right: parent.right\n"; - const QString paddingLeftTopBottom = "leftPadding: 0\ntopPadding: 0\nbottomPadding: 0\n"; qmlTemplate += "Column {\n"; qmlTemplate += anchorLeftRight; @@ -680,7 +679,6 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, qmlTemplate += "Section {\n"; qmlTemplate += "caption: \"User added properties\"\n"; qmlTemplate += anchorLeftRight; - qmlTemplate += paddingLeftTopBottom; qmlTemplate += "Column {\n"; qmlTemplate += "width: parent.width\n"; @@ -747,7 +745,6 @@ QString PropertyEditorQmlBackend::templateGeneration(const NodeMetaInfo &type, qmlTemplate += "Section {\n"; qmlTemplate += QStringLiteral("caption: \"%1 - %2\"\n").arg(QString::fromUtf8(p)).arg(QString::fromUtf8(parentTypeName)); qmlTemplate += anchorLeftRight; - qmlTemplate += paddingLeftTopBottom; qmlTemplate += "level: 1\n"; qmlTemplate += "Column {\n"; qmlTemplate += "width: parent.width\n"; diff --git a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp index 9690ea1c68f..5121de76853 100644 --- a/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp +++ b/src/plugins/qmldesigner/components/richtexteditor/richtexteditor.cpp @@ -119,6 +119,14 @@ RichTextEditor::RichTextEditor(QWidget *parent) ui->textEdit->setTextInteractionFlags(Qt::TextEditorInteraction | Qt::LinksAccessibleByMouse); ui->tableBar->setVisible(false); + const QColor backColor = Theme::getColor(Theme::DSpanelBackground); + + const QString toolBarStyleSheet = + QString("QToolBar { background-color: %1; border-width: 1px }").arg(backColor.name()); + + ui->toolBar->setStyleSheet(toolBarStyleSheet); + ui->tableBar->setStyleSheet(toolBarStyleSheet); + setupEditActions(); setupTextActions(); setupImageActions(); @@ -201,7 +209,7 @@ void RichTextEditor::setDocumentBaseUrl(const QUrl& url) QIcon RichTextEditor::getIcon(Theme::Icon icon) { const QString fontName = "qtds_propertyIconFont.ttf"; - const QColor iconColorNormal(Theme::getColor(Theme::IconsBaseColor)); + const QColor iconColorNormal(Theme::getColor(Theme::DStextColor)); return Utils::StyleHelper::getIconFromIconFont( fontName, Theme::getIconUnicode(icon), 20, 20, iconColorNormal); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp index bfa56b89c7f..dbf5c597807 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp @@ -205,9 +205,10 @@ TimelineWidget::TimelineWidget(TimelineView *view) auto *topSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); auto *bottomSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); - QString labelText = - tr("This file does not contain a timeline.

\ - To create an animation, add a timeline by clicking the + button."); + const QString labelText = + tr("This file does not contain a timeline.

" + "To create an animation, add a timeline by clicking the + button."); + onboardingTopLabel->setText(labelText); onboardingTopLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); @@ -241,7 +242,7 @@ TimelineWidget::TimelineWidget(TimelineView *view) { QPalette timelinePalette; timelinePalette.setColor(QPalette::Text, Utils::creatorTheme()->color( - Utils::Theme::QmlDesigner_FormEditorForegroundColor)); + Utils::Theme::DStextColor)); timelinePalette.setColor(QPalette::WindowText, timelinePalette.color(QPalette::Text)); timelinePalette.setColor(QPalette::Window, Utils::creatorTheme()->color( Utils::Theme::QmlDesigner_BackgroundColorDarkAlternate)); diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h index f34dd2fca4b..bf589d951d5 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h @@ -43,7 +43,8 @@ template class ImageCacheStorage : public ImageCacheStorageInterface { public: - using ReadStatement = typename DatabaseType::ReadStatement; + template + using ReadStatement = typename DatabaseType::template ReadStatement; using WriteStatement = typename DatabaseType::WriteStatement; ImageCacheStorage(DatabaseType &database) @@ -272,11 +273,11 @@ public: DatabaseType &database; Initializer initializer{database}; Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database}; - mutable ReadStatement selectImageStatement{ + mutable ReadStatement<1> selectImageStatement{ "SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database}; - mutable ReadStatement selectSmallImageStatement{ + mutable ReadStatement<1> selectSmallImageStatement{ "SELECT smallImage FROM images WHERE name=?1 AND mtime >= ?2", database}; - mutable ReadStatement selectIconStatement{ + mutable ReadStatement<1> selectIconStatement{ "SELECT icon FROM icons WHERE name=?1 AND mtime >= ?2", database}; WriteStatement upsertImageStatement{ "INSERT INTO images(name, mtime, image, smallImage) VALUES (?1, ?2, ?3, ?4) ON " diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 2a23466e094..432667c63a4 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -934,15 +934,23 @@ void TextToModelMerger::setupUsedImports() const QList allImports = imports->all(); + QSet usedImportsSet; QList usedImports; - foreach (const QmlJS::Import &import, allImports) { - if (import.used && !import.info.name().isEmpty()) { - if (import.info.type() == ImportType::Library) { + // populate usedImportsSet from current model nodes + const QList allModelNodes = m_rewriterView->allModelNodes(); + for (const ModelNode &modelNode : allModelNodes) { + QString type = QString::fromUtf8(modelNode.type()); + if (type.contains('.')) + usedImportsSet.insert(type.left(type.lastIndexOf('.'))); + } + + for (const QmlJS::Import &import : allImports) { + if (!import.info.name().isEmpty() && usedImportsSet.contains(import.info.name())) { + if (import.info.type() == ImportType::Library) usedImports.append(Import::createLibraryImport(import.info.name(), import.info.version().toString(), import.info.as())); - } else if (import.info.type() == ImportType::Directory || import.info.type() == ImportType::File) { + else if (import.info.type() == ImportType::Directory || import.info.type() == ImportType::File) usedImports.append(Import::createFileImport(import.info.name(), import.info.version().toString(), import.info.as())); - } } } diff --git a/src/plugins/qmldesigner/documentmanager.cpp b/src/plugins/qmldesigner/documentmanager.cpp index 49350f634f9..7cd0b2d14c2 100644 --- a/src/plugins/qmldesigner/documentmanager.cpp +++ b/src/plugins/qmldesigner/documentmanager.cpp @@ -324,6 +324,9 @@ void DocumentManager::addFileToVersionControl(const QString &directoryPath, cons Utils::FilePath DocumentManager::currentFilePath() { + if (!QmlDesignerPlugin::instance()->currentDesignDocument()) + return {}; + return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument()->fileName(); } diff --git a/src/plugins/qmldesigner/editorproxy.cpp b/src/plugins/qmldesigner/editorproxy.cpp new file mode 100644 index 00000000000..16bc65cdff3 --- /dev/null +++ b/src/plugins/qmldesigner/editorproxy.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "editorproxy.h" +#include "qmlmodelnodeproxy.h" + +#include + +namespace QmlDesigner { + +EditorProxy::EditorProxy(QObject *parent) + : QObject(parent) +{} + +EditorProxy::~EditorProxy() +{ + hideWidget(); +} + +void EditorProxy::showWidget() +{ + if ((m_widget = createWidget())) { + m_widget->setAttribute(Qt::WA_DeleteOnClose); + m_widget->show(); + m_widget->raise(); + } +} + +void EditorProxy::showWidget(int x, int y) +{ + showWidget(); + if (m_widget) { + m_widget->move(x, y); + } +} + +void EditorProxy::hideWidget() +{ + if (m_widget) + m_widget->close(); + m_widget = nullptr; +} + +QWidget *EditorProxy::widget() const +{ + return m_widget; +} + +ModelNodeEditorProxy::ModelNodeEditorProxy(QObject *parent) + : EditorProxy(parent) +{} + +ModelNodeEditorProxy::~ModelNodeEditorProxy() {} + +ModelNode ModelNodeEditorProxy::modelNode() const +{ + return m_modelNode; +} + +void ModelNodeEditorProxy::setModelNode(const ModelNode &modelNode) +{ + m_modelNodeBackend = {}; + m_modelNode = modelNode; +} + +void ModelNodeEditorProxy::setModelNodeBackend(const QVariant &modelNodeBackend) +{ + if (!modelNodeBackend.isNull() && modelNodeBackend.isValid()) { + const auto modelNodeBackendObject = modelNodeBackend.value(); + const auto backendObjectCasted = qobject_cast( + modelNodeBackendObject); + + if (backendObjectCasted) + m_modelNode = backendObjectCasted->qmlObjectNode().modelNode(); + m_modelNodeBackend = modelNodeBackend; + + emit modelNodeBackendChanged(); + } +} + +QVariant ModelNodeEditorProxy::modelNodeBackend() const +{ + return m_modelNodeBackend; +} + +bool ModelNodeEditorProxy::hasCustomId() const +{ + return m_modelNode.isValid() ? m_modelNode.hasCustomId() : false; +} + +bool ModelNodeEditorProxy::hasAnnotation() const +{ + return m_modelNode.isValid() ? m_modelNode.hasAnnotation() : false; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/editorproxy.h b/src/plugins/qmldesigner/editorproxy.h new file mode 100644 index 00000000000..20d39246fdb --- /dev/null +++ b/src/plugins/qmldesigner/editorproxy.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ +#pragma once + +#include +#include + +#include "modelnode.h" + +namespace QmlDesigner { +class EditorProxy : public QObject +{ + Q_OBJECT +public: + EditorProxy(QObject *parent = nullptr); + ~EditorProxy(); + + Q_INVOKABLE virtual void showWidget(); + Q_INVOKABLE void showWidget(int x, int y); + Q_INVOKABLE virtual void hideWidget(); + + QWidget *widget() const; + virtual QWidget *createWidget() = 0; + + template + static void registerType(const char *className) + { + qmlRegisterType("HelperWidgets", 2, 0, className); + } + +protected: + QPointer m_widget; +}; + +class ModelNodeEditorProxy : public EditorProxy +{ + Q_OBJECT + Q_PROPERTY(bool hasCustomId READ hasCustomId NOTIFY customIdChanged) + Q_PROPERTY(bool hasAnnotation READ hasAnnotation NOTIFY annotationChanged) + Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend + NOTIFY modelNodeBackendChanged) +public: + ModelNodeEditorProxy(QObject *parent = nullptr); + ~ModelNodeEditorProxy(); + + ModelNode modelNode() const; + virtual void setModelNode(const ModelNode &modelNode); + + void setModelNodeBackend(const QVariant &modelNodeBackend); + QVariant modelNodeBackend() const; + + Q_INVOKABLE bool hasCustomId() const; + Q_INVOKABLE bool hasAnnotation() const; + + template + static T *fromModelNode(const ModelNode &modelNode, QVariant const &modelNodeBackend = {}) + { + auto *editor = new T; + editor->setModelNode(modelNode); + if (!modelNodeBackend.isNull()) + editor->setModelNodeBackend(modelNodeBackend); + + editor->showWidget(); + if (editor->m_widget) { + connect(editor->m_widget, &QObject::destroyed, [editor]() { editor->deleteLater(); }); + } + return editor; + } + +signals: + void customIdChanged(); + void annotationChanged(); + void modelNodeBackendChanged(); + +protected: + QVariant m_modelNodeBackend; + ModelNode m_modelNode; +}; +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/qmldesignerplugin.pri b/src/plugins/qmldesigner/qmldesignerplugin.pri index c7d3c1df056..58fb55788f3 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.pri +++ b/src/plugins/qmldesigner/qmldesignerplugin.pri @@ -3,6 +3,7 @@ HEADERS += $$PWD/qmldesignerconstants.h \ $$PWD/qmldesignerplugin.h \ $$PWD/designmodewidget.h \ $$PWD/designersettings.h \ + $$PWD/editorproxy.h \ $$PWD/generateresource.h \ $$PWD/settingspage.h \ $$PWD/designmodecontext.h \ @@ -17,6 +18,7 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \ $$PWD/shortcutmanager.cpp \ $$PWD/designmodewidget.cpp \ $$PWD/designersettings.cpp \ + $$PWD/editorproxy.cpp \ $$PWD/generateresource.cpp \ $$PWD/settingspage.cpp \ $$PWD/designmodecontext.cpp \ diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 816c3d65732..9f9124691ff 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -43,6 +43,7 @@ Project { "../../../share/qtcreator/qml/qmlpuppet/commands", "../../../share/qtcreator/qml/qmlpuppet/types", "components", + "components/annotationeditor", "components/componentcore", "components/curveeditor", "components/connectioneditor", @@ -730,6 +731,7 @@ Project { "annotationeditor/annotationcommenttab.ui", "annotationeditor/annotationeditor.cpp", "annotationeditor/annotationeditor.h", + "annotationeditor/annotationeditor.qrc", "annotationeditor/globalannotationeditor.cpp", "annotationeditor/globalannotationeditor.h", "annotationeditor/annotationeditordialog.cpp", @@ -738,6 +740,12 @@ Project { "annotationeditor/globalannotationeditordialog.cpp", "annotationeditor/globalannotationeditordialog.h", "annotationeditor/globalannotationeditordialog.ui", + "annotationeditor/defaultannotations.cpp", + "annotationeditor/defaultannotations.h", + "annotationeditor/annotationtableview.cpp", + "annotationeditor/annotationtableview.h", + "annotationeditor/annotationtabwidget.cpp", + "annotationeditor/annotationtabwidget.h", "bindingeditor/bindingeditor.cpp", "bindingeditor/bindingeditor.h", "bindingeditor/actioneditor.cpp", @@ -970,6 +978,8 @@ Project { "documentmanager.h", "documentwarningwidget.cpp", "documentwarningwidget.h", + "editorproxy.h", + "editorproxy.cpp", "openuiqmlfiledialog.cpp", "openuiqmlfiledialog.h", "openuiqmlfiledialog.ui", diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index fe7f34ca7f4..d22625e7c75 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -19,3 +19,8 @@ if (TARGET StudioWelcome) ) qtc_add_resources(StudioWelcome StudioWelcome_qml FILES ${qmlfiles}) endif() + +extend_qtc_plugin(StudioWelcome + CONDITION BUILD_WITH_CRASHPAD + DEFINES ENABLE_CRASHPAD +) diff --git a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml index 25257f9ea7d..8dc80601710 100644 --- a/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml +++ b/src/plugins/studiowelcome/qml/welcomepage/ExamplesModel.qml @@ -92,11 +92,20 @@ ListModel { } ListElement { - projectName: "highendivisystem" + projectName: "digitalcluster" qmlFileName: "Screen01.ui.qml" thumbnail: "images/digital_cluster_thumbnail.png" displayName: "Digital Cluster" url: "https://download.qt.io/learning/examples/qtdesignstudio/digitalcluster.zip" showDownload: true } + + ListElement { + projectName: "effectdemo" + qmlFileName: "Screen01.ui.qml" + thumbnail: "images/effectdemo_thumbnail.png" + displayName: "Effect Demo" + url: "https://download.qt.io/learning/examples/qtdesignstudio/effectdemo.zip" + showDownload: true + } } diff --git a/src/plugins/studiowelcome/qml/welcomepage/images/effectdemo_thumbnail.png b/src/plugins/studiowelcome/qml/welcomepage/images/effectdemo_thumbnail.png new file mode 100644 index 00000000000..505c02e88e9 Binary files /dev/null and b/src/plugins/studiowelcome/qml/welcomepage/images/effectdemo_thumbnail.png differ diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index a2ac354fa01..35889ce5222 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -163,7 +163,8 @@ public: { const QString projectFile = data(index(row, 0), ProjectModel::FilePathRole).toString(); - ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); + if (QFileInfo::exists(projectFile)) + ProjectExplorer::ProjectExplorerPlugin::openProjectWelcomePage(projectFile); } Q_INVOKABLE int get(int) diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index 843310f2906..714dbe59d3f 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -546,10 +546,10 @@ void SubmitEditorWidget::verifyDescription() "
    " "
  • Avoid very short commit messages.
  • " "
  • Consider the first line as subject (like in email) " - "and keep it shorter than %1 characters.
  • " + "and keep it shorter than %n characters." "
  • After an empty second line, a longer description can be added.
  • " "
  • Describe why the change was done, not how it was done.
  • " - "
").arg(MaxSubjectLength)); + "", nullptr, MaxSubjectLength)); } } diff --git a/src/plugins/vcsbase/submiteditorwidget.ui b/src/plugins/vcsbase/submiteditorwidget.ui index b1ff57522c7..02699ea20ae 100644 --- a/src/plugins/vcsbase/submiteditorwidget.ui +++ b/src/plugins/vcsbase/submiteditorwidget.ui @@ -37,6 +37,9 @@ + + QFrame::NoFrame + true diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index e2185b0a566..5997c83f06d 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -104,10 +104,7 @@ QVersionNumber WebAssemblyEmSdk::version(const FilePath &sdkRoot) return {}; const QString cacheKey = sdkRoot.toString(); if (!emSdkVersionCache()->contains(cacheKey)) { - Environment env; - // Non-Windows: Need python in path (not provided by emsdk), thus use systemEnvironment - if (!HostOsInfo::isWindowsHost()) - env = Environment::systemEnvironment(); + Environment env = Environment::systemEnvironment(); WebAssemblyEmSdk::addToEnvironment(sdkRoot, env); const QString scriptFile = QLatin1String("emcc") + QLatin1String(HostOsInfo::isWindowsHost() ? ".bat" : ""); diff --git a/src/shared/qbs b/src/shared/qbs index a5c9fa92c86..44ef0344723 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit a5c9fa92c86982e0260f691ea27b790748851db6 +Subproject commit 44ef034472337abdb894f76f593da6648f9782d5 diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index 96dd3205bca..19b3a982807 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -43,7 +43,8 @@ namespace ClangBackEnd { template class BuildDependenciesStorage final : public BuildDependenciesStorageInterface { - using ReadStatement = typename Database::ReadStatement; + template + using ReadStatement = typename Database::template ReadStatement; using WriteStatement = typename Database::WriteStatement; public: BuildDependenciesStorage(Database &database) @@ -99,7 +100,7 @@ public: long long fetchLowestLastModifiedTime(FilePathId sourceId) const override { - ReadStatement &statement = getLowestLastModifiedTimeOfDependencies; + auto &statement = getLowestLastModifiedTimeOfDependencies; return statement.template value(sourceId.filePathId).value_or(0); } @@ -143,12 +144,12 @@ public: SourceEntries fetchDependSources(FilePathId sourceId, ProjectPartId projectPartId) const override { return fetchSourceDependenciesStatement - .template values(300, sourceId.filePathId, projectPartId.projectPathId); + .template values(300, sourceId.filePathId, projectPartId.projectPathId); } UsedMacros fetchUsedMacros(FilePathId sourceId) const override { - return fetchUsedMacrosStatement.template values(128, sourceId.filePathId); + return fetchUsedMacrosStatement.template values(128, sourceId.filePathId); } void updatePchCreationTimeStamp(long long pchCreationTimeStamp, ProjectPartId projectPartId) override @@ -191,8 +192,7 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - auto timeStamps = fetchIndexingTimeStampsStatement.template values( - 1024); + auto timeStamps = fetchIndexingTimeStampsStatement.template values(1024); transaction.commit(); @@ -208,7 +208,7 @@ public: Sqlite::DeferredTransaction transaction{database}; auto timeStamps = fetchIncludedIndexingTimeStampsStatement - .template values(1024, sourcePathId.filePathId); + .template values(1024, sourcePathId.filePathId); transaction.commit(); @@ -325,10 +325,12 @@ public: "DELETE FROM newUsedMacros", database }; - mutable ReadStatement getLowestLastModifiedTimeOfDependencies{ - "WITH RECURSIVE sourceIds(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, sourceIds WHERE sourceDependencies.sourceId = sourceIds.sourceId) SELECT min(lastModified) FROM fileStatuses, sourceIds WHERE fileStatuses.sourceId = sourceIds.sourceId", - database - }; + mutable ReadStatement<1> getLowestLastModifiedTimeOfDependencies{ + "WITH RECURSIVE sourceIds(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM " + "sourceDependencies, sourceIds WHERE sourceDependencies.sourceId = sourceIds.sourceId) " + "SELECT min(lastModified) FROM fileStatuses, sourceIds WHERE fileStatuses.sourceId = " + "sourceIds.sourceId", + database}; WriteStatement insertIntoNewSourceDependenciesStatement{ "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)", database @@ -356,13 +358,13 @@ public: "CONFLICT(sourceId, projectPartId) DO UPDATE SET sourceType = ?003, " "hasMissingIncludes = ?004", database}; - mutable ReadStatement fetchPchSourcesStatement{ + mutable ReadStatement<1> fetchPchSourcesStatement{ "SELECT sourceId FROM projectPartsFiles WHERE projectPartId = ? AND sourceType IN (0, 1, " "3, 4) ORDER BY sourceId", database}; - mutable ReadStatement fetchSourcesStatement{ + mutable ReadStatement<1> fetchSourcesStatement{ "SELECT sourceId FROM projectPartsFiles WHERE projectPartId = ? ORDER BY sourceId", database}; - mutable ReadStatement fetchSourceDependenciesStatement{ + mutable ReadStatement<4> fetchSourceDependenciesStatement{ "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " "SELECT dependencySourceId FROM sourceDependencies, " "collectedDependencies WHERE sourceDependencies.sourceId == " @@ -371,16 +373,14 @@ public: "collectedDependencies NATURAL JOIN projectPartsFiles WHERE " "projectPartId = ? ORDER BY sourceId", database}; - mutable ReadStatement fetchProjectPartIdStatement{ - "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", - database - }; + mutable ReadStatement<1> fetchProjectPartIdStatement{ + "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", database}; WriteStatement insertProjectPartNameStatement{ "INSERT INTO projectParts(projectPartName) VALUES (?)", database}; - mutable ReadStatement fetchUsedMacrosStatement{ - "SELECT macroName, sourceId FROM usedMacros WHERE sourceId = ? ORDER BY sourceId, macroName", - database - }; + mutable ReadStatement<2> fetchUsedMacrosStatement{ + "SELECT macroName, sourceId FROM usedMacros WHERE sourceId = ? ORDER BY sourceId, " + "macroName", + database}; WriteStatement updatePchCreationTimeStampStatement{ "UPDATE projectPartsFiles SET pchCreationTimeStamp = ?001 WHERE projectPartId = ?002", database}; @@ -390,16 +390,16 @@ public: "INSERT INTO fileStatuses(sourceId, indexingTimeStamp) VALUES (?001, ?002) ON " "CONFLICT(sourceId) DO UPDATE SET indexingTimeStamp = ?002", database}; - mutable ReadStatement fetchIncludedIndexingTimeStampsStatement{ + mutable ReadStatement<2> fetchIncludedIndexingTimeStampsStatement{ "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT " "dependencySourceId FROM sourceDependencies, collectedDependencies WHERE " "sourceDependencies.sourceId == collectedDependencies.sourceId) SELECT DISTINCT sourceId, " "indexingTimeStamp FROM collectedDependencies NATURAL LEFT JOIN fileStatuses ORDER BY " "sourceId", database}; - mutable ReadStatement fetchIndexingTimeStampsStatement{ + mutable ReadStatement<2> fetchIndexingTimeStampsStatement{ "SELECT sourceId, indexingTimeStamp FROM fileStatuses ORDER BY sourceId", database}; - mutable ReadStatement fetchDependentSourceIdsStatement{ + mutable ReadStatement<1> fetchDependentSourceIdsStatement{ "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT " "sourceDependencies.sourceId FROM sourceDependencies, collectedDependencies WHERE " "sourceDependencies.dependencySourceId == collectedDependencies.sourceId) SELECT sourceId " diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h index 8592757692d..58b3747a573 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h @@ -38,7 +38,8 @@ namespace ClangBackEnd { template class PrecompiledHeaderStorage final : public PrecompiledHeaderStorageInterface { - using ReadStatement = typename Database::ReadStatement; + template + using ReadStatement = typename Database::template ReadStatement; using WriteStatement = typename Database::WriteStatement; public: PrecompiledHeaderStorage(Database &database) @@ -184,7 +185,7 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - auto value = fetchPrecompiledHeadersStatement.template value( + auto value = fetchPrecompiledHeadersStatement.template value( projectPartId.projectPathId); transaction.commit(); @@ -204,7 +205,7 @@ public: try { Sqlite::DeferredTransaction transaction{database}; - auto value = fetchTimeStampsStatement.template value( + auto value = fetchTimeStampsStatement.template value( projectPartId.projectPathId); transaction.commit(); @@ -265,23 +266,22 @@ public: "systemPchPath=NULL,systemPchBuildTime=NULL,projectPchPath=NULL,projectPchBuildTime=NULL " "WHERE projectPartId = ?", database}; - ReadStatement fetchSystemPrecompiledHeaderPathStatement{ + ReadStatement<1> fetchSystemPrecompiledHeaderPathStatement{ "SELECT systemPchPath FROM precompiledHeaders WHERE projectPartId = ?", database}; - mutable ReadStatement fetchPrecompiledHeaderStatement{ + mutable ReadStatement<1> fetchPrecompiledHeaderStatement{ "SELECT ifnull(nullif(projectPchPath, ''), systemPchPath) " "FROM precompiledHeaders WHERE projectPartId = ?", database}; - mutable ReadStatement fetchPrecompiledHeadersStatement{ + mutable ReadStatement<2> fetchPrecompiledHeadersStatement{ "SELECT projectPchPath, systemPchPath FROM precompiledHeaders WHERE projectPartId = ?", database}; - mutable ReadStatement fetchTimeStampsStatement{ + mutable ReadStatement<2> fetchTimeStampsStatement{ "SELECT projectPchBuildTime, systemPchBuildTime FROM precompiledHeaders WHERE " "projectPartId = ?", database}; - mutable ReadStatement fetchAllPchPathsStatement{ + mutable ReadStatement<1> fetchAllPchPathsStatement{ "SELECT DISTINCT systemPchPath FROM precompiledHeaders UNION ALL SELECT " "DISTINCT projectPchPath FROM precompiledHeaders", database}; }; - -} +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 89855b98cba..bc2d96b5f18 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -45,7 +45,8 @@ template class SymbolStorage final : public SymbolStorageInterface { using Database = DatabaseType; - using ReadStatement = typename Database::ReadStatement; + template + using ReadStatement = typename Database::template ReadStatement; using WriteStatement = typename Database::WriteStatement; public: @@ -166,7 +167,7 @@ public: "INSERT OR IGNORE INTO newLocations(temporarySymbolId, line, column, sourceId, " "locationKind) VALUES(?,?,?,?,?)", database}; - ReadStatement selectNewSourceIdsStatement{ + ReadStatement<1> selectNewSourceIdsStatement{ "SELECT DISTINCT sourceId FROM newLocations WHERE NOT EXISTS (SELECT sourceId FROM sources " "WHERE newLocations.sourceId == sources.sourceId)", database}; diff --git a/src/tools/perfparser b/src/tools/perfparser index 6998eeec65a..84180a4bbe9 160000 --- a/src/tools/perfparser +++ b/src/tools/perfparser @@ -1 +1 @@ -Subproject commit 6998eeec65ad30d67495e71dc3e2486c5a390d32 +Subproject commit 84180a4bbe9fad1426b6f6633b3d3b2f8d14d361 diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt index acbebe0fb1d..73f70489e8d 100644 --- a/tests/unit/unittest/CMakeLists.txt +++ b/tests/unit/unittest/CMakeLists.txt @@ -110,12 +110,8 @@ add_qtc_test(unittest GTEST mocksearch.h mocksearchhandle.h mocksearchresult.h - mocksqlitedatabase.h - mocksqlitereadstatement.cpp - mocksqlitereadstatement.h mocksqlitestatement.h mocksqlitetransactionbackend.h - mocksqlitewritestatement.h mocksymbolindexertaskqueue.h mocksymbolindexing.h mocksymbolquery.h diff --git a/tests/unit/unittest/builddependenciesstorage-test.cpp b/tests/unit/unittest/builddependenciesstorage-test.cpp index 125ac526d5e..f39d1dc2bbe 100644 --- a/tests/unit/unittest/builddependenciesstorage-test.cpp +++ b/tests/unit/unittest/builddependenciesstorage-test.cpp @@ -26,7 +26,7 @@ #include "googletest.h" #include "mockfilepathcaching.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include #include @@ -48,37 +48,40 @@ using Sqlite::Database; using Sqlite::Table; using Utils::PathString; -using Storage = ClangBackEnd::BuildDependenciesStorage; +using Storage = ClangBackEnd::BuildDependenciesStorage; class BuildDependenciesStorage : public testing::Test { protected: - NiceMock mockDatabase; - Storage storage{mockDatabase}; - MockSqliteWriteStatement &insertIntoNewUsedMacrosStatement = storage.insertIntoNewUsedMacrosStatement; - MockSqliteWriteStatement &syncNewUsedMacrosStatement =storage.syncNewUsedMacrosStatement; - MockSqliteWriteStatement &deleteOutdatedUsedMacrosStatement = storage.deleteOutdatedUsedMacrosStatement; - MockSqliteWriteStatement &deleteNewUsedMacrosTableStatement = storage.deleteNewUsedMacrosTableStatement; - MockSqliteWriteStatement &insertOrUpdateFileStatusesStatement = storage.insertOrUpdateFileStatusesStatement; - MockSqliteWriteStatement &insertIntoNewSourceDependenciesStatement = storage.insertIntoNewSourceDependenciesStatement; - MockSqliteWriteStatement &syncNewSourceDependenciesStatement = storage.syncNewSourceDependenciesStatement; - MockSqliteWriteStatement &deleteOutdatedSourceDependenciesStatement = storage.deleteOutdatedSourceDependenciesStatement; - MockSqliteWriteStatement &deleteNewSourceDependenciesStatement = storage.deleteNewSourceDependenciesStatement; - MockSqliteReadStatement &getLowestLastModifiedTimeOfDependencies = storage.getLowestLastModifiedTimeOfDependencies; - MockSqliteWriteStatement &insertOrUpdateProjectPartsFilesStatement = storage.insertOrUpdateProjectPartsFilesStatement; - MockSqliteReadStatement &fetchSourceDependenciesStatement = storage.fetchSourceDependenciesStatement; - MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; - MockSqliteReadStatement &fetchUsedMacrosStatement = storage.fetchUsedMacrosStatement; - MockSqliteWriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; - MockSqliteWriteStatement &updatePchCreationTimeStampStatement = storage.updatePchCreationTimeStampStatement; - MockSqliteWriteStatement &deleteAllProjectPartsFilesWithProjectPartNameStatement + NiceMock databaseMock; + template + using ReadStatement = NiceMock::ReadStatement; + using WriteStatement = NiceMock::WriteStatement; + Storage storage{databaseMock}; + WriteStatement &insertIntoNewUsedMacrosStatement = storage.insertIntoNewUsedMacrosStatement; + WriteStatement &syncNewUsedMacrosStatement = storage.syncNewUsedMacrosStatement; + WriteStatement &deleteOutdatedUsedMacrosStatement = storage.deleteOutdatedUsedMacrosStatement; + WriteStatement &deleteNewUsedMacrosTableStatement = storage.deleteNewUsedMacrosTableStatement; + WriteStatement &insertOrUpdateFileStatusesStatement = storage.insertOrUpdateFileStatusesStatement; + WriteStatement &insertIntoNewSourceDependenciesStatement = storage.insertIntoNewSourceDependenciesStatement; + WriteStatement &syncNewSourceDependenciesStatement = storage.syncNewSourceDependenciesStatement; + WriteStatement &deleteOutdatedSourceDependenciesStatement = storage.deleteOutdatedSourceDependenciesStatement; + WriteStatement &deleteNewSourceDependenciesStatement = storage.deleteNewSourceDependenciesStatement; + ReadStatement<1> &getLowestLastModifiedTimeOfDependencies = storage.getLowestLastModifiedTimeOfDependencies; + WriteStatement &insertOrUpdateProjectPartsFilesStatement = storage.insertOrUpdateProjectPartsFilesStatement; + ReadStatement<4> &fetchSourceDependenciesStatement = storage.fetchSourceDependenciesStatement; + ReadStatement<1> &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; + ReadStatement<2> &fetchUsedMacrosStatement = storage.fetchUsedMacrosStatement; + WriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; + WriteStatement &updatePchCreationTimeStampStatement = storage.updatePchCreationTimeStampStatement; + WriteStatement &deleteAllProjectPartsFilesWithProjectPartNameStatement = storage.deleteAllProjectPartsFilesWithProjectPartNameStatement; - MockSqliteReadStatement &fetchPchSourcesStatement = storage.fetchPchSourcesStatement; - MockSqliteReadStatement &fetchSourcesStatement = storage.fetchSourcesStatement; - MockSqliteWriteStatement &inserOrUpdateIndexingTimesStampStatement = storage.inserOrUpdateIndexingTimesStampStatement; - MockSqliteReadStatement &fetchIndexingTimeStampsStatement = storage.fetchIndexingTimeStampsStatement; - MockSqliteReadStatement &fetchIncludedIndexingTimeStampsStatement = storage.fetchIncludedIndexingTimeStampsStatement; - MockSqliteReadStatement &fetchDependentSourceIdsStatement = storage.fetchDependentSourceIdsStatement; + ReadStatement<1> &fetchPchSourcesStatement = storage.fetchPchSourcesStatement; + ReadStatement<1> &fetchSourcesStatement = storage.fetchSourcesStatement; + WriteStatement &inserOrUpdateIndexingTimesStampStatement = storage.inserOrUpdateIndexingTimesStampStatement; + ReadStatement<2> &fetchIndexingTimeStampsStatement = storage.fetchIndexingTimeStampsStatement; + ReadStatement<2> &fetchIncludedIndexingTimeStampsStatement = storage.fetchIncludedIndexingTimeStampsStatement; + ReadStatement<1> &fetchDependentSourceIdsStatement = storage.fetchDependentSourceIdsStatement; }; TEST_F(BuildDependenciesStorage, ConvertStringsToJson) @@ -132,14 +135,24 @@ TEST_F(BuildDependenciesStorage, AddTablesInConstructor) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newUsedMacros(sourceId INTEGER, macroName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newUsedMacros_sourceId_macroName ON newUsedMacros(sourceId, macroName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, dependencySourceId TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId ON newSourceDependencies(sourceId, dependencySourceId)"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(databaseMock, + execute( + Eq("CREATE TEMPORARY TABLE newUsedMacros(sourceId INTEGER, macroName TEXT)"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE INDEX IF NOT EXISTS index_newUsedMacros_sourceId_macroName ON " + "newUsedMacros(sourceId, macroName)"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, " + "dependencySourceId TEXT)"))); + EXPECT_CALL( + databaseMock, + execute( + Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId " + "ON newSourceDependencies(sourceId, dependencySourceId)"))); + EXPECT_CALL(databaseMock, commit()); - Storage storage{mockDatabase}; + Storage storage{databaseMock}; } TEST_F(BuildDependenciesStorage, FetchLowestLastModifiedTimeIfNoModificationTimeExists) @@ -165,8 +178,12 @@ TEST_F(BuildDependenciesStorage, AddNewUsedMacroTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newUsedMacros(sourceId INTEGER, macroName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newUsedMacros_sourceId_macroName ON newUsedMacros(sourceId, macroName)"))); + EXPECT_CALL(databaseMock, + execute( + Eq("CREATE TEMPORARY TABLE newUsedMacros(sourceId INTEGER, macroName TEXT)"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE INDEX IF NOT EXISTS index_newUsedMacros_sourceId_macroName ON " + "newUsedMacros(sourceId, macroName)"))); storage.createNewUsedMacrosTable(); } @@ -175,8 +192,14 @@ TEST_F(BuildDependenciesStorage, AddNewSourceDependenciesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, dependencySourceId TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId ON newSourceDependencies(sourceId, dependencySourceId)"))); + EXPECT_CALL(databaseMock, + execute(Eq("CREATE TEMPORARY TABLE newSourceDependencies(sourceId INTEGER, " + "dependencySourceId TEXT)"))); + EXPECT_CALL( + databaseMock, + execute( + Eq("CREATE INDEX IF NOT EXISTS index_newSourceDependencies_sourceId_dependencySourceId " + "ON newSourceDependencies(sourceId, dependencySourceId)"))); storage.createNewSourceDependenciesTable(); } @@ -200,9 +223,9 @@ TEST_F(BuildDependenciesStorage, UpdatePchCreationTimeStamp) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(updatePchCreationTimeStampStatement, write(TypedEq(101), TypedEq(1))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.updatePchCreationTimeStamp(101, 1); } @@ -255,9 +278,9 @@ TEST_F(BuildDependenciesStorage, FetchPchSourcesCalls) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchPchSourcesStatement, valuesReturnFilePathIds(_, 22)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); auto sources = storage.fetchPchSources(22); } @@ -266,13 +289,13 @@ TEST_F(BuildDependenciesStorage, FetchPchSourcesCallsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchPchSourcesStatement, valuesReturnFilePathIds(_, 22)) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchPchSourcesStatement, valuesReturnFilePathIds(_, 22)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); auto sources = storage.fetchPchSources(22); } @@ -291,13 +314,13 @@ TEST_F(BuildDependenciesStorage, FetchIndexingTimeStampsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024)) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchIndexingTimeStamps(); } @@ -306,12 +329,12 @@ TEST_F(BuildDependenciesStorage, InsertIndexingTimeStampWithoutTransaction) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()).Times(0); + EXPECT_CALL(databaseMock, immediateBegin()).Times(0); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(1), TypedEq(34))); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(2), TypedEq(34))); - EXPECT_CALL(mockDatabase, commit()).Times(0); + EXPECT_CALL(databaseMock, commit()).Times(0); storage.insertOrUpdateIndexingTimeStampsWithoutTransaction({1, 2}, 34); } @@ -320,12 +343,12 @@ TEST_F(BuildDependenciesStorage, InsertIndexingTimeStamp) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(1), TypedEq(34))); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(2), TypedEq(34))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.insertOrUpdateIndexingTimeStamps({1, 2}, 34); } @@ -334,13 +357,13 @@ TEST_F(BuildDependenciesStorage, InsertIndexingTimeStampsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(1), TypedEq(34))); EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq(2), TypedEq(34))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.insertOrUpdateIndexingTimeStamps({1, 2}, 34); } @@ -349,15 +372,15 @@ TEST_F(BuildDependenciesStorage, FetchIncludedIndexingTimeStampsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchIncludedIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024, TypedEq(1))) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchIncludedIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024, TypedEq(1))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchIncludedIndexingTimeStamps(1); } @@ -366,16 +389,16 @@ TEST_F(BuildDependenciesStorage, FetchDependentSourceIdsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq(3))); EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq(2))) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq(3))); EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq(2))); EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq(7))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDependentSourceIds({3, 2, 7}); } diff --git a/tests/unit/unittest/filepathcache-test.cpp b/tests/unit/unittest/filepathcache-test.cpp index 4b43d3924c5..fce075ab46f 100644 --- a/tests/unit/unittest/filepathcache-test.cpp +++ b/tests/unit/unittest/filepathcache-test.cpp @@ -26,7 +26,7 @@ #include "googletest.h" #include "mockfilepathstorage.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include @@ -75,10 +75,10 @@ protected: } protected: - NiceMock mockDatabase; - NiceMock mockStorage{mockDatabase}; + NiceMock databaseMock; + NiceMock mockStorage{databaseMock}; Cache cache{mockStorage}; - NiceMock mockStorageFilled{mockDatabase}; + NiceMock mockStorageFilled{databaseMock}; Cache cacheNotFilled{mockStorageFilled}; }; @@ -402,14 +402,14 @@ TEST_F(FilePathCache, AddFilePathsCalls) Cache cacheFilled{mockStorageFilled}; InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path3/to"))).WillOnce(Return(7)); EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.h"))).WillOnce(Return(99)); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(6, Eq("file2.h"))).WillOnce(Return(106)); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(7, Eq("file.h"))).WillOnce(Return(101)); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.cpp"))).Times(0); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); cacheFilled.addFilePaths( FilePathViews{"/path3/to/file.h", "/path/to/file.h", "/path2/to/file2.h", "/path/to/file.cpp"}); @@ -420,10 +420,10 @@ TEST_F(FilePathCache, DontUseTransactionIfNotAddingFilesInAddFilePathsCalls) Cache cacheFilled{mockStorageFilled}; InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()).Times(0); + EXPECT_CALL(databaseMock, deferredBegin()).Times(0); EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.cpp"))).Times(0); - EXPECT_CALL(mockDatabase, commit()).Times(0); + EXPECT_CALL(databaseMock, commit()).Times(0); cacheFilled.addFilePaths(FilePathViews{"/path/to/file.cpp"}); } @@ -433,10 +433,10 @@ TEST_F(FilePathCache, UseTransactionIfAddingFilesOnlyInAddFilePathsCalls) Cache cacheFilled{mockStorageFilled}; InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(mockStorageFilled, fetchDirectoryIdUnguarded(Eq("/path/to"))).Times(0); EXPECT_CALL(mockStorageFilled, fetchSourceIdUnguarded(5, Eq("file.h"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); cacheFilled.addFilePaths(FilePathViews{"/path/to/file.h"}); } diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index e943ab43dad..b982156bcfa 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -26,17 +26,18 @@ #include "googletest.h" #include "mockmutex.h" -#include "mocksqlitedatabase.h" -#include "mocksqlitereadstatement.h" -#include "mocksqlitewritestatement.h" +#include "sqlitedatabasemock.h" #include #include namespace { -using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory>; +using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory>; using Storage = ClangBackEnd::FilePathStorage; +template +using ReadStatement = NiceMock::ReadStatement; +using WriteStatement = NiceMock::WriteStatement; using ClangBackEnd::Sources::Directory; using ClangBackEnd::Sources::Source; @@ -54,7 +55,7 @@ protected: ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(Utils::SmallStringView("/path/to"))) .WillByDefault(Return(Utils::optional(5))); - ON_CALL(mockDatabase, lastInsertedRowId()) + ON_CALL(databaseMock, lastInsertedRowId()) .WillByDefault(Return(12)); ON_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(_)) .WillByDefault(Return(std::vector{{"/path/to", 1}, {"/other/path", 2}})); @@ -98,17 +99,17 @@ protected: } protected: - NiceMock mockDatabase; - StatementFactory factory{mockDatabase}; - MockSqliteReadStatement &selectDirectoryIdFromDirectoriesByDirectoryPath = factory.selectDirectoryIdFromDirectoriesByDirectoryPath; - MockSqliteReadStatement &selectSourceIdFromSourcesByDirectoryIdAndSourceName = factory.selectSourceIdFromSourcesByDirectoryIdAndSourceName; - MockSqliteReadStatement &selectDirectoryPathFromDirectoriesByDirectoryId = factory.selectDirectoryPathFromDirectoriesByDirectoryId; - MockSqliteReadStatement &selectSourceNameAndDirectoryIdFromSourcesBySourceId = factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId; - MockSqliteReadStatement &selectAllDirectories = factory.selectAllDirectories; - MockSqliteWriteStatement &insertIntoDirectories = factory.insertIntoDirectories; - MockSqliteWriteStatement &insertIntoSources = factory.insertIntoSources; - MockSqliteReadStatement &selectAllSources = factory.selectAllSources; - MockSqliteReadStatement &selectDirectoryIdFromSourcesBySourceId = factory.selectDirectoryIdFromSourcesBySourceId; + NiceMock databaseMock; + StatementFactory factory{databaseMock}; + ReadStatement<1> &selectDirectoryIdFromDirectoriesByDirectoryPath = factory.selectDirectoryIdFromDirectoriesByDirectoryPath; + ReadStatement<1> &selectSourceIdFromSourcesByDirectoryIdAndSourceName = factory.selectSourceIdFromSourcesByDirectoryIdAndSourceName; + ReadStatement<1> &selectDirectoryPathFromDirectoriesByDirectoryId = factory.selectDirectoryPathFromDirectoriesByDirectoryId; + ReadStatement<2> &selectSourceNameAndDirectoryIdFromSourcesBySourceId = factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId; + ReadStatement<2> &selectAllDirectories = factory.selectAllDirectories; + WriteStatement &insertIntoDirectories = factory.insertIntoDirectories; + WriteStatement &insertIntoSources = factory.insertIntoSources; + ReadStatement<3> &selectAllSources = factory.selectAllSources; + ReadStatement<1> &selectDirectoryIdFromSourcesBySourceId = factory.selectDirectoryIdFromSourcesBySourceId; Storage storage{factory}; }; @@ -229,10 +230,10 @@ TEST_F(FilePathStorage, CallSelectForFetchingDirectoryIdForKnownPath) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/path/to"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryId("/path/to"); } @@ -241,10 +242,10 @@ TEST_F(FilePathStorage, CallSelectForFetchingSourceIdForKnownPath) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("file.h"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceId(5, "file.h"); } @@ -267,11 +268,11 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdForUnknownPath) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/some/not/known/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq("/some/not/known/path"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryId("/some/not/known/path"); } @@ -280,12 +281,12 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceIdForUnknownEntry) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("unknownfile.h"))); EXPECT_CALL(insertIntoSources, write(TypedEq(5), TypedEq("unknownfile.h"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceId(5, "unknownfile.h"); } @@ -294,13 +295,13 @@ TEST_F(FilePathStorage, RestartFetchDirectoryIDIfTheStatementIsBusyInBeginBecaus { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq("/other/unknow/path"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryId("/other/unknow/path"); } @@ -310,17 +311,17 @@ TEST_F(FilePathStorage, { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq("/other/unknow/path"))) .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq("/other/unknow/path"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryId("/other/unknow/path"); } @@ -329,16 +330,16 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheInd { InSequence s; - EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(databaseMock,deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/other/unknow/path"))); EXPECT_CALL(insertIntoDirectories, write(TypedEq("/other/unknow/path"))) .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock,deferredBegin()); EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(TypedEq("/other/unknow/path"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryId("/other/unknow/path"); } @@ -347,14 +348,14 @@ TEST_F(FilePathStorage, RestartFetchSourceIdIfTheStatementIsBusyInBeginBecauseTh { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); EXPECT_CALL(insertIntoSources, write(TypedEq(5), TypedEq("otherunknownfile.h"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); } @@ -364,19 +365,19 @@ TEST_F(FilePathStorage, { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); EXPECT_CALL(insertIntoSources, write(TypedEq(5), TypedEq("otherunknownfile.h"))) .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); EXPECT_CALL(insertIntoSources, write(TypedEq(5), TypedEq("otherunknownfile.h"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); } @@ -385,18 +386,18 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheIndexIsC { InSequence s; - EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(databaseMock,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); EXPECT_CALL(insertIntoSources, write(TypedEq(5), TypedEq("otherunknownfile.h"))) .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase,deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))) .WillOnce(Return(Utils::optional(42))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); } @@ -417,27 +418,27 @@ TEST_F(FilePathStorage, SelectAllSources) TEST_F(FilePathStorage, CallSelectAllDirectories) { - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(256)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchAllDirectories(); } TEST_F(FilePathStorage, CallSelectAllSources) { - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(8192)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchAllSources(); } TEST_F(FilePathStorage, CallValueForFetchDirectoryPathForId) { - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(5)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchDirectoryPath(5); } @@ -456,9 +457,9 @@ TEST_F(FilePathStorage, ThrowAsFetchingDirectoryPathForNonExistingId) TEST_F(FilePathStorage, CallValueForFetchSoureNameForId) { - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(42)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchSourceNameAndDirectoryId(42); } @@ -480,15 +481,15 @@ TEST_F(FilePathStorage, RestartFetchSourceNameIfTheStatementIsBusyInBegin) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, unlock()); - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, unlock()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId, valueReturnSourceNameAndDirectoryId(42)); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchSourceNameAndDirectoryId(42); } @@ -497,15 +498,15 @@ TEST_F(FilePathStorage, RestartFetchDirectoryPathIfTheStatementIsBusyInBegin) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, unlock()); - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, unlock()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(5)); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchDirectoryPath(5); } @@ -514,15 +515,15 @@ TEST_F(FilePathStorage, RestartFetchAllDirectoriesIfBeginIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, unlock()); - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, unlock()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(256)); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchAllDirectories(); } @@ -531,15 +532,15 @@ TEST_F(FilePathStorage, RestartFetchAllSourcesIfBeginIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, unlock()); - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, unlock()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(8192)); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchAllSources(); } @@ -560,11 +561,11 @@ TEST_F(FilePathStorage, FetchDirectoryIdCalls) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq(42))); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchDirectoryId(42); } @@ -573,15 +574,15 @@ TEST_F(FilePathStorage, FetchDirectoryIdCallsDatabaseIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()).Times(0); - EXPECT_CALL(mockDatabase, unlock()); - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(databaseMock, rollback()).Times(0); + EXPECT_CALL(databaseMock, unlock()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq(42))); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, unlock()); storage.fetchDirectoryId(42); } @@ -590,11 +591,11 @@ TEST_F(FilePathStorage, FetchDirectoryIdCallsThrows) { InSequence s; - EXPECT_CALL(mockDatabase, lock()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, lock()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq(41))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, unlock()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, unlock()); ASSERT_ANY_THROW(storage.fetchDirectoryId(41)); } diff --git a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp index 42c1d0541a3..0fb06aa87a8 100644 --- a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp @@ -26,21 +26,19 @@ #include "googletest.h" #include "mockmutex.h" -#include "mocksqlitedatabase.h" -#include "mocksqlitereadstatement.h" -#include "mocksqlitewritestatement.h" +#include "sqlitedatabasemock.h" #include namespace { -using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory>; +using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory>; class FilePathStorageSqliteStatementFactory : public testing::Test { protected: - NiceMock mockDatabase; - StatementFactory factory{mockDatabase}; + NiceMock databaseMock; + StatementFactory factory{databaseMock}; }; TEST_F(FilePathStorageSqliteStatementFactory, SelectDirectoryIdFromDirectoriesByDirectoryPath) diff --git a/tests/unit/unittest/imagecachestorage-test.cpp b/tests/unit/unittest/imagecachestorage-test.cpp index d1246452a24..50995e6c407 100644 --- a/tests/unit/unittest/imagecachestorage-test.cpp +++ b/tests/unit/unittest/imagecachestorage-test.cpp @@ -55,14 +55,15 @@ MATCHER_P2(IsIconEntry, class ImageCacheStorageTest : public testing::Test { protected: - using ReadStatement = QmlDesigner::ImageCacheStorage::ReadStatement; + template + using ReadStatement = QmlDesigner::ImageCacheStorage::ReadStatement; using WriteStatement = QmlDesigner::ImageCacheStorage::WriteStatement; NiceMock databaseMock; QmlDesigner::ImageCacheStorage storage{databaseMock}; - ReadStatement &selectImageStatement = storage.selectImageStatement; - ReadStatement &selectSmallImageStatement = storage.selectSmallImageStatement; - ReadStatement &selectIconStatement = storage.selectIconStatement; + ReadStatement<1> &selectImageStatement = storage.selectImageStatement; + ReadStatement<1> &selectSmallImageStatement = storage.selectSmallImageStatement; + ReadStatement<1> &selectIconStatement = storage.selectIconStatement; WriteStatement &upsertImageStatement = storage.upsertImageStatement; WriteStatement &upsertIconStatement = storage.upsertIconStatement; QImage image1{10, 10, QImage::Format_ARGB32}; diff --git a/tests/unit/unittest/lastchangedrowid-test.cpp b/tests/unit/unittest/lastchangedrowid-test.cpp index aee2d187e35..2ceb8b1731c 100644 --- a/tests/unit/unittest/lastchangedrowid-test.cpp +++ b/tests/unit/unittest/lastchangedrowid-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include @@ -34,7 +34,7 @@ namespace { class LastChangedRowId : public testing::Test { protected: - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; Sqlite::LastChangedRowId<1> lastRowId{mockSqliteDatabase, "main", "foo"}; }; @@ -112,7 +112,7 @@ TEST_F(LastChangedRowId, TakeLastRowIdResetsRowIdToMinusOne) class LastChangedRowIdWithTwoTables : public testing::Test { protected: - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; Sqlite::LastChangedRowId<2> lastRowId{mockSqliteDatabase, "main", "foo", "bar"}; }; @@ -197,7 +197,7 @@ TEST_F(LastChangedRowIdWithTwoTables, TakeLastRowIdResetsRowIdToMinusOne) class LastChangedRowIdWithThreeTables : public testing::Test { protected: - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; Sqlite::LastChangedRowId<3> lastRowId{mockSqliteDatabase, "main", "foo", "bar", "too"}; }; @@ -290,7 +290,7 @@ TEST_F(LastChangedRowIdWithThreeTables, TakeLastRowIdResetsRowIdToMinusOne) class LastChangedRowIdWithNoDatabaseAndTable : public testing::Test { protected: - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; Sqlite::LastChangedRowId<> lastRowId{mockSqliteDatabase}; }; @@ -350,7 +350,7 @@ TEST_F(LastChangedRowIdWithNoDatabaseAndTable, TakeLastRowIdResetsRowIdToMinusOn class LastChangedRowIdWithNoTable : public testing::Test { protected: - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; Sqlite::LastChangedRowId<> lastRowId{mockSqliteDatabase, "main"}; }; diff --git a/tests/unit/unittest/mockfilepathstorage.h b/tests/unit/unittest/mockfilepathstorage.h index cc6cfa07c7b..0ea6c1b16d7 100644 --- a/tests/unit/unittest/mockfilepathstorage.h +++ b/tests/unit/unittest/mockfilepathstorage.h @@ -27,15 +27,15 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include class MockFilePathStorage { public: - MockFilePathStorage(MockSqliteDatabase &mockDatabase) - : mockDatabase{mockDatabase} + MockFilePathStorage(SqliteDatabaseMock &databaseMock) + : databaseMock{databaseMock} {} MOCK_METHOD1(fetchDirectoryId, int(Utils::SmallStringView directoryPath)); @@ -50,8 +50,8 @@ public: MOCK_METHOD0(fetchAllDirectories, std::vector()); MOCK_METHOD0(fetchAllSources, std::vector()); - MockSqliteDatabase &database() { return mockDatabase; } + SqliteDatabaseMock &database() { return databaseMock; } - MockSqliteDatabase &mockDatabase; + SqliteDatabaseMock &databaseMock; }; diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h deleted file mode 100644 index 7a4a8b9e75e..00000000000 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "googletest.h" - -#include "mocksqlitereadstatement.h" -#include "mocksqlitetransactionbackend.h" -#include "mocksqlitewritestatement.h" - -#include -#include -#include - -#include - -class MockSqliteDatabase : public MockSqliteTransactionBackend, public Sqlite::DatabaseInterface -{ -public: - using ReadStatement = NiceMock; - using WriteStatement = NiceMock; - - MOCK_METHOD1(execute, - void (Utils::SmallStringView sqlStatement)); - - MOCK_CONST_METHOD0(lastInsertedRowId, - int64_t ()); - - MOCK_CONST_METHOD1(setLastInsertedRowId, - void (int64_t)); - - MOCK_CONST_METHOD0(isInitialized, - bool ()); - - MOCK_METHOD1(setIsInitialized, - void (bool)); - - MOCK_METHOD0(walCheckpointFull, void()); - - MOCK_METHOD2(setUpdateHook, - void(void *object, - void (*)(void *object, int, char const *database, char const *, long long rowId))); - - MOCK_METHOD0(resetUpdateHook, void()); - - MOCK_METHOD0(applyAndUpdateSessions, void()); - - MOCK_METHOD1(setAttachedTables, void(const Utils::SmallStringVector &tables)); -}; - diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp deleted file mode 100644 index 1f5bc53759b..00000000000 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#include "mocksqlitereadstatement.h" - -template <> -SourceLocations -MockSqliteReadStatement::values(std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column) -{ - return valuesReturnSourceLocations(reserveSize, sourceId, line, column); -} - -template <> -CppTools::Usages -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column) -{ - return valuesReturnSourceUsages(reserveSize, sourceId, line, column); -} - -template<> -CppTools::Usages MockSqliteReadStatement::values(std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column, - const int &locationKind) -{ - return valuesReturnSourceUsages(reserveSize, sourceId, line, column, locationKind); -} - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &symbolKind, - const Utils::SmallStringView &searchTerm) -{ - return valuesReturnSymbols(reserveSize, symbolKind, searchTerm); -} - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &symbolKind1, - const int &symbolKind2, - const Utils::SmallStringView &searchTerm) -{ - return valuesReturnSymbols(reserveSize, symbolKind1, symbolKind2, searchTerm); - -} - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &symbolKind1, - const int &symbolKind2, - const int &symbolKind3, - const Utils::SmallStringView &searchTerm) -{ - return valuesReturnSymbols(reserveSize, symbolKind1, symbolKind2, symbolKind3, searchTerm); - -} - -template <> -UsedMacros -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &sourceId) -{ - return valuesReturnUsedMacros(reserveSize, sourceId); -} - -template<> -FilePathIds MockSqliteReadStatement::values(std::size_t reserveSize, - const int &projectPartId) -{ - return valuesReturnFilePathIds(reserveSize, projectPartId); -} - -template<> -ClangBackEnd::FilePaths MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnFilePaths(reserveSize); -} - -template <> -std::vector MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnStdVectorDirectory(reserveSize); -} - -template<> -std::vector MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnStdVectorSource(reserveSize); -} - -template<> -ProjectPartNameIds MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnProjectPartNameIds(reserveSize); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::SmallStringView &text) -{ - return valueReturnInt32(text); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::PathString &text) -{ - return valueReturnInt32(text); -} - -template<> -Utils::optional MockSqliteReadStatement::value( - const Utils::SmallStringView &text) -{ - return valueReturnProjectPartId(text); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const int &directoryId, const Utils::SmallStringView &text) -{ - return valueReturnInt32(directoryId, text); -} - -template<> -Utils::optional MockSqliteReadStatement::value(const int &value) -{ - return valueReturnInt32(value); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const int &sourceId) -{ - return valueReturnInt64(sourceId); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const int &directoryId) -{ - return valueReturnPathString(directoryId); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::SmallStringView &path) -{ - return valueReturnPathString(path); -} - -template<> -Utils::optional MockSqliteReadStatement::value( - const int &path) -{ - return valueReturnFilePath(path); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const int& sourceId) -{ - return valueReturnProjectPartArtefact(sourceId); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::SmallStringView &projectPartName) -{ - return valueReturnProjectPartArtefact(projectPartName); -} - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &id) -{ - return valueReturnProjectPartContainer(id); -} - -template<> -ClangBackEnd::ProjectPartContainers MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnProjectPartContainers(reserveSize); -} - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &projectPartId) -{ - return valueReturnProjectPartPch(projectPartId); -} - -template<> -Utils::optional MockSqliteReadStatement::value( - const int &projectPartId) -{ - return valueReturnPchPaths(projectPartId); -} - -template<> -Utils::optional MockSqliteReadStatement::value(const int &sourceId) -{ - return valueReturnSmallString(sourceId); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const long long &symbolId, const int &locationKind) -{ - return valueReturnSourceLocation(symbolId, locationKind); -} - -template<> -SourceEntries MockSqliteReadStatement::values(std::size_t reserveSize, - const int &filePathId, - const int &projectPartId) -{ - return valuesReturnSourceEntries(reserveSize, filePathId, projectPartId); -} - -template<> -SourceTimeStamps MockSqliteReadStatement::values(std::size_t reserveSize) -{ - return valuesReturnSourceTimeStamps(reserveSize); -} - -template<> -SourceTimeStamps MockSqliteReadStatement::values(std::size_t reserveSize, - const int &sourcePathId) -{ - return valuesReturnSourceTimeStamps(reserveSize, sourcePathId); -} - -template <> -Utils::optional -MockSqliteReadStatement::value(const int &id) -{ - return valueReturnSourceNameAndDirectoryId(id); -} - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &projectPartId) -{ - return valuesReturnPrecompiledHeaderTimeStamps(projectPartId); -} diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h deleted file mode 100644 index 11a7b126e57..00000000000 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ /dev/null @@ -1,334 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "googletest.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include - -using ClangBackEnd::FilePathIds; -using ClangBackEnd::SourceEntries; -using ClangBackEnd::SourceEntry; -using ClangBackEnd::SourceTimeStamp; -using ClangBackEnd::SourceTimeStamps; -using ClangRefactoring::SourceLocation; -using ClangRefactoring::SourceLocations; -using std::int64_t; -namespace Sources = ClangBackEnd::Sources; -using ClangBackEnd::PrecompiledHeaderTimeStamps; -using ClangBackEnd::UsedMacros; -using ClangBackEnd::Internal::ProjectPartNameId; -using ClangBackEnd::Internal::ProjectPartNameIds; -using ClangRefactoring::Symbol; -using ClangRefactoring::Symbols; - -class MockSqliteDatabase; - -class MockSqliteReadStatement -{ -public: - MockSqliteReadStatement() = default; - MockSqliteReadStatement(Utils::SmallStringView sqlStatement, MockSqliteDatabase &) - : sqlStatement(sqlStatement) - {} - - MOCK_METHOD4(valuesReturnSourceLocations, - SourceLocations(std::size_t, int, int, int)); - - MOCK_METHOD4(valuesReturnSourceUsages, CppTools::Usages(std::size_t, int, int, int)); - - MOCK_METHOD5(valuesReturnSourceUsages, CppTools::Usages(std::size_t, int, int, int, int)); - - MOCK_METHOD1(valuesReturnStdVectorDirectory, - std::vector(std::size_t)); - - MOCK_METHOD1(valuesReturnStdVectorSource, - std::vector(std::size_t)); - - MOCK_METHOD3(valuesReturnSourceEntries, - SourceEntries(std::size_t, int, int)); - - MOCK_METHOD2(valuesReturnUsedMacros, UsedMacros(std::size_t, int)); - - MOCK_METHOD2(valuesReturnFilePathIds, FilePathIds(std::size_t, int)); - - MOCK_METHOD1(valuesReturnProjectPartNameIds, ProjectPartNameIds(std::size_t)); - - MOCK_METHOD1(valueReturnInt32, Utils::optional(Utils::SmallStringView)); - - MOCK_METHOD2(valueReturnInt32, Utils::optional(int, Utils::SmallStringView)); - - MOCK_METHOD1(valueReturnInt32, Utils::optional(int)); - - MOCK_METHOD1(valueReturnInt64, Utils::optional(int)); - - MOCK_METHOD1(valueReturnPathString, - Utils::optional(int)); - - MOCK_METHOD1(valueReturnPathString, - Utils::optional(Utils::SmallStringView)); - - MOCK_METHOD1(valueReturnFilePath, Utils::optional(int)); - - MOCK_METHOD1(valuesReturnFilePaths, ClangBackEnd::FilePaths(std::size_t)); - - MOCK_METHOD1(valueReturnSmallString, - Utils::optional(int)); - - MOCK_METHOD1(valueReturnSourceNameAndDirectoryId, - Utils::optional(int)); - - MOCK_METHOD1(valueReturnProjectPartArtefact, - Utils::optional(int)); - - MOCK_METHOD1(valueReturnProjectPartArtefact, - Utils::optional(Utils::SmallStringView)); - MOCK_METHOD1(valuesReturnProjectPartArtefacts, ClangBackEnd::ProjectPartArtefacts(std::size_t)); - MOCK_METHOD1(valueReturnProjectPartContainer, - Utils::optional(int)); - MOCK_METHOD1(valuesReturnProjectPartContainers, ClangBackEnd::ProjectPartContainers(std::size_t)); - MOCK_METHOD1(valueReturnProjectPartPch, Utils::optional(int)); - - MOCK_METHOD1(valueReturnPchPaths, Utils::optional(int)); - - MOCK_METHOD3(valuesReturnSymbols, Symbols(std::size_t, int, Utils::SmallStringView)); - - MOCK_METHOD4(valuesReturnSymbols, - Symbols(std::size_t, int, int, Utils::SmallStringView)); - - MOCK_METHOD5(valuesReturnSymbols, - Symbols(std::size_t, int, int, int, Utils::SmallStringView)); - - MOCK_METHOD2(valueReturnSourceLocation, - SourceLocation(long long, int)); - - MOCK_METHOD1(valueReturnProjectPartId, - Utils::optional(Utils::SmallStringView)); - - MOCK_METHOD1(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t)); - MOCK_METHOD2(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t, int sourcePathId)); - - MOCK_METHOD1(valuesReturnPrecompiledHeaderTimeStamps, - PrecompiledHeaderTimeStamps(int projectPartId)); - - template - std::vector values(std::size_t reserveSize, const QueryType &... queryValues); - - template - std::vector values(std::size_t reserveSize); - - template class QueryContainerType, - typename QueryElementType> - std::vector values(std::size_t reserveSize, - const QueryContainerType &queryValues); - - template - Utils::optional value(const QueryTypes&... queryValues); - -public: - Utils::SmallString sqlStatement; -}; - -template <> -SourceLocations -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column); - -template <> -CppTools::Usages -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column); - -template<> -CppTools::Usages MockSqliteReadStatement::values(std::size_t reserveSize, - const int &sourceId, - const int &line, - const int &column, - const int &locationKind); - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int&, - const Utils::SmallStringView&); - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int&, - const int&, - const Utils::SmallStringView&); - -template <> -Symbols -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int&, - const int&, - const int&, - const Utils::SmallStringView&); - -template <> -UsedMacros -MockSqliteReadStatement::values( - std::size_t reserveSize, - const int &sourceId); - -template<> -FilePathIds MockSqliteReadStatement::values(std::size_t reserveSize, - const int &projectPartId); - -template<> -ClangBackEnd::FilePaths MockSqliteReadStatement::values(std::size_t reserveSize); - -template <> -std::vector MockSqliteReadStatement::values(std::size_t reserveSize); - -template<> -std::vector MockSqliteReadStatement::values(std::size_t reserveSize); - -template<> -ProjectPartNameIds MockSqliteReadStatement::values(std::size_t reserveSize); - -template<> -Utils::optional MockSqliteReadStatement::value(const Utils::SmallStringView &); - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::PathString&); - -template<> -Utils::optional MockSqliteReadStatement::value( - const Utils::SmallStringView &); - -template<> -Utils::optional MockSqliteReadStatement::value( - const int &); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&, const Utils::SmallStringView&); - -template<> -Utils::optional MockSqliteReadStatement::value(const int &); - -template <> -Utils::optional -MockSqliteReadStatement::value(const ClangBackEnd::FilePathId&); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&); - -template <> -Utils::optional -MockSqliteReadStatement::value(const Utils::SmallStringView&); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&); - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &); - -template<> -Utils::optional MockSqliteReadStatement::value( - const int &); - -template<> -ClangBackEnd::ProjectPartContainers MockSqliteReadStatement::values(std::size_t reserveSize); - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&); - -template <> -Utils::optional -MockSqliteReadStatement::value(const long long &symbolId, const int &locationKind); - -template<> -SourceEntries MockSqliteReadStatement::values(std::size_t reserveSize, - const int &, - const int &); - -template<> -SourceTimeStamps MockSqliteReadStatement::values(std::size_t reserveSize); - -template<> -SourceTimeStamps MockSqliteReadStatement::values(std::size_t reserveSize, - const int &sourcePathId); - -template <> -Utils::optional -MockSqliteReadStatement::value(const int&); - -template<> -Utils::optional -MockSqliteReadStatement::value(const int &); diff --git a/tests/unit/unittest/mocksqlitestatement.h b/tests/unit/unittest/mocksqlitestatement.h index 141eb9520ba..ff556a9a4d6 100644 --- a/tests/unit/unittest/mocksqlitestatement.h +++ b/tests/unit/unittest/mocksqlitestatement.h @@ -58,6 +58,8 @@ public: MOCK_METHOD1(prepare, void(Utils::SmallStringView sqlStatement)); MOCK_METHOD1(checkColumnCount, void(int)); + + MOCK_CONST_METHOD0(isReadOnlyStatement, bool()); }; template<> @@ -96,13 +98,12 @@ Utils::PathString BaseMockSqliteStatement::fetchValue(int col return fetchPathStringValue(column); } -class MockSqliteStatement : public Sqlite::StatementImplementation> +template +class MockSqliteStatement + : public Sqlite::StatementImplementation, ResultCount> { public: - explicit MockSqliteStatement() - : Sqlite::StatementImplementation>() - {} - + explicit MockSqliteStatement() {} protected: void checkIsWritableStatement(); diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h deleted file mode 100644 index 329c5f7f39a..00000000000 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ /dev/null @@ -1,118 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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. -** -****************************************************************************/ - -#pragma once - -#include "googletest.h" - -#include - -class MockSqliteDatabase; - -class MockSqliteWriteStatement -{ -public: - MockSqliteWriteStatement() = default; - MockSqliteWriteStatement(Utils::SmallStringView sqlStatement, MockSqliteDatabase &) - : sqlStatement(sqlStatement) - {} - - MOCK_METHOD0(execute, - void ()); - - MOCK_METHOD2(bind, void(int, Utils::SmallStringView)); - - MOCK_METHOD2(bindValues, - void (Utils::SmallStringView, Utils::SmallStringView)); - - MOCK_METHOD4(write, - void (uint, Utils::SmallStringView, Utils::SmallStringView, uint)); - - MOCK_METHOD4(write, - void (uint, uint, uint, uint)); - - MOCK_METHOD4(write, - void (long long, int, int, int)); - - MOCK_METHOD5(write, - void (long long, int, int, int, int)); - - MOCK_METHOD2(write, void(uint, Utils::SmallStringView)); - - MOCK_METHOD2(write, void(int, Utils::SmallStringView)); - - MOCK_METHOD2(write, void(Utils::SmallStringView, Utils::SmallStringView)); - - MOCK_METHOD3(write, void(int, Utils::SmallStringView, long long)); - - MOCK_METHOD3(write, - void (Utils::SmallStringView, Utils::SmallStringView, Utils::SmallStringView)); - - MOCK_METHOD4(write, - void (Utils::SmallStringView, - Utils::SmallStringView, - Utils::SmallStringView, - Utils::SmallStringView)); - - MOCK_METHOD8(write, - void(int, - Utils::SmallStringView, - Utils::SmallStringView, - Utils::SmallStringView, - Utils::SmallStringView, - int, - int, - int)); - - MOCK_METHOD1(write, - void (Utils::SmallStringView)); - - MOCK_METHOD1(write, - void (long long)); - - MOCK_METHOD1(write, - void (int)); - - MOCK_METHOD2(write, void(int, long long)); - - MOCK_METHOD2(write, - void (int, int)); - - MOCK_METHOD3(write, - void (uint, uint, uint)); - - MOCK_METHOD3(write, void(int, off_t, time_t)); - - MOCK_METHOD2(write, - void (uint, uint)); - - MOCK_METHOD2(write, - void (uchar, int)); - MOCK_METHOD4(write, void(int, int, uchar, uchar)); - MOCK_METHOD2(write, - void (long long, int)); - MOCK_METHOD2(write, void(long long, Utils::SmallStringView)); - Utils::SmallString sqlStatement; -}; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index a1743897358..ae5c0f775ad 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -27,7 +27,7 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include diff --git a/tests/unit/unittest/precompiledheaderstorage-test.cpp b/tests/unit/unittest/precompiledheaderstorage-test.cpp index 77574a28b91..d388f5fb437 100644 --- a/tests/unit/unittest/precompiledheaderstorage-test.cpp +++ b/tests/unit/unittest/precompiledheaderstorage-test.cpp @@ -24,7 +24,7 @@ ****************************************************************************/ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include #include @@ -35,25 +35,28 @@ namespace { -using Storage = ClangBackEnd::PrecompiledHeaderStorage>; +using Storage = ClangBackEnd::PrecompiledHeaderStorage>; +template +using ReadStatement = NiceMock::ReadStatement; +using WriteStatement = NiceMock::WriteStatement; class PrecompiledHeaderStorage : public testing::Test { protected: - NiceMock database; + NiceMock database; Storage storage{database}; - MockSqliteWriteStatement &insertProjectPrecompiledHeaderStatement = storage.insertProjectPrecompiledHeaderStatement; - MockSqliteWriteStatement &deleteProjectPrecompiledHeaderStatement = storage.deleteProjectPrecompiledHeaderStatement; - MockSqliteWriteStatement &deleteProjectPrecompiledHeaderPathAndSetBuildTimeStatement + WriteStatement &insertProjectPrecompiledHeaderStatement = storage.insertProjectPrecompiledHeaderStatement; + WriteStatement &deleteProjectPrecompiledHeaderStatement = storage.deleteProjectPrecompiledHeaderStatement; + WriteStatement &deleteProjectPrecompiledHeaderPathAndSetBuildTimeStatement = storage.deleteProjectPrecompiledHeaderPathAndSetBuildTimeStatement; - MockSqliteWriteStatement &insertSystemPrecompiledHeaderStatement = storage.insertSystemPrecompiledHeaderStatement; - MockSqliteWriteStatement &deleteSystemPrecompiledHeaderStatement = storage.deleteSystemPrecompiledHeaderStatement; - MockSqliteWriteStatement &deleteSystemAndProjectPrecompiledHeaderStatement = storage.deleteSystemAndProjectPrecompiledHeaderStatement; - MockSqliteReadStatement &fetchSystemPrecompiledHeaderPathStatement = storage.fetchSystemPrecompiledHeaderPathStatement; - MockSqliteReadStatement &fetchPrecompiledHeaderStatement = storage.fetchPrecompiledHeaderStatement; - MockSqliteReadStatement &fetchPrecompiledHeadersStatement = storage.fetchPrecompiledHeadersStatement; - MockSqliteReadStatement &fetchTimeStampsStatement = storage.fetchTimeStampsStatement; - MockSqliteReadStatement &fetchAllPchPathsStatement = storage.fetchAllPchPathsStatement; + WriteStatement &insertSystemPrecompiledHeaderStatement = storage.insertSystemPrecompiledHeaderStatement; + WriteStatement &deleteSystemPrecompiledHeaderStatement = storage.deleteSystemPrecompiledHeaderStatement; + WriteStatement &deleteSystemAndProjectPrecompiledHeaderStatement = storage.deleteSystemAndProjectPrecompiledHeaderStatement; + ReadStatement<1> &fetchSystemPrecompiledHeaderPathStatement = storage.fetchSystemPrecompiledHeaderPathStatement; + ReadStatement<1> &fetchPrecompiledHeaderStatement = storage.fetchPrecompiledHeaderStatement; + ReadStatement<2> &fetchPrecompiledHeadersStatement = storage.fetchPrecompiledHeadersStatement; + ReadStatement<2> &fetchTimeStampsStatement = storage.fetchTimeStampsStatement; + ReadStatement<1> &fetchAllPchPathsStatement = storage.fetchAllPchPathsStatement; }; TEST_F(PrecompiledHeaderStorage, UseTransaction) diff --git a/tests/unit/unittest/projectpartsstorage-test.cpp b/tests/unit/unittest/projectpartsstorage-test.cpp index b67cd5a37c4..1039f55d35b 100644 --- a/tests/unit/unittest/projectpartsstorage-test.cpp +++ b/tests/unit/unittest/projectpartsstorage-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include #include @@ -72,7 +72,10 @@ protected: class ProjectPartsStorage : public testing::Test, public Data { - using Storage = ClangBackEnd::ProjectPartsStorage; + using Storage = ClangBackEnd::ProjectPartsStorage; + template + using ReadStatement = NiceMock::ReadStatement; + using WriteStatement = NiceMock::WriteStatement; protected: ProjectPartsStorage() @@ -90,26 +93,25 @@ protected: ON_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(_, Eq(2))) .WillByDefault(Return(projectPart2.sourcePathIds)); } - NiceMock mockDatabase; - Storage storage{mockDatabase}; - MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; - MockSqliteWriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; - MockSqliteReadStatement &fetchProjectPartNameStatement = storage.fetchProjectPartNameStatement; - MockSqliteReadStatement &fetchProjectPartsStatement = storage.fetchProjectPartsStatement; - MockSqliteReadStatement &fetchProjectPartByIdStatement = storage.fetchProjectPartByIdStatement; - MockSqliteWriteStatement &updateProjectPartStatement = storage.updateProjectPartStatement; - MockSqliteReadStatement &getProjectPartArtefactsBySourceId = storage.getProjectPartArtefactsBySourceId; - MockSqliteReadStatement &getProjectPartArtefactsByProjectPartId = storage.getProjectPartArtefactsByProjectPartId; - MockSqliteWriteStatement &deleteProjectPartsHeadersByIdStatement = storage.deleteProjectPartsHeadersByIdStatement; - MockSqliteWriteStatement &deleteProjectPartsSourcesByIdStatement = storage.deleteProjectPartsSourcesByIdStatement; - MockSqliteWriteStatement &insertProjectPartsHeadersStatement = storage.insertProjectPartsHeadersStatement; - MockSqliteWriteStatement &insertProjectPartsSourcesStatement = storage.insertProjectPartsSourcesStatement; - MockSqliteReadStatement &fetchProjectPartsHeadersByIdStatement = storage.fetchProjectPartsHeadersByIdStatement; - MockSqliteReadStatement &fetchProjectPartsSourcesByIdStatement = storage.fetchProjectPartsSourcesByIdStatement; - MockSqliteReadStatement &fetchProjectPrecompiledHeaderPathStatement = storage.fetchProjectPrecompiledHeaderBuildTimeStatement; - MockSqliteReadStatement &fetchProjectPrecompiledHeaderBuildTimeStatement = storage.fetchProjectPrecompiledHeaderBuildTimeStatement; - MockSqliteWriteStatement &resetDependentIndexingTimeStampsStatement = storage.resetDependentIndexingTimeStampsStatement; - MockSqliteReadStatement &fetchAllProjectPartNamesAndIdsStatement = storage.fetchAllProjectPartNamesAndIdsStatement; + NiceMock databaseMock; + Storage storage{databaseMock}; + ReadStatement<1> &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; + WriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; + ReadStatement<1> &fetchProjectPartNameStatement = storage.fetchProjectPartNameStatement; + ReadStatement<8> &fetchProjectPartsStatement = storage.fetchProjectPartsStatement; + ReadStatement<8> &fetchProjectPartByIdStatement = storage.fetchProjectPartByIdStatement; + WriteStatement &updateProjectPartStatement = storage.updateProjectPartStatement; + ReadStatement<8> &getProjectPartArtefactsBySourceId = storage.getProjectPartArtefactsBySourceId; + ReadStatement<8> &getProjectPartArtefactsByProjectPartId = storage.getProjectPartArtefactsByProjectPartId; + WriteStatement &deleteProjectPartsHeadersByIdStatement = storage.deleteProjectPartsHeadersByIdStatement; + WriteStatement &deleteProjectPartsSourcesByIdStatement = storage.deleteProjectPartsSourcesByIdStatement; + WriteStatement &insertProjectPartsHeadersStatement = storage.insertProjectPartsHeadersStatement; + WriteStatement &insertProjectPartsSourcesStatement = storage.insertProjectPartsSourcesStatement; + ReadStatement<1> &fetchProjectPartsHeadersByIdStatement = storage.fetchProjectPartsHeadersByIdStatement; + ReadStatement<1> &fetchProjectPartsSourcesByIdStatement = storage.fetchProjectPartsSourcesByIdStatement; + ReadStatement<1> &fetchProjectPrecompiledHeaderBuildTimeStatement = storage.fetchProjectPrecompiledHeaderBuildTimeStatement; + WriteStatement &resetDependentIndexingTimeStampsStatement = storage.resetDependentIndexingTimeStampsStatement; + ReadStatement<2> &fetchAllProjectPartNamesAndIdsStatement = storage.fetchAllProjectPartNamesAndIdsStatement; IncludeSearchPaths systemIncludeSearchPaths{{"/includes", 1, IncludeSearchPathType::BuiltIn}, {"/other/includes", 2, IncludeSearchPathType::System}}; IncludeSearchPaths projectIncludeSearchPaths{{"/project/includes", 1, IncludeSearchPathType::User}, @@ -134,11 +136,11 @@ TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithNonExistingProjectPartName) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))); EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartId("test"); } @@ -158,12 +160,12 @@ TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithExistingProjectPart) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))) .WillOnce(Return(Utils::optional{20})); EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))).Times(0); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartId("test"); } @@ -184,17 +186,17 @@ TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithBusyDatabaset) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))); EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))) .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))); EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartId("test"); } @@ -204,7 +206,7 @@ TEST_F(ProjectPartsStorage, FetchProjectIdWithNonExistingProjectPartName) ON_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))) .WillByDefault(Return(Utils::optional{})); - ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21)); + ON_CALL(databaseMock, lastInsertedRowId()).WillByDefault(Return(21)); auto id = storage.fetchProjectPartId("test"); @@ -216,7 +218,7 @@ TEST_F(ProjectPartsStorage, FetchProjectIdWithNonExistingProjectPartNameUnguarde ON_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))) .WillByDefault(Return(Utils::optional{})); - ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21)); + ON_CALL(databaseMock, lastInsertedRowId()).WillByDefault(Return(21)); auto id = storage.fetchProjectPartIdUnguarded("test"); @@ -232,7 +234,7 @@ TEST_F(ProjectPartsStorage, FetchProjectIdWithNonExistingProjectPartNameAndIsBus EXPECT_CALL(fetchProjectPartIdStatement, valueReturnProjectPartId(TypedEq("test"))) .WillOnce(Return(ClangBackEnd::ProjectPartId{21})); - ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21)); + ON_CALL(databaseMock, lastInsertedRowId()).WillByDefault(Return(21)); auto id = storage.fetchProjectPartId("test"); @@ -265,10 +267,10 @@ TEST_F(ProjectPartsStorage, FetchProjectPartName) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq(12))) .WillOnce(Return(Utils::optional{"test"})); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartName(12); } @@ -277,14 +279,14 @@ TEST_F(ProjectPartsStorage, FetchProjectPartNameStatementIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq(12))) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq(12))) .WillOnce(Return(Utils::optional{"test"})); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartName(12); } @@ -293,9 +295,9 @@ TEST_F(ProjectPartsStorage, FetchProjectParts) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartsStatement, valuesReturnProjectPartContainers(4096)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectParts(); } @@ -304,7 +306,7 @@ TEST_F(ProjectPartsStorage, FetchProjectPartsByIds) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1))); EXPECT_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(1024, Eq(1))); EXPECT_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(1024, Eq(1))); @@ -313,7 +315,7 @@ TEST_F(ProjectPartsStorage, FetchProjectPartsByIds) EXPECT_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(1024, Eq(2))); EXPECT_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(1024, Eq(2))); EXPECT_CALL(fetchProjectPrecompiledHeaderBuildTimeStatement, valueReturnInt64(Eq(2))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectParts({1, 2}); } @@ -322,15 +324,15 @@ TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1))); EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2))) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1))); EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectParts({1, 2}); } @@ -385,7 +387,7 @@ TEST_F(ProjectPartsStorage, UpdateProjectParts) { InSequence sequence; - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(updateProjectPartStatement, write(TypedEq(1), TypedEq(R"(["-m32"])"), @@ -416,7 +418,7 @@ TEST_F(ProjectPartsStorage, UpdateProjectParts) EXPECT_CALL(deleteProjectPartsSourcesByIdStatement, write(TypedEq(2))); EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq(2), TypedEq(7))); EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq(2), TypedEq(8))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.updateProjectParts({projectPart1, projectPart2}); } @@ -425,8 +427,8 @@ TEST_F(ProjectPartsStorage, UpdateProjectPartsIsBusy) { InSequence sequence; - EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(updateProjectPartStatement, write(TypedEq(1), TypedEq(R"(["-m32"])"), @@ -436,7 +438,7 @@ TEST_F(ProjectPartsStorage, UpdateProjectPartsIsBusy) 2, 35, 2)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.updateProjectParts({projectPart1}); } @@ -445,10 +447,10 @@ TEST_F(ProjectPartsStorage, FetchProjectPartArtefactBySourceIdCallsValueInStatem { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1)) .WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartArtefact(FilePathId{1}); } @@ -457,14 +459,14 @@ TEST_F(ProjectPartsStorage, FetchProjectPartArtefactBySourceIdCallsValueInStatem { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1)) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1)) .WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartArtefact(FilePathId{1}); } @@ -483,10 +485,10 @@ TEST_F(ProjectPartsStorage, FetchProjectPartArtefactByProjectPartIdCallsValueInS { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsByProjectPartId, valueReturnProjectPartArtefact(74)) .WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartArtefact(ProjectPartId{74}); } @@ -505,14 +507,14 @@ TEST_F(ProjectPartsStorage, FetchProjectPartArtefactByProjectPartIdReturnArtefac { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsByProjectPartId, valueReturnProjectPartArtefact(74)) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(getProjectPartArtefactsByProjectPartId, valueReturnProjectPartArtefact(74)) .WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchProjectPartArtefact(ProjectPartId{74}); } @@ -521,12 +523,12 @@ TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStamps) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(3))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(4))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(7))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(8))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.resetIndexingTimeStamps({projectPart1, projectPart2}); } @@ -535,13 +537,13 @@ TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStampsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""})); + EXPECT_CALL(databaseMock, immediateBegin()); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(3))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(4))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(7))); EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq(8))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.resetIndexingTimeStamps({projectPart1, projectPart2}); } @@ -550,10 +552,10 @@ TEST_F(ProjectPartsStorage, FetchAllProjectPartNamesAndIdsCalls) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchAllProjectPartNamesAndIdsStatement, valuesReturnProjectPartNameIds(_)) .WillRepeatedly(Return(projectPartNameIds)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchAllProjectPartNamesAndIds(); } @@ -562,14 +564,14 @@ TEST_F(ProjectPartsStorage, FetchAllProjectPartNamesAndIdsCallsIsBusy) { InSequence s; - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchAllProjectPartNamesAndIdsStatement, valuesReturnProjectPartNameIds(_)) .WillOnce(Throw(Sqlite::StatementIsBusy{""})); - EXPECT_CALL(mockDatabase, rollback()); - EXPECT_CALL(mockDatabase, deferredBegin()); + EXPECT_CALL(databaseMock, rollback()); + EXPECT_CALL(databaseMock, deferredBegin()); EXPECT_CALL(fetchAllProjectPartNamesAndIdsStatement, valuesReturnProjectPartNameIds(_)) .WillRepeatedly(Return(projectPartNameIds)); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, commit()); storage.fetchAllProjectPartNamesAndIds(); } diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 7af00158dfb..89df28be9f2 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -25,30 +25,30 @@ #include "googletest.h" -#include +#include #include namespace { -using Initializer = ClangBackEnd::RefactoringDatabaseInitializer>; +using Initializer = ClangBackEnd::RefactoringDatabaseInitializer>; using Sqlite::Table; class RefactoringDatabaseInitializer : public testing::Test { protected: - NiceMock mockDatabase; - Initializer initializer{mockDatabase}; + NiceMock databaseMock; + Initializer initializer{databaseMock}; }; TEST_F(RefactoringDatabaseInitializer, AddSymbolsTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON symbols(symbolKind, symbolName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON symbols(symbolKind, symbolName)"))); initializer.createSymbolsTable(); } @@ -57,10 +57,10 @@ TEST_F(RefactoringDatabaseInitializer, AddLocationsTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)"))); + EXPECT_CALL(databaseMock, execute(Eq( "CREATE INDEX IF NOT EXISTS index_locations_symbolId ON locations(symbolId)"))); initializer.createLocationsTable(); @@ -70,8 +70,8 @@ TEST_F(RefactoringDatabaseInitializer, AddSourcesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)"))); initializer.createSourcesTable(); } @@ -80,8 +80,8 @@ TEST_F(RefactoringDatabaseInitializer, AddDirectoriesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)"))); initializer.createDirectoriesTable(); } @@ -90,12 +90,12 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsTable) { InSequence s; - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY " "KEY, projectPartName TEXT, toolChainArguments TEXT, compilerMacros " "TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT, " "language INTEGER, languageVersion INTEGER, languageExtension INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); initializer.createProjectPartsTable(); } @@ -104,12 +104,12 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsFilesTable) { InSequence s; - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsFiles(projectPartId INTEGER, " "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " "hasMissingIncludes INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)"))); + EXPECT_CALL(databaseMock, execute(Eq( "CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId_sourceType " "ON projectPartsFiles(projectPartId, sourceType)"))); @@ -121,9 +121,9 @@ TEST_F(RefactoringDatabaseInitializer, AddUsedMacrosTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))); initializer.createUsedMacrosTable(); } @@ -133,7 +133,7 @@ TEST_F(RefactoringDatabaseInitializer, AddFileStatusesTable) InSequence s; EXPECT_CALL( - mockDatabase, + databaseMock, execute(Eq( "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " "lastModified INTEGER, indexingTimeStamp INTEGER)"))); @@ -145,16 +145,16 @@ TEST_F(RefactoringDatabaseInitializer, AddSourceDependenciesTable) { InSequence s; - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, " "dependencySourceId INTEGER)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON " "sourceDependencies(sourceId, dependencySourceId)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_dependencySourceId_sourceId ON " "sourceDependencies(dependencySourceId, sourceId)"))); @@ -166,7 +166,7 @@ TEST_F(RefactoringDatabaseInitializer, AddPrecompiledHeaderTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)"))); initializer.createPrecompiledHeadersTable(); } @@ -175,10 +175,10 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsHeadersTable) { InSequence s; - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsHeaders(projectPartId INTEGER, " "sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsHeaders_projectPartId ON " "projectPartsHeaders(projectPartId)"))); @@ -189,10 +189,10 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsSourcesTable) { InSequence s; - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " "sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON " "projectPartsSources(projectPartId)"))); @@ -203,166 +203,166 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) { InSequence s; - EXPECT_CALL(mockDatabase, isInitialized()).WillOnce(Return(false)); - EXPECT_CALL(mockDatabase, exclusiveBegin()); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, isInitialized()).WillOnce(Return(false)); + EXPECT_CALL(databaseMock, exclusiveBegin()); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr " "TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON " "symbols(symbolKind, symbolName)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, " "column INTEGER, sourceId INTEGER, locationKind INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column " "ON locations(sourceId, line, column)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON " "locations(sourceId, locationKind)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq( "CREATE INDEX IF NOT EXISTS index_locations_symbolId ON locations(symbolId)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, " "directoryId INTEGER, sourceName TEXT)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName " "ON sources(directoryId, sourceName)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY " "KEY, directoryPath TEXT)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON " "directories(directoryPath)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute( Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY " "KEY, projectPartName TEXT, toolChainArguments TEXT, compilerMacros " "TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT, " "language INTEGER, languageVersion INTEGER, languageExtension INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName " "ON projectParts(projectPartName)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsFiles(projectPartId INTEGER, " "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " "hasMissingIncludes INTEGER)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId " "ON projectPartsFiles(sourceId, projectPartId)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId_sourceType ON " "projectPartsFiles(projectPartId, sourceType)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, " "sourceId INTEGER, macroName TEXT)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON " "usedMacros(sourceId, macroName)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute(Eq( "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " "lastModified INTEGER, indexingTimeStamp INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, " "dependencySourceId INTEGER)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON " "sourceDependencies(sourceId, dependencySourceId)"))); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_dependencySourceId_sourceId ON " "sourceDependencies(dependencySourceId, sourceId)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER " "PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, " "systemPchPath TEXT, systemPchBuildTime INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsHeaders(projectPartId INTEGER, " "sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsHeaders_projectPartId ON " "projectPartsHeaders(projectPartId)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " "sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON " "projectPartsSources(projectPartId)"))); - EXPECT_CALL(mockDatabase, commit()); - EXPECT_CALL(mockDatabase, setIsInitialized(true)); + EXPECT_CALL(databaseMock, commit()); + EXPECT_CALL(databaseMock, setIsInitialized(true)); - Initializer initializer{mockDatabase}; + Initializer initializer{databaseMock}; } TEST_F(RefactoringDatabaseInitializer, DontCreateIfAlreadyInitialized) { InSequence s; - EXPECT_CALL(mockDatabase, isInitialized()).WillOnce(Return(true)); - EXPECT_CALL(mockDatabase, exclusiveBegin()).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON symbols(symbolKind, symbolName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT, sourceType INTEGER)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)"))).Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, isInitialized()).WillOnce(Return(true)); + EXPECT_CALL(databaseMock, exclusiveBegin()).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON symbols(symbolKind, symbolName)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT, sourceType INTEGER)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY " "KEY, projectPartName TEXT, toolChainArguments TEXT, compilerMacros " "TEXT, includeSearchPaths TEXT)"))) .Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsFiles(projectPartId INTEGER, sourceId INTEGER)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON projectPartsFiles(projectPartId)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))).Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsFiles(projectPartId INTEGER, sourceId INTEGER)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON projectPartsFiles(projectPartId)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, " "size INTEGER, lastModified INTEGER, indexingTimeStamp INTEGER)"))) .Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)"))).Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)"))).Times(0); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsHeaders(projectPartId INTEGER, " "sourceId INTEGER)"))) .Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsHeaders_projectPartId ON " "projectPartsHeaders(projectPartId)"))) .Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " "sourceId INTEGER)"))) .Times(0); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON " "projectPartsSources(projectPartId)"))) .Times(0); - EXPECT_CALL(mockDatabase, commit()).Times(0); + EXPECT_CALL(databaseMock, commit()).Times(0); - Initializer initializer{mockDatabase}; + Initializer initializer{databaseMock}; } } diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index a93100c3e04..7ba3648a1c5 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -73,7 +73,7 @@ protected: std::vector names() const { - return Sqlite::ReadStatement("SELECT name FROM test", database).values(8); + return Sqlite::ReadStatement<1>("SELECT name FROM test", database).values(8); } static void updateHookCallback( diff --git a/tests/unit/unittest/sqlitedatabasemock.h b/tests/unit/unittest/sqlitedatabasemock.h index 8c1179e4248..d65dd3f0faf 100644 --- a/tests/unit/unittest/sqlitedatabasemock.h +++ b/tests/unit/unittest/sqlitedatabasemock.h @@ -40,7 +40,8 @@ class SqliteDatabaseMock : public SqliteTransactionBackendMock, public Sqlite::DatabaseInterface { public: - using ReadStatement = NiceMock; + template + using ReadStatement = NiceMock>; using WriteStatement = NiceMock; MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement), ()); diff --git a/tests/unit/unittest/sqlitereadstatementmock.cpp b/tests/unit/unittest/sqlitereadstatementmock.cpp index e3e22d4e161..742b17b314c 100644 --- a/tests/unit/unittest/sqlitereadstatementmock.cpp +++ b/tests/unit/unittest/sqlitereadstatementmock.cpp @@ -27,34 +27,9 @@ #include "sqlitedatabasemock.h" -SqliteReadStatementMock::SqliteReadStatementMock(Utils::SmallStringView sqlStatement, - SqliteDatabaseMock &databaseMock) +SqliteReadStatementMockBase::SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement, + SqliteDatabaseMock &databaseMock) : sqlStatement(sqlStatement) { databaseMock.prepare(sqlStatement); } - -template<> -std::vector SqliteReadStatementMock::values(std::size_t reserveSize) -{ - return valuesReturnStringVector(reserveSize); -} - -template<> -std::vector SqliteReadStatementMock::values(std::size_t reserveSize) -{ - return valuesReturnRowIds(reserveSize); -} - -template<> -Utils::optional SqliteReadStatementMock::value() -{ - return valueReturnLongLong(); -} - -template<> -Utils::optional SqliteReadStatementMock::value( - const Utils::SmallStringView &name, const long long &blob) -{ - return valueReturnBlob(name, blob); -} diff --git a/tests/unit/unittest/sqlitereadstatementmock.h b/tests/unit/unittest/sqlitereadstatementmock.h index f74cce1e8ef..4c48bd9d0e1 100644 --- a/tests/unit/unittest/sqlitereadstatementmock.h +++ b/tests/unit/unittest/sqlitereadstatementmock.h @@ -27,7 +27,19 @@ #include "googletest.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include #include #include @@ -37,57 +49,196 @@ #include #include +using ClangBackEnd::FilePathIds; +using ClangBackEnd::SourceEntries; +using ClangBackEnd::SourceEntry; +using ClangBackEnd::SourceTimeStamp; +using ClangBackEnd::SourceTimeStamps; +using ClangRefactoring::SourceLocation; +using ClangRefactoring::SourceLocations; +using std::int64_t; +namespace Sources = ClangBackEnd::Sources; +using ClangBackEnd::PrecompiledHeaderTimeStamps; +using ClangBackEnd::UsedMacros; +using ClangBackEnd::Internal::ProjectPartNameId; +using ClangBackEnd::Internal::ProjectPartNameIds; +using ClangRefactoring::Symbol; +using ClangRefactoring::Symbols; + class SqliteDatabaseMock; -class SqliteReadStatementMock +class SqliteReadStatementMockBase { public: - SqliteReadStatementMock() = default; - SqliteReadStatementMock(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &databaseMock); + SqliteReadStatementMockBase() = default; + SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement, SqliteDatabaseMock &databaseMock); MOCK_METHOD(std::vector, valuesReturnStringVector, (std::size_t), ()); MOCK_METHOD(std::vector, valuesReturnRowIds, (std::size_t), ()); - MOCK_METHOD(Utils::optional, valueReturnLongLong, (), ()); + MOCK_METHOD(Utils::optional, valueReturnInt64, (), ()); MOCK_METHOD(Utils::optional, valueReturnBlob, (Utils::SmallStringView, long long), ()); - template - std::vector values(std::size_t reserveSize, const QueryType &... queryValues); + MOCK_METHOD(SourceLocations, valuesReturnSourceLocations, (std::size_t, int, int, int), ()); - template - std::vector values(std::size_t reserveSize); + MOCK_METHOD(CppTools::Usages, valuesReturnSourceUsages, (std::size_t, int, int, int), ()); - template class QueryContainerType, - typename QueryElementType> - std::vector values(std::size_t reserveSize, - const QueryContainerType &queryValues); + MOCK_METHOD(CppTools::Usages, valuesReturnSourceUsages, (std::size_t, int, int, int, int), ()); - template - Utils::optional value(const QueryTypes&... queryValues); + MOCK_METHOD(std::vector, valuesReturnStdVectorDirectory, (std::size_t), ()); + + MOCK_METHOD(std::vector, valuesReturnStdVectorSource, (std::size_t), ()); + + MOCK_METHOD(SourceEntries, valuesReturnSourceEntries, (std::size_t, int, int), ()); + + MOCK_METHOD(UsedMacros, valuesReturnUsedMacros, (std::size_t, int), ()); + + MOCK_METHOD(FilePathIds, valuesReturnFilePathIds, (std::size_t, int), ()); + + MOCK_METHOD(ProjectPartNameIds, valuesReturnProjectPartNameIds, (std::size_t), ()); + + MOCK_METHOD(Utils::optional, valueReturnInt32, (Utils::SmallStringView), ()); + + MOCK_METHOD(Utils::optional, valueReturnInt32, (int, Utils::SmallStringView), ()); + + MOCK_METHOD(Utils::optional, valueReturnInt32, (int), ()); + + MOCK_METHOD(Utils::optional, valueReturnInt64, (int), ()); + + MOCK_METHOD(Utils::optional, valueReturnPathString, (int), ()); + + MOCK_METHOD(Utils::optional, valueReturnPathString, (Utils::SmallStringView), ()); + + MOCK_METHOD(Utils::optional, valueReturnFilePath, (int), ()); + + MOCK_METHOD(ClangBackEnd::FilePaths, valuesReturnFilePaths, (std::size_t), ()); + + MOCK_METHOD(Utils::optional, valueReturnSmallString, (int), ()); + + MOCK_METHOD(Utils::optional, + valueReturnSourceNameAndDirectoryId, + (int) ); + + MOCK_METHOD(Utils::optional, + valueReturnProjectPartArtefact, + (int) ); + + MOCK_METHOD(Utils::optional, + valueReturnProjectPartArtefact, + (Utils::SmallStringView)); + MOCK_METHOD(ClangBackEnd::ProjectPartArtefacts, valuesReturnProjectPartArtefacts, (std::size_t), ()); + MOCK_METHOD(Utils::optional, + valueReturnProjectPartContainer, + (int) ); + MOCK_METHOD(ClangBackEnd::ProjectPartContainers, + valuesReturnProjectPartContainers, + (std::size_t), + ()); + MOCK_METHOD(Utils::optional, valueReturnProjectPartPch, (int), ()); + + MOCK_METHOD(Utils::optional, valueReturnPchPaths, (int), ()); + + MOCK_METHOD(Symbols, valuesReturnSymbols, (std::size_t, int, Utils::SmallStringView), ()); + + MOCK_METHOD(Symbols, valuesReturnSymbols, (std::size_t, int, int, Utils::SmallStringView), ()); + + MOCK_METHOD(Symbols, valuesReturnSymbols, (std::size_t, int, int, int, Utils::SmallStringView), ()); + + MOCK_METHOD(SourceLocation, valueReturnSourceLocation, (long long, int), ()); + + MOCK_METHOD(Utils::optional, + valueReturnProjectPartId, + (Utils::SmallStringView)); + + MOCK_METHOD(SourceTimeStamps, valuesReturnSourceTimeStamps, (std::size_t), ()); + MOCK_METHOD(SourceTimeStamps, valuesReturnSourceTimeStamps, (std::size_t, int sourcePathId), ()); + + MOCK_METHOD(Utils::optional, + valuesReturnPrecompiledHeaderTimeStamps, + (int projectPartId)); + + template + auto value(const QueryTypes &...queryValues) + { + if constexpr (std::is_same_v) + return valueReturnBlob(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnProjectPartId(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnInt32(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnInt64(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnPathString(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnFilePath(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnProjectPartArtefact(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnProjectPartContainer(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnProjectPartPch(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnPchPaths(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnSmallString(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnSourceLocation(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnSourceNameAndDirectoryId(queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnPrecompiledHeaderTimeStamps(queryValues...); + else + static_assert(!std::is_same_v, + "SqliteReadStatementMock::value does not handle result type!"); + } + + template + auto values(std::size_t reserveSize, const QueryType &...queryValues) + { + if constexpr (std::is_same_v) + return valuesReturnStringVector(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnRowIds(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnSourceLocations(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnSourceUsages(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnSymbols(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnUsedMacros(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnFilePathIds(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnFilePaths(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnStdVectorDirectory(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnStdVectorSource(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnProjectPartNameIds(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnProjectPartContainers(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnSourceEntries(reserveSize, queryValues...); + else if constexpr (std::is_same_v) + return valuesReturnSourceTimeStamps(reserveSize, queryValues...); + else + static_assert(!std::is_same_v, + "SqliteReadStatementMock::values does not handle result type!"); + } public: Utils::SmallString sqlStatement; }; -template<> -std::vector SqliteReadStatementMock::values( - std::size_t reserveSize); - -template<> -std::vector SqliteReadStatementMock::values(std::size_t reserveSize); - -template<> -Utils::optional SqliteReadStatementMock::value(); - -template<> -Utils::optional SqliteReadStatementMock::value( - const Utils::SmallStringView &name, const long long &blob); +template +class SqliteReadStatementMock : public SqliteReadStatementMockBase +{ +public: + using SqliteReadStatementMockBase::SqliteReadStatementMockBase; +}; diff --git a/tests/unit/unittest/sqlitesessions-test.cpp b/tests/unit/unittest/sqlitesessions-test.cpp index 31c71375511..10575731fb5 100644 --- a/tests/unit/unittest/sqlitesessions-test.cpp +++ b/tests/unit/unittest/sqlitesessions-test.cpp @@ -124,8 +124,8 @@ class Sessions : public testing::Test protected: Sessions() { sessions.setAttachedTables({"data", "tags"}); } - std::vector fetchData() { return selectData.values(8); } - std::vector fetchTags() { return selectTags.values(8); } + std::vector fetchData() { return selectData.values(8); } + std::vector fetchTags() { return selectTags.values(8); } protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; @@ -150,10 +150,10 @@ protected: "DELETE FROM tags WHERE dataId=(SELECT id FROM data WHERE name=?)", database}; Sqlite::WriteStatement insertTag{ "INSERT INTO tags(dataId, tag) VALUES ((SELECT id FROM data WHERE name=?1), ?2) ", database}; - Sqlite::ReadStatement selectData{"SELECT name, number, value FROM data", database}; - Sqlite::ReadStatement selectTags{"SELECT name, tag FROM tags JOIN data ON data.id=tags.dataId", - database}; - Sqlite::ReadStatement selectChangeSets{"SELECT changeset FROM testsessions", database}; + Sqlite::ReadStatement<3> selectData{"SELECT name, number, value FROM data", database}; + Sqlite::ReadStatement<2> selectTags{ + "SELECT name, tag FROM tags JOIN data ON data.id=tags.dataId", database}; + Sqlite::ReadStatement<1> selectChangeSets{"SELECT changeset FROM testsessions", database}; }; TEST_F(Sessions, DontThrowForCommittingWithoutSessionStart) diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 1639c1dd1fb..c526cc3d4bc 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -121,12 +121,12 @@ struct Output TEST_F(SqliteStatement, ThrowsStatementHasErrorForWrongSqlStatement) { - ASSERT_THROW(ReadStatement("blah blah blah", database), Sqlite::StatementHasError); + ASSERT_THROW(ReadStatement<0>("blah blah blah", database), Sqlite::StatementHasError); } TEST_F(SqliteStatement, ThrowsNotReadOnlySqlStatementForWritableSqlStatementInReadStatement) { - ASSERT_THROW(ReadStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), + ASSERT_THROW(ReadStatement<0>("INSERT INTO test(name, number) VALUES (?, ?)", database), Sqlite::NotReadOnlySqlStatement); } @@ -143,7 +143,7 @@ TEST_F(SqliteStatement, CountRows) while (statement.next()) ++nextCount; - int sqlCount = ReadStatement::toValue("SELECT count(*) FROM test", database); + int sqlCount = ReadStatement<1>::toValue("SELECT count(*) FROM test", database); ASSERT_THAT(nextCount, sqlCount); } @@ -174,24 +174,28 @@ TEST_F(SqliteStatement, Value) TEST_F(SqliteStatement, ToIntegerValue) { - auto value = ReadStatement::toValue("SELECT number FROM test WHERE name='foo'", database); + auto value = ReadStatement<1>::toValue("SELECT number FROM test WHERE name='foo'", database); ASSERT_THAT(value, 23); } TEST_F(SqliteStatement, ToLongIntegerValue) { - ASSERT_THAT(ReadStatement::toValue("SELECT number FROM test WHERE name='foo'", database), Eq(23)); + ASSERT_THAT(ReadStatement<1>::toValue("SELECT number FROM test WHERE name='foo'", database), + Eq(23)); } TEST_F(SqliteStatement, ToDoubleValue) { - ASSERT_THAT(ReadStatement::toValue("SELECT number FROM test WHERE name='foo'", database), 23.3); + ASSERT_THAT(ReadStatement<1>::toValue("SELECT number FROM test WHERE name='foo'", database), + 23.3); } TEST_F(SqliteStatement, ToStringValue) { - ASSERT_THAT(ReadStatement::toValue("SELECT name FROM test WHERE name='foo'", database), "foo"); + ASSERT_THAT(ReadStatement<1>::toValue( + "SELECT name FROM test WHERE name='foo'", database), + "foo"); } TEST_F(SqliteStatement, BindNull) @@ -319,7 +323,7 @@ TEST_F(SqliteStatement, BindBlob) { SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database); const unsigned char chars[] = "aaafdfdlll"; - auto bytePointer = reinterpret_cast(chars); + auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; statement.bind(1, bytes); @@ -523,7 +527,7 @@ TEST_F(SqliteStatement, WriteBlobs) SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database); SqliteTestStatement readStatement("SELECT value FROM test WHERE name = 'blob'", database); const unsigned char chars[] = "aaafdfdlll"; - auto bytePointer = reinterpret_cast(chars); + auto bytePointer = reinterpret_cast(chars); Sqlite::BlobView bytes{bytePointer, sizeof(chars) - 1}; statement.write(bytes); @@ -544,16 +548,15 @@ TEST_F(SqliteStatement, CannotReadFromClosedDatabase) { database.close(); - ASSERT_THROW(ReadStatement("SELECT * FROM test", database), - Sqlite::DatabaseIsNotOpen); + ASSERT_THROW(ReadStatement<3>("SELECT * FROM test", database), Sqlite::DatabaseIsNotOpen); } TEST_F(SqliteStatement, GetTupleValuesWithoutArguments) { using Tuple = std::tuple; - ReadStatement statement("SELECT name, number, value FROM test", database); + ReadStatement<3> statement("SELECT name, number, value FROM test", database); - auto values = statement.values(3); + auto values = statement.values(3); ASSERT_THAT(values, UnorderedElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, Tuple{"poo", 40.0, 3})); @@ -561,7 +564,7 @@ TEST_F(SqliteStatement, GetTupleValuesWithoutArguments) TEST_F(SqliteStatement, GetSingleValuesWithoutArguments) { - ReadStatement statement("SELECT name FROM test", database); + ReadStatement<1> statement("SELECT name FROM test", database); std::vector values = statement.values(3); @@ -586,7 +589,7 @@ public: TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments) { - ReadStatement statement("SELECT number FROM test", database); + ReadStatement<1> statement("SELECT number FROM test", database); database.execute("INSERT INTO test VALUES (NULL, NULL, NULL)"); std::vector values = statement.values(3); @@ -596,9 +599,9 @@ TEST_F(SqliteStatement, GetSingleSqliteValuesWithoutArguments) TEST_F(SqliteStatement, GetStructValuesWithoutArguments) { - ReadStatement statement("SELECT name, number, value FROM test", database); + ReadStatement<3> statement("SELECT name, number, value FROM test", database); - auto values = statement.values(3); + auto values = statement.values(3); ASSERT_THAT(values, UnorderedElementsAre(Output{"bar", "blah", 1}, @@ -608,7 +611,7 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments) TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes) { - ReadStatement statement("SELECT name FROM test WHERE number=?", database); + ReadStatement<1> statement("SELECT name FROM test WHERE number=?", database); statement.values(3, 40); std::vector values = statement.values(3, 40); @@ -616,56 +619,13 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputWithBindingMultipleTimes) ASSERT_THAT(values, ElementsAre("poo")); } -TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues) -{ - using Tuple = std::tuple; - std::vector queryValues = {40, 23.3}; - ReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database); - - auto values = statement.values(3, queryValues); - - ASSERT_THAT(values, UnorderedElementsAre(Tuple{"poo", 40, 3.}, Tuple{"foo", 23.3, 2.})); -} - -TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues) -{ - std::vector queryValues = {40, 23.3}; - ReadStatement statement("SELECT name FROM test WHERE number=?", database); - - std::vector values = statement.values(3, queryValues); - - ASSERT_THAT(values, UnorderedElementsAre("poo", "foo")); -} - -TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleValues) -{ - using Tuple = std::tuple; - using ResultTuple = std::tuple; - std::vector queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}}; - ReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database); - - auto values = statement.values(3, queryValues); - - ASSERT_THAT(values, UnorderedElementsAre(ResultTuple{"poo", 40, 3}, ResultTuple{"bar", 0, 1})); -} - -TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValues) -{ - using Tuple = std::tuple; - std::vector queryValues = {{"poo", "40"}, {"bar", "blah"}}; - ReadStatement statement("SELECT name FROM test WHERE name= ? AND number=?", database); - - std::vector values = statement.values(3, queryValues); - - ASSERT_THAT(values, UnorderedElementsAre("poo", "bar")); -} - TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + ReadStatement<3> statement( + "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto values = statement.values(3, "bar", "blah", 1); + auto values = statement.values(3, "bar", "blah", 1); ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1})); } @@ -673,51 +633,31 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValueMultipleTimes) { using Tuple = std::tuple; - ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=?", database); - statement.values(3, "bar", "blah"); + ReadStatement<3> statement("SELECT name, number, value FROM test WHERE name=? AND number=?", + database); + statement.values(3, "bar", "blah"); - auto values = statement.values(3, "bar", "blah"); + auto values = statement.values(3, "bar", "blah"); ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1})); } TEST_F(SqliteStatement, GetStructOutputValuesAndMultipleQueryValue) { - ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + ReadStatement<3> statement( + "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto values = statement.values(3, "bar", "blah", 1); + auto values = statement.values(3, "bar", "blah", 1); ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1})); } -TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryValues) -{ - std::vector queryValues = {40, 23.3}; - ReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database); - - auto values = statement.values(3, queryValues); - - ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3}, - Output{"foo", "23.3", 2})); -} - -TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues) -{ - using Tuple = std::tuple; - std::vector queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}}; - ReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database); - - auto values = statement.values(3, queryValues); - - ASSERT_THAT(values, UnorderedElementsAre(Output{"poo", "40", 3}, Output{"bar", "blah", 1})); -} - TEST_F(SqliteStatement, GetBlobValues) { database.execute("INSERT INTO test VALUES ('blob', 40, x'AABBCCDD')"); - ReadStatement statement("SELECT value FROM test WHERE name='blob'", database); + ReadStatement<1> statement("SELECT value FROM test WHERE name='blob'", database); const int value = 0xDDCCBBAA; - auto bytePointer = reinterpret_cast(&value); + auto bytePointer = reinterpret_cast(&value); Sqlite::BlobView bytes{bytePointer, 4}; auto values = statement.values(1); @@ -727,7 +667,7 @@ TEST_F(SqliteStatement, GetBlobValues) TEST_F(SqliteStatement, GetEmptyBlobValueForInteger) { - ReadStatement statement("SELECT value FROM test WHERE name='poo'", database); + ReadStatement<1> statement("SELECT value FROM test WHERE name='poo'", database); auto value = statement.value(); @@ -736,7 +676,7 @@ TEST_F(SqliteStatement, GetEmptyBlobValueForInteger) TEST_F(SqliteStatement, GetEmptyBlobValueForFloat) { - ReadStatement statement("SELECT number FROM test WHERE name='foo'", database); + ReadStatement<1> statement("SELECT number FROM test WHERE name='foo'", database); auto value = statement.value(); @@ -745,7 +685,7 @@ TEST_F(SqliteStatement, GetEmptyBlobValueForFloat) TEST_F(SqliteStatement, GetEmptyBlobValueForText) { - ReadStatement statement("SELECT number FROM test WHERE name='bar'", database); + ReadStatement<1> statement("SELECT number FROM test WHERE name='bar'", database); auto value = statement.value(); @@ -754,7 +694,8 @@ TEST_F(SqliteStatement, GetEmptyBlobValueForText) TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) { - ReadStatement statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", database); + ReadStatement<1> statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", + database); auto value = statement.value("bar", "blah", 1); @@ -763,9 +704,10 @@ TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue) { - ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + ReadStatement<3> statement( + "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto value = statement.value("bar", "blah", 1); + auto value = statement.value("bar", "blah", 1); ASSERT_THAT(value.value(), Eq(Output{"bar", "blah", 1})); } @@ -773,9 +715,10 @@ TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue) TEST_F(SqliteStatement, GetOptionalTupleValueAndMultipleQueryValue) { using Tuple = std::tuple; - ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + ReadStatement<3> statement( + "SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto value = statement.value("bar", "blah", 1); + auto value = statement.value("bar", "blah", 1); ASSERT_THAT(value.value(), Eq(Tuple{"bar", "blah", 1})); } @@ -837,65 +780,6 @@ TEST_F(SqliteStatement, GetValuesWithSimpleArgumentsCallsResetIfExceptionIsThrow EXPECT_THROW(mockStatement.values(3, "foo", "bar"), Sqlite::StatementHasError); } -TEST_F(SqliteStatement, GetValuesWithVectorArgumentsCallsReset) -{ - MockSqliteStatement mockStatement; - - EXPECT_CALL(mockStatement, reset()).Times(2); - - mockStatement.values(3, std::vector{"bar", "foo"}); -} - -TEST_F(SqliteStatement, GetValuesWithVectorArgumentCallsResetIfExceptionIsThrown) -{ - MockSqliteStatement mockStatement; - ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - - EXPECT_CALL(mockStatement, reset()); - - EXPECT_THROW(mockStatement.values(3, std::vector{"bar", "foo"}), - Sqlite::StatementHasError); -} - -TEST_F(SqliteStatement, GetValuesWithTupleArgumentsCallsReset) -{ - MockSqliteStatement mockStatement; - - EXPECT_CALL(mockStatement, reset()).Times(2); - - mockStatement.values(3, std::vector>{{1}, {2}}); -} - -TEST_F(SqliteStatement, GetValuesWithTupleArgumentsCallsResetIfExceptionIsThrown) -{ - MockSqliteStatement mockStatement; - ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - - EXPECT_CALL(mockStatement, reset()); - - EXPECT_THROW(mockStatement.values(3, std::vector>{{1}, {2}}), - Sqlite::StatementHasError); -} - -TEST_F(SqliteStatement, DoubleThrowExceptionsInReset) -{ - MockSqliteStatement mockStatement; - ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - ON_CALL(mockStatement, reset()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - - ASSERT_THROW(mockStatement.values(3, std::vector>{{1}, {2}}), - Sqlite::StatementHasError); -} - -TEST_F(SqliteStatement, ThrowExceptionOnlyInReset) -{ - MockSqliteStatement mockStatement; - ON_CALL(mockStatement, reset()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - - ASSERT_THROW(mockStatement.values(3, std::vector>{{1}, {2}}), - Sqlite::StatementHasError); -} - TEST_F(SqliteStatement, ResetIfWriteIsThrowingException) { MockSqliteStatement mockStatement; @@ -917,138 +801,101 @@ TEST_F(SqliteStatement, ResetIfExecuteThrowsException) ASSERT_ANY_THROW(mockStatement.execute()); } -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValue) +TEST_F(SqliteStatement, ReadStatementThrowsColumnCountDoesNotMatch) { - SqliteTestStatement statement("SELECT name, number FROM test", database); + MockFunction callbackMock; - ASSERT_THROW(statement.value(), Sqlite::ColumnCountDoesNotMatch); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValues) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - - ASSERT_THROW(statement.values(1), Sqlite::ColumnCountDoesNotMatch); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithArguments) -{ - SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database); - - ASSERT_THROW(statement.values(1, 2), Sqlite::ColumnCountDoesNotMatch); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithVectorArguments) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - - ASSERT_THROW(statement.values(1, std::vector{}), Sqlite::ColumnCountDoesNotMatch); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForValuesWithTupleArguments) -{ - SqliteTestStatement statement("SELECT name, number FROM test", database); - - ASSERT_THROW(statement.values(1, std::vector>{}), + ASSERT_THROW(ReadStatement<1> statement("SELECT name, number FROM test", database), Sqlite::ColumnCountDoesNotMatch); } -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForToValues) +TEST_F(SqliteStatement, ReadWriteStatementThrowsColumnCountDoesNotMatch) { - ASSERT_THROW(SqliteTestStatement::toValue("SELECT name, number FROM test", database), + MockFunction callbackMock; + + ASSERT_THROW(ReadWriteStatement<1> statement("SELECT name, number FROM test", database), Sqlite::ColumnCountDoesNotMatch); } TEST_F(SqliteStatement, ReadCallback) { MockFunction callbackMock; - ReadStatement statement("SELECT name, value FROM test", database); + ReadStatement<2> statement("SELECT name, value FROM test", database); EXPECT_CALL(callbackMock, Call(Eq("bar"), Eq(1))); EXPECT_CALL(callbackMock, Call(Eq("foo"), Eq(2))); EXPECT_CALL(callbackMock, Call(Eq("poo"), Eq(3))); - statement.readCallback<2>(callbackMock.AsStdFunction()); + statement.readCallback(callbackMock.AsStdFunction()); } TEST_F(SqliteStatement, ReadCallbackCalledWithArguments) { MockFunction callbackMock; - ReadStatement statement("SELECT name, value FROM test WHERE value=?", database); + ReadStatement<2> statement("SELECT name, value FROM test WHERE value=?", database); EXPECT_CALL(callbackMock, Call(Eq("foo"), Eq(2))); - statement.readCallback<2>(callbackMock.AsStdFunction(), 2); + statement.readCallback(callbackMock.AsStdFunction(), 2); } TEST_F(SqliteStatement, ReadCallbackAborts) { MockFunction callbackMock; - ReadStatement statement("SELECT name, value FROM test ORDER BY name", database); + ReadStatement<2> statement("SELECT name, value FROM test ORDER BY name", database); EXPECT_CALL(callbackMock, Call(Eq("bar"), Eq(1))); EXPECT_CALL(callbackMock, Call(Eq("foo"), Eq(2))).WillOnce(Return(Sqlite::CallbackControl::Abort)); EXPECT_CALL(callbackMock, Call(Eq("poo"), Eq(3))).Times(0); - statement.readCallback<2>(callbackMock.AsStdFunction()); -} - -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForReadCallback) -{ - MockFunction callbackMock; - SqliteTestStatement statement("SELECT name, number FROM test", database); - - ASSERT_THROW(statement.readCallback<1>(callbackMock.AsStdFunction()), - Sqlite::ColumnCountDoesNotMatch); + statement.readCallback(callbackMock.AsStdFunction()); } TEST_F(SqliteStatement, ReadCallbackCallsResetAfterCallbacks) { MockFunction callbackMock; - MockSqliteStatement mockStatement; + MockSqliteStatement<2> mockStatement; EXPECT_CALL(mockStatement, reset()); - mockStatement.readCallback<2>(callbackMock.AsStdFunction()); + mockStatement.readCallback(callbackMock.AsStdFunction()); } TEST_F(SqliteStatement, ReadCallbackCallsResetAfterCallbacksAborts) { MockFunction callbackMock; - MockSqliteStatement mockStatement; + MockSqliteStatement<2> mockStatement; ON_CALL(callbackMock, Call(_, _)).WillByDefault(Return(Sqlite::CallbackControl::Abort)); EXPECT_CALL(mockStatement, reset()); - mockStatement.readCallback<2>(callbackMock.AsStdFunction()); + mockStatement.readCallback(callbackMock.AsStdFunction()); } TEST_F(SqliteStatement, ReadCallbackThrowsForError) { MockFunction callbackMock; - MockSqliteStatement mockStatement; + MockSqliteStatement<2> mockStatement; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); - ASSERT_THROW(mockStatement.readCallback<2>(callbackMock.AsStdFunction()), - Sqlite::StatementHasError); + ASSERT_THROW(mockStatement.readCallback(callbackMock.AsStdFunction()), Sqlite::StatementHasError); } TEST_F(SqliteStatement, ReadCallbackCallsResetIfExceptionIsThrown) { MockFunction callbackMock; - MockSqliteStatement mockStatement; + MockSqliteStatement<2> mockStatement; ON_CALL(mockStatement, next()).WillByDefault(Throw(Sqlite::StatementHasError(""))); EXPECT_CALL(mockStatement, reset()); - EXPECT_THROW(mockStatement.readCallback<2>(callbackMock.AsStdFunction()), - Sqlite::StatementHasError); + EXPECT_THROW(mockStatement.readCallback(callbackMock.AsStdFunction()), Sqlite::StatementHasError); } TEST_F(SqliteStatement, ReadToContainer) { std::deque values; - ReadStatement statement("SELECT number FROM test", database); + ReadStatement<1> statement("SELECT number FROM test", database); statement.readTo<1>(values); @@ -1058,21 +905,13 @@ TEST_F(SqliteStatement, ReadToContainer) TEST_F(SqliteStatement, ReadToContainerCallCallbackWithArguments) { std::deque values; - ReadStatement statement("SELECT number FROM test WHERE value=?", database); + ReadStatement<1> statement("SELECT number FROM test WHERE value=?", database); statement.readTo(values, 2); ASSERT_THAT(values, ElementsAre(Eq(23.3))); } -TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForToManyArgumentsForReadTo) -{ - std::deque values; - SqliteTestStatement statement("SELECT name, number FROM test", database); - - ASSERT_THROW(statement.readTo<1>(values, 2), Sqlite::ColumnCountDoesNotMatch); -} - TEST_F(SqliteStatement, ReadToCallsResetAfterPushingAllValuesBack) { std::deque values; diff --git a/tests/unit/unittest/sqlitetable-test.cpp b/tests/unit/unittest/sqlitetable-test.cpp index f96b451785e..b916ad5bc89 100644 --- a/tests/unit/unittest/sqlitetable-test.cpp +++ b/tests/unit/unittest/sqlitetable-test.cpp @@ -27,7 +27,7 @@ #include "spydummy.h" #include -#include +#include #include namespace { @@ -45,7 +45,7 @@ using Sqlite::OpenMode; class SqliteTable : public ::testing::Test { protected: - NiceMock mockDatabase; + NiceMock databaseMock; Sqlite::Table table; Utils::SmallString tableName = "testTable"; }; @@ -93,9 +93,9 @@ TEST_F(SqliteTable, InitializeTable) table.addColumn("name"); table.addColumn("value"); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE IF NOT EXISTS testTable(name NUMERIC, value NUMERIC) WITHOUT ROWID"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TEMPORARY TABLE IF NOT EXISTS testTable(name NUMERIC, value NUMERIC) WITHOUT ROWID"))); - table.initialize(mockDatabase); + table.initialize(databaseMock); } TEST_F(SqliteTable, InitializeTableWithIndex) @@ -107,11 +107,11 @@ TEST_F(SqliteTable, InitializeTableWithIndex) table.addIndex({column}); table.addIndex({column2}); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE testTable(name NUMERIC, value NUMERIC)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_value ON testTable(value)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE testTable(name NUMERIC, value NUMERIC)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_name ON testTable(name)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_testTable_value ON testTable(value)"))); - table.initialize(mockDatabase); + table.initialize(databaseMock); } TEST_F(SqliteTable, AddForeignKeyColumnWithTableCalls) @@ -125,11 +125,11 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithTableCalls) ForeignKeyAction::Cascade, Enforment::Deferred); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute(Eq("CREATE TABLE testTable(name INTEGER REFERENCES foreignTable ON UPDATE " "SET NULL ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"))); - table.initialize(mockDatabase); + table.initialize(databaseMock); } TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls) @@ -145,12 +145,12 @@ TEST_F(SqliteTable, AddForeignKeyColumnWithColumnCalls) Enforment::Deferred); EXPECT_CALL( - mockDatabase, + databaseMock, execute( Eq("CREATE TABLE testTable(name TEXT REFERENCES foreignTable(foreignColumn) ON UPDATE " "SET DEFAULT ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED)"))); - table.initialize(mockDatabase); + table.initialize(databaseMock); } TEST_F(SqliteTable, AddColumn) @@ -299,10 +299,10 @@ TEST_F(SqliteTable, AddPrimaryTableContraint) const auto &nameColumn = table.addColumn("name"); table.addPrimaryKeyContraint({idColumn, nameColumn}); - EXPECT_CALL(mockDatabase, + EXPECT_CALL(databaseMock, execute( Eq("CREATE TABLE testTable(id NUMERIC, name NUMERIC, PRIMARY KEY(id, name))"))); - table.initialize(mockDatabase); + table.initialize(databaseMock); } } // namespace diff --git a/tests/unit/unittest/sqliteteststatement.h b/tests/unit/unittest/sqliteteststatement.h index 8705280ca62..f2fe6ba2959 100644 --- a/tests/unit/unittest/sqliteteststatement.h +++ b/tests/unit/unittest/sqliteteststatement.h @@ -27,11 +27,13 @@ #include -class SqliteTestStatement : public Sqlite::StatementImplementation +class SqliteTestStatement : public Sqlite::StatementImplementation { + using Base = Sqlite::StatementImplementation; + public: explicit SqliteTestStatement(Utils::SmallStringView sqlStatement, Sqlite::Database &database) - : Sqlite::StatementImplementation(sqlStatement, database) + : Base(sqlStatement, database) {} }; diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp index 0aa426db675..aaadd22d13e 100644 --- a/tests/unit/unittest/sqlitetransaction-test.cpp +++ b/tests/unit/unittest/sqlitetransaction-test.cpp @@ -27,9 +27,9 @@ #include "mocksqlitetransactionbackend.h" -#include +#include #include -#include +#include namespace { diff --git a/tests/unit/unittest/sqlitevalue-test.cpp b/tests/unit/unittest/sqlitevalue-test.cpp index 1a90c330f07..682e8087abb 100644 --- a/tests/unit/unittest/sqlitevalue-test.cpp +++ b/tests/unit/unittest/sqlitevalue-test.cpp @@ -26,6 +26,7 @@ #include "googletest.h" #include +#include namespace { @@ -85,13 +86,22 @@ TEST(SqliteValue, ConstructStringFromQString) ASSERT_THAT(value.toStringView(), Eq("foo")); } -TEST(SqliteValue, ConstructStringFromBlob) +TEST(SqliteValue, ConstructBlobFromSpan) { - // Utils::span bytes{reinterpret_cast("abcd"), 4}; + Utils::span bytes{reinterpret_cast("abcd"), 4}; - // Sqlite::Value value{bytes}; + Sqlite::Value value{Sqlite::BlobView{bytes}}; - //ASSERT_THAT(value.toBlob(), Eq(bytes)); + ASSERT_THAT(value.toBlobView(), Eq(bytes)); +} + +TEST(SqliteValue, ConstructBlobFromBlob) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + + Sqlite::Value value{Sqlite::Blob{bytes}}; + + ASSERT_THAT(value.toBlobView(), Eq(bytes)); } TEST(SqliteValue, ConstructNullFromNullQVariant) @@ -148,6 +158,16 @@ TEST(SqliteValue, ConstructStringFromStringQVariant) ASSERT_THAT(value.toStringView(), Eq("foo")); } +TEST(SqliteValue, ConstructBlobFromByteArrayQVariant) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + QVariant variant{QByteArray{"abcd"}}; + + Sqlite::Value value{variant}; + + ASSERT_THAT(value.toBlobView(), Eq(bytes)); +} + TEST(SqliteValue, ConvertToNullQVariant) { Sqlite::Value value{}; @@ -184,6 +204,16 @@ TEST(SqliteValue, ConvertToFloatQVariant) ASSERT_THAT(variant, Eq(1.1)); } +TEST(SqliteValue, ConvertToByteArrayQVariant) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + Sqlite::Value value{bytes}; + + auto variant = QVariant{value}; + + ASSERT_THAT(variant, Eq(QByteArray{"abcd"})); +} + TEST(SqliteValue, IntegerEquals) { bool isEqual = Sqlite::Value{1} == 1LL; @@ -226,6 +256,22 @@ TEST(SqliteValue, StringEqualsInverse) ASSERT_TRUE(isEqual); } +TEST(SqliteValue, BlobEquals) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + bool isEqual = Sqlite::Value{bytes} == bytes; + + ASSERT_TRUE(isEqual); +} + +TEST(SqliteValue, BlobInverseEquals) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + bool isEqual = bytes == Sqlite::Value{bytes}; + + ASSERT_TRUE(isEqual); +} + TEST(SqliteValue, IntegerAndFloatAreNotEquals) { bool isEqual = Sqlite::Value{1} == 1.; @@ -324,6 +370,14 @@ TEST(SqliteValue, StringType) ASSERT_THAT(type, Sqlite::ValueType::String); } +TEST(SqliteValue, BlobType) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + auto type = Sqlite::Value{bytes}.type(); + + ASSERT_THAT(type, Sqlite::ValueType::Blob); +} + TEST(SqliteValue, NullValueAndValueViewAreNotEqual) { bool isEqual = Sqlite::ValueView::create(Sqlite::NullValue{}) == Sqlite::Value{}; @@ -387,6 +441,15 @@ TEST(SqliteValue, StringValueAndIntergerValueViewAreNotEqual) ASSERT_FALSE(isEqual); } +TEST(SqliteValue, BlobValueAndValueViewEquals) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + + bool isEqual = Sqlite::ValueView::create(bytes) == Sqlite::Value{bytes}; + + ASSERT_TRUE(isEqual); +} + TEST(SqliteValue, ConvertNullValueViewIntoValue) { auto view = Sqlite::ValueView::create(Sqlite::NullValue{}); @@ -423,4 +486,14 @@ TEST(SqliteValue, ConvertFloatValueViewIntoValue) ASSERT_THAT(value, Eq(1.4)); } +TEST(SqliteValue, ConvertBlobValueViewIntoValue) +{ + Utils::span bytes{reinterpret_cast("abcd"), 4}; + auto view = Sqlite::ValueView::create(bytes); + + Sqlite::Value value{view}; + + ASSERT_THAT(value, Eq(Sqlite::BlobView{bytes})); +} + } // namespace diff --git a/tests/unit/unittest/sqlitewritestatementmock.h b/tests/unit/unittest/sqlitewritestatementmock.h index 64ce061d607..30f8383b6be 100644 --- a/tests/unit/unittest/sqlitewritestatementmock.h +++ b/tests/unit/unittest/sqlitewritestatementmock.h @@ -74,8 +74,35 @@ public: Utils::SmallStringView, Utils::SmallStringView), ()); + MOCK_METHOD(void, + write, + (int, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + int, + int, + int), + ()); MOCK_METHOD(void, write, (void *, long long), ()); + MOCK_METHOD(void, write, (int), ()); + MOCK_METHOD(void, write, (int, long long), ()); + MOCK_METHOD(void, write, (int, int), ()); + MOCK_METHOD(void, write, (uint, uint, uint), ()); + MOCK_METHOD(void, write, (int, off_t, time_t), ()); + MOCK_METHOD(void, write, (uint, uint), ()); + MOCK_METHOD(void, write, (uchar, int), ()); + MOCK_METHOD(void, write, (int, int, uchar, uchar), ()); + MOCK_METHOD(void, write, (long long, int), ()); + MOCK_METHOD(void, write, (uint, Utils::SmallStringView, Utils::SmallStringView, uint), ()); + MOCK_METHOD(void, write, (uint, uint, uint, uint), ()); + MOCK_METHOD(void, write, (long long, int, int, int), ()); + MOCK_METHOD(void, write, (long long, int, int, int, int), ()); + MOCK_METHOD(void, write, (uint, Utils::SmallStringView), ()); + MOCK_METHOD(void, write, (int, Utils::SmallStringView), ()); + MOCK_METHOD(void, write, (int, Utils::SmallStringView, long long), ()); Utils::SmallString sqlStatement; }; diff --git a/tests/unit/unittest/stringcache-test.cpp b/tests/unit/unittest/stringcache-test.cpp index 5a2b1d404dc..625de6e5a51 100644 --- a/tests/unit/unittest/stringcache-test.cpp +++ b/tests/unit/unittest/stringcache-test.cpp @@ -27,7 +27,7 @@ #include "mockfilepathstorage.h" #include "mockmutex.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include @@ -86,8 +86,8 @@ protected: } protected: - NiceMock mockDatabase; - NiceMock mockStorage{mockDatabase}; + NiceMock databaseMock; + NiceMock mockStorage{databaseMock}; StorageIdFunction mockStorageFetchDirectyId; StorageStringFunction mockStorageFetchDirectyPath; Cache cache; diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 25c7056f022..63c8d04f6dc 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -263,7 +263,7 @@ protected: mockProjectPartsStorage, mockModifiedTimeChecker, testEnvironment}; - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter, mockSqliteDatabase}; Scheduler indexerScheduler{collectorManger, indexerQueue, diff --git a/tests/unit/unittest/symbolindexertaskqueue-test.cpp b/tests/unit/unittest/symbolindexertaskqueue-test.cpp index 1364091161a..7862231a66d 100644 --- a/tests/unit/unittest/symbolindexertaskqueue-test.cpp +++ b/tests/unit/unittest/symbolindexertaskqueue-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include "mocktaskscheduler.h" #include @@ -55,7 +55,7 @@ protected: NiceMock> mockSetProgressCallback; ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; NiceMock> mockTaskScheduler; - NiceMock mockSqliteDatabase; + NiceMock mockSqliteDatabase; ClangBackEnd::SymbolIndexerTaskQueue queue{mockTaskScheduler, progressCounter, mockSqliteDatabase}; }; diff --git a/tests/unit/unittest/symbolindexing-test.cpp b/tests/unit/unittest/symbolindexing-test.cpp index 67411efd370..d2233d95160 100644 --- a/tests/unit/unittest/symbolindexing-test.cpp +++ b/tests/unit/unittest/symbolindexing-test.cpp @@ -54,7 +54,7 @@ using ClangRefactoring::QuerySqliteStatementFactory; using Utils::PathString; using SL = ClangRefactoring::SourceLocations; -using StatementFactory = QuerySqliteStatementFactory; +using StatementFactory = QuerySqliteStatementFactory; using Query = SymbolQuery; MATCHER_P3(IsLocation, filePathId, line, column, diff --git a/tests/unit/unittest/symbolquery-test.cpp b/tests/unit/unittest/symbolquery-test.cpp index 3ff541564e5..e01891fa331 100644 --- a/tests/unit/unittest/symbolquery-test.cpp +++ b/tests/unit/unittest/symbolquery-test.cpp @@ -25,8 +25,7 @@ #include "googletest.h" -#include "mocksqlitedatabase.h" -#include "mocksqlitereadstatement.h" +#include "sqlitedatabasemock.h" #include #include @@ -42,28 +41,32 @@ using ClangRefactoring::QuerySqliteStatementFactory; using Sqlite::Database; using ClangBackEnd::SourceLocationKind; using ClangBackEnd::SymbolKind; -using MockStatementFactory = QuerySqliteStatementFactory; +using MockStatementFactory = QuerySqliteStatementFactory; using MockQuery = ClangRefactoring::SymbolQuery; -using RealStatementFactory = QuerySqliteStatementFactory; +using RealStatementFactory = QuerySqliteStatementFactory; using RealQuery = ClangRefactoring::SymbolQuery; class SymbolQuery : public testing::Test { + template + using ReadStatement = typename SqliteDatabaseMock::template ReadStatement; + protected: - NiceMock mockDatabase; - MockStatementFactory mockStatementFactory{mockDatabase}; - MockSqliteReadStatement &selectLocationsForSymbolLocation = mockStatementFactory.selectLocationsForSymbolLocation; - MockSqliteReadStatement &selectSourceUsagesForSymbolLocation = mockStatementFactory.selectSourceUsagesForSymbolLocation; - MockSqliteReadStatement &selectSymbolsForKindAndStartsWith = mockStatementFactory.selectSymbolsForKindAndStartsWith; - MockSqliteReadStatement &selectSymbolsForKindAndStartsWith2 = mockStatementFactory.selectSymbolsForKindAndStartsWith2; - MockSqliteReadStatement &selectSymbolsForKindAndStartsWith3 = mockStatementFactory.selectSymbolsForKindAndStartsWith3; - MockSqliteReadStatement &selectLocationOfSymbol = mockStatementFactory.selectLocationOfSymbol; - MockSqliteReadStatement &selectSourceUsagesOrderedForSymbolLocation = mockStatementFactory - .selectSourceUsagesOrderedForSymbolLocation; - MockSqliteReadStatement &selectSourceUsagesByLocationKindForSymbolLocation + NiceMock databaseMock; + MockStatementFactory mockStatementFactory{databaseMock}; + ReadStatement<3> &selectLocationsForSymbolLocation = mockStatementFactory.selectLocationsForSymbolLocation; + ReadStatement<3> &selectSourceUsagesForSymbolLocation = mockStatementFactory + .selectSourceUsagesForSymbolLocation; + ReadStatement<3> &selectSymbolsForKindAndStartsWith = mockStatementFactory.selectSymbolsForKindAndStartsWith; + ReadStatement<3> &selectSymbolsForKindAndStartsWith2 = mockStatementFactory + .selectSymbolsForKindAndStartsWith2; + ReadStatement<3> &selectSymbolsForKindAndStartsWith3 = mockStatementFactory + .selectSymbolsForKindAndStartsWith3; + ReadStatement<3> &selectLocationOfSymbol = mockStatementFactory.selectLocationOfSymbol; + ReadStatement<3> &selectSourceUsagesOrderedForSymbolLocation = mockStatementFactory + .selectSourceUsagesOrderedForSymbolLocation; + ReadStatement<3> &selectSourceUsagesByLocationKindForSymbolLocation = mockStatementFactory.selectSourceUsagesByLocationKindForSymbolLocation; SourceLocations locations{{1, 1, 1}, {1, 2, 3}, {2, 1, 1}, {2, 3, 1}, {4, 1, 1}, {4, 1, 3}}; MockQuery query{mockStatementFactory}; diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index c480296f120..a73d261fcc1 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -26,7 +26,7 @@ #include "googletest.h" #include "mockfilepathcaching.h" -#include "mocksqlitedatabase.h" +#include "sqlitedatabasemock.h" #include #include @@ -52,23 +52,27 @@ using Sqlite::Database; using Sqlite::Table; using Utils::PathString; -using Storage = ClangBackEnd::SymbolStorage; +using Storage = ClangBackEnd::SymbolStorage; +using DatabaseType = Database; +template +using ReadStatement = typename SqliteDatabaseMock::template ReadStatement; +using WriteStatement = typename SqliteDatabaseMock::WriteStatement; class SymbolStorage : public testing::Test { protected: - NiceMock mockDatabase; - Storage storage{mockDatabase}; - MockSqliteWriteStatement &insertSymbolsToNewSymbolsStatement = storage.insertSymbolsToNewSymbolsStatement; - MockSqliteWriteStatement &insertLocationsToNewLocationsStatement = storage.insertLocationsToNewLocationsStatement; - MockSqliteReadStatement &selectNewSourceIdsStatement = storage.selectNewSourceIdsStatement; - MockSqliteWriteStatement &addNewSymbolsToSymbolsStatement = storage.addNewSymbolsToSymbolsStatement; - MockSqliteWriteStatement &syncNewSymbolsFromSymbolsStatement = storage.syncNewSymbolsFromSymbolsStatement; - MockSqliteWriteStatement &syncSymbolsIntoNewLocationsStatement = storage.syncSymbolsIntoNewLocationsStatement; - MockSqliteWriteStatement &deleteAllLocationsFromUpdatedFilesStatement = storage.deleteAllLocationsFromUpdatedFilesStatement; - MockSqliteWriteStatement &insertNewLocationsInLocationsStatement = storage.insertNewLocationsInLocationsStatement; - MockSqliteWriteStatement &deleteNewSymbolsTableStatement = storage.deleteNewSymbolsTableStatement; - MockSqliteWriteStatement &deleteNewLocationsTableStatement = storage.deleteNewLocationsTableStatement; + NiceMock databaseMock; + Storage storage{databaseMock}; + WriteStatement &insertSymbolsToNewSymbolsStatement = storage.insertSymbolsToNewSymbolsStatement; + WriteStatement &insertLocationsToNewLocationsStatement = storage.insertLocationsToNewLocationsStatement; + ReadStatement<1> &selectNewSourceIdsStatement = storage.selectNewSourceIdsStatement; + WriteStatement &addNewSymbolsToSymbolsStatement = storage.addNewSymbolsToSymbolsStatement; + WriteStatement &syncNewSymbolsFromSymbolsStatement = storage.syncNewSymbolsFromSymbolsStatement; + WriteStatement &syncSymbolsIntoNewLocationsStatement = storage.syncSymbolsIntoNewLocationsStatement; + WriteStatement &deleteAllLocationsFromUpdatedFilesStatement = storage.deleteAllLocationsFromUpdatedFilesStatement; + WriteStatement &insertNewLocationsInLocationsStatement = storage.insertNewLocationsInLocationsStatement; + WriteStatement &deleteNewSymbolsTableStatement = storage.deleteNewSymbolsTableStatement; + WriteStatement &deleteNewLocationsTableStatement = storage.deleteNewLocationsTableStatement; SymbolEntries symbolEntries{{1, {"functionUSR", "function", SymbolKind::Function}}, {2, {"function2USR", "function2", SymbolKind::Function}}}; SourceLocationEntries sourceLocations{{1, 3, {42, 23}, SourceLocationKind::Declaration}, @@ -156,9 +160,9 @@ TEST_F(SymbolStorage, AddNewSymbolsTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT, symbolKind INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT, symbolKind INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); storage.createNewSymbolsTable(); } @@ -167,8 +171,8 @@ TEST_F(SymbolStorage, AddNewLocationsTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, sourceId INTEGER, line INTEGER, column INTEGER, locationKind INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_newLocations_sourceId_line_column ON newLocations(sourceId, line, column)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, sourceId INTEGER, line INTEGER, column INTEGER, locationKind INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_newLocations_sourceId_line_column ON newLocations(sourceId, line, column)"))); storage.createNewLocationsTable(); } @@ -177,15 +181,15 @@ TEST_F(SymbolStorage, AddTablesInConstructor) { InSequence s; - EXPECT_CALL(mockDatabase, immediateBegin()); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT, symbolKind INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, sourceId INTEGER, line INTEGER, column INTEGER, locationKind INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_newLocations_sourceId_line_column ON newLocations(sourceId, line, column)"))); - EXPECT_CALL(mockDatabase, commit()); + EXPECT_CALL(databaseMock, immediateBegin()); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT, symbolKind INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, sourceId INTEGER, line INTEGER, column INTEGER, locationKind INTEGER)"))); + EXPECT_CALL(databaseMock, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_newLocations_sourceId_line_column ON newLocations(sourceId, line, column)"))); + EXPECT_CALL(databaseMock, commit()); - Storage storage{mockDatabase}; + Storage storage{databaseMock}; } } // namespace diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 2d8d51b7bab..2a1a2d8ec56 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -97,7 +97,6 @@ SOURCES += \ unittests-main.cpp \ utf8-test.cpp \ symbolstorage-test.cpp \ - mocksqlitereadstatement.cpp \ symbolquery-test.cpp \ sqliteindex-test.cpp \ sqlitetransaction-test.cpp \ @@ -191,6 +190,8 @@ SOURCES += \ unsavedfiles-test.cpp \ unsavedfile-test.cpp \ utf8positionfromlinecolumn-test.cpp \ + clangreferencescollector-test.cpp \ + clangdocumentsuspenderresumer-test.cpp \ readexporteddiagnostics-test.cpp !isEmpty(QTC_UNITTEST_BUILD_CPP_PARSER):SOURCE += \ @@ -203,11 +204,9 @@ SOURCES += \ !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ gtest-llvm-printing.cpp \ - clangdocumentsuspenderresumer-test.cpp \ clangquerygatherer-test.cpp \ clangqueryprojectfindfilter-test.cpp \ clangquery-test.cpp \ - clangreferencescollector-test.cpp \ pchcreator-test.cpp \ refactoringclientserverinprocess-test.cpp \ refactoringclient-test.cpp \ @@ -275,9 +274,6 @@ HEADERS += \ testenvironment.h \ mocksymbolscollector.h \ mocksymbolstorage.h \ - mocksqlitewritestatement.h \ - mocksqlitedatabase.h \ - mocksqlitereadstatement.h \ google-using-declarations.h \ mocksymbolindexing.h \ sqliteteststatement.h \ diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs index 61ad2fb5291..7f2bea7cf8a 100644 --- a/tests/unit/unittest/unittest.qbs +++ b/tests/unit/unittest/unittest.qbs @@ -263,12 +263,8 @@ Project { "mocksearch.h", "mocksearchhandle.h", "mocksearchresult.h", - "mocksqlitedatabase.h", - "mocksqlitereadstatement.cpp", - "mocksqlitereadstatement.h", "mocksqlitestatement.h", "mocksqlitetransactionbackend.h", - "mocksqlitewritestatement.h", "mocksymbolindexertaskqueue.h", "mocksymbolindexing.h", "mocksymbolquery.h", @@ -312,12 +308,17 @@ Project { "sqlitecolumn-test.cpp", "sqlitedatabase-test.cpp", "sqlitedatabasebackend-test.cpp", + "sqlitedatabasemock.h", "sqliteindex-test.cpp", + "sqlitereadstatementmock.cpp", + "sqlitereadstatementmock.h", "sqlitestatement-test.cpp", "sqlitetable-test.cpp", "sqliteteststatement.h", "sqlitetransaction-test.cpp", "sqlitevalue-test.cpp", + "sqlitewritestatementmock.cpp", + "sqlitewritestatementmock.h", "sqlstatementbuilder-test.cpp", "stringcache-test.cpp", "symbolindexer-test.cpp",