diff --git a/cmake/FindQt5.cmake b/cmake/FindQt5.cmake index 1931bf019c2..a48e293e416 100644 --- a/cmake/FindQt5.cmake +++ b/cmake/FindQt5.cmake @@ -83,6 +83,10 @@ foreach(tool qmake lrelease lupdate moc rcc qhelpgenerator) if (TARGET Qt6::${tool} AND NOT TARGET Qt5::${tool}) add_executable(Qt5::${tool} IMPORTED GLOBAL) get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION) + # handle separate tools for each configuration + if (NOT imported_location) + get_target_property(imported_location Qt6::${tool} IMPORTED_LOCATION_RELEASE) + endif() set_target_properties(Qt5::${tool} PROPERTIES IMPORTED_LOCATION "${imported_location}") endif() endforeach() diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 194852d6b7f..1f36ac0af35 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -228,8 +228,8 @@ function(add_qtc_library name) CXX_EXTENSIONS OFF CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON - BUILD_RPATH "${_LIB_RPATH}" - INSTALL_RPATH "${_LIB_RPATH}" + BUILD_RPATH "${_LIB_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_LIB_RPATH};${CMAKE_INSTALL_RPATH}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${_DESTINATION}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}" @@ -478,8 +478,8 @@ function(add_qtc_plugin target_name) VISIBILITY_INLINES_HIDDEN ON _arg_DEPENDS "${_arg_PLUGIN_DEPENDS}" _arg_VERSION "${_arg_VERSION}" - BUILD_RPATH "${_PLUGIN_RPATH}" - INSTALL_RPATH "${_PLUGIN_RPATH}" + BUILD_RPATH "${_PLUGIN_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_PLUGIN_RPATH};${CMAKE_INSTALL_RPATH}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${plugin_dir}" @@ -654,6 +654,8 @@ function(add_qtc_executable name) file(RELATIVE_PATH relative_plugins_path "/${_EXECUTABLE_PATH}" "/${IDE_PLUGIN_PATH}") set(install_rpath "${install_rpath};${_RPATH_BASE}/${relative_qt_path};${_RPATH_BASE}/${relative_plugins_path}") endif() + set(build_rpath "${build_rpath};${CMAKE_BUILD_RPATH}") + set(install_rpath "${install_rpath};${CMAKE_INSTALL_RPATH}") qtc_output_binary_dir(_output_binary_dir) set_target_properties("${name}" PROPERTIES @@ -811,8 +813,8 @@ function(add_qtc_test name) LINK_DEPENDS_NO_SHARED ON CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON - BUILD_RPATH "${_RPATH_BASE}/${_RPATH}" - INSTALL_RPATH "${_RPATH_BASE}/${_RPATH}" + BUILD_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_RPATH_BASE}/${_RPATH};${CMAKE_INSTALL_RPATH}" ) if (NOT _arg_SKIP_PCH) enable_pch(${name}) diff --git a/cmake/QtCreatorAPIInternal.cmake b/cmake/QtCreatorAPIInternal.cmake index 86fe1c0d939..d7bef93491f 100644 --- a/cmake/QtCreatorAPIInternal.cmake +++ b/cmake/QtCreatorAPIInternal.cmake @@ -80,7 +80,7 @@ else () set(_IDE_LIBRARY_ARCHIVE_PATH "${_IDE_LIBRARY_PATH}") set(_IDE_HEADER_INSTALL_PATH "include/qtcreator") - set(_IDE_CMAKE_INSTALL_PATH "lib/cmake") + set(_IDE_CMAKE_INSTALL_PATH "${_IDE_LIBRARY_BASE_PATH}/cmake") endif () file(RELATIVE_PATH _PLUGIN_TO_LIB "/${_IDE_PLUGIN_PATH}" "/${_IDE_LIBRARY_PATH}") diff --git a/dist/changes-7.0.0.md b/dist/changes-7.0.0.md new file mode 100644 index 00000000000..a9c98815a54 --- /dev/null +++ b/dist/changes-7.0.0.md @@ -0,0 +1,228 @@ +Qt Creator 7 +============ + +Qt Creator version 7 contains bug fixes and new features. + +The most important changes are listed in this document. For a complete list of +changes, see the Git log for the Qt Creator sources that you can check out from +the public Git repository. For example: + + git clone git://code.qt.io/qt-creator/qt-creator.git + git log --cherry-pick --pretty=oneline origin/6.0..v7.0.0 + +General +------- + +* Gave `Welcome` a fresh look +* Split `New File or Project` into `New File` and `New Project` +* Added optional notification of new Qt releases available in the online + installer (QTCREATORBUG-26708) +* Added `Show in File System View` to more context menus, like `Show in + Explorer/Finder` +* Added `Tools > Debug Qt Creator > Show Logs` for viewing Qt Creator debug logs +* Moved C++ code model and language client inspectors to `Tools > Debug Qt + Creator` + +Editing +------- + +* Added action for selecting all search results in a document +* Added support for choosing external editor as default editor + (QTCREATORBUG-13880) +* Fixed copy action in text editing macros (QTCREATORBUG-26363) + +### C++ + +* Switched to Clangd by default (QTCREATORBUG-22917) +* Fixed that compilation errors appeared below code model errors in `Issues` + pane (QTCREATORBUG-23655) +* Fixed that duplication files did not adapt header guard (QTCREATORBUG-26654) +* Fixed highlighting and indentation of raw string literals (QTCREATORBUG-26211) +* Fixed performance issue in global indexer (QTCREATORBUG-26841) +* clang-format + * Moved settings to `Code Style` editor + * Added synchronization between `clang-format` settings and custom code style +* Clangd + * Added memory usage inspector to language client inspector + * Added highlighting of `Q_PROPERTY` declarations + * Improved display of diagnostic messages + * Fixed access type categorization for functions + +### QML + +* Updated parser to latest Qt version +* Fixed that application directory was not searched for QML modules + (QTCREATORBUG-24987) + +### Python + +* Added Python specific language server settings + +### Language Server Protocol + +* Removed support for outdated semantic highlighting protocol proposal + (QTCREATORBUG-26624) +* Fixed that outdated diagnostic could be shown (QTCREATORBUG-26585) +* Fixed issue with re-highlighting (QTCREATORBUG-26624) + +### FakeVim + +* Added support for backslashes in substitute command (QTCREATORBUG-26955) + +Projects +-------- + +* Added option to override GCC target triple (QTCREATORBUG-26913) +* Added multiple selection to `Issues` pane (QTCREATORBUG-25547, + QTCREATORBUG-26720) +* Improved automatic (re-)detection of toolchains (QTCREATORBUG-26460) +* Fixed unnecessary toolchain calls at startup + +### CMake + +* Removed grouping of CMake cache variables (QTCREATORBUG-26218) +* Made it possible to stop CMake with button in build configuration +* Renamed `Initial Parameters` to `Initial Configuration` and moved into tabbed + view with `Current Configuration` +* Added field for passing additional CMake options to kit, initial, and current + configuration (QTCREATORBUG-26826) +* Added button for editing kit CMake configuration directly from build + configuration +* Added hint for mismatches between kit, initial, and current configuration +* Added context menu actions for resolving mismatches between kit, initial and + current configuration +* Added `Help` to context menu for variable names + +### Generic + +* Added support for precompiled headers (QTCREATORBUG-26532) + +### Autotools + +* Fixed parsing of `SUBDIRS` + +Debugging +--------- + +* Added debugging helper for `std::variant`, `boost::container::devector`, and + `boost::small_vector` +* Added debugging helper for `QStringView` (QTCREATORBUG-20918) +* Added `Char Code Integer`, `Hexadecimal Float`, and `Normalized, with + Power-of-Two Exponent` display formats (QTCREATORBUG-22849, + QTCREATORBUG-26793) +* Added shortcut for disabling and enabling breakpoints (QTCREATORBUG-26788) + +Analyzer +-------- + +### QML + +* Added support for profiling QtQuick3D (QTBUG-98146) + +Version Control Systems +----------------------- + +### Git + +* Added support for filtering log by author +* Added handling of `HOMEDRIVE` and `HOMEPATH` on Windows +* Fixed that conflicts with deleted files could not be resolved + (QTCREATORBUG-26994) + +Test Integration +---------------- + +### QTest + +* Added option for maximum number of warnings (QTCREATORBUG-26637) + +### Qt Quick + +* Added option for setup code to wizard (QTCREATORBUG-26741) + +Platforms +--------- + +### macOS + +* Fixed that macOS dark mode was not used for dark themes (QTCREATORBUG-22477) +* Fixed that user applications inherited access permissions from Qt Creator + (QTCREATORBUG-26743) + +### Android + +* Added option for default NDK (QTCREATORBUG-21755, QTCREATORBUG-22389, + QTCREATORBUG-24248, QTCREATORBUG-26281) +* Fixed that `Include prebuilt OpenSSL libraries` could add it to the wrong + `.pro` file (QTCREATORBUG-24255) +* Fixed debugging of devices with upper case identifier with LLDB + (QTCREATORBUG-26709) +* Fixed detection of available NDK platforms for recent NDKs + (QTCREATORBUG-26772) + +### Remote Linux + +* Fixed UI state after stopping remote applications (QTCREATORBUG-26848) + +### WebAssembly + +* Improved browser selection (QTCREATORBUG-25028, QTCREATORBUG-26559) +* Fixed running CMake-based Qt Quick applications with Qt 6.2 + (QTCREATORBUG-26562) + +### MCU + +* Added support for Renesas Flash Programmer (UL-5082) + +### Docker + +* Added experimental support for macOS hosts + +Credits for these changes go to: +-------------------------------- +Aaron Barany +Alessandro Portale +Alexander Drozdov +Allan Sandfeld Jensen +André Pönitz +Anton Alimoff +Artem Sokolovskii +Assam Boudjelthia +Christiaan Janssen +Christian Kandeler +Christian Stenger +Cristian Adam +Cristián Maureira-Fredes +David Schulz +Eike Ziller +Fawzi Mohamed +Henning Gruendl +Huixiong Cao +Janne Koskinen +Jaroslaw Kobus +Jean-Michaël Celerier +Jere Tuliniemi +Joerg Kreuzberger +Kai Köhne +Katarina Behrens +Knud Dollereder +Leena Miettinen +Mahmoud Badri +Marco Bubke +Maximilian Goldstein +Miikka Heikkinen +Morten Johan Sørvig +Orgad Shaneh +Petar Perisin +Piotr Mikolajczyk +Robert Löhning +Samuel Ghinet +Tasuku Suzuki +Thomas Hartmann +Tim Jenssen +Tony Leinonen +Topi Reinio +Tor Arne Vestbø +Ulf Hermann +Ville Nummela +XutaxKamay diff --git a/doc/qtcreator/images/qtcreator-android-cmake-settings.png b/doc/qtcreator/images/qtcreator-android-cmake-settings.png index e02c77c38bc..bbe680a0269 100644 Binary files a/doc/qtcreator/images/qtcreator-android-cmake-settings.png and b/doc/qtcreator/images/qtcreator-android-cmake-settings.png differ diff --git a/doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png b/doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png new file mode 100644 index 00000000000..9123fcffd4b Binary files /dev/null and b/doc/qtcreator/images/qtcreator-android-sdk-manager-arguments.png differ diff --git a/doc/qtcreator/images/qtcreator-android-sdk-manager.png b/doc/qtcreator/images/qtcreator-android-sdk-manager.png index 8ff625d2236..7f24683d741 100644 Binary files a/doc/qtcreator/images/qtcreator-android-sdk-manager.png and b/doc/qtcreator/images/qtcreator-android-sdk-manager.png differ diff --git a/doc/qtcreator/images/qtcreator-autotests-project-qt-test.png b/doc/qtcreator/images/qtcreator-autotests-project-qt-test.png new file mode 100644 index 00000000000..aa5bee758c6 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-autotests-project-qt-test.png differ diff --git a/doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png b/doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png new file mode 100644 index 00000000000..24d61b245ac Binary files /dev/null and b/doc/qtcreator/images/qtcreator-autotests-project-qtquick-test.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png b/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png index 90c632411b3..ca0dbd741b3 100644 Binary files a/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png and b/doc/qtcreator/images/qtcreator-cmake-build-settings-initial.png differ diff --git a/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png b/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png index 6a305822caf..d6dd2f6ed10 100644 Binary files a/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png and b/doc/qtcreator/images/qtcreator-cmake-kit-configuration.png differ diff --git a/doc/qtcreator/images/qtcreator-compilers-target-triple.png b/doc/qtcreator/images/qtcreator-compilers-target-triple.png new file mode 100644 index 00000000000..7157cae001e Binary files /dev/null and b/doc/qtcreator/images/qtcreator-compilers-target-triple.png differ diff --git a/doc/qtcreator/images/qtcreator-mime-types.png b/doc/qtcreator/images/qtcreator-mime-types.png index e91bbb8c644..26687cdf23d 100644 Binary files a/doc/qtcreator/images/qtcreator-mime-types.png and b/doc/qtcreator/images/qtcreator-mime-types.png differ diff --git a/doc/qtcreator/images/qtcreator-options-android-main.png b/doc/qtcreator/images/qtcreator-options-android-main.png index 15afbe73b6b..70d119b3206 100644 Binary files a/doc/qtcreator/images/qtcreator-options-android-main.png and b/doc/qtcreator/images/qtcreator-options-android-main.png differ diff --git a/doc/qtcreator/images/qtcreator-options-android-sdk-tools.png b/doc/qtcreator/images/qtcreator-options-android-sdk-tools.png index 966e3707a04..19237d1b789 100644 Binary files a/doc/qtcreator/images/qtcreator-options-android-sdk-tools.png and b/doc/qtcreator/images/qtcreator-options-android-sdk-tools.png differ diff --git a/doc/qtcreator/images/qtcreator-options-clangd.png b/doc/qtcreator/images/qtcreator-options-clangd.png index a277d076c96..ef955f4563d 100644 Binary files a/doc/qtcreator/images/qtcreator-options-clangd.png and b/doc/qtcreator/images/qtcreator-options-clangd.png differ diff --git a/doc/qtcreator/images/qtcreator-toolchains.png b/doc/qtcreator/images/qtcreator-toolchains.png index 1e54fe33330..c82b677b5db 100644 Binary files a/doc/qtcreator/images/qtcreator-toolchains.png and b/doc/qtcreator/images/qtcreator-toolchains.png differ diff --git a/doc/qtcreator/src/android/androiddev.qdoc b/doc/qtcreator/src/android/androiddev.qdoc index cda10b5a287..e9f3e569fa5 100644 --- a/doc/qtcreator/src/android/androiddev.qdoc +++ b/doc/qtcreator/src/android/androiddev.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -113,8 +113,11 @@ The locked items were installed by the SDK Manager, and can only be modified from the \uicontrol {SDK Manager} tab. For more information, see \l{Managing Android NDK Packages}. - \li In the \uicontrol {Android OpenSSL} group, set the path to the - prebuilt OpenSSL libraries. + \li Select the \uicontrol {Automatically create kits for Android tool chains} + check box to allow \QC to create the kits for you. \QC displays a + warning if it cannot find a suitable Qt version. + \li Optionally, in the \uicontrol {Android OpenSSL Settings} group, set + the path to the prebuilt OpenSSL libraries. For Qt applications that require OpenSSL support, \QC allows to quickly add the \l {Android OpenSSL support} to your project. @@ -122,9 +125,6 @@ \li Select \uicontrol {Download OpenSSL} to download the OpenSSL repository to the selected path. If the automatic download fails, the download web page opens for manual download. - \li Select the \uicontrol {Automatically create kits for Android tool chains} - check box to allow \QC to create the kits for you. \QC displays a - warning if it cannot find a suitable Qt version. \endlist \section2 Manual Setup @@ -185,6 +185,9 @@ To manually download NDKs, select \inlineimage icons/online.png . + To use the selected NDK version for all Qt versions by default, select + \uicontrol {Make Default}. + To add custom NDK paths manually to the global list of NDKs, select \uicontrol Add. This creates custom tool chains and debuggers associated to that NDK. However, you have to manually create a kit that uses the @@ -206,8 +209,12 @@ \image qtcreator-android-sdk-manager.png "Android SDK Manager" - To filter the packages, select \uicontrol Available, \uicontrol Installed, - or \uicontrol All in \uicontrol {Show Packages}. + You can show packages for the release channel you select in + \uicontrol {Show Packages} > \uicontrol Channel. Common channel IDs include + \uicontrol Stable, \uicontrol Beta, \uicontrol Dev, and \uicontrol Canary. + To show and update also obsolete packages, select + \uicontrol {Include obsolete}. To filter packages, select + \uicontrol Available, \uicontrol Installed, or \uicontrol All. To update the installed Android SDK packages, select \uicontrol {Update Installed}. Select the packages to update, and then @@ -218,6 +225,8 @@ \uicontrol {SDK Manager arguments} field. The available arguments are listed and described in \uicontrol {Available arguments}. + \image qtcreator-android-sdk-manager-arguments.png "Android SDK Manager Arguments dialog" + \section1 Managing Android Virtual Devices (AVD) The available AVDs are listed in \uicontrol Tools > \uicontrol Options diff --git a/doc/qtcreator/src/android/deploying-android.qdoc b/doc/qtcreator/src/android/deploying-android.qdoc index 362abd7cf3e..4f361e44222 100644 --- a/doc/qtcreator/src/android/deploying-android.qdoc +++ b/doc/qtcreator/src/android/deploying-android.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -128,8 +128,8 @@ \section2 Specifying Settings for Packages To specify settings for the \c androiddeployqt tool, select - \uicontrol Projects > \uicontrol Build > \uicontrol {Build Android APK} > - \uicontrol Details. + \uicontrol Projects > \uicontrol {Build & Run} > \uicontrol Build > + \uicontrol {Build Android APK} > \uicontrol Details. \image qtcreator-android-build-apk-step.png "Build Android APK step" @@ -166,9 +166,9 @@ distribution to the Google Play store, create an AAB by selecting the \uicontrol {Build Android App Bundle (*.aab)} check box. - When building with CMake, you can view the selected ABIs in the - \uicontrol {Initial CMake parameters} field in the \uicontrol CMake section. - You can set additional ABIs as values of the ANDROID_ABI key: + When building with CMake, you can view the selected ABIs in + \uicontrol {Initial Configuration} in the \uicontrol CMake section. + You can set additional ABIs as values of the \c ANDROID_ABI key: \image qtcreator-android-cmake-settings.png "CMake settings for building AABs" diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc index 8b72312a817..2932e1c9d81 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake-building.qdoc @@ -41,15 +41,16 @@ You can view and edit the actual values of the variables that are passed to CMake. Variable names are listed in the \uicontrol Key column and their - current values in the \uicontrol Value column. For more information - about the available variables, see \l{CMake: cmake-variables(7)}. - For more information about Qt-specific variables, see - \l{CMake Variable Reference}. + current values in the \uicontrol Value column. For more information about + the available variables, select \uicontrol Help in the context menu or see + \l{CMake: cmake-variables(7)}. For more information about Qt-specific + variables, see \l{CMake Variable Reference}. You can specify additional CMake options, such as \c {--find-debug}, \c {--preset}, \c {--trace-expand}, or \c {--warn-uninitialized}, in \uicontrol {Additional CMake options}. For more information about - the available options, see \l{CMake: cmake(1)}. + the available options, click the link in the field name or see + \l{CMake: cmake(1)}. After successfully running CMake, you can view and modify the current configuration in \uicontrol {Current Configuration}. @@ -97,7 +98,10 @@ select \uicontrol Copy in the context menu. To modify the value of a variable, double-click it, or select it, - and then select \uicontrol Edit. + and then select \uicontrol Edit. If the initial, current, and kit + configuration get out of sync, select \uicontrol {Apply Kit Value} or + \uicontrol {Apply Initial Configuration Value} in the context menu in + \uicontrol {Initial Configuration} or \uicontrol {Current Configuration}. You can apply actions to multiple variables at a time. To clear the selection, select \uicontrol {Clear Selection}. @@ -194,8 +198,9 @@ \image qtcreator-cmake-generator.png "CMake Generator dialog" \li In \uicontrol Generator, select \uicontrol Ninja. \li Select \uicontrol OK to save your changes and close the dialog. - \li Close the \uicontrol {Kit CMake Configuration} dialog to return to - \uicontrol {Build Settings}. + \li Select \uicontrol Close to close the + \uicontrol {Kit CMake Configuration} dialog + and return to \uicontrol {Build Settings}. \endlist \note To make sure that old build artifacts don't get in the way diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc index 0258564a0b0..5cac40c6372 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc @@ -72,6 +72,26 @@ \QC requires CMake's \l{https://cmake.org/cmake/help/latest/manual/cmake-file-api.7.html} {file-based API}, and therefore you'll need CMake version 3.14, or later. + For systems with older versions of CMake, only workarounds are available: + \list + + \li For CMake version 3.5 or later it is possible to generate a + \l{https://cmake.org/cmake/help/latest/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html}{compilation database} + and open that in \QC, as described in \l{Using Compilation Databases}. + + \li Create an ad-hoc project file for a qmake build using + \c{qmake -project} and \l{Opening Projects}{open} that in \QC. + Be aware that this is typically + not compilable without further manual changes. + + \li Manually create an ad-hoc project file for a + \l{Setting Up a Generic Project}{generic project} and + open that in \QC. Be aware this is typically + not compilable without further manual changes. + + \endlist + + To view and specify settings for CMake: \list 1 diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index 377f50394f4..3211d7d950a 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -149,11 +149,9 @@ \section1 Configuring clangd - You can use the experimental clangd support instead of libclang to receive - exact and complete results for services such as finding references, - following symbols under cursor, and using the locator, even for complex - constructs that the built-in code model cannot handle correctly. These - improvements are based on clangd's \e index. When you \l{Opening Projects} + The clangd \e index provides exact and complete results for services such + as finding references, following symbols under cursor, and using the + locator, even for complex constructs. When you \l{Opening Projects} {open a project}, clangd scans the source files to generate the index. For large projects, this can take a while, but the index is persistent and re-scanning is incremental, so nothing is lost by closing and re-starting @@ -171,8 +169,7 @@ {Outline} view is backed by clangd's document symbol support, which makes the results more reliable than before. - To use clangd for the current project instead of the built-in code model or - Clang: + To specify settings for clangd: \list 1 \li Select \uicontrol Tools > \uicontrol Options > \uicontrol C++ > diff --git a/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc b/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc index 6c4bf3803e5..5fefdd89317 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-mime-types.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -78,7 +78,8 @@ \li In \uicontrol Handler, double-click the editor name to display a context-menu where you can select another editor to open the file in by default. The menu is available only if alternative suitable - editors are available. + editors are available. Select \uicontrol {System Editor} to use + the system's default editor for files of this type by default. \li In \uicontrol Patterns, add the filename extension for the type of files that you want to identify as having this MIME type. diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc index c0c52f936d5..b755f99cf15 100644 --- a/doc/qtcreator/src/external-resources/external-resources.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources.qdoc @@ -101,6 +101,10 @@ \externalpage http://developer.android.com/guide/components/fundamentals.html \title Android Application Fundamentals */ +/*! + \externalpage https://doc.qt.io/qt/qtquicktest-index.html#executing-c-before-qml-tests + \title Executing C++ Before QML Tests +*/ /*! \externalpage https://doc.qt.io/qt/qtqml-cppintegration-overview.html \title Overview - QML and C++ Integration diff --git a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc index 4447c342cea..89064fe4de2 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -95,7 +95,9 @@ \uicontrol {Qt Test} or \uicontrol {Qt Quick Test}. \li For a Qt test, select the \uicontrol {GUI Application} check - box to create a Qt application. + box to create a Qt application. + + \image qtcreator-autotests-project-qt-test.png "Autotest project wizard - Qt Test" \li In the \uicontrol {Test case name} field, enter a name for the test case. @@ -104,6 +106,14 @@ check box to add the include statement for QApplication to the main.cpp file of the project. + \li For a Qt Quick test, select the + \uicontrol {Generate setup code} check box to execute C++ + code before any of the QML tests are run. The testing + framework will call slots and invokable functions, as + described in \l{Executing C++ Before QML Tests}. + + \image qtcreator-autotests-project-qtquick-test.png "Autotest project wizard - Qt Quick Test" + \li Select the \uicontrol {Generate initialization and cleanup code} checkbox to add functions to your test that are executed by the testing framework to initialize and clean diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc new file mode 100644 index 00000000000..72b4ed80305 --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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-project-creating.html + \page creator-file-creating.html + \nextpage creator-project-opening.html + + \title Creating Files + + You can use wizard templates to add individual files to your + \l{Creating Projects}{projects}. + The following table lists the wizard templates for creating files. + + \table + \header + \li Category + \li Wizard Template + \li Purpose + \row + \li {1,3} C/C++ + \li C++ Class + \li C++ header and source file for a new class that you can add to + a C++ project. + \row + \li C/C++ Source File + \li C++ source file that you can add to a C++ project. + \row + \li C/C++ Header File + \li C++ header file that you can add to a C++ project. + \row + \li {1,3} Modeling + \li State Chart + \li State Chart XML (SCXML) file that contains boilerplate + code for state machines. You can use the classes in the + \l {Qt SCXML} module to embed state machines created from + the files in Qt applications. + \row + \li Model + \li Universal Modeling Language (UML) style model with a structured + diagram. However, the model editor uses a variant of UML and + provides only a subset of properties for specifying the + appearance of model elements. For more information, see + \l {Modeling}. + \row + \li Scratch Model + \li Scratch model using a temporary file. + \row + \li {1,7} Qt + \li Qt Item Model + \li Source and header files that you can use to create classes + derived from QAbstractItemModel, QAbstractTableModel, or + QAbstractListModel. + \row + \li \QD Form Class + \li \QD form and a matching class for implementing a UI based + on Qt widgets. + \row + \li \QD Form + \li \QD form for Qt widget based projects. This is useful + if you already have an existing class for the UI logic. + \row + \li Qt Resource File + \li Resource file for storing binary files in the application + executable. + \row + \li QML File (Qt Quick 2) + \li QML file that imports Qt Quick 2.0 for use in Qt Quick projects. + \row + \li Qt Quick UI File + \li \l{UI Files}{UI file} (\e .ui.qml) and the corresponding + implementation file (\e .qml) for use in Qt Quick projects. + \row + \li JS File + \li JavaScript file that you can use to write the application logic + in Qt Quick projects. + \row + \li {1,4} GLSL + \li Fragment Shader (OpenGL/ES 2.0) + \li Fragment shader that generates the final pixel colors for + triangles, points, and lines rendered with OpenGL. You can use + it in both Qt Quick projects and Qt widget based projects. + \row + \li Vertex Shader (OpenGL/ES 2.0) + \li Vertex shader that transforms the positions, normals, and + texture coordinates of triangles, points, and lines rendered + with OpenGL. You can use it in both Qt Quick projects and Qt + widget based projects. + \row + \li Fragment Shader (Desktop OpenGL) + \li Fragment shader for use in both Qt Quick projects and Qt + widget based projects. + \row + \li Vertex Shader (Desktop OpenGL) + \li Vertex shader for use in both Qt Quick projects and Qt + widget based projects. + \row + \li {1,2} General + \li Empty File + \li Empty file that you can save with any filename extensio. + \row + \li Scratch Buffer + \li Scratch buffer that uses temporary files. You can + create this type of files for temporarily storing information + that you do not intend to save + \row + \li Java + \li Java File + \li Java class files that you can use to create Java classes. + \row + \li {1,2} Python + \li Python Class + \li Python class file. + \row + \li Python File + \li Python script file using UTF-8 encoding. + \row + \li {1,2} Nim (experimental) + \li Nim Script File + \li Empty Nim script file using UTF-8 encoding. + \row + \li Nim File + \li Empty Nim source file using UTF-8 encoding. + \endtable + + \section1 Creating C++ Classes + + The \uicontrol {C++ Class Wizard} allows you to create a C++ header and source + file for a new class that you can add to a C++ project. Specify the class + name, base class, and header and source files for the class. + + The wizard supports namespaces. To use a namespace, enter a qualified + class name in the \uicontrol {Class name} field. For example: + \c MyNamespace::MySubNamespace::MyClass. The wizard suggests + existing namespaces and class names as you type. + + \image qtcreator-cpp-class-wizard.png "Enter Class Name dialog" + + The names of the header and source file are based on the class name. To + change the default suffix of a file, select \uicontrol Tools > \uicontrol Options > + \uicontrol {C++} > \uicontrol {File Naming}. + + \image qtcreator-options-cpp-files.png "File Naming tab in Options" + + In the \uicontrol {License template} field, you can use + \l{Using Variables in Wizards}{predefined wizard variables} to specify the + path and filename of the license to use in the source and header files. + + You can create your own project and class wizards. For more information, + see \l{Adding New Custom Wizards}. + + \section1 Creating Resource Files + + \QC supports the \l{The Qt Resource System}{Qt Resource System}, which is a + platform-independent mechanism for storing files in the application's + executable. + + \image qtcreator-add-resource-wizard.png "New File dialog" + + The wizard creates a resource collection file (.qrc) that you can manage in + the resource editor. + + \image qtcreator-add-resource.png "Editing resource files" + + Select \uicontrol {Add Files} to locate and add individual + files. + + To list the folders and files in ascending alphabetic order in the source + tree, select \uicontrol {Sort Alphabetically} in the context menu. + + By default, resources are accessible in the application under the same file + name as they have in the source tree, with a \c{:/} prefix, or by a URL with + a \c qrc scheme. To specify a path prefix for all files in the \c .qrc file, + select \uicontrol {Add Prefix} and enter the prefix in the \uicontrol Prefix + field. + + Some resources need to change based on the user's locale, such as + translation files or icons. You can specify a locale in the + \uicontrol Language field. + + Select \uicontrol Remove to remove the selected file from the resource + collection. In the \uicontrol {Remove File} dialog, select the + \uicontrol {Delete file permanently} check box to remove the file from + the file system. To remove files that cannot be found in the file system, + select \uicontrol {Remove Missing Files}. + + The above functions are also available in the context menu in the + \uicontrol Projects view. + + \section1 Creating OpenGL Fragment and Vertex Shaders + + Qt provides support for integration with OpenGL implementations on all + platforms, which allows you to display hardware accelerated 3D graphics + alongside a more conventional user interface. For more information, see + \l{Qt GUI}. + + You can use the QOpenGLShader class to compile OpenGL shaders written in the + OpenGL Shading Language (GLSL) and in the OpenGL/ES Shading Language + (GLSL/ES). QOpenGLShader and QOpenGLShaderProgram shelter you from the + details of + compiling and linking vertex and fragment shaders. + + You can use \QC code editor to write fragment and vertex shaders + in GLSL or GLSL/ES. The code editor provides syntax highlighting and code + completion for the files. + + \image qtcreator-new-opengl-file.png "New OpenGL file wizard" +*/ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc index e03e367aba0..79280560dca 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-compilers.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -181,6 +181,13 @@ target architecture. This is used to warn about ABI mismatches within the kits. + \li In the \uicontrol {Target triple} field, specify the GCC target + architecture. If services provided by the code model fail because + Clang does not understand the target architecture, select + \uicontrol {Override for code model}. + + \image qtcreator-compilers-target-triple.png "Target triple field" + \endlist \section1 Adding Nim Compilers diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc index a7c9f9a6d61..24b30b4a4c8 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 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-project-managing.html \page creator-project-creating.html - \nextpage creator-project-opening.html + \nextpage creator-file-creating.html \title Creating Projects @@ -239,206 +239,7 @@ \include creator-python-project.qdocinc python project wizards - \section1 Adding Files to Projects - - You can use wizards also to add individual files to your projects. - The following table lists the wizard templates for creating files. - - \table - \header - \li Category - \li Wizard Template - \li Purpose - \row - \li {1,3} C/C++ - \li C++ Class - \li C++ header and source file for a new class that you can add to - a C++ project. - \row - \li C/C++ Source File - \li C++ source file that you can add to a C++ project. - \row - \li C/C++ Header File - \li C++ header file that you can add to a C++ project. - \row - \li {1,3} Modeling - \li State Chart - \li State Chart XML (SCXML) file that contains boilerplate - code for state machines. You can use the classes in the - \l {Qt SCXML} module to embed state machines created from - the files in Qt applications. - \row - \li Model - \li Universal Modeling Language (UML) style model with a structured - diagram. However, the model editor uses a variant of UML and - provides only a subset of properties for specifying the - appearance of model elements. For more information, see - \l {Modeling}. - \row - \li Scratch Model - \li Scratch model using a temporary file. - \row - \li {1,7} Qt - \li Qt Item Model - \li Source and header files that you can use to create classes - derived from QAbstractItemModel, QAbstractTableModel, or - QAbstractListModel. - \row - \li \QD Form Class - \li \QD form and a matching class for implementing a UI based - on Qt widgets. - \row - \li \QD Form - \li \QD form for Qt widget based projects. This is useful - if you already have an existing class for the UI logic. - \row - \li Qt Resource File - \li Resource file for storing binary files in the application - executable. - \row - \li QML File (Qt Quick 2) - \li QML file that imports Qt Quick 2.0 for use in Qt Quick projects. - \row - \li Qt Quick UI File - \li \l{UI Files}{UI file} (\e .ui.qml) and the corresponding - implementation file (\e .qml) for use in Qt Quick projects. - \row - \li JS File - \li JavaScript file that you can use to write the application logic - in Qt Quick projects. - \row - \li {1,4} GLSL - \li Fragment Shader (OpenGL/ES 2.0) - \li Fragment shader that generates the final pixel colors for - triangles, points, and lines rendered with OpenGL. You can use - it in both Qt Quick projects and Qt widget based projects. - \row - \li Vertex Shader (OpenGL/ES 2.0) - \li Vertex shader that transforms the positions, normals, and - texture coordinates of triangles, points, and lines rendered - with OpenGL. You can use it in both Qt Quick projects and Qt - widget based projects. - \row - \li Fragment Shader (Desktop OpenGL) - \li Fragment shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li Vertex Shader (Desktop OpenGL) - \li Vertex shader for use in both Qt Quick projects and Qt - widget based projects. - \row - \li {1,2} General - \li Empty File - \li Empty file that you can save with any filename extensio. - \row - \li Scratch Buffer - \li Scratch buffer that uses temporary files. You can - create this type of files for temporarily storing information - that you do not intend to save - \row - \li Java - \li Java File - \li Java class files that you can use to create Java classes. - \row - \li {1,2} Python - \li Python Class - \li Python class file. - \row - \li Python File - \li Python script file using UTF-8 encoding. - \row - \li {1,2} Nim (experimental) - \li Nim Script File - \li Empty Nim script file using UTF-8 encoding. - \row - \li Nim File - \li Empty Nim source file using UTF-8 encoding. - \endtable - - \section2 Creating C++ Classes - - The \uicontrol {C++ Class Wizard} allows you to create a C++ header and source - file for a new class that you can add to a C++ project. Specify the class - name, base class, and header and source files for the class. - - The wizard supports namespaces. To use a namespace, enter a qualified - class name in the \uicontrol {Class name} field. For example: - \c MyNamespace::MySubNamespace::MyClass. The wizard suggests - existing namespaces and class names as you type. - - \image qtcreator-cpp-class-wizard.png "Enter Class Name dialog" - - The names of the header and source file are based on the class name. To - change the default suffix of a file, select \uicontrol Tools > \uicontrol Options > - \uicontrol {C++} > \uicontrol {File Naming}. - - \image qtcreator-options-cpp-files.png "File Naming tab in Options" - - In the \uicontrol {License template} field, you can use - \l{Using Variables in Wizards}{predefined wizard variables} to specify the - path and filename of the license to use in the source and header files. - - You can create your own project and class wizards. For more information, - see \l{Adding New Custom Wizards}. - - \section2 Creating Resource Files - - \QC supports the \l{The Qt Resource System}{Qt Resource System}, which is a - platform-independent mechanism for storing files in the application's - executable. - - \image qtcreator-add-resource-wizard.png "New File dialog" - - The wizard creates a resource collection file (.qrc) that you can manage in - the resource editor. - - \image qtcreator-add-resource.png "Editing resource files" - - Select \uicontrol {Add Files} to locate and add individual - files. - - To list the folders and files in ascending alphabetic order in the source - tree, select \uicontrol {Sort Alphabetically} in the context menu. - - By default, resources are accessible in the application under the same file - name as they have in the source tree, with a \c{:/} prefix, or by a URL with - a \c qrc scheme. To specify a path prefix for all files in the \c .qrc file, - select \uicontrol {Add Prefix} and enter the prefix in the \uicontrol Prefix - field. - - Some resources need to change based on the user's locale, such as - translation files or icons. You can specify a locale in the - \uicontrol Language field. - - Select \uicontrol Remove to remove the selected file from the resource - collection. In the \uicontrol {Remove File} dialog, select the - \uicontrol {Delete file permanently} check box to remove the file from - the file system. To remove files that cannot be found in the file system, - select \uicontrol {Remove Missing Files}. - - The above functions are also available in the context menu in the - \uicontrol Projects view. - - \section2 Creating OpenGL Fragment and Vertex Shaders - - Qt provides support for integration with OpenGL implementations on all - platforms, which allows you to display hardware accelerated 3D graphics - alongside a more conventional user interface. For more information, see - \l{Qt GUI}. - - You can use the QOpenGLShader class to compile OpenGL shaders written in the - OpenGL Shading Language (GLSL) and in the OpenGL/ES Shading Language - (GLSL/ES). QOpenGLShader and QOpenGLShaderProgram shelter you from the - details of - compiling and linking vertex and fragment shaders. - - You can use \QC code editor to write fragment and vertex shaders - in GLSL or GLSL/ES. The code editor provides syntax highlighting and code - completion for the files. - - \image qtcreator-new-opengl-file.png "New OpenGL file wizard" - - \section2 Displaying Additional File Types in Projects View + \section1 Displaying Additional File Types in Projects View \QC displays all files that are declared to be part of the project by the project files in the \l Projects view. The files are sorted into categories @@ -448,7 +249,7 @@ Alternatively, you can see all the files in a project in the \l {File System} view. - \section3 CMake Projects + \section2 CMake Projects When using CMake, you can specify additional files to display in the \uicontrol Projects view by either adding them as sources or installing @@ -470,7 +271,7 @@ Alternatively, to install the files, use the \l {CMake: install command} {install} command with the \c FILES or \c DIRECTORY property. - \section3 qmake Projects + \section2 qmake Projects When using qmake, add filenames as values of the \c {DISTFILES} variable in the .pro file. You can also use wildcards. @@ -550,6 +351,7 @@ \section1 Related Topics \list + \li \l{Creating Files} \li \l{Opening Projects} \li \l{Adding Libraries to Projects} \li \l{Adding New Custom Wizards} diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc index 1b54b8d8ac0..e6280066895 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-opening.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -31,7 +31,7 @@ // ********************************************************************** /*! - \previouspage creator-project-creating.html + \previouspage creator-file-creating.html \page creator-project-opening.html \nextpage creator-project-qmake-libraries.html diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index ed38c906cf1..23bc02bec20 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -58,6 +58,7 @@ \list \li \l{Creating Projects} \list + \li \l{Creating Files} \li \l{Opening Projects} \li \l{Adding Libraries to Projects} \li \l{Adding New Custom Wizards} diff --git a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc index 60db096f2c8..22babb5026e 100644 --- a/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-file-system-view.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -83,7 +83,11 @@ line endings, indentation, owner, size, last read and modified dates, and permissions. \li Create new files. For more information, see + \if defined(qtdesignstudio) \l{Adding Files to Projects}. + \else + \l{Creating Files}. + \endif \li Rename or remove existing files. \li Create new folders. \li Compare the selected file with the currently open file in the diff diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index 87021c3aa8c..94acded57c3 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -79,7 +79,11 @@ \li Set a project as the active project. \li Execute the \uicontrol Build menu commands. \li Create new files. For more information, see + \if defined(qtdesignstudio) \l{Adding Files to Projects}. + \else + \l{Creating Files}. + \endif \li Rename or remove existing files. If you change the base name of a file, \QC displays a list of other files with the same base name and offers to rename them as well. diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index 8c013c13d38..43645074980 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -508,10 +508,10 @@ \image qtcreator-issues.png "Issues output pane" - Right-clicking on a line brings up a context menu with actions that you can - apply to the contents of the line. You can remove a line, copy its contents - to the clipboard, or search the Internet for a solution using the contents - of the line as search criteria. In addition, you can show a version control + Select one or several lines to apply context-menu actions to their contents. + You can remove the selected lines or copy their contents to the clipboard. + For single lines, you can search the Internet for a solution using the + contents of the line as search criteria or open a version control annotation view of the line that causes the error message. To navigate to the corresponding source code, click an issue or diff --git a/doc/qtdesignstudio/examples/loginui1/loginui1.qmlproject b/doc/qtdesignstudio/examples/Loginui1/Loginui1.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/loginui1.qmlproject rename to doc/qtdesignstudio/examples/Loginui1/Loginui1.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/EntryField.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/EntryField.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/EntryField.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/PushButton.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/PushButton.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/PushButton.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui1/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui1/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg b/doc/qtdesignstudio/examples/Loginui1/content/images/adventurePage.jpg similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/images/adventurePage.jpg rename to doc/qtdesignstudio/examples/Loginui1/content/images/adventurePage.jpg diff --git a/doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png b/doc/qtdesignstudio/examples/Loginui1/content/images/qt_logo_green_128x128px.png similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/content/images/qt_logo_green_128x128px.png rename to doc/qtdesignstudio/examples/Loginui1/content/images/qt_logo_green_128x128px.png diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/Constants.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/Constants.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/Constants.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/Constants.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListModel.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListModel.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListModel.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListModel.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListSimulator.qml b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListSimulator.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/EventListSimulator.qml rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/EventListSimulator.qml diff --git a/doc/qtdesignstudio/examples/loginui1/imports/loginui1/qmldir b/doc/qtdesignstudio/examples/Loginui1/imports/loginui1/qmldir similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/imports/loginui1/qmldir rename to doc/qtdesignstudio/examples/Loginui1/imports/loginui1/qmldir diff --git a/doc/qtdesignstudio/examples/loginui1/src/app_environment.h b/doc/qtdesignstudio/examples/Loginui1/src/app_environment.h similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/app_environment.h rename to doc/qtdesignstudio/examples/Loginui1/src/app_environment.h diff --git a/doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h b/doc/qtdesignstudio/examples/Loginui1/src/import_qml_plugins.h similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/import_qml_plugins.h rename to doc/qtdesignstudio/examples/Loginui1/src/import_qml_plugins.h diff --git a/doc/qtdesignstudio/examples/loginui1/src/main.cpp b/doc/qtdesignstudio/examples/Loginui1/src/main.cpp similarity index 100% rename from doc/qtdesignstudio/examples/loginui1/src/main.cpp rename to doc/qtdesignstudio/examples/Loginui1/src/main.cpp diff --git a/doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject b/doc/qtdesignstudio/examples/Loginui2/Loginui2.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui2/Loginui2.qmlproject rename to doc/qtdesignstudio/examples/Loginui2/Loginui2.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui2/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui2/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui2/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject b/doc/qtdesignstudio/examples/Loginui3/Loginui3.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui3/Loginui3.qmlproject rename to doc/qtdesignstudio/examples/Loginui3/Loginui3.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui3/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui3/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui3/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject b/doc/qtdesignstudio/examples/Loginui4/Loginui4.qmlproject similarity index 100% rename from doc/qtdesignstudio/examples/loginui4/Loginui4.qmlproject rename to doc/qtdesignstudio/examples/Loginui4/Loginui4.qmlproject diff --git a/doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml b/doc/qtdesignstudio/examples/Loginui4/content/Screen01.ui.qml similarity index 100% rename from doc/qtdesignstudio/examples/loginui4/content/Screen01.ui.qml rename to doc/qtdesignstudio/examples/Loginui4/content/Screen01.ui.qml diff --git a/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png b/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png index d8cc017a4d0..b4c67f7a88a 100644 Binary files a/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png and b/doc/qtdesignstudio/examples/doc/images/simplekeyboard-project-details.png differ diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc index 78bc2192b56..4e6a6f11b42 100644 --- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui1 + \example Loginui1 \ingroup gstutorials \nextpage {Log In UI - Positioning} @@ -231,7 +231,7 @@ adds the following \e import statements to the UI files (.ui.qml) that it creates: - \quotefromfile Loginui1/Content/Screen01.ui.qml + \quotefromfile Loginui1/content/Screen01.ui.qml \skipto import \printuntil Controls @@ -334,7 +334,7 @@ To be able to use the functionality of the Button control, the wizard template adds the following \e import statements to the \e EntryField.ui.qml file: - \quotefromfile Loginui1/Content/EntryField.ui.qml + \quotefromfile Loginui1/content/EntryField.ui.qml \skipto import \printuntil Controls diff --git a/doc/qtdesignstudio/examples/doc/loginui3.qdoc b/doc/qtdesignstudio/examples/doc/loginui3.qdoc index 999215d90b1..75ac69e399e 100644 --- a/doc/qtdesignstudio/examples/doc/loginui3.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui3.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui3 + \example Loginui3 \ingroup gstutorials \title Log In UI - States diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc index a6a1ad77d4a..6a43e55b009 100644 --- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc @@ -24,7 +24,7 @@ ****************************************************************************/ /*! - \example loginui4 + \example Loginui4 \ingroup gstutorials \title Log In UI - Timeline @@ -312,7 +312,7 @@ the following \e import statement to the UI files where it uses the components: - \quotefromfile Loginui4/Content/Screen01.ui.qml + \quotefromfile Loginui4/content/Screen01.ui.qml \skipto QtQuick.Timeline \printuntil 1.0 diff --git a/doc/qtdesignstudio/images/studio-project-wizards.png b/doc/qtdesignstudio/images/studio-project-wizards.png index 81fcc3af535..a6cd93f15e2 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/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index de7f7150d35..f8368e90baf 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -62,6 +62,10 @@ \li Category \li Wizard Preset \li Purpose + \row + \li Recents + \li + \li Lists the most recent presets that you have used. \row \li {1,2} General \li Empty diff --git a/qbs/imports/QtcManualtest.qbs b/qbs/imports/QtcManualtest.qbs index cc21c8e3fa6..cfa1abc1d8f 100644 --- a/qbs/imports/QtcManualtest.qbs +++ b/qbs/imports/QtcManualtest.qbs @@ -17,5 +17,7 @@ QtcProduct { return defines; } + destinationDirectory: project.buildDirectory + '/' + + FileInfo.relativePath(project.ide_source_tree, sourceDirectory) install: false } diff --git a/scripts/build.py b/scripts/build.py index 9b1a46c1c4e..2f33b95ff56 100755 --- a/scripts/build.py +++ b/scripts/build.py @@ -126,8 +126,9 @@ def common_cmake_arguments(args): '-G', 'Ninja'] if args.python3: - cmake_args += ['-DPYTHON_EXECUTABLE=' + args.python3] cmake_args += ['-DPython3_EXECUTABLE=' + args.python3] + if args.python_path: + cmake_args += ['-DPython3_ROOT_DIR=' + args.python_path] if args.module_paths: module_paths = [common.to_posix_path(os.path.abspath(fp)) for fp in args.module_paths] @@ -140,11 +141,6 @@ def common_cmake_arguments(args): if not os.environ.get('CC') and not os.environ.get('CXX'): cmake_args += ['-DCMAKE_C_COMPILER=cl', '-DCMAKE_CXX_COMPILER=cl'] - if args.python_path: - python_library = glob.glob(os.path.join(args.python_path, 'libs', 'python??.lib')) - 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] diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml index f52bcf4bee9..48ed09cba70 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/MaterialNodeView.qml @@ -32,6 +32,11 @@ View3D { property Material previewMaterial + function fitToViewPort() + { + // No need to zoom this view, this is here just to avoid runtime warnings + } + SceneEnvironment { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml index 324a020d6fa..de3e3ee431c 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNode3DImageView.qml @@ -41,8 +41,6 @@ Item { property var modelViewComponent property var nodeViewComponent - property bool ready: false - function destroyView() { previewObject = null; @@ -58,8 +56,6 @@ Item { createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); - - previewObject = obj; } function createViewForMaterial(material) @@ -70,6 +66,8 @@ Item { // Always recreate the view to ensure material is up to date if (materialViewComponent.status === Component.Ready) view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); + + previewObject = material; } function createViewForModel(model) @@ -80,6 +78,8 @@ Item { // Always recreate the view to ensure model is up to date if (modelViewComponent.status === Component.Ready) view = modelViewComponent.createObject(viewRect, {"sourceModel": model}); + + previewObject = model; } function createViewForNode(node) @@ -90,16 +90,13 @@ Item { // Always recreate the view to ensure node is up to date if (nodeViewComponent.status === Component.Ready) view = nodeViewComponent.createObject(viewRect, {"importScene": node}); + + previewObject = node; } - function afterRender() + function fitToViewPort() { - if (previewObject instanceof Node) { - view.fitToViewPort(); - ready = view.ready; - } else { - ready = true; - } + view.fitToViewPort(); } View3D { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml index dc10f441e1c..e61a9a8fb25 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/ModelNodeView.qml @@ -32,24 +32,13 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property real prevZoomFactor: -1 property Model sourceModel function fitToViewPort() { - cameraControl.focusObject(model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - model.scale = model.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - model.scale = model.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -58,14 +47,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 @@ -75,15 +56,15 @@ View3D { id: theCamera z: 600 y: 600 + x: 600 eulerRotation.x: -45 + eulerRotation.y: -45 clipFar: 10000 clipNear: 1 } Model { id: model - eulerRotation.y: 45 - source: sourceModel.source geometry: sourceModel.geometry diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml index b41c74af54e..91008abb251 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/NodeNodeView.qml @@ -32,30 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property bool first: true - property real prevZoomFactor: -1 - function fitToViewPort() { - if (first) { - first = false; - selectionBox.targetNode = root.importScene; - } else { - cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - root.importScene.scale = root.importScene.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - root.importScene.scale = root.importScene.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - selectionBox.visible = false; - } - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -64,20 +45,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - SelectionBox { - id: selectionBox - view3D: root - geometryName: "NodeNodeViewSB" - } - - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml index 6103df98c2b..0b6c7bd2144 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/MaterialNodeView.qml @@ -32,6 +32,11 @@ View3D { property Material previewMaterial + function fitToViewPort() + { + // No need to zoom this view, this is here just to avoid runtime warnings + } + SceneEnvironment { id: sceneEnv antialiasingMode: SceneEnvironment.MSAA diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml index 36d4cea8553..4bd07e57d12 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNode3DImageView.qml @@ -41,8 +41,6 @@ Item { property var modelViewComponent property var nodeViewComponent - property bool ready: false - function destroyView() { previewObject = null; @@ -58,8 +56,6 @@ Item { createViewForModel(obj); else if (obj instanceof Node) createViewForNode(obj); - - previewObject = obj; } function createViewForMaterial(material) @@ -70,6 +66,8 @@ Item { // Always recreate the view to ensure material is up to date if (materialViewComponent.status === Component.Ready) view = materialViewComponent.createObject(viewRect, {"previewMaterial": material}); + + previewObject = material; } function createViewForModel(model) @@ -80,6 +78,8 @@ Item { // Always recreate the view to ensure model is up to date if (modelViewComponent.status === Component.Ready) view = modelViewComponent.createObject(viewRect, {"sourceModel": model}); + + previewObject = model; } function createViewForNode(node) @@ -90,16 +90,13 @@ Item { // Always recreate the view to ensure node is up to date if (nodeViewComponent.status === Component.Ready) view = nodeViewComponent.createObject(viewRect, {"importScene": node}); + + previewObject = node; } - function afterRender() + function fitToViewPort() { - if (previewObject instanceof Node) { - view.fitToViewPort(); - ready = view.ready; - } else { - ready = true; - } + view.fitToViewPort(); } Item { diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml index 7fe6a114163..d6574f660ca 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ModelNodeView.qml @@ -32,24 +32,13 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property real prevZoomFactor: -1 property Model sourceModel function fitToViewPort() { - cameraControl.focusObject(model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - model.scale = model.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - model.scale = model.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -58,14 +47,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 @@ -75,16 +56,15 @@ View3D { id: theCamera z: 600 y: 600 + x: 600 eulerRotation.x: -45 + eulerRotation.y: -45 clipFar: 10000 clipNear: 1 } Model { id: model - readonly property bool _edit3dLocked: true // Make this non-pickable - eulerRotation.y: 45 - source: sourceModel.source geometry: sourceModel.geometry diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml index 49d88d4c8a9..a48eb665191 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/NodeNodeView.qml @@ -32,30 +32,11 @@ View3D { environment: sceneEnv camera: theCamera - property bool ready: false - property bool first: true - property real prevZoomFactor: -1 - function fitToViewPort() { - if (first) { - first = false; - selectionBox.targetNode = root.importScene; - } else { - cameraControl.focusObject(selectionBox.model, theCamera.eulerRotation, true, false); - - if (cameraControl._zoomFactor < 0.1) { - root.importScene.scale = root.importScene.scale.times(10); - } else if (cameraControl._zoomFactor > 10) { - root.importScene.scale = root.importScene.scale.times(0.1); - } else { - // We need one more render after zoom factor change, so only set ready when zoom factor - // or scaling hasn't changed from the previous frame - ready = _generalHelper.fuzzyCompare(cameraControl._zoomFactor, prevZoomFactor); - prevZoomFactor = cameraControl._zoomFactor; - selectionBox.visible = false; - } - } + // The magic number is the distance from camera default pos to origin + _generalHelper.calculateNodeBoundsAndFocusCamera(theCamera, importScene, root, + 1040); } SceneEnvironment { @@ -64,20 +45,6 @@ View3D { antialiasingQuality: SceneEnvironment.High } - SelectionBox { - id: selectionBox - view3D: root - geometryName: "NodeNodeViewSB" - } - - EditCameraController { - id: cameraControl - camera: theCamera - anchors.fill: parent - view3d: root - ignoreToolState: true - } - DirectionalLight { eulerRotation.x: -30 eulerRotation.y: -30 diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp index f0131c80895..9d7d4b05ce9 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp @@ -55,6 +55,11 @@ const QString _globalStateId = QStringLiteral("@GTS"); // global tool state const QString _lastSceneIdKey = QStringLiteral("lastSceneId"); const QString _rootSizeKey = QStringLiteral("rootSize"); +static const float floatMin = std::numeric_limits::lowest(); +static const float floatMax = std::numeric_limits::max(); +static const QVector3D maxVec = QVector3D(floatMax, floatMax, floatMax); +static const QVector3D minVec = QVector3D(floatMin, floatMin, floatMin); + GeneralHelper::GeneralHelper() : QObject() { @@ -269,6 +274,37 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul return QVector4D(lookAt, cameraZoomFactor); } +// This function can be used to synchronously focus camera on a node, which doesn't have to be +// a selection box for bound calculations to work. This is used to focus the view for +// various preview image generations, where doing things asynchronously is not good +// and recalculating bounds for every frame is not a problem. +void GeneralHelper::calculateNodeBoundsAndFocusCamera( + QQuick3DCamera *camera, QQuick3DNode *node, QQuick3DViewport *viewPort, + float defaultLookAtDistance) +{ + QVector3D minBounds; + QVector3D maxBounds; + + getBounds(viewPort, node, minBounds, maxBounds); + + QVector3D extents = maxBounds - minBounds; + QVector3D lookAt = minBounds + (extents / 2.f); + float maxExtent = qMax(extents.x(), qMax(extents.y(), extents.z())); + + // Reset camera position to default zoom + QMatrix4x4 m = camera->sceneTransform(); + const float *dataPtr(m.data()); + QVector3D newLookVector(dataPtr[8], dataPtr[9], dataPtr[10]); + newLookVector.normalize(); + newLookVector *= defaultLookAtDistance; + + camera->setPosition(lookAt + newLookVector); + + float newZoomFactor = maxExtent / 725.f; // Divisor taken from focusNodesToCamera function + + zoomCamera(viewPort, camera, 0, defaultLookAtDistance, lookAt, newZoomFactor, false); +} + // Aligns any cameras found in nodes list to a camera. // Only position and rotation are copied, rest of the camera properties stay the same. void GeneralHelper::alignCameras(QQuick3DCamera *camera, const QVariant &nodes) @@ -727,6 +763,129 @@ QVector3D GeneralHelper::pivotScenePosition(QQuick3DNode *node) const return mat44::getPosition(sceneTransform); } +// Calculate bounds for given node, including all child nodes. +// Returns true if the tree contains at least one Model node. +bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, + QVector3D &maxBounds, bool recursive) +{ + if (!node) { + const float halfExtent = 100.f; + minBounds = {-halfExtent, -halfExtent, -halfExtent}; + maxBounds = {halfExtent, halfExtent, halfExtent}; + return false; + } + + QMatrix4x4 localTransform; + auto nodePriv = QQuick3DObjectPrivate::get(node); + auto renderNode = static_cast(nodePriv->spatialNode); + + if (recursive && renderNode) { + if (renderNode->flags.testFlag(QSSGRenderNode::Flag::TransformDirty)) + renderNode->calculateLocalTransform(); + localTransform = renderNode->localTransform; + } + + QVector3D localMinBounds = maxVec; + QVector3D localMaxBounds = minVec; + + // Find bounds for children + QVector minBoundsVec; + QVector maxBoundsVec; + const auto children = node->childItems(); + bool hasModel = false; + for (const auto child : children) { + if (auto childNode = qobject_cast(child)) { + QVector3D newMinBounds = minBounds; + QVector3D newMaxBounds = maxBounds; + hasModel = getBounds(view3D, childNode, newMinBounds, newMaxBounds, true); + // Ignore any subtrees that do not have Model in them as we don't need those + // for visual bounds calculations + if (hasModel) { + minBoundsVec << newMinBounds; + maxBoundsVec << newMaxBounds; + } + } + } + + auto combineMinBounds = [](QVector3D &target, const QVector3D &source) { + target.setX(qMin(source.x(), target.x())); + target.setY(qMin(source.y(), target.y())); + target.setZ(qMin(source.z(), target.z())); + }; + auto combineMaxBounds = [](QVector3D &target, const QVector3D &source) { + target.setX(qMax(source.x(), target.x())); + target.setY(qMax(source.y(), target.y())); + target.setZ(qMax(source.z(), target.z())); + }; + auto transformCorner = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget, + const QVector3D &corner) { + QVector3D mappedCorner = m.map(corner); + combineMinBounds(minTarget, mappedCorner); + combineMaxBounds(maxTarget, mappedCorner); + }; + auto transformCorners = [&](const QMatrix4x4 &m, QVector3D &minTarget, QVector3D &maxTarget, + const QVector3D &minCorner, const QVector3D &maxCorner) { + transformCorner(m, minTarget, maxTarget, minCorner); + transformCorner(m, minTarget, maxTarget, maxCorner); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), minCorner.y(), maxCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(minCorner.x(), maxCorner.y(), maxCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), maxCorner.y(), minCorner.z())); + transformCorner(m, minTarget, maxTarget, QVector3D(maxCorner.x(), minCorner.y(), maxCorner.z())); + }; + + // Combine all child bounds + for (const auto &newBounds : qAsConst(minBoundsVec)) + combineMinBounds(localMinBounds, newBounds); + for (const auto &newBounds : qAsConst(maxBoundsVec)) + combineMaxBounds(localMaxBounds, newBounds); + + if (qobject_cast(node)) { + if (auto renderModel = static_cast(renderNode)) { + QWindow *window = static_cast(view3D->window()); + if (window) { + QSSGRef context; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window)); +#else + context = QQuick3DObjectPrivate::get(node)->sceneManager->rci; +#endif + if (!context.isNull()) { + auto bufferManager = context->bufferManager(); +#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0) + QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager); +#else + QSSGBounds3 bounds = bufferManager->getModelBounds(renderModel); +#endif + QVector3D center = bounds.center(); + QVector3D extents = bounds.extents(); + QVector3D localMin = center - extents; + QVector3D localMax = center + extents; + + combineMinBounds(localMinBounds, localMin); + combineMaxBounds(localMaxBounds, localMax); + + hasModel = true; + } + } + } + } else { + combineMinBounds(localMinBounds, {}); + combineMaxBounds(localMaxBounds, {}); + } + + if (localMaxBounds == minVec) { + localMinBounds = {}; + localMaxBounds = {}; + } + + // Transform local space bounding box to parent space + transformCorners(localTransform, minBounds, maxBounds, localMinBounds, localMaxBounds); + + return hasModel; +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h index 06068601537..46e6019dd58 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h @@ -72,6 +72,9 @@ public: const QVariant &nodes, QQuick3DViewport *viewPort, float oldZoom, bool updateZoom = true, bool closeUp = false); + Q_INVOKABLE void calculateNodeBoundsAndFocusCamera(QQuick3DCamera *camera, QQuick3DNode *node, + QQuick3DViewport *viewPort, + float defaultLookAtDistance); Q_INVOKABLE void alignCameras(QQuick3DCamera *camera, const QVariant &nodes); Q_INVOKABLE QVector3D alignView(QQuick3DCamera *camera, const QVariant &nodes, const QVector3D &lookAtPoint); @@ -126,6 +129,8 @@ protected: private: void handlePendingToolStateUpdate(); QVector3D pivotScenePosition(QQuick3DNode *node) const; + bool getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVector3D &minBounds, + QVector3D &maxBounds, bool recursive = false); QTimer m_overlayUpdateTimer; QTimer m_toolStateUpdateTimer; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index b37486f0481..d496aff3889 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -1588,6 +1588,11 @@ bool NodeInstanceServer::isInformationServer() const return false; } +bool NodeInstanceServer::isPreviewServer() const +{ + return false; +} + static QString baseProperty(const QString &property) { int index = property.indexOf('.'); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index f2255bd891d..ba51f5e5888 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -229,8 +229,10 @@ public: virtual QImage grabWindow() = 0; virtual QImage grabItem(QQuickItem *item) = 0; + virtual bool renderWindow() = 0; virtual bool isInformationServer() const; + virtual bool isPreviewServer() const; void addAnimation(QQuickAbstractAnimation *animation); QVector animations() const; QVariant animationDefaultValue(int index) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 4eb8cdd65f4..9f3a1d6b3bc 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -180,6 +180,11 @@ bool ObjectNodeInstance::isLayoutable() const return false; } +bool ObjectNodeInstance::isRenderable() const +{ + return false; +} + bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const { return false; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 67e1663496c..88e2ca26770 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -103,6 +103,7 @@ public: virtual bool isQuickItem() const; virtual bool isQuickWindow() const; virtual bool isLayoutable() const; + virtual bool isRenderable() const; virtual bool equalGraphicsItem(QGraphicsItem *item) const; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp index c0d763c906b..cff435bdd49 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5captureimagenodeinstanceserver.cpp @@ -44,10 +44,10 @@ QImage renderImage(ServerNodeInstance rootNodeInstance) QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize(); if (previewImageSize.isEmpty()) - previewImageSize = {300, 300}; + previewImageSize = {150, 150}; - if (previewImageSize.width() > 300 || previewImageSize.height() > 300) - previewImageSize.scale({300, 300}, Qt::KeepAspectRatio); + if (previewImageSize.width() > 150 || previewImageSize.height() > 150) + previewImageSize.scale({150, 150}, Qt::KeepAspectRatio); QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize); @@ -68,7 +68,8 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands( inFunction = true; auto rooNodeInstance = rootNodeInstance(); - rooNodeInstance.rootQuickItem()->setClip(true); + if (QQuickItem *qitem = rooNodeInstance.rootQuickItem()) + qitem->setClip(true); DesignerSupport::polishItems(quickWindow()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index afde832afcb..e2bd56562d5 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1007,17 +1007,17 @@ void Qt5InformationNodeInstanceServer::doRenderModelNodeImageView() void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() { #ifdef QUICK3D_MODULE - m_modelNode3DImageViewAsyncData.cleanup(); if (m_modelNode3DImageViewData.rootItem) { QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); if (!m_modelNode3DImageViewData.contentItem) m_modelNode3DImageViewData.contentItem = getContentItemForRendering(m_modelNode3DImageViewData.rootItem); + QImage renderImage; if (m_modelNodePreviewImageCache.contains(m_modelNodePreviewImageCommand.componentPath())) { - m_modelNode3DImageViewAsyncData.renderImage - = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()]; - modelNode3DImageViewSendImageToCreator(); + renderImage = m_modelNodePreviewImageCache[m_modelNodePreviewImageCommand.componentPath()]; } else { + bool createdFromComponent = false; + QObject *instanceObj = nullptr; ServerNodeInstance instance = instanceForId(m_modelNodePreviewImageCommand.instanceId()); if (!m_modelNodePreviewImageCommand.componentPath().isEmpty() && instance.isSubclassOf("QQuick3DNode")) { @@ -1026,15 +1026,14 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() // wouldn't want the children of the Node to appear in the preview. QQmlComponent component(engine()); component.loadUrl(QUrl::fromLocalFile(m_modelNodePreviewImageCommand.componentPath())); - m_modelNode3DImageViewAsyncData.instanceObj = qobject_cast(component.create()); - if (!m_modelNode3DImageViewAsyncData.instanceObj) { + instanceObj = qobject_cast(component.create()); + if (!instanceObj) { qWarning() << "Could not create preview component: " << component.errors(); - m_modelNode3DImageViewAsyncData.cleanup(); return; } - m_modelNode3DImageViewAsyncData.createdFromComponent = true; + createdFromComponent = true; } else { - m_modelNode3DImageViewAsyncData.instanceObj = instance.internalObject(); + instanceObj = instance.internalObject(); } QSize renderSize = m_modelNodePreviewImageCommand.size(); if (Internal::QuickItemNodeInstance::unifiedRenderPathOrQt6()) { @@ -1055,69 +1054,53 @@ void Qt5InformationNodeInstanceServer::doRenderModelNode3DImageView() QMetaObject::invokeMethod( m_modelNode3DImageViewData.rootItem, "createViewForObject", - Q_ARG(QVariant, objectToVariant(m_modelNode3DImageViewAsyncData.instanceObj))); + Q_ARG(QVariant, objectToVariant(instanceObj))); - // Selection box geometry updates have an asynchronous step, so we need to do rendering - // in asynchronous steps as well, since we are adjusting the selection box geometry - // while finding correct zoom level. - m_modelNode3DImageViewAsyncData.timer.start(); - } - } + // Need to render twice, first render updates spatial nodes + for (int i = 0; i < 2; ++i) { + if (i == 1) + QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "fitToViewPort" + , Qt::DirectConnection); + + updateNodesRecursive(m_modelNode3DImageViewData.contentItem); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { + renderImage = m_modelNode3DImageViewData.window->grabWindow(); + } else { + // Fake render loop signaling to update things like QML items as 3D textures + m_modelNode3DImageViewData.window->beforeSynchronizing(); + m_modelNode3DImageViewData.window->beforeRendering(); + + QSizeF size = qobject_cast(m_modelNode3DImageViewData.contentItem)->size(); + QRectF renderRect(QPointF(0., 0.), size); + renderImage = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem, + renderRect, size.toSize()); + m_modelNode3DImageViewData.window->afterRendering(); + } +#else + renderImage = grabRenderControl(m_modelNode3DImageViewData); #endif -} + } -void Qt5InformationNodeInstanceServer::modelNode3DImageViewSendImageToCreator() -{ - if (!m_modelNode3DImageViewAsyncData.renderImage.isNull()) { + QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); + + if (createdFromComponent) { + // If component changes, puppet will need a reset anyway, so we can cache the image + m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), + renderImage); + delete instanceObj; + } + } // Key number is selected so that it is unlikely to conflict other ImageContainer use. ImageContainer imgContainer(m_modelNodePreviewImageCommand.instanceId(), {}, 2100000001); - imgContainer.setImage(m_modelNode3DImageViewAsyncData.renderImage); + imgContainer.setImage(renderImage); // send the rendered image to creator process nodeInstanceClient()->handlePuppetToCreatorCommand( {PuppetToCreatorCommand::RenderModelNodePreviewImage, QVariant::fromValue(imgContainer)}); - - m_modelNode3DImageViewAsyncData.cleanup(); } -} - -void Qt5InformationNodeInstanceServer::modelNode3DImageViewRenderStep() -{ - ++m_modelNode3DImageViewAsyncData.count; - - updateNodesRecursive(m_modelNode3DImageViewData.contentItem); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - if (Internal::QuickItemNodeInstance::unifiedRenderPath()) { - m_modelNode3DImageViewAsyncData.renderImage = m_modelNode3DImageViewData.window->grabWindow(); - } else { - // Fake render loop signaling to update things like QML items as 3D textures - m_modelNode3DImageViewData.window->beforeSynchronizing(); - m_modelNode3DImageViewData.window->beforeRendering(); - - QSizeF size = qobject_cast(m_modelNode3DImageViewData.contentItem)->size(); - QRectF renderRect(QPointF(0., 0.), size); - m_modelNode3DImageViewAsyncData.renderImage - = designerSupport()->renderImageForItem(m_modelNode3DImageViewData.contentItem, - renderRect, size.toSize()); - m_modelNode3DImageViewData.window->afterRendering(); - } -#else - m_modelNode3DImageViewAsyncData.renderImage = grabRenderControl(m_modelNode3DImageViewData); #endif - QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "afterRender"); - const bool ready = QQmlProperty::read(m_modelNode3DImageViewData.rootItem, "ready").value(); - if (ready || m_modelNode3DImageViewAsyncData.count >= 10) { - QMetaObject::invokeMethod(m_modelNode3DImageViewData.rootItem, "destroyView"); - if (m_modelNode3DImageViewAsyncData.createdFromComponent) { - // If component changes, puppet will need a reset anyway, so we can cache the image - m_modelNodePreviewImageCache.insert(m_modelNodePreviewImageCommand.componentPath(), - m_modelNode3DImageViewAsyncData.renderImage); - } - modelNode3DImageViewSendImageToCreator(); - } else { - m_modelNode3DImageViewAsyncData.timer.start(); - } } static QRectF itemBoundingRect(QQuickItem *item) @@ -1234,7 +1217,6 @@ Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceC m_render3DEditViewTimer.setSingleShot(true); m_inputEventTimer.setSingleShot(true); m_renderModelNodeImageViewTimer.setSingleShot(true); - m_modelNode3DImageViewAsyncData.timer.setSingleShot(true); m_dynamicAddObjectTimer.setSingleShot(true); #ifdef FPS_COUNTER @@ -1260,7 +1242,6 @@ Qt5InformationNodeInstanceServer::~Qt5InformationNodeInstanceServer() m_render3DEditViewTimer.stop(); m_inputEventTimer.stop(); m_renderModelNodeImageViewTimer.stop(); - m_modelNode3DImageViewAsyncData.timer.stop(); m_dynamicAddObjectTimer.stop(); if (m_editView3DData.rootItem) @@ -1677,8 +1658,6 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList &instances); void handleInputEvents(); @@ -190,26 +188,6 @@ private: QObject *m_3dHelper = nullptr; int m_need3DEditViewRender = 0; QSet m_dynamicObjectConstructors; - - struct ModelNode3DImageViewAsyncData { - QTimer timer; - QImage renderImage; - int count = 0; - bool createdFromComponent = false; - QObject *instanceObj = nullptr; - - void cleanup() - { - timer.stop(); - count = 0; - renderImage = {}; - if (createdFromComponent) - delete instanceObj; - instanceObj = nullptr; - createdFromComponent = false; - } - }; - ModelNode3DImageViewAsyncData m_modelNode3DImageViewAsyncData; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h index 4af451b61ae..a0c79296033 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -70,6 +70,7 @@ public: QImage grabWindow() override; QImage grabItem(QQuickItem *item) override; + bool renderWindow() override; static QQuickItem *parentEffectItem(QQuickItem *item); @@ -97,7 +98,6 @@ protected: virtual bool initRhi(RenderViewData &viewData); virtual QImage grabRenderControl(RenderViewData &viewData); - virtual bool renderWindow(); private: RenderViewData m_viewData; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp index fb3113bdcd1..f61ba1a3421 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.cpp @@ -133,4 +133,9 @@ void Qt5PreviewNodeInstanceServer::changePreviewImageSize( collectItemChangesAndSendChangeCommands(); } +bool Qt5PreviewNodeInstanceServer::isPreviewServer() const +{ + return true; +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h index 182db45d405..6c97658466f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h @@ -39,6 +39,7 @@ public: void changeState(const ChangeStateCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changePreviewImageSize(const ChangePreviewImageSizeCommand &command) override; + bool isPreviewServer() const override; QImage renderPreviewImage(); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp index 980da0da791..65bda831a6e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -26,6 +26,8 @@ #include "quick3dnodeinstance.h" #include "qt5nodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h" +#include "quickitemnodeinstance.h" +#include "../editor3d/generalhelper.h" #include @@ -37,6 +39,7 @@ #include #ifdef QUICK3D_MODULE +#include #include #include #include @@ -45,8 +48,10 @@ #if defined(QUICK3D_ASSET_UTILS_MODULE) && QT_VERSION > QT_VERSION_CHECK(6, 2, 0) #include #endif +#include #endif + namespace QmlDesigner { namespace Internal { @@ -57,6 +62,7 @@ Quick3DNodeInstance::Quick3DNodeInstance(QObject *node) Quick3DNodeInstance::~Quick3DNodeInstance() { + delete m_dummyRootView; } void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, @@ -87,10 +93,123 @@ void Quick3DNodeInstance::initialize(const ObjectNodeInstance::Pointer &objectNo } } } + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + // In case this is the scene root, we need to create a dummy View3D for the scene + // in preview puppets + if (instanceId() == 0 && nodeInstanceServer()->isPreviewServer()) { + auto helper = new QmlDesigner::Internal::GeneralHelper(); + engine()->rootContext()->setContextProperty("_generalHelper", helper); + + QQmlComponent component(engine()); + component.loadUrl(QUrl("qrc:/qtquickplugin/mockfiles/qt6/ModelNode3DImageView.qml")); + m_dummyRootView = qobject_cast(component.create()); + + QMetaObject::invokeMethod( + m_dummyRootView, "createViewForNode", + Q_ARG(QVariant, QVariant::fromValue(object()))); + + nodeInstanceServer()->setRootItem(m_dummyRootView); + } +#endif #endif ObjectNodeInstance::initialize(objectNodeInstance, flags); } +QImage Quick3DNodeInstance::renderImage() const +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!isRootNodeInstance() || !m_dummyRootView) + return {}; + + QSize size(640, 480); + nodeInstanceServer()->quickWindow()->resize(size); + m_dummyRootView->setSize(size); + + // Just render the window once to update spatial nodes + nodeInstanceServer()->renderWindow(); + + QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection); + + QRectF renderBoundingRect = m_dummyRootView->boundingRect(); + QImage renderImage; + + if (QuickItemNodeInstance::unifiedRenderPath()) { + renderImage = nodeInstanceServer()->grabWindow(); + renderImage = renderImage.copy(renderBoundingRect.toRect()); + } else { + renderImage = nodeInstanceServer()->grabItem(m_dummyRootView); + } + + // When grabbing an offscreen window the device pixel ratio is 1 + renderImage.setDevicePixelRatio(1); + + return renderImage; +#endif + return {}; +} + +QImage Quick3DNodeInstance::renderPreviewImage(const QSize &previewImageSize) const +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (!isRootNodeInstance() || !m_dummyRootView) + return {}; + + nodeInstanceServer()->quickWindow()->resize(previewImageSize); + m_dummyRootView->setSize(previewImageSize); + + // Just render the window once to update spatial nodes + nodeInstanceServer()->renderWindow(); + + QMetaObject::invokeMethod(m_dummyRootView, "fitToViewPort", Qt::DirectConnection); + + QRectF previewItemBoundingRect = boundingRect(); + + if (previewItemBoundingRect.isValid()) { + const QSize size = previewImageSize; + if (m_dummyRootView->isVisible()) { + QImage image; + image = nodeInstanceServer()->grabWindow(); + image = image.copy(previewItemBoundingRect.toRect()); + image = image.scaledToWidth(size.width()); + return image; + } else { + QImage transparentImage(size, QImage::Format_ARGB32_Premultiplied); + transparentImage.fill(Qt::transparent); + return transparentImage; + } + } +#endif + return {}; +} + +bool Quick3DNodeInstance::isRenderable() const +{ + return m_dummyRootView; +} + +QRectF Quick3DNodeInstance::boundingRect() const +{ + if (m_dummyRootView) + return m_dummyRootView->boundingRect(); + return ObjectNodeInstance::boundingRect(); +} + +QList Quick3DNodeInstance::stateInstances() const +{ + QList instanceList; +#ifdef QUICK3D_MODULE + if (auto obj3D = quick3DNode()) { + const QList stateList = QQuick3DObjectPrivate::get(obj3D)->_states()->states(); + for (QQuickState *state : stateList) { + if (state && nodeInstanceServer()->hasInstanceForObject(state)) + instanceList.append(nodeInstanceServer()->instanceForObject(state)); + } + } +#endif + return instanceList; +} + Qt5NodeInstanceServer *Quick3DNodeInstance::qt5NodeInstanceServer() const { return qobject_cast(nodeInstanceServer()); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h index 892946ee1f6..322762af26a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.h @@ -47,12 +47,22 @@ public: void initialize(const ObjectNodeInstance::Pointer &objectNodeInstance, InstanceContainer::NodeFlags flags) override; + QImage renderImage() const override; + QImage renderPreviewImage(const QSize &previewImageSize) const override; + + bool isRenderable() const override; + QRectF boundingRect() const override; + + QList stateInstances() const override; + protected: explicit Quick3DNodeInstance(QObject *node); private: Qt5NodeInstanceServer *qt5NodeInstanceServer() const; QQuick3DNode *quick3DNode() const; + + QQuickItem *m_dummyRootView = nullptr; }; } // namespace Internal diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp index b78bf6328e7..41d0015ce56 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.cpp @@ -571,6 +571,11 @@ bool QuickItemNodeInstance::isQuickItem() const return true; } +bool QuickItemNodeInstance::isRenderable() const +{ + return quickItem() && (!s_unifiedRenderPath || isRootNodeInstance()); +} + QList QuickItemNodeInstance::stateInstances() const { QList instanceList; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h index 46b22b8c9a8..50cf494e8e2 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quickitemnodeinstance.h @@ -94,6 +94,7 @@ public: bool isResizable() const override; bool isMovable() const override; bool isQuickItem() const override; + bool isRenderable() const override; QList stateInstances() const override; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 6b2ba783402..9803f6d79e6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -154,7 +154,7 @@ void ServerNodeInstance::setNodeSource(const QString &source) bool ServerNodeInstance::holdsGraphical() const { - return m_nodeInstance->isQuickItem(); + return m_nodeInstance->isRenderable(); } bool ServerNodeInstance::isComponentWrap() const diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml similarity index 90% rename from share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml rename to share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml index 71399afa011..492ef767a6e 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddImport.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AddModuleView.qml @@ -32,28 +32,40 @@ import StudioTheme 1.0 as StudioTheme Column { id: root - Text { - id: header - text: qsTr("Select a Module to Add") - color: StudioTheme.Values.themeTextColor - font.pixelSize: 16 - width: parent.width - height: 50 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + spacing: 5 + + signal back() + + Row { + spacing: 5 + anchors.horizontalCenter: parent.horizontalCenter + + Button { + anchors.verticalCenter: parent.verticalCenter + text: "<" + width: 25 + height: 25 + onClicked: back() + } + + Text { + text: qsTr("Select a Module to Add") + color: StudioTheme.Values.themeTextColor + font.pixelSize: 16 + } } ScrollView { // ListView not used because of QTBUG-52941 id: listView width: parent.width - height: parent.height - header.height + height: parent.height - y clip: true Column { spacing: 2 Repeater { - model: addImportModel + model: addModuleModel delegate: Rectangle { id: itemBackground diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml index 115309c1277..2efe499f0f6 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml @@ -40,6 +40,11 @@ Item { property var contextDir: undefined property bool isDirContextMenu: false + function clearSearchFilter() + { + searchBox.text = ""; + } + DropArea { id: dropArea @@ -90,6 +95,70 @@ Item { selectedAssetsChanged() } + StudioControls.Menu { + id: contextMenu + + StudioControls.MenuItem { + text: qsTr("Expand All") + enabled: allExpandedState !== 1 + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.toggleExpandAll(true) + } + + StudioControls.MenuItem { + text: qsTr("Collapse All") + enabled: allExpandedState !== 2 + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.toggleExpandAll(false) + } + + StudioControls.MenuSeparator { + visible: isDirContextMenu + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: qsTr("Delete File") + visible: contextFilePath + height: visible ? implicitHeight : 0 + onTriggered: assetsModel.deleteFile(contextFilePath) + } + + StudioControls.MenuSeparator { + visible: contextFilePath + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: qsTr("Rename Folder") + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: renameFolderDialog.open() + } + + StudioControls.MenuItem { + text: qsTr("New Folder") + onTriggered: newFolderDialog.open() + } + + StudioControls.MenuItem { + text: qsTr("Delete Folder") + visible: isDirContextMenu + height: visible ? implicitHeight : 0 + onTriggered: { + var dirEmpty = !(contextDir.dirsModel && contextDir.dirsModel.rowCount() > 0) + && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0); + + if (dirEmpty) + assetsModel.deleteFolder(contextDir.dirPath) + else + confirmDeleteFolderDialog.open() + } + } + } + RegExpValidator { id: folderNameValidator regExp: /^(\w[^*/> 0) - && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0); - - if (dirEmpty) - assetsModel.deleteFolder(contextDir.dirPath) - else - confirmDeleteFolderDialog.open() - } - } + onClicked: rootView.handleAddAsset() } } - Column { - Repeater { - model: assetsModel // context property - delegate: dirSection - } + Text { + text: qsTr("No match found.") + leftPadding: 10 + color: StudioTheme.Values.themeTextColor + font.pixelSize: 12 + visible: assetsModel.isEmpty && !searchBox.isEmpty() + } - Component { - id: dirSection + ScrollView { // TODO: experiment using ListView instead of ScrollView + Column + id: assetsView + width: parent.width + height: parent.height - y + clip: true + interactive: assetsView.verticalScrollBarVisible - Section { - width: assetsView.width - - (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5 - caption: dirName - sectionHeight: 30 - sectionFontSize: 15 - leftPadding: 0 - topPadding: dirDepth > 0 ? 5 : 0 - bottomPadding: 0 - hideHeader: dirDepth === 0 - showLeftBorder: dirDepth > 0 - expanded: dirExpanded - visible: !assetsModel.isEmpty && dirVisible - expandOnClick: false - useDefaulContextMenu: false + Column { + Repeater { + model: assetsModel // context property + delegate: dirSection + } - onToggleExpand: { - dirExpanded = !dirExpanded - } + Component { + id: dirSection - onShowContextMenu: { - contextFilePath = "" - contextDir = model - isDirContextMenu = true - allExpandedState = assetsModel.getAllExpandedState() - contextMenu.popup() - } + Section { + width: assetsView.width - + (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5 + caption: dirName + sectionHeight: 30 + sectionFontSize: 15 + leftPadding: 0 + topPadding: dirDepth > 0 ? 5 : 0 + bottomPadding: 0 + hideHeader: dirDepth === 0 + showLeftBorder: dirDepth > 0 + expanded: dirExpanded + visible: !assetsModel.isEmpty && dirVisible + expandOnClick: false + useDefaulContextMenu: false - Column { - spacing: 5 - leftPadding: 5 - - Repeater { - model: dirsModel - delegate: dirSection + onToggleExpand: { + dirExpanded = !dirExpanded } - Repeater { - model: filesModel - delegate: fileSection + onShowContextMenu: { + contextFilePath = "" + contextDir = model + isDirContextMenu = true + allExpandedState = assetsModel.getAllExpandedState() + contextMenu.popup() } - Text { - text: qsTr("Empty folder") - color: StudioTheme.Values.themeTextColorDisabled - font.pixelSize: 12 - visible: !(dirsModel && dirsModel.rowCount() > 0) - && !(filesModel && filesModel.rowCount() > 0) + Column { + spacing: 5 + leftPadding: 5 - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: { - contextFilePath = "" - contextDir = model - isDirContextMenu = true - contextMenu.popup() + Repeater { + model: dirsModel + delegate: dirSection + } + + Repeater { + model: filesModel + delegate: fileSection + } + + Text { + text: qsTr("Empty folder") + color: StudioTheme.Values.themeTextColorDisabled + font.pixelSize: 12 + visible: !(dirsModel && dirsModel.rowCount() > 0) + && !(filesModel && filesModel.rowCount() > 0) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + contextFilePath = "" + contextDir = model + isDirContextMenu = true + contextMenu.popup() + } } } } } } - } - Component { - id: fileSection + Component { + id: fileSection - Rectangle { - width: assetsView.width - - (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - height: img.height - color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction - : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground - : "transparent") + Rectangle { + width: assetsView.width - + (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) + height: img.height + color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction + : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground + : "transparent") - Row { - spacing: 5 + Row { + spacing: 5 - Image { - id: img - asynchronous: true - width: 48 - height: 48 - source: "image://qmldesigner_assets/" + filePath + Image { + id: img + asynchronous: true + width: 48 + height: 48 + source: "image://qmldesigner_assets/" + filePath + } + + Text { + text: fileName + color: StudioTheme.Values.themeTextColor + font.pixelSize: 14 + anchors.verticalCenter: parent.verticalCenter + } } - Text { - text: fileName - color: StudioTheme.Values.themeTextColor - font.pixelSize: 14 - anchors.verticalCenter: parent.verticalCenter - } - } + readonly property string suffix: fileName.substr(-4) + readonly property bool isFont: suffix === ".ttf" || suffix === ".otf" + property bool currFileSelected: false - readonly property string suffix: fileName.substr(-4) - readonly property bool isFont: suffix === ".ttf" || suffix === ".otf" - property bool currFileSelected: false + MouseArea { + id: mouseArea - MouseArea { - id: mouseArea + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton + onExited: tooltipBackend.hideTooltip() + onCanceled: tooltipBackend.hideTooltip() + onPositionChanged: tooltipBackend.reposition() + onPressed: (mouse)=> { + forceActiveFocus() + if (mouse.button === Qt.LeftButton) { + var ctrlDown = mouse.modifiers & Qt.ControlModifier + if (!selectedAssets[filePath] && !ctrlDown) + selectedAssets = {} + currFileSelected = ctrlDown ? !selectedAssets[filePath] : true + selectedAssets[filePath] = currFileSelected + selectedAssetsChanged() - onExited: tooltipBackend.hideTooltip() - onCanceled: tooltipBackend.hideTooltip() - onPositionChanged: tooltipBackend.reposition() - onPressed: (mouse)=> { - forceActiveFocus() - if (mouse.button === Qt.LeftButton) { - var ctrlDown = mouse.modifiers & Qt.ControlModifier - if (!selectedAssets[filePath] && !ctrlDown) - selectedAssets = {} - currFileSelected = ctrlDown ? !selectedAssets[filePath] : true - selectedAssets[filePath] = currFileSelected - selectedAssetsChanged() + var selectedAssetsArr = [] + for (var assetPath in selectedAssets) { + if (selectedAssets[assetPath]) + selectedAssetsArr.push(assetPath) + } - var selectedAssetsArr = [] - for (var assetPath in selectedAssets) { - if (selectedAssets[assetPath]) - selectedAssetsArr.push(assetPath) + if (currFileSelected) + rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y)) + } else { + contextFilePath = filePath + contextDir = model.fileDir + + tooltipBackend.hideTooltip() + isDirContextMenu = false + contextMenu.popup() } - - if (currFileSelected) - rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y)) - } else { - contextFilePath = filePath - contextDir = model.fileDir - - tooltipBackend.hideTooltip() - isDirContextMenu = false - contextMenu.popup() } - } - onReleased: (mouse)=> { - if (mouse.button === Qt.LeftButton) { - if (!(mouse.modifiers & Qt.ControlModifier)) - selectedAssets = {} - selectedAssets[filePath] = currFileSelected - selectedAssetsChanged() + onReleased: (mouse)=> { + if (mouse.button === Qt.LeftButton) { + if (!(mouse.modifiers & Qt.ControlModifier)) + selectedAssets = {} + selectedAssets[filePath] = currFileSelected + selectedAssetsChanged() + } } - } - ToolTip { - visible: !isFont && mouseArea.containsMouse && !contextMenu.visible - text: filePath - delay: 1000 - } + ToolTip { + visible: !isFont && mouseArea.containsMouse && !contextMenu.visible + text: filePath + delay: 1000 + } - Timer { - interval: 1000 - running: mouseArea.containsMouse - onTriggered: { - if (suffix === ".ttf" || suffix === ".otf") { - tooltipBackend.name = fileName - tooltipBackend.path = filePath - tooltipBackend.showTooltip() + Timer { + interval: 1000 + running: mouseArea.containsMouse + onTriggered: { + if (suffix === ".ttf" || suffix === ".otf") { + tooltipBackend.name = fileName + tooltipBackend.path = filePath + tooltipBackend.showTooltip() + } } } } @@ -568,7 +605,7 @@ Item { // Placeholder when the assets panel is empty Column { id: colNoAssets - visible: assetsModel.isEmpty && !rootView.searchActive + visible: assetsModel.isEmpty && searchBox.isEmpty() spacing: 20 x: 20 @@ -612,13 +649,4 @@ Item { wrapMode: Text.WordWrap } } - - Text { - text: qsTr("No match found.") - x: 20 - y: 10 - color: StudioTheme.Values.themeTextColor - font.pixelSize: 12 - visible: assetsModel.isEmpty && rootView.searchActive - } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml index 6f7fbc454f4..17d187c2418 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemsView.qml @@ -81,6 +81,7 @@ Item { property var currentCategory: null property var currentImport: null property bool isHorizontalView: false + property bool isAddModuleView: false // Called also from C++ to close context menu on focus out function closeContextMenu() @@ -89,6 +90,12 @@ Item { itemContextMenu.close() } + // Called also from C++ + function switchToComponentsView() + { + isAddModuleView = false + } + onWidthChanged: { itemsView.isHorizontalView = itemsView.width > widthLimit } @@ -188,9 +195,38 @@ Item { } } - Loader { - anchors.fill: parent - sourceComponent: itemsView.isHorizontalView ? horizontalView : verticalView + Column { + id: col + width: parent.width + height: parent.height + y: 5 + spacing: 5 + + Row { + width: parent.width + + SearchBox { + id: searchBox + + width: parent.width - addAssetButton.width - 5 + } + + PlusButton { + id: addAssetButton + tooltip: qsTr("Add a module.") + + onClicked: isAddModuleView = true + } + } + + Loader { + id: loader + + width: col.width + height: col.height - y - 5 + sourceComponent: isAddModuleView ? addModuleView + : itemsView.isHorizontalView ? horizontalView : verticalView + } } Component { @@ -198,8 +234,9 @@ Item { ScrollView { id: verticalScrollView - width: itemsView.width - height: itemsView.height + anchors.fill: parent + clip: true + onContentHeightChanged: { var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0) if (contentY > maxPosition) @@ -312,7 +349,9 @@ Item { ScrollView { id: horizontalScrollView width: 270 - height: itemsView.height + height: parent.height + clip: true + onContentHeightChanged: { var maxPosition = Math.max(contentHeight - horizontalScrollView.height, 0) if (contentY > maxPosition) @@ -452,4 +491,12 @@ Item { } } } + + Component { + id: addModuleView + + AddModuleView { + onBack: isAddModuleView = false + } + } } diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml deleted file mode 100644 index c68891f3318..00000000000 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/LibraryHeader.qml +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -import QtQuick 2.15 -import QtQuick.Controls 2.15 -import QtQuickDesignerTheme 1.0 -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme - -Item { - id: root - - function setTab(index) - { - tabBar.setCurrentIndex(index); - } - - function clearSearchFilter() - { - searchFilterText.text = ""; - } - - Column { - anchors.left: parent.left - anchors.right: parent.right - spacing: 9 - - TabBar { - id: tabBar - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 5 - anchors.rightMargin: 5 - spacing: 40 - - background: Rectangle { - color: StudioTheme.Values.themePanelBackground - } - - Repeater { - model: [{title: qsTr("Components"), addToolTip: qsTr("Add Module")}, - {title: qsTr("Assets"), addToolTip: qsTr("Add new assets to project.")}] - - TabButton { - topPadding: 4 - bottomPadding: 4 - contentItem: Item { - implicitHeight: plusButton.height - - Text { // TabButton text - text: modelData.title - font.pixelSize: 13 - font.bold: false - color: tabBar.currentIndex === index ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeTextColor - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: plusButton.left - anchors.bottomMargin: 2 - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignBottom - elide: Text.ElideRight - } - - Rectangle { // + button - id: plusButton - anchors.right: parent.right - anchors.top: parent.top - anchors.topMargin: 1 - width: 24 - height: 24 - color: mouseArea.containsMouse && enabled - ? StudioTheme.Values.themeControlBackgroundHover - : StudioTheme.Values.themeControlBackground - - Behavior on color { - ColorAnimation { - duration: StudioTheme.Values.hoverDuration - easing.type: StudioTheme.Values.hoverEasing - } - } - - enabled: index !== 0 || !rootView.subCompEditMode - - Label { // + sign - text: StudioTheme.Constants.plus - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: StudioTheme.Values.myIconFontSize - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - color: !plusButton.enabled - ? StudioTheme.Values.themeIconColorDisabled - : tabBar.currentIndex === index - ? StudioTheme.Values.themeIconColorSelected - : StudioTheme.Values.themeIconColor - } - - HelperWidgets.ToolTipArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: index === 0 ? rootView.handleAddModule() - : rootView.handleAddAsset() - tooltip: modelData.addToolTip - } - } - } - - background: Item { // TabButton background - Rectangle { // bottom strip - anchors.bottom: parent.bottom - width: parent.width - height: 2 - color: tabBar.currentIndex === index ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeTextColor - } - } - - onClicked: rootView.handleTabChanged(index); - } - } - } - - TextField { // filter - id: searchFilterText - placeholderText: qsTr("Search") - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - color: StudioTheme.Values.themeTextColor - selectionColor: StudioTheme.Values.themeTextSelectionColor - selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor - background: Rectangle { - id: textFieldBackground - color: StudioTheme.Values.themeControlBackground - border.color: StudioTheme.Values.themeControlOutline - border.width: StudioTheme.Values.border - - Behavior on color { - ColorAnimation { - duration: StudioTheme.Values.hoverDuration - easing.type: StudioTheme.Values.hoverEasing - } - } - } - - height: StudioTheme.Values.defaultControlHeight - - leftPadding: 32 - rightPadding: 30 - topPadding: 6 - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 5 - anchors.rightMargin: 5 - selectByMouse: true - hoverEnabled: true - - onTextChanged: rootView.handleSearchfilterChanged(text) - - Label { - text: StudioTheme.Constants.search - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: 16 - anchors.left: parent.left - anchors.leftMargin: 7 - anchors.verticalCenter: parent.verticalCenter - color: StudioTheme.Values.themeIconColor - } - - Rectangle { // x button - width: 16 - height: 15 - anchors.right: parent.right - anchors.rightMargin: 5 - anchors.verticalCenter: parent.verticalCenter - visible: searchFilterText.text !== "" - color: xMouseArea.containsMouse ? StudioTheme.Values.themePanelBackground - : "transparent" - - Label { - text: StudioTheme.Constants.closeCross - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: StudioTheme.Values.myIconFontSize - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - anchors.centerIn: parent - color: StudioTheme.Values.themeIconColor - } - - MouseArea { - id: xMouseArea - hoverEnabled: true - anchors.fill: parent - onClicked: searchFilterText.text = "" - } - } - - states: [ - State { - name: "default" - when: !searchFilterText.hovered && !searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackground - border.color: StudioTheme.Values.themeControlOutline - } - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - } - }, - State { - name: "hover" - when: searchFilterText.hovered && !searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackgroundHover - border.color: StudioTheme.Values.themeControlOutline - } - - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor - } - }, - State { - name: "edit" - when: searchFilterText.activeFocus - PropertyChanges { - target: textFieldBackground - color: StudioTheme.Values.themeControlBackgroundInteraction - border.color: StudioTheme.Values.themeControlOutlineInteraction - } - PropertyChanges { - target: searchFilterText - placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction - } - } - ] - } - } -} diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml new file mode 100644 index 00000000000..31f69be9967 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/PlusButton.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuickDesignerTheme 1.0 +import HelperWidgets 2.0 as HelperWidgets +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Rectangle { + id: root + + property string tooltip: "" + + signal clicked() + + implicitWidth: 29 + implicitHeight: 29 + color: mouseArea.containsMouse && enabled + ? StudioTheme.Values.themeControlBackgroundHover + : StudioTheme.Values.themeControlBackground + + Behavior on color { + ColorAnimation { + duration: StudioTheme.Values.hoverDuration + easing.type: StudioTheme.Values.hoverEasing + } + } + + Label { // + sign + text: StudioTheme.Constants.plus + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.myIconFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.centerIn: parent + color: root.enabled ? StudioTheme.Values.themeIconColor + : StudioTheme.Values.themeIconColorDisabled + scale: mouseArea.containsMouse ? 1.4 : 1 + + Behavior on scale { + NumberAnimation { + duration: 300 + easing.type: Easing.OutExpo + } + } + } + + HelperWidgets.ToolTipArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: root.clicked() + tooltip: root.tooltip + } +} diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml new file mode 100644 index 00000000000..81ed5c11e49 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/SearchBox.qml @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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. +** +****************************************************************************/ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuickDesignerTheme 1.0 +import HelperWidgets 2.0 as HelperWidgets +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme + +Item { + id: root + + property alias text: searchFilterText.text + + function clearSearchFilter() + { + searchFilterText.text = ""; + } + + function isEmpty() + { + return searchFilterText.text === ""; + } + + implicitWidth: searchFilterText.width + implicitHeight: searchFilterText.height + + TextField { + id: searchFilterText + + placeholderText: qsTr("Search") + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + color: StudioTheme.Values.themeTextColor + selectionColor: StudioTheme.Values.themeTextSelectionColor + selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor + background: Rectangle { + id: textFieldBackground + color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline + border.width: StudioTheme.Values.border + + Behavior on color { + ColorAnimation { + duration: StudioTheme.Values.hoverDuration + easing.type: StudioTheme.Values.hoverEasing + } + } + } + + height: StudioTheme.Values.defaultControlHeight + + leftPadding: 32 + rightPadding: 30 + topPadding: 6 + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 5 + anchors.rightMargin: 5 + selectByMouse: true + hoverEnabled: true + + onTextChanged: rootView.handleSearchfilterChanged(text) + + Label { + text: StudioTheme.Constants.search + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: 16 + anchors.left: parent.left + anchors.leftMargin: 7 + anchors.verticalCenter: parent.verticalCenter + color: StudioTheme.Values.themeIconColor + } + + Rectangle { // x button + width: 16 + height: 15 + anchors.right: parent.right + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + visible: searchFilterText.text !== "" + color: xMouseArea.containsMouse ? StudioTheme.Values.themePanelBackground + : "transparent" + + Label { + text: StudioTheme.Constants.closeCross + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.myIconFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + anchors.centerIn: parent + color: StudioTheme.Values.themeIconColor + } + + MouseArea { + id: xMouseArea + hoverEnabled: true + anchors.fill: parent + onClicked: searchFilterText.text = "" + } + } + + states: [ + State { + name: "default" + when: !searchFilterText.hovered && !searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackground + border.color: StudioTheme.Values.themeControlOutline + } + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + } + }, + State { + name: "hover" + when: searchFilterText.hovered && !searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackgroundHover + border.color: StudioTheme.Values.themeControlOutline + } + + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColor + } + }, + State { + name: "edit" + when: searchFilterText.activeFocus + PropertyChanges { + target: textFieldBackground + color: StudioTheme.Values.themeControlBackgroundInteraction + border.color: StudioTheme.Values.themeControlOutlineInteraction + } + PropertyChanges { + target: searchFilterText + placeholderTextColor: StudioTheme.Values.themePlaceholderTextColorInteraction + } + } + ] + } +} diff --git a/share/qtcreator/qmldesigner/misc/BusyIndicator.qml b/share/qtcreator/qmldesigner/misc/BusyIndicator.qml new file mode 100644 index 00000000000..93cf639bca7 --- /dev/null +++ b/share/qtcreator/qmldesigner/misc/BusyIndicator.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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. +** +****************************************************************************/ + +import QtQuick +import QtQuick.Controls + +BusyIndicator { + id: control + + contentItem: Item { + implicitWidth: 64 + implicitHeight: 64 + + Item { + id: item + anchors.centerIn: parent + width: 64 + height: 64 + opacity: control.running ? 1 : 0 + + Behavior on opacity { + OpacityAnimator { + duration: 250 + } + } + + RotationAnimator { + target: item + running: control.visible && control.running + from: 0 + to: 360 + loops: Animation.Infinite + duration: 2000 + } + + Repeater { + id: repeater + model: 6 + + Rectangle { + id: delegate + anchors.centerIn: parent + implicitWidth: 10 + implicitHeight: 10 + radius: 5 + color: "#2aafd3" + + required property int index + + transform: [ + Translate { + y: -Math.min(item.width, item.height) * 0.5 + 5 + }, + Rotation { + angle: delegate.index / repeater.count * 360 + origin.x: 5 + origin.y: 5 + } + ] + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk b/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk index 62c823b1470..fba5f4a822f 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/3D_Preset.wrk @@ -3,8 +3,9 @@ - - + + + diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk index 0b1a7c2d528..2bdbc74f22c 100644 --- a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk +++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk @@ -3,8 +3,9 @@ - - + + + diff --git a/share/qtcreator/scripts/openTerminal.py b/share/qtcreator/scripts/openTerminal.py index bae549ca9fa..a0347c08674 100755 --- a/share/qtcreator/scripts/openTerminal.py +++ b/share/qtcreator/scripts/openTerminal.py @@ -42,9 +42,9 @@ def clean_environment_script(): 'TERM_SESSION_ID']) return r''' function ignore() { - local keys="''' + env_to_keep + '''" + local keys=(''' + env_to_keep + ''') local v=$1 - for e in $keys; do [[ "$e" == "$v" ]] && return 0; done + for e in "${keys[@]}"; do [[ "$e" == "$v" ]] && return 0; done } while read -r line; do key=$(echo $line | /usr/bin/cut -d '=' -f 1) diff --git a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt index a8f5980862e..4d352af3d65 100644 --- a/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/CMakeLists.txt @@ -29,6 +29,7 @@ add_qtc_library(KSyntaxHighlighting SHARED src/lib/foldingregion.cpp src/lib/foldingregion.h src/lib/format.cpp src/lib/format.h src/lib/format_p.h src/lib/htmlhighlighter.cpp src/lib/htmlhighlighter.h + src/lib/highlightingdata.cpp src/lib/highlightingdata_p.hpp src/lib/keywordlist.cpp src/lib/keywordlist_p.h src/lib/matchresult_p.h src/lib/repository.cpp src/lib/repository.h src/lib/repository_p.h diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h index a8c5d74235a..4336b19ce5d 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/ksyntaxhighlighting_version.h @@ -3,10 +3,10 @@ #ifndef SyntaxHighlighting_VERSION_H #define SyntaxHighlighting_VERSION_H -#define SyntaxHighlighting_VERSION_STRING "5.87.0" +#define SyntaxHighlighting_VERSION_STRING "5.90.0" #define SyntaxHighlighting_VERSION_MAJOR 5 -#define SyntaxHighlighting_VERSION_MINOR 87 +#define SyntaxHighlighting_VERSION_MINOR 90 #define SyntaxHighlighting_VERSION_PATCH 0 -#define SyntaxHighlighting_VERSION ((5<<16)|(87<<8)|(0)) +#define SyntaxHighlighting_VERSION ((5<<16)|(90<<8)|(0)) #endif diff --git a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h index 1213499635c..25fb987a978 100644 --- a/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h +++ b/src/libs/3rdparty/syntax-highlighting/autogenerated/src/lib/ksyntaxhighlighting_export.h @@ -88,7 +88,7 @@ #define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00 #endif #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 @@ -98,7 +98,7 @@ # ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00 # endif #endif @@ -178,7 +178,7 @@ #define KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(major, minor) 1 #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED -# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55700 +# define KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT 0x55a00 #endif #ifdef KSYNTAXHIGHLIGHTING_NO_DEPRECATED_WARNINGS # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0 @@ -188,7 +188,7 @@ # ifdef KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE KSYNTAXHIGHLIGHTING_DISABLE_DEPRECATED_BEFORE_AND_AT # else -# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55700 +# define KSYNTAXHIGHLIGHTING_DEPRECATED_WARNINGS_SINCE 0x55a00 # endif #endif diff --git a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt index acc2429ec84..6e86a05e9e3 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/data/CMakeLists.txt @@ -64,7 +64,7 @@ if (QRC_SYNTAX) # generate the qrc file manually, to make dependencies on generated files work... add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" - COMMAND ${Qt5Core_RCC_EXECUTABLE} --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc" + COMMAND Qt${QT_MAJOR_VERSION}::rcc --name syntax_data -o "${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" "${CMAKE_CURRENT_BINARY_DIR}/syntax-data.qrc" DEPENDS ${defs} ${CMAKE_CURRENT_BINARY_DIR}/index.katesyntax ) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/qrc_syntax-data.cpp" PROPERTIES SKIP_AUTOMOC ON) @@ -79,5 +79,5 @@ endif() # this needs some more recent CMake than generally required set_property(TARGET SyntaxHighlightingData PROPERTY POSITION_INDEPENDENT_CODE 1) if(NOT ${CMAKE_VERSION} VERSION_LESS "3.13.0") - target_link_libraries(SyntaxHighlightingData PRIVATE Qt5::Core) + target_link_libraries(SyntaxHighlightingData PRIVATE Qt${QT_MAJOR_VERSION}::Core) endif() diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl index 1c1a3da4ba2..45057a8a054 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.xml.tpl @@ -1,7 +1,10 @@ + + + + ]> - + + + @@ -54,6 +59,9 @@ + + + @@ -87,6 +95,24 @@ + + + + + + + + + + + + + + + + + + @@ -94,25 +120,68 @@ beginRegion="" endRegion="" /> + + + - - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + @@ -132,9 +201,21 @@ + + + + + + + + + + + + - + @@ -153,33 +234,27 @@ - + + + - + + - - - - - - - - - - + - + @@ -198,7 +273,7 @@ - + @@ -229,6 +304,15 @@ + + + + + + + + + @@ -261,12 +345,12 @@ - - + + - + @@ -330,9 +414,12 @@ + + + @@ -351,8 +438,10 @@ - + + + @@ -360,7 +449,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml index ab26c2153b3..f5437900627 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/cmake.yaml @@ -1,4 +1,4 @@ -version: 34 +version: 37 global-properties: - ALLOW_DUPLICATE_CUSTOM_TARGETS @@ -415,6 +415,7 @@ test-properties: - DEPENDS - DISABLED - ENVIRONMENT + - ENVIRONMENT_MODIFICATION # Since 3.22 - FAIL_REGULAR_EXPRESSION - FIXTURES_CLEANUP - FIXTURES_REQUIRED @@ -790,6 +791,7 @@ variables: - CMAKE_PROJECT_INCLUDE # Since 3.15 - CMAKE_PROJECT_INCLUDE_BEFORE # Since 3.15 - CMAKE_PROJECT__INCLUDE + - CMAKE_REQUIRE_FIND_PACKAGE_ # Since 3.22 - CMAKE_SKIP_INSTALL_ALL_DEPENDENCY - CMAKE_STAGING_PREFIX - CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS @@ -967,6 +969,7 @@ variables: - CMAKE__LINKER_LAUNCHER # Sine 3.21 - CMAKE__LINK_LIBRARY_FILE_FLAG # Sine 3.16 - CMAKE__LINK_LIBRARY_FLAG # Sine 3.16 + - CMAKE__LINK_WHAT_YOU_USE_FLAG # Since 3.22 - CMAKE__VISIBILITY_PRESET - CMAKE_LIBRARY_OUTPUT_DIRECTORY - CMAKE_LIBRARY_OUTPUT_DIRECTORY_ @@ -977,6 +980,7 @@ variables: - CMAKE_LINK_LIBRARY_FILE_FLAG - CMAKE_LINK_LIBRARY_FLAG - CMAKE_LINK_WHAT_YOU_USE + - CMAKE_LINK_WHAT_YOU_USE_CHECK # Since 3.22 - CMAKE_MACOSX_BUNDLE - CMAKE_MACOSX_RPATH - CMAKE_MAP_IMPORTED_CONFIG_ @@ -1055,6 +1059,10 @@ variables: - CMAKE_Fortran_MODDIR_DEFAULT - CMAKE_Fortran_MODDIR_FLAG - CMAKE_Fortran_MODOUT_FLAG + - CMAKE_HIP_ARCHITECTURES # Since 3.21 + - CMAKE_HIP_EXTENSIONS # Since 3.21 + - CMAKE_HIP_STANDARD # Since 3.21 + - CMAKE_HIP_STANDARD_REQUIRED # Since 3.21 - CMAKE_ISPC_HEADER_DIRECTORY # Since 3.19 - CMAKE_ISPC_HEADER_SUFFIX # Since 3.19.2 - CMAKE_ISPC_INSTRUCTION_SETS # Since 3.19 @@ -1075,6 +1083,8 @@ variables: - CMAKE__CREATE_SHARED_LIBRARY - CMAKE__CREATE_SHARED_MODULE - CMAKE__CREATE_STATIC_LIBRARY + - CMAKE__EXTENSIONS + - CMAKE__EXTENSIONS_DEFAULT # Since 3.22 - CMAKE__FLAGS - CMAKE__FLAGS_DEBUG - CMAKE__FLAGS_DEBUG_INIT @@ -1269,7 +1279,14 @@ variables: - CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM - CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL - CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND + # Fallback Interface Variables for `cmake_host_system_information` + # Since CMake 3.22 + - CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS + - CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ + - CMAKE_GET_OS_RELEASE_FALLBACK_RESULT # Well known CMake's official module's variables + # - BundleUtilities + - BU_CHMOD_BUNDLE_ITEMS # - CheckCompilerFlag # - CheckCCompilerFlag # - CheckSourceCompiles @@ -1289,6 +1306,13 @@ variables: # - CheckIncludeFile # - CheckIncludeFiles # - CheckLibraryExists + # - CheckPIESupported + - CMAKE_C_LINK_PIE_SUPPORTED + - CMAKE_CXX_LINK_PIE_SUPPORTED + - CMAKE_Fortran_LINK_PIE_SUPPORTED + - CMAKE_C_LINK_NO_PIE_SUPPORTED + - CMAKE_CXX_LINK_NO_PIE_SUPPORTED + - CMAKE_Fortran_LINK_NO_PIE_SUPPORTED # - CheckPrototypeDefinition # - CheckStructHasMember # - CheckSymbolExists @@ -1498,6 +1522,7 @@ variables: - CPACK_NSIS_BRANDING_TEXT # Since 3.20 - CPACK_NSIS_BRANDING_TEXT_TRIM_POSITION # Since 3.20 - CPACK_NSIS_EXECUTABLE # Since 3.21 + - CPACK_NSIS_IGNORE_LICENSE_PAGE # Since 3.22 # - CPackNuGet (since 3.12) - CPACK_NUGET_COMPONENT_INSTALL - CPACK_NUGET_PACKAGE_NAME @@ -1655,6 +1680,7 @@ variables: - CPACK_RPM_SOURCE_PKG_BUILD_PARAMS - CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX - CPACK_RPM_BUILDREQUIRES + - CPACK_RPM_REQUIRES_EXCLUDE_FROM # Since 3.22 # - CPack - CPACK_PACKAGE_NAME - CPACK_PACKAGE_VENDOR @@ -1746,18 +1772,552 @@ variables: - ExternalData_CUSTOM_LOCATION - ExternalData_CUSTOM_FILE - ExternalData_CUSTOM_ERROR + # - FetchContent + - FETCHCONTENT_QUIET + - FETCHCONTENT_FULLY_DISCONNECTED + - FETCHCONTENT_UPDATES_DISCONNECTED + - FETCHCONTENT_SOURCE_DIR_ + - FETCHCONTENT_UPDATES_DISCONNECTED_ # - FindXXX module "standard" variables - _INCLUDE_DIRS - _LIBRARIES - _LIBRARY_DIRS - _VERSION_STRING + # NOTE For the other stanfard finders below variables matched + # the regular expressions above gonna be omitted. + # - FindALSA + - ALSA_LIBRARY + # - FindArmadillo + - ALSA_LIBRARY + # - FindASPELL + - ASPELL_EXECUTABLE + - ASPELL_DEFINITIONS + # - FindAVIFile + - AVIFILE_DEFINITIONS + # - FindBacktrace + - Backtrace_HEADER + - Backtrace_LIBRARY + # - FindBISON + - BISON_EXECUTABLE + - BISON__DEFINED + - BISON__INPUT + - BISON__OUTPUT_SOURCE + - BISON__OUTPUT_HEADER + - BISON__OUTPUTS + - BISON__COMPILE_FLAGS + # - FindBLAS + - BLA_STATIC + - BLA_VENDOR + - BLA_F95 + - BLA_PREFER_PKGCONFIG + - BLAS_LINKER_FLAGS + - BLA_SIZEOF_INTEGER # Since 3.22 + # - FindBoost + - Boost__LIBRARY + - Boost_VERSION_MACRO + - Boost_VERSION_COUNT + - Boost_INCLUDE_DIR + - Boost_LIBRARY_DIR_DEBUG + - Boost_LIBRARY_DIR_RELEASE + - Boost__LIBRARY_DEBUG + - Boost__LIBRARY_RELEASE + - BOOSTROOT + - BOOST_INCLUDEDIR + - BOOST_LIBRARYDIR + - Boost_NO_SYSTEM_PATHS + - Boost_ADDITIONAL_VERSIONS + - Boost_USE_DEBUG_LIBS + - Boost_USE_RELEASE_LIBS + - Boost_USE_MULTITHREADED + - Boost_USE_STATIC_LIBS + - Boost_USE_DEBUG_RUNTIME + - Boost_USE_DEBUG_PYTHON + - Boost_USE_STLPORT + - Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS + - Boost_COMPILER + - Boost_LIB_PREFIX + - Boost_ARCHITECTURE + - Boost_THREADAPI + - Boost_NAMESPACE + - Boost_DEBUG + - Boost_REALPATH + - Boost_NO_WARN_NEW_VERSIONS + # - FindBullet + # - FindBZip2 + - BZIP2_NEED_PREFIX + - BZIP2_INCLUDE_DIR + # - FindCABLE + - CABLE + - CABLE_TCL_LIBRARY + - CABLE_INCLUDE_DIR + # - FindCoin3D + # - FindCUDAToolkit + - CUDAToolkit_NVCC_EXECUTABLE + # - FindCups + - CUPS_INCLUDE_DIR + # - FindCURL + - CURL_NO_CURL_CMAKE + # - FindCurses + - CURSES_CFLAGS + - CURSES_HAVE_CURSES_H + - CURSES_HAVE_NCURSES_H + - CURSES_HAVE_NCURSES_NCURSES_H + - CURSES_HAVE_NCURSES_CURSES_H + - CURSES_NEED_NCURSES + - CURSES_NEED_WIDE + # - CURSES_LIBRARY deprecated + # - FindCVS + - CVS_EXECUTABLE + # - FindCxxTest + - CXXTEST_USE_PYTHON + - CXXTEST_TESTGEN_ARGS + - CXXTEST_PERL_TESTGEN_EXECUTABLE + - CXXTEST_PYTHON_TESTGEN_EXECUTABLE + - CXXTEST_TESTGEN_EXECUTABLE + - CXXTEST_TESTGEN_INTERPRETER + # - FindCygwin + # - FindDart + # - FindDCMTK + # - FindDevIL # - FindDoxygen - DOXYGEN_ + # - FindEnvModules + - EnvModules_COMMAND + # - FindEXPAT + # - FindFLEX + - FLEX_EXECUTABLE + # - FindFLTK + - FLTK_SKIP_OPENGL + - FLTK_SKIP_FORMS + - FLTK_SKIP_IMAGES + - FLTK_SKIP_FLUID + - FLTK_FLUID_EXECUTABLE + - FLTK_WRAP_UI + - FLTK_BASE_LIBRARY_RELEASE + - FLTK_BASE_LIBRARY_DEBUG + - FLTK_GL_LIBRARY_RELEASE + - FLTK_GL_LIBRARY_DEBUG + - FLTK_FORMS_LIBRARY_RELEASE + - FLTK_FORMS_LIBRARY_DEBUG + - FLTK_IMAGES_LIBRARY_RELEASE + - FLTK_IMAGES_LIBRARY_DEBUG + # - FindFLTK2 + - FLTK2_FLUID_EXECUTABLE + - FLTK2_WRAP_UI + - FLTK2_BASE_LIBRARY + - FLTK2_GL_LIBRARY + - FLTK2_IMAGES_LIBRARY + # - FindFontconfig + - Fontconfig_COMPILE_OPTIONS + # - FindFreetype + - FREETYPE_INCLUDE_DIR_ft2build + - FREETYPE_INCLUDE_DIR_freetype2 + # - FindGCCXML + - GCCXML + # - FindGDAL + - GDAL_LIBRARY + - FindGDAL_SKIP_GDAL_CONFIG + - GDAL_ADDITIONAL_LIBRARY_VERSIONS + # - FindGettext + - GETTEXT_MSGMERGE_EXECUTABLE + - GETTEXT_MSGFMT_EXECUTABLE + # - FindGIF + - GIF_LIBRARY + # - FindGit + - GIT_EXECUTABLE + # - FindGLEW + - GLEW_USE_STATIC_LIBS + - GLEW_VERBOSE + # - FindGLUT + - GLUT_glut_LIBRARY + - GLUT_Xmu_LIBRARY + - GLUT_Xi_LIBRARY + # - FindGnuplot + - GNUPLOT_EXECUTABLE + # - FindGnuTLS + - GNUTLS_DEFINITIONS + # - FindGSL + - GSL_CBLAS_LIBRARY + - GSL_CBLAS_LIBRARY_DEBUG + - GSL_CONFIG_EXECUTABLE + - GSL_LIBRARY + - GSL_LIBRARY_DEBUG + # - FindGTest + - GTEST_MSVC_SEARCH + # - FindGTK + # - FindGTK2 + - GTK2_TARGETS + - GTK2_DEFINITIONS + - GTK2_USE_IMPORTED_TARGETS + - GTK2_DEBUG + - GTK2_ADDITIONAL_SUFFIXES + # - FindHDF5 + - HDF5_DEFINITIONS + - HDF5_C_DEFINITIONS + - HDF5_CXX_DEFINITIONS + - HDF5_Fortran_DEFINITIONS + - HDF5_IS_PARALLEL + - HDF5_C_COMPILER_EXECUTABLE + - HDF5_CXX_COMPILER_EXECUTABLE + - HDF5_Fortran_COMPILER_EXECUTABLE + - HDF5_C_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_CXX_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_Fortran_COMPILER_EXECUTABLE_NO_INTERROGATE + - HDF5_DIFF_EXECUTABLE + - HDF5_PREFER_PARALLEL + - HDF5_FIND_DEBUG + - HDF5_NO_FIND_PACKAGE_CONFIG_FILE + # - FindHg + - HG_EXECUTABLE + #- _WC_CHANGESET + #- _WC_REVISION + # - FindHSPELL + # - FindHTMLHelp + - HTML_HELP_COMPILER + - HTML_HELP_LIBRARY + # - FindIce + # - FindIconv + - Iconv_IS_BUILT_IN + - Iconv_LIBRARY + # - FindIcotool + - ICOTOOL_EXECUTABLE + # - FindICU + - ICU_MAKEFILE_INC + - ICU_PKGDATA_INC + - ICU_

_EXECUTABLE + - ICU__LIBRARY + - ICU_DEBUG + # - FindImageMagick + # - FindIntl + - Intl_LIBRARY + - Intl_IS_BUILT_IN + # - FindITK + # - FindJasper + - JASPER_LIBRARY_RELEASE + - JASPER_LIBARRY_DEBUG + # - FindJava + - Java_JAVA_EXECUTABLE + - Java_JAVAC_EXECUTABLE + - Java_JAVAH_EXECUTABLE + - Java_JAVADOC_EXECUTABLE + - Java_IDLJ_EXECUTABLE + - Java_JAR_EXECUTABLE + - Java_JARSIGNER_EXECUTABLE + # - FindJNI + - JAVA_AWT_LIBRARY + - JAVA_JVM_LIBRARY + - JAVA_INCLUDE_PATH + - JAVA_INCLUDE_PATH2 + - JAVA_AWT_INCLUDE_PATH + # - FindJPEG + - JPEG_LIBRARY_RELEASE + - JPEG_LIBRARY_DEBUG + - JPEG_LIBRARY + # - FindKDE3 + # - FindKDE4 + # - FindLAPACK + - LAPACK_LINKER_FLAGS + # - FindLATEX + - LATEX_COMPILER + - PDFLATEX_COMPILER + - XELATEX_COMPILER + - LUALATEX_COMPILER + - BIBTEX_COMPILER + - BIBER_COMPILER + - MAKEINDEX_COMPILER + - XINDY_COMPILER + - DVIPS_CONVERTER + - DVIPDF_CONVERTER + - PS2PDF_CONVERTER + - PDFTOPS_CONVERTER + - LATEX2HTML_CONVERTER + - HTLATEX_COMPILER + # - FindLibArchive + # - FindLibinput + - Libinput_COMPILE_OPTIONS + # - FindLibLZMA + - LIBLZMA_HAS_AUTO_DECODER + - LIBLZMA_HAS_EASY_ENCODER + - LIBLZMA_HAS_LZMA_PRESET + # - FindLibXml2 + - LIBXML2_DEFINITIONS + - LIBXML2_XMLLINT_EXECUTABLE + - LIBXML2_LIBRARY + # - FindLibXslt + - LIBXSLT_DEFINITIONS + - LIBXSLT_XSLTPROC_EXECUTABLE + # - FindLTTngUST + - LTTNGUST_HAS_TRACEF + - LTTNGUST_HAS_TRACELOG + # - FindLua + # - FindLua50 + # - FindLua51 + # - FindMatlab + - MATLAB_FIND_DEBUG + - MATLAB_ADDITIONAL_VERSIONS + - Matlab_MAIN_PROGRAM + - Matlab_MEX_LIBRARY + - Matlab_MX_LIBRARY + - Matlab_ENG_LIBRARY + - Matlab_MAT_LIBRARY + - Matlab_ENGINE_LIBRARY + - Matlab_DATAARRAY_LIBRARY + - Matlab_MEX_COMPILER + - Matlab_MCC_COMPILER + - Matlab_MEX_EXTENSION + # - FindMFC + # - FindMotif + # - FindMPEG + - MPEG_mpeg2_LIBRARY + - MPEG_vo_LIBRARY + # - FindMPEG2 + - MPEG2_mpeg2_LIBRARY + - MPEG2_vo_LIBRARY + # - FindMPI + - MPI__COMPILER + - MPI__COMPILE_OPTIONS + - MPI__COMPILE_DEFINITIONS + - MPI_Fortran_HAVE_F77_HEADER + - MPI_Fortran_HAVE_F90_MODULE + - MPI_Fortran_HAVE_F08_MODULE + - MPIEXEC_EXECUTABLE + - MPIEXEC_NUMPROC_FLAG + - MPIEXEC_MAX_NUMPROCS + - MPIEXEC_PREFLAGS + - MPIEXEC_POSTFLAGS + - MPIEXEC_EXECUTABLE + - MPI_HOME + - MPI_COMPILER_FLAGS + - MPI_EXECUTABLE_SUFFIX + - MPI_GUESS_LIBRARY_NAME + - MPI_ASSUME_NO_BUILTIN_MPI + - MPI_SKIP_COMPILER_WRAPPER + - MPI_SKIP_GUESSING + - MPI_CXX_SKIP_MPICXX + - MPI__ADDITIONAL_INCLUDE_VARS + - MPI__LIBRARY + - MPI__LIB_NAMES + - MPI_DETERMINE_Fortran_CAPABILITIES + - MPI_SUBARRAYS_SUPPORTED + - MPI_ASYNC_PROTECTS_NONBLOCKING + - MPI_Fortran_F77_HEADER_SUBARRAYS + - MPI_Fortran_F77_HEADER_ASYNCPROT + - MPI_Fortran_F90_MODULE_SUBARRAYS + - MPI_Fortran_F90_MODULE_ASYNCPROT + - MPI_Fortran_F08_MODULE_SUBARRAYS + - MPI_Fortran_F08_MODULE_ASYNCPROT + # - FindMsys + # - FindODBC + - ODBC_CONFIG + - ODBC_LIBRARY + # - FindOpenACC + - OpenACC__FLAGS + - OpenACC__OPTIONS + - OpenACC__SPEC_DATE + - OpenACC_ACCEL_TARGET + # - FindOpenAL + - OPENAL_LIBRARY + # - FindOpenCL + - OpenCL_LIBRARY + # - FindOpenGL + - OPENGL_egl_LIBRARY + - OPENGL_glu_LIBRARY + - OPENGL_glx_LIBRARY + - OPENGL_opengl_LIBRARY + - OPENGL_gl_LIBRARY + - OpenGL_GL_PREFERENCE + # - FindOpenMP + - OpenMP__FLAGS + - OpenMP__LIB_NAMES + - OpenMP__LIBRARY + - OpenMP_Fortran_HAVE_OMPLIB_HEADER + - OpenMP_Fortran_HAVE_OMPLIB_MODULE + - OpenMP__SPEC_DATE + # - FindOpenSceneGraph + # - FindOpenSSL + - OPENSSL_CRYPTO_LIBRARY + - OPENSSL_SSL_LIBRARY + - OPENSSL_APPLINK_SOURCE + - OPENSSL_USE_STATIC_LIBS + - OPENSSL_MSVC_STATIC_RT + # - FindOpenThreads + # - Findosg + # - Findosg_functions + # - FindosgAnimation + # - FindosgDB + # - FindosgFX + # - FindosgGA + # - FindosgIntrospection + # - FindosgManipulator + # - FindosgParticle + # - FindosgPresentation + # - FindosgProducer + # - FindosgQt + # - FindosgShadow + # - FindosgSim + # - FindosgTerrain + # - FindosgText + # - FindosgUtil + # - FindosgViewer + # - FindosgVolume + # - FindosgWidget + # - FindPatch + - Patch_EXECUTABLE + # - FindPerl + - PERL_EXECUTABLE + # - FindPerlLibs + - PERL_SITESEARCH + - PERL_SITEARCH + - PERL_SITELIB + - PERL_VENDORARCH + - PERL_VENDORLIB + - PERL_ARCHLIB + - PERL_PRIVLIB + - PERL_UPDATE_ARCHLIB + - PERL_UPDATE_PRIVLIB + - PERL_EXTRA_C_FLAGS + # - FindPHP4 + - PHP4_INCLUDE_PATH + - PHP4_EXECUTABLE + # - FindPhysFS + - PHYSFS_LIBRARY + # - FindPike + - PIKE_INCLUDE_PATH + - PIKE_EXECUTABLE # - FindPkgConfig - PKG_CONFIG_EXECUTABLE - PKG_CONFIG_VERSION_STRING - PKG_CONFIG_USE_CMAKE_PREFIX_PATH - _MODULE_NAME # Since 3.16 + # - FindPNG + - PNG_DEFINITIONS + - PNG_LIBRARY + # - FindPostgreSQL + # - FindProducer + # - FindProtobuf + - Protobuf_SRC_ROOT_FOLDER + - Protobuf_IMPORT_DIRS + - Protobuf_DEBUG + - Protobuf_USE_STATIC_LIBS + - Protobuf_LIBRARY + - Protobuf_PROTOC_LIBRARY + - Protobuf_PROTOC_EXECUTABLE + - Protobuf_LIBRARY_DEBUG + - Protobuf_PROTOC_LIBRARY_DEBUG + - Protobuf_LITE_LIBRARY + - Protobuf_LITE_LIBRARY_DEBUG + # - FindPython + - Python_EXECUTABLE + - Python_INTERPRETER_ID + - Python_STDLIB + - Python_STDARCH + - Python_SITELIB + - Python_SITEARCH + - Python_SOABI + - Python_COMPILER + - Python_COMPILER_ID + - Python_DOTNET_LAUNCHER + - Python_LINK_OPTIONS + - Python_USE_STATIC_LIBS + - Python_FIND_ABI + - Python_FIND_STRATEGY + - Python_FIND_REGISTRY + - Python_FIND_FRAMEWORK + - Python_FIND_VIRTUALENV + - Python_FIND_IMPLEMENTATIONS + - Python_FIND_UNVERSIONED_NAMES + - Python_ARTIFACTS_INTERACTIVE + # - FindPython2 + - Python2_EXECUTABLE + - Python2_INTERPRETER_ID + - Python2_STDLIB + - Python2_STDARCH + - Python2_SITELIB + - Python2_SITEARCH + - Python2_SOABI + - Python2_COMPILER + - Python2_COMPILER_ID + - Python2_DOTNET_LAUNCHER + - Python2_LINK_OPTIONS + - Python2_USE_STATIC_LIBS + - Python2_FIND_ABI + - Python2_FIND_STRATEGY + - Python2_FIND_REGISTRY + - Python2_FIND_FRAMEWORK + - Python2_FIND_VIRTUALENV + - Python2_FIND_IMPLEMENTATIONS + - Python2_FIND_UNVERSIONED_NAMES + - Python2_ARTIFACTS_INTERACTIVE + # - FindPython3 + - Python3_EXECUTABLE + - Python3_INTERPRETER_ID + - Python3_STDLIB + - Python3_STDARCH + - Python3_SITELIB + - Python3_SITEARCH + - Python3_SOABI + - Python3_COMPILER + - Python3_COMPILER_ID + - Python3_DOTNET_LAUNCHER + - Python3_LINK_OPTIONS + - Python3_USE_STATIC_LIBS + - Python3_FIND_ABI + - Python3_FIND_STRATEGY + - Python3_FIND_REGISTRY + - Python3_FIND_FRAMEWORK + - Python3_FIND_VIRTUALENV + - Python3_FIND_IMPLEMENTATIONS + - Python3_FIND_UNVERSIONED_NAMES + - Python3_ARTIFACTS_INTERACTIVE + # - FindQt3 + # - FindQt4 + # - FindQuickTime + # - FindRTI + - RTI_DEFINITIONS + # - FindRuby + - Ruby_EXECUTABLE + - Ruby_FIND_VIRTUALENV + # - FindSDL + - SDL_LIBRARY + - SDL_BUILDING_LIBRARY + # - FindSDL_image + - SDLIMAGE_LIBRARY + # - FindSDL_mixer + - SDLMIXER_LIBRARY + # - FindSDL_net + - SDLNET_LIBRARY + # - FindSDL_sound + - SDL_SOUND_LIBRARY + # - FindSDL_ttf + - SDLTTF_LIBRARY + # - FindSelfPackers + # - FindSquish + - SQUISH_SERVER_EXECUTABLE + - SQUISH_CLIENT_EXECUTABLE + # - FindSQLite3 + # - FindSubversion + - Subversion_SVN_EXECUTABLE + - Subversion_VERSION_SVN + # _WC_URL + # _WC_ROOT + # _WC_REVISION + # _WC_LAST_CHANGED_AUTHOR + # _WC_LAST_CHANGED_DATE + # _WC_LAST_CHANGED_REV + # _WC_INFO + # - FindSWIG + - SWIG_EXECUTABLE + # - FindTCL + - TCL_INCLUDE_PATH + - TCL_TCLSH + - TK_LIBRARY + - TK_INCLUDE_PATH + - TK_WISH + # - FindTclsh + # - FindTclStub + - TCL_STUB_LIBRARY + - TK_STUB_LIBRARY + - TTK_STUB_LIBRARY # - FindThreads - CMAKE_THREAD_LIBS_INIT - CMAKE_USE_SPROC_INIT @@ -1766,6 +2326,62 @@ variables: - CMAKE_HP_PTHREADS_INIT - CMAKE_THREAD_PREFER_PTHREAD - THREADS_PREFER_PTHREAD_FLAG + # - FindTIFF + - TIFF_LIBRARY_RELEASE + - TIFF_LIBRARY_DEBUG + - TIFFXX_LIBRARY_RELEASE + - TIFFXX_LIBRARY_DEBUG + # - FindUnixCommands + # - FindVTK + # - FindVulkan + - Vulkan_LIBRARY + - Vulkan_GLSLC_EXECUTABLE + - Vulkan_GLSLANG_VALIDATOR_EXECUTABLE + # - FindWget + - WGET_EXECUTABLE + # - FindWish + # - FindwxWidgets + - wxWidgets_CONFIGURATION + - wxWidgets_EXCLUDE_COMMON_LIBRARIES + - wxWidgets_USE_DEBUG + - wxWidgets_USE_UNICODE + - wxWidgets_USE_UNIVERSAL + - wxWidgets_USE_STATIC + - wxWidgets_DEFINITIONS + - wxWidgets_DEFINITIONS_DEBUG + - wxWidgets_CXX_FLAGS + - wxWidgets_USE_FILE + # - FindX11 + # - FindXalanC + - XalanC_LIBRARY + # - FindXCTest + - XCTest_EXECUTABLE + # - FindXercesC + - XercesC_LIBRARY + # - FindXMLRPC + # - FindZLIB + # - FortranCInterface + # The following vars gonna match by regex + # - FortranCInterface_GLOBAL_FOUND + # - FortranCInterface_MODULE_FOUND + - FortranCInterface_GLOBAL_PREFIX + - FortranCInterface_GLOBAL_SUFFIX + - FortranCInterface_GLOBAL_CASE + - FortranCInterface_GLOBAL__PREFIX + - FortranCInterface_GLOBAL__SUFFIX + - FortranCInterface_GLOBAL__CASE + - FortranCInterface_MODULE_PREFIX + - FortranCInterface_MODULE_MIDDLE + - FortranCInterface_MODULE_SUFFIX + - FortranCInterface_MODULE_CASE + - FortranCInterface_MODULE__PREFIX + - FortranCInterface_MODULE__MIDDLE + - FortranCInterface_MODULE__SUFFIX + - FortranCInterface_MODULE__CASE + - FortranCInterface_VERIFIED_C + - FortranCInterface_VERIFIED_CXX + - FortranCInterface_GLOBAL_SYMBOLS + - FortranCInterface_MODULE_SYMBOLS # - GNUInstallDirs - CMAKE_INSTALL_BINDIR - CMAKE_INSTALL_FULL_BINDIR @@ -1799,6 +2415,8 @@ variables: - CMAKE_INSTALL_FULL_MANDIR - CMAKE_INSTALL_DOCDIR - CMAKE_INSTALL_FULL_DOCDIR + # - GoogleTest + - CMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE # - InstallRequiredSystemLibraries - CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS - CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP @@ -1866,12 +2484,15 @@ environment-variables: # Environment Variables that Control the Build - CMAKE_APPLE_SILICON_PROCESSOR # Since 3.19.2 - CMAKE_BUILD_PARALLEL_LEVEL + - CMAKE_BUILD_TYPE # Since 3.22 + - CMAKE_CONFIGURATION_TYPES # Since 3.22 - CMAKE_CONFIG_TYPE - CMAKE_EXPORT_COMPILE_COMMANDS # Since 3.17 - CMAKE_GENERATOR - CMAKE_GENERATOR_INSTANCE - CMAKE_GENERATOR_PLATFORM - CMAKE_GENERATOR_TOOLSET + - CMAKE_INSTALL_MODE # Since 3.22 - CMAKE__COMPILER_LAUNCHER # Since 3.17 - CMAKE_MSVCIDE_RUN_PATH - CMAKE_NO_VERBOSE @@ -1951,6 +2572,9 @@ scripting-commands: , OS_RELEASE , OS_VERSION , OS_PLATFORM + # Since 3.22 + , DISTRIB_INFO + , DISTRIB_ ] - name: cmake_language @@ -2075,6 +2699,7 @@ scripting-commands: , IN_LIST , DEFINED ] + has-target-name-after-kw: TARGET nested-parentheses?: true - name: else @@ -2460,6 +3085,7 @@ scripting-commands: - name: if named-args: *if + has-target-name-after-kw: TARGET nested-parentheses?: true start-region: if - @@ -2671,6 +3297,7 @@ scripting-commands: - name: while named-args: *if + has-target-name-after-kw: TARGET nested-parentheses?: true start-region: while @@ -2703,6 +3330,7 @@ project-commands: , POST_BUILD ] nested-parentheses?: true + has-target-name-after-kw: TARGET - name: add_custom_target named-args: [ @@ -2721,17 +3349,22 @@ project-commands: , COMMAND_EXPAND_LISTS , SOURCES ] + first-arg-is-target?: true nested-parentheses?: true - name: add_definitions - name: add_dependencies + first-args-are-targets?: true - name: add_executable named-args: [WIN32, MACOSX_BUNDLE, EXCLUDE_FROM_ALL, IMPORTED, GLOBAL, ALIAS] + first-arg-is-target?: true - name: add_library named-args: [STATIC, SHARED, MODULE, OBJECT, EXCLUDE_FROM_ALL, IMPORTED, UNKNOWN, GLOBAL, ALIAS, INTERFACE] + first-arg-is-target?: true + has-target-name-after-kw: ALIAS - name: add_link_options - @@ -2750,6 +3383,7 @@ project-commands: , PARALLEL_LEVEL # Since 3.21 , TARGET ] + has-target-name-after-kw: TARGET - name: create_test_sourcelist named-args: [EXTRA_INCLUDE, FUNCTION] @@ -2760,7 +3394,7 @@ project-commands: - name: enable_language named-args: [OPTIONAL] - special-args: [ + special-args: &langs [ ASM , ASM-ATT , ASM_NASM @@ -2783,6 +3417,7 @@ project-commands: - name: export named-args: [EXPORT, NAMESPACE, FILE, TARGETS, APPEND, EXPORT_LINK_INTERFACE_LIBRARIES, ANDROID_MK] + has-target-names-after-kw: TARGETS - name: fltk_wrap_ui - @@ -2795,6 +3430,7 @@ project-commands: property-args: &get_source_file_property [source-properties] - name: get_target_property + second-arg-is-target?: true property-args: &get_target_property [target-properties] - name: get_test_property @@ -2882,6 +3518,7 @@ project-commands: , SETUID , SETGID ] + has-target-names-after-kw: TARGETS - name: link_directories named-args: [AFTER, BEFORE] @@ -2936,6 +3573,7 @@ project-commands: name: set_target_properties named-args: [PROPERTIES] property-args: *get_target_property + first-args-are-targets?: true # NOTE Multiple target args - name: set_tests_properties named-args: [PROPERTIES] @@ -2946,6 +3584,7 @@ project-commands: - name: target_compile_definitions named-args: &target_compile_definitions [INTERFACE, PUBLIC, PRIVATE] + first-arg-is-target?: true - name: target_compile_features named-args: *target_compile_definitions @@ -3032,9 +3671,11 @@ project-commands: , cuda_std_20 , cuda_std_23 # Since 3.21 ] + first-arg-is-target?: true - name: target_compile_options named-args: &target_compile_options [BEFORE, INTERFACE, PUBLIC, PRIVATE] + first-arg-is-target?: true - name: target_include_directories named-args: [ @@ -3045,23 +3686,29 @@ project-commands: , PUBLIC , PRIVATE ] + first-arg-is-target?: true - # Since 3.13 name: target_link_directories named-args: *target_compile_options + first-arg-is-target?: true - name: target_link_libraries named-args: *target_compile_definitions + first-arg-is-target?: true - name: target_link_options named-args: *target_compile_definitions + first-arg-is-target?: true - # Since 3.16 name: target_precompile_headers named-args: [INTERFACE, PUBLIC, PRIVATE, REUSE_FROM] + first-arg-is-target?: true - name: target_sources named-args: *target_compile_definitions + first-arg-is-target?: true - name: try_compile named-args: [ @@ -3191,3 +3838,1174 @@ ctest-commands: - name: ctest_upload named-args: [FILES, CAPTURE_CMAKE_ERROR, QUIET] + +modules: + # The modules listed here are part of the CMake distribution: + # https://cmake.org/cmake/help/latest/manual/cmake-modules.7.html + utility: + - AndroidTestUtilities + - BundleUtilities + - CheckCCompilerFlag + - CheckCompilerFlag + - CheckCSourceCompiles + - CheckCSourceRuns + - CheckCXXCompilerFlag + - CheckCXXSourceCompiles + - CheckCXXSourceRuns + - CheckCXXSymbolExists + - CheckFortranCompilerFlag + - CheckFortranFunctionExists + - CheckFortranSourceCompiles + - CheckFortranSourceRuns + - CheckFunctionExists + - CheckIncludeFileCXX + - CheckIncludeFile + - CheckIncludeFiles + - CheckIPOSupported + - CheckLanguage + - CheckLibraryExists + - CheckLinkerFlag + - CheckOBJCCompilerFlag + - CheckOBJCSourceCompiles + - CheckOBJCSourceRuns + - CheckOBJCXXCompilerFlag + - CheckOBJCXXSourceCompiles + - CheckOBJCXXSourceRuns + - CheckPIESupported + - CheckPrototypeDefinition + - CheckSourceCompiles + - CheckSourceRuns + - CheckStructHasMember + - CheckSymbolExists + - CheckTypeSize + - CheckVariableExists + - CMakeAddFortranSubdirectory + - CMakeBackwardCompatibilityCXX + - CMakeDependentOption + - CMakeFindDependencyMacro + - CMakeFindFrameworks + # NOTE The commented modules below are not for `include()` + # - CMakeFindPackageMode + # - CMakeGraphVizOptions + - CMakePackageConfigHelpers + - CMakePrintHelpers + - CMakePrintSystemInformation + - CMakePushCheckState + # NOTE The commented module below is not for `include()` + # - CMakeVerifyManifest + - CPack + - CPackComponent + - CPackIFW + - CPackIFWConfigureFile + - CSharpUtilities + - CTest + - CTestCoverageCollectGCOV + - CTestScriptMode + - CTestUseLaunchers + - Dart + - DeployQt4 + - ExternalData + - ExternalProject + - FeatureSummary + - FetchContent + - FindPackageHandleStandardArgs + - FindPackageMessage + - FortranCInterface + - GenerateExportHeader + - GNUInstallDirs + - GoogleTest + - InstallRequiredSystemLibraries + - ProcessorCount + - SelectLibraryConfigurations + # NOTE The commented module below is not for `include()` + # - SquishTestScript + - TestForANSIForScope + - TestForANSIStreamHeaders + - TestForSSTREAM + - TestForSTDNamespace + - UseEcos + - UseJava + - UseSWIG + - UsewxWidgets + + finder: + - FindALSA + - FindArmadillo + - FindASPELL + - FindAVIFile + - FindBacktrace + - FindBISON + - FindBLAS + - FindBoost + - FindBullet + - FindBZip2 + - FindCABLE + - FindCoin3D + - FindCUDAToolkit + - FindCups + - FindCURL + - FindCurses + - FindCVS + - FindCxxTest + - FindCygwin + - FindDart + - FindDCMTK + - FindDevIL + - FindDoxygen + - FindEnvModules + - FindEXPAT + - FindFLEX + - FindFLTK + - FindFLTK2 + - FindFontconfig + - FindFreetype + - FindGCCXML + - FindGDAL + - FindGettext + - FindGIF + - FindGit + - FindGLEW + - FindGLUT + - FindGnuplot + - FindGnuTLS + - FindGSL + - FindGTest + - FindGTK + - FindGTK2 + - FindHDF5 + - FindHg + - FindHSPELL + - FindHTMLHelp + - FindIce + - FindIconv + - FindIcotool + - FindICU + - FindImageMagick + - FindIntl + - FindITK + - FindJasper + - FindJava + - FindJNI + - FindJPEG + - FindKDE3 + - FindKDE4 + - FindLAPACK + - FindLATEX + - FindLibArchive + - FindLibinput + - FindLibLZMA + - FindLibXml2 + - FindLibXslt + - FindLTTngUST + - FindLua + - FindLua50 + - FindLua51 + - FindMatlab + - FindMFC + - FindMotif + - FindMPEG + - FindMPEG2 + - FindMPI + - FindMsys + - FindODBC + - FindOpenACC + - FindOpenAL + - FindOpenCL + - FindOpenGL + - FindOpenMP + - FindOpenSceneGraph + - FindOpenSSL + - FindOpenThreads + - Findosg + - Findosg_functions + - FindosgAnimation + - FindosgDB + - FindosgFX + - FindosgGA + - FindosgIntrospection + - FindosgManipulator + - FindosgParticle + - FindosgPresentation + - FindosgProducer + - FindosgQt + - FindosgShadow + - FindosgSim + - FindosgTerrain + - FindosgText + - FindosgUtil + - FindosgViewer + - FindosgVolume + - FindosgWidget + - FindPatch + - FindPerl + - FindPerlLibs + - FindPHP4 + - FindPhysFS + - FindPike + - FindPkgConfig + - FindPNG + - FindPostgreSQL + - FindProducer + - FindProtobuf + - FindPython + - FindPython2 + - FindPython3 + - FindQt3 + - FindQt4 + - FindQuickTime + - FindRTI + - FindRuby + - FindSDL + - FindSDL_image + - FindSDL_mixer + - FindSDL_net + - FindSDL_sound + - FindSDL_ttf + - FindSelfPackers + - FindSquish + - FindSQLite3 + - FindSubversion + - FindSWIG + - FindTCL + - FindTclsh + - FindTclStub + - FindThreads + - FindTIFF + - FindUnixCommands + - FindVTK + - FindVulkan + - FindWget + - FindWish + - FindwxWidgets + - FindX11 + - FindXalanC + - FindXCTest + - FindXercesC + - FindXMLRPC + - FindZLIB + + deprecated: + # Deprecated Utility Modules + - AddFileDependencies + - CMakeDetermineVSServicePack + - CMakeExpandImportedTargets + - CMakeForceCompiler + - CMakeParseArguments + - Documentation + - MacroAddFileDependencies + - TestCXXAcceptsFlag + - UseJavaClassFilelist + - UseJavaSymlinks + - UsePkgConfig + - Use_wxWindows + - WriteBasicConfigVersionFile + - WriteCompilerDetectionHeader + # Deprecated Find Modules + - FindCUDA + - FindPythonInterp + - FindPythonLibs + - FindQt + - FindwxWindows + # Legacy CPack Modules + - CPackArchive + - CPackBundle + - CPackCygwin + - CPackDeb + - CPackDMG + - CPackFreeBSD + - CPackNSIS + - CPackNuGet + - CPackPackageMaker + - CPackProductBuild + - CPackRPM + - CPackWIX + # ATTENTION The following modules still in the list of the standard modules + # however, the docs claims that they have been deprecated + - GetPrerequisites + - TestBigEndian + +standard-module-commands: + # AndroidTestUtilities + - + name: android_add_test_data + named-args: + - FILES + - FILES_DEST + - LIBS + - LIBS_DEST + - DEVICE_OBJECT_STORE + - DEVICE_TEST_DIR + - NO_LINK_REGEX + # BundleUtilities + - name: fixup_bundle + - name: copy_and_fixup_bundle + - name: verify_app + - name: get_bundle_main_executable + - name: get_dotapp_dir + - name: get_bundle_and_executable + - name: get_bundle_all_executables + - name: get_item_key + - name: get_item_rpaths + - name: clear_bundle_keys + - name: set_bundle_key_values + - name: get_bundle_keys + - name: copy_resolved_item_into_bundle + - name: copy_resolved_framework_into_bundle + - name: fixup_bundle_item + - name: verify_bundle_prerequisites + - name: verify_bundle_symlinks + # CheckCCompilerFlag + - name: check_c_compiler_flag + # CheckCompilerFlag + - name: check_compiler_flag + # CheckCSourceCompiles + - + name: check_c_source_compiles + named-args: &ccsc [FAIL_REGEX] + # CheckCSourceRuns + - name: check_c_source_runs + # CheckCXXCompilerFlag + - name: check_cxx_compiler_flag + # CheckCXXSourceCompiles + - + name: check_cxx_source_compiles + named-args: *ccsc + # CheckCXXSourceRuns + - name: check_cxx_source_runs + # CheckCXXSymbolExists + - name: check_cxx_symbol_exists + # CheckFortranCompilerFlag + - name: check_fortran_compiler_flag + # CheckFortranFunctionExists + - name: check_fortran_function_exists + # CheckFortranSourceCompiles + - + name: check_fortran_source_compiles + named-args: &frse [FAIL_REGEX, SRC_EXT] + # CheckFortranSourceRuns + - + name: check_fortran_source_runs + named-args: &se [SRC_EXT] + # CheckFunctionExists + - name: check_function_exists + # CheckIncludeFileCXX + - name: check_include_file_cxx + # CheckIncludeFile + - name: check_include_file + # CheckIncludeFiles + - + name: check_include_files + named-args: &l [LANGUAGE] + special-args: &ccxx [C, CXX] + # CheckIPOSupported + - + name: check_ipo_supported + named-args: [RESULT, OUTPUT, LANGUAGES] + special-args: &ccxxf [C, CXX, Fortran] + # CheckLanguage + - + name: check_language + special-args: *langs + # CheckLibraryExists + - name: check_library_exists + # CheckLinkerFlag + - name: check_linker_flag + # CheckOBJCCompilerFlag + - name: check_objc_compiler_flag + # CheckOBJCSourceCompiles + - + name: check_objc_source_compiles + named-args: *ccsc + # CheckOBJCSourceRuns + - name: check_objc_source_runs + # CheckOBJCXXCompilerFlag + - name: check_objcxx_compiler_flag + # CheckOBJCXXSourceCompiles + - + name: check_objcxx_source_compiles + named-args: *ccsc + # CheckOBJCXXSourceRuns + - name: check_objcxx_source_runs + # CheckPIESupported + - + name: check_pie_supported + named-args: [OUTPUT_VARIABLE, LANGUAGES] + special-args: *ccxxf + # CheckPrototypeDefinition + - name: check_prototype_definition + # CheckSourceCompiles + - + name: check_source_compiles + named-args: *frse + # CheckSourceRuns + - + name: check_source_runs + named-args: *se + # CheckStructHasMember + - + name: check_struct_has_member + named-args: *l + special-args: *ccxx + # CheckSymbolExists + - name: check_symbol_exists + # CheckTypeSize + - + name: check_type_size + named-args: [BUILTIN_TYPES_ONLY, LANGUAGE] + special-args: *ccxx + # CheckVariableExists + - name: check_variable_exists + # CMakeAddFortranSubdirectory + - + name: cmake_add_fortran_subdirectory + named-args: + - PROJECT + - ARCHIVE_DIR + - RUNTIME_DIR + - LIBRARIES + - LINK_LIBRARIES + - LINK_LIBS + - CMAKE_COMMAND_LINE + - NO_EXTERNAL_INSTALL + # CMakeBackwardCompatibilityCXX + # CMakeDependentOption + - name: cmake_dependent_option + # CMakeFindDependencyMacro + - name: find_dependency + # CMakeFindFrameworks + # CMakeFindPackageMode + # CMakeGraphVizOptions + # CMakePackageConfigHelpers + - + name: configure_package_config_file + named-args: + - INSTALL_DESTINATION + - PATH_VARS + - NO_SET_AND_CHECK_MACRO + - NO_CHECK_REQUIRED_COMPONENTS_MACRO + - INSTALL_PREFIX + - + name: write_basic_package_version_file + named-args: + - VERSION + - COMPATIBILITY + - ARCH_INDEPENDENT + special-args: [AnyNewerVersion, SameMajorVersion, SameMinorVersion, ExactVersion] + # CMakePrintHelpers + - + name: cmake_print_properties + named-args: + - TARGETS + - SOURCES + - DIRECTORIES + - TESTS + - CACHE_ENTRIES + - PROPERTIES + has-target-names-after-kw: TARGETS + # CMakePrintSystemInformation + # CMakePushCheckState + - + name: cmake_push_check_state + named-args: [RESET] + - name: cmake_pop_check_state + - name: cmake_reset_check_state + # CMakeVerifyManifest + # CPack + # CPackComponent + - + name: cpack_add_component + named-args: + - DISPLAY_NAME + - DESCRIPTION + - HIDDEN + - REQUIRED + - DISABLED + - GROUP + - DEPENDS + - INSTALL_TYPES + - DOWNLOADED + - ARCHIVE_FILE + - PLIST + - + name: cpack_add_component_group + named-args: + - DISPLAY_NAME + - DESCRIPTION + - PARENT_GROUP + - EXPANDED + - BOLD_TITLE + - + name: cpack_add_install_type + named-args: [DISPLAY_NAME] + - + name: cpack_configure_downloads + named-args: + - UPLOAD_DIRECTORY + - ALL + - ADD_REMOVE + - NO_ADD_REMOVE + # CPackIFW + - + name: cpack_ifw_configure_component + named-args: + - COMMON + - ESSENTIAL + - VIRTUAL + - FORCED_INSTALLATION + - REQUIRES_ADMIN_RIGHTS] + - NAME + - DISPLAY_NAME + - DESCRIPTION + - UPDATE_TEXT + - VERSION + - RELEASE_DATE + - SCRIPT + - PRIORITY + - SORTING_PRIORITY + - DEPENDS + - DEPENDENCIES + - AUTO_DEPEND_ON + - LICENSES + - DEFAULT + - USER_INTERFACES + - TRANSLATIONS + - REPLACES + - CHECKABLE + - + name: cpack_ifw_configure_component_group + named-args: + - VIRTUAL + - FORCED_INSTALLATION + - REQUIRES_ADMIN_RIGHTS + - NAME + - DISPLAY_NAME + - DESCRIPTION + - UPDATE_TEXT + - VERSION + - RELEASE_DATE + - SCRIPT + - PRIORITY + - SORTING_PRIORITY + - DEPENDS + - DEPENDENCIES + - AUTO_DEPEND_ON + - LICENSES + - DEFAULT + - USER_INTERFACES + - TRANSLATIONS + - REPLACES + - CHECKABLE + - + name: cpack_ifw_add_repository + named-args: + - DISABLED + - URL + - USERNAME + - PASSWORD + - DISPLAY_NAME + - + name: cpack_ifw_update_repository + named-args: + - ADD + - REMOVE + - URL + - REPLACE + - OLD_URL + - NEW_URL + - USERNAME + - PASSWORD + - DISPLAY_NAME + - name: cpack_ifw_add_package_resources + # CPackIFWConfigureFile + - name: cpack_ifw_configure_file + # CSharpUtilities + - name: csharp_set_windows_forms_properties + - name: csharp_set_designer_cs_properties + - name: csharp_set_xaml_cs_properties + - name: csharp_get_filename_keys + - name: csharp_get_filename_key_base + - name: csharp_get_dependentupon_name + # CTest + # CTestCoverageCollectGCOV + - + name: ctest_coverage_collect_gcov + named-args: + - TARBALL + - TARBALL_COMPRESSION + - SOURCE + - BUILD + - GCOV_COMMAND + - GCOV_OPTIONS + - GLOB + - DELETE + - QUIET + # CTestScriptMode + # CTestUseLaunchers + # Dart + # DeployQt4 + - name: write_qt4_conf + - name: resolve_qt4_paths + - name: fixup_qt4_executable + - name: install_qt4_plugin_path + - name: install_qt4_plugin + - name: install_qt4_executable + # ExternalData + - name: ExternalData_Expand_Arguments + - name: ExternalData_Add_Test + - + name: ExternalData_Add_Target + named-args: [SHOW_PROGRESS] + # ExternalProject + - + name: ExternalProject_Add + named-args: + - PREFIX + - TMP_DIR + - STAMP_DIR + - LOG_DIR + - DOWNLOAD_DIR + - SOURCE_DIR + - BINARY_DIR + - INSTALL_DIR + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - CONFIGURE_COMMAND + - CMAKE_COMMAND + - CMAKE_GENERATOR + - CMAKE_GENERATOR_PLATFORM + - CMAKE_GENERATOR_TOOLSET + - CMAKE_GENERATOR_INSTANCE + - CMAKE_ARGS + - CMAKE_CACHE_ARGS + - CMAKE_CACHE_DEFAULT_ARGS + - SOURCE_SUBDIR + - CONFIGURE_HANDLED_BY_BUILD + - BUILD_COMMAND + - BUILD_IN_SOURCE + - BUILD_ALWAYS + - BUILD_BYPRODUCTS + - INSTALL_COMMAND + - TEST_COMMAND + - TEST_BEFORE_INSTALL + - TEST_AFTER_INSTALL + - TEST_EXCLUDE_FROM_MAIN + - LOG_DOWNLOAD + - LOG_UPDATE + - LOG_PATCH + - LOG_CONFIGURE + - LOG_BUILD + - LOG_INSTALL + - LOG_TEST + - LOG_MERGED_STDOUTERR + - LOG_OUTPUT_ON_FAILURE + - USES_TERMINAL_DOWNLOAD + - USES_TERMINAL_UPDATE + - USES_TERMINAL_CONFIGURE + - USES_TERMINAL_BUILD + - USES_TERMINAL_INSTALL + - USES_TERMINAL_TEST + - DEPENDS + - EXCLUDE_FROM_ALL + - STEP_TARGETS + - INDEPENDENT_STEP_TARGETS + - LIST_SEPARATOR + - COMMAND + special-args: [IGNORED, OPTIONAL, REQUIRED, CHECKOUT, REBASE, REBASE_CHECKOUT] + property-args: *get_target_property + - name: ExternalProject_Get_Property + - + name: ExternalProject_Add_Step + named-args: + - COMMAND + - COMMENT + - DEPENDEES + - DEPENDERS + - DEPENDS + - INDEPENDENT + - BYPRODUCTS + - ALWAYS + - EXCLUDE_FROM_MAIN + - WORKING_DIRECTORY + - LOG + - USES_TERMINAL + - + name: ExternalProject_Add_StepTargets + named-args: + - NO_DEPENDS + - name: ExternalProject_Add_StepDependencies + # FeatureSummary + - + name: feature_summary + named-args: + - FILENAME + - APPEND + - VAR + - INCLUDE_QUIET_PACKAGES + - FATAL_ON_MISSING_REQUIRED_PACKAGES + - DESCRIPTION + - DEFAULT_DESCRIPTION + - QUIET_ON_EMPTY + - WHAT + - ALL + - PACKAGES_FOUND + - PACKAGES_NOT_FOUND + - ENABLED_FEATURES + - DISABLED_FEATURES + - + name: set_package_properties + named-args: + - PROPERTIES + - URL + - DESCRIPTION + - TYPE + - RUNTIME + - OPTIONAL + - RECOMMENDED + - REQUIRED + - PURPOSE + - name: add_feature_info + - name: set_package_info + - name: set_feature_info + - name: print_enabled_features + - name: print_disabled_features + # FetchContent + - + name: FetchContent_Declare + named-args: + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - SOURCE_SUBDIR + - + name: FetchContent_Populate + named-args: + - QUIET + - SUBBUILD_DIR + - SOURCE_DIR + - BINARY_DIR + - DOWNLOAD_COMMAND + - URL + - URL_HASH + - URL_MD5 + - DOWNLOAD_NAME + - DOWNLOAD_NO_EXTRACT + - DOWNLOAD_NO_PROGRESS + - TIMEOUT + - INACTIVITY_TIMEOUT + - HTTP_USERNAME + - HTTP_PASSWORD + - HTTP_HEADER + - TLS_VERIFY + - TLS_CAINFO + - NETRC + - NETRC_FILE + - GIT_REPOSITORY + - GIT_TAG + - GIT_REMOTE_NAME + - GIT_SUBMODULES + - GIT_SUBMODULES_RECURSE + - GIT_SHALLOW + - GIT_PROGRESS + - GIT_CONFIG + - GIT_REMOTE_UPDATE_STRATEGY + - SVN_REPOSITORY + - SVN_REVISION + - SVN_USERNAME + - SVN_PASSWORD + - SVN_TRUST_CERT + - HG_REPOSITORY + - HG_TAG + - CVS_REPOSITORY + - CVS_MODULE + - CVS_TAG + - UPDATE_COMMAND + - UPDATE_DISCONNECTED + - PATCH_COMMAND + - SOURCE_SUBDIR + - + name: FetchContent_GetProperties + named-args: + - SOURCE_DIR + - BINARY_DIR + - POPULATED + - name: FetchContent_MakeAvailable + # FindPackageHandleStandardArgs + - + name: find_package_handle_standard_args + named-args: + - DEFAULT_MSG + - FOUND_VAR + - REQUIRED_VARS + - VERSION_VAR + - HANDLE_VERSION_RANGE + - HANDLE_COMPONENTS + - CONFIG_MODE + - NAME_MISMATCHED + - REASON_FAILURE_MESSAGE + - FAIL_MESSAGE + - + name: find_package_check_version + named-args: + - HANDLE_VERSION_RANGE + - RESULT_MESSAGE_VARIABLE + # FindPackageMessage + - name: find_package_message + # FortranCInterface + - + name: FortranCInterface_HEADER + named-args: + - MACRO_NAMESPACE + - SYMBOL_NAMESPACE + - SYMBOLS + - + name: FortranCInterface_VERIFY + named-args: [CXX, QUIET] + # GenerateExportHeader + - + name: generate_export_header + named-args: + - BASE_NAME + - EXPORT_MACRO_NAME + - EXPORT_FILE_NAME + - DEPRECATED_MACRO_NAME + - NO_EXPORT_MACRO_NAME + - INCLUDE_GUARD_NAME + - STATIC_DEFINE + - NO_DEPRECATED_MACRO_NAME + - DEFINE_NO_DEPRECATED + - PREFIX_NAME + - CUSTOM_CONTENT_FROM_VARIABLE + first-arg-is-target?: true + # GetPrerequisites (NOTE The module has functions but has been deprecated) + # GNUInstallDirs + - name: GNUInstallDirs_get_absolute_install_dir + # GoogleTest + - + name: gtest_add_tests + named-args: + - TARGET + - SOURCES + - EXTRA_ARGS + - WORKING_DIRECTORY + - TEST_PREFIX + - TEST_SUFFIX + - SKIP_DEPENDENCY + - TEST_LIST + has-target-name-after-kw: TARGET + - + name: gtest_discover_tests # Since 3.10 + named-args: + - EXTRA_ARGS + - WORKING_DIRECTORY + - TEST_PREFIX + - TEST_SUFFIX + - TEST_FILTER # Since 3.22 + - NO_PRETTY_TYPES + - NO_PRETTY_VALUES + - PROPERTIES + - TEST_LIST + - DISCOVERY_TIMEOUT + - XML_OUTPUT_DIR + - DISCOVERY_MODE + special-args: [POST_BUILD, PRE_TEST] + first-arg-is-target?: true + # InstallRequiredSystemLibraries + # ProcessorCount + - name: processorcount + # SelectLibraryConfigurations + - name: select_library_configurations + # SquishTestScript + # TestBigEndian + - name: test_big_endian + # TestForANSIForScope + # TestForANSIStreamHeaders + # TestForSSTREAM + # TestForSTDNamespace + # UseEcos + - name: ecos_add_include_directories + - name: ecos_add_executable + - name: ecos_add_target_lib + - name: ecos_adjust_directory + - name: ecos_use_arm_elf_tools + - name: ecos_use_i386_elf_tools + - name: ecos_use_ppc_eabi_tools + # UseJava + - + name: add_jar + named-args: + - SOURCES + - RESOURCES + - NAMESPACE + - INCLUDE_JARS + - ENTRY_POINT + - VERSION + - MANIFEST + - OUTPUT_NAME + - OUTPUT_DIR + - GENERATE_NATIVE_HEADERS + - DESTINATION + - INSTALL + - BUILD + first-arg-is-target?: true + - + name: install_jar + named-args: &dc [DESTINATION, COMPONENT] + first-arg-is-target?: true + - + name: install_jni_symlink + named-args: *dc + first-arg-is-target?: true + - + name: create_javah + named-args: + - TARGET + - GENERATED_FILES + - CLASSES + - CLASSPATH + - DEPENDS + - OUTPUT_NAME + - OUTPUT_DIR + has-target-name-after-kw: TARGET + - + name: install_jar_exports + named-args: + - TARGETS + - NAMESPACE + - FILE + - DESTINATION + - COMPONENT + has-target-names-after-kw: TARGETS + - + name: export_jars + named-args: + - TARGETS + - NAMESPACE + - FILE + has-target-names-after-kw: TARGETS + - + name: find_jar + named-args: + - NAMES + - PATHS + - ENV + - VERSIONS + - DOC + - + name: create_javadoc + named-args: + - PACKAGES + - FILES + - SOURCEPATH + - CLASSPATH + - INSTALLPATH + - DOCTITLE + - WINDOWTITLE + - AUTHOR + - USE + - VERSION + # UseSWIG + - + name: swig_add_library + named-args: + - TYPE + - SHARED + - MODULE + - STATIC + - USE_BUILD_SHARED_LIBS + - LANGUAGE + - NO_PROXY + - OUTPUT_DIR + - OUTFILE_DIR + - SOURCES + - name: swig_link_libraries + # UsewxWidgets + # NOTE Some standard finder modules also provide commands + # FindSquish + - + name: squish_add_test + named-args: + - AUT + - SUITE + - TEST + - SETTINGSGROUP + - PRE_COMMAND + - POST_COMMAND + # FindBISON + - + name: bison_target + named-args: + - COMPILE_FLAGS + - DEFINES_FILE + - VERBOSE + - REPORT_FILE + # FindCxxTest + - name: cxxtest_add_test + # FindDoxygen + - + name: doxygen_add_docs + named-args: [ALL, USE_STAMP_FILE, WORKING_DIRECTORY, COMMENT] + # FindEnvModules + - + name: env_module + named-args: [COMMAND, OUTPUT_VARIABLE, RESULT_VARIABLE] + - + name: env_module_swap + named-args: [OUTPUT_VARIABLE, RESULT_VARIABLE] + - name: env_module_list + - name: env_module_avail + # FindFLEX + - + name: flex_target + named-args: + - COMPILE_FLAGS + - DEFINES_FILE + - name: add_flex_bison_dependency + # FindGettext + - + name: gettext_create_translations + named-args: [ALL] + - + name: gettext_process_pot_file + named-args: [ALL, INSTALL_DESTINATION, LANGUAGES] + - + name: gettext_process_po_files + named-args: [ALL, INSTALL_DESTINATION, PO_FILES] + # FindHg + - name: hg_wc_info + # FindMatlab + - name: matlab_get_version_from_release_name + - name: matlab_get_release_name_from_version + - name: matlab_extract_all_installed_versions_from_registry + - name: matlab_get_all_valid_matlab_roots_from_registry + - name: matlab_get_mex_suffix + - name: matlab_get_version_from_matlab_run + - + name: matlab_add_unit_test + named-args: + - NAME + - UNITTEST_FILE + - CUSTOM_TEST_COMMAND + - UNITTEST_PRECOMMAND + - TIMEOUT + - ADDITIONAL_PATH + - MATLAB_ADDITIONAL_STARTUP_OPTIONS + - TEST_ARGS + - NO_UNITTEST_FRAMEWORK + - + name: matlab_add_mex + named-args: + - NAME + - EXECUTABLE + - MODULE + - SHARED + - SRC + - OUTPUT_NAME + - DOCUMENTATION + - LINK_TO + - EXCLUDE_FROM_ALL + special-args: [R2017b, R2018a] + # FindPkgConfig + - + name: pkg_check_modules + named-args: &pkgcm + - REQUIRED + - QUIET + - NO_CMAKE_PATH + - NO_CMAKE_ENVIRONMENT_PATH + - IMPORTED_TARGET + - GLOBAL + - + name: pkg_search_module + named-args: *pkgcm + - + name: pkg_get_variable + # FindProtobuf + - + name: protobuf_generate_cpp + named-args: [DESCRIPTORS, EXPORT_MACRO] + - + name: protobuf_generate_python + # FindPython + - + name: Python_add_library + named-args: [STATIC, SHARED, MODULE, WITH_SOABI] + # FindSubversion + - + name: Subversion_WC_INFO + named-args: [IGNORE_SVN_FAILURE] + - + name: Subversion_WC_LOG + # FindXCTest + - name: xctest_add_bundle + - name: xctest_add_test diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py index 24b1eb0d7cc..dfe77e4627e 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/generate-cmake-syntax.py @@ -57,7 +57,7 @@ def try_transform_placeholder_string_to_regex(name): if 'ARGV' in m: return 'ARGV[0-9]+' - return '&id_re;'.join(m) if 1 < len(m) else name + return '&var_ref_re;'.join(m) if 1 < len(m) else name def try_placeholders_to_regex(names): @@ -109,6 +109,26 @@ def transform_command(cmd): cmd['nested_parentheses'] = cmd['nested-parentheses?'] if 'nested-parentheses?' in cmd else False + if 'first-arg-is-target?' in cmd: + cmd['first_arg_is_target'] = cmd['first-arg-is-target?'] + can_be_nulary = False + + if 'first-args-are-targets?' in cmd: + cmd['first_args_are_targets'] = cmd['first-args-are-targets?'] + can_be_nulary = False + + if 'has-target-name-after-kw' in cmd: + cmd['has_target_name_after_kw'] = cmd['has-target-name-after-kw'] + can_be_nulary = False + + if 'has-target-names-after-kw' in cmd: + cmd['has_target_names_after_kw'] = cmd['has-target-names-after-kw'] + can_be_nulary = False + + if 'second-arg-is-target?' in cmd: + cmd['second_arg_is_target'] = cmd['second-arg-is-target?'] + can_be_nulary = False + if 'nulary?' in cmd and cmd['nulary?'] and not can_be_nulary: raise RuntimeError('Command `{}` w/ args declared nulary!?'.format(cmd['name'])) @@ -124,8 +144,7 @@ def transform_command(cmd): #BEGIN Jinja filters def cmd_is_nulary(cmd): - assert not ('named-args' in cmd or 'special-args' in cmd or 'property-args' in cmd) - return 'nulary?' in cmd and cmd['nulary?'] + return cmd.setdefault('nulary?', False) #END Jinja filters @@ -134,7 +153,7 @@ def cmd_is_nulary(cmd): @click.argument('input_yaml', type=click.File('r')) @click.argument('template', type=click.File('r'), default='./cmake.xml.tpl') def cli(input_yaml, template): - data = yaml.load(input_yaml) + data = yaml.load(input_yaml, Loader=yaml.BaseLoader) # Partition `variables` and `environment-variables` lists into "pure" (key)words and regexes to match for var_key in _VAR_KIND_LIST: @@ -164,8 +183,16 @@ def cli(input_yaml, template): data['commands'] = list( map( transform_command - , data['scripting-commands'] + data['project-commands'] + data['ctest-commands']) + , data['scripting-commands'] + data['project-commands'] + data['ctest-commands'] + ) ) + data['standard_module_commands'] = list( + map( + transform_command + , data['standard-module-commands'] + ) + ) + del data['standard-module-commands'] # Fix node names to be accessible from Jinja template data['generator_expressions'] = data['generator-expressions'] diff --git a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl index 58cc80f960b..b9944a2bd04 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl +++ b/src/libs/3rdparty/syntax-highlighting/data/generators/spdx-comments.xml.tpl @@ -1,7 +1,12 @@ + - - - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd index fa510e0d147..fdea0dd7521 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd +++ b/src/libs/3rdparty/syntax-highlighting/data/schema/language.xsd @@ -130,8 +130,8 @@ extensions: A file glob or pattern to decide for which documents to use this syntax description style: The style that this highlighter provides. It is used through required-syntax-style by the indenters. [optional] mimetype: A list of mimetypes to decide for which documents to use this syntax description [optional] - version: Version number of this syntax description [optional] - kateversion: Kate version required for using this file [optional] + version: Version number of this syntax description + kateversion: Kate version required for using this file casesensitive: Whether text is matched case sensitive. [boolean, optional, default=true] FIXME: This is not implemented yet priority: Priority of this language, if more than one are usable for the file [optional] author: Name of author of this hl file [optional] diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml index c7b21cb2a01..72e200cce2d 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/bash.xml @@ -39,7 +39,7 @@ ]> - + arch awk + b2sum + base32 + base64 bash bunzip2 bzcat @@ -147,11 +150,15 @@ bzmore cat chattr + chcon chgrp chmod chown chvt + cksum cp + crontab + csplit date dd deallocvt @@ -165,9 +172,11 @@ dumpkeys ed egrep + expand false fgconsole fgrep + fold fuser gawk getkeycodes @@ -178,7 +187,9 @@ gunzip gzexe gzip + hostid hostname + iconv igawk install kbd_mode @@ -206,6 +217,7 @@ lzmainfo lzmore mapscrn + md5sum mesg mkdir mkfifo @@ -217,20 +229,29 @@ nano netstat nisdomainname + nproc nroff + numfmt openvt + paste + pathchk pgawk pidof ping + pinky + printenv ps pstree + ptx rbash readlink + realpath red resizecons rm rmdir run-parts + runcon sash sed setfont @@ -239,22 +260,33 @@ setmetamode setserial sh + sha1sum + sha224sum + sha256sum + sha384sum + sha512sum showkey shred + shuf sleep ssed stat + stdbuf stty su sync tar tempfile + timeout touch + tput troff true truncate + tty umount uname + unexpand unicode_start unicode_stop unlink @@ -263,6 +295,7 @@ utmpdump uuidgen vdir + vi wall wc xz @@ -336,6 +369,7 @@ gc gcc clang + clang++ valgrind xdg-open cmake @@ -464,6 +498,19 @@ + + + + + + + + + + + + + @@ -1104,6 +1151,7 @@ + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml index d8676a250db..e94885b856f 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/cmake.xml @@ -1,7 +1,10 @@ + + + + ]> - + + - + - + + - + + - + + - + + - + + - + + - + @@ -3102,154 +4678,175 @@ + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + - + + - + + - + + - + + - + + + - + + - + + - + + - + + - + @@ -3257,9 +4854,10 @@ + - + @@ -3267,17 +4865,19 @@ + - + + - + @@ -3294,101 +4894,116 @@ + - + + - + + - + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + @@ -3405,9 +5020,10 @@ + - + @@ -3424,186 +5040,239 @@ + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + - + + + + + + + + + + - + - + + - + - + + - - + + + + + + - + + + + + + + + + + - + - + + + + + + + + + + - + + + - + + - + + - + - + + - + + - + + + - + + - + @@ -3620,40 +5289,55 @@ + - + + - + + - + + + + + + + + + + + + - + + - + @@ -3661,122 +5345,159 @@ + - + + - + + - + + - + + - + + - + + + + + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + - + + + + + + + + + + + + - + @@ -3784,268 +5505,1824 @@ + - + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + - + + + + + + + + + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - - - - - - - - + - + - + - + - - + + - + - + @@ -4069,6 +7346,15 @@ + + + + + + + + + @@ -4101,12 +7387,12 @@ - - + + - + @@ -4170,9 +7456,12 @@ + + + @@ -4191,8 +7480,10 @@ - + + + @@ -4200,7 +7491,7 @@ - + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml index f03587977a4..b850cca6733 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/markdown.xml @@ -90,7 +90,7 @@ ]> - + @@ -149,32 +149,42 @@ - - - - - - - + + + + + + - + - + - + - + - + + + + + + + + + + + + @@ -320,6 +330,7 @@ + @@ -404,6 +415,10 @@ + + + + diff --git a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml index e64399098c3..7d893119279 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml +++ b/src/libs/3rdparty/syntax-highlighting/data/syntax/spdx-comments.xml @@ -1,7 +1,12 @@ + - 0BSD - AAL - ADSL - AFL-1.1 - AFL-1.2 - AFL-2.0 - AFL-2.1 - AFL-3.0 - AGPL-1.0-only - AGPL-1.0-or-later - AGPL-3.0-only - AGPL-3.0-or-later - AMDPLPA - AML - AMPAS - ANTLR-PD - ANTLR-PD-fallback - APAFML - APL-1.0 - APSL-1.0 - APSL-1.1 - APSL-1.2 - APSL-2.0 - Abstyles - Adobe-2006 - Adobe-Glyph - Afmparse - Aladdin - Apache-1.0 - Apache-1.1 - Apache-2.0 - Artistic-1.0 - Artistic-1.0-Perl - Artistic-1.0-cl8 - Artistic-2.0 - BSD-1-Clause - BSD-2-Clause - BSD-2-Clause-Patent - BSD-2-Clause-Views - BSD-3-Clause - BSD-3-Clause-Attribution - BSD-3-Clause-Clear - BSD-3-Clause-LBNL - BSD-3-Clause-No-Nuclear-License - BSD-3-Clause-No-Nuclear-License-2014 - BSD-3-Clause-No-Nuclear-Warranty - BSD-3-Clause-Open-MPI - BSD-4-Clause - BSD-4-Clause-UC - BSD-Protection - BSD-Source-Code - BSL-1.0 - BUSL-1.1 - Bahyph - Barr - Beerware - BitTorrent-1.0 - BitTorrent-1.1 - BlueOak-1.0.0 - Borceux - CAL-1.0 - CAL-1.0-Combined-Work-Exception - CATOSL-1.1 - CC-BY-1.0 - CC-BY-2.0 - CC-BY-2.5 - CC-BY-3.0 - CC-BY-3.0-AT - CC-BY-3.0-US - CC-BY-4.0 - CC-BY-NC-1.0 - CC-BY-NC-2.0 - CC-BY-NC-2.5 - CC-BY-NC-3.0 - CC-BY-NC-4.0 - CC-BY-NC-ND-1.0 - CC-BY-NC-ND-2.0 - CC-BY-NC-ND-2.5 - CC-BY-NC-ND-3.0 - CC-BY-NC-ND-3.0-IGO - CC-BY-NC-ND-4.0 - CC-BY-NC-SA-1.0 - CC-BY-NC-SA-2.0 - CC-BY-NC-SA-2.5 - CC-BY-NC-SA-3.0 - CC-BY-NC-SA-4.0 - CC-BY-ND-1.0 - CC-BY-ND-2.0 - CC-BY-ND-2.5 - CC-BY-ND-3.0 - CC-BY-ND-4.0 - CC-BY-SA-1.0 - CC-BY-SA-2.0 - CC-BY-SA-2.0-UK - CC-BY-SA-2.5 - CC-BY-SA-3.0 - CC-BY-SA-3.0-AT - CC-BY-SA-4.0 - CC-PDDC - CC0-1.0 - CDDL-1.0 - CDDL-1.1 - CDLA-Permissive-1.0 - CDLA-Sharing-1.0 - CECILL-1.0 - CECILL-1.1 - CECILL-2.0 - CECILL-2.1 - CECILL-B - CECILL-C - CERN-OHL-1.1 - CERN-OHL-1.2 - CERN-OHL-P-2.0 - CERN-OHL-S-2.0 - CERN-OHL-W-2.0 - CNRI-Jython - CNRI-Python - CNRI-Python-GPL-Compatible - CPAL-1.0 - CPL-1.0 - CPOL-1.02 - CUA-OPL-1.0 - Caldera - ClArtistic - Condor-1.1 - Crossword - CrystalStacker - Cube - D-FSL-1.0 - DOC - DSDP - Dotseqn - ECL-1.0 - ECL-2.0 - EFL-1.0 - EFL-2.0 - EPICS - EPL-1.0 - EPL-2.0 - EUDatagrid - EUPL-1.0 - EUPL-1.1 - EUPL-1.2 - Entessa - ErlPL-1.1 - Eurosym - FSFAP - FSFUL - FSFULLR - FTL - Fair - Frameworx-1.0 - FreeImage - GFDL-1.1-invariants-only - GFDL-1.1-invariants-or-later - GFDL-1.1-no-invariants-only - GFDL-1.1-no-invariants-or-later - GFDL-1.1-only - GFDL-1.1-or-later - GFDL-1.2-invariants-only - GFDL-1.2-invariants-or-later - GFDL-1.2-no-invariants-only - GFDL-1.2-no-invariants-or-later - GFDL-1.2-only - GFDL-1.2-or-later - GFDL-1.3-invariants-only - GFDL-1.3-invariants-or-later - GFDL-1.3-no-invariants-only - GFDL-1.3-no-invariants-or-later - GFDL-1.3-only - GFDL-1.3-or-later - GL2PS - GLWTPL - GPL-1.0-only - GPL-1.0-or-later - GPL-2.0-only - GPL-2.0-or-later - GPL-3.0-only - GPL-3.0-or-later - Giftware - Glide - Glulxe - HPND - HPND-sell-variant - HTMLTIDY - HaskellReport - Hippocratic-2.1 - IBM-pibs - ICU - IJG - IPA - IPL-1.0 - ISC - ImageMagick - Imlib2 - Info-ZIP - Intel - Intel-ACPI - Interbase-1.0 - JPNIC - JSON - JasPer-2.0 - LAL-1.2 - LAL-1.3 - LGPL-2.0-only - LGPL-2.0-or-later - LGPL-2.1-only - LGPL-2.1-or-later - LGPL-3.0-only - LGPL-3.0-or-later - LGPLLR - LPL-1.0 - LPL-1.02 - LPPL-1.0 - LPPL-1.1 - LPPL-1.2 - LPPL-1.3a - LPPL-1.3c - Latex2e - Leptonica - LiLiQ-P-1.1 - LiLiQ-R-1.1 - LiLiQ-Rplus-1.1 - Libpng - Linux-OpenIB - MIT - MIT-0 - MIT-CMU - MIT-advertising - MIT-enna - MIT-feh - MIT-open-group - MITNFA - MPL-1.0 - MPL-1.1 - MPL-2.0 - MPL-2.0-no-copyleft-exception - MS-PL - MS-RL - MTLL - MakeIndex - MirOS - Motosoto - MulanPSL-1.0 - MulanPSL-2.0 - Multics - Mup - NASA-1.3 - NBPL-1.0 - NCGL-UK-2.0 - NCSA - NGPL - NIST-PD - NIST-PD-fallback - NLOD-1.0 - NLPL - NOSL - NPL-1.0 - NPL-1.1 - NPOSL-3.0 - NRL - NTP - NTP-0 - Naumen - Net-SNMP - NetCDF - Newsletr - Nokia - Noweb - O-UDA-1.0 - OCCT-PL - OCLC-2.0 - ODC-By-1.0 - ODbL-1.0 - OFL-1.0 - OFL-1.0-RFN - OFL-1.0-no-RFN - OFL-1.1 - OFL-1.1-RFN - OFL-1.1-no-RFN - OGC-1.0 - OGL-Canada-2.0 - OGL-UK-1.0 - OGL-UK-2.0 - OGL-UK-3.0 - OGTSL - OLDAP-1.1 - OLDAP-1.2 - OLDAP-1.3 - OLDAP-1.4 - OLDAP-2.0 - OLDAP-2.0.1 - OLDAP-2.1 - OLDAP-2.2 - OLDAP-2.2.1 - OLDAP-2.2.2 - OLDAP-2.3 - OLDAP-2.4 - OLDAP-2.5 - OLDAP-2.6 - OLDAP-2.7 - OLDAP-2.8 - OML - OPL-1.0 - OSET-PL-2.1 - OSL-1.0 - OSL-1.1 - OSL-2.0 - OSL-2.1 - OSL-3.0 - OpenSSL - PDDL-1.0 - PHP-3.0 - PHP-3.01 - PSF-2.0 - Parity-6.0.0 - Parity-7.0.0 - Plexus - PolyForm-Noncommercial-1.0.0 - PolyForm-Small-Business-1.0.0 - PostgreSQL - Python-2.0 - QPL-1.0 - Qhull - RHeCos-1.1 - RPL-1.1 - RPL-1.5 - RPSL-1.0 - RSA-MD - RSCPL - Rdisc - Ruby - SAX-PD - SCEA - SGI-B-1.0 - SGI-B-1.1 - SGI-B-2.0 - SHL-0.5 - SHL-0.51 - SISSL - SISSL-1.2 - SMLNJ - SMPPL - SNIA - SPL-1.0 - SSH-OpenSSH - SSH-short - SSPL-1.0 - SWL - Saxpath - Sendmail - Sendmail-8.23 - SimPL-2.0 - Sleepycat - Spencer-86 - Spencer-94 - Spencer-99 - SugarCRM-1.1.3 - TAPR-OHL-1.0 - TCL - TCP-wrappers - TMate - TORQUE-1.1 - TOSL - TU-Berlin-1.0 - TU-Berlin-2.0 - UCL-1.0 - UPL-1.0 - Unicode-DFS-2015 - Unicode-DFS-2016 - Unicode-TOU - Unlicense - VOSTROM - VSL-1.0 - Vim - W3C - W3C-19980720 - W3C-20150513 - WTFPL - Watcom-1.0 - Wsuipa - X11 - XFree86-1.1 - XSkat - Xerox - Xnet - YPL-1.0 - YPL-1.1 - ZPL-1.1 - ZPL-2.0 - ZPL-2.1 - Zed - Zend-2.0 - Zimbra-1.3 - Zimbra-1.4 - Zlib - blessing - bzip2-1.0.5 bzip2-1.0.6 - copyleft-next-0.3.0 - copyleft-next-0.3.1 - curl - diffmark - dvipdfm + Intel-ACPI + XSkat + CC-BY-NC-SA-2.0 + Plexus + Giftware + BitTorrent-1.0 + APSL-1.1 + UPL-1.0 + Caldera + Zend-2.0 + CUA-OPL-1.0 + JPNIC + SAX-PD + CC-BY-ND-2.5 eGenix - etalab-2.0 - gSOAP-1.3b + LGPLLR + OLDAP-2.2.2 + CC-BY-ND-3.0-DE + IPA + NCSA + W3C + Adobe-2006 + Net-SNMP + CC-BY-SA-4.0 + YPL-1.0 + MITNFA + PHP-3.01 + BSD-Source-Code + CC-BY-SA-2.5 + Motosoto + OSL-1.1 + NGPL + CC-BY-2.5-AU + Unicode-TOU + BSD-3-Clause-No-Nuclear-License + OPUBL-1.0 + CC-BY-NC-SA-2.0-UK + NLOD-2.0 gnuplot + EPICS + Info-ZIP + OLDAP-2.0 + CERN-OHL-P-2.0 + BSD-3-Clause-No-Nuclear-Warranty + AML + MulanPSL-1.0 + Multics + VSL-1.0 + RSA-MD + CC-PDDC + CC-BY-SA-2.1-JP + LPPL-1.2 + Spencer-94 + OLDAP-1.2 + O-UDA-1.0 + OLDAP-2.7 + Glulxe iMatix - libpng-2.0 - libselinux-1.0 + TAPR-OHL-1.0 + NBPL-1.0 + LiLiQ-R-1.1 + Noweb + CC0-1.0 + BSD-Protection + CC-BY-NC-2.5 + Zlib + GFDL-1.3-invariants-or-later + CC-BY-3.0-AT + LPPL-1.3c + EPL-1.0 + GFDL-1.1-invariants-or-later + ANTLR-PD-fallback + OLDAP-2.4 + OLDAP-2.3 + ZPL-2.1 + Apache-2.0 + SGI-B-2.0 + Hippocratic-2.1 + CC-BY-SA-3.0-DE + CC-BY-NC-SA-1.0 + LGPL-2.1-or-later + CC-BY-3.0-US + TCP-wrappers + GFDL-1.2-invariants-or-later + Eurosym + LPPL-1.0 + SGI-B-1.0 + APL-1.0 libtiff - mpich2 - psfrag - psutils - xinetd + AFL-2.1 + CC-BY-NC-1.0 + GD + AFL-1.1 + CC-BY-NC-ND-3.0-IGO + Unicode-DFS-2015 + GFDL-1.2-only + MPL-1.1 + GPL-2.0-only + CC-BY-NC-4.0 + FreeImage + SHL-0.51 + CNRI-Jython + ZPL-1.1 + Afmparse + OLDAP-2.1 + Rdisc + Imlib2 + BSD-4-Clause-Shortened + Sendmail + CC-BY-2.5 + AAL + MPL-2.0-no-copyleft-exception + CC-BY-NC-ND-2.5 + CC-BY-3.0-NL + LPL-1.02 + ECL-1.0 + OFL-1.0-no-RFN + CC-BY-NC-SA-3.0-DE + CC-BY-SA-3.0 + NTP + MPL-2.0 + APSL-1.2 + GFDL-1.2-no-invariants-only + Artistic-2.0 + RSCPL + Sleepycat xpp + CDLA-Sharing-1.0 + ClArtistic + AGPL-1.0-only + CC-BY-3.0-DE + AFL-2.0 + Intel + GFDL-1.1-no-invariants-or-later + APAFML + SISSL + Naumen + HTMLTIDY + OLDAP-2.8 + blessing + CC-BY-ND-2.0 + OGTSL + LGPL-2.0-or-later + Parity-7.0.0 + CC-BY-ND-1.0 + dvipdfm + CNRI-Python + BSD-4-Clause-UC + NLOD-1.0 + MS-RL + CC-BY-NC-SA-4.0 + HaskellReport + CC-BY-1.0 + UCL-1.0 + Mup + SMPPL + PHP-3.0 + GL2PS + CrystalStacker + W3C-20150513 + NIST-PD-fallback + OGL-UK-1.0 + CPL-1.0 + LGPL-2.1-only + ZPL-2.0 + Frameworx-1.0 + AGPL-3.0-only + DRL-1.0 + EFL-2.0 + Spencer-99 + CAL-1.0-Combined-Work-Exception + GFDL-1.1-invariants-only + TCL + SHL-0.5 + OFL-1.0-RFN + CERN-OHL-W-2.0 + Glide + mpich2 + psutils + SPL-1.0 + Apache-1.1 + CC-BY-ND-4.0 + FreeBSD-DOC + SCEA + Latex2e + Artistic-1.0-cl8 + SGI-B-1.1 + NRL + SWL + Zed + CERN-OHL-1.1 + RHeCos-1.1 + JasPer-2.0 + SSPL-1.0 + OLDAP-1.4 + libpng-2.0 + CNRI-Python-GPL-Compatible + Aladdin + CECILL-1.0 + Ruby + NPL-1.1 + ImageMagick + Cube + GFDL-1.1-only + CC-BY-2.0 + AFL-1.2 + CC-BY-SA-2.0 + CECILL-2.0 + MIT-advertising + CC-BY-NC-SA-2.5 + Artistic-1.0 + OSL-3.0 + X11 + Bahyph + OLDAP-2.0.1 + EUDatagrid + MTLL + GFDL-1.2-invariants-only + GFDL-1.3-no-invariants-or-later + curl + LAL-1.3 + DSDP + CERN-OHL-1.2 + TOSL + CC-BY-3.0 + Qhull + GFDL-1.3-no-invariants-only + TORQUE-1.1 + MS-PL + Apache-1.0 + copyleft-next-0.3.1 + GFDL-1.2-or-later + MulanPSL-2.0 + FSFAP + Xerox + CDDL-1.0 + GFDL-1.3-invariants-only + etalab-2.0 + XFree86-1.1 + SNIA + LPPL-1.1 + CATOSL-1.1 + TU-Berlin-2.0 + GFDL-1.3-or-later + LAL-1.2 + ICU + FTL + MirOS + CC-BY-NC-ND-3.0 + OSET-PL-2.1 + CC-BY-NC-ND-2.0 + SISSL-1.2 + Wsuipa + Zimbra-1.4 + Linux-OpenIB + OLDAP-2.5 + AMPAS + GPL-1.0-or-later + BUSL-1.1 + Adobe-Glyph + 0BSD + W3C-19980720 + FSFUL + CC-BY-NC-SA-3.0 + DOC + TMate + MIT-open-group + AMDPLPA + Condor-1.1 + PolyForm-Noncommercial-1.0.0 + BSD-3-Clause-No-Military-License + CC-BY-4.0 + OGL-Canada-2.0 + CC-BY-NC-SA-3.0-IGO + EFL-1.0 + Newsletr + copyleft-next-0.3.0 + GPL-3.0-or-later + CDLA-Permissive-2.0 + CC-BY-ND-3.0 + C-UDA-1.0 + Barr + Vim + BitTorrent-1.1 + CDL-1.0 + CC-BY-SA-1.0 + ADSL + PostgreSQL + OFL-1.1 + NPL-1.0 + xinetd + LGPL-2.0-only zlib-acknowledgement + OLDAP-2.2.1 + APSL-1.0 + BSD-3-Clause-LBNL + GLWTPL + LGPL-3.0-only + OGC-1.0 + Dotseqn + MakeIndex + GPL-3.0-only + BSD-3-Clause-No-Nuclear-License-2014 + GPL-1.0-only + IJG + AGPL-1.0-or-later + OFL-1.1-no-RFN + BSL-1.0 + Libpng + CC-BY-NC-3.0 + CC-BY-NC-2.0 + Unlicense + LPL-1.0 + bzip2-1.0.5 + Entessa + BSD-2-Clause-Patent + ECL-2.0 + Crossword + CC-BY-NC-ND-1.0 + OCLC-2.0 + CECILL-1.1 + CECILL-2.1 + OGDL-Taiwan-1.0 + Abstyles + libselinux-1.0 + ANTLR-PD + GPL-2.0-or-later + IPL-1.0 + MIT-enna + CPOL-1.02 + CC-BY-SA-3.0-AT + BSD-1-Clause + NTP-0 + SugarCRM-1.1.3 + MIT + OFL-1.1-RFN + Watcom-1.0 + CC-BY-NC-SA-2.0-FR + ODbL-1.0 + FSFULLR + OLDAP-1.3 + SSH-OpenSSH + BSD-2-Clause + HPND + Zimbra-1.3 + Borceux + OLDAP-1.1 + OFL-1.0 + NASA-1.3 + VOSTROM + MIT-0 + ISC + Unicode-DFS-2016 + BlueOak-1.0.0 + LiLiQ-Rplus-1.1 + NOSL + SMLNJ + CPAL-1.0 + PSF-2.0 + RPL-1.5 + MIT-Modern-Variant + Nokia + GFDL-1.1-no-invariants-only + PDDL-1.0 + EUPL-1.0 + CDDL-1.1 + GFDL-1.3-only + OLDAP-2.6 + JSON + LGPL-3.0-or-later + Fair + OSL-2.1 + LPPL-1.3a + NAIST-2003 + CC-BY-NC-ND-4.0 + CC-BY-NC-3.0-DE + OPL-1.0 + HPND-sell-variant + QPL-1.0 + EUPL-1.2 + GFDL-1.2-no-invariants-or-later + NCGL-UK-2.0 + Beerware + BSD-3-Clause-Open-MPI + CECILL-B + EPL-2.0 + MIT-feh + RPL-1.1 + CDLA-Permissive-1.0 + Python-2.0 + MPL-1.0 + GFDL-1.1-or-later + diffmark + OpenSSL + OSL-1.0 + Parity-6.0.0 + YPL-1.1 + SSH-short + IBM-pibs + Xnet + TU-Berlin-1.0 + CAL-1.0 + AFL-3.0 + CECILL-C + OGL-UK-3.0 + BSD-3-Clause-Clear + BSD-3-Clause-Modification + CC-BY-SA-2.0-UK + Saxpath + NLPL + SimPL-2.0 + psfrag + Spencer-86 + OCCT-PL + CERN-OHL-S-2.0 + ErlPL-1.1 + MIT-CMU + NIST-PD + OSL-2.0 + APSL-2.0 + Leptonica + PolyForm-Small-Business-1.0.0 + LiLiQ-P-1.1 + NetCDF + OML + AGPL-3.0-or-later + OLDAP-2.2 + BSD-3-Clause + WTFPL + OGL-UK-2.0 + BSD-3-Clause-Attribution + RPSL-1.0 + CC-BY-NC-ND-3.0-DE + EUPL-1.1 + Sendmail-8.23 + ODC-By-1.0 + D-FSL-1.0 + BSD-4-Clause + BSD-2-Clause-Views + Artistic-1.0-Perl + NPOSL-3.0 + gSOAP-1.3b + Interbase-1.0 + GPL-1.0 + GPL-2.0-with-GCC-exception + wxWindows + Nunit + GFDL-1.1 + GPL-2.0 + GFDL-1.2 + LGPL-2.0 + GPL-3.0-with-autoconf-exception + GFDL-1.3 + BSD-2-Clause-NetBSD + LGPL-3.0 + GPL-2.0-with-classpath-exception + GPL-3.0-with-GCC-exception + BSD-2-Clause-FreeBSD + GPL-3.0 + GPL-2.0-with-font-exception + eCos-2.0 + GPL-2.0-with-bison-exception + GPL-2.0-with-autoconf-exception AGPL-1.0 AGPL-3.0 - BSD-2-Clause-FreeBSD - BSD-2-Clause-NetBSD - GFDL-1.1 - GFDL-1.2 - GFDL-1.3 - GPL-1.0 - GPL-2.0 - GPL-2.0-with-GCC-exception - GPL-2.0-with-autoconf-exception - GPL-2.0-with-bison-exception - GPL-2.0-with-classpath-exception - GPL-2.0-with-font-exception - GPL-3.0 - GPL-3.0-with-GCC-exception - GPL-3.0-with-autoconf-exception - LGPL-2.0 LGPL-2.1 - LGPL-3.0 - Nunit StandardML-NJ - eCos-2.0 - wxWindows - GCC-exception-2.0 - openvpn-openssl-exception - GPL-3.0-linking-exception - Fawkes-Runtime-exception - u-boot-exception-2.0 - PS-or-PDF-font-exception-20170817 - gnu-javamail-exception - LGPL-3.0-linking-exception - DigiRule-FOSS-exception - LLVM-exception - Linux-syscall-note - GPL-3.0-linking-source-exception - Qwt-exception-1.0 - 389-exception - mif-exception - eCos-exception-2.0 - CLISP-exception-2.0 - Bison-exception-2.2 - Libtool-exception - LZMA-exception - OpenJDK-assembly-exception-1.0 - Font-exception-2.0 - OCaml-LGPL-linking-exception - GCC-exception-3.1 - Bootloader-exception - SHL-2.0 - Classpath-exception-2.0 - Swift-exception - Autoconf-exception-2.0 - FLTK-exception - freertos-exception-2.0 - Universal-FOSS-exception-1.0 - WxWindows-exception-3.1 - OCCT-exception-1.0 - Autoconf-exception-3.0 - i2p-gpl-java-exception GPL-CC-1.0 - Qt-LGPL-exception-1.1 - SHL-2.1 + openvpn-openssl-exception + WxWindows-exception-3.1 + GPL-3.0-linking-exception + i2p-gpl-java-exception + OpenJDK-assembly-exception-1.0 + mif-exception + CLISP-exception-2.0 + freertos-exception-2.0 + Bison-exception-2.2 + OCCT-exception-1.0 + Autoconf-exception-2.0 + LLVM-exception + GCC-exception-3.1 + Font-exception-2.0 + Libtool-exception + u-boot-exception-2.0 + Swift-exception + eCos-exception-2.0 + OCaml-LGPL-linking-exception Qt-GPL-exception-1.0 + Linux-syscall-note + Bootloader-exception + PS-or-PDF-font-exception-20170817 + Universal-FOSS-exception-1.0 + Classpath-exception-2.0 + Qwt-exception-1.0 + LZMA-exception + Autoconf-exception-3.0 + DigiRule-FOSS-exception + 389-exception + SHL-2.0 + GCC-exception-2.0 + GPL-3.0-linking-source-exception + Qt-LGPL-exception-1.1 + Fawkes-Runtime-exception + gnu-javamail-exception + FLTK-exception + LGPL-3.0-linking-exception + SHL-2.1 diff --git a/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme b/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme index a433fb883a4..87dac8a5d35 100644 --- a/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme +++ b/src/libs/3rdparty/syntax-highlighting/data/themes/oblivion.theme @@ -162,9 +162,9 @@ "MarkError": "#cc0000", "MarkExecution": "#888a85", "MarkWarning": "#ad7fa8", - "ModifiedLines": "#451e1a", + "ModifiedLines": "#cc0000", "ReplaceHighlight": "#356703", - "SavedLines": "#23321a", + "SavedLines": "#4e9a06", "SearchHighlight": "#4e9a06", "Separator": "#787775", "SpellChecking": "#e85848", diff --git a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt index beac3d50e89..419b8ed5b7c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt @@ -1,8 +1,11 @@ add_subdirectory(indexer) -if(TARGET Qt5::Gui) +if(TARGET Qt${QT_MAJOR_VERSION}::Gui) add_subdirectory(lib) add_subdirectory(cli) endif() +if(TARGET Qt${QT_MAJOR_VERSION}::Quick) + add_subdirectory(quick) +endif() ecm_qt_install_logging_categories( EXPORT KSYNTAXHIGHLIGHTING diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 4a84696ad91..9aede60ad78 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -20,6 +20,7 @@ elseif(CMAKE_CROSSCOMPILING) -DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} INSTALL_COMMAND "" + BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer ) add_executable(katehighlightingindexer IMPORTED GLOBAL) add_dependencies(katehighlightingindexer native_katehighlightingindexer) @@ -32,6 +33,6 @@ else() if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) else() - target_link_libraries(katehighlightingindexer Qt5::Core) + target_link_libraries(katehighlightingindexer Qt${QT_MAJOR_VERSION}::Core) endif() endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 4de51ba7c89..d491e13ab99 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -350,7 +350,7 @@ private: friend uint qHash(const Item &item, uint seed = 0) { - return uint(qHash(item.content, seed)); + return qHash(item.content, seed); } friend bool operator==(const Item &item0, const Item &item1) @@ -513,7 +513,7 @@ private: static const QRegularExpression isDot(QStringLiteral(R"(^\(?\.(?:[*+][*+?]?|[*+]|\{1\})?\$?$)")); // remove "(?:" and ")" static const QRegularExpression removeParentheses(QStringLiteral(R"(\((?:\?:)?|\))")); - // remove parentheses on a double from the string + // remove parentheses on a copy of string auto reg = QString(string).replace(removeParentheses, QString()); isDotRegex = reg.contains(isDot); } @@ -719,7 +719,7 @@ private: friend uint qHash(const Style &style, uint seed = 0) { - return uint(qHash(style.name, seed)); + return qHash(style.name, seed); } friend bool operator==(const Style &style0, const Style &style1) @@ -995,7 +995,6 @@ private: } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; - success = checkAnyChar(rule) && success; success = checkKeyword(definition, rule, referencedKeywords) && success; success = checkRegExpr(filename, rule, context) && success; success = checkDelimiters(definition, rule) && success; @@ -1053,12 +1052,9 @@ private: "\\.\\*[?*]?" REG_CHAR "|" "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" ")$")); - if (( rule.lookAhead == XmlBool::True - || rule.minimal == XmlBool::True - || rule.string.contains(QStringLiteral(".*?")) - || rule.string.contains(QStringLiteral("[^")) - ) && reg.contains(isRange) - ) { + if ((rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) + || rule.string.contains(QStringLiteral("[^"))) + && reg.contains(isRange)) { qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; return false; } @@ -1079,13 +1075,10 @@ private: #undef REG_ESCAPE_CHAR // use minimal or lazy operator - static const QRegularExpression isMinimal(QStringLiteral( - R"([.][*+][^][?+*()|$]*$)")); - if (rule.lookAhead == XmlBool::True - && rule.minimal != XmlBool::True - && reg.contains(isMinimal) - ) { - qWarning() << filename << "line" << rule.line << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; + static const QRegularExpression isMinimal(QStringLiteral(R"([.][*+][^][?+*()|$]*$)")); + if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(isMinimal)) { + qWarning() << filename << "line" << rule.line + << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; return false; } @@ -1179,19 +1172,18 @@ private: if (*first == QLatin1Char('^')) { hasStartOfLine = true; break; - } - else if (*first == QLatin1Char('(')) { + } else if (*first == QLatin1Char('(')) { if (last - first >= 3 && first[1] == QLatin1Char('?') && first[2] == QLatin1Char(':')) { first += 2; } - } - else { + } else { break; } } if (!hasStartOfLine) { - qWarning() << rule.filename << "line" << rule.line << "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string; + qWarning() << rule.filename << "line" << rule.line + << "start of line missing in the pattern with column=\"0\" (i.e. abc -> ^abc):" << rule.string; return false; } } @@ -1314,14 +1306,12 @@ private: } // unnecessary quantifier - static const QRegularExpression unnecessaryQuantifier1(QStringLiteral( - R"([*+?]([.][*+?]{0,2})?$)")); - static const QRegularExpression unnecessaryQuantifier2(QStringLiteral( - R"([*+?]([.][*+?]{0,2})?[)]*$)")); + static const QRegularExpression unnecessaryQuantifier1(QStringLiteral(R"([*+?]([.][*+?]{0,2})?$)")); + static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(R"([*+?]([.][*+?]{0,2})?[)]*$)")); auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2; if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) { - qWarning() << filename << "line" << rule.line << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" - << rule.string; + qWarning() << filename << "line" << rule.line + << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" << rule.string; return false; } } @@ -1484,32 +1474,11 @@ private: qWarning() << rule.filename << "line" << rule.line << "broken regex:" << rule.string << "problem: dynamic=true but no %\\d+ placeholder"; return false; } - } else { - if (rule.string.size() <= 1) { - const auto replacement = rule.insensitive == XmlBool::True ? QStringLiteral("AnyChar") : QStringLiteral("DetectChar"); - qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by" << replacement; - return false; - } - - if (rule.string.size() <= 2 && rule.insensitive != XmlBool::True) { - qWarning() << rule.filename << "line" << rule.line << "StringDetect should be replaced by Detect2Chars"; - return false; - } } } return true; } - //! Check that AnyChar contains more that 1 character - bool checkAnyChar(const Context::Rule &rule) const - { - if (rule.type == Context::Rule::Type::AnyChar && rule.string.size() <= 1) { - qWarning() << rule.filename << "line" << rule.line << "AnyChar should be replaced by DetectChar"; - return false; - } - return true; - } - //! Check \ and delimiter in a keyword list bool checkKeywordsList(const Definition &definition, QSet &referencedKeywords) const { @@ -1895,7 +1864,7 @@ private: Rule4 detectIdentifierRule{}; // Contains includedRules and included includedRules - QMap includeContexts; + QMap includeContexts; DotRegex dotRegex; @@ -2232,8 +2201,7 @@ private: if (auto &ruleAndInclude = includeContexts[rule.context.context]) { updateUnreachable1(ruleAndInclude); - } - else { + } else { ruleAndInclude.rule = &rule; } @@ -2378,55 +2346,52 @@ private: const auto end = context.rules.end() - 1; for (; it < end; ++it) { - auto& rule1 = *it; - auto& rule2 = it[1]; + auto &rule1 = *it; + auto &rule2 = it[1]; - auto isCommonCompatible = [&]{ - return rule1.attribute == rule2.attribute - && rule1.beginRegion == rule2.beginRegion - && rule1.endRegion == rule2.endRegion - && rule1.lookAhead == rule2.lookAhead - && rule1.firstNonSpace == rule2.firstNonSpace - && rule1.context.context == rule2.context.context - && rule1.context.popCount == rule2.context.popCount - ; + auto isCommonCompatible = [&] { + return rule1.attribute == rule2.attribute && rule1.beginRegion == rule2.beginRegion && rule1.endRegion == rule2.endRegion + && rule1.lookAhead == rule2.lookAhead && rule1.firstNonSpace == rule2.firstNonSpace && rule1.context.context == rule2.context.context + && rule1.context.popCount == rule2.context.popCount; }; switch (rule1.type) { - // request to merge AnyChar/DetectChar - case Context::Rule::Type::AnyChar: - case Context::Rule::Type::DetectChar: - if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible() && rule1.column == rule2.column) { - qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule"; - success = false; - } - break; + // request to merge AnyChar/DetectChar + case Context::Rule::Type::AnyChar: + case Context::Rule::Type::DetectChar: + if ((rule2.type == Context::Rule::Type::AnyChar || rule2.type == Context::Rule::Type::DetectChar) && isCommonCompatible() + && rule1.column == rule2.column) { + qWarning() << filename << "line" << rule2.line << "can be merged as AnyChar with the previous rule"; + success = false; + } + break; - // request to merge multiple RegExpr - case Context::Rule::Type::RegExpr: - if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic && (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) { - qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule"; - success = false; - } - break; + // request to merge multiple RegExpr + case Context::Rule::Type::RegExpr: + if (rule2.type == Context::Rule::Type::RegExpr && isCommonCompatible() && rule1.dynamic == rule2.dynamic + && (rule1.column == rule2.column || (rule1.column <= 0 && rule2.column <= 0))) { + qWarning() << filename << "line" << rule2.line << "can be merged with the previous rule"; + success = false; + } + break; - case Context::Rule::Type::DetectSpaces: - case Context::Rule::Type::HlCChar: - case Context::Rule::Type::HlCHex: - case Context::Rule::Type::HlCOct: - case Context::Rule::Type::HlCStringChar: - case Context::Rule::Type::Int: - case Context::Rule::Type::Float: - case Context::Rule::Type::LineContinue: - case Context::Rule::Type::WordDetect: - case Context::Rule::Type::StringDetect: - case Context::Rule::Type::Detect2Chars: - case Context::Rule::Type::IncludeRules: - case Context::Rule::Type::DetectIdentifier: - case Context::Rule::Type::keyword: - case Context::Rule::Type::Unknown: - case Context::Rule::Type::RangeDetect: - break; + case Context::Rule::Type::DetectSpaces: + case Context::Rule::Type::HlCChar: + case Context::Rule::Type::HlCHex: + case Context::Rule::Type::HlCOct: + case Context::Rule::Type::HlCStringChar: + case Context::Rule::Type::Int: + case Context::Rule::Type::Float: + case Context::Rule::Type::LineContinue: + case Context::Rule::Type::WordDetect: + case Context::Rule::Type::StringDetect: + case Context::Rule::Type::Detect2Chars: + case Context::Rule::Type::IncludeRules: + case Context::Rule::Type::DetectIdentifier: + case Context::Rule::Type::keyword: + case Context::Rule::Type::Unknown: + case Context::Rule::Type::RangeDetect: + break; } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index 43a60cc19b0..2ab0e603a29 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -7,6 +7,7 @@ target_sources(KF5SyntaxHighlighting PRIVATE context.cpp contextswitch.cpp definitiondownloader.cpp + highlightingdata.cpp foldingregion.cpp format.cpp htmlhighlighter.cpp @@ -46,13 +47,13 @@ set_target_properties(KF5SyntaxHighlighting PROPERTIES SOVERSION ${SyntaxHighlighting_SOVERSION} EXPORT_NAME SyntaxHighlighting ) -target_include_directories(KF5SyntaxHighlighting INTERFACE "$") +target_include_directories(KF5SyntaxHighlighting INTERFACE "$") target_include_directories(KF5SyntaxHighlighting PUBLIC "$") target_link_libraries(KF5SyntaxHighlighting PUBLIC - Qt5::Gui + Qt${QT_MAJOR_VERSION}::Gui PRIVATE - Qt5::Network + Qt${QT_MAJOR_VERSION}::Network ) ecm_generate_headers(SyntaxHighlighting_HEADERS @@ -74,7 +75,7 @@ install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${KDE_ install(FILES ${SyntaxHighlighting_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h - DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting) + DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting) if(BUILD_QCH) ecm_add_qch( @@ -104,6 +105,6 @@ ecm_generate_pri_file( KF5SyntaxHighlighting DEPS "gui" FILENAME_VAR PRI_FILENAME - INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting + INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting ) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index d6f8cad0c71..5794291ff00 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -137,8 +137,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * see https://phabricator.kde.org/D18509 */ int endlessLoopingCounter = 0; - while (!stateData->topContext()->lineEmptyContext().isStay() - || (stateData->topContext()->lineEmptyContext().isStay() && !stateData->topContext()->lineEndContext().isStay())) { + while (!stateData->topContext()->lineEmptyContext().isStay() || !stateData->topContext()->lineEndContext().isStay()) { /** * line empty context switches */ @@ -153,8 +152,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * line end context switches only when lineEmptyContext is #stay. This avoids * skipping empty lines after a line continuation character (see bug 405903) */ - } else if (!stateData->topContext()->lineEndContext().isStay() - && !d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + } else if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { break; } @@ -305,7 +303,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) d->switchContext(stateData, rule->context(), newResult.captures()); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); - if (newOffset == text.size() && std::dynamic_pointer_cast(rule)) { + if (newOffset == text.size() && rule->isLineContinue()) { lineContinuation = true; } break; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 8ae47d80ebf..95517328045 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include @@ -539,7 +539,7 @@ double calculate_CIEDE2000(const CieLab &color1, const CieLab &color2) } struct AnsiBuffer { - using ColorCache = QMap; + using ColorCache = QHash; void append(char c) { @@ -683,7 +683,8 @@ struct GraphLine { int labelLineLength = 0; int nextLabelOffset = 0; - template void pushLabel(int offset, String const &s, int charCounter) + template + void pushLabel(int offset, String const &s, int charCounter) { Q_ASSERT(offset >= labelLineLength); const int n = offset - labelLineLength; @@ -693,7 +694,8 @@ struct GraphLine { nextLabelOffset = labelLineLength; } - template void pushGraph(int offset, String const &s, int charCounter) + template + void pushGraph(int offset, String const &s, int charCounter) { Q_ASSERT(offset >= graphLineLength); const int n = offset - graphLineLength; @@ -754,8 +756,15 @@ public: void setDefinition(const KSyntaxHighlighting::Definition &def) override { AbstractHighlighter::setDefinition(def); - m_defData = DefinitionData::get(def); m_contextCapture.setDefinition(def); + + const auto &definitions = def.includedDefinitions(); + for (const auto &definition : definitions) { + const auto *defData = DefinitionData::get(definition); + for (const auto &context : defData->contexts) { + m_defDataBycontexts.insert(&context, defData); + } + } } void highlightData(QTextStream &in, @@ -928,8 +937,8 @@ private: } const auto context = stateData->topContext(); - const auto defData = DefinitionData::get(context->definition()); - const auto contextName = (defData != m_defData) ? QString(QLatin1Char('<') % defData->name % QLatin1Char('>')) : QString(); + const auto defDataIt = m_defDataBycontexts.find(context); + const auto contextName = (defDataIt != m_defDataBycontexts.end()) ? QString(QLatin1Char('<') % (*defDataIt)->name % QLatin1Char('>')) : QString(); return QString(label % contextName % QLatin1Char('[') % context->name() % QLatin1Char(']')); } @@ -1128,12 +1137,13 @@ private: std::vector m_highlightedFragments; std::vector m_formatGraph; ContextCaptureHighlighter m_contextCapture; - DefinitionData *m_defData; int m_regionDepth = 0; std::vector m_regions; std::vector m_regionGraph; std::vector m_regionStyles; + + QHash m_defDataBycontexts; }; } // anonymous namespace diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index 724f37a03f1..2bd940d8aa7 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -18,177 +18,111 @@ using namespace KSyntaxHighlighting; -Definition Context::definition() const +Context::Context(const DefinitionData &def, const HighlightingContextData &data) + : m_name(data.name) + , m_attributeFormat(data.attribute.isEmpty() ? Format() : def.formatByName(data.attribute)) + , m_indentationBasedFolding(!data.noIndentationBasedFolding && def.indentationBasedFolding) { - return m_def.definition(); -} - -void Context::setDefinition(const DefinitionRef &def) -{ - m_def = def; + if (!data.attribute.isEmpty() && !m_attributeFormat.isValid()) { + qCWarning(Log) << "Context: Unknown format" << data.attribute << "in context" << m_name << "of definition" << def.name; + } } bool Context::indentationBasedFoldingEnabled() const { - if (m_noIndentationBasedFolding) { - return false; - } - - return m_def.definition().indentationBasedFoldingEnabled(); + return m_indentationBasedFolding; } -void Context::load(QXmlStreamReader &reader) +void Context::resolveContexts(DefinitionData &def, const HighlightingContextData &data) { - Q_ASSERT(reader.name() == QLatin1String("context")); - Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - - m_name = reader.attributes().value(QLatin1String("name")).toString(); - m_attribute = reader.attributes().value(QLatin1String("attribute")).toString(); - m_lineEndContext.parse(reader.attributes().value(QLatin1String("lineEndContext"))); - m_lineEmptyContext.parse(reader.attributes().value(QLatin1String("lineEmptyContext"))); - m_fallthroughContext.parse(reader.attributes().value(QLatin1String("fallthroughContext"))); + m_lineEndContext.resolve(def, data.lineEndContext); + m_lineEmptyContext.resolve(def, data.lineEmptyContext); + m_fallthroughContext.resolve(def, data.fallthroughContext); m_fallthrough = !m_fallthroughContext.isStay(); - m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); - reader.readNext(); - while (!reader.atEnd()) { - switch (reader.tokenType()) { - case QXmlStreamReader::StartElement: { - auto rule = Rule::create(reader.name()); - if (rule) { - rule->setDefinition(m_def.definition()); - if (rule->load(reader)) { - m_rules.push_back(std::move(rule)); - } - } else { - reader.skipCurrentElement(); - } - reader.readNext(); - break; - } - case QXmlStreamReader::EndElement: - return; - default: - reader.readNext(); - break; + m_rules.reserve(data.rules.size()); + for (const auto &ruleData : data.rules) { + m_rules.push_back(Rule::create(def, ruleData, m_name)); + if (!m_rules.back()) { + m_rules.pop_back(); } } } -void Context::resolveContexts() +void Context::resolveIncludes(DefinitionData &def) { - const auto def = m_def.definition(); - m_lineEndContext.resolve(def); - m_lineEmptyContext.resolve(def); - m_fallthroughContext.resolve(def); - for (const auto &rule : m_rules) { - rule->resolveContext(); - } -} - -Context::ResolveState Context::resolveState() -{ - if (m_resolveState == Unknown) { - for (const auto &rule : m_rules) { - auto inc = std::dynamic_pointer_cast(rule); - if (inc) { - m_resolveState = Unresolved; - return m_resolveState; - } - } - m_resolveState = Resolved; - } - return m_resolveState; -} - -void Context::resolveIncludes() -{ - if (resolveState() == Resolved) { + if (m_resolveState == Resolved) { return; } - if (resolveState() == Resolving) { + if (m_resolveState == Resolving) { qCWarning(Log) << "Cyclic dependency!"; return; } - Q_ASSERT(resolveState() == Unresolved); + Q_ASSERT(m_resolveState == Unresolved); m_resolveState = Resolving; // cycle guard for (auto it = m_rules.begin(); it != m_rules.end();) { - auto inc = std::dynamic_pointer_cast(*it); - if (!inc) { + const IncludeRules *includeRules = it->get()->castToIncludeRules(); + if (!includeRules) { ++it; continue; } + Context *context = nullptr; - auto myDefData = DefinitionData::get(m_def.definition()); - if (inc->definitionName().isEmpty()) { // local include - context = myDefData->contextByName(inc->contextName()); + DefinitionData *defData = &def; + + const auto &contextName = includeRules->contextName(); + const int idx = contextName.indexOf(QLatin1String("##")); + + if (idx == -1) { // local include + context = def.contextByName(contextName); } else { - auto def = myDefData->repo->definitionForName(inc->definitionName()); - if (!def.isValid()) { - qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name(); + auto definitionName = contextName.mid(idx + 2); + auto includedDef = def.repo->definitionForName(definitionName); + if (!includedDef.isValid()) { + qCWarning(Log) << "Unable to resolve external include rule for definition" << definitionName << "in" << def.name; ++it; continue; } - auto defData = DefinitionData::get(def); + defData = DefinitionData::get(includedDef); + def.addImmediateIncludedDefinition(includedDef); defData->load(); - if (inc->contextName().isEmpty()) { + if (idx == 0) { context = defData->initialContext(); } else { - context = defData->contextByName(inc->contextName()); + context = defData->contextByName(contextName.left(idx)); } } + if (!context) { - qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" - << m_def.definition().name(); + qCWarning(Log) << "Unable to resolve include rule for definition" << contextName << "in" << def.name; ++it; continue; } - context->resolveIncludes(); + + if (context == this) { + qCWarning(Log) << "Unable to resolve self include rule for definition" << contextName << "in" << def.name; + ++it; + continue; + } + + if (context->m_resolveState != Resolved) { + context->resolveIncludes(*defData); + } /** * handle included attribute * transitive closure: we might include attributes included from somewhere else */ - if (inc->includeAttribute()) { - m_attribute = context->m_attribute; - m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context; + if (includeRules->includeAttribute()) { + m_attributeFormat = context->m_attributeFormat; } it = m_rules.erase(it); - for (const auto &rule : context->rules()) { - it = m_rules.insert(it, rule); - ++it; - } + it = m_rules.insert(it, context->rules().begin(), context->rules().end()); + it += context->rules().size(); } m_resolveState = Resolved; } - -void Context::resolveAttributeFormat() -{ - /** - * try to get our format from the definition we stem from - * we need to handle included attributes via m_attributeContext - */ - if (!m_attribute.isEmpty()) { - const auto def = m_attributeContext ? m_attributeContext->m_def.definition() : m_def.definition(); - m_attributeFormat = DefinitionData::get(def)->formatByName(m_attribute); - if (!m_attributeFormat.isValid()) { - if (m_attributeContext) { - qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name() - << "from included context" << m_attributeContext->m_name << "of definition" << def.name(); - } else { - qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name(); - } - } - } - - /** - * lookup formats for our rules - */ - for (const auto &rule : m_rules) { - rule->resolveAttributeFormat(this); - } -} diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h index 62630455370..7e077b5a244 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h @@ -8,9 +8,8 @@ #define KSYNTAXHIGHLIGHTING_CONTEXT_P_H #include "contextswitch_p.h" -#include "definition.h" -#include "definitionref_p.h" #include "format.h" +#include "highlightingdata_p.hpp" #include "rule_p.h" #include @@ -23,14 +22,18 @@ QT_END_NAMESPACE namespace KSyntaxHighlighting { +class DefinitionData; + class Context { public: - Context() = default; - ~Context() = default; + Q_DISABLE_COPY(Context) - Definition definition() const; - void setDefinition(const DefinitionRef &def); + Context(Context &&) = default; + Context &operator=(Context &&) = default; + + Context(const DefinitionData &def, const HighlightingContextData &data); + ~Context() = default; const QString &name() const { @@ -73,44 +76,28 @@ public: */ bool indentationBasedFoldingEnabled() const; - void load(QXmlStreamReader &reader); - void resolveContexts(); - void resolveIncludes(); - void resolveAttributeFormat(); + void resolveContexts(DefinitionData &def, const HighlightingContextData &data); + void resolveIncludes(DefinitionData &def); private: - Q_DISABLE_COPY(Context) + enum ResolveState : quint8 { Unresolved, Resolving, Resolved }; - enum ResolveState { Unknown, Unresolved, Resolving, Resolved }; - ResolveState resolveState(); + std::vector m_rules; - DefinitionRef m_def; QString m_name; - /** - * attribute name, to lookup our format - */ - QString m_attribute; - - /** - * context to use for lookup, if != this context - */ - const Context *m_attributeContext = nullptr; - - /** - * resolved format for our attribute, done in resolveAttributeFormat - */ - Format m_attributeFormat; - ContextSwitch m_lineEndContext; ContextSwitch m_lineEmptyContext; ContextSwitch m_fallthroughContext; - std::vector m_rules; + /** + * resolved format for our attribute, done in constructor and resolveIncludes + */ + Format m_attributeFormat; - ResolveState m_resolveState = Unknown; + ResolveState m_resolveState = Unresolved; bool m_fallthrough = false; - bool m_noIndentationBasedFolding = false; + bool m_indentationBasedFolding; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp index e829af463a3..9cab177dae1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp @@ -7,69 +7,45 @@ #include "contextswitch_p.h" #include "definition.h" #include "definition_p.h" +#include "highlightingdata_p.hpp" #include "ksyntaxhighlighting_logging.h" #include "repository.h" using namespace KSyntaxHighlighting; -bool ContextSwitch::isStay() const +void ContextSwitch::resolve(DefinitionData &def, QStringView contextInstr) { - return m_popCount == 0 && !m_context && m_contextName.isEmpty() && m_defName.isEmpty(); -} + HighlightingContextData::ContextSwitch ctx(contextInstr); -int ContextSwitch::popCount() const -{ - return m_popCount; -} + m_popCount = ctx.popCount(); + m_isStay = !m_popCount; -Context *ContextSwitch::context() const -{ - return m_context; -} + auto contextName = ctx.contextName(); + auto defName = ctx.defName(); -void ContextSwitch::parse(QStringView contextInstr) -{ - if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay")) { + if (contextName.isEmpty() && defName.isEmpty()) { return; } - if (contextInstr.startsWith(QLatin1String("#pop!"))) { - ++m_popCount; - m_contextName = contextInstr.mid(5).toString(); - return; - } - - if (contextInstr.startsWith(QLatin1String("#pop"))) { - ++m_popCount; - parse(contextInstr.mid(4)); - return; - } - - const auto idx = contextInstr.indexOf(QLatin1String("##")); - if (idx >= 0) { - m_contextName = contextInstr.left(idx).toString(); - m_defName = contextInstr.mid(idx + 2).toString(); + if (defName.isEmpty()) { + m_context = def.contextByName(contextName.toString()); } else { - m_contextName = contextInstr.toString(); - } -} - -void ContextSwitch::resolve(const Definition &def) -{ - auto d = def; - if (!m_defName.isEmpty()) { - d = DefinitionData::get(def)->repo->definitionForName(m_defName); - auto data = DefinitionData::get(d); - data->load(); - if (m_contextName.isEmpty()) { - m_context = data->initialContext(); + auto d = def.repo->definitionForName(defName.toString()); + if (d.isValid()) { + auto data = DefinitionData::get(d); + def.addImmediateIncludedDefinition(d); + data->load(); + if (contextName.isEmpty()) { + m_context = data->initialContext(); + } else { + m_context = data->contextByName(contextName.toString()); + } } } - if (!m_contextName.isEmpty()) { - m_context = DefinitionData::get(d)->contextByName(m_contextName); - if (!m_context) { - qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name(); - } + if (!m_context) { + qCWarning(Log) << "cannot find context" << contextName << "in" << def.name; + } else { + m_isStay = false; } } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h index 8230c4a3884..29b0e685e24 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h @@ -12,7 +12,7 @@ namespace KSyntaxHighlighting { class Context; -class Definition; +class DefinitionData; class ContextSwitch { @@ -20,19 +20,27 @@ public: ContextSwitch() = default; ~ContextSwitch() = default; - bool isStay() const; + bool isStay() const + { + return m_isStay; + } - int popCount() const; - Context *context() const; + int popCount() const + { + return m_popCount; + } - void parse(QStringView contextInstr); - void resolve(const Definition &def); + Context *context() const + { + return m_context; + } + + void resolve(DefinitionData &def, QStringView contextInstr); private: - QString m_defName; - QString m_contextName; Context *m_context = nullptr; int m_popCount = 0; + bool m_isStay = true; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 068907a4e28..0fbc9187c09 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -14,6 +14,7 @@ #include "context_p.h" #include "format.h" #include "format_p.h" +#include "highlightingdata_p.hpp" #include "ksyntaxhighlighting_logging.h" #include "ksyntaxhighlighting_version.h" #include "repository.h" @@ -39,10 +40,7 @@ DefinitionData::DefinitionData() { } -DefinitionData::~DefinitionData() -{ - qDeleteAll(contexts); -} +DefinitionData::~DefinitionData() = default; DefinitionData *DefinitionData::get(const Definition &def) { @@ -237,45 +235,23 @@ QVector Definition::includedDefinitions() const d->load(); // init worklist and result used as guard with this definition - QVector queue{*this}; + QVector queue{d.get()}; QVector definitions{*this}; - while (!queue.isEmpty()) { - // Iterate all context rules to find associated Definitions. This will - // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch. - const auto definition = queue.takeLast(); - for (const auto &context : std::as_const(definition.d->contexts)) { - // handle context switch attributes of this context itself - for (const auto switchContext : - {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) { - if (switchContext) { - if (!definitions.contains(switchContext->definition())) { - queue.push_back(switchContext->definition()); - definitions.push_back(switchContext->definition()); - } - } - } - - // handle the embedded rules - for (const auto &rule : context->rules()) { - // handle include rules like inclusion - if (!definitions.contains(rule->definition())) { - queue.push_back(rule->definition()); - definitions.push_back(rule->definition()); - } - - // handle context switch context inclusion - if (auto switchContext = rule->context().context()) { - if (!definitions.contains(switchContext->definition())) { - queue.push_back(switchContext->definition()); - definitions.push_back(switchContext->definition()); - } - } + while (!queue.empty()) { + const auto *def = queue.back(); + queue.pop_back(); + for (const auto &defRef : def->immediateIncludedDefinitions) { + const auto definition = defRef.definition(); + if (!definitions.contains(definition)) { + definitions.push_back(definition); + queue.push_back(definition.d.get()); } } } // remove the 1st entry, since it is this Definition - definitions.pop_front(); + definitions.front() = std::move(definitions.back()); + definitions.pop_back(); return definitions; } @@ -304,17 +280,17 @@ QVector> Definition::characterEncodings() const return d->characterEncodings; } -Context *DefinitionData::initialContext() const +Context *DefinitionData::initialContext() { - Q_ASSERT(!contexts.isEmpty()); - return contexts.first(); + Q_ASSERT(!contexts.empty()); + return &contexts.front(); } -Context *DefinitionData::contextByName(const QString &wantedName) const +Context *DefinitionData::contextByName(const QString &wantedName) { - for (const auto context : contexts) { - if (context->name() == wantedName) { - return context; + for (auto &context : contexts) { + if (context.name() == wantedName) { + return &context; } } return nullptr; @@ -338,7 +314,7 @@ Format DefinitionData::formatByName(const QString &wantedName) const bool DefinitionData::isLoaded() const { - return !contexts.isEmpty(); + return !contexts.empty(); } bool DefinitionData::load(OnlyKeywords onlyKeywords) @@ -383,17 +359,7 @@ bool DefinitionData::load(OnlyKeywords onlyKeywords) it->setCaseSensitivity(caseSensitive); } - for (const auto context : std::as_const(contexts)) { - context->resolveContexts(); - context->resolveIncludes(); - context->resolveAttributeFormat(); - } - - for (const auto context : std::as_const(contexts)) { - for (const auto &rule : context->rules()) { - rule->resolvePostProcessing(); - } - } + resolveContexts(); return true; } @@ -402,9 +368,21 @@ void DefinitionData::clear() { // keep only name and repo, so we can re-lookup to make references persist over repo reloads keywordLists.clear(); - qDeleteAll(contexts); contexts.clear(); formats.clear(); + contextDatas.clear(); + immediateIncludedDefinitions.clear(); + wordDelimiters = WordDelimiters(); + wordWrapDelimiters = wordDelimiters; + keywordIsLoaded = false; + hasFoldingRegions = false; + indentationBasedFolding = false; + foldingIgnoreList.clear(); + singleLineCommentMarker.clear(); + singleLineCommentPosition = CommentPosition::StartOfLine; + multiLineCommentStartMarker.clear(); + multiLineCommentEndMarker.clear(); + characterEncodings.clear(); fileName.clear(); section.clear(); @@ -414,8 +392,6 @@ void DefinitionData::clear() license.clear(); mimetypes.clear(); extensions.clear(); - wordDelimiters = WordDelimiters(); - wordWrapDelimiters = wordDelimiters; caseSensitive = Qt::CaseSensitive; version = 0.0f; priority = 0; @@ -563,14 +539,14 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader) Q_ASSERT(reader.name() == QLatin1String("contexts")); Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); + contextDatas.reserve(32); + while (!reader.atEnd()) { switch (reader.tokenType()) { case QXmlStreamReader::StartElement: if (reader.name() == QLatin1String("context")) { - auto context = new Context; - context->setDefinition(q); - context->load(reader); - contexts.push_back(context); + contextDatas.push_back(HighlightingContextData()); + contextDatas.back().load(name, reader); } reader.readNext(); break; @@ -583,6 +559,50 @@ void DefinitionData::loadContexts(QXmlStreamReader &reader) } } +void DefinitionData::resolveContexts() +{ + contexts.reserve(contextDatas.size()); + + /** + * Transform all HighlightingContextData to Context. + * This is necessary so that Context::resolveContexts() can find the referenced contexts. + */ + for (const auto &contextData : std::as_const(contextDatas)) { + contexts.emplace_back(*this, contextData); + } + + /** + * Resolves contexts and rules. + */ + auto ctxIt = contexts.begin(); + for (const auto &contextData : std::as_const(contextDatas)) { + ctxIt->resolveContexts(*this, contextData); + ++ctxIt; + } + + /** + * To free the memory, constDatas is emptied because it is no longer used. + */ + contextDatas.clear(); + contextDatas.shrink_to_fit(); + + /** + * Resolved includeRules. + */ + for (auto &context : contexts) { + context.resolveIncludes(*this); + } + + /** + * Post-processing on rules. + */ + for (const auto &context : contexts) { + for (auto &rule : context.rules()) { + rule->resolvePostProcessing(); + } + } +} + void DefinitionData::loadItemData(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("itemDatas")); @@ -635,8 +655,7 @@ void DefinitionData::loadGeneral(QXmlStreamReader &reader) wordDelimiters.remove(reader.attributes().value(QLatin1String("weakDeliminator"))); // adapt WordWrapDelimiters - auto wordWrapDeliminatorAttr = reader.attributes().value( - QLatin1String("wordWrapDeliminator")); + auto wordWrapDeliminatorAttr = reader.attributes().value(QLatin1String("wordWrapDeliminator")); if (wordWrapDeliminatorAttr.isEmpty()) { wordWrapDelimiters = wordDelimiters; } else { @@ -803,21 +822,40 @@ quint16 DefinitionData::foldingRegionId(const QString &foldName) return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName); } -DefinitionRef::DefinitionRef() +void DefinitionData::addImmediateIncludedDefinition(const Definition &def) { + if (get(def) != this) { + DefinitionRef defRef(def); + if (!immediateIncludedDefinitions.contains(defRef)) { + immediateIncludedDefinitions.push_back(std::move(defRef)); + } + } } +DefinitionRef::DefinitionRef() = default; + DefinitionRef::DefinitionRef(const Definition &def) : d(def.d) { } +DefinitionRef::DefinitionRef(Definition &&def) + : d(std::move(def.d)) +{ +} + DefinitionRef &DefinitionRef::operator=(const Definition &def) { d = def.d; return *this; } +DefinitionRef &DefinitionRef::operator=(Definition &&def) +{ + d = std::move(def.d); + return *this; +} + Definition DefinitionRef::definition() const { if (!d.expired()) { @@ -828,9 +866,5 @@ Definition DefinitionRef::definition() const bool DefinitionRef::operator==(const DefinitionRef &other) const { - if (d.expired() != other.d.expired()) { - return false; - } - - return d.expired() || d.lock().get() == other.d.lock().get(); + return !d.owner_before(other.d) && !other.d.owner_before(d); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h index e5455e14e98..7d89a47a48d 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h @@ -8,14 +8,16 @@ #ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H #define KSYNTAXHIGHLIGHTING_DEFINITION_P_H -#include "definition.h" #include "definitionref_p.h" +#include "highlightingdata_p.hpp" #include "worddelimiters_p.h" #include #include #include +#include + QT_BEGIN_NAMESPACE class QCborMap; class QXmlStreamReader; @@ -55,23 +57,31 @@ public: void loadSpellchecking(QXmlStreamReader &reader); bool checkKateVersion(QStringView verStr); + void resolveContexts(); + void resolveIncludeKeywords(); KeywordList *keywordList(const QString &name); - Context *initialContext() const; - Context *contextByName(const QString &name) const; + Context *initialContext(); + Context *contextByName(const QString &name); Format formatByName(const QString &name) const; quint16 foldingRegionId(const QString &foldName); + void addImmediateIncludedDefinition(const Definition &def); + DefinitionRef q; Repository *repo = nullptr; QHash keywordLists; - QVector contexts; + std::vector contexts; QHash formats; + // data loaded from xml file and emptied after loading contexts + QVector contextDatas; + // Definition referenced by IncludeRules and ContextSwitch + QVector immediateIncludedDefinitions; WordDelimiters wordDelimiters; WordDelimiters wordWrapDelimiters; bool keywordIsLoaded = false; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index b16139b731f..f9dbc298666 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -172,8 +172,7 @@ void DefinitionDownloader::start() const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.') + QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml"); auto req = QNetworkRequest(QUrl(url)); - req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, - QNetworkRequest::NoLessSafeRedirectPolicy); + req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); auto reply = d->nam->get(req); QObject::connect(reply, &QNetworkReply::finished, this, [=]() { d->definitionListDownloadFinished(reply); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h index db0c6ee68ae..2eaf0561ef1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h @@ -59,7 +59,7 @@ public: /** * Destructor. */ - ~DefinitionDownloader(); + ~DefinitionDownloader() override; /** * Starts the update procedure. diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 285fec3e206..a92fc988d90 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -7,6 +7,8 @@ #ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H #define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H +#include "definition.h" + #include namespace KSyntaxHighlighting @@ -29,7 +31,9 @@ class DefinitionRef public: DefinitionRef(); explicit DefinitionRef(const Definition &def); + explicit DefinitionRef(Definition &&def); DefinitionRef &operator=(const Definition &def); + DefinitionRef &operator=(Definition &&def); Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp new file mode 100644 index 00000000000..7f589e252b8 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp @@ -0,0 +1,402 @@ +/* + SPDX-FileCopyrightText: 2021 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#include "highlightingdata_p.hpp" +#include "ksyntaxhighlighting_logging.h" +#include "xml_p.h" + +#include +#include + +using namespace KSyntaxHighlighting; + +template +static void initRuleData(Data &data, Args &&...args) +{ + new (&data) Data{std::move(args)...}; +} + +static Qt::CaseSensitivity attrToCaseSensitivity(QStringView str) +{ + return Xml::attrToBool(str) ? Qt::CaseInsensitive : Qt::CaseSensitive; +} + +static HighlightingContextData::Rule::WordDelimiters loadAdditionalWordDelimiters(QXmlStreamReader &reader) +{ + return HighlightingContextData::Rule::WordDelimiters{ + reader.attributes().value(QLatin1String("additionalDeliminator")).toString(), + reader.attributes().value(QLatin1String("weakDeliminator")).toString(), + }; +} + +static bool checkIsNotEmpty(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader) +{ + if (!str.isEmpty()) { + return true; + } + + qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute is empty"; + return false; +} + +static bool checkIsChar(QStringView str, const char *attrName, const QString &defName, QXmlStreamReader &reader) +{ + if (str.size() == 1) { + return true; + } + + qCWarning(Log) << defName << "at line" << reader.lineNumber() << ": " << attrName << "attribute must contain exactly 1 character"; + return false; +} + +static bool loadRule(const QString &defName, HighlightingContextData::Rule &rule, QXmlStreamReader &reader) +{ + using Rule = HighlightingContextData::Rule; + + QStringView name = reader.name(); + const auto attrs = reader.attributes(); + bool isIncludeRules = false; + + if (name == QLatin1String("DetectChar")) { + const auto s = attrs.value(QLatin1String("char")); + if (!checkIsChar(s, "char", defName, reader)) { + return false; + } + const QChar c = s.at(0); + const bool dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + + initRuleData(rule.data.detectChar, c, dynamic); + rule.type = Rule::Type::DetectChar; + } else if (name == QLatin1String("RegExpr")) { + const auto pattern = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(pattern, "String", defName, reader)) { + return false; + } + + const auto isCaseInsensitive = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + const auto isMinimal = Xml::attrToBool(attrs.value(QLatin1String("minimal"))); + const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + + initRuleData(rule.data.regExpr, pattern.toString(), isCaseInsensitive, isMinimal, dynamic); + rule.type = Rule::Type::RegExpr; + } else if (name == QLatin1String("IncludeRules")) { + const auto context = attrs.value(QLatin1String("context")); + if (!checkIsNotEmpty(context, "context", defName, reader)) { + return false; + } + const bool includeAttribute = Xml::attrToBool(attrs.value(QLatin1String("includeAttrib"))); + + initRuleData(rule.data.includeRules, context.toString(), includeAttribute); + rule.type = Rule::Type::IncludeRules; + isIncludeRules = true; + } else if (name == QLatin1String("Detect2Chars")) { + const auto s1 = attrs.value(QLatin1String("char")); + const auto s2 = attrs.value(QLatin1String("char1")); + if (!checkIsChar(s1, "char", defName, reader)) { + return false; + } + if (!checkIsChar(s2, "char1", defName, reader)) { + return false; + } + + initRuleData(rule.data.detect2Chars, s1.at(0), s2.at(0)); + rule.type = Rule::Type::Detect2Chars; + } else if (name == QLatin1String("keyword")) { + const auto s = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(s, "String", defName, reader)) { + return false; + } + Qt::CaseSensitivity caseSensitivityOverride = Qt::CaseInsensitive; + bool hasCaseSensitivityOverride = false; + + /** + * we might overwrite the case sensitivity + * then we need to init the list for lookup of that sensitivity setting + */ + if (attrs.hasAttribute(QLatin1String("insensitive"))) { + hasCaseSensitivityOverride = true; + caseSensitivityOverride = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + } + + initRuleData(rule.data.keyword, s.toString(), loadAdditionalWordDelimiters(reader), caseSensitivityOverride, hasCaseSensitivityOverride); + rule.type = Rule::Type::Keyword; + } else if (name == QLatin1String("DetectSpaces")) { + rule.type = Rule::Type::DetectSpaces; + } else if (name == QLatin1String("StringDetect")) { + const auto string = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(string, "String", defName, reader)) { + return false; + } + const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + const auto dynamic = Xml::attrToBool(attrs.value(QLatin1String("dynamic"))); + const bool isSensitive = (caseSensitivity == Qt::CaseSensitive); + + // String can be replaced with DetectChar or AnyChar + if (!dynamic && string.size() == 1) { + QChar c = string.at(0); + if (isSensitive || c.toLower() == c.toUpper()) { + initRuleData(rule.data.detectChar, c, dynamic); + rule.type = Rule::Type::DetectChar; + } else { + initRuleData(rule.data.anyChar, c.toLower() + c.toUpper()); + rule.type = Rule::Type::AnyChar; + } + } + // String can be replaced with Detect2Chars + else if (isSensitive && !dynamic && string.size() == 2) { + initRuleData(rule.data.detect2Chars, string.at(0), string.at(1)); + rule.type = Rule::Type::Detect2Chars; + } else { + initRuleData(rule.data.stringDetect, string.toString(), caseSensitivity, dynamic); + rule.type = Rule::Type::StringDetect; + } + } else if (name == QLatin1String("WordDetect")) { + const auto word = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(word, "String", defName, reader)) { + return false; + } + const auto caseSensitivity = attrToCaseSensitivity(attrs.value(QLatin1String("insensitive"))); + + initRuleData(rule.data.wordDetect, word.toString(), loadAdditionalWordDelimiters(reader), caseSensitivity); + rule.type = Rule::Type::WordDetect; + } else if (name == QLatin1String("AnyChar")) { + const auto chars = attrs.value(QLatin1String("String")); + if (!checkIsNotEmpty(chars, "String", defName, reader)) { + return false; + } + + // AnyChar can be replaced with DetectChar + if (chars.size() == 1) { + initRuleData(rule.data.detectChar, chars.at(0), false); + rule.type = Rule::Type::DetectChar; + } else { + initRuleData(rule.data.anyChar, chars.toString()); + rule.type = Rule::Type::AnyChar; + } + } else if (name == QLatin1String("DetectIdentifier")) { + rule.type = Rule::Type::DetectIdentifier; + } else if (name == QLatin1String("LineContinue")) { + const auto s = attrs.value(QLatin1String("char")); + const QChar c = s.isEmpty() ? QLatin1Char('\\') : s.at(0); + + initRuleData(rule.data.lineContinue, c); + rule.type = Rule::Type::LineContinue; + } else if (name == QLatin1String("Int")) { + initRuleData(rule.data.detectInt, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::Int; + } else if (name == QLatin1String("Float")) { + initRuleData(rule.data.detectFloat, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::Float; + } else if (name == QLatin1String("HlCStringChar")) { + rule.type = Rule::Type::HlCStringChar; + } else if (name == QLatin1String("RangeDetect")) { + const auto s1 = attrs.value(QLatin1String("char")); + const auto s2 = attrs.value(QLatin1String("char1")); + if (!checkIsChar(s1, "char", defName, reader)) { + return false; + } + if (!checkIsChar(s2, "char1", defName, reader)) { + return false; + } + + initRuleData(rule.data.rangeDetect, s1.at(0), s2.at(0)); + rule.type = Rule::Type::RangeDetect; + } else if (name == QLatin1String("HlCHex")) { + initRuleData(rule.data.hlCHex, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::HlCHex; + } else if (name == QLatin1String("HlCChar")) { + rule.type = Rule::Type::HlCChar; + } else if (name == QLatin1String("HlCOct")) { + initRuleData(rule.data.hlCOct, loadAdditionalWordDelimiters(reader)); + rule.type = Rule::Type::HlCOct; + } else { + qCWarning(Log) << "Unknown rule type:" << name; + return false; + } + + if (!isIncludeRules) { + rule.common.contextName = attrs.value(QLatin1String("context")).toString(); + rule.common.beginRegionName = attrs.value(QLatin1String("beginRegion")).toString(); + rule.common.endRegionName = attrs.value(QLatin1String("endRegion")).toString(); + rule.common.attributeName = attrs.value(QLatin1String("attribute")).toString(); + rule.common.firstNonSpace = Xml::attrToBool(attrs.value(QLatin1String("firstNonSpace"))); + rule.common.lookAhead = Xml::attrToBool(attrs.value(QLatin1String("lookAhead"))); + bool colOk = false; + rule.common.column = attrs.value(QLatin1String("column")).toInt(&colOk); + if (!colOk) { + rule.common.column = -1; + } + } + + return true; +} + +template +static void dataRuleVisit(HighlightingContextData::Rule::Type type, Data1 &&data1, Data2 &&data2, Visitor &&visitor) +{ + using Rule = HighlightingContextData::Rule; + using Type = Rule::Type; + switch (type) { + case Type::AnyChar: + visitor(data1.anyChar, data2.anyChar); + break; + case Type::DetectChar: + visitor(data1.detectChar, data2.detectChar); + break; + case Type::Detect2Chars: + visitor(data1.detect2Chars, data2.detect2Chars); + break; + case Type::HlCOct: + visitor(data1.hlCOct, data2.hlCOct); + break; + case Type::IncludeRules: + visitor(data1.includeRules, data2.includeRules); + break; + case Type::Int: + visitor(data1.detectInt, data2.detectInt); + break; + case Type::Keyword: + visitor(data1.keyword, data2.keyword); + break; + case Type::LineContinue: + visitor(data1.lineContinue, data2.lineContinue); + break; + case Type::RangeDetect: + visitor(data1.rangeDetect, data2.rangeDetect); + break; + case Type::RegExpr: + visitor(data1.regExpr, data2.regExpr); + break; + case Type::StringDetect: + visitor(data1.stringDetect, data2.stringDetect); + break; + case Type::WordDetect: + visitor(data1.wordDetect, data2.wordDetect); + break; + case Type::Float: + visitor(data1.detectFloat, data2.detectFloat); + break; + case Type::HlCHex: + visitor(data1.hlCHex, data2.hlCHex); + break; + + case Type::HlCStringChar: + case Type::DetectIdentifier: + case Type::DetectSpaces: + case Type::HlCChar: + case Type::Unknown:; + } +} + +HighlightingContextData::Rule::Rule() noexcept = default; + +HighlightingContextData::Rule::Rule(Rule &&other) noexcept + : common(std::move(other.common)) +{ + dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) { + using Data = std::remove_reference_t; + new (&data1) Data(std::move(data2)); + }); + type = other.type; +} + +HighlightingContextData::Rule::Rule(const Rule &other) + : common(other.common) +{ + dataRuleVisit(other.type, data, other.data, [](auto &data1, auto &data2) { + using Data = std::remove_reference_t; + new (&data1) Data(data2); + }); + type = other.type; +} + +HighlightingContextData::Rule::~Rule() +{ + dataRuleVisit(type, data, data, [](auto &data, auto &) { + using Data = std::remove_reference_t; + data.~Data(); + }); +} + +HighlightingContextData::ContextSwitch::ContextSwitch(QStringView str) +{ + if (str.isEmpty() || str == QStringLiteral("#stay")) { + return; + } + + while (str.startsWith(QStringLiteral("#pop"))) { + ++m_popCount; + if (str.size() > 4 && str.at(4) == QLatin1Char('!')) { + str = str.mid(5); + break; + } + str = str.mid(4); + } + + if (str.isEmpty()) { + return; + } + + m_contextAndDefName = str.toString(); + m_defNameIndex = str.indexOf(QStringLiteral("##")); +} + +bool HighlightingContextData::ContextSwitch::isStay() const +{ + return m_popCount == -1 && m_contextAndDefName.isEmpty(); +} + +QStringView HighlightingContextData::ContextSwitch::contextName() const +{ + if (m_defNameIndex == -1) { + return m_contextAndDefName; + } + return QStringView(m_contextAndDefName).left(m_defNameIndex); +} + +QStringView HighlightingContextData::ContextSwitch::defName() const +{ + if (m_defNameIndex == -1) { + return QStringView(); + } + return QStringView(m_contextAndDefName).mid(m_defNameIndex + 2); +} + +void HighlightingContextData::load(const QString &defName, QXmlStreamReader &reader) +{ + Q_ASSERT(reader.name() == QLatin1String("context")); + Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); + + name = reader.attributes().value(QLatin1String("name")).toString(); + attribute = reader.attributes().value(QLatin1String("attribute")).toString(); + lineEndContext = reader.attributes().value(QLatin1String("lineEndContext")).toString(); + lineEmptyContext = reader.attributes().value(QLatin1String("lineEmptyContext")).toString(); + fallthroughContext = reader.attributes().value(QLatin1String("fallthroughContext")).toString(); + noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); + + rules.reserve(8); + + reader.readNext(); + while (!reader.atEnd()) { + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: { + auto &rule = rules.emplace_back(); + if (!loadRule(defName, rule, reader)) { + rules.pop_back(); + } + // be done with this rule, skip all subelements, e.g. no longer supported sub-rules + reader.skipCurrentElement(); + reader.readNext(); + break; + } + case QXmlStreamReader::EndElement: + return; + default: + reader.readNext(); + break; + } + } +} diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp new file mode 100644 index 00000000000..80aeaf49340 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp @@ -0,0 +1,215 @@ +/* + SPDX-FileCopyrightText: 2021 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#ifndef KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H +#define KSYNTAXHIGHLIGHTING_HIGHLIGHTING_DATA_P_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE + +namespace KSyntaxHighlighting +{ +/** + * Represents the raw xml data of a context and its rules. + * After resolving contexts, members of this class are no longer + * use and the instance can be freed to recover used memory. + */ +class HighlightingContextData +{ +public: + void load(const QString &defName, QXmlStreamReader &reader); + + struct ContextSwitch { + ContextSwitch() = default; + ContextSwitch(QStringView str); + + QStringView contextName() const; + QStringView defName() const; + + bool isStay() const; + + int popCount() const + { + return m_popCount; + } + + private: + int m_popCount = 0; + int m_defNameIndex = -1; + QString m_contextAndDefName; + }; + + struct Rule { + enum class Type : quint8 { + Unknown, + AnyChar, + Detect2Chars, + DetectChar, + HlCOct, + IncludeRules, + Int, + Keyword, + LineContinue, + RangeDetect, + RegExpr, + StringDetect, + WordDetect, + Float, + HlCStringChar, + DetectIdentifier, + DetectSpaces, + HlCChar, + HlCHex, + }; + + struct AnyChar { + QString chars; + }; + + struct Detect2Chars { + QChar char1; + QChar char2; + }; + + struct DetectChar { + QChar char1; + bool dynamic; + }; + + struct WordDelimiters { + QString additionalDeliminator; + QString weakDeliminator; + }; + + struct Float { + WordDelimiters wordDelimiters; + }; + + struct HlCHex { + WordDelimiters wordDelimiters; + }; + + struct HlCOct { + WordDelimiters wordDelimiters; + }; + + struct IncludeRules { + QString contextName; + bool includeAttribute; + }; + + struct Int { + WordDelimiters wordDelimiters; + }; + + struct Keyword { + QString name; + WordDelimiters wordDelimiters; + Qt::CaseSensitivity caseSensitivityOverride; + bool hasCaseSensitivityOverride; + }; + + struct LineContinue { + QChar char1; + }; + + struct RangeDetect { + QChar begin; + QChar end; + }; + + struct RegExpr { + QString pattern; + Qt::CaseSensitivity caseSensitivity; + bool isMinimal; + bool dynamic; + }; + + struct StringDetect { + QString string; + Qt::CaseSensitivity caseSensitivity; + bool dynamic; + }; + + struct WordDetect { + QString word; + WordDelimiters wordDelimiters; + Qt::CaseSensitivity caseSensitivity; + }; + + union Data { + AnyChar anyChar; + Detect2Chars detect2Chars; + DetectChar detectChar; + HlCOct hlCOct; + IncludeRules includeRules; + Int detectInt; + Keyword keyword; + LineContinue lineContinue; + RangeDetect rangeDetect; + RegExpr regExpr; + StringDetect stringDetect; + WordDetect wordDetect; + Float detectFloat; + HlCHex hlCHex; + + Data() noexcept + { + } + + ~Data() + { + } + }; + + struct Common { + QString contextName; + QString attributeName; + QString beginRegionName; + QString endRegionName; + int column = -1; + bool firstNonSpace = false; + bool lookAhead = false; + }; + + Type type = Type::Unknown; + Common common; + Data data; + + Rule() noexcept; + Rule(Rule &&other) noexcept; + Rule(const Rule &other); + ~Rule(); + + // since nothing is deleted in the rules vector, these functions do not need to be implemented + Rule &operator=(Rule &&other) = delete; + Rule &operator=(const Rule &other) = delete; + }; + + QString name; + + /** + * attribute name, to lookup our format + */ + QString attribute; + + QString lineEndContext; + QString lineEmptyContext; + QString fallthroughContext; + + std::vector rules; + + bool noIndentationBasedFolding = false; +}; +} + +#endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h index 3ff06952830..a8578522cba 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h @@ -44,6 +44,11 @@ public: return m_keywords; } + Qt::CaseSensitivity caseSensitivity() const + { + return m_caseSensitive; + } + void setKeywordList(const QStringList &keywords) { m_keywords = keywords; @@ -53,7 +58,10 @@ public: } /** Checks if @p str is a keyword in this list. */ - bool contains(QStringView str) const { return contains(str, m_caseSensitive); } + bool contains(QStringView str) const + { + return contains(str, m_caseSensitive); + } /** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */ bool contains(QStringView str, Qt::CaseSensitivity caseSensitive) const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp index f4e88b719a7..0357dbf2a3c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp @@ -14,7 +14,6 @@ #include "xml_p.h" #include -#include using namespace KSyntaxHighlighting; @@ -97,172 +96,137 @@ static QString replaceCaptures(const QString &pattern, const QStringList &captur return result; } -Rule::~Rule() +static MatchResult matchString(QStringView pattern, QStringView text, int offset, Qt::CaseSensitivity caseSensitivity) { - if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) { - delete m_wordDelimiters; + if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, caseSensitivity) == 0) { + return offset + pattern.size(); } + return offset; } -Definition Rule::definition() const +static void resolveAdditionalWordDelimiters(WordDelimiters &wordDelimiters, const HighlightingContextData::Rule::WordDelimiters &delimiters) { - return m_def.definition(); -} - -void Rule::setDefinition(const Definition &def) -{ - m_def = def; -} - -bool Rule::load(QXmlStreamReader &reader) -{ - Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement); - - m_attribute = reader.attributes().value(QLatin1String("attribute")).toString(); - if (reader.name() != QLatin1String("IncludeRules")) { // IncludeRules uses this with a different semantic - m_context.parse(reader.attributes().value(QLatin1String("context"))); - } - m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QLatin1String("firstNonSpace"))); - m_lookAhead = Xml::attrToBool(reader.attributes().value(QLatin1String("lookAhead"))); - bool colOk = false; - m_column = reader.attributes().value(QLatin1String("column")).toInt(&colOk); - if (!colOk) { - m_column = -1; - } - - auto regionName = reader.attributes().value(QLatin1String("beginRegion")); - if (!regionName.isEmpty()) { - m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); - } - regionName = reader.attributes().value(QLatin1String("endRegion")); - if (!regionName.isEmpty()) { - m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString())); - } - - auto result = doLoad(reader); - - if (m_lookAhead && m_context.isStay()) { - result = false; - } - - // be done with this rule, skip all subelements, e.g. no longer supported sub-rules - reader.skipCurrentElement(); - return result; -} - -void Rule::resolveContext() -{ - auto const &def = m_def.definition(); - - m_context.resolve(def); - // cache for DefinitionData::wordDelimiters, is accessed VERY often - m_wordDelimiters = &DefinitionData::get(def)->wordDelimiters; - if (!m_additionalDeliminator.isEmpty() || !m_weakDeliminator.isEmpty()) { - m_wordDelimiters = new WordDelimiters(*m_wordDelimiters); - m_wordDelimiters->append(m_additionalDeliminator); - m_wordDelimiters->remove(m_weakDeliminator); + if (!delimiters.additionalDeliminator.isEmpty() || !delimiters.weakDeliminator.isEmpty()) { + wordDelimiters.append(QStringView(delimiters.additionalDeliminator)); + wordDelimiters.remove(QStringView(delimiters.weakDeliminator)); } } -void Rule::resolveAttributeFormat(Context *lookupContext) +Rule::~Rule() = default; + +const IncludeRules *Rule::castToIncludeRules() const { + if (m_type != Type::IncludeRules) { + return nullptr; + } + return static_cast(this); +} + +bool Rule::resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) +{ + switch (ruleData.type) { + // IncludeRules uses this with a different semantic + case HighlightingContextData::Rule::Type::IncludeRules: + m_type = Type::IncludeRules; + return true; + case HighlightingContextData::Rule::Type::LineContinue: + m_type = Type::LineContinue; + break; + default: + m_type = Type::OtherRule; + break; + } + /** * try to get our format from the definition we stem from */ - if (!m_attribute.isEmpty()) { - m_attributeFormat = DefinitionData::get(definition())->formatByName(m_attribute); + if (!ruleData.common.attributeName.isEmpty()) { + m_attributeFormat = def.formatByName(ruleData.common.attributeName); if (!m_attributeFormat.isValid()) { - qCWarning(Log) << "Rule: Unknown format" << m_attribute << "in context" << lookupContext->name() << "of definition" << definition().name(); + qCWarning(Log) << "Rule: Unknown format" << ruleData.common.attributeName << "in context" << lookupContextName << "of definition" << def.name; } } + + m_firstNonSpace = ruleData.common.firstNonSpace; + m_lookAhead = ruleData.common.lookAhead; + m_column = ruleData.common.column; + + if (!ruleData.common.beginRegionName.isEmpty()) { + m_beginRegion = FoldingRegion(FoldingRegion::Begin, def.foldingRegionId(ruleData.common.beginRegionName)); + } + if (!ruleData.common.endRegionName.isEmpty()) { + m_endRegion = FoldingRegion(FoldingRegion::End, def.foldingRegionId(ruleData.common.endRegionName)); + } + + m_context.resolve(def, ruleData.common.contextName); + + return !(m_lookAhead && m_context.isStay()); } -bool Rule::doLoad(QXmlStreamReader &reader) +static Rule::Ptr createRule(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) { - Q_UNUSED(reader); - return true; -} + using Type = HighlightingContextData::Rule::Type; -void Rule::loadAdditionalWordDelimiters(QXmlStreamReader &reader) -{ - m_additionalDeliminator = reader.attributes().value(QLatin1String("additionalDeliminator")).toString(); - m_weakDeliminator = reader.attributes().value(QLatin1String("weakDeliminator")).toString(); -} - -Rule::Ptr Rule::create(QStringView name) -{ - if (name == QLatin1String("AnyChar")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectChar")) { - return std::make_shared(); - } - if (name == QLatin1String("Detect2Chars")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectIdentifier")) { - return std::make_shared(); - } - if (name == QLatin1String("DetectSpaces")) { - return std::make_shared(); - } - if (name == QLatin1String("Float")) { - return std::make_shared(); - } - if (name == QLatin1String("Int")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCChar")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCHex")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCOct")) { - return std::make_shared(); - } - if (name == QLatin1String("HlCStringChar")) { + switch (ruleData.type) { + case Type::AnyChar: + return std::make_shared(ruleData.data.anyChar); + case Type::DetectChar: + return std::make_shared(ruleData.data.detectChar); + case Type::Detect2Chars: + return std::make_shared(ruleData.data.detect2Chars); + case Type::IncludeRules: + return std::make_shared(ruleData.data.includeRules); + case Type::Int: + return std::make_shared(def, ruleData.data.detectInt); + case Type::Keyword: + return KeywordListRule::create(def, ruleData.data.keyword, lookupContextName); + case Type::LineContinue: + return std::make_shared(ruleData.data.lineContinue); + case Type::RangeDetect: + return std::make_shared(ruleData.data.rangeDetect); + case Type::RegExpr: + return std::make_shared(ruleData.data.regExpr); + case Type::StringDetect: + if (ruleData.data.stringDetect.dynamic) { + return std::make_shared(ruleData.data.stringDetect); + } + return std::make_shared(ruleData.data.stringDetect); + case Type::WordDetect: + return std::make_shared(def, ruleData.data.wordDetect); + case Type::Float: + return std::make_shared(def, ruleData.data.detectFloat); + case Type::HlCOct: + return std::make_shared(def, ruleData.data.hlCOct); + case Type::HlCStringChar: return std::make_shared(); - } - if (name == QLatin1String("IncludeRules")) { - return std::make_shared(); - } - if (name == QLatin1String("keyword")) { - return std::make_shared(); - } - if (name == QLatin1String("LineContinue")) { - return std::make_shared(); - } - if (name == QLatin1String("RangeDetect")) { - return std::make_shared(); - } - if (name == QLatin1String("RegExpr")) { - return std::make_shared(); - } - if (name == QLatin1String("StringDetect")) { - return std::make_shared(); - } - if (name == QLatin1String("WordDetect")) { - return std::make_shared(); + case Type::DetectIdentifier: + return std::make_shared(); + case Type::DetectSpaces: + return std::make_shared(); + case Type::HlCChar: + return std::make_shared(); + case Type::HlCHex: + return std::make_shared(def, ruleData.data.hlCHex); + + case Type::Unknown:; } - qCWarning(Log) << "Unknown rule type:" << name; - return Ptr(nullptr); + return Rule::Ptr(nullptr); } -bool Rule::isWordDelimiter(QChar c) const +Rule::Ptr Rule::create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName) { - return m_wordDelimiters->contains(c); + auto rule = createRule(def, ruleData, lookupContextName); + if (rule && !rule->resolveCommon(def, ruleData, lookupContextName)) { + rule.reset(); + } + return rule; } -bool AnyChar::doLoad(QXmlStreamReader &reader) +AnyChar::AnyChar(const HighlightingContextData::Rule::AnyChar &data) + : m_chars(data.chars) { - m_chars = reader.attributes().value(QLatin1String("String")).toString(); - if (m_chars.size() == 1) { - qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead."; - } - return !m_chars.isEmpty(); } MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const @@ -273,18 +237,11 @@ MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) return offset; } -bool DetectChar::doLoad(QXmlStreamReader &reader) +DetectChar::DetectChar(const HighlightingContextData::Rule::DetectChar &data) + : m_char(data.char1) + , m_captureIndex(data.dynamic ? data.char1.digitValue() : 0) { - const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) { - return false; - } - m_char = s.at(0); - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - if (m_dynamic) { - m_captureIndex = m_char.digitValue(); - } - return true; + m_dynamic = data.dynamic; } MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const @@ -305,19 +262,13 @@ MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList return offset; } -bool Detect2Char::doLoad(QXmlStreamReader &reader) +Detect2Chars::Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data) + : m_char1(data.char1) + , m_char2(data.char2) { - const auto s1 = reader.attributes().value(QLatin1String("char")); - const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) { - return false; - } - m_char1 = s1.at(0); - m_char2 = s2.at(0); - return true; } -MatchResult Detect2Char::doMatch(QStringView text, int offset, const QStringList &) const +MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &) const { if (text.size() - offset < 2) { return offset; @@ -352,15 +303,15 @@ MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringLis return offset; } -bool Float::doLoad(QXmlStreamReader &reader) +Float::Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -432,15 +383,15 @@ MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) return offset; } -bool HlCHex::doLoad(QXmlStreamReader &reader) +HlCHex::HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -466,15 +417,15 @@ MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) c return offset; } -bool HlCOct::doLoad(QXmlStreamReader &reader) +HlCOct::HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -503,53 +454,28 @@ MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringLi return matchEscapedChar(text, offset); } -QString IncludeRules::contextName() const +IncludeRules::IncludeRules(const HighlightingContextData::Rule::IncludeRules &data) + : m_contextName(data.contextName) + , m_includeAttribute(data.includeAttribute) { - return m_contextName; -} - -QString IncludeRules::definitionName() const -{ - return m_defName; -} - -bool IncludeRules::includeAttribute() const -{ - return m_includeAttribute; -} - -bool IncludeRules::doLoad(QXmlStreamReader &reader) -{ - const auto s = reader.attributes().value(QLatin1String("context")); - const auto split = s.split(QString::fromLatin1("##"), Qt::KeepEmptyParts); - if (split.isEmpty()) { - return false; - } - m_contextName = split.at(0).toString(); - if (split.size() > 1) { - m_defName = split.at(1).toString(); - } - m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib"))); - - return !m_contextName.isEmpty() || !m_defName.isEmpty(); } MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const { Q_UNUSED(text); - qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName; + qCWarning(Log) << "Unresolved include rule"; return offset; } -bool Int::doLoad(QXmlStreamReader &reader) +Int::Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data) + : m_wordDelimiters(def.wordDelimiters) { - loadAdditionalWordDelimiters(reader); - return true; + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const { - if (offset > 0 && !isWordDelimiter(text.at(offset - 1))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) { return offset; } @@ -559,67 +485,61 @@ MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) cons return offset; } -bool KeywordListRule::doLoad(QXmlStreamReader &reader) +Rule::Ptr KeywordListRule::create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName) { /** * get our keyword list, if not found => bail out */ - auto defData = DefinitionData::get(definition()); - m_keywordList = defData->keywordList(reader.attributes().value(QLatin1String("String")).toString()); - if (!m_keywordList) { - return false; + auto *keywordList = def.keywordList(data.name); + if (!keywordList) { + qCWarning(Log) << "Rule: Unknown keyword list" << data.name << "in context" << lookupContextName << "of definition" << def.name; + return Rule::Ptr(); + } + + if (keywordList->isEmpty()) { + return Rule::Ptr(); } /** * we might overwrite the case sensitivity * then we need to init the list for lookup of that sensitivity setting */ - if (reader.attributes().hasAttribute(QLatin1String("insensitive"))) { - m_hasCaseSensitivityOverride = true; - m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - m_keywordList->initLookupForCaseSensitivity(m_caseSensitivityOverride); - } else { - m_hasCaseSensitivityOverride = false; + if (data.hasCaseSensitivityOverride) { + keywordList->initLookupForCaseSensitivity(data.caseSensitivityOverride); } - loadAdditionalWordDelimiters(reader); + return std::make_shared(*keywordList, def, data); +} - return !m_keywordList->isEmpty(); +KeywordListRule::KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data) + : m_wordDelimiters(def.wordDelimiters) + , m_keywordList(keywordList) + , m_caseSensitivity(data.hasCaseSensitivityOverride ? data.caseSensitivityOverride : keywordList.caseSensitivity()) +{ + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const { auto newOffset = offset; - while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset))) { + while (text.size() > newOffset && !m_wordDelimiters.contains(text.at(newOffset))) { ++newOffset; } if (newOffset == offset) { return offset; } - if (m_hasCaseSensitivityOverride) { - if (m_keywordList->contains(text.mid(offset, newOffset - offset), m_caseSensitivityOverride)) { - return newOffset; - } - } else { - if (m_keywordList->contains(text.mid(offset, newOffset - offset))) { - return newOffset; - } + if (m_keywordList.contains(text.mid(offset, newOffset - offset), m_caseSensitivity)) { + return newOffset; } // we don't match, but we can skip until newOffset as we can't start a keyword in-between return MatchResult(offset, newOffset); } -bool LineContinue::doLoad(QXmlStreamReader &reader) +LineContinue::LineContinue(const HighlightingContextData::Rule::LineContinue &data) + : m_char(data.char1) { - const auto s = reader.attributes().value(QLatin1String("char")); - if (s.isEmpty()) { - m_char = QLatin1Char('\\'); - } else { - m_char = s.at(0); - } - return true; } MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const @@ -630,16 +550,10 @@ MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringLis return offset; } -bool RangeDetect::doLoad(QXmlStreamReader &reader) +RangeDetect::RangeDetect(const HighlightingContextData::Rule::RangeDetect &data) + : m_begin(data.begin) + , m_end(data.end) { - const auto s1 = reader.attributes().value(QLatin1String("char")); - const auto s2 = reader.attributes().value(QLatin1String("char1")); - if (s1.isEmpty() || s2.isEmpty()) { - return false; - } - m_begin = s1.at(0); - m_end = s2.at(0); - return true; } MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const @@ -661,25 +575,20 @@ MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList return offset; } -bool RegExpr::doLoad(QXmlStreamReader &reader) +RegExpr::RegExpr(const HighlightingContextData::Rule::RegExpr &data) { - m_regexp.setPattern(reader.attributes().value(QLatin1String("String")).toString()); - - const auto isMinimal = Xml::attrToBool(reader.attributes().value(QLatin1String("minimal"))); - const auto isCaseInsensitive = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))); - m_regexp.setPatternOptions((isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) - | (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption) + m_regexp.setPattern(data.pattern); + m_regexp.setPatternOptions((data.isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) + | (data.caseSensitivity == Qt::CaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption) // DontCaptureOption is removed by resolvePostProcessing() when necessary | QRegularExpression::DontCaptureOption // ensure Unicode support is enabled | QRegularExpression::UseUnicodePropertiesOption); - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - - return !m_regexp.pattern().isEmpty(); + m_dynamic = data.dynamic; } -void KSyntaxHighlighting::RegExpr::resolvePostProcessing() +void RegExpr::resolvePostProcessing() { if (m_isResolved) { return; @@ -728,11 +637,7 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca /** * match the pattern */ -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 2) - const auto result = regexp.match(text.toString(), offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); -#else const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption); -#endif if (result.capturedStart() == offset) { /** * we only need to compute the captured texts if we have real capture groups @@ -756,33 +661,39 @@ MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &ca return MatchResult(offset, result.capturedStart()); } -bool StringDetect::doLoad(QXmlStreamReader &reader) +StringDetect::StringDetect(const HighlightingContextData::Rule::StringDetect &data) + : m_string(data.string) + , m_caseSensitivity(data.caseSensitivity) { - m_string = reader.attributes().value(QLatin1String("String")).toString(); - m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - m_dynamic = Xml::attrToBool(reader.attributes().value(QLatin1String("dynamic"))); - return !m_string.isEmpty(); } -MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const +MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &) const +{ + return matchString(m_string, text, offset, m_caseSensitivity); +} + +DynamicStringDetect::DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data) + : m_string(data.string) + , m_caseSensitivity(data.caseSensitivity) +{ + m_dynamic = true; +} + +MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const { /** * for dynamic case: create new pattern with right instantiation */ - const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string; - - if (offset + pattern.size() <= text.size() && text.mid(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0) { - return offset + pattern.size(); - } - return offset; + const auto pattern = replaceCaptures(m_string, captures, false); + return matchString(pattern, text, offset, m_caseSensitivity); } -bool WordDetect::doLoad(QXmlStreamReader &reader) +WordDetect::WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data) + : m_wordDelimiters(def.wordDelimiters) + , m_word(data.word) + , m_caseSensitivity(data.caseSensitivity) { - m_word = reader.attributes().value(QLatin1String("String")).toString(); - m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive; - loadAdditionalWordDelimiters(reader); - return !m_word.isEmpty(); + resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters); } MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const @@ -795,7 +706,7 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList * detect delimiter characters on the inner and outer boundaries of the string * NOTE: m_word isn't empty */ - if (offset > 0 && !isWordDelimiter(text.at(offset - 1)) && !isWordDelimiter(text.at(offset))) { + if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1)) && !m_wordDelimiters.contains(text.at(offset))) { return offset; } @@ -803,7 +714,8 @@ MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList return offset; } - if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())) || isWordDelimiter(text.at(offset + m_word.size() - 1))) { + if (text.size() == offset + m_word.size() || m_wordDelimiters.contains(text.at(offset + m_word.size())) + || m_wordDelimiters.contains(text.at(offset + m_word.size() - 1))) { return offset + m_word.size(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h index 374eb87dfaf..faf2a97f484 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h @@ -9,25 +9,24 @@ #define KSYNTAXHIGHLIGHTING_RULE_P_H #include "contextswitch_p.h" -#include "definition.h" #include "definitionref_p.h" #include "foldingregion.h" #include "format.h" +#include "highlightingdata_p.hpp" #include "keywordlist_p.h" #include "matchresult_p.h" +#include "worddelimiters_p.h" #include #include #include -QT_BEGIN_NAMESPACE -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class WordDelimiters; +class DefinitionData; +class IncludeRules; class Rule { @@ -37,9 +36,6 @@ public: typedef std::shared_ptr Ptr; - Definition definition() const; - void setDefinition(const Definition &def); - const Format &attributeFormat() const { return m_attributeFormat; @@ -80,51 +76,51 @@ public: return m_endRegion; } - bool load(QXmlStreamReader &reader); - void resolveContext(); - void resolveAttributeFormat(Context *lookupContext); + const IncludeRules *castToIncludeRules() const; + + bool isLineContinue() const + { + return m_type == Type::LineContinue; + } + virtual void resolvePostProcessing() { } virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0; - static Rule::Ptr create(QStringView name); - -protected: - virtual bool doLoad(QXmlStreamReader &reader); - - bool isWordDelimiter(QChar c) const; - - void loadAdditionalWordDelimiters(QXmlStreamReader &reader); + static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName); private: Q_DISABLE_COPY(Rule) - DefinitionRef m_def; - QString m_attribute; + bool resolveCommon(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName); + + enum class Type : quint8 { + OtherRule, + LineContinue, + IncludeRules, + }; + Format m_attributeFormat; ContextSwitch m_context; int m_column = -1; FoldingRegion m_beginRegion; FoldingRegion m_endRegion; + Type m_type; bool m_firstNonSpace = false; bool m_lookAhead = false; - // cache for DefinitionData::wordDelimiters, is accessed VERY often - WordDelimiters *m_wordDelimiters = nullptr; - - QString m_additionalDeliminator; - QString m_weakDeliminator; - protected: bool m_dynamic = false; }; class AnyChar final : public Rule { +public: + AnyChar(const HighlightingContextData::Rule::AnyChar &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -133,20 +129,24 @@ private: class DetectChar final : public Rule { +public: + DetectChar(const HighlightingContextData::Rule::DetectChar &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_char; int m_captureIndex = 0; }; -class Detect2Char final : public Rule +class Detect2Chars final : public Rule { +public: + Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QChar m_char1; @@ -167,33 +167,49 @@ protected: class Float final : public Rule { +public: + Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class IncludeRules final : public Rule { public: - QString contextName() const; - QString definitionName() const; - bool includeAttribute() const; + IncludeRules(const HighlightingContextData::Rule::IncludeRules &data); + + const QString &contextName() const + { + return m_contextName; + } + + bool includeAttribute() const + { + return m_includeAttribute; + } protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_contextName; - QString m_defName; bool m_includeAttribute; }; class Int final : public Rule { +public: + Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCChar final : public Rule @@ -204,16 +220,26 @@ protected: class HlCHex final : public Rule { +public: + HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCOct final : public Rule { +public: + HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + WordDelimiters m_wordDelimiters; }; class HlCStringChar final : public Rule @@ -224,20 +250,26 @@ protected: class KeywordListRule final : public Rule { +public: + KeywordListRule(const KeywordList &keywordList, DefinitionData &def, const HighlightingContextData::Rule::Keyword &data); + + static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: - KeywordList *m_keywordList; - bool m_hasCaseSensitivityOverride; - Qt::CaseSensitivity m_caseSensitivityOverride; + WordDelimiters m_wordDelimiters; + const KeywordList &m_keywordList; + Qt::CaseSensitivity m_caseSensitivity; }; class LineContinue final : public Rule { +public: + LineContinue(const HighlightingContextData::Rule::LineContinue &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -246,8 +278,10 @@ private: class RangeDetect final : public Rule { +public: + RangeDetect(const HighlightingContextData::Rule::RangeDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: @@ -257,10 +291,12 @@ private: class RegExpr final : public Rule { +public: + RegExpr(const HighlightingContextData::Rule::RegExpr &data); + protected: + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; void resolvePostProcessing() override; - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; private: QRegularExpression m_regexp; @@ -269,9 +305,24 @@ private: class StringDetect final : public Rule { +public: + StringDetect(const HighlightingContextData::Rule::StringDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; + +private: + QString m_string; + Qt::CaseSensitivity m_caseSensitivity; +}; + +class DynamicStringDetect final : public Rule +{ +public: + DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data); + +protected: + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: QString m_string; @@ -280,11 +331,14 @@ private: class WordDetect final : public Rule { +public: + WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data); + protected: - bool doLoad(QXmlStreamReader &reader) override; - MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const override; + MatchResult doMatch(QStringView text, int offset, const QStringList &) const override; private: + WordDelimiters m_wordDelimiters; QString m_word; Qt::CaseSensitivity m_caseSensitivity; }; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp index 98daff19d6e..ab62f88b7e3 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp @@ -9,7 +9,6 @@ using namespace KSyntaxHighlighting; #include -#include namespace { diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp index f9079ea1f3d..c5401a57cc9 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp @@ -12,15 +12,14 @@ WordDelimiters::WordDelimiters() : asciiDelimiters{} { for (const char *p = "\t !%&()*+,-./:;<=>?[\\]^{|}~"; *p; ++p) { - // int(*p) fix -Wchar-subscripts - asciiDelimiters[int(*p)] = true; + asciiDelimiters.set(*p); } } bool WordDelimiters::contains(QChar c) const { if (c.unicode() < 128) { - return asciiDelimiters[c.unicode()]; + return asciiDelimiters.test(c.unicode()); } // perf tells contains is MUCH faster than binary search here, very short array return notAsciiDelimiters.contains(c); @@ -30,7 +29,7 @@ void WordDelimiters::append(QStringView s) { for (QChar c : s) { if (c.unicode() < 128) { - asciiDelimiters[c.unicode()] = true; + asciiDelimiters.set(c.unicode()); } else { notAsciiDelimiters.append(c); } @@ -41,7 +40,7 @@ void WordDelimiters::remove(QStringView s) { for (QChar c : s) { if (c.unicode() < 128) { - asciiDelimiters[c.unicode()] = false; + asciiDelimiters.set(c.unicode(), false); } else { notAsciiDelimiters.remove(c); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h index c1afaaa6bb0..ccad679a4ef 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h @@ -9,6 +9,8 @@ #include +#include + namespace KSyntaxHighlighting { /** @@ -44,7 +46,7 @@ private: * An array which represents ascii characters for very fast lookup. * The character is used as an index and the value @c true indicates a word delimiter. */ - bool asciiDelimiters[128]; + std::bitset<128> asciiDelimiters; /** * Contains characters that are not ascii and is empty for most syntax definition. diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index aee880b4ddb..b4ef8af90cd 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -42,8 +42,8 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt) #qtc_enable_separate_debug_info(qlitehtml "${IDE_LIBRARY_PATH}") qtc_output_binary_dir(_output_binary_dir) set_target_properties(qlitehtml PROPERTIES - BUILD_RPATH "${_LIB_RPATH}" - INSTALL_RPATH "${_LIB_RPATH}" + BUILD_RPATH "${_LIB_RPATH};${CMAKE_BUILD_RPATH}" + INSTALL_RPATH "${_LIB_RPATH};${CMAKE_INSTALL_RPATH}" RUNTIME_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_BIN_PATH}" LIBRARY_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_PATH}" ARCHIVE_OUTPUT_DIRECTORY "${_output_binary_dir}/${IDE_LIBRARY_ARCHIVE_PATH}" diff --git a/src/libs/qmljs/parser/qmljsast_p.h b/src/libs/qmljs/parser/qmljsast_p.h index 78b9f4b0800..50ab370922a 100644 --- a/src/libs/qmljs/parser/qmljsast_p.h +++ b/src/libs/qmljs/parser/qmljsast_p.h @@ -43,9 +43,11 @@ #include -QT_QML_BEGIN_NAMESPACE - +QT_BEGIN_NAMESPACE class QString; +QT_END_NAMESPACE + +QT_QML_BEGIN_NAMESPACE namespace QmlJS { class Parser; diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index 03ca0eda6d8..bf3d1c0989d 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -90,7 +90,7 @@ if (_library_enabled) extend_qtc_library(qtcreatorcdbext DEPENDS "${Python3_LIBRARIES}" INCLUDES "${Python3_INCLUDE_DIRS}" - DEFINES WITH_PYTHON=1 + DEFINES WITH_PYTHON=1 PY_SSIZE_T_CLEAN SOURCES pycdbextmodule.cpp pycdbextmodule.h pyfield.cpp pyfield.h diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs index fac2f7a25b7..91e91bc8514 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs @@ -87,7 +87,7 @@ QtcLibrary { Properties { condition: pythonDllProbe.found - cpp.defines: ["WITH_PYTHON=1"] + cpp.defines: ["WITH_PYTHON=1", "PY_SSIZE_T_CLEAN"] } cpp.includePaths: { if (pythonDllProbe.found) diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp index bbfec939eba..0cb916acf13 100644 --- a/src/libs/ssh/sshremoteprocess.cpp +++ b/src/libs/ssh/sshremoteprocess.cpp @@ -60,8 +60,6 @@ SshRemoteProcess::SshRemoteProcess(const QString &command, const QStringList &co QString error; if (exitStatus() == QProcess::CrashExit) error = tr("The ssh process crashed: %1").arg(errorString()); - else if (exitCode() == 255) - error = tr("Remote process crashed."); emit done(error); }); connect(this, &QtcProcess::errorOccurred, [this](QProcess::ProcessError error) { diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 07f57bfa455..05839823188 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -310,6 +310,7 @@ public: DSerrorColor, DSwarningColor, DSdisabledColor, + DSinteractionHover, DScontrolBackground, DScontrolBackgroundInteraction, DScontrolBackgroundDisabled, diff --git a/src/plugins/bookmarks/bookmarkfilter.cpp b/src/plugins/bookmarks/bookmarkfilter.cpp index 28173ffe5d1..594b18e11c9 100644 --- a/src/plugins/bookmarks/bookmarkfilter.cpp +++ b/src/plugins/bookmarks/bookmarkfilter.cpp @@ -124,7 +124,7 @@ QList BookmarkFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp index ced0fafa76e..47b4803f894 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.cpp @@ -135,7 +135,7 @@ QList ClangCurrentDocumentFilter::matchesFor( return goodEntries; } -void ClangCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, +void ClangCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *, int *, int *) const { if (!m_currentEditor) diff --git a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h index 599bbd2d59b..c60d20630f8 100644 --- a/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h +++ b/src/plugins/clangcodemodel/clangcurrentdocumentfilter.h @@ -42,7 +42,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 89271c75464..f7bf79b1166 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -1095,6 +1095,7 @@ class MemoryUsageWidget : public QWidget Q_DECLARE_TR_FUNCTIONS(MemoryUsageWidget) public: MemoryUsageWidget(ClangdClient *client); + ~MemoryUsageWidget(); private: void setupUi(); @@ -1103,6 +1104,7 @@ private: ClangdClient * const m_client; MemoryTreeModel * const m_model; Utils::TreeView m_view; + Utils::optional m_currentRequest; }; class ClangdClient::Private @@ -1161,6 +1163,7 @@ public: std::unordered_map highlighters; QHash, int>> previousTokens; + QHash parserConfigs; // The ranges of symbols referring to virtual functions, with document version, // as extracted by the highlighting procedure. @@ -1534,6 +1537,7 @@ void ClangdClient::handleDocumentClosed(TextDocument *doc) d->astCache.remove(doc); d->previousTokens.remove(doc); d->virtualRanges.remove(doc); + d->parserConfigs.remove(doc->filePath()); } QTextCursor ClangdClient::adjustedCursorForHighlighting(const QTextCursor &cursor, @@ -1697,6 +1701,39 @@ void ClangdClient::handleUiHeaderChange(const QString &fileName) } } +void ClangdClient::updateParserConfig(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config) +{ + if (config.preferredProjectPartId.isEmpty()) + return; + + CppEditor::BaseEditorDocumentParser::Configuration &cachedConfig = d->parserConfigs[filePath]; + if (cachedConfig == config) + return; + cachedConfig = config; + + // TODO: Also handle editorDefines (and usePrecompiledHeaders?) + const auto projectPart = CppEditor::CppModelManager::instance() + ->projectPartForId(config.preferredProjectPartId); + if (!projectPart) + return; + const CppEditor::ClangDiagnosticConfig projectWarnings = warningsConfigForProject(project()); + const QStringList projectOptions = optionsForProject(project()); + QJsonObject cdbChanges; + QStringList args = createClangOptions(*projectPart, filePath.toString(), projectWarnings, + projectOptions); + args.prepend("clang"); + args.append(filePath.toString()); + QJsonObject value; + value.insert("workingDirectory", filePath.parentDir().toString()); + value.insert("compilationCommand", QJsonArray::fromStringList(args)); + cdbChanges.insert(filePath.toUserOutput(), value); + const QJsonObject settings({qMakePair(QString("compilationDatabaseChanges"), cdbChanges)}); + DidChangeConfigurationParams configChangeParams; + configChangeParams.setSettings(settings); + sendContent(DidChangeConfigurationNotification(configChangeParams)); +} + void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList &locations) { const auto refData = runningFindUsages.find(key); @@ -2604,7 +2641,7 @@ private: // clangd reports also the #ifs, #elses and #endifs around the disabled code as disabled, // and not even in a consistent manner. We don't want this, so we have to clean up here. // But note that we require this behavior, as otherwise we would not be able to grey out -// e.g. empty lines after an #fdef, due to the lack of symbols. +// e.g. empty lines after an #ifdef, due to the lack of symbols. static QList cleanupDisabledCode(HighlightingResults &results, const QTextDocument *doc, const QString &docContent) { @@ -2630,8 +2667,13 @@ static QList cleanupDisabledCode(HighlightingResults &results, const && !content.startsWith(QLatin1String("#elif")) && !content.startsWith(QLatin1String("#else")) && !content.startsWith(QLatin1String("#endif"))) { - ++it; - continue; + static const QStringList ppSuffixes{"if", "ifdef", "elif", "else", "endif"}; + const QList contentList = content.split(' ', Qt::SkipEmptyParts); + if (contentList.size() < 2 || contentList.first() != QLatin1String("#") + || !ppSuffixes.contains(contentList.at(1))) { + ++it; + continue; + } } if (!wasIfdefedOut) { @@ -2643,7 +2685,8 @@ static QList cleanupDisabledCode(HighlightingResults &results, const } if (wasIfdefedOut && (it + 1 == results.end() - || (it + 1)->textStyles.mainStyle != C_DISABLED_CODE)) { + || (it + 1)->textStyles.mainStyle != C_DISABLED_CODE + || (it + 1)->line != it->line + 1)) { // The #else or #endif that ends disabled code should not be disabled. const QTextBlock block = doc->findBlockByNumber(it->line - 1); ifdefedOutRanges << BlockRange(rangeStartPos, block.position()); @@ -3261,7 +3304,8 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, QTextCursor cursor = manipulator.textCursorAt(rangeStart); cursor.movePosition(QTextCursor::EndOfWord); const QString textAfterCursor = manipulator.textAt(currentPos, cursor.position() - currentPos); - if (textToBeInserted != textAfterCursor + if (currentPos < cursor.position() + && textToBeInserted != textAfterCursor && textToBeInserted.indexOf(textAfterCursor, currentPos - rangeStart) >= 0) { currentPos = cursor.position(); } @@ -4033,6 +4077,12 @@ MemoryUsageWidget::MemoryUsageWidget(ClangdClient *client) getMemoryTree(); } +MemoryUsageWidget::~MemoryUsageWidget() +{ + if (m_currentRequest.has_value()) + m_client->cancelRequest(m_currentRequest.value()); +} + void MemoryUsageWidget::setupUi() { const auto layout = new QVBoxLayout(this); @@ -4052,11 +4102,13 @@ void MemoryUsageWidget::getMemoryTree() { Request request("$/memoryUsage", {}); request.setResponseCallback([this](decltype(request)::Response response) { + m_currentRequest.reset(); qCDebug(clangdLog) << "received memory usage response"; if (const auto result = response.result()) m_model->update(*result); }); qCDebug(clangdLog) << "sending memory usage request"; + m_currentRequest = request.id(); m_client->sendContent(request, ClangdClient::SendDocUpdates::Ignore); } diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 2e4f1517002..7c9135a0c57 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -25,6 +25,7 @@ #pragma once +#include #include #include #include @@ -90,6 +91,9 @@ public: static void handleUiHeaderChange(const QString &fileName); + void updateParserConfig(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config); + signals: void indexingFinished(); void foundReferences(const QList &items); diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp index cafd7633d7d..6aa5d1e9703 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.cpp @@ -198,7 +198,7 @@ QList ClangGlobalSymbolFilter::matchesFor( return matches; } -void ClangGlobalSymbolFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void ClangGlobalSymbolFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { if (qvariant_cast(selection.internalData)) @@ -318,7 +318,7 @@ QList ClangdCurrentDocumentFilter::matchesFor( return d->activeFilter->matchesFor(future, entry); } -void ClangdCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void ClangdCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { QTC_ASSERT(d->activeFilter, return); diff --git a/src/plugins/clangcodemodel/clangdlocatorfilters.h b/src/plugins/clangcodemodel/clangdlocatorfilters.h index 28341a6a573..bf3f6792820 100644 --- a/src/plugins/clangcodemodel/clangdlocatorfilters.h +++ b/src/plugins/clangcodemodel/clangdlocatorfilters.h @@ -41,7 +41,7 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; Core::ILocatorFilter * const m_cppFilter; @@ -70,7 +70,7 @@ private: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; class Private; diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 2461120d9af..1b2027139f1 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -328,6 +328,12 @@ void ClangEditorDocumentProcessor::setParserConfig( { m_parser->setConfiguration(config); m_builtinProcessor.parser()->setConfiguration(config); + emit parserConfigChanged(Utils::FilePath::fromString(filePath()), config); +} + +CppEditor::BaseEditorDocumentParser::Configuration ClangEditorDocumentProcessor::parserConfig() const +{ + return m_parser->configuration(); } static bool isCursorOnIdentifier(const QTextCursor &textCursor) diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 532c134b40b..7111eee4c80 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -91,6 +91,7 @@ public: void editorDocumentTimerRestarted() override; void setParserConfig(const CppEditor::BaseEditorDocumentParser::Configuration &config) override; + CppEditor::BaseEditorDocumentParser::Configuration parserConfig() const; QFuture cursorInfo(const CppEditor::CursorInfoParams ¶ms) override; QFuture requestLocalReferences(const QTextCursor &cursor) override; @@ -115,6 +116,8 @@ public: signals: void tokenInfosUpdated(); + void parserConfigChanged(const Utils::FilePath &filePath, + const CppEditor::BaseEditorDocumentParser::Configuration &config); private: void onParserFinished(); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 1b6a1042321..7daf90aa540 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -218,7 +218,15 @@ bool ClangModelManagerSupport::supportsLocalUses(const TextEditor::TextDocument CppEditor::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) { - return new ClangEditorDocumentProcessor(m_communicator, baseTextDocument); + const auto processor = new ClangEditorDocumentProcessor(m_communicator, baseTextDocument); + const auto handleConfigChange = [this](const Utils::FilePath &fp, + const BaseEditorDocumentParser::Configuration &config) { + if (const auto client = clientForFile(fp)) + client->updateParserConfig(fp, config); + }; + connect(processor, &ClangEditorDocumentProcessor::parserConfigChanged, + this, handleConfigChange); + return processor; } void ClangModelManagerSupport::onCurrentEditorChanged(Core::IEditor *editor) @@ -234,6 +242,8 @@ void ClangModelManagerSupport::onCurrentEditorChanged(Core::IEditor *editor) if (auto processor = ClangEditorDocumentProcessor::get(filePath.toString())) { processor->semanticRehighlight(); processor->generateTaskHubIssues(); + if (const auto client = clientForFile(filePath)) + client->updateParserConfig(filePath, processor->parserConfig()); } } @@ -343,16 +353,38 @@ void ClangModelManagerSupport::updateLanguageClient( if (!newProjectInfo || *newProjectInfo != *projectInfo) return; + const auto updateParserConfig = [client] { + if (const auto editor = TextEditor::BaseTextEditor::currentTextEditor()) { + if (!client->documentOpen(editor->textDocument())) + return; + const Utils::FilePath filePath = editor->textDocument()->filePath(); + if (const auto processor = ClangEditorDocumentProcessor::get( + filePath.toString())) { + const CppEditor::BaseEditorDocumentParser::Configuration config + = processor->parserConfig(); + client->updateParserConfig(filePath, config); + } + } + }; + // Acquaint the client with all open C++ documents for this project. bool hasDocuments = false; for (TextEditor::BaseTextEditor * const editor : allCppEditors()) { - if (!project->isKnownFile(editor->textDocument()->filePath())) + const Utils::FilePath filePath = editor->textDocument()->filePath(); + if (!project->isKnownFile(filePath)) continue; LanguageClientManager::openDocumentWithClient(editor->textDocument(), client); - ClangEditorDocumentProcessor::clearTextMarks(editor->textDocument()->filePath()); + ClangEditorDocumentProcessor::clearTextMarks(filePath); hasDocuments = true; } + if (client->state() == Client::Initialized) + updateParserConfig(); + else + connect(client, &Client::initialized, client, updateParserConfig); + connect(CppModelManager::instance(), &CppModelManager::projectPartsUpdated, + client, updateParserConfig); + if (hasDocuments) return; diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 36217ad8d76..6ed6163a6bd 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -675,6 +675,8 @@ void ClangdTestHighlighting::initTestCase() { ClangdTest::initTestCase(); + connect(document("highlighting.cpp"), &TextDocument::ifdefedOutBlocksChanged, this, + [this](const QList &ranges) { m_ifdefedOutBlocks = ranges; }); QTimer timer; timer.setSingleShot(true); QEventLoop loop; @@ -1380,6 +1382,17 @@ void ClangdTestHighlighting::test() QCOMPARE(result.kind, expectedKind); } +void ClangdTestHighlighting::testIfdefedOutBlocks() +{ + QCOMPARE(m_ifdefedOutBlocks.size(), 3); + QCOMPARE(m_ifdefedOutBlocks.at(0).first(), 12033); + QCOMPARE(m_ifdefedOutBlocks.at(0).last(), 12050); + QCOMPARE(m_ifdefedOutBlocks.at(1).first(), 13351); + QCOMPARE(m_ifdefedOutBlocks.at(1).last(), 13364); + QCOMPARE(m_ifdefedOutBlocks.at(2).first(), 13390); + QCOMPARE(m_ifdefedOutBlocks.at(2).last(), 13402); +} + class Manipulator : public TextDocumentManipulatorInterface { diff --git a/src/plugins/clangcodemodel/test/clangdtests.h b/src/plugins/clangcodemodel/test/clangdtests.h index b6399a9c59f..66f41cfa156 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.h +++ b/src/plugins/clangcodemodel/test/clangdtests.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -141,9 +142,11 @@ private slots: void initTestCase() override; void test_data(); void test(); + void testIfdefedOutBlocks(); private: TextEditor::HighlightingResults m_results; + QList m_ifdefedOutBlocks; }; class ClangdTestCompletion : public ClangdTest diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp index 46112c2f136..7ebc39d433f 100644 --- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp +++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp @@ -869,3 +869,14 @@ void constMemberAsFunctionArg() const Foo &constMember; }; } + +# if 0 +#define FOO + +#endif + +// comment + +#if 0 +#define BAR +# endif diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index fa95514ca32..d9e36e3717a 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "clangformatbaseindenter.h" +#include "clangformatutils.h" #include @@ -728,14 +729,16 @@ clang::format::FormatStyle ClangFormatBaseIndenter::styleForFile() const { llvm::Expected style = clang::format::getStyle("file", m_fileName.toString().toStdString(), "none"); - if (style) + if (style) { + addQtcStatementMacros(*style); return *style; + } handleAllErrors(style.takeError(), [](const llvm::ErrorInfoBase &) { // do nothing }); - return clang::format::getLLVMStyle(); + return qtcStyle(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index ff184ea737c..e59a151f0b2 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -46,7 +47,7 @@ using namespace Utils; namespace ClangFormat { -static clang::format::FormatStyle qtcStyle() +clang::format::FormatStyle qtcStyle() { clang::format::FormatStyle style = getLLVMStyle(); style.Language = FormatStyle::LK_Cpp; @@ -355,18 +356,38 @@ clang::format::FormatStyle styleForFile(Utils::FilePath fileName) return styleForFile(fileName, true); } +void addQtcStatementMacros(clang::format::FormatStyle &style) +{ + static const std::vector macros = {"Q_OBJECT", + "QT_BEGIN_NAMESPACE", + "QT_END_NAMESPACE"}; + for (const std::string ¯o : macros) { + if (std::find(style.StatementMacros.begin(), style.StatementMacros.end(), macro) + == style.StatementMacros.end()) + style.StatementMacros.emplace_back(macro); + } +} + static std::string readFile(const QString &path) { + const std::string defaultStyle = clang::format::configurationAsText(qtcStyle()); + QFile file(path); - if (!file.open(QFile::ReadOnly)) { - clang::format::FormatStyle defaultStyle = qtcStyle(); - return clang::format::configurationAsText(defaultStyle); - } + if (!file.open(QFile::ReadOnly)) + return defaultStyle; const QByteArray content = file.readAll(); file.close(); - return content.toStdString(); + clang::format::FormatStyle style; + style.Language = clang::format::FormatStyle::LK_Cpp; + const std::error_code error = clang::format::parseConfiguration(content.toStdString(), &style); + + QTC_ASSERT(error.value() == static_cast(ParseError::Success), return defaultStyle); + + addQtcStatementMacros(style); + + return clang::format::configurationAsText(style); } std::string currentProjectConfigText() diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 74fd84c9c6b..3caf6c9d6fc 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -51,4 +51,6 @@ clang::format::FormatStyle currentGlobalStyle(); QString configForFile(Utils::FilePath fileName); clang::format::FormatStyle styleForFile(Utils::FilePath fileName); +void addQtcStatementMacros(clang::format::FormatStyle &style); +clang::format::FormatStyle qtcStyle(); } diff --git a/src/plugins/clangformat/tests/clangformat-test.cpp b/src/plugins/clangformat/tests/clangformat-test.cpp index 3bef6506795..bc5e07328df 100644 --- a/src/plugins/clangformat/tests/clangformat-test.cpp +++ b/src/plugins/clangformat/tests/clangformat-test.cpp @@ -646,4 +646,12 @@ void ClangFormatTest::testCommentBlock() "****************************************************************************/"})); } +void ClangFormatTest::testClassIndentStructure() +{ + insertLines({"class test {", " Q_OBJECT", " public:", "};"}); + m_indenter->indent(*m_cursor, QChar::Null, TextEditor::TabSettings()); + QCOMPARE(documentLines(), + (std::vector{"class test {", " Q_OBJECT", "public:", "};"})); +} + } // namespace ClangFormat::Internal diff --git a/src/plugins/clangformat/tests/clangformat-test.h b/src/plugins/clangformat/tests/clangformat-test.h index e34a1491168..094657d1b01 100644 --- a/src/plugins/clangformat/tests/clangformat-test.h +++ b/src/plugins/clangformat/tests/clangformat-test.h @@ -109,6 +109,7 @@ private slots: void testSortIncludes(); void testChainedMemberFunctionCalls(); void testCommentBlock(); + void testClassIndentStructure(); private: void insertLines(const std::vector &lines); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index 0acbd3ddc27..46a0c0e54d5 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -102,7 +102,7 @@ const char DEVELOPMENT_TEAM_FLAG[] = "Ios:DevelopmentTeam:Flag"; const char PROVISIONING_PROFILE_FLAG[] = "Ios:ProvisioningProfile:Flag"; const char CMAKE_OSX_ARCHITECTURES_FLAG[] = "CMAKE_OSX_ARCHITECTURES:DefaultFlag"; const char CMAKE_QT6_TOOLCHAIN_FILE_ARG[] = - "-DCMAKE_TOOLCHAIN_FILE:PATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake"; + "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=%{Qt:QT_INSTALL_PREFIX}/lib/cmake/Qt6/qt.toolchain.cmake"; namespace Internal { @@ -121,8 +121,8 @@ private: void updateAdvancedCheckBox(); void updateFromKit(); void updateConfigurationStateIndex(int index); - CMakeProjectManager::CMakeConfig getQmlDebugCxxFlags(); - CMakeProjectManager::CMakeConfig getSigningFlagsChanges(); + CMakeConfig getQmlDebugCxxFlags(); + CMakeConfig getSigningFlagsChanges(); void updateSelection(); void updateConfigurationStateSelection(); @@ -639,6 +639,7 @@ void CMakeBuildSettingsWidget::kitCMakeConfiguration() dialog->setWindowTitle(tr("Kit CMake Configuration")); dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setModal(true); + dialog->setSizeGripEnabled(true); connect(dialog, &QDialog::finished, this, [=]{ m_buildConfiguration->kit()->unblockNotification(); }); @@ -658,6 +659,12 @@ void CMakeBuildSettingsWidget::kitCMakeConfiguration() layout->setColumnStretch(1, 1); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttons, &QDialogButtonBox::clicked, dialog, &QDialog::close); + layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Maximum, QSizePolicy::MinimumExpanding), + 4, 0); + layout->addWidget(buttons, 5, 0, 1, -1); + dialog->setMinimumWidth(400); dialog->resize(800, 1); dialog->show(); @@ -695,19 +702,19 @@ void CMakeBuildSettingsWidget::updateButtonState() ni.inCMakeCache = i.inCMakeCache; ni.values = i.values; switch (i.type) { - case CMakeProjectManager::ConfigModel::DataItem::BOOLEAN: + case ConfigModel::DataItem::BOOLEAN: ni.type = CMakeConfigItem::BOOL; break; - case CMakeProjectManager::ConfigModel::DataItem::FILE: + case ConfigModel::DataItem::FILE: ni.type = CMakeConfigItem::FILEPATH; break; - case CMakeProjectManager::ConfigModel::DataItem::DIRECTORY: + case ConfigModel::DataItem::DIRECTORY: ni.type = CMakeConfigItem::PATH; break; - case CMakeProjectManager::ConfigModel::DataItem::STRING: + case ConfigModel::DataItem::STRING: ni.type = CMakeConfigItem::STRING; break; - case CMakeProjectManager::ConfigModel::DataItem::UNKNOWN: + case ConfigModel::DataItem::UNKNOWN: default: ni.type = CMakeConfigItem::UNINITIALIZED; break; @@ -763,7 +770,9 @@ void CMakeBuildSettingsWidget::updateAdvancedCheckBox() void CMakeBuildSettingsWidget::updateFromKit() { const Kit *k = m_buildConfiguration->kit(); - const CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); + CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); + + config.append(CMakeGeneratorKitAspect::generatorCMakeConfig(k)); // First the key value parameters ConfigModel::KitConfiguration configHash; @@ -1056,10 +1065,11 @@ static bool isDocker(const Kit *k) static bool isWindowsARM64(const Kit *k) { ToolChain *toolchain = ToolChainKitAspect::cxxToolChain(k); - QTC_ASSERT(toolchain, return false); + if (!toolchain) + return false; const Abi targetAbi = toolchain->targetAbi(); return targetAbi.os() == Abi::WindowsOS && targetAbi.architecture() == Abi::ArmArchitecture - && targetAbi.wordWidth() == 64; + && targetAbi.wordWidth() == 64; } static CommandLine defaultInitialCMakeCommand(const Kit *k, const QString buildType) @@ -1080,7 +1090,7 @@ static CommandLine defaultInitialCMakeCommand(const Kit *k, const QString buildT // Package manager if (!isDocker(k) && settings->packageManagerAutoSetup.value()) { - cmd.addArg("-DCMAKE_PROJECT_INCLUDE_BEFORE:PATH=" + cmd.addArg("-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=" "%{IDE:ResourcePath}/package-manager/auto-setup.cmake"); } @@ -1197,7 +1207,7 @@ CMakeBuildConfiguration::CMakeBuildConfiguration(Target *target, Id id) auto ndkLocation = bs->data(Android::Constants::NdkLocation).value(); cmd.addArg("-DANDROID_NDK:PATH=" + ndkLocation.path()); - cmd.addArg("-DCMAKE_TOOLCHAIN_FILE:PATH=" + cmd.addArg("-DCMAKE_TOOLCHAIN_FILE:FILEPATH=" + ndkLocation.pathAppended("build/cmake/android.toolchain.cmake").path()); auto androidAbis = bs->data(Android::Constants::AndroidMkSpecAbis).toStringList(); @@ -1633,12 +1643,12 @@ BuildSystem *CMakeBuildConfiguration::buildSystem() const void CMakeBuildConfiguration::setSourceDirectory(const FilePath &path) { - aspect()->setValue(path.toString()); + aspect()->setFilePath(path); } FilePath CMakeBuildConfiguration::sourceDirectory() const { - return FilePath::fromString(aspect()->value()); + return aspect()->filePath(); } QString CMakeBuildConfiguration::cmakeBuildType() const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 5817ace058a..c4d2127573b 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -805,17 +805,6 @@ void CMakeBuildSystem::wireUpConnections() // At this point the entire project will be fully configured, so let's connect everything and // trigger an initial parser run - // Kit changed: - connect(KitManager::instance(), &KitManager::kitUpdated, this, [this](Kit *k) { - if (k != kit()) - return; // not for us... - // FIXME: This is no longer correct: QtC now needs to update the initial parameters - // FIXME: and then ask to reconfigure. - qCDebug(cmakeBuildSystemLog) << "Requesting parse due to kit being updated"; - setParametersAndRequestParse(BuildDirParameters(cmakeBuildConfiguration()), - CMakeBuildSystem::REPARSE_FORCE_CMAKE_RUN); - }); - // Became active/inactive: connect(target(), &Target::activeBuildConfigurationChanged, this, [this]() { // Build configuration has changed: diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp index 9347d84eccb..ad9c2277928 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.cpp @@ -51,6 +51,10 @@ CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, key(k), type(t), value(v), documentation(d), values(s) { } +CMakeConfigItem::CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &v) : + key(k), type(t), value(v) +{ } + CMakeConfigItem::CMakeConfigItem(const QByteArray &k, const QByteArray &v) : key(k), value(v) { } diff --git a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h index 10a8d8b7174..e7490562e3d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeconfigitem.h +++ b/src/plugins/cmakeprojectmanager/cmakeconfigitem.h @@ -50,6 +50,7 @@ public: enum Type { FILEPATH, PATH, BOOL, STRING, INTERNAL, STATIC, UNINITIALIZED }; CMakeConfigItem(); CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &d, const QByteArray &v, const QStringList &s = {}); + CMakeConfigItem(const QByteArray &k, Type t, const QByteArray &v); CMakeConfigItem(const QByteArray &k, const QByteArray &v); static QStringList cmakeSplitValue(const QString &in, bool keepEmpty = false); diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp index 33224d439d1..bc43f8be3ca 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.cpp @@ -660,6 +660,29 @@ QStringList CMakeGeneratorKitAspect::generatorArguments(const Kit *k) return result; } +CMakeConfig CMakeGeneratorKitAspect::generatorCMakeConfig(const ProjectExplorer::Kit *k) +{ + CMakeConfig config; + + GeneratorInfo info = generatorInfo(k); + if (info.generator.isEmpty()) + return config; + + if (info.extraGenerator.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR", info.generator.toUtf8()); + else + config << CMakeConfigItem("CMAKE_GENERATOR", + (info.extraGenerator + " - " + info.generator).toUtf8()); + + if (!info.platform.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR_PLATFORM", info.platform.toUtf8()); + + if (!info.toolset.isEmpty()) + config << CMakeConfigItem("CMAKE_GENERATOR_TOOLSET", info.toolset.toUtf8()); + + return config; +} + bool CMakeGeneratorKitAspect::isMultiConfigGenerator(const Kit *k) { const QString generator = CMakeGeneratorKitAspect::generator(k); @@ -1109,12 +1132,12 @@ CMakeConfig CMakeConfigurationKitAspect::defaultConfiguration(const Kit *k) Q_UNUSED(k) CMakeConfig config; // Qt4: - config << CMakeConfigItem(CMAKE_QMAKE_KEY, "%{Qt:qmakeExecutable}"); + config << CMakeConfigItem(CMAKE_QMAKE_KEY, CMakeConfigItem::FILEPATH, "%{Qt:qmakeExecutable}"); // Qt5: - config << CMakeConfigItem(CMAKE_PREFIX_PATH_KEY, "%{Qt:QT_INSTALL_PREFIX}"); + config << CMakeConfigItem(CMAKE_PREFIX_PATH_KEY, CMakeConfigItem::PATH, "%{Qt:QT_INSTALL_PREFIX}"); - config << CMakeConfigItem(CMAKE_C_TOOLCHAIN_KEY, "%{Compiler:Executable:C}"); - config << CMakeConfigItem(CMAKE_CXX_TOOLCHAIN_KEY, "%{Compiler:Executable:Cxx}"); + config << CMakeConfigItem(CMAKE_C_TOOLCHAIN_KEY, CMakeConfigItem::FILEPATH, "%{Compiler:Executable:C}"); + config << CMakeConfigItem(CMAKE_CXX_TOOLCHAIN_KEY, CMakeConfigItem::FILEPATH, "%{Compiler:Executable:Cxx}"); return config; } diff --git a/src/plugins/cmakeprojectmanager/cmakekitinformation.h b/src/plugins/cmakeprojectmanager/cmakekitinformation.h index 65c3a24dccd..9129f0704cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakekitinformation.h +++ b/src/plugins/cmakeprojectmanager/cmakekitinformation.h @@ -77,6 +77,7 @@ public: static void set(ProjectExplorer::Kit *k, const QString &generator, const QString &extraGenerator, const QString &platform, const QString &toolset); static QStringList generatorArguments(const ProjectExplorer::Kit *k); + static CMakeConfig generatorCMakeConfig(const ProjectExplorer::Kit *k); static bool isMultiConfigGenerator(const ProjectExplorer::Kit *k); // KitAspect interface diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp index 9364b155952..ec6d14b9b5e 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.cpp @@ -121,7 +121,7 @@ BuildCMakeTargetLocatorFilter::BuildCMakeTargetLocatorFilter() setPriority(High); } -void BuildCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection, +void BuildCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const @@ -171,7 +171,7 @@ OpenCMakeTargetLocatorFilter::OpenCMakeTargetLocatorFilter() setPriority(Medium); } -void OpenCMakeTargetLocatorFilter::accept(Core::LocatorFilterEntry selection, +void OpenCMakeTargetLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const diff --git a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h index 0749e2bb858..99cc87eca68 100644 --- a/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h +++ b/src/plugins/cmakeprojectmanager/cmakelocatorfilter.h @@ -54,7 +54,7 @@ class BuildCMakeTargetLocatorFilter : CMakeTargetLocatorFilter public: BuildCMakeTargetLocatorFilter(); - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const final; @@ -67,7 +67,7 @@ class OpenCMakeTargetLocatorFilter : CMakeTargetLocatorFilter public: OpenCMakeTargetLocatorFilter(); - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const final; diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 190ffbc9120..73f6f1e2280 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -30,17 +30,107 @@ #include #include -#include #include #include namespace CMakeProjectManager { +namespace Internal { + +// DataItem + +ConfigModel::DataItem::DataItem(const CMakeConfigItem &cmi) +{ + key = QString::fromUtf8(cmi.key); + value = QString::fromUtf8(cmi.value); + description = QString::fromUtf8(cmi.documentation); + values = cmi.values; + inCMakeCache = cmi.inCMakeCache; + + isAdvanced = cmi.isAdvanced; + isInitial = cmi.isInitial; + isHidden = cmi.type == CMakeConfigItem::INTERNAL || cmi.type == CMakeConfigItem::STATIC; + + setType(cmi.type); +} + +void ConfigModel::DataItem::setType(CMakeConfigItem::Type cmt) +{ + switch (cmt) { + case CMakeConfigItem::FILEPATH: + type = FILE; + break; + case CMakeConfigItem::PATH: + type = DIRECTORY; + break; + case CMakeConfigItem::BOOL: + type = BOOLEAN; + break; + case CMakeConfigItem::STRING: + type = STRING; + break; + default: + type = UNKNOWN; + break; + } +} + +QString ConfigModel::DataItem::typeDisplay() const +{ + switch (type) { + case DataItem::BOOLEAN: + return "BOOL"; + case DataItem::FILE: + return "FILEPATH"; + case DataItem::DIRECTORY: + return "PATH"; + case DataItem::STRING: + return "STRING"; + case DataItem::UNKNOWN: + break; + } + return "UNINITIALIZED"; +} + +CMakeConfigItem ConfigModel::DataItem::toCMakeConfigItem() const +{ + CMakeConfigItem cmi; + cmi.key = key.toUtf8(); + cmi.value = value.toUtf8(); + switch (type) { + case DataItem::BOOLEAN: + cmi.type = CMakeConfigItem::BOOL; + break; + case DataItem::FILE: + cmi.type = CMakeConfigItem::FILEPATH; + break; + case DataItem::DIRECTORY: + cmi.type = CMakeConfigItem::PATH; + break; + case DataItem::STRING: + cmi.type = CMakeConfigItem::STRING; + break; + case DataItem::UNKNOWN: + cmi.type = CMakeConfigItem::UNINITIALIZED; + break; + } + cmi.isUnset = isUnset; + cmi.isAdvanced = isAdvanced; + cmi.isInitial = isInitial; + cmi.values = values; + cmi.documentation = description.toUtf8(); + + return cmi; +} + +// ConfigModel ConfigModel::ConfigModel(QObject *parent) : Utils::TreeModel<>(parent) { setHeader({tr("Key"), tr("Value")}); } +ConfigModel::~ConfigModel() = default; + QVariant ConfigModel::data(const QModelIndex &idx, int role) const { // Hide/show groups according to "isAdvanced" setting: @@ -76,8 +166,6 @@ bool ConfigModel::setData(const QModelIndex &idx, const QVariant &data, int role return res; } -ConfigModel::~ConfigModel() = default; - void ConfigModel::appendConfiguration(const QString &key, const QString &value, const ConfigModel::DataItem::Type type, bool isInitial, @@ -454,7 +542,6 @@ QString ConfigModel::InternalDataItem::currentValue() const return isUserChanged ? newValue : value; } -namespace Internal { ConfigModelTreeItem::~ConfigModelTreeItem() = default; @@ -514,7 +601,7 @@ QVariant ConfigModelTreeItem::data(int column, int role) const case Qt::DisplayRole: if (column == 0) return dataItem->key.isEmpty() - ? QCoreApplication::translate("CMakeProjectManager::ConfigModel", "") + ? ConfigModel::tr("") : dataItem->key; return value; case Qt::EditRole: @@ -600,30 +687,28 @@ QString ConfigModelTreeItem::toolTip() const if (!dataItem->description.isEmpty()) tooltip << dataItem->description; + const QString pattern = "

%1 %2

"; if (dataItem->isInitial) { if (!dataItem->kitValue.isEmpty()) - tooltip << QCoreApplication::translate("CMakeProjectManager", "

Kit: %1

") - .arg(dataItem->kitValue); + tooltip << pattern.arg(ConfigModel::tr("Kit:")).arg(dataItem->kitValue); - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Initial Configuration: %1

") - .arg(dataItem->currentValue()); + tooltip << pattern.arg(ConfigModel::tr("Initial Configuration:")).arg(dataItem->currentValue()); } else { - if (!dataItem->initialValue.isEmpty()) - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Initial Configuration: %1

") - .arg(dataItem->initialValue); + if (!dataItem->initialValue.isEmpty()) { + tooltip << pattern.arg(ConfigModel::tr("Initial Configuration:")) + .arg(dataItem->initialValue); + } if (dataItem->inCMakeCache) { - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Current Configuration: %1

") - .arg(dataItem->currentValue()); + tooltip << pattern.arg(ConfigModel::tr("Current Configuration:")) + .arg(dataItem->currentValue()); } else { - tooltip << QCoreApplication::translate("CMakeProjectManager", - "

Not in CMakeCache.txt

"); + tooltip << pattern.arg(ConfigModel::tr("Not in CMakeCache.txt")).arg(QString()); } } - return tooltip.join(""); + tooltip << pattern.arg(ConfigModel::tr("Type:")).arg(dataItem->typeDisplay()); + + return tooltip.join(QString()); } QString ConfigModelTreeItem::currentValue() const diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 83e34d191b5..95b1ae383db 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -32,8 +32,9 @@ #include namespace CMakeProjectManager { +namespace Internal { -namespace Internal { class ConfigModelTreeItem; } +class ConfigModelTreeItem; class ConfigModel : public Utils::TreeModel<> { @@ -46,74 +47,18 @@ public: }; struct DataItem { - bool operator == (const DataItem& other) const { + bool operator==(const DataItem &other) const { return key == other.key && isInitial == other.isInitial; } DataItem() {} - DataItem(const CMakeConfigItem &cmi) { - key = QString::fromUtf8(cmi.key); - value = QString::fromUtf8(cmi.value); - description = QString::fromUtf8(cmi.documentation); - values = cmi.values; - inCMakeCache = cmi.inCMakeCache; + DataItem(const CMakeConfigItem &cmi); - isAdvanced = cmi.isAdvanced; - isInitial = cmi.isInitial; - isHidden = cmi.type == CMakeConfigItem::INTERNAL || cmi.type == CMakeConfigItem::STATIC; + void setType(CMakeConfigItem::Type cmt); - setType(cmi.type); - } + QString typeDisplay() const; - void setType(CMakeConfigItem::Type cmt) { - switch (cmt) { - case CMakeConfigItem::FILEPATH: - type = FILE; - break; - case CMakeConfigItem::PATH: - type = DIRECTORY; - break; - case CMakeConfigItem::BOOL: - type = BOOLEAN; - break; - case CMakeConfigItem::STRING: - type = STRING; - break; - default: - type = UNKNOWN; - break; - } - } - - CMakeConfigItem toCMakeConfigItem() const { - CMakeConfigItem cmi; - cmi.key = key.toUtf8(); - cmi.value = value.toUtf8(); - switch (type) { - case DataItem::BOOLEAN: - cmi.type = CMakeConfigItem::BOOL; - break; - case DataItem::FILE: - cmi.type = CMakeConfigItem::FILEPATH; - break; - case DataItem::DIRECTORY: - cmi.type = CMakeConfigItem::PATH; - break; - case DataItem::STRING: - cmi.type = CMakeConfigItem::STRING; - break; - case DataItem::UNKNOWN: - cmi.type = CMakeConfigItem::UNINITIALIZED; - break; - } - cmi.isUnset = isUnset; - cmi.isAdvanced = isAdvanced; - cmi.isInitial = isInitial; - cmi.values = values; - cmi.documentation = description.toUtf8(); - - return cmi; - } + CMakeConfigItem toCMakeConfigItem() const; enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN}; @@ -198,8 +143,6 @@ private: friend class Internal::ConfigModelTreeItem; }; -namespace Internal { - class ConfigModelTreeItem : public Utils::TreeItem { public: diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp index cacea4cb855..c09a6cd0d56 100644 --- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.cpp @@ -33,6 +33,7 @@ #include namespace CMakeProjectManager { +namespace Internal { ConfigModelItemDelegate::ConfigModelItemDelegate(const Utils::FilePath &base, QObject* parent) : QStyledItemDelegate(parent) @@ -131,8 +132,8 @@ void ConfigModelItemDelegate::setModelData(QWidget *editor, QAbstractItemModel * QStyledItemDelegate::setModelData(editor, model, index); } -QSize CMakeProjectManager::ConfigModelItemDelegate::sizeHint(const QStyleOptionViewItem &option, - const QModelIndex &index) const +QSize ConfigModelItemDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const { static int height = -1; if (height < 0) { @@ -154,5 +155,6 @@ QSize CMakeProjectManager::ConfigModelItemDelegate::sizeHint(const QStyleOptionV return QSize(100, height); } +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h index 1c6d5927918..f6cacd57614 100644 --- a/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h +++ b/src/plugins/cmakeprojectmanager/configmodelitemdelegate.h @@ -32,6 +32,7 @@ #include namespace CMakeProjectManager { +namespace Internal { class ConfigModelItemDelegate : public QStyledItemDelegate { @@ -51,4 +52,5 @@ private: Utils::FilePath m_base; }; +} // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/coreplugin/find/finddialog.ui b/src/plugins/coreplugin/find/finddialog.ui index 4ccc2c99202..bcd64728b4e 100644 --- a/src/plugins/coreplugin/find/finddialog.ui +++ b/src/plugins/coreplugin/find/finddialog.ui @@ -57,7 +57,7 @@ - Sear&ch for: + Search f&or: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -132,7 +132,7 @@ - Case &sensitive + &Case sensitive diff --git a/src/plugins/coreplugin/find/findtoolbar.cpp b/src/plugins/coreplugin/find/findtoolbar.cpp index f7345f28c9c..ccfd99e9859 100644 --- a/src/plugins/coreplugin/find/findtoolbar.cpp +++ b/src/plugins/coreplugin/find/findtoolbar.cpp @@ -437,6 +437,8 @@ void FindToolBar::updateToolBar() m_ui.findPreviousButton->setVisible(showAllControls); m_ui.findNextButton->setEnabled(enabled); m_ui.findNextButton->setVisible(showAllControls); + m_ui.selectAllButton->setVisible(style == ControlStyle::Text + && m_currentDocumentFind->supportsSelectAll()); m_ui.horizontalSpacer->changeSize((showAllControls ? FINDBUTTON_SPACER_WIDTH : 0), 0, QSizePolicy::Expanding, QSizePolicy::Ignored); m_ui.findButtonLayout->invalidate(); // apply spacer change @@ -768,10 +770,25 @@ FindToolBar::ControlStyle FindToolBar::controlStyle(bool replaceIsVisible) { const Qt::ToolButtonStyle currentFindButtonStyle = m_ui.findNextButton->toolButtonStyle(); const int fullWidth = width(); + + if (replaceIsVisible) { + // Since the replace buttons do not collapse to icons, they have precedence, here. + const int replaceFixedWidth = m_ui.replaceLabel->sizeHint().width() + + m_ui.replaceButton->sizeHint().width() + + m_ui.replaceNextButton->sizeHint().width() + + m_ui.replaceAllButton->sizeHint().width() + + m_ui.advancedButton->sizeHint().width(); + return fullWidth - replaceFixedWidth >= MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT ? + ControlStyle::Text : ControlStyle::Hidden; + } + const auto findWidth = [this] { + const int selectAllWidth = m_currentDocumentFind->supportsSelectAll() ? + m_ui.selectAllButton->sizeHint().width() : 0; return m_ui.findLabel->sizeHint().width() + m_ui.findNextButton->sizeHint().width() - + m_ui.findPreviousButton->sizeHint().width() + FINDBUTTON_SPACER_WIDTH - + m_ui.close->sizeHint().width(); + + m_ui.findPreviousButton->sizeHint().width() + + selectAllWidth + FINDBUTTON_SPACER_WIDTH + + m_ui.close->sizeHint().width(); }; setFindButtonStyle(Qt::ToolButtonTextOnly); const int findWithTextWidth = findWidth(); @@ -782,15 +799,8 @@ FindToolBar::ControlStyle FindToolBar::controlStyle(bool replaceIsVisible) return ControlStyle::Hidden; if (fullWidth - findWithTextWidth < MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT) return ControlStyle::Icon; - if (!replaceIsVisible) - return ControlStyle::Text; - const int replaceFixedWidth = m_ui.replaceLabel->sizeHint().width() - + m_ui.replaceButton->sizeHint().width() - + m_ui.replaceNextButton->sizeHint().width() - + m_ui.replaceAllButton->sizeHint().width() - + m_ui.advancedButton->sizeHint().width(); - return fullWidth - replaceFixedWidth >= MINIMUM_WIDTH_FOR_COMPLEX_LAYOUT ? ControlStyle::Text - : ControlStyle::Hidden; + + return ControlStyle::Text; } void FindToolBar::setFindButtonStyle(Qt::ToolButtonStyle style) diff --git a/src/plugins/coreplugin/locator/basefilefilter.cpp b/src/plugins/coreplugin/locator/basefilefilter.cpp index 8c34e305aac..888db29ac58 100644 --- a/src/plugins/coreplugin/locator/basefilefilter.cpp +++ b/src/plugins/coreplugin/locator/basefilefilter.cpp @@ -218,7 +218,7 @@ QList BaseFileFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; static void openEditorAt(const LocatorFilterEntry &selection); diff --git a/src/plugins/coreplugin/locator/commandlocator.cpp b/src/plugins/coreplugin/locator/commandlocator.cpp index bb8029ce25a..7a803ac1c98 100644 --- a/src/plugins/coreplugin/locator/commandlocator.cpp +++ b/src/plugins/coreplugin/locator/commandlocator.cpp @@ -112,7 +112,7 @@ QList CommandLocator::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 7924b8a0053..327731f1e26 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -80,7 +80,7 @@ QList ExecuteFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp index 159af87cafc..719f52e59d4 100644 --- a/src/plugins/coreplugin/locator/externaltoolsfilter.cpp +++ b/src/plugins/coreplugin/locator/externaltoolsfilter.cpp @@ -49,7 +49,7 @@ QList ExternalToolsFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void prepareSearch(const QString &entry) override; diff --git a/src/plugins/coreplugin/locator/filesystemfilter.cpp b/src/plugins/coreplugin/locator/filesystemfilter.cpp index 9e0751e570f..08ecb68418a 100644 --- a/src/plugins/coreplugin/locator/filesystemfilter.cpp +++ b/src/plugins/coreplugin/locator/filesystemfilter.cpp @@ -169,7 +169,7 @@ QList FileSystemFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.cpp b/src/plugins/coreplugin/locator/ilocatorfilter.cpp index aee4fe49065..3d15253ef31 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/ilocatorfilter.cpp @@ -595,7 +595,7 @@ bool ILocatorFilter::isOldSetting(const QByteArray &state) */ /*! - \fn void Core::ILocatorFilter::accept(Core::LocatorFilterEntry selection, QString *newText, int *selectionStart, int *selectionLength) const + \fn void Core::ILocatorFilter::accept(Core::const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const Called with the entry specified by \a selection when the user activates it in the result list. diff --git a/src/plugins/coreplugin/locator/ilocatorfilter.h b/src/plugins/coreplugin/locator/ilocatorfilter.h index 48679878691..dfcbfc4e67f 100644 --- a/src/plugins/coreplugin/locator/ilocatorfilter.h +++ b/src/plugins/coreplugin/locator/ilocatorfilter.h @@ -143,7 +143,7 @@ public: virtual QList matchesFor(QFutureInterface &future, const QString &entry) = 0; - virtual void accept(LocatorFilterEntry selection, + virtual void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const = 0; virtual void refresh(QFutureInterface &future) { Q_UNUSED(future) }; diff --git a/src/plugins/coreplugin/locator/javascriptfilter.cpp b/src/plugins/coreplugin/locator/javascriptfilter.cpp index 257f133dda8..b15c69f5337 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.cpp +++ b/src/plugins/coreplugin/locator/javascriptfilter.cpp @@ -89,7 +89,7 @@ QList JavaScriptFilter::matchesFor( return entries; } -void JavaScriptFilter::accept(Core::LocatorFilterEntry selection, QString *newText, +void JavaScriptFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/coreplugin/locator/javascriptfilter.h b/src/plugins/coreplugin/locator/javascriptfilter.h index ccded299900..fffe0ad1b07 100644 --- a/src/plugins/coreplugin/locator/javascriptfilter.h +++ b/src/plugins/coreplugin/locator/javascriptfilter.h @@ -49,7 +49,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, QString *newText, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp index 7b62ff1bf1e..6eed862a5cb 100644 --- a/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp +++ b/src/plugins/coreplugin/locator/locatorfiltersfilter.cpp @@ -89,7 +89,7 @@ QList LocatorFiltersFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp index e6aced8d00a..2570c7ea650 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.cpp +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.cpp @@ -120,7 +120,7 @@ void OpenDocumentsFilter::refresh(QFutureInterface &future) QMetaObject::invokeMethod(this, &OpenDocumentsFilter::refreshInternally, Qt::QueuedConnection); } -void OpenDocumentsFilter::accept(LocatorFilterEntry selection, +void OpenDocumentsFilter::accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/coreplugin/locator/opendocumentsfilter.h b/src/plugins/coreplugin/locator/opendocumentsfilter.h index 956dea22d2e..eb9315d1916 100644 --- a/src/plugins/coreplugin/locator/opendocumentsfilter.h +++ b/src/plugins/coreplugin/locator/opendocumentsfilter.h @@ -45,7 +45,7 @@ public: OpenDocumentsFilter(); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void refresh(QFutureInterface &future) override; diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.cpp b/src/plugins/coreplugin/locator/urllocatorfilter.cpp index 2e58cde291e..061c5c49bac 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.cpp +++ b/src/plugins/coreplugin/locator/urllocatorfilter.cpp @@ -162,7 +162,7 @@ QList UrlLocatorFilter::matchesFor( return entries; } -void UrlLocatorFilter::accept(Core::LocatorFilterEntry selection, +void UrlLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const diff --git a/src/plugins/coreplugin/locator/urllocatorfilter.h b/src/plugins/coreplugin/locator/urllocatorfilter.h index fdfe8096d3a..8a011a42f41 100644 --- a/src/plugins/coreplugin/locator/urllocatorfilter.h +++ b/src/plugins/coreplugin/locator/urllocatorfilter.h @@ -46,7 +46,7 @@ public: // ILocatorFilter QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void restoreState(const QByteArray &state) override; bool openConfigDialog(QWidget *parent, bool &needsRefresh) override; diff --git a/src/plugins/coreplugin/loggingviewer.cpp b/src/plugins/coreplugin/loggingviewer.cpp index 25e015e1ac3..89046e39b2e 100644 --- a/src/plugins/coreplugin/loggingviewer.cpp +++ b/src/plugins/coreplugin/loggingviewer.cpp @@ -737,6 +737,7 @@ void LoggingViewer::showLoggingView() // explicitly disable manager again widget->deleteLater(); }); + ICore::registerWindow(widget, Context("Qtc.LogViewer")); widget->show(); } diff --git a/src/plugins/coreplugin/menubarfilter.cpp b/src/plugins/coreplugin/menubarfilter.cpp index 207959f2d74..4d30763eebf 100644 --- a/src/plugins/coreplugin/menubarfilter.cpp +++ b/src/plugins/coreplugin/menubarfilter.cpp @@ -79,7 +79,7 @@ QList MenuBarFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(LocatorFilterEntry selection, QString *newText, + void accept(const LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void prepareSearch(const QString &entry) override; diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 6eeccbcf194..8f7454d402c 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -525,11 +525,14 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti painter->setPen(themeColor(Theme::Welcome_LinkColor)); m_currentTagRects.clear(); + int emptyTagRowsLeft = 2; int xx = 0; int yy = 0; for (const QString &tag : item->tags) { const int ww = fm.horizontalAdvance(tag) + tagsHorSpacing; if (xx + ww > textArea.width() - tagsLabelRect.width()) { + if (--emptyTagRowsLeft == 0) + break; yy += fm.lineSpacing(); xx = 0; } diff --git a/src/plugins/cppeditor/baseeditordocumentparser.h b/src/plugins/cppeditor/baseeditordocumentparser.h index 2e10d561787..2f48058b8b6 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.h +++ b/src/plugins/cppeditor/baseeditordocumentparser.h @@ -50,6 +50,13 @@ public: bool usePrecompiledHeaders = false; QByteArray editorDefines; QString preferredProjectPartId; + + bool operator==(const Configuration &other) + { + return usePrecompiledHeaders == other.usePrecompiledHeaders + && editorDefines == other.editorDefines + && preferredProjectPartId == other.preferredProjectPartId; + } }; struct UpdateParams { diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp index a35eb9c6f14..7c83ceaec61 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.cpp @@ -117,7 +117,7 @@ QList CppCurrentDocumentFilter::matchesFor( return betterEntries; } -void CppCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, +void CppCurrentDocumentFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { diff --git a/src/plugins/cppeditor/cppcurrentdocumentfilter.h b/src/plugins/cppeditor/cppcurrentdocumentfilter.h index 073f601d374..b6c715c70db 100644 --- a/src/plugins/cppeditor/cppcurrentdocumentfilter.h +++ b/src/plugins/cppeditor/cppcurrentdocumentfilter.h @@ -47,7 +47,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index 2a8557b2981..0bc90d1f1f1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -516,6 +516,7 @@ void CppEditorPluginPrivate::inspectCppCodeModel() ICore::raiseWindow(m_cppCodeModelInspectorDialog); } else { m_cppCodeModelInspectorDialog = new CppCodeModelInspectorDialog(ICore::dialogParent()); + ICore::registerWindow(m_cppCodeModelInspectorDialog, Context("CppEditor.Inspector")); m_cppCodeModelInspectorDialog->show(); } } diff --git a/src/plugins/cppeditor/cpplocatorfilter.cpp b/src/plugins/cppeditor/cpplocatorfilter.cpp index 1def7351788..08421e6cb9d 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.cpp +++ b/src/plugins/cppeditor/cpplocatorfilter.cpp @@ -136,7 +136,7 @@ QList CppLocatorFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void CppLocatorFilter::accept(Core::LocatorFilterEntry selection, +void CppLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/cppeditor/cpplocatorfilter.h b/src/plugins/cppeditor/cpplocatorfilter.h index fa579f1067a..fd74f1a9f6a 100644 --- a/src/plugins/cppeditor/cpplocatorfilter.h +++ b/src/plugins/cppeditor/cpplocatorfilter.h @@ -43,7 +43,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; protected: diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 35b1c30449d..0b577eb6e57 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1615,9 +1615,9 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (Breakpoint bp : selectedBreakpoints) { @@ -1629,7 +1629,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); @@ -1645,7 +1645,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) // bp.setThreadSpec(threadId); // }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -1659,7 +1659,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) } ); - addAction(menu, + addAction(this, menu, selectedLocations.size() > 1 ? locationsEnabled ? tr("Disable Selected Locations") : tr("Enable Selected Locations") : locationsEnabled ? tr("Disable Location") : tr("Enable Location"), @@ -1672,7 +1672,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -1687,7 +1687,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) breakpointsInFile.append(findBreakpointByIndex(index)); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -1700,6 +1700,7 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; @@ -2640,20 +2641,20 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); + addAction(this, menu, tr("Add Breakpoint..."), true, &BreakpointManager::executeAddBreakpointDialog); - addAction(menu, tr("Delete Selected Breakpoints"), + addAction(this, menu, tr("Delete Selected Breakpoints"), !selectedBreakpoints.isEmpty(), [selectedBreakpoints] { for (GlobalBreakpoint gbp : selectedBreakpoints) gbp->deleteBreakpoint(); }); - addAction(menu, tr("Edit Selected Breakpoints..."), + addAction(this, menu, tr("Edit Selected Breakpoints..."), !selectedBreakpoints.isEmpty(), [this, selectedBreakpoints, ev] { editBreakpoints(selectedBreakpoints, ev.view()); }); - addAction(menu, + addAction(this, menu, selectedBreakpoints.size() > 1 ? breakpointsEnabled ? tr("Disable Selected Breakpoints") : tr("Enable Selected Breakpoints") : breakpointsEnabled ? tr("Disable Breakpoint") : tr("Enable Breakpoint"), @@ -2666,7 +2667,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addSeparator(); - addAction(menu, tr("Delete All Breakpoints"), + addAction(this, menu, tr("Delete All Breakpoints"), rowCount() > 0, &BreakpointManager::executeDeleteAllBreakpointsDialog); @@ -2682,7 +2683,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) }); } } - addAction(menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), + addAction(this, menu, tr("Delete Breakpoints of \"%1\"").arg(file.toUserOutput()), tr("Delete Breakpoints of File"), breakpointsInFile.size() > 1, [breakpointsInFile] { @@ -2695,6 +2696,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->useToolTipsInBreakpointsView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; diff --git a/src/plugins/debugger/debuggercore.h b/src/plugins/debugger/debuggercore.h index bd228b2560f..e4123d3cdd5 100644 --- a/src/plugins/debugger/debuggercore.h +++ b/src/plugins/debugger/debuggercore.h @@ -32,6 +32,7 @@ #include QT_BEGIN_NAMESPACE +class QObject; class QWidget; class QMenu; class QAction; @@ -53,12 +54,12 @@ void openTextEditor(const QString &titlePattern, const QString &contents); bool isTestRun(); -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered = {}); -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered); -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered); +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered); // Qt's various build paths for unpatched versions QStringList qtBuildPaths(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index ae727383d26..cec08760aab 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -428,25 +428,33 @@ static QIcon interruptIcon(bool toolBarStyle) return toolBarStyle ? iconToolBar : icon; } -QAction *addAction(QMenu *menu, const QString &display, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &display, bool on, const std::function &onTriggered) { QAction *act = menu->addAction(display); act->setEnabled(on); - QObject::connect(act, &QAction::triggered, onTriggered); + // Always queue the connection to prevent the following sequence of events if the menu cleans + // itself up on dismissal: + // 1. The menu is dismissed when selecting a menu item. + // 2. The deletion gets queued via deleteLater(). + // 2. The onTriggered action gets invoked and opens a dialog box. + // 3. The dialog box triggers the events to be processed. + // 4. The menu is deleted when processing the events, while still in the event function to + // handle the dismissal. + QObject::connect(act, &QAction::triggered, parent, onTriggered, Qt::QueuedConnection); return act; }; -QAction *addAction(QMenu *menu, const QString &d1, const QString &d2, bool on, +QAction *addAction(const QObject *parent, QMenu *menu, const QString &d1, const QString &d2, bool on, const std::function &onTriggered) { - return on ? addAction(menu, d1, true, onTriggered) : addAction(menu, d2, false); + return on ? addAction(parent, menu, d1, true, onTriggered) : addAction(parent, menu, d2, false); }; -QAction *addCheckableAction(QMenu *menu, const QString &display, bool on, bool checked, - const std::function &onTriggered) +QAction *addCheckableAction(const QObject *parent, QMenu *menu, const QString &display, bool on, + bool checked, const std::function &onTriggered) { - QAction *act = addAction(menu, display, on, onTriggered); + QAction *act = addAction(parent, menu, display, on, onTriggered); act->setCheckable(true); act->setChecked(checked); return act; @@ -1186,8 +1194,9 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) this, &DebuggerPluginPrivate::updateBreakMenuItem); // Application interaction - connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, - [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }); + // Use a queued connection so the dialog isn't triggered in the same event. + connect(debuggerSettings()->settingsDialog.action(), &QAction::triggered, this, + [] { ICore::showOptionsDialog(DEBUGGER_COMMON_SETTINGS_ID); }, Qt::QueuedConnection); m_perspective.useSubPerspectiveSwitcher(EngineManager::engineChooser()); m_perspective.addToolBarAction(&m_startAction); diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index e894042c2d8..a040c7f1feb 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -179,51 +179,52 @@ bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Update Module List"), + addAction(this, menu, tr("Update Module List"), enabled && canReload, [this] { engine->reloadModules(); }); - addAction(menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Source Files for Module \"%1\"").arg(moduleName), tr("Show Source Files for Module"), moduleNameValid && enabled && canReload, [this, modulePath] { engine->loadSymbols(modulePath); }); // FIXME: Dependencies only available on Windows, when "depends" is installed. - addAction(menu, tr("Show Dependencies of \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Dependencies of \"%1\"").arg(moduleName), tr("Show Dependencies"), moduleNameValid && !moduleName.isEmpty() && HostOsInfo::isWindowsHost(), [modulePath] { QtcProcess::startDetached({{"depends"}, {modulePath}}); }); - addAction(menu, tr("Load Symbols for All Modules"), + addAction(this, menu, tr("Load Symbols for All Modules"), enabled && canLoadSymbols, [this] { engine->loadAllSymbols(); }); - addAction(menu, tr("Examine All Modules"), + addAction(this, menu, tr("Examine All Modules"), enabled && canLoadSymbols, [this] { engine->examineModules(); }); - addAction(menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), + addAction(this, menu, tr("Load Symbols for Module \"%1\"").arg(moduleName), tr("Load Symbols for Module"), moduleNameValid && canLoadSymbols, [this, modulePath] { engine->loadSymbols(modulePath); }); - addAction(menu, tr("Edit File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Edit File \"%1\"").arg(moduleName), tr("Edit File"), moduleNameValid, [this, modulePath] { engine->gotoLocation(FilePath::fromString(modulePath)); }); - addAction(menu, tr("Show Symbols in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Symbols in File \"%1\"").arg(moduleName), tr("Show Symbols"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSymbols(modulePath); }); - addAction(menu, tr("Show Sections in File \"%1\"").arg(moduleName), + addAction(this, menu, tr("Show Sections in File \"%1\"").arg(moduleName), tr("Show Sections"), canShowSymbols && moduleNameValid, [this, modulePath] { engine->requestModuleSections(modulePath); }); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/outputcollector.cpp b/src/plugins/debugger/outputcollector.cpp index e40fb3541c2..831a9f1276d 100644 --- a/src/plugins/debugger/outputcollector.cpp +++ b/src/plugins/debugger/outputcollector.cpp @@ -109,6 +109,8 @@ bool OutputCollector::listen() void OutputCollector::shutdown() { + // Make sure any last data is read first. + bytesAvailable(); #ifdef Q_OS_WIN delete m_server; // Deletes socket as well (QObject parent) m_server = nullptr; diff --git a/src/plugins/debugger/peripheralregisterhandler.cpp b/src/plugins/debugger/peripheralregisterhandler.cpp index 3f466ab1805..2cdf51c9773 100644 --- a/src/plugins/debugger/peripheralregisterhandler.cpp +++ b/src/plugins/debugger/peripheralregisterhandler.cpp @@ -799,6 +799,7 @@ bool PeripheralRegisterHandler::contextMenuEvent(const ItemViewEvent &ev) } menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } @@ -841,7 +842,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Hexadecimal; @@ -851,7 +852,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_reg.format = PeripheralRegisterFormat::Decimal; @@ -861,7 +862,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_reg.format = PeripheralRegisterFormat::Octal; @@ -871,7 +872,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_reg.format = PeripheralRegisterFormat::Binary; @@ -895,7 +896,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Hexadecimal action. const auto hexAct = addCheckableAction( - fmtMenu, tr("Hexadecimal"), on, + this, fmtMenu, tr("Hexadecimal"), on, fmt == PeripheralRegisterFormat::Hexadecimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Hexadecimal; @@ -905,7 +906,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Decimal action. const auto decAct = addCheckableAction( - fmtMenu, tr("Decimal"), on, + this, fmtMenu, tr("Decimal"), on, fmt == PeripheralRegisterFormat::Decimal, [item] { item->m_fld.format = PeripheralRegisterFormat::Decimal; @@ -915,7 +916,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Octal action. const auto octAct = addCheckableAction( - fmtMenu, tr("Octal"), on, + this, fmtMenu, tr("Octal"), on, fmt == PeripheralRegisterFormat::Octal, [item] { item->m_fld.format = PeripheralRegisterFormat::Octal; @@ -925,7 +926,7 @@ QMenu *PeripheralRegisterHandler::createRegisterFieldFormatMenu( // Binary action. const auto binAct = addCheckableAction( - fmtMenu, tr("Binary"), on, + this, fmtMenu, tr("Binary"), on, fmt == PeripheralRegisterFormat::Binary, [item] { item->m_fld.format = PeripheralRegisterFormat::Binary; diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index b071ca6eb1b..db0df2dd232 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -795,9 +795,15 @@ void QmlEngine::assignValueInDebugger(WatchItem *item, const QString &expression, const QVariant &editValue) { if (!expression.isEmpty()) { - QVariant value = (editValue.type() == QVariant::String) - ? QVariant('"' + editValue.toString().replace('"', "\\\"") + '"') - : editValue; + QTC_CHECK(editValue.type() == QVariant::String); + QVariant value; + QString val = editValue.toString(); + if (item->type == "boolean") + value = val != "false" && val != "0"; + else if (item->type == "number") + value = val.toDouble(); + else + value = QString('"' + val.replace('"', "\\\"") + '"'); if (item->isInspect()) { d->inspectorAgent.assignValue(item, expression, value); diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 7ed8af63001..1dbafd23f3a 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -764,14 +764,14 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Reload Register Listing"), + addAction(this, menu, tr("Reload Register Listing"), m_engine->hasCapability(RegisterCapability) && (state == InferiorStopOk || state == InferiorUnrunnable), [this] { m_engine->reloadRegisters(); }); menu->addSeparator(); - addAction(menu, tr("Open Memory View at Value of Register %1 0x%2") + addAction(this, menu, tr("Open Memory View at Value of Register %1 0x%2") .arg(registerName).arg(address, 0, 16), tr("Open Memory View at Value of Register"), address, @@ -784,7 +784,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address && actionsEnabled && m_engine->hasCapability(ShowMemoryCapability), [this, registerName, address] { @@ -796,12 +796,12 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openMemoryView(data); }); - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address && m_engine->hasCapability(DisassemblerCapability), [this, address] { m_engine->openDisassemblerView(Location(address)); }); - addAction(menu, tr("Open Disassembler..."), + addAction(this, menu, tr("Open Disassembler..."), m_engine->hasCapability(DisassemblerCapability), [this, address] { AddressDialog dialog; @@ -820,9 +820,10 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) : HexadecimalFormat; auto addFormatAction = - [menu, currentFormat, registerItem](const QString &display, RegisterFormat format) { - addCheckableAction(menu, display, registerItem, currentFormat == format, - [registerItem, format] { + [this, menu, currentFormat, registerItem]( + const QString &display, RegisterFormat format) { + addCheckableAction(this, menu, display, registerItem, currentFormat == format, + [registerItem, format] { registerItem->m_format = format; registerItem->update(); }); @@ -834,6 +835,7 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) addFormatAction(tr("Binary"), BinaryFormat); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 488c6649b10..c42c196b09f 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -457,24 +457,24 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->expandStack.action()); - addAction(menu, tr("Copy Contents to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Contents to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), true)); }); - addAction(menu, tr("Copy Selection to Clipboard"), true, [ev] { + addAction(this, menu, tr("Copy Selection to Clipboard"), true, [ev] { copyTextToClipboard(selectedText(ev.view(), false)); }); - addAction(menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); + addAction(this, menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); if (m_engine->hasCapability(CreateFullBacktraceCapability)) menu->addAction(debuggerSettings()->createFullBacktrace.action()); if (m_engine->hasCapability(AdditionalQmlStackCapability)) - addAction(menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); + addAction(this, menu, tr("Load QML Stack"), true, [this] { m_engine->loadAdditionalQmlStack(); }); if (m_engine->hasCapability(ShowMemoryCapability)) - addAction(menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at 0x%1").arg(address, 0, 16), tr("Open Memory Editor"), address, [this, row, frame, address] { @@ -488,12 +488,12 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) }); if (m_engine->hasCapability(DisassemblerCapability)) { - addAction(menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), + addAction(this, menu, tr("Open Disassembler at 0x%1").arg(address, 0, 16), tr("Open Disassembler"), address, [this, frame] { m_engine->openDisassemblerView(frame); }); - addAction(menu, tr("Open Disassembler at Address..."), true, + addAction(this, menu, tr("Open Disassembler at Address..."), true, [this, address] { AddressDialog dialog; if (address) @@ -502,7 +502,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) m_engine->openDisassemblerView(Location(dialog.address())); }); - addAction(menu, tr("Disassemble Function..."), true, + addAction(this, menu, tr("Disassemble Function..."), true, [this] { const StackFrame frame = inputFunctionForDisassembly(); if (!frame.function.isEmpty()) @@ -511,13 +511,14 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) } if (m_engine->hasCapability(ShowModuleSymbolsCapability)) { - addAction(menu, tr("Try to Load Unknown Symbols"), true, + addAction(this, menu, tr("Try to Load Unknown Symbols"), true, [this] { m_engine->loadSymbolsForStack(); }); } menu->addSeparator(); menu->addAction(debuggerSettings()->useToolTipsInStackView.action()); menu->addAction(debuggerSettings()->settingsDialog.action()); + connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater); menu->popup(ev.globalPos()); return true; } diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index bc1e57206c1..8818ceb4fd3 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1720,24 +1720,24 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) auto menu = new QMenu; - addAction(menu, tr("Add New Expression Evaluator..."), + addAction(this, menu, tr("Add New Expression Evaluator..."), canHandleWatches && canInsertWatches, [this] { inputNewExpression(); }); - addAction(menu, addWatchActionText(exp), + addAction(this, menu, addWatchActionText(exp), // Suppress for top-level watchers. canHandleWatches && !exp.isEmpty() && item && !(item->level() == 2 && item->isWatcher()), [this, exp, name] { m_handler->watchExpression(exp, name); }); - addAction(menu, removeWatchActionText(exp), + addAction(this, menu, removeWatchActionText(exp), canRemoveWatches && !exp.isEmpty() && item && item->isWatcher(), [this, item] { removeWatchItem(item); }); - addAction(menu, tr("Remove All Expression Evaluators"), + addAction(this, menu, tr("Remove All Expression Evaluators"), canRemoveWatches && !WatchHandler::watchedExpressions().isEmpty(), [this] { clearWatches(); }); - addAction(menu, tr("Select Widget to Add into Expression Evaluator"), + addAction(this, menu, tr("Select Widget to Add into Expression Evaluator"), state == InferiorRunOk && m_engine->hasCapability(WatchWidgetsCapability), [this] { grabWidget(); }); @@ -1757,7 +1757,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) menu->addMenu(createBreakpointMenu(item, menu)); menu->addSeparator(); - addAction(menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Expand All Children"), item, [this, name = item ? item->iname : QString()] { m_expandedINames.insert(name); if (auto item = findItem(name)) { item->forFirstLevelChildren( @@ -1766,7 +1766,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { + addAction(this, menu, tr("Collapse All Children"), item, [this, name = item ? item->iname : QString()] { if (auto item = findItem(name)) { item->forFirstLevelChildren( [this](WatchItem *child) { m_expandedINames.remove(child->iname); }); @@ -1774,15 +1774,15 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) } }); - addAction(menu, tr("Close Editor Tooltips"), + addAction(this, menu, tr("Close Editor Tooltips"), m_engine->toolTipManager()->hasToolTips(), [this] { m_engine->toolTipManager()->closeAllToolTips(); }); - addAction(menu, tr("Copy View Contents to Clipboard"), + addAction(this, menu, tr("Copy View Contents to Clipboard"), true, [this] { copyToClipboard(editorContents()); }); - addAction(menu, + addAction(this, menu, tr("Copy Current Value to Clipboard"), item, [this, name = item ? item->iname : QString()] { @@ -1794,7 +1794,7 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) // selectionModel()->hasSelection(), // [this] { copyToClipboard(editorContents(selectionModel()->selectedRows())); }); - addAction(menu, tr("Open View Contents in Editor"), + addAction(this, menu, tr("Open View Contents in Editor"), m_engine->debuggerActionsEnabled(), [this] { Internal::openTextEditor(tr("Locals & Expressions"), editorContents()); }); @@ -1827,7 +1827,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) const bool canSetWatchpoint = m_engine->hasCapability(WatchpointByAddressCapability); const bool createPointerActions = item->origaddr && item->origaddr != item->address; - act = addAction(menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Add Data Breakpoint"), canSetWatchpoint && item->address, [bh, item] { bh->setWatchpointAtAddress(item->address, item->size); }); @@ -1836,7 +1836,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); act->setToolTip(tr("Stop the program when the data at the address is modified.")); - act = addAction(menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + act = addAction(this, menu, tr("Add Data Breakpoint at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Add Data Breakpoint at Pointer's Address"), canSetWatchpoint && item->address && createPointerActions, // FIXME: an approximation. This should be target's sizeof(void) @@ -1847,7 +1847,7 @@ QMenu *WatchModel::createBreakpointMenu(WatchItem *item, QWidget *parent) act->setChecked(bh->findWatchpoint(bp)); } - act = addAction(menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), + act = addAction(this, menu, tr("Add Data Breakpoint at Expression \"%1\"").arg(item->name), tr("Add Data Breakpoint at Expression"), m_engine->hasCapability(WatchpointByExpressionCapability) && !item->name.isEmpty(), [bh, item] { bh->setWatchpointAtExpression(item->name); }); @@ -1869,37 +1869,37 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) QPoint pos = QPoint(100, 100); // ev->globalPos - addAction(menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory View at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory View at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(true, item, false, pos); }); - addAction(menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory View at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory View at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(true, item, true, pos); }); - addAction(menu, tr("Open Memory View Showing Stack Layout"), + addAction(this, menu, tr("Open Memory View Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(true, pos); }); menu->addSeparator(); - addAction(menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Object's Address (0x%1)").arg(item->address, 0, 16), tr("Open Memory Editor at Object's Address"), item->address, [this, item, pos] { addVariableMemoryView(false, item, false, pos); }); - addAction(menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), + addAction(this, menu, tr("Open Memory Editor at Pointer's Address (0x%1)").arg(item->origaddr, 0, 16), tr("Open Memory Editor at Pointer's Address"), createPointerActions, [this, item, pos] { addVariableMemoryView(false, item, true, pos); }); - addAction(menu, tr("Open Memory Editor Showing Stack Layout"), + addAction(this, menu, tr("Open Memory Editor Showing Stack Layout"), true, [this, pos] { addStackLayoutMemoryView(false, pos); }); - addAction(menu, tr("Open Memory Editor..."), + addAction(this, menu, tr("Open Memory Editor..."), true, [this, item] { AddressDialog dialog; @@ -1918,7 +1918,7 @@ QMenu *WatchModel::createMemoryMenu(WatchItem *item, QWidget *parent) void WatchModel::addCharsPrintableMenu(QMenu *menu) { auto addBaseChangeAction = [this, menu](const QString &text, int base) { - addCheckableAction(menu, text, true, theUnprintableBase == base, [this, base] { + addCheckableAction(this, menu, text, true, theUnprintableBase == base, [this, base] { theUnprintableBase = base; emit layoutChanged(); // FIXME }); @@ -1954,13 +1954,13 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); + addAction(this, menu, tr("Change Display for Object Named \"%1\":").arg(iname), false); QString msg = (individualFormat == AutomaticFormat && typeFormat != AutomaticFormat) ? tr("Use Format for Type (Currently %1)").arg(nameForFormat(typeFormat)) : QString(tr("Use Display Format Based on Type") + ' '); - addCheckableAction(menu, spacer + msg, true, individualFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + msg, true, individualFormat == AutomaticFormat, [this, iname] { // FIXME: Extend to multi-selection. //const QModelIndexList active = activeRows(); @@ -1971,23 +1971,23 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == individualFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == individualFormat, [this, format, iname] { setIndividualFormat(iname, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Individual Formats"), true, [this]() { + addAction(this, menu, tr("Reset All Individual Formats"), true, [this]() { theIndividualFormats.clear(); saveFormats(); m_engine->updateLocals(); }); menu->addSeparator(); - addAction(menu, tr("Change Display for Type \"%1\":").arg(item->type), false); + addAction(this, menu, tr("Change Display for Type \"%1\":").arg(item->type), false); - addCheckableAction(menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, + addCheckableAction(this, menu, spacer + tr("Automatic"), true, typeFormat == AutomaticFormat, [this, item] { //const QModelIndexList active = activeRows(); //for (const QModelIndex &idx : active) @@ -1997,14 +1997,14 @@ QMenu *WatchModel::createFormatMenu(WatchItem *item, QWidget *parent) }); for (int format : alternativeFormats) { - addCheckableAction(menu, spacer + nameForFormat(format), true, format == typeFormat, + addCheckableAction(this, menu, spacer + nameForFormat(format), true, format == typeFormat, [this, format, item] { setTypeFormat(item->type, format); m_engine->updateLocals(); }); } - addAction(menu, tr("Reset All Formats for Types"), true, [this]() { + addAction(this, menu, tr("Reset All Formats for Types"), true, [this]() { theTypeFormats.clear(); saveFormats(); m_engine->updateLocals(); @@ -2046,9 +2046,9 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW const QString spacer = " "; menu->addSeparator(); - addAction(menu, tr("Change Display for Objects"), false); + addAction(this, menu, tr("Change Display for Objects"), false); QString msg = QString(tr("Use Display Format Based on Type")); - addCheckableAction(menu, spacer + msg, true, false, + addCheckableAction(this, menu, spacer + msg, true, false, [this, items] { setItemsFormat(items, AutomaticFormat); m_engine->updateLocals(); @@ -2061,7 +2061,7 @@ QMenu *WatchModel::createFormatMenuForManySelected(const WatchItemSet &items, QW if (formatName.isEmpty()) continue; - addCheckableAction(menu, spacer + formatName, + addCheckableAction(this, menu, spacer + formatName, it.value() == countOfSelectItems, false, [this, format, items] { diff --git a/src/plugins/docker/dockerbuildstep.cpp b/src/plugins/docker/dockerbuildstep.cpp index 52c6c6cf45f..1970147569a 100644 --- a/src/plugins/docker/dockerbuildstep.cpp +++ b/src/plugins/docker/dockerbuildstep.cpp @@ -94,10 +94,20 @@ private: { MacroExpander *expander = target()->kit()->macroExpander(); expander->registerVariable("BuildDevice:DockerImage", - "Build Host Docker Image ID", [=]() -> QString { + "Build Host Docker Image ID", [this] { const DockerDevice *dockerDevice = dockerBuildDevice(); return dockerDevice ? dockerDevice->data().imageId : QString(); }, true); + expander->registerVariable("BuildDevice:DockerRepo", + "Build Host Docker Repo", [this] { + const DockerDevice *dockerDevice = dockerBuildDevice(); + return dockerDevice ? dockerDevice->data().repo : QString(); + }, true); + expander->registerVariable("BuildDevice:DockerTag", + "Build Host Docker Tag", [this] { + const DockerDevice *dockerDevice = dockerBuildDevice(); + return dockerDevice ? dockerDevice->data().tag : QString(); + }, true); return expander; } diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 99c795ae22a..4cff9e89a84 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -87,6 +87,8 @@ #include #endif +//#define ALLOW_LOCAL_ACCESS 1 + using namespace Core; using namespace ProjectExplorer; using namespace QtSupport; @@ -249,6 +251,7 @@ class DockerDevicePrivate : public QObject public: DockerDevicePrivate(DockerDevice *parent) : q(parent) { +#ifdef ALLOW_LOCAL_ACCESS connect(&m_mergedDirWatcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &path) { Q_UNUSED(path) LOG("Container watcher change, file: " << path); @@ -257,6 +260,7 @@ public: Q_UNUSED(path) LOG("Container watcher change, directory: " << path); }); +#endif } ~DockerDevicePrivate() { stopCurrentContainer(); } @@ -279,8 +283,11 @@ public: QPointer m_shell; mutable QMutex m_shellMutex; QString m_container; + +#ifdef ALLOW_LOCAL_ACCESS QString m_mergedDir; QFileSystemWatcher m_mergedDirWatcher; +#endif Environment m_cachedEnviroment; @@ -300,16 +307,21 @@ public: DockerDeviceData &data = dockerDevice->data(); - auto idLabel = new QLabel(tr("Image ID:")); - m_idLineEdit = new QLineEdit; - m_idLineEdit->setText(data.imageId); - m_idLineEdit->setEnabled(false); - auto repoLabel = new QLabel(tr("Repository:")); m_repoLineEdit = new QLineEdit; m_repoLineEdit->setText(data.repo); m_repoLineEdit->setEnabled(false); + auto tagLabel = new QLabel(tr("Tag:")); + m_tagLineEdit = new QLineEdit; + m_tagLineEdit->setText(data.tag); + m_tagLineEdit->setEnabled(false); + + auto idLabel = new QLabel(tr("Image ID:")); + m_idLineEdit = new QLineEdit; + m_idLineEdit->setText(data.imageId); + m_idLineEdit->setEnabled(false); + auto daemonStateLabel = new QLabel(tr("Daemon state:")); m_daemonReset = new QToolButton; m_daemonReset->setToolTip(tr("Clears detected daemon state. " @@ -333,6 +345,7 @@ public: data.useLocalUidGid = on; }); +#ifdef ALLOW_LOCAL_ACCESS // This tries to find the directory in the host file system that corresponds to the // docker container root file system, which is a merge of the layers from the // container image and the volumes mapped using -v on container startup. @@ -348,6 +361,7 @@ public: data.useFilePathMapping = on; dockerDevice->updateContainerAccess(); }); +#endif m_pathsListEdit = new PathListEditor; m_pathsListEdit->setToolTip(tr("Maps paths in this list one-to-one to the " @@ -390,11 +404,11 @@ public: }; connect(autoDetectButton, &QPushButton::clicked, this, - [this, logView, id = data.id(), dockerDevice, searchPaths] { + [this, logView, data, dockerDevice, searchPaths] { logView->clear(); dockerDevice->updateContainerAccess(); - m_kitItemDetector.autoDetect(id, searchPaths()); + m_kitItemDetector.autoDetect(data.autodetectId(), searchPaths()); if (DockerPlugin::isDaemonRunning().value_or(false) == false) logView->append(tr("Docker daemon appears to be not running.")); @@ -403,24 +417,27 @@ public: updateDaemonStateTexts(); }); - connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, id = data.id()] { + connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, data] { logView->clear(); - m_kitItemDetector.undoAutoDetect(id); + m_kitItemDetector.undoAutoDetect(data.autodetectId()); }); - connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, id = data.id()] { + connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, data] { logView->clear(); - m_kitItemDetector.listAutoDetected(id); + m_kitItemDetector.listAutoDetected(data.autodetectId()); }); using namespace Layouting; Form { - idLabel, m_idLineEdit, Break(), repoLabel, m_repoLineEdit, Break(), + tagLabel, m_tagLineEdit, Break(), + idLabel, m_idLineEdit, Break(), daemonStateLabel, m_daemonReset, m_daemonState, Break(), m_runAsOutsideUser, Break(), +#ifdef ALLOW_LOCAL_ACCESS m_usePathMapping, Break(), +#endif Column { new QLabel(tr("Paths to mount:")), m_pathsListEdit, @@ -454,12 +471,15 @@ public: void updateDaemonStateTexts(); private: - QLineEdit *m_idLineEdit; QLineEdit *m_repoLineEdit; + QLineEdit *m_tagLineEdit; + QLineEdit *m_idLineEdit; QToolButton *m_daemonReset; QLabel *m_daemonState; QCheckBox *m_runAsOutsideUser; +#ifdef ALLOW_LOCAL_ACCESS QCheckBox *m_usePathMapping; +#endif Utils::PathListEditor *m_pathsListEdit; KitDetector m_kitItemDetector; @@ -483,6 +503,19 @@ Tasks DockerDevice::validate() const } +// DockerDeviceData + +QString DockerDeviceData::dockerId() const +{ + if (repo == "") + return imageId; + + if (tag == "") + return repo; + + return repo + ':' + tag; +} + // DockerDevice DockerDevice::DockerDevice(const DockerDeviceData &data) @@ -493,39 +526,34 @@ DockerDevice::DockerDevice(const DockerDeviceData &data) setDisplayType(tr("Docker")); setOsType(OsTypeOtherUnix); setDefaultDisplayName(tr("Docker Image"));; - setDisplayName(tr("Docker Image \"%1\" (%2)").arg(data.repo).arg(data.imageId)); + setDisplayName(tr("Docker Image \"%1\" (%2)").arg(data.dockerId()).arg(data.imageId)); setAllowEmptyCommand(true); setOpenTerminal([this](const Environment &env, const FilePath &workingDir) { - DeviceProcess * const proc = createProcess(nullptr); - QObject::connect(proc, &DeviceProcess::finished, [proc] { - if (!proc->errorString().isEmpty()) { - MessageManager::writeDisrupting( - tr("Error running remote shell: %1").arg(proc->errorString())); - } - proc->deleteLater(); - }); + Q_UNUSED(env); // TODO: That's the runnable's environment in general. Use it via -e below. + updateContainerAccess(); + if (d->m_container.isEmpty()) { + MessageManager::writeDisrupting(tr("Error starting remote shell. No container")); + return; + } + + QtcProcess *proc = new QtcProcess(QtcProcess::TerminalOn); + QObject::connect(proc, &QtcProcess::finished, proc, &QObject::deleteLater); + QObject::connect(proc, &DeviceProcess::errorOccurred, [proc] { MessageManager::writeDisrupting(tr("Error starting remote shell.")); proc->deleteLater(); }); - Runnable runnable; - runnable.command = {"/bin/sh", {}}; - runnable.device = sharedFromThis(); - runnable.environment = env; - runnable.workingDirectory = workingDir; - runnable.extraData[Constants::DOCKER_RUN_FLAGS] = QStringList({"--interactive", "--tty"}); - - proc->setRunInTerminal(true); - proc->start(runnable); + const QString wd = workingDir.isEmpty() ? "/" : workingDir.path(); + proc->setCommand({"docker", {"exec", "-it", "-w", wd, d->m_container, "/bin/sh"}}); + proc->setEnvironment(Environment::systemEnvironment()); // The host system env. Intentional. + proc->start(); }); - if (HostOsInfo::isAnyUnixHost()) { - addDeviceAction({tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) { - device->openTerminal(Environment(), FilePath()); - }}); - } + addDeviceAction({tr("Open Shell in Container"), [](const IDevice::Ptr &device, QWidget *) { + device->openTerminal(device->systemEnvironment(), FilePath()); + }}); } DockerDevice::~DockerDevice() @@ -791,7 +819,9 @@ void DockerDevicePrivate::stopCurrentContainer() if (m_shell->state() == QProcess::NotRunning) { LOG("Clean exit via shell"); m_container.clear(); +#ifdef ALLOW_LOCAL_ACCESS m_mergedDir.clear(); +#endif delete m_shell; m_shell = nullptr; return; @@ -802,7 +832,9 @@ void DockerDevicePrivate::stopCurrentContainer() proc.setCommand({"docker", {"container", "stop", m_container}}); m_container.clear(); +#ifdef ALLOW_LOCAL_ACCESS m_mergedDir.clear(); +#endif proc.runBlocking(); } @@ -848,7 +880,7 @@ void DockerDevicePrivate::startContainer() dockerCreate.addArgs({"-v", q->debugDumperPath().toUserOutput() + ':' + dumperPath.path()}); q->setDebugDumperPath(dumperPath); - dockerCreate.addArgs({"--entrypoint", "/bin/sh", m_data.imageId}); + dockerCreate.addArgs({"--entrypoint", "/bin/sh", m_data.dockerId()}); LOG("RUNNING: " << dockerCreate.toUserOutput()); QtcProcess createProcess; @@ -917,6 +949,7 @@ void DockerDevicePrivate::updateContainerAccess() void DockerDevicePrivate::updateFileSystemAccess() { +#ifdef ALLOW_LOCAL_ACCESS if (!m_data.useFilePathMapping) { // Direct access was used previously, but is not wanted anymore. if (!m_mergedDir.isEmpty()) { @@ -958,14 +991,19 @@ void DockerDevicePrivate::updateFileSystemAccess() } m_mergedDirWatcher.addPath(m_mergedDir); +#endif } bool DockerDevice::hasLocalFileAccess() const { +#ifdef ALLOW_LOCAL_ACCESS static const bool denyLocalAccess = qEnvironmentVariableIsSet("QTC_DOCKER_DENY_LOCAL_ACCESS"); if (denyLocalAccess) return false; return !d->m_mergedDir.isEmpty(); +#else + return false; +#endif } void DockerDevice::setMounts(const QStringList &mounts) const @@ -976,6 +1014,7 @@ void DockerDevice::setMounts(const QStringList &mounts) const FilePath DockerDevice::mapToLocalAccess(const FilePath &filePath) const { +#ifdef ALLOW_LOCAL_ACCESS QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {}); QString path = filePath.path(); for (const QString &mount : qAsConst(d->m_data.mounts)) { @@ -985,6 +1024,10 @@ FilePath DockerDevice::mapToLocalAccess(const FilePath &filePath) const if (path.startsWith('/')) return FilePath::fromString(d->m_mergedDir + path); return FilePath::fromString(d->m_mergedDir + '/' + path); +#else + QTC_CHECK(false); + return {}; +#endif } FilePath DockerDevice::mapFromLocalAccess(const FilePath &filePath) const @@ -995,9 +1038,14 @@ FilePath DockerDevice::mapFromLocalAccess(const FilePath &filePath) const FilePath DockerDevice::mapFromLocalAccess(const QString &filePath) const { +#ifdef ALLOW_LOCAL_FILE_ACCESS QTC_ASSERT(!d->m_mergedDir.isEmpty(), return {}); QTC_ASSERT(filePath.startsWith(d->m_mergedDir), return FilePath::fromString(filePath)); return mapToGlobalPath(FilePath::fromString(filePath.mid(d->m_mergedDir.size()))); +#else + QTC_CHECK(false); + return {}; +#endif } const char DockerDeviceDataImageIdKey[] = "DockerDeviceDataImageId"; @@ -1011,9 +1059,9 @@ const char DockerDeviceMappedPaths[] = "DockerDeviceMappedPaths"; void DockerDevice::fromMap(const QVariantMap &map) { ProjectExplorer::IDevice::fromMap(map); - d->m_data.imageId = map.value(DockerDeviceDataImageIdKey).toString(); d->m_data.repo = map.value(DockerDeviceDataRepoKey).toString(); d->m_data.tag = map.value(DockerDeviceDataTagKey).toString(); + d->m_data.imageId = map.value(DockerDeviceDataImageIdKey).toString(); d->m_data.size = map.value(DockerDeviceDataSizeKey).toString(); d->m_data.useLocalUidGid = map.value(DockerDeviceUseOutsideUser, HostOsInfo::isLinuxHost()).toBool(); @@ -1025,9 +1073,9 @@ void DockerDevice::fromMap(const QVariantMap &map) QVariantMap DockerDevice::toMap() const { QVariantMap map = ProjectExplorer::IDevice::toMap(); - map.insert(DockerDeviceDataImageIdKey, d->m_data.imageId); map.insert(DockerDeviceDataRepoKey, d->m_data.repo); map.insert(DockerDeviceDataTagKey, d->m_data.tag); + map.insert(DockerDeviceDataImageIdKey, d->m_data.imageId); map.insert(DockerDeviceDataSizeKey, d->m_data.size); map.insert(DockerDeviceUseOutsideUser, d->m_data.useLocalUidGid); map.insert(DockerDeviceUseFilePathMapping, d->m_data.useFilePathMapping); @@ -1079,7 +1127,7 @@ FilePath DockerDevice::mapToGlobalPath(const FilePath &pathOnDevice) const } FilePath result; result.setScheme("docker"); - result.setHost(d->m_data.imageId); + result.setHost(d->m_data.dockerId()); result.setPath(pathOnDevice.path()); return result; } @@ -1099,7 +1147,7 @@ QString DockerDevice::mapToDevicePath(const Utils::FilePath &globalPath) const bool DockerDevice::handlesFile(const FilePath &filePath) const { - return filePath.scheme() == "docker" && filePath.host() == d->m_data.imageId; + return filePath.scheme() == "docker" && filePath.host() == d->m_data.dockerId(); } bool DockerDevice::isExecutableFile(const FilePath &filePath) const @@ -1649,7 +1697,7 @@ Environment DockerDevice::systemEnvironment() const void DockerDevice::aboutToBeRemoved() const { KitDetector detector(sharedFromThis()); - detector.undoAutoDetect(d->m_data.id()); + detector.undoAutoDetect(d->m_data.autodetectId()); } void DockerDevicePrivate::fetchSystemEnviroment() @@ -1752,15 +1800,15 @@ public: switch (column) { case 0: if (role == Qt::DisplayRole) - return imageId; + return repo; break; case 1: if (role == Qt::DisplayRole) - return repo; + return tag; break; case 2: if (role == Qt::DisplayRole) - return tag; + return imageId; break; case 3: if (role == Qt::DisplayRole) @@ -1781,7 +1829,7 @@ public: setWindowTitle(DockerDevice::tr("Docker Image Selection")); resize(800, 600); - m_model.setHeader({"Image", "Repository", "Tag", "Size"}); + m_model.setHeader({"Repository", "Tag", "Image", "Size"}); m_view = new TreeView; m_view->setModel(&m_model); @@ -1853,7 +1901,7 @@ public: QTC_ASSERT(item, return {}); auto device = DockerDevice::create(*item); - device->setupId(IDevice::ManuallyAdded, Id::fromString(item->id())); + device->setupId(IDevice::ManuallyAdded, Id::fromString(item->autodetectId())); device->setType(Constants::DOCKER_DEVICE_TYPE); device->setMachineType(IDevice::Hardware); diff --git a/src/plugins/docker/dockerdevice.h b/src/plugins/docker/dockerdevice.h index 9ead0c5c102..6b2cca21a68 100644 --- a/src/plugins/docker/dockerdevice.h +++ b/src/plugins/docker/dockerdevice.h @@ -37,7 +37,10 @@ namespace Internal { class DockerDeviceData { public: - QString id() const { return "docker:" + imageId; } + // Used for "docker run" and for host parts of FilePaths + QString dockerId() const; + // Used as autodetection source string + QString autodetectId() const { return "docker:" + dockerId(); } QString imageId; QString repo; diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index b6217011c28..0bc75d7813f 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -911,6 +911,8 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) VcsCommand *command = d->client->asyncUpstreamStatus( d->workingDirectory, node->fullRef(), node->tracking); QObject::connect(command, &VcsCommand::stdOutText, node, [this, node](const QString &text) { + if (text.isEmpty()) + return; const QStringList split = text.trimmed().split('\t'); QTC_ASSERT(split.size() == 2, return); diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 71ac8da38ea..d0904f96d6d 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -348,6 +348,7 @@ void GerritPlugin::openView() } GerritDialog *gd = new GerritDialog(m_parameters, m_server, currentRepository(), ICore::dialogParent()); gd->setModal(false); + ICore::registerWindow(gd, Context("Git.Gerrit")); connect(gd, &GerritDialog::fetchDisplay, this, [this](const QSharedPointer &change) { fetch(change, FetchDisplay); }); connect(gd, &GerritDialog::fetchCherryPick, this, diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index 77a948e7773..2dbcfeb56ff 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -1715,6 +1715,7 @@ void GitPluginPrivate::branchList() void GitPluginPrivate::manageRemotes() { showNonModalDialog(currentState().topLevel(), m_remoteDialog); + ICore::registerWindow(m_remoteDialog, Context("Git.Remotes")); } void GitPluginPrivate::initRepository() @@ -1725,6 +1726,7 @@ void GitPluginPrivate::initRepository() void GitPluginPrivate::stashList() { showNonModalDialog(currentState().topLevel(), m_stashDialog); + ICore::registerWindow(m_stashDialog, Context("Git.Stashes")); } void GitPluginPrivate::updateActions(VcsBasePluginPrivate::ActionState as) diff --git a/src/plugins/help/helpindexfilter.cpp b/src/plugins/help/helpindexfilter.cpp index ee810c866e7..5e422c3a59d 100644 --- a/src/plugins/help/helpindexfilter.cpp +++ b/src/plugins/help/helpindexfilter.cpp @@ -197,7 +197,7 @@ QList HelpIndexFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; void refresh(QFutureInterface &future) override; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 37d502a945b..cc8b03ea6dc 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -159,7 +159,6 @@ void LanguageClientManager::clientFinished(Client *client) = managerInstance->m_clientForDocument.keys(client); if (client->reset()) { qCDebug(Log) << "restart unexpectedly finished client: " << client->name() << client; - client->disconnect(managerInstance); client->log( tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS)); QTimer::singleShot(restartTimeoutS * 1000, client, [client]() { client->start(); }); @@ -453,6 +452,7 @@ void LanguageClientManager::showInspector() clientName = client->name(); QWidget *inspectorWidget = instance()->m_inspector.createWidget(clientName); inspectorWidget->setAttribute(Qt::WA_DeleteOnClose); + Core::ICore::registerWindow(inspectorWidget, Core::Context("LanguageClient.Inspector")); inspectorWidget->show(); } diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index bddb300fe23..f61c9de507f 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -170,6 +170,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, m_view.setModel(&m_model); m_view.setHeaderHidden(true); m_view.setExpandsOnDoubleClick(false); + m_view.setFrameStyle(QFrame::NoFrame); connect(&m_view, &QAbstractItemView::activated, this, &LanguageClientOutlineWidget::onItemActivated); connect(m_editor->editorWidget(), &TextEditor::TextEditorWidget::cursorPositionChanged, diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 28d01d2c82d..5ccc4d175a0 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -218,7 +218,7 @@ QList DocumentLocatorFilter::matchesFor( return {}; } -void DocumentLocatorFilter::accept(Core::LocatorFilterEntry selection, +void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const @@ -325,7 +325,7 @@ QList WorkspaceLocatorFilter::matchesFor( .toList(); } -void WorkspaceLocatorFilter::accept(Core::LocatorFilterEntry selection, +void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString * /*newText*/, int * /*selectionStart*/, int * /*selectionLength*/) const diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index ebc35de57a7..c149fadcad0 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -49,7 +49,7 @@ public: void prepareSearch(const QString &entry) override; QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; @@ -103,7 +103,7 @@ public: void prepareSearch(const QString &entry, const QVector &clients); QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; diff --git a/src/plugins/macros/macrolocatorfilter.cpp b/src/plugins/macros/macrolocatorfilter.cpp index 35b238454b7..533f2461907 100644 --- a/src/plugins/macros/macrolocatorfilter.cpp +++ b/src/plugins/macros/macrolocatorfilter.cpp @@ -85,7 +85,7 @@ QList MacroLocatorFilter::matchesFor(QFutureInterface< return betterEntries; } -void MacroLocatorFilter::accept(Core::LocatorFilterEntry selection, +void MacroLocatorFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/macros/macrolocatorfilter.h b/src/plugins/macros/macrolocatorfilter.h index b12a8a30ff4..f81831c3f8b 100644 --- a/src/plugins/macros/macrolocatorfilter.h +++ b/src/plugins/macros/macrolocatorfilter.h @@ -42,7 +42,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index a85b35b5f9b..261dd6e0b52 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -2,12 +2,14 @@ add_qtc_plugin(McuSupport DEPENDS Qt5::Core PLUGIN_DEPENDS Core BareMetal ProjectExplorer Debugger CMakeProjectManager QtSupport SOURCES + mcukitinformation.cpp mcukitinformation.h mcusupport.qrc mcusupport_global.h mcusupportconstants.h mcusupportdevice.cpp mcusupportdevice.h mcusupportoptions.cpp mcusupportoptions.h mcusupportoptionspage.cpp mcusupportoptionspage.h + mcupackage.cpp mcupackage.h mcusupportplugin.cpp mcusupportplugin.h mcusupportsdk.cpp mcusupportsdk.h mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h diff --git a/src/plugins/mcusupport/mcukitinformation.cpp b/src/plugins/mcusupport/mcukitinformation.cpp new file mode 100644 index 00000000000..f72fef1f2e7 --- /dev/null +++ b/src/plugins/mcusupport/mcukitinformation.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 "mcukitinformation.h" + +#include + +using namespace ProjectExplorer; + +namespace { + +class McuDependenciesKitAspectWidget final : public KitAspectWidget +{ +public: + McuDependenciesKitAspectWidget(Kit *workingCopy, const KitAspect *ki) + : KitAspectWidget(workingCopy, ki) + {} + + void makeReadOnly() override {} + void refresh() override {} + void addToLayout(Utils::LayoutBuilder &) override {} +}; + +} // anonymous namespace + +namespace McuSupport { +namespace Internal { + +McuDependenciesKitAspect::McuDependenciesKitAspect() +{ + setObjectName(QLatin1String("McuDependenciesKitAspect")); + setId(McuDependenciesKitAspect::id()); + setDisplayName(tr("MCU Dependencies")); + setDescription(tr("Paths to 3rd party dependencies")); + setPriority(28500); +} + +Tasks McuDependenciesKitAspect::validate(const Kit *k) const +{ + Tasks result; + QTC_ASSERT(k, return result); + + const QVariant checkFormat = k->value(McuDependenciesKitAspect::id()); + if (!checkFormat.isNull() && !checkFormat.canConvert(QVariant::List)) + return { BuildSystemTask(Task::Error, tr("The MCU dependencies setting value is invalid.")) }; + + const QVariant envStringList = k->value(EnvironmentKitAspect::id()); + if (!envStringList.isNull() && !envStringList.canConvert(QVariant::List)) + return { BuildSystemTask(Task::Error, tr("The environment setting value is invalid.")) }; + + const auto environment = Utils::NameValueDictionary(envStringList.toStringList()); + for (const auto &dependency: dependencies(k)) { + if (!environment.hasKey(dependency.name)) { + result << BuildSystemTask(Task::Warning, tr("Environment variable %1 not defined.").arg(dependency.name)); + } else { + const auto path = Utils::FilePath::fromUserInput( + environment.value(dependency.name) + "/" + dependency.value); + if (!path.exists()) { + result << BuildSystemTask(Task::Warning, tr("%1 not found.").arg(path.toUserOutput())); + } + } + } + + return result; +} + +void McuDependenciesKitAspect::fix(Kit *k) +{ + QTC_ASSERT(k, return); + + const QVariant variant = k->value(McuDependenciesKitAspect::id()); + if (!variant.isNull() && !variant.canConvert(QVariant::List)) { + qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(k->displayName())); + setDependencies(k, Utils::NameValueItems()); + } +} + +KitAspectWidget *McuDependenciesKitAspect::createConfigWidget(Kit *k) const +{ + QTC_ASSERT(k, return nullptr); + return new McuDependenciesKitAspectWidget(k, this); +} + +KitAspect::ItemList McuDependenciesKitAspect::toUserOutput(const Kit *k) const +{ + Q_UNUSED(k) + + return {}; +} + +Utils::Id McuDependenciesKitAspect::id() +{ + return "PE.Profile.McuDependencies"; +} + + +Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *k) +{ + if (k) + return Utils::NameValueItem::fromStringList(k->value(McuDependenciesKitAspect::id()).toStringList()); + return Utils::NameValueItems(); +} + +void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) +{ + if (k) + k->setValue(McuDependenciesKitAspect::id(), Utils::NameValueItem::toStringList(dependencies)); +} + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcukitinformation.h b/src/plugins/mcusupport/mcukitinformation.h new file mode 100644 index 00000000000..85c811ad668 --- /dev/null +++ b/src/plugins/mcusupport/mcukitinformation.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** 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 + +namespace McuSupport { +namespace Internal { + +class McuDependenciesKitAspect final : public ProjectExplorer::KitAspect +{ + Q_OBJECT + +public: + McuDependenciesKitAspect(); + + ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const override; + void fix(ProjectExplorer::Kit *k) override; + + ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const override; + + ItemList toUserOutput(const ProjectExplorer::Kit *k) const override; + + static Utils::Id id(); + static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *k); + static void setDependencies(ProjectExplorer::Kit *k, const Utils::NameValueItems &dependencies); +}; + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp new file mode 100644 index 00000000000..7a98738ffa5 --- /dev/null +++ b/src/plugins/mcusupport/mcupackage.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** 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 "mcupackage.h" +#include "mcusupportconstants.h" +#include "mcusupportsdk.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace Utils; + +namespace McuSupport { +namespace Internal { + +static bool automaticKitCreationFromSettings(QSettings::Scope scope = QSettings::UserScope) +{ + QSettings *settings = Core::ICore::settings(scope); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); + bool automaticKitCreation = settings->value(key, true).toBool(); + return automaticKitCreation; +} + +McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, + const QString &detectionPath, const QString &settingsKey, + const QString &envVarName, const QString &downloadUrl, + const McuPackageVersionDetector *versionDetector) + : m_label(label) + , m_defaultPath(Sdk::packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath)) + , m_detectionPath(detectionPath) + , m_settingsKey(settingsKey) + , m_versionDetector(versionDetector) + , m_environmentVariableName(envVarName) + , m_downloadUrl(downloadUrl) +{ + m_path = Sdk::packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath); + m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); +} + +FilePath McuPackage::basePath() const +{ + return m_fileChooser != nullptr ? m_fileChooser->filePath() : m_path; +} + +FilePath McuPackage::path() const +{ + return basePath().resolvePath(m_relativePathModifier).absoluteFilePath(); +} + +QString McuPackage::label() const +{ + return m_label; +} + +FilePath McuPackage::defaultPath() const +{ + return m_defaultPath; +} + +QString McuPackage::detectionPath() const +{ + return m_detectionPath; +} + +QWidget *McuPackage::widget() +{ + if (m_widget) + return m_widget; + + m_widget = new QWidget; + m_fileChooser = new PathChooser; + m_fileChooser->lineEdit()->setButtonIcon(FancyLineEdit::Right, + Icons::RESET.icon()); + m_fileChooser->lineEdit()->setButtonVisible(FancyLineEdit::Right, true); + connect(m_fileChooser->lineEdit(), &FancyLineEdit::rightButtonClicked, this, [&] { + m_fileChooser->setFilePath(m_defaultPath); + }); + + auto layout = new QGridLayout(m_widget); + layout->setContentsMargins(0, 0, 0, 0); + m_infoLabel = new InfoLabel(); + + if (!m_downloadUrl.isEmpty()) { + auto downLoadButton = new QToolButton; + downLoadButton->setIcon(Icons::ONLINE.icon()); + downLoadButton->setToolTip(tr("Download from \"%1\"").arg(m_downloadUrl)); + QObject::connect(downLoadButton, &QToolButton::pressed, this, [this] { + QDesktopServices::openUrl(m_downloadUrl); + }); + layout->addWidget(downLoadButton, 0, 2); + } + + layout->addWidget(m_fileChooser, 0, 0, 1, 2); + layout->addWidget(m_infoLabel, 1, 0, 1, -1); + + m_fileChooser->setFilePath(m_path); + + QObject::connect(this, &McuPackage::statusChanged, this, [this] { + updateStatusUi(); + }); + + QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { + updatePath(); + emit changed(); + }); + + updateStatus(); + return m_widget; +} + +McuPackage::Status McuPackage::status() const +{ + return m_status; +} + +bool McuPackage::validStatus() const +{ + return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion; +} + +const QString &McuPackage::environmentVariableName() const +{ + return m_environmentVariableName; +} + +void McuPackage::setAddToPath(bool addToPath) +{ + m_addToPath = addToPath; +} + +bool McuPackage::addToPath() const +{ + return m_addToPath; +} + +void McuPackage::writeGeneralSettings() const +{ + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); + QSettings *settings = Core::ICore::settings(); + settings->setValue(key, m_automaticKitCreation); +} + +bool McuPackage::writeToSettings() const +{ + const FilePath savedPath = Sdk::packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; + Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString()); + + return savedPath != m_path; +} + +void McuPackage::setRelativePathModifier(const QString &path) +{ + m_relativePathModifier = path; +} + +void McuPackage::setVersions(const QStringList &versions) +{ + m_versions = versions; +} + +bool McuPackage::automaticKitCreationEnabled() const +{ + return m_automaticKitCreation; +} + +void McuPackage::setAutomaticKitCreationEnabled(const bool enabled) +{ + m_automaticKitCreation = enabled; +} + +void McuPackage::updatePath() +{ + m_path = m_fileChooser->rawFilePath(); + m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); + updateStatus(); +} + +void McuPackage::updateStatus() +{ + bool validPath = !m_path.isEmpty() && m_path.exists(); + const FilePath detectionPath = basePath() / m_detectionPath; + const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists(); + m_detectedVersion = validPath && validPackage && m_versionDetector + ? m_versionDetector->parseVersion(basePath().toString()) : QString(); + const bool validVersion = m_detectedVersion.isEmpty() || + m_versions.isEmpty() || m_versions.contains(m_detectedVersion); + + m_status = validPath ? + ( validPackage ? + (validVersion ? ValidPackage : ValidPackageMismatchedVersion) + : ValidPathInvalidPackage ) + : m_path.isEmpty() ? EmptyPath : InvalidPath; + + emit statusChanged(); +} + +void McuPackage::updateStatusUi() +{ + switch (m_status) { + case ValidPackage: m_infoLabel->setType(InfoLabel::Ok); break; + case ValidPackageMismatchedVersion: m_infoLabel->setType(InfoLabel::Warning); break; + default: m_infoLabel->setType(InfoLabel::NotOk); break; + } + m_infoLabel->setText(statusText()); +} + +QString McuPackage::statusText() const +{ + const QString displayPackagePath = m_path.toUserOutput(); + const QString displayVersions = m_versions.join(" or "); + const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); + const QString displayRequiredPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, displayVersions); + const QString displayDetectedPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, m_detectedVersion); + + QString response; + switch (m_status) { + case ValidPackage: + response = m_detectionPath.isEmpty() + ? ( m_detectedVersion.isEmpty() + ? tr("Path %1 exists.").arg(displayPackagePath) + : tr("Path %1 exists. Version %2 was found.") + .arg(displayPackagePath, m_detectedVersion) ) + : tr("Path %1 is valid, %2 was found.") + .arg(displayPackagePath, displayDetectedPath); + break; + case ValidPackageMismatchedVersion: { + const QString versionWarning = m_versions.size() == 1 ? + tr("but only version %1 is supported").arg(m_versions.first()) : + tr("but only versions %1 are supported").arg(displayVersions); + response = tr("Path %1 is valid, %2 was found, %3.") + .arg(displayPackagePath, displayDetectedPath, versionWarning); + break; + } + case ValidPathInvalidPackage: + response = tr("Path %1 exists, but does not contain %2.") + .arg(displayPackagePath, displayRequiredPath); + break; + case InvalidPath: + response = tr("Path %1 does not exist.").arg(displayPackagePath); + break; + case EmptyPath: + response = m_detectionPath.isEmpty() + ? tr("Path is empty.") + : tr("Path is empty, %1 not found.") + .arg(displayRequiredPath); + break; + } + return response; +} + +McuToolChainPackage::McuToolChainPackage(const QString &label, + const FilePath &defaultPath, + const QString &detectionPath, + const QString &settingsKey, + McuToolChainPackage::Type type, const QString &envVarName, + const McuPackageVersionDetector *versionDetector) + : McuPackage(label, defaultPath, detectionPath, settingsKey, envVarName, {}, versionDetector) + , m_type(type) +{ +} + +McuToolChainPackage::Type McuToolChainPackage::type() const +{ + return m_type; +} + +bool McuToolChainPackage::isDesktopToolchain() const +{ + return m_type == Type::MSVC || m_type == Type::GCC; +} + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h new file mode 100644 index 00000000000..8729a40a335 --- /dev/null +++ b/src/plugins/mcusupport/mcupackage.h @@ -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. +** +****************************************************************************/ + +#pragma once + +#include "mcusupportversiondetection.h" + +#include +#include + +#include + +QT_FORWARD_DECLARE_CLASS(QWidget) + +namespace ProjectExplorer { +class ToolChain; +} + +namespace Utils { +class PathChooser; +class InfoLabel; +} // namespace Utils + +namespace McuSupport { +namespace Internal { + +class McuPackage : public QObject +{ + Q_OBJECT + +public: + enum Status { + EmptyPath, + InvalidPath, + ValidPathInvalidPackage, + ValidPackageMismatchedVersion, + ValidPackage + }; + + McuPackage(const QString &label, const Utils::FilePath &defaultPath, + const QString &detectionPath, const QString &settingsKey, + const QString &envVarName = {}, const QString &downloadUrl = {}, + const McuPackageVersionDetector *versionDetector = nullptr); + virtual ~McuPackage() = default; + + Utils::FilePath basePath() const; + Utils::FilePath path() const; + QString label() const; + Utils::FilePath defaultPath() const; + QString detectionPath() const; + QString statusText() const; + void updateStatus(); + + Status status() const; + bool validStatus() const; + void setAddToPath(bool addToPath); + bool addToPath() const; + void writeGeneralSettings() const; + bool writeToSettings() const; + void setRelativePathModifier(const QString &path); + void setVersions(const QStringList &versions); + + bool automaticKitCreationEnabled() const; + void setAutomaticKitCreationEnabled(const bool enabled); + + QWidget *widget(); + + const QString &environmentVariableName() const; + +signals: + void changed(); + void statusChanged(); + +private: + void updatePath(); + void updateStatusUi(); + + QWidget *m_widget = nullptr; + Utils::PathChooser *m_fileChooser = nullptr; + Utils::InfoLabel *m_infoLabel = nullptr; + + const QString m_label; + const Utils::FilePath m_defaultPath; + const QString m_detectionPath; + const QString m_settingsKey; + const McuPackageVersionDetector *m_versionDetector; + + Utils::FilePath m_path; + QString m_relativePathModifier; // relative path to m_path to be returned by path() + QString m_detectedVersion; + QStringList m_versions; + const QString m_environmentVariableName; + const QString m_downloadUrl; + bool m_addToPath = false; + bool m_automaticKitCreation = true; + + Status m_status = InvalidPath; +}; + +class McuToolChainPackage : public McuPackage +{ +public: + enum class Type { + IAR, + KEIL, + MSVC, + GCC, + ArmGcc, + GHS, + GHSArm, + Unsupported + }; + + McuToolChainPackage(const QString &label, + const Utils::FilePath &defaultPath, + const QString &detectionPath, + const QString &settingsKey, + Type type, + const QString &envVarName = {}, + const McuPackageVersionDetector *versionDetector = nullptr + ); + + Type type() const; + bool isDesktopToolchain() const; + ProjectExplorer::ToolChain *toolChain(Utils::Id language) const; + QString toolChainName() const; + QString cmakeToolChainFileName() const; + QVariant debuggerId() const; + +private: + const Type m_type; +}; + +} // namespace Internal +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 2f775a01549..e8529e24649 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -15,6 +15,8 @@ QtcPlugin { Depends { name: "QtSupport" } files: [ + "mcupackage.cpp", + "mcupackage.h", "mcusupport.qrc", "mcusupport_global.h", "mcusupportconstants.h", @@ -33,6 +35,8 @@ QtcPlugin { "mcusupportversiondetection.cpp", "mcusupportversiondetection.h", "mcusupportcmakemapper.h", - "mcusupportcmakemapper.cpp" + "mcusupportcmakemapper.cpp", + "mcukitinformation.cpp", + "mcukitinformation.h" ] } diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 8ee5f1f9179..36811c5a13a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -23,6 +23,8 @@ ** ****************************************************************************/ +#include "mcukitinformation.h" +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptions.h" #include "mcusupportsdk.h" @@ -73,26 +75,6 @@ namespace Internal { static const int KIT_VERSION = 9; // Bumps up whenever details in Kit creation change -static FilePath packagePathFromSettings(const QString &settingsKey, - QSettings::Scope scope = QSettings::UserScope, - const FilePath &defaultPath = {}) -{ - QSettings *settings = Core::ICore::settings(scope); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + settingsKey; - const QString path = settings->value(key, defaultPath.toString()).toString(); - return FilePath::fromUserInput(path); -} - -static bool automaticKitCreationFromSettings(QSettings::Scope scope = QSettings::UserScope) -{ - QSettings *settings = Core::ICore::settings(scope); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); - bool automaticKitCreation = settings->value(key, true).toBool(); - return automaticKitCreation; -} - static bool kitNeedsQtVersion() { // Only on Windows, Qt is linked into the distributed qul Desktop libs. Also, the host tools @@ -116,267 +98,6 @@ static void remapQul2xCmakeVars(Kit *kit, const EnvironmentItems &envItems) CMakeConfigurationKitAspect::setConfiguration(kit, config); } -McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, - const QString &detectionPath, const QString &settingsKey, - const McuPackageVersionDetector *versionDetector) - : m_label(label) - , m_defaultPath(packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath)) - , m_detectionPath(detectionPath) - , m_settingsKey(settingsKey) - , m_versionDetector(versionDetector) -{ - m_path = packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath); - m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); -} - -FilePath McuPackage::basePath() const -{ - return m_fileChooser != nullptr ? m_fileChooser->filePath() : m_path; -} - -FilePath McuPackage::path() const -{ - return basePath().resolvePath(m_relativePathModifier).absoluteFilePath(); -} - -QString McuPackage::label() const -{ - return m_label; -} - -FilePath McuPackage::defaultPath() const -{ - return m_defaultPath; -} - -QString McuPackage::detectionPath() const -{ - return m_detectionPath; -} - -QWidget *McuPackage::widget() -{ - if (m_widget) - return m_widget; - - m_widget = new QWidget; - m_fileChooser = new PathChooser; - m_fileChooser->lineEdit()->setButtonIcon(FancyLineEdit::Right, - Icons::RESET.icon()); - m_fileChooser->lineEdit()->setButtonVisible(FancyLineEdit::Right, true); - connect(m_fileChooser->lineEdit(), &FancyLineEdit::rightButtonClicked, this, [&] { - m_fileChooser->setFilePath(m_defaultPath); - }); - - auto layout = new QGridLayout(m_widget); - layout->setContentsMargins(0, 0, 0, 0); - m_infoLabel = new InfoLabel(); - - if (!m_downloadUrl.isEmpty()) { - auto downLoadButton = new QToolButton; - downLoadButton->setIcon(Icons::ONLINE.icon()); - downLoadButton->setToolTip(tr("Download from \"%1\"").arg(m_downloadUrl)); - QObject::connect(downLoadButton, &QToolButton::pressed, this, [this] { - QDesktopServices::openUrl(m_downloadUrl); - }); - layout->addWidget(downLoadButton, 0, 2); - } - - layout->addWidget(m_fileChooser, 0, 0, 1, 2); - layout->addWidget(m_infoLabel, 1, 0, 1, -1); - - m_fileChooser->setFilePath(m_path); - - QObject::connect(this, &McuPackage::statusChanged, this, [this] { - updateStatusUi(); - }); - - QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { - updatePath(); - emit changed(); - }); - - updateStatus(); - return m_widget; -} - -McuPackage::Status McuPackage::status() const -{ - return m_status; -} - -bool McuPackage::validStatus() const -{ - return m_status == McuPackage::ValidPackage || m_status == McuPackage::ValidPackageMismatchedVersion; -} - -void McuPackage::setDownloadUrl(const QString &url) -{ - m_downloadUrl = url; -} - -void McuPackage::setEnvironmentVariableName(const QString &name) -{ - m_environmentVariableName = name; -} - -QString McuPackage::environmentVariableName() const -{ - return m_environmentVariableName; -} - -void McuPackage::setAddToPath(bool addToPath) -{ - m_addToPath = addToPath; -} - -bool McuPackage::addToPath() const -{ - return m_addToPath; -} - -void McuPackage::writeGeneralSettings() const -{ - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_AUTOMATIC_KIT_CREATION); - QSettings *settings = Core::ICore::settings(); - settings->setValue(key, m_automaticKitCreation); -} - -bool McuPackage::writeToSettings() const -{ - const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); - const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + - QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; - Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString()); - - return savedPath != m_path; -} - -void McuPackage::setRelativePathModifier(const QString &path) -{ - m_relativePathModifier = path; -} - -void McuPackage::setVersions(const QStringList &versions) -{ - m_versions = versions; -} - -bool McuPackage::automaticKitCreationEnabled() const -{ - return m_automaticKitCreation; -} - -void McuPackage::setAutomaticKitCreationEnabled(const bool enabled) -{ - m_automaticKitCreation = enabled; -} - -void McuPackage::updatePath() -{ - m_path = m_fileChooser->rawFilePath(); - m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); - updateStatus(); -} - -void McuPackage::updateStatus() -{ - bool validPath = !m_path.isEmpty() && m_path.exists(); - const FilePath detectionPath = basePath() / m_detectionPath; - const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists(); - m_detectedVersion = validPath && validPackage && m_versionDetector - ? m_versionDetector->parseVersion(basePath().toString()) : QString(); - const bool validVersion = m_detectedVersion.isEmpty() || - m_versions.isEmpty() || m_versions.contains(m_detectedVersion); - - m_status = validPath ? - ( validPackage ? - (validVersion ? ValidPackage : ValidPackageMismatchedVersion) - : ValidPathInvalidPackage ) - : m_path.isEmpty() ? EmptyPath : InvalidPath; - - emit statusChanged(); -} - -void McuPackage::updateStatusUi() -{ - switch (m_status) { - case ValidPackage: m_infoLabel->setType(InfoLabel::Ok); break; - case ValidPackageMismatchedVersion: m_infoLabel->setType(InfoLabel::Warning); break; - default: m_infoLabel->setType(InfoLabel::NotOk); break; - } - m_infoLabel->setText(statusText()); -} - -QString McuPackage::statusText() const -{ - const QString displayPackagePath = m_path.toUserOutput(); - const QString displayVersions = m_versions.join(" or "); - const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); - const QString displayRequiredPath = m_versions.empty() ? - outDetectionPath : - QString("%1 %2").arg(outDetectionPath, displayVersions); - const QString displayDetectedPath = m_versions.empty() ? - outDetectionPath : - QString("%1 %2").arg(outDetectionPath, m_detectedVersion); - - QString response; - switch (m_status) { - case ValidPackage: - response = m_detectionPath.isEmpty() - ? ( m_detectedVersion.isEmpty() - ? tr("Path %1 exists.").arg(displayPackagePath) - : tr("Path %1 exists. Version %2 was found.") - .arg(displayPackagePath, m_detectedVersion) ) - : tr("Path %1 is valid, %2 was found.") - .arg(displayPackagePath, displayDetectedPath); - break; - case ValidPackageMismatchedVersion: { - const QString versionWarning = m_versions.size() == 1 ? - tr("but only version %1 is supported").arg(m_versions.first()) : - tr("but only versions %1 are supported").arg(displayVersions); - response = tr("Path %1 is valid, %2 was found, %3.") - .arg(displayPackagePath, displayDetectedPath, versionWarning); - break; - } - case ValidPathInvalidPackage: - response = tr("Path %1 exists, but does not contain %2.") - .arg(displayPackagePath, displayRequiredPath); - break; - case InvalidPath: - response = tr("Path %1 does not exist.").arg(displayPackagePath); - break; - case EmptyPath: - response = m_detectionPath.isEmpty() - ? tr("Path is empty.") - : tr("Path is empty, %1 not found.") - .arg(displayRequiredPath); - break; - } - return response; -} - -McuToolChainPackage::McuToolChainPackage(const QString &label, - const FilePath &defaultPath, - const QString &detectionPath, - const QString &settingsKey, - McuToolChainPackage::Type type, - const McuPackageVersionDetector *versionDetector) - : McuPackage(label, defaultPath, detectionPath, settingsKey, versionDetector) - , m_type(type) -{ -} - -McuToolChainPackage::Type McuToolChainPackage::type() const -{ - return m_type; -} - -bool McuToolChainPackage::isDesktopToolchain() const -{ - return m_type == TypeMSVC || m_type == TypeGCC; -} static ToolChain *msvcToolChain(Id language) { @@ -458,35 +179,42 @@ static ToolChain *iarToolChain(const FilePath &path, Id language) ToolChain *McuToolChainPackage::toolChain(Id language) const { - ToolChain *tc = nullptr; - if (m_type == TypeMSVC) - tc = msvcToolChain(language); - else if (m_type == TypeGCC) - tc = gccToolChain(language); - else if (m_type == TypeIAR) { + switch (m_type) { + case Type::MSVC: + return msvcToolChain(language); + case Type::GCC: + return gccToolChain(language); + case Type::IAR: { const FilePath compiler = path().pathAppended("/bin/iccarm").withExecutableSuffix(); - tc = iarToolChain(compiler, language); + return iarToolChain(compiler, language); } - else { + case Type::ArmGcc: + case Type::KEIL: + case Type::GHS: + case Type::GHSArm: + case Type::Unsupported: { const QLatin1String compilerName( - language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++"); - const QString comp = QLatin1String(m_type == TypeArmGcc ? "/bin/arm-none-eabi-%1" : "/bar/foo-keil-%1") - .arg(compilerName); + language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++"); + const QString comp = QLatin1String(m_type == Type::ArmGcc ? "/bin/arm-none-eabi-%1" + : "/bar/foo-keil-%1") + .arg(compilerName); const FilePath compiler = path().pathAppended(comp).withExecutableSuffix(); - tc = armGccToolChain(compiler, language); + return armGccToolChain(compiler, language); + } + default: + Q_UNREACHABLE(); } - return tc; } QString McuToolChainPackage::toolChainName() const { switch (m_type) { - case TypeArmGcc: return QLatin1String("armgcc"); - case TypeIAR: return QLatin1String("iar"); - case TypeKEIL: return QLatin1String("keil"); - case TypeGHS: return QLatin1String("ghs"); - case TypeGHSArm: return QLatin1String("ghs-arm"); + case Type::ArmGcc: return QLatin1String("armgcc"); + case Type::IAR: return QLatin1String("iar"); + case Type::KEIL: return QLatin1String("keil"); + case Type::GHS: return QLatin1String("ghs"); + case Type::GHSArm: return QLatin1String("ghs-arm"); default: return QLatin1String("unsupported"); } } @@ -504,52 +232,56 @@ QVariant McuToolChainPackage::debuggerId() const DebuggerEngineType engineType; switch (m_type) { - case TypeArmGcc: { + case Type::ArmGcc: { sub = QString::fromLatin1("bin/arm-none-eabi-gdb-py"); displayName = McuPackage::tr("Arm GDB at %1"); engineType = Debugger::GdbEngineType; - break; } - case TypeIAR: { + break; + } + case Type::IAR: { sub = QString::fromLatin1("../common/bin/CSpyBat"); displayName = QLatin1String("CSpy"); engineType = Debugger::NoEngineType; // support for IAR missing - break; } - case TypeKEIL: { + break; + } + case Type::KEIL: { sub = QString::fromLatin1("UV4/UV4"); displayName = QLatin1String("KEIL uVision Debugger"); engineType = Debugger::UvscEngineType; - break; } - default: return QVariant(); + break; + } + default: + return QVariant(); } const FilePath command = path().pathAppended(sub).withExecutableSuffix(); - const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); - QVariant debuggerId; - if (!debugger) { - DebuggerItem newDebugger; - newDebugger.setCommand(command); - newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput())); - newDebugger.setEngineType(engineType); - debuggerId = DebuggerItemManager::registerDebugger(newDebugger); - } else { - debuggerId = debugger->id(); + if (const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command)) { + return debugger->id(); } - return debuggerId; + + DebuggerItem newDebugger; + newDebugger.setCommand(command); + newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput())); + newDebugger.setEngineType(engineType); + return DebuggerItemManager::registerDebugger(newDebugger); } McuTarget::McuTarget(const QVersionNumber &qulVersion, - const Platform &platform, OS os, + const Platform &platform, + OS os, const QVector &packages, - const McuToolChainPackage *toolChainPackage) + const McuToolChainPackage *toolChainPackage, + int colorDepth) : m_qulVersion(qulVersion) , m_platform(platform) , m_os(os) , m_packages(packages) , m_toolChainPackage(toolChainPackage) + , m_colorDepth(colorDepth) { } -QVector McuTarget::packages() const +const QVector &McuTarget::packages() const { return m_packages; } @@ -564,7 +296,7 @@ McuTarget::OS McuTarget::os() const return m_os; } -McuTarget::Platform McuTarget::platform() const +const McuTarget::Platform &McuTarget::platform() const { return m_platform; } @@ -596,7 +328,7 @@ void McuTarget::printPackageProblems() const } } -QVersionNumber McuTarget::qulVersion() const +const QVersionNumber &McuTarget::qulVersion() const { return m_qulVersion; } @@ -606,11 +338,6 @@ int McuTarget::colorDepth() const return m_colorDepth; } -void McuTarget::setColorDepth(int colorDepth) -{ - m_colorDepth = colorDepth; -} - void McuSdkRepository::deletePackagesAndTargets() { qDeleteAll(packages); @@ -701,8 +428,8 @@ void McuSupportOptions::setQulDir(const FilePath &dir) FilePath McuSupportOptions::qulDirFromSettings() { - return packagePathFromSettings(Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, - QSettings::UserScope); + return Sdk::packagePathFromSettings(Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, + QSettings::UserScope); } static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mcuTarget, @@ -738,33 +465,60 @@ static void setKitProperties(const QString &kitName, Kit *k, const McuTarget *mc static void setKitToolchains(Kit *k, const McuToolChainPackage *tcPackage) { - // No Green Hills toolchain, because support for it is missing. - if (tcPackage->type() == McuToolChainPackage::TypeUnsupported - || tcPackage->type() == McuToolChainPackage::TypeGHS - || tcPackage->type() == McuToolChainPackage::TypeGHSArm) + switch (tcPackage->type()) { + case McuToolChainPackage::Type::Unsupported: return; - ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( - ProjectExplorer::Constants::C_LANGUAGE_ID)); - ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( - ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + case McuToolChainPackage::Type::GHS: + case McuToolChainPackage::Type::GHSArm: + return; // No Green Hills toolchain, because support for it is missing. + + case McuToolChainPackage::Type::IAR: + case McuToolChainPackage::Type::KEIL: + case McuToolChainPackage::Type::MSVC: + case McuToolChainPackage::Type::GCC: + case McuToolChainPackage::Type::ArmGcc: + ToolChainKitAspect::setToolChain(k, + tcPackage->toolChain( + ProjectExplorer::Constants::C_LANGUAGE_ID)); + ToolChainKitAspect::setToolChain(k, + tcPackage->toolChain( + ProjectExplorer::Constants::CXX_LANGUAGE_ID)); + return; + + default: + Q_UNREACHABLE(); + } } static void setKitDebugger(Kit *k, const McuToolChainPackage *tcPackage) { - // Qt Creator seems to be smart enough to deduce the right Kit debugger from the ToolChain - // We rely on that at least in the Desktop case. - if (tcPackage->isDesktopToolchain() - // No Green Hills and IAR debugger, because support for it is missing. - || tcPackage->type() == McuToolChainPackage::TypeUnsupported - || tcPackage->type() == McuToolChainPackage::TypeGHS - || tcPackage->type() == McuToolChainPackage::TypeGHSArm - || tcPackage->type() == McuToolChainPackage::TypeIAR) + if (tcPackage->isDesktopToolchain()) { + // Qt Creator seems to be smart enough to deduce the right Kit debugger from the ToolChain return; + } - const QVariant debuggerId = tcPackage->debuggerId(); - if (debuggerId.isValid()) - Debugger::DebuggerKitAspect::setDebugger(k, debuggerId); + switch (tcPackage->type()) { + case McuToolChainPackage::Type::Unsupported: + case McuToolChainPackage::Type::GHS: + case McuToolChainPackage::Type::GHSArm: + case McuToolChainPackage::Type::IAR: + return; // No Green Hills and IAR debugger, because support for it is missing. + + case McuToolChainPackage::Type::KEIL: + case McuToolChainPackage::Type::MSVC: + case McuToolChainPackage::Type::GCC: + case McuToolChainPackage::Type::ArmGcc: { + const QVariant debuggerId = tcPackage->debuggerId(); + if (debuggerId.isValid()) { + Debugger::DebuggerKitAspect::setDebugger(k, debuggerId); + } + return; + } + + default: + Q_UNREACHABLE(); + } } static void setKitDevice(Kit *k, const McuTarget* mcuTarget) @@ -876,8 +630,8 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); // CMake ToolChain file for ghs handles CMAKE_*_COMPILER autonomously - if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::TypeGHS && - mcuTarget->toolChainPackage()->type() != McuToolChainPackage::TypeGHSArm) { + if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHS && + mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHSArm) { config.append(CMakeConfigItem("CMAKE_CXX_COMPILER", "%{Compiler:Executable:Cxx}")); config.append(CMakeConfigItem("CMAKE_C_COMPILER", "%{Compiler:Executable:C}")); } @@ -909,7 +663,7 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat if (mcuTarget->qulVersion() <= QVersionNumber{1,3} // OS variable was removed in Qul 1.4 && mcuTarget->os() == McuTarget::OS::FreeRTOS) config.append(CMakeConfigItem("OS", "FreeRTOS")); - if (mcuTarget->colorDepth() >= 0) + if (mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth) config.append(CMakeConfigItem("QUL_COLOR_DEPTH", QString::number(mcuTarget->colorDepth()).toLatin1())); if (kitNeedsQtVersion()) @@ -918,7 +672,7 @@ static void setKitCMakeOptions(Kit *k, const McuTarget* mcuTarget, const FilePat if (HostOsInfo::isWindowsHost()) { auto type = mcuTarget->toolChainPackage()->type(); - if (type == McuToolChainPackage::TypeGHS || type == McuToolChainPackage::TypeGHSArm) { + if (type == McuToolChainPackage::Type::GHS || type == McuToolChainPackage::Type::GHSArm) { // See https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565802&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565802 // and https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565803&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565803 CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM"); @@ -944,7 +698,7 @@ QString McuSupportOptions::kitName(const McuTarget *mcuTarget) const QString compilerName = tcPkg && !tcPkg->isDesktopToolchain() ? QString::fromLatin1(" (%1)").arg(tcPkg->toolChainName().toUpper()) : ""; - const QString colorDepth = mcuTarget->colorDepth() > 0 + const QString colorDepth = mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth ? QString::fromLatin1(" %1bpp").arg(mcuTarget->colorDepth()) : ""; const QString targetName = mcuTarget->platform().displayName.isEmpty() @@ -1310,100 +1064,5 @@ void McuSupportOptions::fixExistingKits() delete qtForMCUsPackage; } -class McuDependenciesKitAspectWidget final : public KitAspectWidget -{ - Q_DECLARE_TR_FUNCTIONS(McuSupport::McuDependenciesKitAspect) - -public: - McuDependenciesKitAspectWidget(Kit *workingCopy, const KitAspect *ki) - : KitAspectWidget(workingCopy, ki) - {} - - void makeReadOnly() override {} - void refresh() override {} - void addToLayout(Utils::LayoutBuilder &) override {} -}; - } // Internal - -McuDependenciesKitAspect::McuDependenciesKitAspect() -{ - setObjectName(QLatin1String("McuDependenciesKitAspect")); - setId(McuDependenciesKitAspect::id()); - setDisplayName(tr("MCU Dependencies")); - setDescription(tr("Paths to 3rd party dependencies")); - setPriority(28500); -} - -Tasks McuDependenciesKitAspect::validate(const Kit *k) const -{ - Tasks result; - QTC_ASSERT(k, return result); - - const QVariant checkFormat = k->value(McuDependenciesKitAspect::id()); - if (!checkFormat.isNull() && !checkFormat.canConvert(QVariant::List)) - return { BuildSystemTask(Task::Error, tr("The MCU dependencies setting value is invalid.")) }; - - const QVariant envStringList = k->value(EnvironmentKitAspect::id()); - if (!envStringList.isNull() && !envStringList.canConvert(QVariant::List)) - return { BuildSystemTask(Task::Error, tr("The environment setting value is invalid.")) }; - - const auto environment = Utils::NameValueDictionary(envStringList.toStringList()); - for (const auto &dependency: dependencies(k)) { - if (!environment.hasKey(dependency.name)) { - result << BuildSystemTask(Task::Warning, tr("Environment variable %1 not defined.").arg(dependency.name)); - } else { - const auto path = Utils::FilePath::fromUserInput( - environment.value(dependency.name) + "/" + dependency.value); - if (!path.exists()) { - result << BuildSystemTask(Task::Warning, tr("%1 not found.").arg(path.toUserOutput())); - } - } - } - - return result; -} - -void McuDependenciesKitAspect::fix(Kit *k) -{ - QTC_ASSERT(k, return); - - const QVariant variant = k->value(McuDependenciesKitAspect::id()); - if (!variant.isNull() && !variant.canConvert(QVariant::List)) { - qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(k->displayName())); - setDependencies(k, Utils::NameValueItems()); - } -} - -KitAspectWidget *McuDependenciesKitAspect::createConfigWidget(Kit *k) const -{ - QTC_ASSERT(k, return nullptr); - return new Internal::McuDependenciesKitAspectWidget(k, this); -} - -KitAspect::ItemList McuDependenciesKitAspect::toUserOutput(const Kit *k) const -{ - Q_UNUSED(k); - return {}; -} - -Utils::Id McuDependenciesKitAspect::id() -{ - return "PE.Profile.McuDependencies"; -} - - -Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *k) -{ - if (k) - return Utils::NameValueItem::fromStringList(k->value(McuDependenciesKitAspect::id()).toStringList()); - return Utils::NameValueItems(); -} - -void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) -{ - if (k) - k->setValue(McuDependenciesKitAspect::id(), Utils::NameValueItem::toStringList(dependencies)); -} - } // McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 807683167f2..e7b0f66015a 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -1,6 +1,7 @@ /**************************************************************************** ** -** 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 Qt Creator. @@ -25,12 +26,8 @@ #pragma once -#include "mcusupportversiondetection.h" #include "mcusupport_global.h" -#include -#include - #include #include #include @@ -51,115 +48,11 @@ class ToolChain; namespace McuSupport { namespace Internal { +class McuPackage; +class McuToolChainPackage; + void printMessage(const QString &message, bool important); -class McuPackage : public QObject -{ - Q_OBJECT - -public: - enum Status { - EmptyPath, - InvalidPath, - ValidPathInvalidPackage, - ValidPackageMismatchedVersion, - ValidPackage - }; - - McuPackage(const QString &label, const Utils::FilePath &defaultPath, - const QString &detectionPath, const QString &settingsKey, - const McuPackageVersionDetector *versionDetector = nullptr); - virtual ~McuPackage() = default; - - Utils::FilePath basePath() const; - Utils::FilePath path() const; - QString label() const; - Utils::FilePath defaultPath() const; - QString detectionPath() const; - QString statusText() const; - void updateStatus(); - - Status status() const; - bool validStatus() const; - void setDownloadUrl(const QString &url); - void setEnvironmentVariableName(const QString &name); - void setAddToPath(bool addToPath); - bool addToPath() const; - void writeGeneralSettings() const; - bool writeToSettings() const; - void setRelativePathModifier(const QString &path); - void setVersions(const QStringList &versions); - - bool automaticKitCreationEnabled() const; - void setAutomaticKitCreationEnabled(const bool enabled); - - QWidget *widget(); - - QString environmentVariableName() const; - -signals: - void changed(); - void statusChanged(); - -private: - void updatePath(); - void updateStatusUi(); - - QWidget *m_widget = nullptr; - Utils::PathChooser *m_fileChooser = nullptr; - Utils::InfoLabel *m_infoLabel = nullptr; - - const QString m_label; - const Utils::FilePath m_defaultPath; - const QString m_detectionPath; - const QString m_settingsKey; - const McuPackageVersionDetector *m_versionDetector; - - Utils::FilePath m_path; - QString m_relativePathModifier; // relative path to m_path to be returned by path() - QString m_detectedVersion; - QStringList m_versions; - QString m_downloadUrl; - QString m_environmentVariableName; - bool m_addToPath = false; - bool m_automaticKitCreation = true; - - Status m_status = InvalidPath; -}; - -class McuToolChainPackage : public McuPackage -{ -public: - enum Type { - TypeArmGcc, - TypeIAR, - TypeKEIL, - TypeGHS, - TypeMSVC, - TypeGCC, - TypeGHSArm, - TypeUnsupported - }; - - McuToolChainPackage(const QString &label, - const Utils::FilePath &defaultPath, - const QString &detectionPath, - const QString &settingsKey, - Type type, - const McuPackageVersionDetector *versionDetector = nullptr - ); - - Type type() const; - bool isDesktopToolchain() const; - ProjectExplorer::ToolChain *toolChain(Utils::Id language) const; - QString toolChainName() const; - QString cmakeToolChainFileName() const; - QVariant debuggerId() const; - -private: - const Type m_type; -}; - class McuTarget : public QObject { Q_OBJECT @@ -177,16 +70,20 @@ public: QString vendor; }; - McuTarget(const QVersionNumber &qulVersion, const Platform &platform, OS os, - const QVector &packages, - const McuToolChainPackage *toolChainPackage); + enum { UnspecifiedColorDepth = -1 }; - QVersionNumber qulVersion() const; - QVector packages() const; + McuTarget(const QVersionNumber &qulVersion, + const Platform &platform, + OS os, + const QVector &packages, + const McuToolChainPackage *toolChainPackage, + int colorDepth = UnspecifiedColorDepth); + + const QVersionNumber &qulVersion() const; + const QVector &packages() const; const McuToolChainPackage *toolChainPackage() const; - Platform platform() const; + const Platform &platform() const; OS os() const; - void setColorDepth(int colorDepth); int colorDepth() const; bool isValid() const; void printPackageProblems() const; @@ -194,10 +91,10 @@ public: private: const QVersionNumber m_qulVersion; const Platform m_platform; - const OS m_os = OS::BareMetal; + const OS m_os; const QVector m_packages; const McuToolChainPackage *m_toolChainPackage; - int m_colorDepth = -1; + const int m_colorDepth; }; class McuSdkRepository @@ -261,24 +158,4 @@ signals: }; } // namespace Internal - -class MCUSUPPORTSHARED_EXPORT McuDependenciesKitAspect : public ProjectExplorer::KitAspect -{ - Q_OBJECT - -public: - McuDependenciesKitAspect(); - - ProjectExplorer::Tasks validate(const ProjectExplorer::Kit *k) const override; - void fix(ProjectExplorer::Kit *k) override; - - ProjectExplorer::KitAspectWidget *createConfigWidget(ProjectExplorer::Kit *k) const override; - - ItemList toUserOutput(const ProjectExplorer::Kit *k) const override; - - static Utils::Id id(); - static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *k); - static void setDependencies(ProjectExplorer::Kit *k, const Utils::NameValueItems &dependencies); -}; - } // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index f4b79ec0f2e..eb83d48f30a 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptionspage.h" #include "mcusupportoptions.h" diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp index 3e7db5e0ad7..21d8878645b 100644 --- a/src/plugins/mcusupport/mcusupportplugin.cpp +++ b/src/plugins/mcusupport/mcusupportplugin.cpp @@ -23,6 +23,7 @@ ** ****************************************************************************/ +#include "mcukitinformation.h" #include "mcusupportplugin.h" #include "mcusupportconstants.h" #include "mcusupportdevice.h" diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 44ad3c2356e..a966d10870d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -23,12 +23,14 @@ ** ****************************************************************************/ +#include "mcupackage.h" #include "mcusupportconstants.h" #include "mcusupportoptions.h" #include "mcusupportsdk.h" #include "mcusupportversiondetection.h" #include +#include #include #include #include @@ -63,28 +65,26 @@ static FilePath findInProgramFiles(const QString &folder) McuPackage *createQtForMCUsPackage() { - auto result = new McuPackage( - McuPackage::tr("Qt for MCUs SDK"), - FileUtils::homePath(), - FilePath("bin/qmltocpp").withExecutableSuffix().toString(), - Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK); - result->setEnvironmentVariableName("Qul_DIR"); - return result; + return new McuPackage(McuPackage::tr("Qt for MCUs SDK"), + FileUtils::homePath(), // defaultPath + FilePath("bin/qmltocpp").withExecutableSuffix().toString(), // detectionPath + Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, // settingsKey + QStringLiteral("Qul_DIR")); // envVarName } static McuToolChainPackage *createMsvcToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeMSVC); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::MSVC); } static McuToolChainPackage *createGccToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeGCC); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::GCC); } static McuToolChainPackage *createUnsupportedToolChainPackage() { - return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::TypeUnsupported); + return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::Unsupported); } static McuToolChainPackage *createArmGccPackage() @@ -112,15 +112,13 @@ static McuToolChainPackage *createArmGccPackage() "\\b(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - McuPackage::tr("GNU Arm Embedded Toolchain"), - defaultPath, - detectionPath, - "GNUArmEmbeddedToolchain", - McuToolChainPackage::TypeArmGcc, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage(McuPackage::tr("GNU Arm Embedded Toolchain"), + defaultPath, + detectionPath, + "GNUArmEmbeddedToolchain", // settingsKey + McuToolChainPackage::Type::ArmGcc, + envVar, + versionDetector); } static McuToolChainPackage *createGhsToolchainPackage() @@ -135,15 +133,14 @@ static McuToolChainPackage *createGhsToolchainPackage() "\\bv(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - "Green Hills Compiler", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("ccv850"), - "GHSToolchain", - McuToolChainPackage::TypeGHS, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("Green Hills Compiler", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix( + "ccv850"), // detectionPath + "GHSToolchain", // settingsKey + McuToolChainPackage::Type::GHS, + envVar, + versionDetector); } static McuToolChainPackage *createGhsArmToolchainPackage() @@ -158,15 +155,13 @@ static McuToolChainPackage *createGhsArmToolchainPackage() "\\bv(\\d+\\.\\d+\\.\\d+)\\b" ); - auto result = new McuToolChainPackage( - "Green Hills Compiler for ARM", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("cxarm"), - "GHSArmToolchain", - McuToolChainPackage::TypeGHSArm, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("Green Hills Compiler for ARM", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix("cxarm"), // detectionPath + "GHSArmToolchain", // settingsKey + McuToolChainPackage::Type::GHSArm, + envVar, + versionDetector); } static McuToolChainPackage *createIarToolChainPackage() @@ -194,15 +189,13 @@ static McuToolChainPackage *createIarToolChainPackage() "\\bV(\\d+\\.\\d+\\.\\d+)\\.\\d+\\b" ); - auto result = new McuToolChainPackage( - "IAR ARM Compiler", - defaultPath, - detectionPath, - "IARToolchain", - McuToolChainPackage::TypeIAR, - versionDetector); - result->setEnvironmentVariableName(envVar); - return result; + return new McuToolChainPackage("IAR ARM Compiler", + defaultPath, + detectionPath, + "IARToolchain", // settings key + McuToolChainPackage::Type::IAR, + envVar, + versionDetector); } static McuPackage *createRGLPackage() @@ -223,13 +216,11 @@ static McuPackage *createRGLPackage() } } - auto result = new McuPackage( - "Renesas Graphics Library", - defaultPath, - {}, - "RGL"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage("Renesas Graphics Library", + defaultPath, + {}, // detection path + "RGL", + envVar); } static McuPackage *createStm32CubeProgrammerPackage() @@ -245,15 +236,16 @@ static McuPackage *createStm32CubeProgrammerPackage() if (programPath.exists()) defaultPath = programPath; } - auto result = new McuPackage( - McuPackage::tr("STM32CubeProgrammer"), - defaultPath, - QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "/bin/STM32_Programmer_CLI.exe" - : "/bin/STM32_Programmer.sh"), - "Stm32CubeProgrammer"); + auto result + = new McuPackage(McuPackage::tr("STM32CubeProgrammer"), + defaultPath, + QLatin1String(Utils::HostOsInfo::isWindowsHost() + ? "/bin/STM32_Programmer_CLI.exe" + : "/bin/STM32_Programmer.sh"), // detection path + "Stm32CubeProgrammer", + {}, // env var + "https://www.st.com/en/development-tools/stm32cubeprog.html"); // download url result->setRelativePathModifier("/bin"); - result->setDownloadUrl( - "https://www.st.com/en/development-tools/stm32cubeprog.html"); result->setAddToPath(true); return result; } @@ -281,14 +273,13 @@ static McuPackage *createMcuXpressoIdePackage() defaultPath = programPath; } - auto result = new McuPackage( - "MCUXpresso IDE", - defaultPath, - Utils::HostOsInfo::withExecutableSuffix("ide/binaries/crt_emu_cm_redlink"), - "MCUXpressoIDE"); - result->setDownloadUrl("https://www.nxp.com/mcuxpresso/ide"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage("MCUXpresso IDE", + defaultPath, + Utils::HostOsInfo::withExecutableSuffix( + "ide/binaries/crt_emu_cm_redlink"), // detection path + "MCUXpressoIDE", // settings key + envVar, + "https://www.nxp.com/mcuxpresso/ide"); // download url } static McuPackage *createCypressProgrammerPackage() @@ -313,8 +304,8 @@ static McuPackage *createCypressProgrammerPackage() "Cypress Auto Flash Utility", defaultPath, Utils::HostOsInfo::withExecutableSuffix("/bin/openocd"), - "CypressAutoFlashUtil"); - result->setEnvironmentVariableName(envVar); + "CypressAutoFlashUtil", + envVar); return result; } @@ -340,8 +331,8 @@ static McuPackage *createRenesasProgrammerPackage() "Renesas Flash Programmer", defaultPath, Utils::HostOsInfo::withExecutableSuffix("rfp-cli"), - "RenesasFlashProgrammer"); - result->setEnvironmentVariableName(envVar); + "RenesasFlashProgrammer", + envVar); return result; } @@ -420,14 +411,13 @@ static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc) const auto versionDetector = generatePackageVersionDetector(desc.boardSdk.envVar); - auto result = new McuPackage( - sdkName, - defaultPath, - {}, - desc.boardSdk.envVar, - versionDetector); - result->setEnvironmentVariableName(desc.boardSdk.envVar); - return result; + return new McuPackage(sdkName, + defaultPath, + {}, // detection path + desc.boardSdk.envVar, // settings key + desc.boardSdk.envVar, // env var + {}, // download URL + versionDetector); } static McuPackage *createFreeRTOSSourcesPackage(const QString &envVar, const FilePath &boardSdkDir, @@ -441,14 +431,12 @@ static McuPackage *createFreeRTOSSourcesPackage(const QString &envVar, const Fil else if (!boardSdkDir.isEmpty() && !freeRTOSBoardSdkSubDir.isEmpty()) defaultPath = boardSdkDir / freeRTOSBoardSdkSubDir; - auto result = new McuPackage( - QString::fromLatin1("FreeRTOS Sources (%1)").arg(envVarPrefix), - defaultPath, - {}, - QString::fromLatin1("FreeRTOSSourcePackage_%1").arg(envVarPrefix)); - result->setDownloadUrl("https://freertos.org"); - result->setEnvironmentVariableName(envVar); - return result; + return new McuPackage(QString::fromLatin1("FreeRTOS Sources (%1)").arg(envVarPrefix), + defaultPath, + {}, + QString::fromLatin1("FreeRTOSSourcePackage_%1").arg(envVarPrefix), + envVar, + "https://freertos.org"); } struct McuTargetFactory @@ -524,9 +512,13 @@ protected: const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), - platform, os, required3rdPartyPkgs, tcPkg); - if (desc.platform.colorDepths.count() > 1) - mcuTarget->setColorDepth(colorDepth); + platform, + os, + required3rdPartyPkgs, + tcPkg, + desc.platform.colorDepths.count() > 1 + ? colorDepth + : McuTarget::UnspecifiedColorDepth); mcuTargets.append(mcuTarget); } } @@ -567,7 +559,7 @@ protected: // Desktop toolchains don't need any additional settings if (tcPkg && !tcPkg->isDesktopToolchain() - && tcPkg->type() != McuToolChainPackage::TypeUnsupported) + && tcPkg->type() != McuToolChainPackage::Type::Unsupported) required3rdPartyPkgs.append(tcPkg); // Add setting specific to platform IDE @@ -598,10 +590,13 @@ protected: required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOS.envVar)); } - const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; + const McuTarget::Platform platform({ desc.platform.id, desc.platform.name, desc.platform.vendor }); auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), - platform, os, required3rdPartyPkgs, tcPkg); - mcuTarget->setColorDepth(colorDepth); + platform, + os, + required3rdPartyPkgs, + tcPkg, + colorDepth); mcuTargets.append(mcuTarget); } return mcuTargets; @@ -883,6 +878,15 @@ void targetsAndPackages(const Utils::FilePath &dir, McuSdkRepository *repo) }); } +FilePath packagePathFromSettings(const QString &settingsKey, QSettings::Scope scope, const FilePath &defaultPath) +{ + QSettings *settings = Core::ICore::settings(scope); + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + + QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + settingsKey; + const QString path = settings->value(key, defaultPath.toString()).toString(); + return FilePath::fromUserInput(path); +} + } // namespace Sdk } // namespace Internal } // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportsdk.h b/src/plugins/mcusupport/mcusupportsdk.h index 2f687555d68..8429462880d 100644 --- a/src/plugins/mcusupport/mcusupportsdk.h +++ b/src/plugins/mcusupport/mcusupportsdk.h @@ -25,6 +25,7 @@ #pragma once +#include #include namespace Utils { @@ -48,6 +49,9 @@ void targetsAndPackages(const Utils::FilePath &qulDir, McuSdkRepository *repo); Utils::FilePath kitsPath(const Utils::FilePath &dir); +Utils::FilePath packagePathFromSettings(const QString &settingsKey, + QSettings::Scope scope = QSettings::UserScope, + const Utils::FilePath &defaultPath = {}); } // namespace Sdk } // namespace Internal } // namespace McuSupport diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp index ea9dbd4a059..ab685ae8cbd 100644 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ b/src/plugins/projectexplorer/applicationlauncher.cpp @@ -451,18 +451,8 @@ void ApplicationLauncherPrivate::handleApplicationFinished() { QTC_ASSERT(m_state == Run, return); - if (m_deviceProcess->exitStatus() == QProcess::CrashExit) { + if (m_deviceProcess->exitStatus() == QProcess::CrashExit) doReportError(m_deviceProcess->errorString(), QProcess::Crashed); - } else { - const int exitCode = m_deviceProcess->exitCode(); - if (exitCode != 0) { - doReportError(ApplicationLauncher::tr("Application finished with exit code %1.") - .arg(exitCode), QProcess::UnknownError); - } else { - emit q->appendMessage(ApplicationLauncher::tr("Application finished with exit code 0."), - Utils::NormalMessageFormat); - } - } setFinished(); } diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 4920f771571..076fb1c8953 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -172,7 +172,10 @@ AppOutputPane::AppOutputPane() : m_attachButton(new QToolButton), m_settingsButton(new QToolButton), m_formatterWidget(new QWidget), - m_handler(new ShowOutputTaskHandler(this)) + m_handler(new ShowOutputTaskHandler(this, + tr("Show &App Output"), + tr("Show the output that generated this issue in the application output window"), + tr("A"))) { ExtensionSystem::PluginManager::addObject(m_handler); diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 8382d2d0600..424b49d802c 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -29,6 +29,7 @@ #include "projectexplorer.h" #include "runconfiguration.h" #include "runcontrol.h" +#include "session.h" #include "target.h" #include @@ -77,7 +78,13 @@ BuildSystem::BuildSystem(Target *target) // Timer: d->m_delayedParsingTimer.setSingleShot(true); - connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, &BuildSystem::triggerParsing); + connect(&d->m_delayedParsingTimer, &QTimer::timeout, this, + [this] { + if (SessionManager::hasProject(project())) + triggerParsing(); + else + requestDelayedParse(); + }); } BuildSystem::~BuildSystem() diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp index 839a1d25469..a51397bd256 100644 --- a/src/plugins/projectexplorer/compileoutputwindow.cpp +++ b/src/plugins/projectexplorer/compileoutputwindow.cpp @@ -116,7 +116,10 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) : qRegisterMetaType("QTextCharFormat"); - m_handler = new ShowOutputTaskHandler(this); + m_handler = new ShowOutputTaskHandler(this, + tr("Show Compile &Output"), + tr("Show the output that generated this issue in the compile output window"), + tr("O")); ExtensionSystem::PluginManager::addObject(m_handler); setupContext(C_COMPILE_OUTPUT, m_outputWindow); loadSettings(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 8e395368a8c..9090500f493 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -59,7 +59,6 @@ class QtcProcess; namespace ProjectExplorer { -class Connection; class DeviceProcess; class DeviceProcessList; class Kit; diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 5d7d285e668..bf265b0258f 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -51,7 +51,7 @@ public: SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {} SshDeviceProcess * const q; - bool ignoreFinished = true; + bool ignoreSelfSignals = true; QSsh::SshConnection *connection = nullptr; QSsh::SshRemoteProcessPtr remoteProcess; Runnable runnable; @@ -74,7 +74,17 @@ SshDeviceProcess::SshDeviceProcess(const IDevice::ConstPtr &device, QObject *par : DeviceProcess(device, QtcProcess::TerminalOn, parent), d(std::make_unique(this)) { - connect(this, &QtcProcess::finished, this, &SshDeviceProcess::handleThisProcessFinished); + // Hack: we rely on fact that below slots were called before any other external slots connected + // to this instance signals. That's why we don't re-emit them from inside our handlers since + // these signal will reach all other external slots anyway after our handlers are done. + connect(this, &QtcProcess::started, this, [this] { + if (!d->ignoreSelfSignals) + handleProcessStarted(); + }); + connect(this, &QtcProcess::finished, this, [this] { + if (!d->ignoreSelfSignals) + handleProcessFinished(QtcProcess::errorString()); + }); connect(&d->killTimer, &QTimer::timeout, this, &SshDeviceProcess::handleKillOperationTimeout); } @@ -185,8 +195,8 @@ void SshDeviceProcess::handleConnected() const QString display = d->displayName(); if (!display.isEmpty()) d->remoteProcess->requestX11Forwarding(display); + d->ignoreSelfSignals = !runInTerminal(); if (runInTerminal()) { - d->ignoreFinished = false; setAbortOnMetaChars(false); setCommand(d->remoteProcess->fullLocalCommandLine(true)); QtcProcess::start(); @@ -194,7 +204,7 @@ void SshDeviceProcess::handleConnected() connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::started, this, &SshDeviceProcess::handleProcessStarted); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::done, - this, &SshDeviceProcess::handleRemoteProcessFinished); + this, &SshDeviceProcess::handleProcessFinished); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardOutput, this, &QtcProcess::readyReadStandardOutput); connect(d->remoteProcess.get(), &QSsh::SshRemoteProcess::readyReadStandardError, @@ -234,31 +244,17 @@ void SshDeviceProcess::handleProcessStarted() QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connected, return); d->setState(SshDeviceProcessPrivate::ProcessRunning); - emit started(); + if (d->ignoreSelfSignals) + emit started(); } -void SshDeviceProcess::handleThisProcessFinished() -{ - if (d->ignoreFinished) - return; - // Hack: we rely on fact that this slot was called before any other external slot connected - // to finished() signal. That's why we don't emit finished() signal from inside - // handleProcessFinished() since this signal will reach all other external slots anyway. - handleProcessFinished(QtcProcess::errorString(), false); -} - -void SshDeviceProcess::handleRemoteProcessFinished(const QString &error) -{ - handleProcessFinished(error, true); -} - -void SshDeviceProcess::handleProcessFinished(const QString &error, bool emitFinished) +void SshDeviceProcess::handleProcessFinished(const QString &error) { d->errorMessage = error; if (d->killOperation && error.isEmpty()) d->errorMessage = tr("The process was ended forcefully."); d->setState(SshDeviceProcessPrivate::Inactive); - if (emitFinished) + if (d->ignoreSelfSignals) emit finished(); } @@ -345,7 +341,6 @@ void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDe QMetaObject::invokeMethod(q, &QtcProcess::stopProcess, Qt::QueuedConnection); } killTimer.stop(); - ignoreFinished = true; if (remoteProcess) remoteProcess->disconnect(q); if (connection) { diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h index 11b5a92bc12..0980d530bcf 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h @@ -60,9 +60,7 @@ private: void handleConnectionError(); void handleDisconnected(); void handleProcessStarted(); - void handleThisProcessFinished(); - void handleRemoteProcessFinished(const QString &error); - void handleProcessFinished(const QString &error, bool emitFinished); + void handleProcessFinished(const QString &error); void handleKillOperationFinished(const QString &errorMessage); void handleKillOperationTimeout(); diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e4f4098c5ff..a194f3f8f3c 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1187,8 +1187,8 @@ Toolchains GccToolChainFactory::autoDetectToolchains( bool existingTcMatches = false; const FilePath existingCommand = existingTc->compilerCommand(); if ((requiredTypeId == Constants::CLANG_TOOLCHAIN_TYPEID - && language == Constants::CXX_LANGUAGE_ID - && !existingCommand.fileName().contains("clang++")) + && ((language == Constants::CXX_LANGUAGE_ID && !existingCommand.fileName().contains("clang++")) + || (language == Constants::C_LANGUAGE_ID && !existingCommand.baseName().endsWith("clang")))) || compilerPath.toString().contains("icecc") || compilerPath.toString().contains("ccache")) { existingTcMatches = existingCommand == compilerPath; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index f0824ead6e0..883760dfda0 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1196,6 +1196,7 @@ void SimpleTargetRunner::start() void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstPtr &device) { + m_stopForced = false; m_stopReported = false; m_launcher.disconnect(this); m_launcher.setUseTerminal(m_useTerminal); @@ -1205,11 +1206,34 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP const QString msg = RunControl::tr("Starting %1...").arg(runnable.command.toUserOutput()); appendMessage(msg, Utils::NormalMessageFormat); + connect(&m_launcher, &ApplicationLauncher::processExited, + this, [this, runnable](int exitCode, QProcess::ExitStatus status) { + if (m_stopReported) + return; + const QString msg = (status == QProcess::CrashExit) + ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode); + const QString displayName = runnable.command.executable().toUserOutput(); + appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); + m_stopReported = true; + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::error, + this, [this, runnable](QProcess::ProcessError error) { + if (m_stopReported) + return; + if (error == QProcess::Timedout) + return; // No actual change on the process side. + const QString msg = m_stopForced ? tr("The process was ended forcefully.") + : userMessageForProcessError(error, runnable.command.executable()); + appendMessage(msg, Utils::NormalMessageFormat); + m_stopReported = true; + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::appendMessage, this, &RunWorker::appendMessage); + if (isDesktop) { - - connect(&m_launcher, &ApplicationLauncher::appendMessage, - this, &SimpleTargetRunner::appendMessage); - connect(&m_launcher, &ApplicationLauncher::processStarted, this, [this] { // Console processes only know their pid after being started ProcessHandle pid = m_launcher.applicationPID(); @@ -1218,33 +1242,6 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP reportStarted(); }); - connect(&m_launcher, &ApplicationLauncher::processExited, - this, [this, runnable](int exitCode, QProcess::ExitStatus status) { - if (m_stopReported) - return; - const QString msg = (status == QProcess::CrashExit) - ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode); - const QString displayName = runnable.command.executable().toUserOutput(); - appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); - m_stopReported = true; - reportStopped(); - }); - - connect(&m_launcher, &ApplicationLauncher::error, - this, [this, runnable](QProcess::ProcessError error) { - if (error == QProcess::Timedout) - return; // No actual change on the process side. - if (error != QProcess::Crashed) { - const QString msg = userMessageForProcessError( - error, runnable.command.executable()); - appendMessage(msg, Utils::NormalMessageFormat); - } - if (!m_stopReported) { - m_stopReported = true; - reportStopped(); - } - }); - if (runnable.command.isEmpty()) { reportFailure(RunControl::tr("No executable specified.")); } else { @@ -1252,27 +1249,14 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP } } else { - - connect(&m_launcher, &ApplicationLauncher::error, this, [this] { - reportFailure(m_launcher.errorString()); - }); - connect(&m_launcher, &ApplicationLauncher::processStarted, this, &RunWorker::reportStarted); - - connect(&m_launcher, &ApplicationLauncher::processExited, - this, [this] { - m_launcher.disconnect(this); - reportStopped(); - }); - - connect(&m_launcher, &ApplicationLauncher::appendMessage, this, &RunWorker::appendMessage); - m_launcher.start(runnable, device); } } void SimpleTargetRunner::stop() { + m_stopForced = true; m_launcher.stop(); } @@ -1559,7 +1543,7 @@ QString RunWorker::userMessageForProcessError(QProcess::ProcessError error, cons "permissions to invoke the program.").arg(program.toUserOutput()); break; case QProcess::Crashed: - msg = tr("The process was ended forcefully."); + msg = tr("The process crashed."); break; case QProcess::Timedout: // "The last waitFor...() function timed out. " diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index 6f00b57e97d..c1ab5d67813 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -308,6 +308,7 @@ private: bool m_stopReported = false; bool m_useTerminal = false; bool m_runAsRoot = false; + bool m_stopForced = false; }; class PROJECTEXPLORER_EXPORT OutputFormatterFactory diff --git a/src/plugins/projectexplorer/showoutputtaskhandler.cpp b/src/plugins/projectexplorer/showoutputtaskhandler.cpp index 8190cd7431b..592ab6e8dab 100644 --- a/src/plugins/projectexplorer/showoutputtaskhandler.cpp +++ b/src/plugins/projectexplorer/showoutputtaskhandler.cpp @@ -30,15 +30,19 @@ #include #include #include +#include #include namespace ProjectExplorer { namespace Internal { -ShowOutputTaskHandler::ShowOutputTaskHandler(Core::IOutputPane *window) : m_window(window) +ShowOutputTaskHandler::ShowOutputTaskHandler(Core::IOutputPane *window, const QString &text, + const QString &tooltip, const QString &shortcut) + : m_window(window), m_text(text), m_tooltip(tooltip), m_shortcut(shortcut) { - Q_ASSERT(m_window); + QTC_CHECK(m_window); + QTC_CHECK(!m_text.isEmpty()); } bool ShowOutputTaskHandler::canHandle(const Task &task) const @@ -64,9 +68,11 @@ void ShowOutputTaskHandler::handle(const Task &task) QAction *ShowOutputTaskHandler::createAction(QObject *parent) const { - QAction *outputAction = new QAction(tr("Show &Output"), parent); - outputAction->setToolTip(tr("Show output generating this issue.")); - outputAction->setShortcut(QKeySequence(tr("O"))); + QAction * const outputAction = new QAction(m_text, parent); + if (!m_tooltip.isEmpty()) + outputAction->setToolTip(m_tooltip); + if (!m_shortcut.isEmpty()) + outputAction->setShortcut(QKeySequence(m_shortcut)); outputAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); return outputAction; } diff --git a/src/plugins/projectexplorer/showoutputtaskhandler.h b/src/plugins/projectexplorer/showoutputtaskhandler.h index 0dd70f7f10d..b30f63388d7 100644 --- a/src/plugins/projectexplorer/showoutputtaskhandler.h +++ b/src/plugins/projectexplorer/showoutputtaskhandler.h @@ -37,7 +37,8 @@ class ShowOutputTaskHandler : public ITaskHandler Q_OBJECT public: - explicit ShowOutputTaskHandler(Core::IOutputPane *window); + explicit ShowOutputTaskHandler(Core::IOutputPane *window, const QString &text, + const QString &tooltip, const QString &shortcut); bool canHandle(const Task &) const override; void handle(const Task &task) override; @@ -45,6 +46,9 @@ public: private: Core::IOutputPane * const m_window; + const QString m_text; + const QString m_tooltip; + const QString m_shortcut; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 68532c1a534..b501a98bdd1 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -251,11 +251,19 @@ extend_qtc_plugin(QmlDesigner itemlibraryimport.cpp itemlibraryimport.h itemlibrarycategoriesmodel.cpp itemlibrarycategoriesmodel.h itemlibraryaddimportmodel.cpp itemlibraryaddimportmodel.h - itemlibraryassetsmodel.cpp itemlibraryassetsmodel.h - itemlibraryassetsiconprovider.cpp itemlibraryassetsiconprovider.h - itemlibraryassetsdir.cpp itemlibraryassetsdir.h - itemlibraryassetsdirsmodel.cpp itemlibraryassetsdirsmodel.h - itemlibraryassetsfilesmodel.cpp itemlibraryassetsfilesmodel.h +) + +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/assetslibrary + SOURCES + assetslibrary.qrc + assetslibraryview.cpp assetslibraryview.h + assetslibrarywidget.cpp assetslibrarywidget.h + assetslibrarymodel.cpp assetslibrarymodel.h + assetslibraryiconprovider.cpp assetslibraryiconprovider.h + assetslibrarydir.cpp assetslibrarydir.h + assetslibrarydirsmodel.cpp assetslibrarydirsmodel.h + assetslibraryfilesmodel.cpp assetslibraryfilesmodel.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc new file mode 100644 index 00000000000..f8cea612985 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrary.qrc @@ -0,0 +1,16 @@ + + + images/asset_default.png + images/asset_default@2x.png + images/asset_shader.png + images/asset_shader@2x.png + images/asset_shader_128.png + images/asset_sound.png + images/asset_sound@2x.png + images/asset_sound_128.png + images/asset_video.png + images/asset_video@2x.png + images/browse.png + images/browse@2x.png + + diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp similarity index 62% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp index e5bbaf792dd..2c965d702f6 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.cpp @@ -23,13 +23,13 @@ ** ****************************************************************************/ -#include "itemlibraryassetsdir.h" -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibrarydir.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibraryfilesmodel.h" namespace QmlDesigner { -ItemLibraryAssetsDir::ItemLibraryAssetsDir(const QString &path, int depth, bool expanded, QObject *parent) +AssetsLibraryDir::AssetsLibraryDir(const QString &path, int depth, bool expanded, QObject *parent) : QObject(parent) , m_dirPath(path) , m_dirDepth(depth) @@ -38,13 +38,13 @@ ItemLibraryAssetsDir::ItemLibraryAssetsDir(const QString &path, int depth, bool } -QString ItemLibraryAssetsDir::dirName() const { return m_dirPath.split('/').last(); } -QString ItemLibraryAssetsDir::dirPath() const { return m_dirPath; } -int ItemLibraryAssetsDir::dirDepth() const { return m_dirDepth; } -bool ItemLibraryAssetsDir::dirExpanded() const { return m_dirExpanded; } -bool ItemLibraryAssetsDir::dirVisible() const { return m_dirVisible; } +QString AssetsLibraryDir::dirName() const { return m_dirPath.split('/').last(); } +QString AssetsLibraryDir::dirPath() const { return m_dirPath; } +int AssetsLibraryDir::dirDepth() const { return m_dirDepth; } +bool AssetsLibraryDir::dirExpanded() const { return m_dirExpanded; } +bool AssetsLibraryDir::dirVisible() const { return m_dirVisible; } -void ItemLibraryAssetsDir::setDirExpanded(bool expand) +void AssetsLibraryDir::setDirExpanded(bool expand) { if (m_dirExpanded != expand) { m_dirExpanded = expand; @@ -52,7 +52,7 @@ void ItemLibraryAssetsDir::setDirExpanded(bool expand) } } -void ItemLibraryAssetsDir::setDirVisible(bool visible) +void AssetsLibraryDir::setDirVisible(bool visible) { if (m_dirVisible != visible) { m_dirVisible = visible; @@ -60,17 +60,17 @@ void ItemLibraryAssetsDir::setDirVisible(bool visible) } } -QObject *ItemLibraryAssetsDir::filesModel() const +QObject *AssetsLibraryDir::filesModel() const { return m_filesModel; } -QObject *ItemLibraryAssetsDir::dirsModel() const +QObject *AssetsLibraryDir::dirsModel() const { return m_dirsModel; } -QList ItemLibraryAssetsDir::childAssetsDirs() const +QList AssetsLibraryDir::childAssetsDirs() const { if (m_dirsModel) return m_dirsModel->assetsDirs(); @@ -78,18 +78,18 @@ QList ItemLibraryAssetsDir::childAssetsDirs() const return {}; } -void ItemLibraryAssetsDir::addDir(ItemLibraryAssetsDir *assetsDir) +void AssetsLibraryDir::addDir(AssetsLibraryDir *assetsDir) { if (!m_dirsModel) - m_dirsModel = new ItemLibraryAssetsDirsModel(this); + m_dirsModel = new AssetsLibraryDirsModel(this); m_dirsModel->addDir(assetsDir); } -void ItemLibraryAssetsDir::addFile(const QString &filePath) +void AssetsLibraryDir::addFile(const QString &filePath) { if (!m_filesModel) - m_filesModel = new ItemLibraryAssetsFilesModel(this); + m_filesModel = new AssetsLibraryFilesModel(this); m_filesModel->addFile(filePath); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h similarity index 85% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h index 66cc5509d7e..07e13389389 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdir.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydir.h @@ -29,10 +29,10 @@ namespace QmlDesigner { -class ItemLibraryAssetsDirsModel; -class ItemLibraryAssetsFilesModel; +class AssetsLibraryDirsModel; +class AssetsLibraryFilesModel; -class ItemLibraryAssetsDir : public QObject +class AssetsLibraryDir : public QObject { Q_OBJECT @@ -45,7 +45,7 @@ class ItemLibraryAssetsDir : public QObject Q_PROPERTY(QObject *dirsModel READ dirsModel NOTIFY dirsModelChanged) public: - ItemLibraryAssetsDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr); + AssetsLibraryDir(const QString &path, int depth, bool expanded = true, QObject *parent = nullptr); QString dirName() const; QString dirPath() const; @@ -59,9 +59,9 @@ public: QObject *filesModel() const; QObject *dirsModel() const; - QList childAssetsDirs() const; + QList childAssetsDirs() const; - void addDir(ItemLibraryAssetsDir *assetsDir); + void addDir(AssetsLibraryDir *assetsDir); void addFile(const QString &filePath); signals: @@ -78,8 +78,8 @@ private: int m_dirDepth = 0; bool m_dirExpanded = true; bool m_dirVisible = true; - ItemLibraryAssetsDirsModel *m_dirsModel = nullptr; - ItemLibraryAssetsFilesModel *m_filesModel = nullptr; + AssetsLibraryDirsModel *m_dirsModel = nullptr; + AssetsLibraryFilesModel *m_filesModel = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp similarity index 75% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp index 6af4049d872..563e0f111b1 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.cpp @@ -23,24 +23,24 @@ ** ****************************************************************************/ -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsmodel.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibrarymodel.h" #include #include namespace QmlDesigner { -ItemLibraryAssetsDirsModel::ItemLibraryAssetsDirsModel(QObject *parent) +AssetsLibraryDirsModel::AssetsLibraryDirsModel(QObject *parent) : QAbstractListModel(parent) { // add roles - const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject; + const QMetaObject meta = AssetsLibraryDir::staticMetaObject; for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i) m_roleNames.insert(i, meta.property(i).name()); } -QVariant ItemLibraryAssetsDirsModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryDirsModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -54,7 +54,7 @@ QVariant ItemLibraryAssetsDirsModel::data(const QModelIndex &index, int role) co return {}; } -bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVariant &value, int role) +bool AssetsLibraryDirsModel::setData(const QModelIndex &index, const QVariant &value, int role) { // currently only dirExpanded property is updatable if (index.isValid() && m_roleNames.contains(role)) { @@ -62,7 +62,7 @@ bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVarian if (currValue != value) { m_dirs.at(index.row())->setProperty(m_roleNames.value(role), value); if (m_roleNames.value(role) == "dirExpanded") - ItemLibraryAssetsModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath()); + AssetsLibraryModel::saveExpandedState(value.toBool(), m_dirs.at(index.row())->dirPath()); emit dataChanged(index, index, {role}); return true; } @@ -70,24 +70,24 @@ bool ItemLibraryAssetsDirsModel::setData(const QModelIndex &index, const QVarian return false; } -int ItemLibraryAssetsDirsModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryDirsModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_dirs.size(); } -QHash ItemLibraryAssetsDirsModel::roleNames() const +QHash AssetsLibraryDirsModel::roleNames() const { return m_roleNames; } -void ItemLibraryAssetsDirsModel::addDir(ItemLibraryAssetsDir *assetsDir) +void AssetsLibraryDirsModel::addDir(AssetsLibraryDir *assetsDir) { m_dirs.append(assetsDir); } -const QList ItemLibraryAssetsDirsModel::assetsDirs() const +const QList AssetsLibraryDirsModel::assetsDirs() const { return m_dirs; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h similarity index 84% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h index b139d2dd837..44e3f91ad8c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsdirsmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarydirsmodel.h @@ -26,28 +26,28 @@ #pragma once #include -#include "itemlibraryassetsdir.h" +#include "assetslibrarydir.h" namespace QmlDesigner { -class ItemLibraryAssetsDirsModel : public QAbstractListModel +class AssetsLibraryDirsModel : public QAbstractListModel { Q_OBJECT public: - ItemLibraryAssetsDirsModel(QObject *parent = nullptr); + AssetsLibraryDirsModel(QObject *parent = nullptr); QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role) override; int rowCount(const QModelIndex & parent = QModelIndex()) const override; QHash roleNames() const override; - void addDir(ItemLibraryAssetsDir *assetsDir); + void addDir(AssetsLibraryDir *assetsDir); - const QList assetsDirs() const; + const QList assetsDirs() const; private: - QList m_dirs; + QList m_dirs; QHash m_roleNames; }; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp similarity index 83% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp index 271f330fd23..ab9b6d9fcba 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.cpp @@ -22,13 +22,13 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibraryfilesmodel.h" #include namespace QmlDesigner { -ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent) +AssetsLibraryFilesModel::AssetsLibraryFilesModel(QObject *parent) : QAbstractListModel(parent) { // add roles @@ -37,7 +37,7 @@ ItemLibraryAssetsFilesModel::ItemLibraryAssetsFilesModel(QObject *parent) m_roleNames.insert(FileDirRole, "fileDir"); } -QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryFilesModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -57,19 +57,19 @@ QVariant ItemLibraryAssetsFilesModel::data(const QModelIndex &index, int role) c return {}; } -int ItemLibraryAssetsFilesModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryFilesModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_files.size(); } -QHash ItemLibraryAssetsFilesModel::roleNames() const +QHash AssetsLibraryFilesModel::roleNames() const { return m_roleNames; } -void ItemLibraryAssetsFilesModel::addFile(const QString &filePath) +void AssetsLibraryFilesModel::addFile(const QString &filePath) { m_files.append(filePath); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h similarity index 93% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h index 5b44878eefc..ca010bae60c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsfilesmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryfilesmodel.h @@ -29,12 +29,12 @@ namespace QmlDesigner { -class ItemLibraryAssetsFilesModel : public QAbstractListModel +class AssetsLibraryFilesModel : public QAbstractListModel { Q_OBJECT public: - ItemLibraryAssetsFilesModel(QObject *parent = nullptr); + AssetsLibraryFilesModel(QObject *parent = nullptr); QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex & parent = QModelIndex()) const override; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp similarity index 54% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index ad6f3136837..9d11d264008 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -23,8 +23,8 @@ ** ****************************************************************************/ -#include "itemlibraryassetsiconprovider.h" -#include "itemlibraryassetsmodel.h" +#include "assetslibraryiconprovider.h" +#include "assetslibrarymodel.h" #include #include @@ -32,40 +32,47 @@ namespace QmlDesigner { -ItemLibraryAssetsIconProvider::ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache) +AssetsLibraryIconProvider::AssetsLibraryIconProvider(SynchronousImageCache &fontImageCache) : QQuickImageProvider(QQuickImageProvider::Pixmap) , m_fontImageCache(fontImageCache) { } -QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) { QPixmap pixmap; const QString suffix = "*." + id.split('.').last().toLower(); - if (id == "browse") - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/browse.png"); - else if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix)) - pixmap = generateFontIcons(id); - else if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) + if (id == "browse") { + pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png"); + } else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { + pixmap = generateFontIcons(id, requestedSize); + } else if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { pixmap = Utils::StyleHelper::dpiSpecificImageFile(id); - else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) + } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { pixmap = HdrImage{id}.toPixmap(); - else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_shader_48.png"); - else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/asset_sound_48.png"); - else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix)) - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-video-icon.png"); + } else { + QString type; + if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) + type = "shader"; + else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) + type = "sound"; + else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) + type = "video"; + + QString pathTemplate = QString(":/AssetsLibrary/images/asset_%1%2.png").arg(type); + QString path = pathTemplate.arg('_' + QString::number(requestedSize.width())); + + pixmap = Utils::StyleHelper::dpiSpecificImageFile(QFileInfo::exists(path) ? path + : pathTemplate.arg("")); + } if (size) { size->setWidth(pixmap.width()); size->setHeight(pixmap.height()); } - if (pixmap.isNull()) { - pixmap = QPixmap(Utils::StyleHelper::dpiSpecificImageFile( - QStringLiteral(":/ItemLibrary/images/item-default-icon.png"))); - } + if (pixmap.isNull()) + pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); if (requestedSize.isValid()) return pixmap.scaled(requestedSize); @@ -73,12 +80,13 @@ QPixmap ItemLibraryAssetsIconProvider::requestPixmap(const QString &id, QSize *s return pixmap; } -QPixmap ItemLibraryAssetsIconProvider::generateFontIcons(const QString &filePath) const +QPixmap AssetsLibraryIconProvider::generateFontIcons(const QString &filePath, const QSize &requestedSize) const { - return m_fontImageCache.icon(filePath, {}, + QSize reqSize = requestedSize.isValid() ? requestedSize : QSize{48, 48}; + return m_fontImageCache.icon(filePath, {}, ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes}, Theme::getColor(Theme::DStextColor).name(), - "Abc"}).pixmap({48, 48}); + "Abc"}).pixmap(reqSize); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h similarity index 72% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h index 3c5bc4081e3..83f4a63f96d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsiconprovider.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h @@ -31,28 +31,23 @@ namespace QmlDesigner { -class ItemLibraryAssetsIconProvider : public QQuickImageProvider +class AssetsLibraryIconProvider : public QQuickImageProvider { public: - ItemLibraryAssetsIconProvider(SynchronousImageCache &fontImageCache); + AssetsLibraryIconProvider(SynchronousImageCache &fontImageCache); QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; private: - QPixmap generateFontIcons(const QString &filePath) const; + QPixmap generateFontIcons(const QString &filePath, const QSize &requestedSize) const; SynchronousImageCache &m_fontImageCache; // Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their // x2 versions for HDPI sceens - std::vector iconSizes = {{384, 384}, - {192, 192}, // Large - {256, 256}, - {128, 128}, // Drag - {96, 96}, // Medium - {48, 48}, // Small - {64, 64}, - {32, 32}}; // List + std::vector iconSizes = {{128, 128}, // Drag + {96, 96}, // list @2x + {48, 48}}; // list }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp similarity index 79% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index c7c8db45342..0470c81ee3a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -23,9 +23,9 @@ ** ****************************************************************************/ -#include "itemlibraryassetsmodel.h" -#include "itemlibraryassetsdirsmodel.h" -#include "itemlibraryassetsfilesmodel.h" +#include "assetslibrarymodel.h" +#include "assetslibrarydirsmodel.h" +#include "assetslibraryfilesmodel.h" #include #include @@ -50,17 +50,17 @@ namespace QmlDesigner { -void ItemLibraryAssetsModel::saveExpandedState(bool expanded, const QString &assetPath) +void AssetsLibraryModel::saveExpandedState(bool expanded, const QString &assetPath) { m_expandedStateHash.insert(assetPath, expanded); } -bool ItemLibraryAssetsModel::loadExpandedState(const QString &assetPath) +bool AssetsLibraryModel::loadExpandedState(const QString &assetPath) { return m_expandedStateHash.value(assetPath, true); } -ItemLibraryAssetsModel::DirExpandState ItemLibraryAssetsModel::getAllExpandedState() const +AssetsLibraryModel::DirExpandState AssetsLibraryModel::getAllExpandedState() const { const auto keys = m_expandedStateHash.keys(); bool allExpanded = true; @@ -81,16 +81,16 @@ ItemLibraryAssetsModel::DirExpandState ItemLibraryAssetsModel::getAllExpandedSta : DirExpandState::SomeExpanded; } -void ItemLibraryAssetsModel::toggleExpandAll(bool expand) +void AssetsLibraryModel::toggleExpandAll(bool expand) { - std::function expandDirRecursive; - expandDirRecursive = [&](ItemLibraryAssetsDir *currAssetsDir) { + std::function expandDirRecursive; + expandDirRecursive = [&](AssetsLibraryDir *currAssetsDir) { if (currAssetsDir->dirDepth() > 0) { currAssetsDir->setDirExpanded(expand); saveExpandedState(expand, currAssetsDir->dirPath()); } - const QList childDirs = currAssetsDir->childAssetsDirs(); + const QList childDirs = currAssetsDir->childAssetsDirs(); for (const auto childDir : childDirs) expandDirRecursive(childDir); }; @@ -100,7 +100,7 @@ void ItemLibraryAssetsModel::toggleExpandAll(bool expand) endResetModel(); } -void ItemLibraryAssetsModel::deleteFile(const QString &filePath) +void AssetsLibraryModel::deleteFile(const QString &filePath) { bool askBeforeDelete = DesignerSettings::getValue( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool(); @@ -135,7 +135,7 @@ void ItemLibraryAssetsModel::deleteFile(const QString &filePath) } } -bool ItemLibraryAssetsModel::renameFolder(const QString &folderPath, const QString &newName) +bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &newName) { QDir dir{folderPath}; QString oldName = dir.dirName(); @@ -147,7 +147,7 @@ bool ItemLibraryAssetsModel::renameFolder(const QString &folderPath, const QStri return dir.rename(oldName, newName); } -void ItemLibraryAssetsModel::addNewFolder(const QString &folderPath) +void AssetsLibraryModel::addNewFolder(const QString &folderPath) { QString iterPath = folderPath; QRegularExpression rgx("\\d+$"); // matches a number at the end of a string @@ -183,17 +183,17 @@ void ItemLibraryAssetsModel::addNewFolder(const QString &folderPath) dir.mkpath(iterPath); } -void ItemLibraryAssetsModel::deleteFolder(const QString &folderPath) +void AssetsLibraryModel::deleteFolder(const QString &folderPath) { QDir{folderPath}.removeRecursively(); } -QObject *ItemLibraryAssetsModel::rootDir() const +QObject *AssetsLibraryModel::rootDir() const { return m_assetsDir; } -const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes() +const QStringList &AssetsLibraryModel::supportedImageSuffixes() { static QStringList retList; if (retList.isEmpty()) { @@ -204,13 +204,13 @@ const QStringList &ItemLibraryAssetsModel::supportedImageSuffixes() return retList; } -const QStringList &ItemLibraryAssetsModel::supportedFragmentShaderSuffixes() +const QStringList &AssetsLibraryModel::supportedFragmentShaderSuffixes() { static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedShaderSuffixes() +const QStringList &AssetsLibraryModel::supportedShaderSuffixes() { static const QStringList retList {"*.frag", "*.vert", "*.glsl", "*.glslv", "*.glslf", @@ -218,32 +218,32 @@ const QStringList &ItemLibraryAssetsModel::supportedShaderSuffixes() return retList; } -const QStringList &ItemLibraryAssetsModel::supportedFontSuffixes() +const QStringList &AssetsLibraryModel::supportedFontSuffixes() { static const QStringList retList {"*.ttf", "*.otf"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedAudioSuffixes() +const QStringList &AssetsLibraryModel::supportedAudioSuffixes() { static const QStringList retList {"*.wav", "*.mp3"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedVideoSuffixes() +const QStringList &AssetsLibraryModel::supportedVideoSuffixes() { static const QStringList retList {"*.mp4"}; return retList; } -const QStringList &ItemLibraryAssetsModel::supportedTexture3DSuffixes() +const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes() { // These are file types only supported by 3D textures static QStringList retList {"*.hdr", "*.ktx"}; return retList; } -ItemLibraryAssetsModel::ItemLibraryAssetsModel(SynchronousImageCache &fontImageCache, +AssetsLibraryModel::AssetsLibraryModel(SynchronousImageCache &fontImageCache, Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent) : QAbstractListModel(parent) @@ -252,12 +252,12 @@ ItemLibraryAssetsModel::ItemLibraryAssetsModel(SynchronousImageCache &fontImageC { // add role names int role = 0; - const QMetaObject meta = ItemLibraryAssetsDir::staticMetaObject; + const QMetaObject meta = AssetsLibraryDir::staticMetaObject; for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i) m_roleNames.insert(role++, meta.property(i).name()); } -QVariant ItemLibraryAssetsModel::data(const QModelIndex &index, int role) const +QVariant AssetsLibraryModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { qWarning() << Q_FUNC_INFO << "Invalid index requested: " << QString::number(index.row()); @@ -271,32 +271,32 @@ QVariant ItemLibraryAssetsModel::data(const QModelIndex &index, int role) const return {}; } -int ItemLibraryAssetsModel::rowCount(const QModelIndex &parent) const +int AssetsLibraryModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } -QHash ItemLibraryAssetsModel::roleNames() const +QHash AssetsLibraryModel::roleNames() const { return m_roleNames; } // called when a directory is changed to refresh the model for this directory -void ItemLibraryAssetsModel::refresh() +void AssetsLibraryModel::refresh() { setRootPath(m_assetsDir->dirPath()); } -void ItemLibraryAssetsModel::setRootPath(const QString &path) +void AssetsLibraryModel::setRootPath(const QString &path) { static const QStringList ignoredTopLevelDirs {"imports", "asset_imports"}; m_fileSystemWatcher->clear(); - std::function parseDirRecursive; - parseDirRecursive = [this, &parseDirRecursive](ItemLibraryAssetsDir *currAssetsDir, int currDepth) { + std::function parseDirRecursive; + parseDirRecursive = [this, &parseDirRecursive](AssetsLibraryDir *currAssetsDir, int currDepth) { m_fileSystemWatcher->addDirectory(currAssetsDir->dirPath(), Utils::FileSystemWatcher::WatchAllChanges); QDir dir(currAssetsDir->dirPath()); @@ -323,7 +323,8 @@ void ItemLibraryAssetsModel::setRootPath(const QString &path) if (currDepth == 1 && ignoredTopLevelDirs.contains(subDir.dirName())) continue; - ItemLibraryAssetsDir *assetsDir = new ItemLibraryAssetsDir(subDir.path(), currDepth, loadExpandedState(subDir.path()), currAssetsDir); + auto assetsDir = new AssetsLibraryDir(subDir.path(), currDepth, + loadExpandedState(subDir.path()), currAssetsDir); currAssetsDir->addDir(assetsDir); saveExpandedState(loadExpandedState(assetsDir->dirPath()), assetsDir->dirPath()); isEmpty &= parseDirRecursive(assetsDir, currDepth + 1); @@ -339,13 +340,13 @@ void ItemLibraryAssetsModel::setRootPath(const QString &path) delete m_assetsDir; beginResetModel(); - m_assetsDir = new ItemLibraryAssetsDir(path, 0, true, this); + m_assetsDir = new AssetsLibraryDir(path, 0, true, this); bool noAssets = parseDirRecursive(m_assetsDir, 1); setIsEmpty(noAssets); endResetModel(); } -void ItemLibraryAssetsModel::setSearchText(const QString &searchText) +void AssetsLibraryModel::setSearchText(const QString &searchText) { if (m_searchText != searchText) { m_searchText = searchText; @@ -353,7 +354,7 @@ void ItemLibraryAssetsModel::setSearchText(const QString &searchText) } } -const QSet &ItemLibraryAssetsModel::supportedSuffixes() const +const QSet &AssetsLibraryModel::supportedSuffixes() const { static QSet allSuffixes; if (allSuffixes.isEmpty()) { @@ -371,12 +372,12 @@ const QSet &ItemLibraryAssetsModel::supportedSuffixes() const return allSuffixes; } -bool ItemLibraryAssetsModel::isEmpty() const +bool AssetsLibraryModel::isEmpty() const { return m_isEmpty; }; -void ItemLibraryAssetsModel::setIsEmpty(bool empty) +void AssetsLibraryModel::setIsEmpty(bool empty) { if (m_isEmpty != empty) { m_isEmpty = empty; @@ -384,7 +385,7 @@ void ItemLibraryAssetsModel::setIsEmpty(bool empty) } }; -const QSet &ItemLibraryAssetsModel::previewableSuffixes() const +const QSet &AssetsLibraryModel::previewableSuffixes() const { static QSet previewableSuffixes; if (previewableSuffixes.isEmpty()) { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h similarity index 93% rename from src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h rename to src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 989f9f7226f..7651ae1a224 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetsmodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -32,24 +32,22 @@ #include #include #include -#include - -#include "itemlibraryassetsdir.h" namespace Utils { class FileSystemWatcher; } namespace QmlDesigner { class SynchronousImageCache; +class AssetsLibraryDir; -class ItemLibraryAssetsModel : public QAbstractListModel +class AssetsLibraryModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(bool isEmpty READ isEmpty WRITE setIsEmpty NOTIFY isEmptyChanged) public: - ItemLibraryAssetsModel(QmlDesigner::SynchronousImageCache &fontImageCache, + AssetsLibraryModel(QmlDesigner::SynchronousImageCache &fontImageCache, Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent = nullptr); @@ -103,7 +101,7 @@ private: QString m_searchText; Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; - ItemLibraryAssetsDir *m_assetsDir = nullptr; + AssetsLibraryDir *m_assetsDir = nullptr; bool m_isEmpty = true; QHash m_roleNames; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp new file mode 100644 index 00000000000..2fc4aacac3c --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "assetslibraryview.h" +#include "assetslibrarywidget.h" +#include "metainfo.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +namespace { +ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project) +{ + if (project) + return project->activeTarget(); + + return {}; +} +} // namespace + +class ImageCacheData +{ +public: + Sqlite::Database database{Utils::PathString{ + Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, + Sqlite::JournalMode::Wal, + Sqlite::LockingMode::Normal}; + ImageCacheStorage storage{database}; + ImageCacheConnectionManager connectionManager; + ImageCacheCollector collector{connectionManager}; + ImageCacheFontCollector fontCollector; + ImageCacheGenerator generator{collector, storage}; + ImageCacheGenerator fontGenerator{fontCollector, storage}; + TimeStampProvider timeStampProvider; + AsynchronousImageCache cache{storage, generator, timeStampProvider}; + AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider}; + SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector}; +}; + +AssetsLibraryView::AssetsLibraryView(QObject *parent) + : AbstractView(parent) +{} + +AssetsLibraryView::~AssetsLibraryView() +{} + +bool AssetsLibraryView::hasWidget() const +{ + return true; +} + +WidgetInfo AssetsLibraryView::widgetInfo() +{ + if (m_widget.isNull()) { + m_widget = new AssetsLibraryWidget{imageCacheData()->cache, + imageCacheData()->asynchronousFontImageCache, + imageCacheData()->synchronousFontImageCache}; + } + + return createWidgetInfo(m_widget.data(), "Assets", WidgetInfo::LeftPane, 0, tr("Assets")); +} + +void AssetsLibraryView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + + m_widget->clearSearchFilter(); + m_widget->setModel(model); + + setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()); +} + +void AssetsLibraryView::modelAboutToBeDetached(Model *model) +{ + AbstractView::modelAboutToBeDetached(model); + + m_widget->setModel(nullptr); +} + +void AssetsLibraryView::setResourcePath(const QString &resourcePath) +{ + if (m_widget.isNull()) { + m_widget = new AssetsLibraryWidget{m_imageCacheData->cache, + m_imageCacheData->asynchronousFontImageCache, + m_imageCacheData->synchronousFontImageCache}; + } + + m_widget->setResourcePath(resourcePath); +} + +ImageCacheData *AssetsLibraryView::imageCacheData() +{ + std::call_once(imageCacheFlag, [this]() { + m_imageCacheData = std::make_unique(); + auto setTargetInImageCache = + [imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) { + if (target == imageCacheData->collector.target()) + return; + + if (target) + imageCacheData->cache.clean(); + + imageCacheData->collector.setTarget(target); + }; + + if (auto project = ProjectExplorer::SessionManager::startupProject(); project) { + m_imageCacheData->collector.setTarget(project->activeTarget()); + connect(project, + &ProjectExplorer::Project::activeTargetChanged, + this, + setTargetInImageCache); + } + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, + [=](ProjectExplorer::Project *project) { + setTargetInImageCache(activeTarget(project)); + }); + }); + return m_imageCacheData.get(); +} + +AsynchronousImageCache &AssetsLibraryView::imageCache() +{ + return imageCacheData()->cache; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h new file mode 100644 index 00000000000..79fbde852f9 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 + +namespace QmlDesigner { + +class AssetsLibraryWidget; +class ImageCacheData; +class AsynchronousImageCache; + +class AssetsLibraryView : public AbstractView +{ + Q_OBJECT + +public: + AssetsLibraryView(QObject* parent = nullptr); + ~AssetsLibraryView() override; + + bool hasWidget() const override; + WidgetInfo widgetInfo() override; + + // AbstractView + void modelAttached(Model *model) override; + void modelAboutToBeDetached(Model *model) override; + + void setResourcePath(const QString &resourcePath); + + AsynchronousImageCache &imageCache(); + +private: + ImageCacheData *imageCacheData(); + + std::once_flag imageCacheFlag; + std::unique_ptr m_imageCacheData; + QPointer m_widget; +}; + +} diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp new file mode 100644 index 00000000000..f51e070bf6a --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "assetslibrarywidget.h" + +#include "assetslibrarymodel.h" +#include "assetslibraryiconprovider.h" + +#include + +#include +#include "modelnodeoperations.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner { + +static QString propertyEditorResourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString(); +} + +bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::FocusOut) { + if (obj == m_assetsWidget.data()) + QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut"); + } else if (event->type() == QMouseEvent::MouseMove) { + if (!m_assetsToDrag.isEmpty()) { + QMouseEvent *me = static_cast(event); + if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { + auto drag = new QDrag(this); + drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); + QMimeData *mimeData = new QMimeData; + mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetsToDrag.join(',').toUtf8()); + drag->setMimeData(mimeData); + drag->exec(); + drag->deleteLater(); + + m_assetsToDrag.clear(); + } + } + } else if (event->type() == QMouseEvent::MouseButtonRelease) { + m_assetsToDrag.clear(); + QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); + if (view) { + NavigatorWidget *navView = qobject_cast(view); + if (navView) { + navView->setDragType(""); + navView->update(); + } + } + } + + return QObject::eventFilter(obj, event); +} + +AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache, + AsynchronousImageCache &asynchronousFontImageCache, + SynchronousImageCache &synchronousFontImageCache) + : m_itemIconSize(24, 24) + , m_fontImageCache(synchronousFontImageCache) + , m_assetsIconProvider(new AssetsLibraryIconProvider(synchronousFontImageCache)) + , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) + , m_assetsModel(new AssetsLibraryModel(synchronousFontImageCache, m_fileSystemWatcher, this)) + , m_assetsWidget(new QQuickWidget(this)) + , m_imageCache{imageCache} +{ + m_assetCompressionTimer.setInterval(200); + m_assetCompressionTimer.setSingleShot(true); + + setWindowTitle(tr("Assets Library", "Title of assets library widget")); + setMinimumWidth(250); + + m_assetsWidget->installEventFilter(this); + + m_fontPreviewTooltipBackend = std::make_unique(asynchronousFontImageCache); + // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's + // a commonly used sentence to preview the font glyphs in latin fonts. + // For fonts that do not have latin glyphs, the font family name will have to suffice for preview. + m_fontPreviewTooltipBackend->setAuxiliaryData( + ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300}, + Theme::getColor(Theme::DStextColor).name(), + QStringLiteral("The quick brown fox jumps\n" + "over the lazy dog\n" + "1234567890")}); + // create assets widget + m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + Theme::setupTheme(m_assetsWidget->engine()); + m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); + m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider); + m_assetsWidget->rootContext()->setContextProperties(QVector{ + {{"assetsModel"}, QVariant::fromValue(m_assetsModel.data())}, + {{"rootView"}, QVariant::fromValue(this)}, + {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())} + }); + + // If project directory contents change, or one of the asset files is modified, we must + // reconstruct the model to update the icons + connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) { + Q_UNUSED(changedDirPath) + m_assetCompressionTimer.start(); + }); + + auto layout = new QVBoxLayout(this); + layout->setContentsMargins({}); + layout->setSpacing(0); + layout->addWidget(m_assetsWidget.data()); + + updateSearch(); + + setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F6), this); + connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &AssetsLibraryWidget::reloadQmlSource); + + connect(&m_assetCompressionTimer, &QTimer::timeout, this, [this]() { + // TODO: find a clever way to only refresh the changed directory part of the model + + // Don't bother with asset updates after model has detached, project is probably closing + if (!m_model.isNull()) { + if (QApplication::activeModalWidget()) { + // Retry later, as updating file system watchers can crash when there is an active + // modal widget + m_assetCompressionTimer.start(); + } else { + m_assetsModel->refresh(); + // reload assets qml so that an overridden file's image shows the new image + QTimer::singleShot(100, this, &AssetsLibraryWidget::reloadQmlSource); + } + } + }); + + // init the first load of the QML UI elements + reloadQmlSource(); +} + +AssetsLibraryWidget::~AssetsLibraryWidget() = default; + +QList AssetsLibraryWidget::createToolBarWidgets() +{ + return {}; +} + +void AssetsLibraryWidget::handleSearchfilterChanged(const QString &filterText) +{ + if (filterText != m_filterText) { + m_filterText = filterText; + updateSearch(); + } +} + +void AssetsLibraryWidget::handleAddAsset() +{ + addResources({}); +} + +void AssetsLibraryWidget::handleFilesDrop(const QStringList &filesPaths) +{ + addResources(filesPaths); +} + +QSet AssetsLibraryWidget::supportedDropSuffixes() +{ + const QList handlers = QmlDesignerPlugin::instance()->viewManager() + .designerActionManager().addResourceHandler(); + + QSet suffixes; + for (const AddResourceHandler &handler : handlers) + suffixes.insert(handler.filter); + + return suffixes; +} + +void AssetsLibraryWidget::setModel(Model *model) +{ + m_model = model; +} + +QString AssetsLibraryWidget::qmlSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/itemLibraryQmlSources"; +#endif + return Core::ICore::resourcePath("qmldesigner/itemLibraryQmlSources").toString(); +} + +void AssetsLibraryWidget::clearSearchFilter() +{ + QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "clearSearchFilter"); +} + +void AssetsLibraryWidget::reloadQmlSource() +{ + const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; + QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return); + m_assetsWidget->engine()->clearComponentCache(); + m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); +} + +void AssetsLibraryWidget::updateSearch() +{ + m_assetsModel->setSearchText(m_filterText); +} + +void AssetsLibraryWidget::setResourcePath(const QString &resourcePath) +{ + m_assetsModel->setRootPath(resourcePath); + updateSearch(); +} + +void AssetsLibraryWidget::startDragAsset(const QStringList &assetPaths, const QPointF &mousePos) +{ + // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay + // active (and blocks mouse release) if mouse is released at the same spot of the drag start. + m_assetsToDrag = assetPaths; + m_dragStartPoint = mousePos.toPoint(); +} + +QPair AssetsLibraryWidget::getAssetTypeAndData(const QString &assetPath) +{ + QString suffix = "*." + assetPath.split('.').last().toLower(); + if (!suffix.isEmpty()) { + if (AssetsLibraryModel::supportedImageSuffixes().contains(suffix)) { + // Data: Image format (suffix) + return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; + } else if (AssetsLibraryModel::supportedFontSuffixes().contains(suffix)) { + // Data: Font family name + QRawFont font(assetPath, 10); + QString fontFamily = font.isValid() ? font.familyName() : ""; + return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()}; + } else if (AssetsLibraryModel::supportedShaderSuffixes().contains(suffix)) { + // Data: shader type, frament (f) or vertex (v) + return {"application/vnd.bauhaus.libraryresource.shader", + AssetsLibraryModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; + } else if (AssetsLibraryModel::supportedAudioSuffixes().contains(suffix)) { + // No extra data for sounds + return {"application/vnd.bauhaus.libraryresource.sound", {}}; + } else if (AssetsLibraryModel::supportedVideoSuffixes().contains(suffix)) { + // No extra data for videos + return {"application/vnd.bauhaus.libraryresource.video", {}}; + } else if (AssetsLibraryModel::supportedTexture3DSuffixes().contains(suffix)) { + // Data: Image format (suffix) + return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; + } + } + return {}; +} + +static QHash allImageFormats() +{ + const QList mimeTypes = QImageReader::supportedMimeTypes(); + auto transformer = [](const QByteArray& format) -> QString { return QString("*.") + format; }; + QHash imageFormats; + for (const auto &mimeType : mimeTypes) + imageFormats.insert(mimeType, Utils::transform(QImageReader::imageFormatsForMimeType(mimeType), transformer)); + imageFormats.insert("image/vnd.radiance", {"*.hdr"}); + imageFormats.insert("image/ktx", {"*.ktx"}); + + return imageFormats; +} + +void AssetsLibraryWidget::addResources(const QStringList &files) +{ + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + + QTC_ASSERT(document, return); + + const QList handlers = QmlDesignerPlugin::instance()->viewManager() + .designerActionManager().addResourceHandler(); + + QStringList fileNames = files; + if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog + QMultiMap map; + QHash priorities; + for (const AddResourceHandler &handler : handlers) { + map.insert(handler.category, handler.filter); + priorities.insert(handler.category, handler.piority); + } + + QStringList sortedKeys = map.uniqueKeys(); + Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) { + return priorities.value(first) < priorities.value(second); + }); + + QStringList filters { tr("All Files (%1)").arg("*.*") }; + QString filterTemplate = "%1 (%2)"; + for (const QString &key : qAsConst(sortedKeys)) { + const QStringList values = map.values(key); + if (values.contains("*.png")) { // Avoid long filter for images by splitting + const QHash imageFormats = allImageFormats(); + QHash::const_iterator i = imageFormats.constBegin(); + while (i != imageFormats.constEnd()) { + filters.append(filterTemplate.arg(key + QString::fromLatin1(i.key()), i.value().join(' '))); + ++i; + } + } else { + filters.append(filterTemplate.arg(key, values.join(' '))); + } + } + + static QString lastDir; + const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir; + + fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), + tr("Add Assets"), + currentDir, + filters.join(";;")); + + if (!fileNames.isEmpty()) + lastDir = QFileInfo(fileNames.first()).absolutePath(); + } + + QHash filterToCategory; + QHash categoryToOperation; + for (const AddResourceHandler &handler : handlers) { + filterToCategory.insert(handler.filter, handler.category); + categoryToOperation.insert(handler.category, handler.operation); + } + + QMultiMap categoryFileNames; // filenames grouped by category + + for (const QString &fileName : qAsConst(fileNames)) { + const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); + const QString category = filterToCategory.value(suffix); + categoryFileNames.insert(category, fileName); + } + + for (const QString &category : categoryFileNames.uniqueKeys()) { + QStringList fileNames = categoryFileNames.values(category); + AddResourceOperation operation = categoryToOperation.value(category); + QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); + if (operation) { + AddFilesResult result = operation(fileNames, + document->fileName().parentDir().toString()); + if (result == AddFilesResult::Failed) { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), + tr("Could not add %1 to project.") + .arg(fileNames.join(' '))); + } + } else { + Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), + tr("Could not add %1 to project. Unsupported file format.") + .arg(fileNames.join(' '))); + } + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h new file mode 100644 index 00000000000..6c27be54a61 --- /dev/null +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "assetslibrarymodel.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QShortcut; +QT_END_NAMESPACE + +namespace Utils { class FileSystemWatcher; } + +namespace QmlDesigner { + +class MetaInfo; +class Model; + +class AssetsLibraryIconProvider; +class AssetsLibraryModel; +class SynchronousImageCache; +class AsynchronousImageCache; +class ImageCacheCollector; + +class AssetsLibraryWidget : public QFrame +{ + Q_OBJECT + +public: + AssetsLibraryWidget(AsynchronousImageCache &imageCache, + AsynchronousImageCache &asynchronousFontImageCache, + SynchronousImageCache &synchronousFontImageCache); + ~AssetsLibraryWidget(); + + QList createToolBarWidgets(); + + static QString qmlSourcesPath(); + void clearSearchFilter(); + + void delayedUpdateModel(); + void updateModel(); + + void setResourcePath(const QString &resourcePath); + void setModel(Model *model); + static QPair getAssetTypeAndData(const QString &assetPath); + + Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); + Q_INVOKABLE void handleAddAsset(); + Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); + Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths); + Q_INVOKABLE QSet supportedDropSuffixes(); + +signals: + void itemActivated(const QString &itemName); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + void reloadQmlSource(); + + void addResources(const QStringList &files); + void updateSearch(); + + QTimer m_assetCompressionTimer; + QSize m_itemIconSize; + + SynchronousImageCache &m_fontImageCache; + + AssetsLibraryIconProvider *m_assetsIconProvider = nullptr; + Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; + QPointer m_assetsModel; + + QScopedPointer m_assetsWidget; + std::unique_ptr m_fontPreviewTooltipBackend; + + QShortcut *m_qmlSourceUpdateShortcut = nullptr; + AsynchronousImageCache &m_imageCache; + QPointer m_model; + QStringList m_assetsToDrag; + bool m_updateRetry = false; + QString m_filterText; + QPoint m_dragStartPoint; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png new file mode 100644 index 00000000000..ef59d892791 Binary files /dev/null and b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default.png differ diff --git a/src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png new file mode 100644 index 00000000000..6540cc859cd Binary files /dev/null and b/src/plugins/qmldesigner/components/assetslibrary/images/asset_default@2x.png differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_48.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_shader.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_48.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_shader.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_96.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_shader@2x.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_96.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_shader@2x.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_128.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_shader_128.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_128.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_shader_128.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_48.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_sound.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_48.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_sound.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_96.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_sound@2x.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_96.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_sound@2x.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_128.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_sound_128.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_128.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_sound_128.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-video-icon.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_video.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/item-video-icon.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_video.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-video-icon@2x.png b/src/plugins/qmldesigner/components/assetslibrary/images/asset_video@2x.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/item-video-icon@2x.png rename to src/plugins/qmldesigner/components/assetslibrary/images/asset_video@2x.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/browse.png b/src/plugins/qmldesigner/components/assetslibrary/images/browse.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/browse.png rename to src/plugins/qmldesigner/components/assetslibrary/images/browse.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/browse@2x.png b/src/plugins/qmldesigner/components/assetslibrary/images/browse@2x.png similarity index 100% rename from src/plugins/qmldesigner/components/itemlibrary/images/browse@2x.png rename to src/plugins/qmldesigner/components/assetslibrary/images/browse@2x.png diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index e160f030dbf..959ba6772f0 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -50,6 +50,7 @@ #include #include +#include #include #include #include @@ -1471,8 +1472,7 @@ void DesignerActionManager::createDefaultDesignerActions() &singleSelection, &singleSelection)); - const bool standaloneMode - = Core::ICore::settings()->value(DesignerSettingsKey::STANDALONE_MODE).toBool(); + const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); if (!standaloneMode) { addDesignerAction(new ModelNodeContextMenuAction(goToImplementationCommandId, diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp index 2967b89da7a..de64139cb91 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionviewwidget.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -97,7 +98,7 @@ ConnectionViewWidget::ConnectionViewWidget(QWidget *parent) : auto settings = QmlDesignerPlugin::instance()->settings(); - if (!settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (!QmlProjectManager::QmlProject::isQtDesignStudio()) ui->tabBar->addTab(tr("Backends", "Title of dynamic properties view")); ui->tabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index cb42996b129..06c2078f537 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -110,6 +110,11 @@ void DebugView::nodeCreated(const ModelNode &createdNode) QString string; message.setString(&string); message << createdNode; + message << createdNode.nodeSource(); + message << "MetaInfo " << createdNode.metaInfo().isValid(); + if (createdNode.metaInfo().isValid()) { + message << createdNode.metaInfo().componentFileName(); + } log("::nodeCreated:", message.readAll()); } } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 7ea74f6cbee..65e1b763e59 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -30,21 +30,43 @@ #include "nodehints.h" #include "qmlvisualnode.h" +#include + +#include + #include #include -#include +#include #include +#include +#include namespace QmlDesigner { +static QQuickWidget *createBusyIndicator(QWidget *p) +{ + auto widget = new QQuickWidget(p); + + const QString source = Core::ICore::resourcePath("qmldesigner/misc/BusyIndicator.qml").toString(); + QTC_ASSERT(QFileInfo::exists(source), return widget); + widget->setSource(QUrl::fromLocalFile(source)); + widget->setFixedSize(64, 64); + widget->setAttribute(Qt::WA_AlwaysStackOnTop); + widget->setClearColor(Qt::transparent); + widget->setResizeMode(QQuickWidget::SizeRootObjectToView); + return widget; +} + Edit3DCanvas::Edit3DCanvas(Edit3DWidget *parent) - : QWidget(parent), - m_parent(parent) + : QWidget(parent) + , m_parent(parent) + , m_busyIndicator(createBusyIndicator(this)) { setMouseTracking(true); setAcceptDrops(true); setFocusPolicy(Qt::ClickFocus); + m_busyIndicator->show(); } void Edit3DCanvas::updateRenderImage(const QImage &img) @@ -58,6 +80,21 @@ void Edit3DCanvas::updateActiveScene(qint32 activeScene) m_activeScene = activeScene; } +QImage QmlDesigner::Edit3DCanvas::renderImage() const +{ + return m_image; +} + +void Edit3DCanvas::setOpacity(qreal opacity) +{ + m_opacity = opacity; +} + +QWidget *Edit3DCanvas::busyIndicator() const +{ + return m_busyIndicator; +} + void Edit3DCanvas::mousePressEvent(QMouseEvent *e) { m_parent->view()->sendInputEvent(e); @@ -108,11 +145,17 @@ void Edit3DCanvas::paintEvent(QPaintEvent *e) QPainter painter(this); + if (m_opacity < 1.0) { + painter.fillRect(rect(), Qt::black); + painter.setOpacity(m_opacity); + } + painter.drawImage(rect(), m_image, QRect(0, 0, m_image.width(), m_image.height())); } void Edit3DCanvas::resizeEvent(QResizeEvent *e) { + positionBusyInidicator(); m_parent->view()->edit3DViewResized(e->size()); } @@ -161,4 +204,9 @@ void Edit3DCanvas::focusInEvent(QFocusEvent *focusEvent) QWidget::focusInEvent(focusEvent); } +void Edit3DCanvas::positionBusyInidicator() +{ + m_busyIndicator->move(width() / 2 - 32, height() / 2 - 32); +} + } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h index b6f07683d7e..faa164bfe9c 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h @@ -45,8 +45,10 @@ public: void updateRenderImage(const QImage &img); void updateActiveScene(qint32 activeScene); - qint32 activeScene() const { return m_activeScene; } + QImage renderImage() const; + void setOpacity(qreal opacity); + QWidget *busyIndicator() const; protected: void mousePressEvent(QMouseEvent *e) override; @@ -64,11 +66,15 @@ protected: void focusInEvent(QFocusEvent *focusEvent) override; private: + void positionBusyInidicator(); + QPointer m_parent; QImage m_image; qint32 m_activeScene = -1; ItemLibraryEntry m_itemLibraryEntry; QElapsedTimer m_usageTimer; + qreal m_opacity = 1.0; + QWidget *m_busyIndicator = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 3981be8280a..bb795eb40fc 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -110,6 +110,10 @@ void Edit3DView::renderImage3DChanged(const QImage &img) // Notify puppet to resize if received image wasn't correct size if (img.size() != canvasSize()) edit3DViewResized(canvasSize()); + if (edit3DWidget()->canvas()->busyIndicator()->isVisible()) { + edit3DWidget()->canvas()->setOpacity(1.0); + edit3DWidget()->canvas()->busyIndicator()->hide(); + } } void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) @@ -195,13 +199,19 @@ void Edit3DView::modelAttached(Model *model) AbstractView::modelAttached(model); checkImports(); + auto cachedImage = m_canvasCache.take(model); + if (cachedImage) { + edit3DWidget()->canvas()->updateRenderImage(*cachedImage); + edit3DWidget()->canvas()->setOpacity(0.5); + } + + edit3DWidget()->canvas()->busyIndicator()->show(); } void Edit3DView::modelAboutToBeDetached(Model *model) { - Q_UNUSED(model) - // Hide the canvas when model is detached (i.e. changing documents) + m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage()); edit3DWidget()->showCanvas(false); AbstractView::modelAboutToBeDetached(model); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 721a69bfa2e..daddb84d6c8 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -27,6 +27,8 @@ #include "view3dactioncommand.h" #include "seekerslider.h" +#include + #include #include #include @@ -107,6 +109,7 @@ private: Edit3DAction *m_visibilityTogglesAction = nullptr; SeekerSlider *m_seeker = nullptr; int particlemode; + ModelCache m_canvasCache; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp index 4d658deb8d5..f9d05307aad 100644 --- a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp @@ -27,7 +27,7 @@ #include "formeditorview.h" #include "formeditorwidget.h" #include "formeditorscene.h" -#include "itemlibrarywidget.h" +#include "assetslibrarywidget.h" #include @@ -240,7 +240,7 @@ void AbstractFormEditorTool::dragEnterEvent(const QList &itemLis const QStringList assetPaths = QString::fromUtf8(event->mimeData() ->data("application/vnd.bauhaus.libraryresource")).split(","); for (const QString &assetPath : assetPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.image" || assetType == "application/vnd.bauhaus.libraryresource.font") { hasValidAssets = true; diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp index f2eb5844066..b3650aaae0d 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp @@ -27,7 +27,7 @@ #include "formeditorscene.h" #include "formeditorview.h" -#include "itemlibrarywidget.h" +#include "assetslibrarywidget.h" #include #include #include @@ -142,7 +142,7 @@ void DragTool::createQmlItemNodeFromFont(const QString &fontPath, QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform() .inverted().map(scenePos); - const auto typeAndData = ItemLibraryWidget::getAssetTypeAndData(fontPath); + const auto typeAndData = AssetsLibraryWidget::getAssetTypeAndData(fontPath); QString fontFamily = QString::fromUtf8(typeAndData.second); m_dragNodes.append(QmlItemNode::createQmlItemNodeFromFont(view(), fontFamily, @@ -328,7 +328,7 @@ void DragTool::createDragNodes(const QMimeData *mimeData, const QPointF &scenePo const QStringList assetPaths = QString::fromUtf8(mimeData ->data("application/vnd.bauhaus.libraryresource")).split(","); for (const QString &assetPath : assetPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.image") createQmlItemNodeFromImage(assetPath, targetContainerQmlItemNode, scenePosition); else if (assetType == "application/vnd.bauhaus.libraryresource.font") diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h index 7e1b4cb4812..63d3de6e8f7 100644 --- a/src/plugins/qmldesigner/components/formeditor/dragtool.h +++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h @@ -99,7 +99,7 @@ private: QList m_dragNodes; bool m_blockMove; QPointF m_startPoint; - bool m_isAborted; + bool m_isAborted = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png deleted file mode 100644 index 44dd517b354..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_128.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png deleted file mode 100644 index f6f394fdb08..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_192.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png deleted file mode 100644 index 2a830a216a5..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_256.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_32.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_32.png deleted file mode 100644 index d939fe85337..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_32.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_384.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_384.png deleted file mode 100644 index 4cd1e731339..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_384.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png deleted file mode 100644 index e8691a29761..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_48.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_64.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_64.png deleted file mode 100644 index e70c8d55d91..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_64.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_96.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_96.png deleted file mode 100644 index 5e4c62b7985..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_font_96.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png deleted file mode 100644 index 5f8ee5151d8..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_192.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_256.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_256.png deleted file mode 100644 index c7e20e0c978..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_256.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_32.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_32.png deleted file mode 100644 index 1c256cca426..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_32.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_384.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_384.png deleted file mode 100644 index 8604a7f7b72..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_384.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png deleted file mode 100644 index 16023491cf5..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_shader_64.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png deleted file mode 100644 index 8dd93eb33d5..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_192.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png deleted file mode 100644 index e73588220ff..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_256.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_32.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_32.png deleted file mode 100644 index c681c6d4dcf..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_32.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png deleted file mode 100644 index 571de696e31..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_384.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_64.png b/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_64.png deleted file mode 100644 index 21d15eee877..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/asset_sound_64.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/x.png b/src/plugins/qmldesigner/components/itemlibrary/images/x.png deleted file mode 100644 index 323d2a2911a..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png deleted file mode 100644 index 18fa9a35f78..00000000000 Binary files a/src/plugins/qmldesigner/components/itemlibrary/images/x@2x.png and /dev/null differ diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc index c6d60413d07..eb927c2aa95 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrary.qrc @@ -1,39 +1,9 @@ - images/item-default-icon.png images/item-invalid-icon.png + images/item-default-icon.png images/item-default-icon@2x.png images/item-3D_model-icon.png images/item-3D_model-icon@2x.png - images/asset_font_32.png - images/asset_font_48.png - images/asset_font_64.png - images/asset_font_96.png - images/asset_font_128.png - images/asset_font_192.png - images/asset_font_256.png - images/asset_font_384.png - images/asset_shader_32.png - images/asset_shader_48.png - images/asset_shader_64.png - images/asset_shader_96.png - images/asset_shader_128.png - images/asset_shader_192.png - images/asset_shader_256.png - images/asset_shader_384.png - images/asset_sound_32.png - images/asset_sound_48.png - images/asset_sound_64.png - images/asset_sound_96.png - images/asset_sound_128.png - images/asset_sound_192.png - images/asset_sound_256.png - images/asset_sound_384.png - images/x.png - images/x@2x.png - images/browse.png - images/browse@2x.png - images/item-video-icon.png - images/item-video-icon@2x.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index c65d5256c8d..9c70baa7997 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -33,7 +33,10 @@ #include "rewritertransaction.h" #include "rewritingexception.h" +#include + #include +#include #include #include @@ -568,7 +571,7 @@ bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) QProcessUniquePointer process = puppetCreator.createPuppetProcess( "custom", {}, - std::function(), + [&] {}, [&](int exitCode, QProcess::ExitStatus exitStatus) { importProcessFinished(exitCode, exitStatus); }, @@ -598,7 +601,7 @@ bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFil QProcessUniquePointer process = puppetCreator.createPuppetProcess( "custom", {}, - std::function(), + [&] {}, [&](int exitCode, QProcess::ExitStatus exitStatus) { iconProcessFinished(exitCode, exitStatus); }, @@ -653,6 +656,16 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() addInfo(progressTitle); notifyProgress(0, progressTitle); + auto modelManager = QmlJS::ModelManagerInterface::instance(); + QFuture result; + if (modelManager) { + QmlJS::PathsAndLanguages pathToScan; + pathToScan.maybeInsert(Utils::FilePath::fromString(m_importPath)); + result = Utils::runAsync(&QmlJS::ModelManagerInterface::importScan, + modelManager->workingCopy(), pathToScan, + modelManager, true, true, true); + } + // First we have to wait a while to ensure qmljs detects new files and updates its // internal model. Then we make a non-change to the document to trigger qmljs snapshot // update. There is an inbuilt delay before rewriter change actually updates the data @@ -661,24 +674,37 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() QTimer *timer = new QTimer(parent()); static int counter; counter = 0; - timer->callOnTimeout([this, timer, progressTitle, model]() { + timer->callOnTimeout([this, timer, progressTitle, model, result]() { if (!isCancelled()) { - notifyProgress(++counter * 5, progressTitle); - if (counter < 10) { - // Do not proceed while application isn't active as the filesystem - // watcher qmljs uses won't trigger unless application is active - if (QApplication::applicationState() != Qt::ApplicationActive) - --counter; - } else if (counter == 10) { + notifyProgress(++counter, progressTitle); + if (counter < 50) { + if (result.isCanceled() || result.isFinished()) + counter = 49; // skip to next step + } else if (counter == 50) { model->rewriterView()->textModifier()->replace(0, 0, {}); - } else if (counter == 19) { + } else if (counter < 100) { try { + const QList posImports = model->possibleImports(); const QList currentImports = model->imports(); QList newImportsToAdd; + for (auto &imp : qAsConst(m_requiredImports)) { + const bool isPos = Utils::contains(posImports, [imp](const Import &posImp) { + return posImp.url() == imp.url(); + }); + const bool isCur = Utils::contains(currentImports, [imp](const Import &curImp) { + return curImp.url() == imp.url(); + }); + if (!(isPos || isCur)) + return; + // Check again with 'contains' to ensure we insert latest version if (!currentImports.contains(imp)) newImportsToAdd.append(imp); } + if (counter == 99) + addError(tr("Failed to insert import statement into qml document.")); + else + counter = 99; if (!newImportsToAdd.isEmpty()) { RewriterTransaction transaction = model->rewriterView()->beginRewriterTransaction( @@ -689,8 +715,9 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() } } catch (const RewritingException &e) { addError(tr("Failed to update imports: %1").arg(e.description())); + counter = 99; } - } else if (counter >= 20) { + } else if (counter >= 100) { if (!m_overwrittenImports.isEmpty()) model->rewriterView()->emitCustomNotification("asset_import_update"); timer->stop(); @@ -700,7 +727,7 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport() timer->stop(); } }); - timer->start(100); + timer->start(50); } else { notifyFinished(); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp index 78e06f0b56b..c86e5360d1c 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryitem.cpp @@ -48,7 +48,8 @@ QString ItemLibraryItem::typeName() const QString ItemLibraryItem::itemLibraryIconPath() const { - if (m_itemLibraryEntry.customComponentSource().isEmpty()) { + if (m_itemLibraryEntry.customComponentSource().isEmpty() + || !m_itemLibraryEntry.libraryEntryIconPath().isEmpty()) { return QStringLiteral("image://qmldesigner_itemlibrary/") + m_itemLibraryEntry.libraryEntryIconPath(); } else { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index e8cdb4dcd07..321607fc7bf 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -103,11 +103,7 @@ WidgetInfo ItemLibraryView::widgetInfo() imageCacheData()->synchronousFontImageCache}; } - return createWidgetInfo(m_widget.data(), - QStringLiteral("Library"), - WidgetInfo::LeftPane, - 0, - tr("Library")); + return createWidgetInfo(m_widget.data(), "Components", WidgetInfo::LeftPane, 0, tr("Components")); } void ItemLibraryView::modelAttached(Model *model) @@ -121,7 +117,6 @@ void ItemLibraryView::modelAttached(Model *model) m_widget->updatePossibleImports(model->possibleImports()); m_hasErrors = !rewriterView()->errors().isEmpty(); m_widget->setFlowMode(QmlItemNode(rootModelNode()).isFlowView()); - setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()); } void ItemLibraryView::modelAboutToBeDetached(Model *model) @@ -182,16 +177,6 @@ void ItemLibraryView::usedImportsChanged(const QList &usedImports) m_widget->updateUsedImports(usedImports); } -void ItemLibraryView::setResourcePath(const QString &resourcePath) -{ - if (m_widget.isNull()) - m_widget = new ItemLibraryWidget{m_imageCacheData->cache, - m_imageCacheData->asynchronousFontImageCache, - m_imageCacheData->synchronousFontImageCache}; - - m_widget->setResourcePath(resourcePath); -} - ImageCacheData *ItemLibraryView::imageCacheData() { std::call_once(imageCacheFlag, [this]() { diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h index 3741df65c39..8d85383d5dc 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h @@ -59,8 +59,6 @@ public: void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; - void setResourcePath(const QString &resourcePath); - AsynchronousImageCache &imageCache(); protected: diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index f71c629a43b..edca09720fd 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -25,7 +25,6 @@ #include "itemlibrarywidget.h" -#include "itemlibraryassetsmodel.h" #include "itemlibraryiconimageprovider.h" #include "itemlibraryimport.h" @@ -37,7 +36,6 @@ #include #include #include -#include "itemlibraryassetsiconprovider.h" #include "modelnodeoperations.h" #include #include @@ -91,10 +89,8 @@ static QString propertyEditorResourcesPath() bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::FocusOut) { - if (obj == m_itemViewQuickWidget.data()) - QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu"); - else if (obj == m_assetsWidget.data()) - QMetaObject::invokeMethod(m_assetsWidget->rootObject(), "handleViewFocusOut"); + if (obj == m_itemsWidget.data()) + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "closeContextMenu"); } else if (event->type() == QMouseEvent::MouseMove) { if (m_itemToDrag.isValid()) { QMouseEvent *me = static_cast(event); @@ -134,23 +130,9 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event) m_itemToDrag = {}; } - } else if (!m_assetsToDrag.isEmpty()) { - QMouseEvent *me = static_cast(event); - if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 10) { - auto drag = new QDrag(this); - drag->setPixmap(m_assetsIconProvider->requestPixmap(m_assetsToDrag[0], nullptr, {128, 128})); - QMimeData *mimeData = new QMimeData; - mimeData->setData("application/vnd.bauhaus.libraryresource", m_assetsToDrag.join(',').toUtf8()); - drag->setMimeData(mimeData); - drag->exec(); - drag->deleteLater(); - - m_assetsToDrag.clear(); - } } } else if (event->type() == QMouseEvent::MouseButtonRelease) { m_itemToDrag = {}; - m_assetsToDrag.clear(); QWidget *view = QmlDesignerPlugin::instance()->viewManager().widget("Navigator"); if (view) { NavigatorWidget *navView = qobject_cast(view); @@ -175,113 +157,47 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, : m_itemIconSize(24, 24) , m_fontImageCache(synchronousFontImageCache) , m_itemLibraryModel(new ItemLibraryModel(this)) - , m_itemLibraryAddImportModel(new ItemLibraryAddImportModel(this)) - , m_assetsIconProvider(new ItemLibraryAssetsIconProvider(synchronousFontImageCache)) - , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) - , m_assetsModel(new ItemLibraryAssetsModel(synchronousFontImageCache, m_fileSystemWatcher, this)) - , m_headerWidget(new QQuickWidget(this)) - , m_addImportWidget(new QQuickWidget(this)) - , m_itemViewQuickWidget(new QQuickWidget(this)) - , m_assetsWidget(new QQuickWidget(this)) + , m_addModuleModel(new ItemLibraryAddImportModel(this)) + , m_itemsWidget(new QQuickWidget(this)) , m_imageCache{imageCache} { m_compressionTimer.setInterval(200); m_compressionTimer.setSingleShot(true); - m_assetCompressionTimer.setInterval(200); - m_assetCompressionTimer.setSingleShot(true); ItemLibraryModel::registerQmlTypes(); - setWindowTitle(tr("Library", "Title of library view")); + setWindowTitle(tr("Components Library", "Title of library view")); setMinimumWidth(100); - // create header widget - m_headerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - m_headerWidget->setMinimumHeight(75); - m_headerWidget->setMinimumWidth(100); - Theme::setupTheme(m_headerWidget->engine()); - m_headerWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_headerWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_headerWidget->rootContext()->setContextProperty("rootView", QVariant::fromValue(this)); + // set up Component Library view and model + m_itemsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_itemsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - // create add imports widget - m_addImportWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - Theme::setupTheme(m_addImportWidget->engine()); - m_addImportWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_addImportWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_addImportWidget->rootContext()->setContextProperties({ - {"addImportModel", QVariant::fromValue(m_itemLibraryAddImportModel.data())}, + m_itemsWidget->rootContext()->setContextProperties({ + {"itemLibraryModel", QVariant::fromValue(m_itemLibraryModel.data())}, + {"addModuleModel", QVariant::fromValue(m_addModuleModel.data())}, + {"itemLibraryIconWidth", m_itemIconSize.width()}, + {"itemLibraryIconHeight", m_itemIconSize.height()}, {"rootView", QVariant::fromValue(this)}, - }); - - // set up Item Library view and model - m_itemViewQuickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - m_itemViewQuickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - - m_itemViewQuickWidget->rootContext()->setContextProperties(QVector{ - {{"itemLibraryModel"}, QVariant::fromValue(m_itemLibraryModel.data())}, - {{"itemLibraryIconWidth"}, m_itemIconSize.width()}, - {{"itemLibraryIconHeight"}, m_itemIconSize.height()}, - {{"rootView"}, QVariant::fromValue(this)}, - {{"widthLimit"}, HORIZONTAL_LAYOUT_WIDTH_LIMIT}, - {{"highlightColor"}, Utils::StyleHelper::notTooBrightHighlightColor()}, + {"widthLimit", HORIZONTAL_LAYOUT_WIDTH_LIMIT}, + {"highlightColor", Utils::StyleHelper::notTooBrightHighlightColor()}, }); m_previewTooltipBackend = std::make_unique(m_imageCache); - m_itemViewQuickWidget->rootContext()->setContextProperty("tooltipBackend", - m_previewTooltipBackend.get()); + m_itemsWidget->rootContext()->setContextProperty("tooltipBackend", m_previewTooltipBackend.get()); - m_itemViewQuickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); - m_itemViewQuickWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), + m_itemsWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground)); + m_itemsWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), new Internal::ItemLibraryImageProvider); - Theme::setupTheme(m_itemViewQuickWidget->engine()); - m_itemViewQuickWidget->installEventFilter(this); - m_assetsWidget->installEventFilter(this); - - m_fontPreviewTooltipBackend = std::make_unique(asynchronousFontImageCache); - // Note: Though the text specified here appears in UI, it shouldn't be translated, as it's - // a commonly used sentence to preview the font glyphs in latin fonts. - // For fonts that do not have latin glyphs, the font family name will have to suffice for preview. - m_fontPreviewTooltipBackend->setAuxiliaryData( - ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300}, - Theme::getColor(Theme::DStextColor).name(), - QStringLiteral("The quick brown fox jumps\n" - "over the lazy dog\n" - "1234567890")}); - // create assets widget - m_assetsWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - Theme::setupTheme(m_assetsWidget->engine()); - m_assetsWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); - m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); - m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider); - m_assetsWidget->rootContext()->setContextProperties(QVector{ - {{"assetsModel"}, QVariant::fromValue(m_assetsModel.data())}, - {{"rootView"}, QVariant::fromValue(this)}, - {{"tooltipBackend"}, QVariant::fromValue(m_fontPreviewTooltipBackend.get())} - }); - - // If project directory contents change, or one of the asset files is modified, we must - // reconstruct the model to update the icons - connect(m_fileSystemWatcher, &Utils::FileSystemWatcher::directoryChanged, [this](const QString & changedDirPath) { - Q_UNUSED(changedDirPath) - m_assetCompressionTimer.start(); - }); - - m_stackedWidget = new QStackedWidget(this); - m_stackedWidget->addWidget(m_itemViewQuickWidget.data()); - m_stackedWidget->addWidget(m_assetsWidget.data()); - m_stackedWidget->addWidget(m_addImportWidget.data()); - m_stackedWidget->setMinimumHeight(30); - m_stackedWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + Theme::setupTheme(m_itemsWidget->engine()); + m_itemsWidget->installEventFilter(this); auto layout = new QVBoxLayout(this); layout->setContentsMargins({}); layout->setSpacing(0); - layout->addWidget(m_headerWidget.data()); - layout->addWidget(m_stackedWidget.data()); + layout->addWidget(m_itemsWidget.data()); updateSearch(); - /* style sheets */ setStyleSheet(Theme::replaceCssColors( QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); @@ -289,28 +205,8 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache, connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ItemLibraryWidget::reloadQmlSource); connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel); - connect(&m_assetCompressionTimer, &QTimer::timeout, this, [this]() { - // TODO: find a clever way to only refresh the changed directory part of the model - // Don't bother with asset updates after model has detached, project is probably closing - if (!m_model.isNull()) { - if (QApplication::activeModalWidget()) { - // Retry later, as updating file system watchers can crash when there is an active - // modal widget - m_assetCompressionTimer.start(); - } else { - m_assetsModel->refresh(); - // reload assets qml so that an overridden file's image shows the new image - QTimer::singleShot(100, this, [this] { - const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; - m_assetsWidget->engine()->clearComponentCache(); - m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); - }); - } - } - }); - - m_itemViewQuickWidget->engine()->addImageProvider("itemlibrary_preview", + m_itemsWidget->engine()->addImageProvider("itemlibrary_preview", new ItemLibraryIconImageProvider{m_imageCache}); // init the first load of the QML UI elements @@ -336,42 +232,28 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo) this, &ItemLibraryWidget::delayedUpdateModel); connect(m_itemLibraryInfo.data(), &ItemLibraryInfo::priorityImportsChanged, this, &ItemLibraryWidget::handlePriorityImportsChanged); - m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); } delayedUpdateModel(); } QList ItemLibraryWidget::createToolBarWidgets() { -// TODO: implement - QList buttons; - return buttons; + return {}; } + void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText) { if (filterText != m_filterText) { m_filterText = filterText; - emit searchActiveChanged(); + updateSearch(); } - - updateSearch(); -} - -void ItemLibraryWidget::handleAddModule() -{ - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 0)); - handleTabChanged(2); -} - -void ItemLibraryWidget::handleAddAsset() -{ - addResources({}); } void ItemLibraryWidget::handleAddImport(int index) { - Import import = m_itemLibraryAddImportModel->getImportAt(index); + Import import = m_addModuleModel->getImportAt(index); if (import.isLibraryImport() && (import.url().startsWith("QtQuick") || import.url().startsWith("SimulinkConnector"))) { QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED @@ -381,27 +263,10 @@ void ItemLibraryWidget::handleAddImport(int index) auto document = QmlDesignerPlugin::instance()->currentDesignDocument(); document->documentModel()->changeImports({import}, {}); - m_stackedWidget->setCurrentIndex(0); // switch to the Components view after import is added + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "switchToComponentsView"); updateSearch(); } -void ItemLibraryWidget::handleFilesDrop(const QStringList &filesPaths) -{ - addResources(filesPaths); -} - -QSet ItemLibraryWidget::supportedDropSuffixes() -{ - const QList handlers = QmlDesignerPlugin::instance()->viewManager() - .designerActionManager().addResourceHandler(); - - QSet suffixes; - for (const AddResourceHandler &handler : handlers) - suffixes.insert(handler.filter); - - return suffixes; -} - void ItemLibraryWidget::delayedUpdateModel() { static bool disableTimer = DesignerSettings::getValue(DesignerSettingsKey::DISABLE_ITEM_LIBRARY_UPDATE_TIMER).toBool(); @@ -423,20 +288,14 @@ void ItemLibraryWidget::setModel(Model *model) const bool subCompEditMode = document->inFileComponentModelActive(); if (m_subCompEditMode != subCompEditMode) { m_subCompEditMode = subCompEditMode; - // Switch out of module add panel if it's active - if (m_subCompEditMode && m_stackedWidget->currentIndex() == 2) - m_stackedWidget->setCurrentIndex(0); + // Switch out of add module view if it's active + if (m_subCompEditMode) + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "switchToComponentsView"); emit subCompEditModeChanged(); } } } -void ItemLibraryWidget::handleTabChanged(int index) -{ - m_stackedWidget->setCurrentIndex(index); - updateSearch(); -} - QString ItemLibraryWidget::qmlSourcesPath() { #ifdef SHARE_QML_PATH @@ -448,30 +307,15 @@ QString ItemLibraryWidget::qmlSourcesPath() void ItemLibraryWidget::clearSearchFilter() { - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "clearSearchFilter"); + QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "clearSearchFilter"); } void ItemLibraryWidget::reloadQmlSource() { - const QString libraryHeaderQmlPath = qmlSourcesPath() + "/LibraryHeader.qml"; - QTC_ASSERT(QFileInfo::exists(libraryHeaderQmlPath), return); - m_headerWidget->engine()->clearComponentCache(); - m_headerWidget->setSource(QUrl::fromLocalFile(libraryHeaderQmlPath)); - - const QString addImportQmlPath = qmlSourcesPath() + "/AddImport.qml"; - QTC_ASSERT(QFileInfo::exists(addImportQmlPath), return); - m_addImportWidget->engine()->clearComponentCache(); - m_addImportWidget->setSource(QUrl::fromLocalFile(addImportQmlPath)); - const QString itemLibraryQmlPath = qmlSourcesPath() + "/ItemsView.qml"; QTC_ASSERT(QFileInfo::exists(itemLibraryQmlPath), return); - m_itemViewQuickWidget->engine()->clearComponentCache(); - m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath)); - - const QString assetsQmlPath = qmlSourcesPath() + "/Assets.qml"; - QTC_ASSERT(QFileInfo::exists(assetsQmlPath), return); - m_assetsWidget->engine()->clearComponentCache(); - m_assetsWidget->setSource(QUrl::fromLocalFile(assetsQmlPath)); + m_itemsWidget->engine()->clearComponentCache(); + m_itemsWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlPath)); } void ItemLibraryWidget::updateModel() @@ -496,7 +340,7 @@ void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updatePossibleImports(const QList &possibleImports) { - m_itemLibraryAddImportModel->update(possibleImports); + m_addModuleModel->update(possibleImports); delayedUpdateModel(); } @@ -507,30 +351,19 @@ void ItemLibraryWidget::updateUsedImports(const QList &usedImports) void ItemLibraryWidget::updateSearch() { - if (m_stackedWidget->currentIndex() == 0) { // Item Library tab selected - m_itemLibraryModel->setSearchText(m_filterText); - m_itemViewQuickWidget->update(); - } else if (m_stackedWidget->currentIndex() == 1) { // Assets tab selected - m_assetsModel->setSearchText(m_filterText); - } else if (m_stackedWidget->currentIndex() == 2) { // QML imports tab selected - m_itemLibraryAddImportModel->setSearchText(m_filterText); - } + m_itemLibraryModel->setSearchText(m_filterText); + m_itemsWidget->update(); + m_addModuleModel->setSearchText(m_filterText); } void ItemLibraryWidget::handlePriorityImportsChanged() { if (!m_itemLibraryInfo.isNull()) { - m_itemLibraryAddImportModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); - m_itemLibraryAddImportModel->update(m_model->possibleImports()); + m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports()); + m_addModuleModel->update(m_model->possibleImports()); } } -void ItemLibraryWidget::setResourcePath(const QString &resourcePath) -{ - m_assetsModel->setRootPath(resourcePath); - updateSearch(); -} - void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos) { // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay @@ -539,54 +372,11 @@ void ItemLibraryWidget::startDragAndDrop(const QVariant &itemLibEntry, const QPo m_dragStartPoint = mousePos.toPoint(); } -void ItemLibraryWidget::startDragAsset(const QStringList &assetPaths, const QPointF &mousePos) -{ - // Actual drag is created after mouse has moved to avoid a QDrag bug that causes drag to stay - // active (and blocks mouse release) if mouse is released at the same spot of the drag start. - m_assetsToDrag = assetPaths; - m_dragStartPoint = mousePos.toPoint(); -} - -QPair ItemLibraryWidget::getAssetTypeAndData(const QString &assetPath) -{ - QString suffix = "*." + assetPath.split('.').last().toLower(); - if (!suffix.isEmpty()) { - if (ItemLibraryAssetsModel::supportedImageSuffixes().contains(suffix)) { - // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.image", suffix.toUtf8()}; - } else if (ItemLibraryAssetsModel::supportedFontSuffixes().contains(suffix)) { - // Data: Font family name - QRawFont font(assetPath, 10); - QString fontFamily = font.isValid() ? font.familyName() : ""; - return {"application/vnd.bauhaus.libraryresource.font", fontFamily.toUtf8()}; - } else if (ItemLibraryAssetsModel::supportedShaderSuffixes().contains(suffix)) { - // Data: shader type, frament (f) or vertex (v) - return {"application/vnd.bauhaus.libraryresource.shader", - ItemLibraryAssetsModel::supportedFragmentShaderSuffixes().contains(suffix) ? "f" : "v"}; - } else if (ItemLibraryAssetsModel::supportedAudioSuffixes().contains(suffix)) { - // No extra data for sounds - return {"application/vnd.bauhaus.libraryresource.sound", {}}; - } else if (ItemLibraryAssetsModel::supportedVideoSuffixes().contains(suffix)) { - // No extra data for videos - return {"application/vnd.bauhaus.libraryresource.video", {}}; - } else if (ItemLibraryAssetsModel::supportedTexture3DSuffixes().contains(suffix)) { - // Data: Image format (suffix) - return {"application/vnd.bauhaus.libraryresource.texture3d", suffix.toUtf8()}; - } - } - return {}; -} - bool ItemLibraryWidget::subCompEditMode() const { return m_subCompEditMode; } -bool ItemLibraryWidget::searchActive() const -{ - return !m_filterText.isEmpty(); -} - void ItemLibraryWidget::setFlowMode(bool b) { m_itemLibraryModel->setFlowMode(b); @@ -608,111 +398,8 @@ void ItemLibraryWidget::addImportForItem(const QString &importUrl) QTC_ASSERT(m_itemLibraryModel, return); QTC_ASSERT(m_model, return); - Import import = m_itemLibraryAddImportModel->getImport(importUrl); + Import import = m_addModuleModel->getImport(importUrl); m_model->changeImports({import}, {}); } -static QHash allImageFormats() -{ - const QList mimeTypes = QImageReader::supportedMimeTypes(); - auto transformer = [](const QByteArray& format) -> QString { return QString("*.") + format; }; - QHash imageFormats; - for (const auto &mimeType : mimeTypes) - imageFormats.insert(mimeType, Utils::transform(QImageReader::imageFormatsForMimeType(mimeType), transformer)); - imageFormats.insert("image/vnd.radiance", {"*.hdr"}); - imageFormats.insert("image/ktx", {"*.ktx"}); - - return imageFormats; -} - -void ItemLibraryWidget::addResources(const QStringList &files) -{ - DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); - - QTC_ASSERT(document, return); - - const QList handlers = QmlDesignerPlugin::instance()->viewManager() - .designerActionManager().addResourceHandler(); - - QStringList fileNames = files; - if (fileNames.isEmpty()) { // if no files, show the "add assets" dialog - QMultiMap map; - QHash priorities; - for (const AddResourceHandler &handler : handlers) { - map.insert(handler.category, handler.filter); - priorities.insert(handler.category, handler.piority); - } - - QStringList sortedKeys = map.uniqueKeys(); - Utils::sort(sortedKeys, [&priorities](const QString &first, const QString &second) { - return priorities.value(first) < priorities.value(second); - }); - - QStringList filters { tr("All Files (%1)").arg("*.*") }; - QString filterTemplate = "%1 (%2)"; - for (const QString &key : qAsConst(sortedKeys)) { - const QStringList values = map.values(key); - if (values.contains("*.png")) { // Avoid long filter for images by splitting - const QHash imageFormats = allImageFormats(); - QHash::const_iterator i = imageFormats.constBegin(); - while (i != imageFormats.constEnd()) { - filters.append(filterTemplate.arg(key + QString::fromLatin1(i.key()), i.value().join(' '))); - ++i; - } - } else { - filters.append(filterTemplate.arg(key, values.join(' '))); - } - } - - static QString lastDir; - const QString currentDir = lastDir.isEmpty() ? document->fileName().parentDir().toString() : lastDir; - - fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), - tr("Add Assets"), - currentDir, - filters.join(";;")); - - if (!fileNames.isEmpty()) { - lastDir = QFileInfo(fileNames.first()).absolutePath(); - // switch to assets view after an asset is added - m_stackedWidget->setCurrentIndex(1); - QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 1)); - } - } - - QHash filterToCategory; - QHash categoryToOperation; - for (const AddResourceHandler &handler : handlers) { - filterToCategory.insert(handler.filter, handler.category); - categoryToOperation.insert(handler.category, handler.operation); - } - - QMultiMap categoryFileNames; // filenames grouped by category - - for (const QString &fileName : qAsConst(fileNames)) { - const QString suffix = "*." + QFileInfo(fileName).suffix().toLower(); - const QString category = filterToCategory.value(suffix); - categoryFileNames.insert(category, fileName); - } - - for (const QString &category : categoryFileNames.uniqueKeys()) { - QStringList fileNames = categoryFileNames.values(category); - AddResourceOperation operation = categoryToOperation.value(category); - QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category); - if (operation) { - AddFilesResult result = operation(fileNames, - document->fileName().parentDir().toString()); - if (result == AddFilesResult::Failed) { - Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), - tr("Could not add %1 to project.") - .arg(fileNames.join(' '))); - } - } else { - Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), - tr("Could not add %1 to project. Unsupported file format.") - .arg(fileNames.join(' '))); - } - } -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h index d67c3df71db..85b95ce23f4 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h @@ -31,7 +31,6 @@ #include #include #include -#include "itemlibraryassetsmodel.h" #include #include @@ -48,18 +47,13 @@ class QStackedWidget; class QShortcut; QT_END_NAMESPACE -namespace Utils { class FileSystemWatcher; } - namespace QmlDesigner { class MetaInfo; class ItemLibraryEntry; class Model; -class CustomFileSystemModel; class ItemLibraryModel; -class ItemLibraryAssetsIconProvider; -class ItemLibraryAssetsModel; class ItemLibraryAddImportModel; class ItemLibraryResourceView; class SynchronousImageCache; @@ -72,7 +66,6 @@ class ItemLibraryWidget : public QFrame public: Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged) - Q_PROPERTY(bool searchActive READ searchActive NOTIFY searchActiveChanged) ItemLibraryWidget(AsynchronousImageCache &imageCache, AsynchronousImageCache &asynchronousFontImageCache, @@ -90,32 +83,22 @@ public: void updatePossibleImports(const QList &possibleImports); void updateUsedImports(const QList &usedImports); - void setResourcePath(const QString &resourcePath); void setModel(Model *model); void setFlowMode(bool b); - static QPair getAssetTypeAndData(const QString &assetPath); inline static bool isHorizontalLayout = false; bool subCompEditMode() const; - bool searchActive() const; Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos); - Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos); Q_INVOKABLE void removeImport(const QString &importUrl); Q_INVOKABLE void addImportForItem(const QString &importUrl); - Q_INVOKABLE void handleTabChanged(int index); - Q_INVOKABLE void handleAddModule(); - Q_INVOKABLE void handleAddAsset(); Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText); Q_INVOKABLE void handleAddImport(int index); - Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths); - Q_INVOKABLE QSet supportedDropSuffixes(); signals: void itemActivated(const QString &itemName); void subCompEditModeChanged(); - void searchActiveChanged(); protected: bool eventFilter(QObject *obj, QEvent *event) override; @@ -124,38 +107,25 @@ protected: private: void reloadQmlSource(); - void addResources(const QStringList &files); void updateSearch(); void handlePriorityImportsChanged(); QTimer m_compressionTimer; - QTimer m_assetCompressionTimer; QSize m_itemIconSize; SynchronousImageCache &m_fontImageCache; QPointer m_itemLibraryInfo; QPointer m_itemLibraryModel; - QPointer m_itemLibraryAddImportModel; - ItemLibraryAssetsIconProvider *m_assetsIconProvider = nullptr; - Utils::FileSystemWatcher *m_fileSystemWatcher = nullptr; - QPointer m_assetsModel; + QPointer m_addModuleModel; - QPointer m_stackedWidget; - - QScopedPointer m_headerWidget; - QScopedPointer m_addImportWidget; - QScopedPointer m_itemViewQuickWidget; - QScopedPointer m_assetsWidget; + QScopedPointer m_itemsWidget; std::unique_ptr m_previewTooltipBackend; - std::unique_ptr m_fontPreviewTooltipBackend; QShortcut *m_qmlSourceUpdateShortcut; AsynchronousImageCache &m_imageCache; QPointer m_model; QVariant m_itemToDrag; - QStringList m_assetsToDrag; - QPair m_assetToDragTypeAndData; bool m_updateRetry = false; QString m_filterText; QPoint m_dragStartPoint; diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 7e7b650da82..c92e2a20fe8 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -28,7 +28,7 @@ #include "navigatorwidget.h" #include "choosefrompropertylistdialog.h" #include "qmldesignerplugin.h" -#include "itemlibrarywidget.h" +#include "assetslibrarywidget.h" #include #include @@ -47,6 +47,8 @@ #include +#include + #include #include #include @@ -226,7 +228,7 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const } else if (role == Qt::ToolTipRole) { if (currentQmlObjectNode.hasError()) { QString errorString = currentQmlObjectNode.error(); - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool() + if (QmlProjectManager::QmlProject::isQtDesignStudio() && currentQmlObjectNode.isRootNode()) { errorString.append(QString("\n%1").arg(tr("Changing the setting \"%1\" might solve the issue.").arg( tr("Use QML emulation layer that is built with the selected Qt")))); @@ -341,8 +343,7 @@ QList NavigatorTreeModel::filteredList(const NodeListProperty &proper return list; } -QModelIndex NavigatorTreeModel::index(int row, int column, - const QModelIndex &parent) const +QModelIndex NavigatorTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!m_view->model()) return {}; @@ -389,21 +390,20 @@ QModelIndex NavigatorTreeModel::parent(const QModelIndex &index) const int row = 0; - if (!parentModelNode.isRootNode() && parentModelNode.parentProperty().isNodeListProperty()) + if (!parentModelNode.isRootNode() && parentModelNode.parentProperty().isNodeListProperty()) { row = filteredList(parentModelNode.parentProperty().toNodeListProperty(), m_showOnlyVisibleItems, m_reverseItemOrder).indexOf(parentModelNode); + } return createIndexFromModelNode(row, 0, parentModelNode); } int NavigatorTreeModel::rowCount(const QModelIndex &parent) const { - if (!m_view->isAttached()) + if (!m_view->isAttached() || parent.column() > 0) return 0; - if (parent.column() > 0) - return 0; const ModelNode modelNode = modelNodeForIndex(parent); if (!modelNode.isValid()) @@ -411,10 +411,11 @@ int NavigatorTreeModel::rowCount(const QModelIndex &parent) const int rows = 0; - if (modelNode.defaultNodeListProperty().isValid()) + if (modelNode.defaultNodeListProperty().isValid()) { rows = filteredList(modelNode.defaultNodeListProperty(), m_showOnlyVisibleItems, m_reverseItemOrder).count(); + } return rows; } @@ -454,8 +455,8 @@ void NavigatorTreeModel::setView(NavigatorView *view) QStringList NavigatorTreeModel::mimeTypes() const { const static QStringList types({"application/vnd.modelnode.list", - "application/vnd.bauhaus.itemlibraryinfo", - "application/vnd.bauhaus.libraryresource"}); + "application/vnd.bauhaus.itemlibraryinfo", + "application/vnd.bauhaus.libraryresource"}); return types; } @@ -566,7 +567,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, if (document && !document->inFileComponentModelActive()) { QSet neededImports; for (const QString &assetPath : assetsPaths) { - QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first; + QString assetType = AssetsLibraryWidget::getAssetTypeAndData(assetPath).first; if (assetType == "application/vnd.bauhaus.libraryresource.shader") neededImports.insert("QtQuick3D"); else if (assetType == "application/vnd.bauhaus.libraryresource.sound") @@ -582,7 +583,7 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, m_view->executeInTransaction("NavigatorTreeModel::dropMimeData", [&] { for (const QString &assetPath : assetsPaths) { - auto assetTypeAndData = ItemLibraryWidget::getAssetTypeAndData(assetPath); + auto assetTypeAndData = AssetsLibraryWidget::getAssetTypeAndData(assetPath); QString assetType = assetTypeAndData.first; QString assetData = QString::fromUtf8(assetTypeAndData.second); if (assetType == "application/vnd.bauhaus.libraryresource.image") @@ -788,8 +789,7 @@ ModelNode NavigatorTreeModel::handleItemLibraryImageDrop(const QString &imagePat ModelNode newModelNode; if (!dropAsImage3dTexture(targetNode, targetProperty, imagePathRelative, newModelNode)) { - if (targetNode.isSubclassOf("QtQuick.Image") - || targetNode.isSubclassOf("QtQuick.BorderImage")) { + if (targetNode.isSubclassOf("QtQuick.Image") || targetNode.isSubclassOf("QtQuick.BorderImage")) { // if dropping an image on an existing image, set the source targetNode.variantProperty("source").setValue(imagePathRelative); } else { @@ -964,28 +964,27 @@ bool NavigatorTreeModel::dropAsImage3dTexture(const ModelNode &targetNode, const QString &imagePath, ModelNode &newNode) { - if (targetNode.isSubclassOf("QtQuick3D.Material")) { - // if dropping an image on a default material, create a texture instead of image - ChooseFromPropertyListDialog *dialog = nullptr; - if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") - || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) { - // Show texture property selection dialog - dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, "QtQuick3D.Texture", - Core::ICore::dialogParent()); - if (dialog) - dialog->exec(); - } - if (!dialog || dialog->result() == QDialog::Accepted) { + if (targetNode.isSubclassOf("QtQuick3D.DefaultMaterial") + || targetNode.isSubclassOf("QtQuick3D.PrincipledMaterial")) { + // if dropping an image on a material, create a texture instead of image + // Show texture property selection dialog + auto dialog = ChooseFromPropertyListDialog::createIfNeeded(targetNode, "QtQuick3D.Texture", + Core::ICore::dialogParent()); + if (!dialog) + return false; + + dialog->exec(); + + if (dialog->result() == QDialog::Accepted) { m_view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { newNode = createTextureNode(targetProp, imagePath); - if (newNode.isValid() && dialog) { - // Automatically set the texture to selected property + if (newNode.isValid()) // Automatically set the texture to selected property targetNode.bindingProperty(dialog->selectedProperty()).setExpression(newNode.validId()); - } }); } + delete dialog; - return newNode.isValid(); + return true; } else if (targetNode.isSubclassOf("QtQuick3D.TextureInput")) { // If dropping an image on a TextureInput, create a texture on the same level as // TextureInput, as the TextureInput doesn't support Texture children (QTBUG-86219) diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui index fec0ba8f384..6839c1b107d 100644 --- a/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui +++ b/src/plugins/qmldesigner/components/previewtooltip/previewimagetooltip.ui @@ -6,8 +6,8 @@ 0 0 - 651 - 318 + 517 + 166 @@ -90,8 +90,8 @@ - 300 - 300 + 150 + 150 @@ -163,7 +163,7 @@ 0 - 1 + 3 diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp index b4f50848b9a..f5164a97213 100644 --- a/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachecollector.cpp @@ -90,7 +90,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name, model->setRewriterView(&rewriterView); - if (rewriterView.inErrorState() || !rewriterView.rootModelNode().metaInfo().isGraphicalItem()) { + if (rewriterView.inErrorState() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() + && !rewriterView.rootModelNode().isSubclassOf("Quick3D.Node") )) { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed); return; diff --git a/src/plugins/qmldesigner/designercore/include/modelcache.h b/src/plugins/qmldesigner/designercore/include/modelcache.h new file mode 100644 index 00000000000..bd4704294dd --- /dev/null +++ b/src/plugins/qmldesigner/designercore/include/modelcache.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 + +#include +#include + +namespace QmlDesigner { + +template +class ModelCache +{ +public: + ModelCache(int max = 20) + : m_maxEntries(max) + {} + + void insert(Model *model, const DataType &data) + { + QObject::connect(model, &Model::destroyed, [this](QObject *o) { + QObject *deletedModel = o; + + if (deletedModel) { + m_content.remove(deletedModel); + m_queue.removeAll(deletedModel); + } + }); + + m_content.insert(model, data); + if (!m_queue.contains(model)) + m_queue.append(model); + if (m_queue.length() > m_maxEntries) { + QObject *first = m_queue.takeFirst(); + m_content.remove(first); + } + } + + Utils::optional take(Model *model) + { + if (!m_content.contains(model)) + return {}; + m_queue.removeOne(model); + return m_content.take(model); + } + +private: + QHash m_content; + QQueue m_queue; + int m_maxEntries = 20; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index e29498e1438..48ecd4119f6 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -27,6 +27,7 @@ #include "qmldesignercorelib_global.h" #include "abstractview.h" +#include "modelcache.h" #include #include @@ -232,11 +233,29 @@ private: // functions PropertyChangeFlags flags); private: + struct NodeInstanceCacheData + { + NodeInstanceCacheData(const QHash &i, + const QHash &p) + : instances(i) + , previewImages(p) + {} + + NodeInstanceCacheData() = default; + + QHash instances; + QHash previewImages; + }; + + QList loadInstancesFromCache(const QList &nodeList, + const NodeInstanceCacheData &cache); + QHash m_imageDataMap; NodeInstance m_rootNodeInstance; NodeInstance m_activeStateInstance; QHash m_nodeInstanceHash; + ModelCache m_nodeInstanceCache; QHash m_statePreviewImage; ConnectionManagerInterface &m_connectionManager; std::unique_ptr m_nodeInstanceServer; diff --git a/src/plugins/qmldesigner/designercore/include/viewmanager.h b/src/plugins/qmldesigner/designercore/include/viewmanager.h index ecfec36860b..04f25b84f81 100644 --- a/src/plugins/qmldesigner/designercore/include/viewmanager.h +++ b/src/plugins/qmldesigner/designercore/include/viewmanager.h @@ -64,7 +64,6 @@ public: void attachViewsExceptRewriterAndComponetView(); void detachViewsExceptRewriterAndComponetView(); - void setItemLibraryViewResourcePath(const QString &resourcePath); void setComponentNode(const ModelNode &componentNode); void setComponentViewToMaster(); void setNodeInstanceViewTarget(ProjectExplorer::Target *target); @@ -116,7 +115,6 @@ private: // functions void addView(std::unique_ptr &&view); void attachNodeInstanceView(); - void attachItemLibraryView(); void attachAdditionalViews(); void detachAdditionalViews(); void detachStandardViews(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 5b83b637953..48391fe4b9c 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -265,6 +265,9 @@ void NodeInstanceView::modelAboutToBeDetached(Model * model) { m_connectionManager.setCrashCallback({}); + m_nodeInstanceCache.insert(model, + NodeInstanceCacheData(m_nodeInstanceHash, m_statePreviewImage)); + removeAllInstanceNodeRelationships(); if (m_nodeInstanceServer) { m_nodeInstanceServer->clearScene(createClearSceneCommand()); @@ -935,10 +938,16 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() QList nodeList = allModelNodes(); QList instanceList; - for (const ModelNode &node : std::as_const(nodeList)) { - NodeInstance instance = loadNode(node); - if (!isSkippedNode(node)) - instanceList.append(instance); + Utils::optional oldNodeInstanceHash = m_nodeInstanceCache.take(model()); + if (oldNodeInstanceHash + && oldNodeInstanceHash->instances.value(rootModelNode()).isValid()) { + instanceList = loadInstancesFromCache(nodeList, oldNodeInstanceHash.value()); + } else { + for (const ModelNode &node : std::as_const(nodeList)) { + NodeInstance instance = loadNode(node); + if (!isSkippedNode(node)) + instanceList.append(instance); + } } nodeList = filterNodesForSkipItems(nodeList); @@ -1942,4 +1951,32 @@ void NodeInstanceView::maybeResetOnPropertyChange(const PropertyName &name, cons resetPuppet(); } +QList NodeInstanceView::loadInstancesFromCache(const QList &nodeList, + const NodeInstanceCacheData &cache) +{ + QList instanceList; + + auto previews = cache.previewImages; + auto iterator = previews.begin(); + while (iterator != previews.end()) { + if (iterator.key().isValid()) + m_statePreviewImage.insert(iterator.key(), iterator.value()); + iterator++; + } + + for (const ModelNode &node : std::as_const(nodeList)) { + NodeInstance instance = cache.instances.value(node); + if (instance.isValid()) + insertInstanceRelationships(instance); + else + instance = loadNode(node); + + if (node.isRootNode()) + m_rootNodeInstance = instance; + if (!isSkippedNode(node)) + instanceList.append(instanceForModelNode(node)); + } + + return instanceList; } +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index cede56f299d..a001a8b0c29 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -420,6 +420,7 @@ void SubComponentManager::parseQuick3DAssetsItem(const QString &importUrl, const itemLibraryEntry.setType(type.toUtf8(), 1, 0); itemLibraryEntry.setName(name); itemLibraryEntry.setCategory(::QmlDesigner::SubComponentManager::tr("My 3D Components")); + itemLibraryEntry.setCustomComponentSource(qmlIt.fileInfo().absoluteFilePath()); itemLibraryEntry.setRequiredImport(importUrl); QString iconPath = qmlIt.fileInfo().absolutePath() + '/' + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 27f3298125b..8d02354a448 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -631,7 +631,15 @@ void AbstractView::enableWidget() void AbstractView::contextHelp(const Core::IContext::HelpCallback &callback) const { #ifndef QMLDESIGNER_TEST + + const QString id = const_cast(this)->widgetInfo().uniqueId; + + QString nodeId; + if (!selectedModelNodes().isEmpty()) + nodeId = selectedModelNodes().first().simplifiedTypeName(); + QmlDesignerPlugin::instance()->emitUsageStatisticsHelpRequested(id + " " + nodeId); QmlDesignerPlugin::instance()->viewManager().qmlJSEditorContextHelp(callback); + #else callback(QString()); #endif diff --git a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp index bddbe63b33c..70bb2719383 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlstate.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlstate.cpp @@ -157,7 +157,13 @@ void QmlModelState::addChangeSetIfNotExists(const ModelNode &node) if (!hasPropertyChanges(node)) { ModelNode newChangeSet; - newChangeSet = modelNode().view()->createModelNode("QtQuick.PropertyChanges", view()->majorQtQuickVersion(), 0); + const QByteArray typeName = "QtQuick.PropertyChanges"; + NodeMetaInfo metaInfo = modelNode().model()->metaInfo(typeName); + + int major = metaInfo.majorVersion(); + int minor = metaInfo.minorVersion(); + + newChangeSet = modelNode().view()->createModelNode(typeName, major, minor); modelNode().nodeListProperty("changes").reparentHere(newChangeSet); @@ -287,9 +293,16 @@ QmlModelStateGroup QmlModelState::stateGroup() const ModelNode QmlModelState::createQmlState(AbstractView *view, const PropertyListType &propertyList) { + QTC_ASSERT(view, return {}); QTC_CHECK(view->majorQtQuickVersion() < 3); - return view->createModelNode("QtQuick.State", 2, 0, propertyList); + const QByteArray typeName = "QtQuick.State"; + NodeMetaInfo metaInfo = view->model()->metaInfo(typeName); + + int major = metaInfo.majorVersion(); + int minor = metaInfo.minorVersion(); + + return view->createModelNode(typeName, major, minor, propertyList); } void QmlModelState::setAsDefault() diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 051c449e21a..a988fe26a30 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -88,7 +88,7 @@ RewriterView::RewriterView(DifferenceHandling differenceHandling, QObject *paren m_textToModelMerger(new Internal::TextToModelMerger(this)) { m_amendTimer.setSingleShot(true); - m_amendTimer.setInterval(400); + m_amendTimer.setInterval(800); connect(&m_amendTimer, &QTimer::timeout, this, &RewriterView::amendQmlText); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); @@ -861,11 +861,17 @@ ModelNode RewriterView::nodeAtTextCursorPositionHelper(const ModelNode &root, in ModelNode lastNode = root; + int i = 0; for (const myPair &pair : data) { ModelNode node = pair.first; + i++; + if (i >= data.size()) { + lastNode = node; + break; + } - const int nodeTextLength = nodeLength(node); const int nodeTextOffset = nodeOffset(node); + const int nodeTextLength = m_textModifier->text().indexOf("}", nodeTextOffset) - nodeTextOffset - 1; if (isInNodeDefinition(nodeTextOffset, nodeTextLength, cursorPosition)) lastNode = node; @@ -1035,12 +1041,9 @@ void RewriterView::moveToComponent(const ModelNode &modelNode) { int offset = nodeOffset(modelNode); - bool instant = m_instantQmlTextUpdate; - m_instantQmlTextUpdate = true; textModifier()->moveToComponent(offset); - m_instantQmlTextUpdate = instant; } QStringList RewriterView::autoComplete(const QString &text, int pos, bool explicitComplete) diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index 127925df1b3..a2565d0c415 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,7 @@ public: Edit3DView edit3DView; FormEditorView formEditorView; TextEditorView textEditorView; + AssetsLibraryView assetsLibraryView; ItemLibraryView itemLibraryView; NavigatorView navigatorView; PropertyEditorView propertyEditorView; @@ -177,6 +179,7 @@ QList ViewManager::standardViews() const QList list = {&d->edit3DView, &d->formEditorView, &d->textEditorView, + &d->assetsLibraryView, &d->itemLibraryView, &d->navigatorView, &d->propertyEditorView, @@ -210,11 +213,6 @@ void ViewManager::detachViewsExceptRewriterAndComponetView() currentModel()->setNodeInstanceView(nullptr); } -void ViewManager::attachItemLibraryView() -{ - currentModel()->attachView(&d->itemLibraryView); -} - void ViewManager::attachAdditionalViews() { for (auto &view : d->additionalViews) @@ -292,11 +290,6 @@ void ViewManager::attachViewsExceptRewriterAndComponetView() switchStateEditorViewToSavedState(); } -void ViewManager::setItemLibraryViewResourcePath(const QString &resourcePath) -{ - d->itemLibraryView.setResourcePath(resourcePath); -} - void ViewManager::setComponentNode(const ModelNode &componentNode) { d->componentView.setComponentNode(componentNode); @@ -319,6 +312,7 @@ QList ViewManager::widgetInfos() const widgetInfoList.append(d->edit3DView.widgetInfo()); widgetInfoList.append(d->formEditorView.widgetInfo()); widgetInfoList.append(d->textEditorView.widgetInfo()); + widgetInfoList.append(d->assetsLibraryView.widgetInfo()); widgetInfoList.append(d->itemLibraryView.widgetInfo()); widgetInfoList.append(d->navigatorView.widgetInfo()); widgetInfoList.append(d->propertyEditorView.widgetInfo()); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 8ecaaa6edd9..aad91e06b48 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -74,7 +74,6 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::IGNORE_DEVICE_PIXEL_RATIO, false); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS, true); restoreValue(settings, DesignerSettingsKey::NAVIGATOR_REVERSE_ITEM_ORDER, false); - restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false); restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW, true); restoreValue(settings, DesignerSettingsKey::COLOR_PALETTE_RECENT, QStringList()); restoreValue(settings, DesignerSettingsKey::COLOR_PALETTE_FAVORITE, QStringList()); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index bb25e2e04c9..2fbc09f248c 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -64,7 +64,6 @@ const char NAVIGATOR_SHOW_ONLY_VISIBLE_ITEMS[] = "NavigatorShowOnlyVisibleItems" const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder"; const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */ const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ -const char STANDALONE_MODE[] = "StandAloneMode"; const char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; const char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent"; diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 3830c9e8da8..1bfdbb8ddbf 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -97,6 +97,7 @@ const char EVENT_PROPERTY_ADDED[] = "Property Added"; const char EVENT_ANNOTATION_ADDED[] = "Annotation Added"; const char EVENT_RESOURCE_IMPORTED[] = "Resource Imported "; const char EVENT_ACTION_EXECUTED[] = "Action Executed "; +const char EVENT_HELP_REQUESTED[] = "Help Requested "; const char EVENT_IMPORT_ADDED[] = "Import Added "; const char EVENT_BINDINGEDITOR_OPENED[] = "Binding Editor Opened"; const char EVENT_RICHTEXT_OPENED[] = "Richtext Editor Opened"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 35f21ced65a..2114a56d3d7 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -53,6 +53,8 @@ #include +#include + #include #include #include @@ -224,7 +226,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage)) return false; d = new QmlDesignerPluginPrivate; - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (QmlProjectManager::QmlProject::isQtDesignStudio()) GenerateResource::generateMenuEntry(); GenerateCmake::generateMenuEntry(); @@ -308,7 +310,7 @@ bool QmlDesignerPlugin::delayedInitialize() d->viewManager.registerFormEditorTool(std::make_unique()); d->viewManager.registerFormEditorTool(std::make_unique()); - if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) + if (QmlProjectManager::QmlProject::isQtDesignStudio()) emitUsageStatistics("StandaloneMode"); return true; @@ -615,6 +617,11 @@ void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifi emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier); } +void QmlDesignerPlugin::emitUsageStatisticsHelpRequested(const QString &identifier) +{ + emitUsageStatistics(Constants::EVENT_HELP_REQUESTED + identifier); +} + AsynchronousImageCache &QmlDesignerPlugin::imageCache() { return m_instance->d->viewManager.imageCache(); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h index a773368c4d8..22800aa0454 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.h +++ b/src/plugins/qmldesigner/qmldesignerplugin.h @@ -87,6 +87,7 @@ public: static void emitUsageStatistics(const QString &identifier); static void emitUsageStatisticsContextAction(const QString &identifier); + static void emitUsageStatisticsHelpRequested(const QString &identifier); static void emitUsageStatisticsTime(const QString &identifier, int elapsed); static AsynchronousImageCache &imageCache(); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index e8bd9e68a04..a3f5649680c 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -45,6 +45,7 @@ Project { "../../../share/qtcreator/qml/qmlpuppet/types", "components", "components/annotationeditor", + "components/assetslibrary", "components/componentcore", "components/curveeditor", "components/connectioneditor", @@ -449,6 +450,21 @@ Project { Group { prefix: "components/" files: [ + "assetslibrary/assetslibrary.qrc", + "assetslibrary/assetslibraryview.cpp", + "assetslibrary/assetslibraryview.h", + "assetslibrary/assetslibrarywidget.cpp", + "assetslibrary/assetslibrarywidget.h", + "assetslibrary/assetslibrarymodel.cpp", + "assetslibrary/assetslibrarymodel.h", + "assetslibrary/assetslibraryiconprovider.cpp", + "assetslibrary/assetslibraryiconprovider.h", + "assetslibrary/assetslibrarydir.cpp", + "assetslibrary/assetslibrarydir.h", + "assetslibrary/assetslibrarydirsmodel.cpp", + "assetslibrary/assetslibrarydirsmodel.h", + "assetslibrary/assetslibraryfilesmodel.cpp", + "assetslibrary/assetslibraryfilesmodel.h", "componentcore/addimagesdialog.cpp", "componentcore/addimagesdialog.h", "componentcore/abstractaction.cpp", @@ -472,7 +488,7 @@ Project { "componentcore/formatoperation.h", "componentcore/layoutingridlayout.cpp", "componentcore/layoutingridlayout.h", - "componentcore/theme.cpp", + "componentcore/theme.cpp", "componentcore/theme.h", "componentcore/modelnodecontextmenu.cpp", "componentcore/modelnodecontextmenu.h", @@ -639,16 +655,6 @@ Project { "itemlibrary/itemlibraryassetimportdialog.ui", "itemlibrary/itemlibraryassetimporter.cpp", "itemlibrary/itemlibraryassetimporter.h", - "itemlibrary/itemlibraryassetsdir.cpp", - "itemlibrary/itemlibraryassetsdir.h", - "itemlibrary/itemlibraryassetsdirsmodel.cpp", - "itemlibrary/itemlibraryassetsdirsmodel.h", - "itemlibrary/itemlibraryassetsfilesmodel.cpp", - "itemlibrary/itemlibraryassetsfilesmodel.h", - "itemlibrary/itemlibraryassetsiconprovider.cpp", - "itemlibrary/itemlibraryassetsiconprovider.h", - "itemlibrary/itemlibraryassetsmodel.cpp", - "itemlibrary/itemlibraryassetsmodel.h", "itemlibrary/itemlibrarycategoriesmodel.cpp", "itemlibrary/itemlibrarycategoriesmodel.h", "itemlibrary/itemlibrarycategory.cpp", diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 30e06946d85..23e0a948067 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -37,6 +37,8 @@ #include #include +#include + #include #include @@ -252,7 +254,7 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.askBeforeDeletingAssetCheckBox->setChecked(settings.value( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool()); - const auto standaloneMode = settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool(); + const bool standaloneMode = QmlProjectManager::QmlProject::isQtDesignStudio(); #ifdef QT_DEBUG const auto showDebugSettings = true; #else diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo index 5468269e83c..aca27866ac4 100644 --- a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo +++ b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo @@ -1,18 +1,4 @@ MetaInfo { - Type { - name: "QtStudio3D.Studio3D" - icon: ":/qtquickplugin/images/item-icon16.png" - - ItemLibraryEntry { - name: "Studio 3D" - category: "Qt 3D Studio" - libraryIcon: ":/qtquickplugin/images/item-icon.png" - version: "2.0" - requiredImport: "QtStudio3D" - - QmlSource { source: ":/studioplugin/data/qt3ditem.qml" } - } - } Imports { blacklistImports: [ diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.cpp b/src/plugins/qmljstools/qmljsfunctionfilter.cpp index 60b0cedc8c7..6525cff633a 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.cpp +++ b/src/plugins/qmljstools/qmljsfunctionfilter.cpp @@ -95,7 +95,7 @@ QList FunctionFilter::matchesFor( return std::accumulate(std::begin(entries), std::end(entries), QList()); } -void FunctionFilter::accept(Core::LocatorFilterEntry selection, +void FunctionFilter::accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const { Q_UNUSED(newText) diff --git a/src/plugins/qmljstools/qmljsfunctionfilter.h b/src/plugins/qmljstools/qmljsfunctionfilter.h index ee96834a5c1..d0997f54b96 100644 --- a/src/plugins/qmljstools/qmljsfunctionfilter.h +++ b/src/plugins/qmljstools/qmljsfunctionfilter.h @@ -42,7 +42,7 @@ public: QList matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/qmlprofiler/quick3dmodel.cpp b/src/plugins/qmlprofiler/quick3dmodel.cpp index fd2b5959dfe..ac8f42d5338 100644 --- a/src/plugins/qmlprofiler/quick3dmodel.cpp +++ b/src/plugins/qmlprofiler/quick3dmodel.cpp @@ -38,11 +38,6 @@ Quick3DModel::Quick3DModel(QmlProfilerModelManager *manager, { } -int Quick3DModel::typeId(int index) const -{ - return m_data[index].typeId; -} - QRgb Quick3DModel::color(int index) const { return colorBySelectionId(index); @@ -58,6 +53,15 @@ static const char *messageTypes[] = { QT_TRANSLATE_NOOP("Quick3DModel", "Generate Shader"), QT_TRANSLATE_NOOP("Quick3DModel", "Load Shader"), QT_TRANSLATE_NOOP("Quick3DModel", "Particle Update"), + + QT_TRANSLATE_NOOP("Quick3DModel", "Mesh Memory consumption"), + QT_TRANSLATE_NOOP("Quick3DModel", "Texture Memory consumption"), +}; + +static const char *unloadMessageTypes[] = { + QT_TRANSLATE_NOOP("Quick3DModel", "Mesh Unload"), + QT_TRANSLATE_NOOP("Quick3DModel", "Custom Mesh Unload"), + QT_TRANSLATE_NOOP("Quick3DModel", "Texture Unload"), }; QString Quick3DModel::messageType(uint i) @@ -66,12 +70,26 @@ QString Quick3DModel::messageType(uint i) tr("Unknown Message %1").arg(i); } +QString Quick3DModel::unloadMessageType(uint i) +{ + switch (i) { + case MeshLoad: + return tr(unloadMessageTypes[0]); + case CustomMeshLoad: + return tr(unloadMessageTypes[1]); + case TextureLoad: + return tr(unloadMessageTypes[2]); + } + return tr("Unknown Unload Message %1").arg(i); +} + QVariantList Quick3DModel::labels() const { QVariantList result; for (int i = 0; i <= m_maximumMsgType; ++i) { QVariantMap element; - element.insert(QLatin1String("displayName"), i < ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); + element.insert(QLatin1String("displayName"), + i != ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); element.insert(QLatin1String("description"), messageType(i)); element.insert(QLatin1String("id"), i); result << element; @@ -79,17 +97,49 @@ QVariantList Quick3DModel::labels() const return result; } +float Quick3DModel::relativeHeight(int index) const +{ + auto detailType = m_data[index].additionalType; + if (detailType == TextureMemoryConsumption) + return qMin(1.0f, (float)m_data[index].data / (float)m_maxTextureSize); + if (detailType == MeshMemoryConsumption) + return qMin(1.0f, (float)m_data[index].data / (float)m_maxMeshSize); + return 1.0f; +} + +qint64 Quick3DModel::rowMaxValue(int rowNumber) const +{ + int index = rowNumber - 1; + if (index == TextureMemoryConsumption) + return m_maxTextureSize; + if (index == MeshMemoryConsumption) + return m_maxMeshSize; + return 0; +} + QVariantMap Quick3DModel::details(int index) const { - const QmlProfilerModelManager *manager = modelManager(); - const QmlEventType &type = manager->eventType(m_data[index].typeId); - + auto detailType = m_data[index].additionalType; + bool unload = m_data[index].unload; QVariantMap result; - result.insert(QLatin1String("displayName"), type.detailType() < ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); - result.insert(tr("Description"), messageType(type.detailType())); - result.insert(tr("Duration"), Timeline::formatTime(duration(index))); - if (type.detailType() == ParticleUpdate) + result.insert(QLatin1String("displayName"), + detailType != ParticleUpdate ? tr("Render Thread") : tr("GUI Thread")); + result.insert(tr("Description"), + !unload ? messageType(detailType) : unloadMessageType(detailType)); + if (detailType < MeshMemoryConsumption) + result.insert(tr("Duration"), Timeline::formatTime(duration(index))); + if (detailType == ParticleUpdate) result.insert(tr("Count"), m_data[index].data); + if (detailType == RenderFrame) { + quint32 calls = m_data[index].data & 0xffffffff; + quint32 passes = m_data[index].data >> 32; + result.insert(tr("Draw Calls"), calls); + result.insert(tr("Render Passes"), passes); + } + if ((detailType >= MeshLoad && detailType <= TextureLoad) + || (detailType >= MeshMemoryConsumption && detailType <= TextureMemoryConsumption)) { + result.insert(tr("Total Memory Usage"), m_data[index].data); + } return result; } @@ -106,23 +156,80 @@ int Quick3DModel::collapsedRow(int index) const void Quick3DModel::loadEvent(const QmlEvent &event, const QmlEventType &type) { + auto detailType = type.detailType(); qint64 eventDuration = event.number(0); - qint64 startTime = event.timestamp() - eventDuration; - if (type.detailType() == MessageType::ParticleUpdate) { - quint64 particleCount = event.number(1); - m_data.insert(insert(startTime, eventDuration, type.detailType()), - Item(event.typeIndex(), particleCount)); - } else { - m_data.insert(insert(startTime, eventDuration, type.detailType()), - Item(event.typeIndex(), 0)); - } + qint64 eventTime = event.timestamp() - eventDuration; + QVector numbers = event.numbers>(); + quint64 data = numbers.size() > 1 ? event.number(1) : 0; - if (type.detailType() > m_maximumMsgType) - m_maximumMsgType = type.detailType(); + int typeCount = detailType; + if (detailType == MeshLoad || detailType == CustomMeshLoad) { + bool updatePrevValues = true; + if (m_prevMeshStartTime != -1) { + bool unload = m_prevMeshData > data; + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data, unload)); + if (m_prevMeshData != data) { + m_data.insert(insert(m_prevMeshStartTime, + eventTime - m_prevMeshStartTime, MeshMemoryConsumption), + Item(MeshMemoryConsumption, m_prevMeshData)); + } else { + updatePrevValues = false; + } + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + m_maxMeshSize = qMax(m_maxMeshSize, data); + if (updatePrevValues) { + m_prevMeshStartTime = eventTime; + m_prevMeshData = data; + } + typeCount = MeshMemoryConsumption; + } else if (detailType == TextureLoad) { + bool updatePrevValues = true; + if (m_prevTexStartTime != -1) { + bool unload = m_prevTexData > data; + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data, unload)); + if (m_prevTexData != data) { + m_data.insert(insert(m_prevTexStartTime, + eventTime - m_prevTexStartTime, TextureMemoryConsumption), + Item(TextureMemoryConsumption, m_prevTexData)); + } else { + updatePrevValues = false; + } + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + m_maxTextureSize = qMax(m_maxTextureSize, data); + if (updatePrevValues) { + m_prevTexData = data; + m_prevTexStartTime = eventTime; + } + typeCount = TextureMemoryConsumption; + } else { + m_data.insert(insert(eventTime, eventDuration, detailType), + Item(detailType, data)); + } + if (typeCount > m_maximumMsgType) + m_maximumMsgType = typeCount; } void Quick3DModel::finalize() { + if (m_prevMeshStartTime != -1) { + m_data.insert(insert(m_prevMeshStartTime, modelManager()->traceEnd() - m_prevMeshStartTime, + MeshMemoryConsumption), + Item(MeshMemoryConsumption, m_prevMeshData)); + } + if (m_prevTexStartTime != -1) { + m_data.insert(insert(m_prevTexStartTime, modelManager()->traceEnd() - m_prevTexStartTime, + TextureMemoryConsumption), + Item(TextureMemoryConsumption, m_prevTexData)); + } + computeNesting(); setCollapsedRowCount(Constants::QML_MIN_LEVEL + 1); setExpandedRowCount(m_maximumMsgType + 2); QmlProfilerTimelineModel::finalize(); @@ -132,6 +239,10 @@ void Quick3DModel::clear() { m_data.clear(); m_maximumMsgType = -1; + m_prevTexStartTime = -1; + m_prevMeshStartTime = -1; + m_maxMeshSize = 0; + m_maxTextureSize = 0; QmlProfilerTimelineModel::clear(); } diff --git a/src/plugins/qmlprofiler/quick3dmodel.h b/src/plugins/qmlprofiler/quick3dmodel.h index 50bcebcb732..c82a2056ae3 100644 --- a/src/plugins/qmlprofiler/quick3dmodel.h +++ b/src/plugins/qmlprofiler/quick3dmodel.h @@ -36,10 +36,11 @@ class Quick3DModel : public QmlProfilerTimelineModel public: struct Item { - Item(int typeId, int data) : - typeId(typeId), data(data) {} - int typeId; - int data; + Item(int additionalType, quint64 data, bool unload = false) : + additionalType(additionalType), data(data), unload(unload) {} + int additionalType = 0; + quint64 data = 0; + bool unload = false; }; enum MessageType @@ -53,16 +54,21 @@ public: GenerateShader, LoadShader, ParticleUpdate, + + // additional types + MeshMemoryConsumption, + TextureMemoryConsumption }; Quick3DModel(QmlProfilerModelManager *manager, Timeline::TimelineModelAggregator *parent); - int typeId(int index) const override; QRgb color(int index) const override; QVariantList labels() const override; QVariantMap details(int index) const override; int expandedRow(int index) const override; int collapsedRow(int index) const override; + qint64 rowMaxValue(int rowNumber) const override; + float relativeHeight(int index) const override; void loadEvent(const QmlEvent &event, const QmlEventType &type) override; void finalize() override; void clear() override; @@ -70,8 +76,15 @@ public: private: static QString messageType(uint i); + static QString unloadMessageType(uint i); - int m_maximumMsgType; + int m_maximumMsgType = 0; + qint64 m_prevTexStartTime = -1; + qint64 m_prevMeshStartTime = -1; + quint64 m_prevMeshData = 0; + quint64 m_prevTexData = 0; + quint64 m_maxMeshSize = 0; + quint64 m_maxTextureSize = 0; QVector m_data; }; diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp index 7695bbd39d7..7b772023986 100644 --- a/src/plugins/texteditor/linenumberfilter.cpp +++ b/src/plugins/texteditor/linenumberfilter.cpp @@ -90,7 +90,7 @@ QList LineNumberFilter::matchesFor(QFutureInterface matchesFor(QFutureInterface &future, const QString &entry) override; - void accept(Core::LocatorFilterEntry selection, + void accept(const Core::LocatorFilterEntry &selection, QString *newText, int *selectionStart, int *selectionLength) const override; private: diff --git a/src/plugins/texteditor/refactoroverlay.cpp b/src/plugins/texteditor/refactoroverlay.cpp index 2906ef045cc..5c1c56ad7e6 100644 --- a/src/plugins/texteditor/refactoroverlay.cpp +++ b/src/plugins/texteditor/refactoroverlay.cpp @@ -87,7 +87,10 @@ void RefactorOverlay::paintMarker(const RefactorMarker& marker, QPainter *painte const QSize proposedIconSize = QSize(m_editor->fontMetrics().horizontalAdvance(QLatin1Char(' ')) + 3, cursorRect.height()) * devicePixelRatio; - const QSize actualIconSize = icon.actualSize(proposedIconSize) / devicePixelRatio; + QSize actualIconSize = icon.actualSize(proposedIconSize); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + actualIconSize /= devicePixelRatio; +#endif // Qt < 6.0 const int y = cursorRect.top() + ((cursorRect.height() - actualIconSize.height()) / 2); const int x = cursorRect.right(); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 4376cc17398..696e4caf0a2 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -532,6 +532,10 @@ void TextDocument::setIfdefedOutBlocks(const QList &blocks) if (needUpdate) documentLayout->requestUpdate(); + +#ifdef WITH_TESTS + emit ifdefedOutBlocksChanged(blocks); +#endif } const ExtraEncodingSettings &TextDocument::extraEncodingSettings() const diff --git a/src/plugins/texteditor/textdocument.h b/src/plugins/texteditor/textdocument.h index 71a9a120a6c..0385bb2463f 100644 --- a/src/plugins/texteditor/textdocument.h +++ b/src/plugins/texteditor/textdocument.h @@ -172,6 +172,10 @@ signals: void fontSettingsChanged(); void markRemoved(TextMark *mark); +#ifdef WITH_TESTS + void ifdefedOutBlocksChanged(const QList &blocks); +#endif + protected: virtual void applyFontSettings(); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 11caca4d573..fdf244cd9b6 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -5897,7 +5897,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey() QTC_ASSERT(!q->multiTextCursor().hasSelection(), return); MultiTextCursor cursor = m_cursors; cursor.beginEditBlock(); - for (QTextCursor c : cursor) { + for (QTextCursor &c : cursor) { const int pos = c.position(); if (!pos) continue; diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp index 60d929e50a0..dc6ac9f708b 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.cpp +++ b/src/plugins/vcsbase/vcsoutputformatter.cpp @@ -28,6 +28,8 @@ #include +#include +#include #include #include #include @@ -88,6 +90,8 @@ void VcsOutputLineParser::fillLinkContextMenu( tr("&Open \"%1\"").arg(href), [href] { QDesktopServices::openUrl(QUrl(href)); }); menu->setDefaultAction(action); + menu->addAction(tr("&Copy to clipboard: \"%1\"").arg(href), + [href] { QApplication::clipboard()->setText(href); }); return; } if (Core::IVersionControl *vcs = Core::VcsManager::findVersionControlForDirectory(workingDirectory)) diff --git a/src/tools/screenshotcropper/screenshotcropperwindow.h b/src/tools/screenshotcropper/screenshotcropperwindow.h index 19f9a9fcf67..1ba13b685ca 100644 --- a/src/tools/screenshotcropper/screenshotcropperwindow.h +++ b/src/tools/screenshotcropper/screenshotcropperwindow.h @@ -29,7 +29,9 @@ #include #include +QT_BEGIN_NAMESPACE namespace Ui { class ScreenShotCropperWindow; } +QT_END_NAMESPACE class ScreenShotCropperWindow : public QMainWindow { diff --git a/src/tools/sdktool/addabiflavor.cpp b/src/tools/sdktool/addabiflavor.cpp index 01faa7b4183..c7fde38a62a 100644 --- a/src/tools/sdktool/addabiflavor.cpp +++ b/src/tools/sdktool/addabiflavor.cpp @@ -97,7 +97,7 @@ int AddAbiFlavor::execute() const if (map.isEmpty()) map = initializeAbiFlavors(); - QVariantMap result = addAbiFlavor(map, m_oses, m_flavor); + QVariantMap result = addAbiFlavor(map); if (result.isEmpty() || result == map) return 2; @@ -113,7 +113,7 @@ bool AddAbiFlavor::test() const || !map.contains(QLatin1String(VERSION))) return false; - map = addAbiFlavor(map, {"linux", "windows"}, "foo"); + map = AddAbiFlavorData{{"linux", "windows"}, "foo"}.addAbiFlavor(map); if (map.count() != 2 || !map.contains(QLatin1String(VERSION)) @@ -126,7 +126,7 @@ bool AddAbiFlavor::test() const return false; // Ignore known flavors: - const QVariantMap result = addAbiFlavor(map, {"linux"}, "foo"); + const QVariantMap result = AddAbiFlavorData({{"linux"}, "foo"}).addAbiFlavor(map);; if (map != result) return false; @@ -135,37 +135,35 @@ bool AddAbiFlavor::test() const } #endif -QVariantMap AddAbiFlavor::addAbiFlavor(const QVariantMap &map, - const QStringList &oses, - const QString &flavor) +QVariantMap AddAbiFlavorData::addAbiFlavor(const QVariantMap &map) const { // Sanity check: Is flavor already set in abi file? - if (exists(map, flavor)) { - std::cerr << "Error: flavor " << qPrintable(flavor) << " already defined as extra ABI flavor." << std::endl; + if (exists(map, m_flavor)) { + std::cerr << "Error: flavor " << qPrintable(m_flavor) << " already defined as extra ABI flavor." << std::endl; return map; } QVariantMap result = map; QVariantMap flavorMap = map.value(QLatin1String(FLAVORS)).toMap(); - flavorMap.insert(flavor, oses); + flavorMap.insert(m_flavor, m_oses); result.insert(QLatin1String(FLAVORS), flavorMap); return result; } -QVariantMap AddAbiFlavor::initializeAbiFlavors() +QVariantMap AddAbiFlavorData::initializeAbiFlavors() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); return map; } -bool AddAbiFlavor::exists(const QString &flavor) +bool AddAbiFlavorData::exists(const QString &flavor) { - QVariantMap map = load(QLatin1String(ABI_FILE_ID)); + QVariantMap map = Operation::load(QLatin1String(ABI_FILE_ID)); return exists(map, flavor); } -bool AddAbiFlavor::exists(const QVariantMap &map, const QString &flavor) +bool AddAbiFlavorData::exists(const QVariantMap &map, const QString &flavor) { const QVariantMap flavorMap = map.value(QLatin1String(FLAVORS)).toMap(); return flavorMap.contains(flavor); diff --git a/src/tools/sdktool/addabiflavor.h b/src/tools/sdktool/addabiflavor.h index 61c817b8797..fabd9d001a9 100644 --- a/src/tools/sdktool/addabiflavor.h +++ b/src/tools/sdktool/addabiflavor.h @@ -27,32 +27,32 @@ #include "operation.h" -#include - -class AddAbiFlavor : public Operation +class AddAbiFlavorData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addAbiFlavor(const QVariantMap &map, - const QStringList &oses, const QString &flavor); + QVariantMap addAbiFlavor(const QVariantMap &map) const; static QVariantMap initializeAbiFlavors(); static bool exists(const QString &flavor); static bool exists(const QVariantMap &map, const QString &flavor); -private: QStringList m_oses; QString m_flavor; }; + +class AddAbiFlavor : public Operation, public AddAbiFlavorData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addcmakeoperation.cpp b/src/tools/sdktool/addcmakeoperation.cpp index a5c087e8466..9bbec46ac68 100644 --- a/src/tools/sdktool/addcmakeoperation.cpp +++ b/src/tools/sdktool/addcmakeoperation.cpp @@ -122,7 +122,7 @@ int AddCMakeOperation::execute() const if (map.isEmpty()) map = initializeCMake(); - QVariantMap result = addCMake(map, m_id, m_displayName, m_path, m_extra); + QVariantMap result = addCMake(map); if (result.isEmpty() || map == result) return 2; @@ -135,8 +135,7 @@ bool AddCMakeOperation::test() const QVariantMap map = initializeCMake(); // Add toolchain: - map = addCMake(map, "testId", "name", "/tmp/test", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddCMakeData{"testId", "name", "/tmp/test", {{"ExtraKey", QVariant("ExtraValue")}}}.addCMake(map); if (map.value(COUNT).toInt() != 1 || !map.contains(QString::fromLatin1(PREFIX) + '0')) return false; @@ -150,14 +149,14 @@ bool AddCMakeOperation::test() const return false; // Ignore same Id: - QVariantMap unchanged = addCMake(map, "testId", "name2", "/tmp/test2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue2"))); + QVariantMap unchanged = AddCMakeData{"testId", "name2", "/tmp/test2", {{"ExtraKey", QVariant("ExtraValue2")}}} + .addCMake(map); if (!unchanged.isEmpty()) return false; // add 2nd cmake - map = addCMake(map, "{some-cm-id}", "name", "/tmp/test", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddCMakeData{"{some-cm-id}", "name", "/tmp/test", {{"ExtraKey", QVariant("ExtraValue")}}} + .addCMake(map); if (map.value(COUNT).toInt() != 2 || !map.contains(QString::fromLatin1(PREFIX) + '0') || !map.contains(QString::fromLatin1(PREFIX) + '1')) @@ -183,13 +182,11 @@ bool AddCMakeOperation::test() const } #endif -QVariantMap AddCMakeOperation::addCMake(const QVariantMap &map, const QString &id, - const QString &displayName, const QString &path, - const KeyValuePairList &extra) +QVariantMap AddCMakeData::addCMake(const QVariantMap &map) const { // Sanity check: Does the Id already exist? - if (exists(map, id)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined for tool chains." << std::endl; + if (exists(map, m_id)) { + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined for tool chains." << std::endl; return QVariantMap(); } @@ -206,20 +203,20 @@ QVariantMap AddCMakeOperation::addCMake(const QVariantMap &map, const QString &i const QString cm = QString::fromLatin1(PREFIX) + QString::number(count); KeyValuePairList data; - data << KeyValuePair({cm, ID_KEY}, QVariant(id)); - data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(displayName)); + data << KeyValuePair({cm, ID_KEY}, QVariant(m_id)); + data << KeyValuePair({cm, DISPLAYNAME_KEY}, QVariant(m_displayName)); data << KeyValuePair({cm, AUTODETECTED_KEY}, QVariant(true)); - data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(path).toVariant()); + data << KeyValuePair({cm, PATH_KEY}, Utils::FilePath::fromUserInput(m_path).toVariant()); KeyValuePairList extraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) extraList << KeyValuePair(QStringList({cm}) << pair.key, pair.value); data.append(extraList); data << KeyValuePair(COUNT, QVariant(count + 1)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } -QVariantMap AddCMakeOperation::initializeCMake() +QVariantMap AddCMakeData::initializeCMake() { QVariantMap map; map.insert(COUNT, 0); @@ -227,7 +224,7 @@ QVariantMap AddCMakeOperation::initializeCMake() return map; } -bool AddCMakeOperation::exists(const QVariantMap &map, const QString &id) +bool AddCMakeData::exists(const QVariantMap &map, const QString &id) { QStringList valueKeys = FindValueOperation::findValue(map, id); // support old settings using QByteArray for id's @@ -241,7 +238,7 @@ bool AddCMakeOperation::exists(const QVariantMap &map, const QString &id) return false; } -bool AddCMakeOperation::exists(const QString &id) +bool AddCMakeData::exists(const QString &id) { QVariantMap map = Operation::load("cmaketools"); return exists(map, id); diff --git a/src/tools/sdktool/addcmakeoperation.h b/src/tools/sdktool/addcmakeoperation.h index 51212154526..13045290178 100644 --- a/src/tools/sdktool/addcmakeoperation.h +++ b/src/tools/sdktool/addcmakeoperation.h @@ -27,34 +27,34 @@ #include "operation.h" -#include - -class AddCMakeOperation : public Operation +class AddCMakeData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addCMake(const QVariantMap &map, const QString &id, - const QString &displayName, const QString &path, - const KeyValuePairList &extra); + QVariantMap addCMake(const QVariantMap &map) const; static QVariantMap initializeCMake(); + static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; QString m_displayName; QString m_path; KeyValuePairList m_extra; }; + +class AddCMakeOperation : public Operation, public AddCMakeData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/adddebuggeroperation.cpp b/src/tools/sdktool/adddebuggeroperation.cpp index eb7b9c66004..e3797525786 100644 --- a/src/tools/sdktool/adddebuggeroperation.cpp +++ b/src/tools/sdktool/adddebuggeroperation.cpp @@ -144,8 +144,7 @@ int AddDebuggerOperation::execute() const if (map.isEmpty()) map = initializeDebuggers(); - QVariantMap result = addDebugger(map, m_id, m_displayName, m_engine, m_binary, m_abis, - m_extra); + QVariantMap result = addDebugger(map); if (result.isEmpty() || map == result) return 2; @@ -169,13 +168,10 @@ bool AddDebuggerOperation::test() const } #endif -QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, - const QString &id, const QString &displayName, - int engine, const QString &binary, - const QStringList &abis, const KeyValuePairList &extra) +QVariantMap AddDebuggerData::addDebugger(const QVariantMap &map) const { // Sanity check: Make sure autodetection source is not in use already: - QStringList valueKeys = FindValueOperation::findValue(map, QVariant(id)); + QStringList valueKeys = FindValueOperation::findValue(map, QVariant(m_id)); bool hasId = false; foreach (const QString &k, valueKeys) { if (k.endsWith(QString(QLatin1Char('/')) + QLatin1String(ID))) { @@ -184,7 +180,7 @@ QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, } } if (hasId) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as debugger." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as debugger." << std::endl; return QVariantMap(); } @@ -204,27 +200,27 @@ QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, // insert data: KeyValuePairList data; - data << KeyValuePair(QStringList() << debugger << QLatin1String(ID), QVariant(id)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ID), QVariant(m_id)); data << KeyValuePair(QStringList() << debugger << QLatin1String(DISPLAYNAME), - QVariant(displayName)); + QVariant(m_displayName)); data << KeyValuePair(QStringList() << debugger << QLatin1String(AUTODETECTED), QVariant(true)); - data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(abis)); - data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(engine)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ABIS), QVariant(m_abis)); + data << KeyValuePair(QStringList() << debugger << QLatin1String(ENGINE_TYPE), QVariant(m_engine)); data << KeyValuePair(QStringList() << debugger << QLatin1String(BINARY), - Utils::FilePath::fromUserInput(binary).toVariant()); + Utils::FilePath::fromUserInput(m_binary).toVariant()); data << KeyValuePair(QStringList() << QLatin1String(COUNT), QVariant(count + 1)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << debugger << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(cleaned, data); + return AddKeysData{data}.addKeys(cleaned); } -QVariantMap AddDebuggerOperation::initializeDebuggers() +QVariantMap AddDebuggerData::initializeDebuggers() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); diff --git a/src/tools/sdktool/adddebuggeroperation.h b/src/tools/sdktool/adddebuggeroperation.h index 5c7731d780a..788900ee2c6 100644 --- a/src/tools/sdktool/adddebuggeroperation.h +++ b/src/tools/sdktool/adddebuggeroperation.h @@ -27,31 +27,13 @@ #include "operation.h" -#include - -class AddDebuggerOperation : public Operation +class AddDebuggerData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addDebugger(const QVariantMap &map, - const QString &id, const QString &displayName, - int engine, const QString &binary, - const QStringList &abis, const KeyValuePairList &extra); + QVariantMap addDebugger(const QVariantMap &map) const; static QVariantMap initializeDebuggers(); -private: QString m_id; QString m_displayName; int m_engine = 0; @@ -59,3 +41,19 @@ private: QStringList m_abis; KeyValuePairList m_extra; }; + +class AddDebuggerOperation : public Operation, public AddDebuggerData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/adddeviceoperation.cpp b/src/tools/sdktool/adddeviceoperation.cpp index 91eff774cfe..4484e699225 100644 --- a/src/tools/sdktool/adddeviceoperation.cpp +++ b/src/tools/sdktool/adddeviceoperation.cpp @@ -247,10 +247,7 @@ int AddDeviceOperation::execute() const if (map.isEmpty()) map = initializeDevices(); - QVariantMap result = addDevice(map, m_id, m_displayName, m_type, m_authentication, - m_b2q_platformHardware, m_b2q_platformSoftware, m_debugServer, - m_freePortsSpec, m_host, m_keyFile, m_origin, m_osType, - m_password, m_sshPort, m_timeout, m_uname, m_version, m_extra); + QVariantMap result = addDevice(map); if (result.isEmpty() || map == result) return 2; @@ -263,13 +260,15 @@ bool AddDeviceOperation::test() const { QVariantMap map = initializeDevices(); - QVariantMap result = addDevice(map, QLatin1String("test id"), QLatin1String("test name"), - 1, 2, QLatin1String("HW"), QLatin1String("SW"), - QLatin1String("debugServer"), QLatin1String("ports"), - QLatin1String("host"), QLatin1String("keyfile"), 3, - QLatin1String("ostype"), QLatin1String("passwd"), 4, 5, - QLatin1String("uname"), 6, KeyValuePairList()); - + AddDeviceData devData = { + QLatin1String("test id"), QLatin1String("test name"), + 1, 2, QLatin1String("HW"), QLatin1String("SW"), + QLatin1String("debugServer"), QLatin1String("ports"), + QLatin1String("host"), QLatin1String("keyfile"), 3, + QLatin1String("ostype"), QLatin1String("passwd"), 4, 5, + QLatin1String("uname"), 6, KeyValuePairList() + }; + QVariantMap result = devData.addDevice(map); QVariantMap data = result.value(QLatin1String(DEVICEMANAGER_ID)).toMap(); QVariantList devList = data.value(QLatin1String(DEVICE_LIST_ID)).toList(); if (devList.count() != 1) @@ -312,30 +311,38 @@ bool AddDeviceOperation::test() const } #endif -QVariantMap AddDeviceOperation::addDevice(const QVariantMap &map, - const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra) +QVariantMap AddDeviceData::addDevice(const QVariantMap &map) const { QVariantMap result = map; - if (exists(map, id)) { - std::cerr << "Device " << qPrintable(id) << " already exists!" << std::endl; + if (exists(map, m_id)) { + std::cerr << "Device " << qPrintable(m_id) << " already exists!" << std::endl; return result; } QVariantMap dmMap = map.value(QLatin1String(DEVICEMANAGER_ID)).toMap(); QVariantList devList = dmMap.value(QLatin1String(DEVICE_LIST_ID)).toList(); - QVariantMap devMap - = AddKeysOperation::addKeys(QVariantMap(), - createDevice(id, displayName, type, auth, hwPlatform, - swPlatform, debugServer, freePorts, host, - keyFile, origin, osType, passwd, sshPort, - timeout, uname, version, extra)); + KeyValuePairList dev; + dev.append(KeyValuePair(QLatin1String(DEVICE_ID_ID), QVariant(m_id))); + dev.append(KeyValuePair(QLatin1String("Name"), QVariant(m_displayName))); + dev.append(KeyValuePair(QLatin1String("Type"), QVariant(m_type))); + dev.append(KeyValuePair(QLatin1String("Authentication"), QVariant(m_authentication))); + dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoHardware"), QVariant(m_b2q_platformHardware))); + dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoSoftware"), QVariant(m_b2q_platformSoftware))); + dev.append(KeyValuePair(QLatin1String("DebugServerKey"), QVariant(m_debugServer))); + dev.append(KeyValuePair(QLatin1String("FreePortsSpec"), QVariant(m_freePortsSpec))); + dev.append(KeyValuePair(QLatin1String("Host"), QVariant(m_host))); + dev.append(KeyValuePair(QLatin1String("KeyFile"), QVariant(m_keyFile))); + dev.append(KeyValuePair(QLatin1String("Origin"), QVariant(m_origin))); + dev.append(KeyValuePair(QLatin1String("OsType"), QVariant(m_osType))); + dev.append(KeyValuePair(QLatin1String("Password"), QVariant(m_password))); + dev.append(KeyValuePair(QLatin1String("SshPort"), QVariant(m_sshPort))); + dev.append(KeyValuePair(QLatin1String("Timeout"), QVariant(m_timeout))); + dev.append(KeyValuePair(QLatin1String("Uname"), QVariant(m_uname))); + dev.append(KeyValuePair(QLatin1String("Version"), QVariant(m_version))); + dev.append(m_extra); + + QVariantMap devMap = AddKeysData{dev}.addKeys(QVariantMap()); devList.append(devMap); @@ -346,7 +353,7 @@ QVariantMap AddDeviceOperation::addDevice(const QVariantMap &map, return result; } -QVariantMap AddDeviceOperation::initializeDevices() +QVariantMap AddDeviceData::initializeDevices() { QVariantMap dmData; dmData.insert(QLatin1String(DEFAULT_DEVICES_ID), QVariantMap()); @@ -357,13 +364,13 @@ QVariantMap AddDeviceOperation::initializeDevices() return data; } -bool AddDeviceOperation::exists(const QString &id) +bool AddDeviceData::exists(const QString &id) { - QVariantMap map = load(QLatin1String("Devices")); + QVariantMap map = Operation::load(QLatin1String("Devices")); return exists(map, id); } -bool AddDeviceOperation::exists(const QVariantMap &map, const QString &id) +bool AddDeviceData::exists(const QVariantMap &map, const QString &id) { if (id == QLatin1String(INTERNAL_DSEKTOP_DEVICE_ID)) return true; @@ -377,37 +384,3 @@ bool AddDeviceOperation::exists(const QVariantMap &map, const QString &id) } return false; } - -Operation::KeyValuePairList AddDeviceOperation::createDevice(const QString &id, const QString &displayName, - int type, int auth, const QString &hwPlatform, - const QString &swPlatform, const QString &debugServer, - const QString &freePorts, const QString &host, - const QString &keyFile, int origin, - const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, - int version, const Operation::KeyValuePairList &extra) -{ - Operation::KeyValuePairList dev; - dev.append(KeyValuePair(QLatin1String(DEVICE_ID_ID), QVariant(id))); - dev.append(KeyValuePair(QLatin1String("Name"), QVariant(displayName))); - dev.append(KeyValuePair(QLatin1String("Type"), QVariant(type))); - - dev.append(KeyValuePair(QLatin1String("Authentication"), QVariant(auth))); - dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoHardware"), QVariant(hwPlatform))); - dev.append(KeyValuePair(QLatin1String("Boot2Qt.PlatformInfoSoftware"), QVariant(swPlatform))); - dev.append(KeyValuePair(QLatin1String("DebugServerKey"), QVariant(debugServer))); - dev.append(KeyValuePair(QLatin1String("FreePortsSpec"), QVariant(freePorts))); - dev.append(KeyValuePair(QLatin1String("Host"), QVariant(host))); - dev.append(KeyValuePair(QLatin1String("KeyFile"), QVariant(keyFile))); - dev.append(KeyValuePair(QLatin1String("Origin"), QVariant(origin))); - dev.append(KeyValuePair(QLatin1String("OsType"), QVariant(osType))); - dev.append(KeyValuePair(QLatin1String("Password"), QVariant(passwd))); - dev.append(KeyValuePair(QLatin1String("SshPort"), QVariant(sshPort))); - dev.append(KeyValuePair(QLatin1String("Timeout"), QVariant(timeout))); - dev.append(KeyValuePair(QLatin1String("Uname"), QVariant(uname))); - dev.append(KeyValuePair(QLatin1String("Version"), QVariant(version))); - - dev.append(extra); - - return dev; -} diff --git a/src/tools/sdktool/adddeviceoperation.h b/src/tools/sdktool/adddeviceoperation.h index 843d78f6f6c..2e0c9cfb615 100644 --- a/src/tools/sdktool/adddeviceoperation.h +++ b/src/tools/sdktool/adddeviceoperation.h @@ -35,60 +35,48 @@ extern const char DEVICE_LIST_ID[]; extern const char DEVICE_ID_ID[]; -class AddDeviceOperation : public Operation +class AddDeviceData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addDevice(const QVariantMap &map, - const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra); + QVariantMap addDevice(const QVariantMap &map) const; static QVariantMap initializeDevices(); static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: - static KeyValuePairList createDevice(const QString &id, const QString &displayName, int type, - int auth, const QString &hwPlatform, const QString &swPlatform, - const QString &debugServer, const QString &freePorts, - const QString &host, const QString &keyFile, - int origin, const QString &osType, const QString &passwd, - int sshPort, int timeout, const QString &uname, int version, - const KeyValuePairList &extra); - + QString m_id; + QString m_displayName; + int m_type = -1; int m_authentication = -1; QString m_b2q_platformHardware; QString m_b2q_platformSoftware; QString m_debugServer; QString m_freePortsSpec; QString m_host; - QString m_id; QString m_keyFile; - QString m_displayName; int m_origin = 1; QString m_osType; QString m_password; int m_sshPort = 0; int m_timeout = 5; - int m_type = -1; QString m_uname; int m_version = 0; KeyValuePairList m_extra; }; + +class AddDeviceOperation : public Operation, public AddDeviceData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addkeysoperation.cpp b/src/tools/sdktool/addkeysoperation.cpp index 95535a7e976..cc26b536f58 100644 --- a/src/tools/sdktool/addkeysoperation.cpp +++ b/src/tools/sdktool/addkeysoperation.cpp @@ -76,7 +76,7 @@ int AddKeysOperation::execute() const QVariantMap map = load(m_file); - QVariantMap result = addKeys(map, m_data); + QVariantMap result = addKeys(map); if (result.isEmpty() || map == result) return 4; @@ -108,7 +108,7 @@ bool AddKeysOperation::test() const data.append(KeyValuePair(QLatin1String("newsub/1/2/3/qbytearray"), QString::fromLatin1("QByteArray:test array."))); data.append(KeyValuePair(QLatin1String("newsub/1/2.1/3/qbytearray"), QString::fromLatin1("QByteArray:test array."))); - QVariantMap result = addKeys(testMap, data); + QVariantMap result = AddKeysData{data}.addKeys(testMap); if (result.count() != 9) return false; @@ -194,13 +194,13 @@ bool AddKeysOperation::test() const // preexisting: data.clear(); data.append(KeyValuePair(QLatin1String("testint"), QString::fromLatin1("int:4"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; data.clear(); data.append(KeyValuePair(QLatin1String("subkeys/testbool"), QString::fromLatin1("int:24"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; @@ -208,7 +208,7 @@ bool AddKeysOperation::test() const data.clear(); data.append(KeyValuePair(QLatin1String("bool-true"), QString::fromLatin1("bool:trUe"))); data.append(KeyValuePair(QLatin1String("bool-true"), QString::fromLatin1("bool:trUe"))); - result = addKeys(testMap, data); + result = AddKeysData{data}.addKeys(testMap); if (!result.isEmpty()) return false; @@ -216,12 +216,12 @@ bool AddKeysOperation::test() const } #endif -QVariantMap AddKeysOperation::addKeys(const QVariantMap &map, const KeyValuePairList &additions) +QVariantMap AddKeysData::addKeys(const QVariantMap &map) const { // Insert data: QVariantMap result = map; - foreach (const KeyValuePair &p, additions) { + foreach (const KeyValuePair &p, m_data) { QList stack; // Set up a stack of QVariantMaps along the path we take: diff --git a/src/tools/sdktool/addkeysoperation.h b/src/tools/sdktool/addkeysoperation.h index 40483befd10..9623d715045 100644 --- a/src/tools/sdktool/addkeysoperation.h +++ b/src/tools/sdktool/addkeysoperation.h @@ -27,25 +27,29 @@ #include "operation.h" -class AddKeysOperation : public Operation +class AddKeysData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addKeys(const QVariantMap &map, const KeyValuePairList &additions); - -private: - QString m_file; + QVariantMap addKeys(const QVariantMap &map) const; QList m_data; }; + +class AddKeysOperation : public Operation, public AddKeysData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif + +private: + QString m_file; +}; diff --git a/src/tools/sdktool/addkitoperation.cpp b/src/tools/sdktool/addkitoperation.cpp index d5de0562bfa..d6b3442a701 100644 --- a/src/tools/sdktool/addkitoperation.cpp +++ b/src/tools/sdktool/addkitoperation.cpp @@ -293,12 +293,7 @@ int AddKitOperation::execute() const if (map.isEmpty()) map = initializeKits(); - QVariantMap result = addKit(map, m_id, m_displayName, m_icon, m_debuggerId, m_debuggerEngine, - m_debugger, m_deviceType, m_device, m_sysRoot, m_tcs, m_qt, - m_mkspec, m_cmakeId, m_cmakeGenerator, m_cmakeExtraGenerator, - m_cmakeGeneratorToolset, m_cmakeGeneratorPlatform, m_cmakeConfiguration, - m_env, m_extra); - + const QVariantMap result = addKit(map); if (result.isEmpty() || map == result) return 2; @@ -308,26 +303,26 @@ int AddKitOperation::execute() const #ifdef WITH_TESTS bool AddKitOperation::test() const { + AddKitData kitData; QVariantMap map = initializeKits(); - QVariantMap tcMap = AddToolChainOperation::initializeToolChains(); - tcMap = AddToolChainOperation::addToolChain(tcMap, "{tc-id}", "langId", "TC", "/usr/bin/gcc", - "x86-linux-generic-elf-32bit", - "x86-linux-generic-elf-32bit", - KeyValuePairList()); + QVariantMap tcMap = AddToolChainData::initializeToolChains(); + tcMap = AddToolChainData{"{tc-id}", "langId", "TC", "/usr/bin/gcc", + "x86-linux-generic-elf-32bit", "x86-linux-generic-elf-32bit", {}} + .addToolChain(tcMap); - QVariantMap qtMap = AddQtOperation::initializeQtVersions(); - qtMap = AddQtOperation::addQt(qtMap, "{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", - KeyValuePairList(), {}); + QVariantMap qtMap = AddQtData::initializeQtVersions(); + qtMap = AddQtData{"{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", {}, {}}.addQt(qtMap); QVariantMap devMap = AddDeviceOperation::initializeDevices(); - devMap = AddDeviceOperation::addDevice(devMap, "{dev-id}", "Dev", 0, 0, - "HWplatform", "SWplatform", - "localhost", "10000-11000", - "localhost", "", 42, - "desktop", "", 22, 10000, - "uname", 1, - KeyValuePairList()); + devMap = AddDeviceData{"{dev-id}", "Dev", 0, 0, + "HWplatform", "SWplatform", + "localhost", "10000-11000", + "localhost", "", 42, + "desktop", "", 22, 10000, + "uname", 1, + KeyValuePairList()} + .addDevice(devMap); const QStringList env = {"TEST=1", "PATH"}; @@ -341,34 +336,35 @@ bool AddKitOperation::test() const tcs.insert("Cxx", "{tcXX-id}"); // Fail if TC is not there: - QVariantMap empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), - QStringList(), - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), + QStringList(), + {{{"PE.Profile.Data/extraData", QVariant("extraValue")}}}}; + QVariantMap empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); + if (!empty.isEmpty()) return false; // Do not fail if TC is an ABI: tcs.clear(); tcs.insert("C", "x86-linux-generic-elf-64bit"); - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (empty.isEmpty()) return false; // QTCREATORBUG-11983, mach_o was not covered by the first attempt to fix this. tcs.insert("D", "x86-macos-generic-mach_o-64bit"); - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (empty.isEmpty()) return false; @@ -376,31 +372,31 @@ bool AddKitOperation::test() const tcs.insert("Cxx", "{tc-id}"); // Fail if Qt is not there: - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), tcs, "{qtXX-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{dev-id}", QString(), tcs, "{qtXX-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!empty.isEmpty()) return false; // Fail if dev is not there: - empty = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", "{devXX-id}", QString(), tcs, "{qt-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", "{devXX-id}", QString(), tcs, "{qt-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + empty = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!empty.isEmpty()) return false; // Profile 0: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Kit", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, "{qt-id}", - "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Kit", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, "{qt-id}", + "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (map.count() != 4 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 @@ -434,22 +430,23 @@ bool AddKitOperation::test() const return false; // Ignore existing ids: - QVariantMap result = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId", "Test Qt Version X", - "/tmp/icon3.png", QString(), 1, "/usr/bin/gdb-test3", "Desktop", - QString(), QString(), tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId", "Test Qt Version X", + "/tmp/icon3.png", QString(), 1, "/usr/bin/gdb-test3", "Desktop", + QString(), QString(), tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + QVariantMap result = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (!result.isEmpty()) return false; // Profile 1: Make sure name is unique: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "testId2", "Test Kit2", "/tmp/icon2.png", QString(), 1, - "/usr/bin/gdb-test2", "Desktop", "{dev-id}", "/sys/root//", tcs, - "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"testId2", "Test Kit2", "/tmp/icon2.png", QString(), 1, + "/usr/bin/gdb-test2", "Desktop", "{dev-id}", "/sys/root//", tcs, + "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {{KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); + if (map.count() != 5 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 || !map.contains(COUNT) || map.value(COUNT).toInt() != 2 @@ -489,12 +486,12 @@ bool AddKitOperation::test() const return false; // Profile 2: Test debugger id: - map = addKit(map, tcMap, qtMap, devMap, QVariantMap(), - "test with debugger Id", "Test debugger Id", - "/tmp/icon2.png", "debugger Id", 0, QString(), "Desktop", QString(), QString(), - tcs, "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), env, - KeyValuePairList({KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))})); + kitData = {"test with debugger Id", "Test debugger Id", + "/tmp/icon2.png", "debugger Id", 0, QString(), "Desktop", QString(), QString(), + tcs, "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), env, + {KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))}}; + map = kitData.addKit(map, tcMap, qtMap, devMap, {}); if (map.count() != 6 || !map.contains(VERSION) || map.value(VERSION).toInt() != 1 || !map.contains(COUNT) || map.value(COUNT).toInt() != 3 @@ -528,61 +525,35 @@ bool AddKitOperation::test() const } #endif -QVariantMap AddKitOperation::addKit(const QVariantMap &map, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, const QString &qt, - const QString &mkspec, const QString &cmakeId, - const QString &cmakeGenerator, const QString &cmakeExtraGenerator, - const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra) +QVariantMap AddKitData::addKit(const QVariantMap &map) const { - QVariantMap tcMap = load("ToolChains"); - QVariantMap qtMap = load("QtVersions"); - QVariantMap devMap = load("Devices"); - QVariantMap cmakeMap = load("cmaketools"); + QVariantMap tcMap = Operation::load("ToolChains"); + QVariantMap qtMap = Operation::load("QtVersions"); + QVariantMap devMap = Operation::load("Devices"); + QVariantMap cmakeMap = Operation::load("cmaketools"); - return addKit(map, tcMap, qtMap, devMap, cmakeMap, id, displayName, icon, debuggerId, debuggerType, - debugger, deviceType, device, sysRoot, tcs, qt, mkspec, - cmakeId, cmakeGenerator, cmakeExtraGenerator, cmakeGeneratorToolset, - cmakeGeneratorPlatform, cmakeConfiguration, - env, extra); + return AddKitData::addKit(map, tcMap, qtMap, devMap, cmakeMap); } -QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &tcMap, +QVariantMap AddKitData::addKit(const QVariantMap &map, const QVariantMap &tcMap, const QVariantMap &qtMap, const QVariantMap &devMap, - const QVariantMap &cmakeMap, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, const QString &qt, - const QString &mkspec, const QString &cmakeId, - const QString &cmakeGenerator, const QString &cmakeExtraGenerator, - const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra) + const QVariantMap &cmakeMap) const { // Sanity check: Make sure autodetection source is not in use already: - QStringList valueKeys = FindValueOperation::findValue(map, QVariant(id)); + const QStringList valueKeys = FindValueOperation::findValue(map, QVariant(m_id)); bool hasId = false; - foreach (const QString &k, valueKeys) { + for (const QString &k : valueKeys) { if (k.endsWith(QString('/') + ID)) { hasId = true; break; } } if (hasId) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as kit." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as kit." << std::endl; return QVariantMap(); } - for (auto i = tcs.constBegin(); i != tcs.constEnd(); ++i) { + for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i) { if (!i.value().isEmpty() && !AddToolChainOperation::exists(tcMap, i.value())) { const QRegularExpression abiRegExp("^[a-z0-9_]+-[a-z0-9_]+-[a-z0-9_]+-[a-z0-9_]+-(8|16|32|64|128)bit$"); if (!abiRegExp.match(i.value()).hasMatch()) { @@ -593,15 +564,15 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t } } - QString qtId = qt; + QString qtId = m_qt; if (!qtId.isEmpty() && !qtId.startsWith("SDK.")) - qtId = QString::fromLatin1("SDK.") + qt; - if (!qtId.isEmpty() && !AddQtOperation::exists(qtMap, qtId)) { + qtId = QString::fromLatin1("SDK.") + m_qt; + if (!qtId.isEmpty() && !AddQtData::exists(qtMap, qtId)) { std::cerr << "Error: Qt " << qPrintable(qtId) << " does not exist." << std::endl; return QVariantMap(); } - if (!device.isEmpty() && !AddDeviceOperation::exists(devMap, device)) { - std::cerr << "Error: Device " << qPrintable(device) << " does not exist." << std::endl; + if (!m_device.isEmpty() && !AddDeviceOperation::exists(devMap, m_device)) { + std::cerr << "Error: Device " << qPrintable(m_device) << " does not exist." << std::endl; return QVariantMap(); } @@ -609,8 +580,8 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t if (!qtId.isNull() && qtId.isEmpty()) qtId = "-1"; - if (!cmakeId.isEmpty() && !AddCMakeOperation::exists(cmakeMap, cmakeId)) { - std::cerr << "Error: CMake tool " << qPrintable(cmakeId) << " does not exist." << std::endl; + if (!m_cmakeId.isEmpty() && !AddCMakeData::exists(cmakeMap, m_cmakeId)) { + std::cerr << "Error: CMake tool " << qPrintable(m_cmakeId) << " does not exist." << std::endl; return QVariantMap(); } @@ -625,68 +596,69 @@ QVariantMap AddKitOperation::addKit(const QVariantMap &map, const QVariantMap &t QString defaultKit = GetOperation::get(map, DEFAULT).toString(); if (defaultKit.isEmpty()) - defaultKit = id; + defaultKit = m_id; // remove data: QVariantMap cleaned = RmKeysOperation::rmKeys(map, {COUNT, DEFAULT}); // insert data: - KeyValuePairList data = {KeyValuePair({kit, ID}, QVariant(id)), - KeyValuePair({kit, DISPLAYNAME}, QVariant(displayName)), - KeyValuePair({kit, ICON}, QVariant(icon)), + KeyValuePairList data = {KeyValuePair({kit, ID}, QVariant(m_id)), + KeyValuePair({kit, DISPLAYNAME}, QVariant(m_displayName)), + KeyValuePair({kit, ICON}, QVariant(m_icon)), KeyValuePair({kit, AUTODETECTED}, QVariant(true)), KeyValuePair({kit, SDK}, QVariant(true))}; - if (!debuggerId.isEmpty() || !debugger.isEmpty()) { - if (debuggerId.isEmpty()) { - data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_ENGINE}, QVariant(debuggerType)); - data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_BINARY}, QVariant(debugger)); + if (!m_debuggerId.isEmpty() || !m_debugger.isEmpty()) { + if (m_debuggerId.isEmpty()) { + data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_ENGINE}, QVariant(m_debuggerEngine)); + data << KeyValuePair({kit, DATA, DEBUGGER, DEBUGGER_BINARY}, QVariant(m_debugger)); } else { - data << KeyValuePair({kit, DATA, DEBUGGER }, QVariant(debuggerId)); + data << KeyValuePair({kit, DATA, DEBUGGER }, QVariant(m_debuggerId)); } } - if (!deviceType.isNull()) - data << KeyValuePair({kit, DATA, DEVICE_TYPE}, QVariant(deviceType)); - if (!device.isNull()) - data << KeyValuePair({kit, DATA, DEVICE_ID}, QVariant(device)); - if (!sysRoot.isNull()) - data << KeyValuePair({kit, DATA, SYSROOT}, Utils::FilePath::fromUserInput(sysRoot).toVariant()); - for (auto i = tcs.constBegin(); i != tcs.constEnd(); ++i) + + if (!m_deviceType.isNull()) + data << KeyValuePair({kit, DATA, DEVICE_TYPE}, QVariant(m_deviceType)); + if (!m_device.isNull()) + data << KeyValuePair({kit, DATA, DEVICE_ID}, QVariant(m_device)); + if (!m_sysRoot.isNull()) + data << KeyValuePair({kit, DATA, SYSROOT}, Utils::FilePath::fromUserInput(m_sysRoot).toVariant()); + for (auto i = m_tcs.constBegin(); i != m_tcs.constEnd(); ++i) data << KeyValuePair({kit, DATA, TOOLCHAIN, i.key()}, QVariant(i.value())); if (!qtId.isNull()) data << KeyValuePair({kit, DATA, QT}, QVariant(qtId)); - if (!mkspec.isNull()) - data << KeyValuePair({kit, DATA, MKSPEC}, QVariant(mkspec)); - if (!cmakeId.isNull()) - data << KeyValuePair({kit, DATA, CMAKE_ID}, QVariant(cmakeId)); - if (!cmakeGenerator.isNull()) { + if (!m_mkspec.isNull()) + data << KeyValuePair({kit, DATA, MKSPEC}, QVariant(m_mkspec)); + if (!m_cmakeId.isNull()) + data << KeyValuePair({kit, DATA, CMAKE_ID}, QVariant(m_cmakeId)); + if (!m_cmakeGenerator.isNull()) { QVariantMap generatorMap; - generatorMap.insert("Generator", cmakeGenerator); - if (!cmakeExtraGenerator.isNull()) - generatorMap.insert("ExtraGenerator", cmakeExtraGenerator); - if (!cmakeGeneratorToolset.isNull()) - generatorMap.insert("Toolset", cmakeGeneratorToolset); - if (!cmakeGeneratorPlatform.isNull()) - generatorMap.insert("Platform", cmakeGeneratorPlatform); + generatorMap.insert("Generator", m_cmakeGenerator); + if (!m_cmakeExtraGenerator.isNull()) + generatorMap.insert("ExtraGenerator", m_cmakeExtraGenerator); + if (!m_cmakeGeneratorToolset.isNull()) + generatorMap.insert("Toolset", m_cmakeGeneratorToolset); + if (!m_cmakeGeneratorPlatform.isNull()) + generatorMap.insert("Platform", m_cmakeGeneratorPlatform); data << KeyValuePair({kit, DATA, CMAKE_GENERATOR}, generatorMap); } - if (!cmakeConfiguration.isEmpty()) - data << KeyValuePair({kit, DATA, CMAKE_CONFIGURATION}, QVariant(cmakeConfiguration)); - if (!env.isEmpty()) - data << KeyValuePair({kit, DATA, ENV}, QVariant(env)); + if (!m_cmakeConfiguration.isEmpty()) + data << KeyValuePair({kit, DATA, CMAKE_CONFIGURATION}, QVariant(m_cmakeConfiguration)); + if (!m_env.isEmpty()) + data << KeyValuePair({kit, DATA, ENV}, QVariant(m_env)); data << KeyValuePair(DEFAULT, QVariant(defaultKit)); data << KeyValuePair(COUNT, QVariant(count + 1)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << kit << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(cleaned, data); + return AddKeysData{data}.addKeys(cleaned); } -QVariantMap AddKitOperation::initializeKits() +QVariantMap AddKitData::initializeKits() { QVariantMap map; map.insert(VERSION, 1); diff --git a/src/tools/sdktool/addkitoperation.h b/src/tools/sdktool/addkitoperation.h index 037144353a0..89b588e7944 100644 --- a/src/tools/sdktool/addkitoperation.h +++ b/src/tools/sdktool/addkitoperation.h @@ -28,49 +28,17 @@ #include "operation.h" #include -#include -class AddKitOperation : public Operation +class AddKitData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addKit(const QVariantMap &map, const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, - const QString &qt, const QString &mkspec, - const QString &cmakeId, const QString &cmakeGenerator, - const QString &cmakeExtraGenerator, const QString &cmakeGeneratorToolset, - const QString &cmakeGeneratorPlatform, - const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra); + QVariantMap addKit(const QVariantMap &map) const; + QVariantMap addKit(const QVariantMap &map, const QVariantMap &tcMap, + const QVariantMap &qtMap, const QVariantMap &devMap, + const QVariantMap &cmakeMap) const; static QVariantMap initializeKits(); - // internal: - static QVariantMap addKit(const QVariantMap &map, const QVariantMap &tcMap, - const QVariantMap &qtMap, const QVariantMap &devMap, const QVariantMap &cmakeMap, - const QString &id, const QString &displayName, - const QString &icon, const QString &debuggerId, - const quint32 &debuggerType, const QString &debugger, - const QString &deviceType, const QString &device, - const QString &sysRoot, const QHash &tcs, - const QString &qt, const QString &mkspec, const QString &cmakeId, const QString &cmakeGenerator, const QString &cmakeExtraGenerator, const QString &cmakeGeneratorToolset, const QString &cmakeGeneratorPlatform, const QStringList &cmakeConfiguration, const QStringList &env, - const KeyValuePairList &extra); - -private: QString m_id; QString m_displayName; QString m_icon; @@ -92,3 +60,18 @@ private: QStringList m_env; KeyValuePairList m_extra; }; + +class AddKitOperation : public Operation, public AddKitData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addqtoperation.cpp b/src/tools/sdktool/addqtoperation.cpp index 7a94480d4a8..99eb3c78c0d 100644 --- a/src/tools/sdktool/addqtoperation.cpp +++ b/src/tools/sdktool/addqtoperation.cpp @@ -169,7 +169,7 @@ int AddQtOperation::execute() const if (map.isEmpty()) map = initializeQtVersions(); - QVariantMap result = addQt(map, m_id, m_displayName, m_type, m_qmake, m_extra, m_abis); + QVariantMap result = addQt(map); if (result.isEmpty() || result == map) return 2; @@ -180,6 +180,7 @@ int AddQtOperation::execute() const #ifdef WITH_TESTS bool AddQtOperation::test() const { + AddQtData qtData; QVariantMap map = initializeQtVersions(); if (map.count() != 1 @@ -188,16 +189,13 @@ bool AddQtOperation::test() const return false; #if defined Q_OS_WIN - map = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version"), QLatin1String("testType"), - QLatin1String("/tmp//../tmp/test\\qmake"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version", "testType", "/tmp//../tmp/test\\qmake", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; #else - map = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version"), QLatin1String("testType"), - QLatin1String("/tmp//../tmp/test/qmake"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version", "testType", "/tmp//../tmp/test/qmake", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; #endif + map = qtData.addQt(map); if (map.count() != 2 || !map.contains(QLatin1String(VERSION)) @@ -226,18 +224,16 @@ bool AddQtOperation::test() const return false; // Ignore existing ids: - QVariantMap result = addQt(map, QLatin1String("{some-qt-id}"), QLatin1String("Test Qt Version2"), QLatin1String("testType2"), - QLatin1String("/tmp/test/qmake2"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"{some-qt-id}", "Test Qt Version2", "testType2", "/tmp/test/qmake2", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; + QVariantMap result = qtData.addQt(map); if (!result.isEmpty()) return false; // add 2nd Qt version: - map = addQt(map, QLatin1String("testId2"), QLatin1String("Test Qt Version"), QLatin1String("testType3"), - QLatin1String("/tmp/test/qmake2"), - KeyValuePairList() << KeyValuePair(QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))), - QStringList()); + qtData = {"testId2", "Test Qt Version", "testType3", "/tmp/test/qmake2", {}, + {{QLatin1String("extraData"), QVariant(QLatin1String("extraValue"))}}}; + map = qtData.addQt(map); if (map.count() != 3 || !map.contains(QLatin1String(VERSION)) || map.value(QLatin1String(VERSION)).toInt() != 1 @@ -272,16 +268,13 @@ bool AddQtOperation::test() const } #endif -QVariantMap AddQtOperation::addQt(const QVariantMap &map, - const QString &id, const QString &displayName, const QString &type, - const QString &qmake, const KeyValuePairList &extra, - const QStringList &abis) +QVariantMap AddQtData::addQt(const QVariantMap &map) const { - QString sdkId = extendId(id); + QString sdkId = extendId(m_id); // Sanity check: Make sure autodetection source is not in use already: if (exists(map, sdkId)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined as Qt versions." << std::endl; + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined as Qt versions." << std::endl; return QVariantMap(); } @@ -299,40 +292,41 @@ QVariantMap AddQtOperation::addQt(const QVariantMap &map, const QString qt = QString::fromLatin1(PREFIX) + QString::number(versionCount); // Sanitize qmake path: - FilePath saneQmake = FilePath::fromUserInput(qmake).cleanPath(); + FilePath saneQmake = FilePath::fromUserInput(m_qmake).cleanPath(); // insert data: KeyValuePairList data; data << KeyValuePair(QStringList() << qt << QLatin1String(ID), QVariant(-1)); - data << KeyValuePair(QStringList() << qt << QLatin1String(DISPLAYNAME), QVariant(displayName)); + data << KeyValuePair(QStringList() << qt << QLatin1String(DISPLAYNAME), QVariant(m_displayName)); data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTED), QVariant(true)); data << KeyValuePair(QStringList() << qt << QLatin1String(AUTODETECTION_SOURCE), QVariant(sdkId)); + data << KeyValuePair(QStringList() << qt << QLatin1String(QMAKE), saneQmake.toVariant()); - data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(type)); - data << KeyValuePair(QStringList() << qt << ABIS, QVariant(abis)); + data << KeyValuePair(QStringList() << qt << QLatin1String(TYPE), QVariant(m_type)); + data << KeyValuePair(QStringList() << qt << ABIS, QVariant(m_abis)); KeyValuePairList qtExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) qtExtraList << KeyValuePair(QStringList() << qt << pair.key, pair.value); data.append(qtExtraList); - return AddKeysOperation::addKeys(map, data); + return AddKeysData{data}.addKeys(map); } -QVariantMap AddQtOperation::initializeQtVersions() +QVariantMap AddQtData::initializeQtVersions() { QVariantMap map; map.insert(QLatin1String(VERSION), 1); return map; } -bool AddQtOperation::exists(const QString &id) +bool AddQtData::exists(const QString &id) { - QVariantMap map = load(QLatin1String("QtVersions")); + QVariantMap map = Operation::load(QLatin1String("QtVersions")); return exists(map, id); } -bool AddQtOperation::exists(const QVariantMap &map, const QString &id) +bool AddQtData::exists(const QVariantMap &map, const QString &id) { QString sdkId = extendId(id); diff --git a/src/tools/sdktool/addqtoperation.h b/src/tools/sdktool/addqtoperation.h index 65e31ff8353..d7269e32454 100644 --- a/src/tools/sdktool/addqtoperation.h +++ b/src/tools/sdktool/addqtoperation.h @@ -27,34 +27,16 @@ #include "operation.h" -#include - -class AddQtOperation : public Operation +class AddQtData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addQt(const QVariantMap &map, - const QString &id, const QString &displayName, const QString &type, - const QString &qmake, const KeyValuePairList &extra, - const QStringList &abis); + QVariantMap addQt(const QVariantMap &map) const; static QVariantMap initializeQtVersions(); static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; // actually this is the autodetectionSource QString m_displayName; QString m_type; @@ -62,3 +44,17 @@ private: QStringList m_abis; KeyValuePairList m_extra; }; + +class AddQtOperation : public Operation, public AddQtData +{ +private: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + bool setArguments(const QStringList &args) final; + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addtoolchainoperation.cpp b/src/tools/sdktool/addtoolchainoperation.cpp index 6bd8380a15d..aec304b647e 100644 --- a/src/tools/sdktool/addtoolchainoperation.cpp +++ b/src/tools/sdktool/addtoolchainoperation.cpp @@ -158,8 +158,7 @@ int AddToolChainOperation::execute() const if (map.isEmpty()) map = initializeToolChains(); - QVariantMap result = addToolChain(map, m_id, m_languageId, m_displayName, m_path, - m_targetAbi, m_supportedAbis, m_extra); + QVariantMap result = addToolChain(map); if (result.isEmpty() || map == result) return 2; @@ -172,8 +171,8 @@ bool AddToolChainOperation::test() const QVariantMap map = initializeToolChains(); // Add toolchain: - map = addToolChain(map, "testId", "langId", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddToolChainData{"testId", "langId", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", + {{"ExtraKey", QVariant("ExtraValue")}}}.addToolChain(map); if (map.value(COUNT).toInt() != 1 || !map.contains(QString::fromLatin1(PREFIX) + '0')) return false; @@ -190,15 +189,15 @@ bool AddToolChainOperation::test() const return false; // Ignore same Id: - QVariantMap unchanged = addToolChain(map, "testId", "langId", "name2", "/tmp/test2", "test-abi2", + QVariantMap unchanged = AddToolChainData{"testId", "langId", "name2", "/tmp/test2", "test-abi2", "test-abi2,test-abi3", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue2"))); + {{"ExtraKey", QVariant("ExtraValue2")}}}.addToolChain(map); if (!unchanged.isEmpty()) return false; // add 2nd tool chain: - map = addToolChain(map, "{some-tc-id}", "langId2", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", - KeyValuePairList() << KeyValuePair("ExtraKey", QVariant("ExtraValue"))); + map = AddToolChainData{"{some-tc-id}", "langId2", "name", "/tmp/test", "test-abi", "test-abi,test-abi2", + {{"ExtraKey", QVariant("ExtraValue")}}}.addToolChain(map); if (map.value(COUNT).toInt() != 2 || !map.contains(QString::fromLatin1(PREFIX) + '0') || !map.contains(QString::fromLatin1(PREFIX) + '1')) @@ -230,15 +229,11 @@ bool AddToolChainOperation::test() const } #endif -QVariantMap AddToolChainOperation::addToolChain(const QVariantMap &map, const QString &id, - const QString &lang, const QString &displayName, - const QString &path, const QString &abi, - const QString &supportedAbis, - const KeyValuePairList &extra) +QVariantMap AddToolChainData::addToolChain(const QVariantMap &map) const { // Sanity check: Does the Id already exist? - if (exists(map, id)) { - std::cerr << "Error: Id " << qPrintable(id) << " already defined for tool chains." << std::endl; + if (exists(map, m_id)) { + std::cerr << "Error: Id " << qPrintable(m_id) << " already defined for tool chains." << std::endl; return QVariantMap(); } @@ -255,44 +250,44 @@ QVariantMap AddToolChainOperation::addToolChain(const QVariantMap &map, const QS const QString tc = QString::fromLatin1(PREFIX) + QString::number(count); KeyValuePairList data; - data << KeyValuePair({tc, ID}, QVariant(id)); + data << KeyValuePair({tc, ID}, QVariant(m_id)); // Language compatibility hack for old Qt components that use the language spec from 4.2. // Some Qt 5.15 components were actually still using this. QString newLang; // QtC 4.3 and later - lang.toInt(&ok); - if (lang == "2" || lang == "Cxx") { + m_languageId.toInt(&ok); + if (m_languageId == "2" || m_languageId == "Cxx") { newLang = "Cxx"; - } else if (lang == "1" || lang == "C") { + } else if (m_languageId == "1" || m_languageId == "C") { newLang = "C"; } else if (ok) { std::cerr << "Error: Language ID must be 1 for C, 2 for Cxx " << "or a string like \"C\", \"Cxx\", \"Nim\" (was \"" - << qPrintable(lang) << "\")" << std::endl; + << qPrintable(m_languageId) << "\")" << std::endl; return {}; } else if (!ok) { - newLang = lang; + newLang = m_languageId; } data << KeyValuePair({tc, LANGUAGE_KEY_V2}, QVariant(newLang)); - data << KeyValuePair({tc, DISPLAYNAME}, QVariant(displayName)); + data << KeyValuePair({tc, DISPLAYNAME}, QVariant(m_displayName)); data << KeyValuePair({tc, AUTODETECTED}, QVariant(true)); - data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(path).toVariant()); - data << KeyValuePair({tc, TARGET_ABI}, QVariant(abi)); + data << KeyValuePair({tc, PATH}, Utils::FilePath::fromUserInput(m_path).toVariant()); + data << KeyValuePair({tc, TARGET_ABI}, QVariant(m_targetAbi)); QVariantList abis; - QStringList abiStrings = supportedAbis.split(','); + QStringList abiStrings = m_supportedAbis.split(','); foreach (const QString &s, abiStrings) abis << QVariant(s); data << KeyValuePair({tc, SUPPORTED_ABIS}, QVariant(abis)); KeyValuePairList tcExtraList; - foreach (const KeyValuePair &pair, extra) + foreach (const KeyValuePair &pair, m_extra) tcExtraList << KeyValuePair(QStringList({tc}) << pair.key, pair.value); data.append(tcExtraList); data << KeyValuePair(COUNT, QVariant(count + 1)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } -QVariantMap AddToolChainOperation::initializeToolChains() +QVariantMap AddToolChainData::initializeToolChains() { QVariantMap map; map.insert(COUNT, 0); @@ -300,7 +295,7 @@ QVariantMap AddToolChainOperation::initializeToolChains() return map; } -bool AddToolChainOperation::exists(const QVariantMap &map, const QString &id) +bool AddToolChainData::exists(const QVariantMap &map, const QString &id) { QStringList valueKeys = FindValueOperation::findValue(map, id); // support old settings using QByteArray for id's @@ -314,7 +309,7 @@ bool AddToolChainOperation::exists(const QVariantMap &map, const QString &id) return false; } -bool AddToolChainOperation::exists(const QString &id) +bool AddToolChainData::exists(const QString &id) { QVariantMap map = Operation::load("ToolChains"); return exists(map, id); diff --git a/src/tools/sdktool/addtoolchainoperation.h b/src/tools/sdktool/addtoolchainoperation.h index 5f743eba483..5e6ac39a7c2 100644 --- a/src/tools/sdktool/addtoolchainoperation.h +++ b/src/tools/sdktool/addtoolchainoperation.h @@ -27,34 +27,16 @@ #include "operation.h" -#include - -class AddToolChainOperation : public Operation +class AddToolChainData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; - - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap addToolChain(const QVariantMap &map, - const QString &id, const QString &lang, - const QString &displayName, const QString &path, - const QString &abi, const QString &supportedAbis, - const KeyValuePairList &extra); + QVariantMap addToolChain(const QVariantMap &map) const; static QVariantMap initializeToolChains(); + static bool exists(const QString &id); static bool exists(const QVariantMap &map, const QString &id); -private: QString m_id; QString m_languageId; QString m_displayName; @@ -63,3 +45,19 @@ private: QString m_supportedAbis; KeyValuePairList m_extra; }; + +class AddToolChainOperation : public Operation, public AddToolChainData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/addvalueoperation.cpp b/src/tools/sdktool/addvalueoperation.cpp index ef434d3b3f5..a604409f611 100644 --- a/src/tools/sdktool/addvalueoperation.cpp +++ b/src/tools/sdktool/addvalueoperation.cpp @@ -79,7 +79,7 @@ bool AddValueOperation::setArguments(const QStringList &args) m_file = tempArgs.takeFirst(); m_key = tempArgs.takeFirst(); for (const auto &arg : tempArgs) { - const auto val = Operation::valueFromString(arg); + const auto val = valueFromString(arg); if (!val.isValid() || val.isNull()) { std::cerr << "Error: " << std::quoted(arg.toStdString()) << " is not a valid QVariant like string Type:Value.\n" @@ -101,7 +101,7 @@ int AddValueOperation::execute() const return FAILURE; } - auto status = appendListToMap(map, m_key, m_values); + bool status = appendListToMap(map); if (status) { status = save(map, m_file); @@ -122,13 +122,12 @@ bool AddValueOperation::test() const testKvpList.append(KeyValuePair(QLatin1String("test/foobar"), QString::fromLatin1("int:42"))); testKvpList.append(KeyValuePair(QLatin1String("test/bar"), testDataList)); - const auto valueList = QVariantList( - {Operation::valueFromString("QString:ELIL"), Operation::valueFromString("int:-1")}); + const QVariantList valueList = {valueFromString("QString:ELIL"), valueFromString("int:-1")}; QVariantMap testMap; // add to empty map - auto result = appendListToMap(testMap, "some key", valueList); + bool result = AddValueData{"some key", valueList}.appendListToMap(testMap); if (result) return false; @@ -137,19 +136,19 @@ bool AddValueOperation::test() const testMap.insert(QLatin1String("aKey"), "withAString"); // append to a value - result = appendListToMap(testMap, "aKey", valueList); + result = AddValueData{"aKey", valueList}.appendListToMap(testMap); if (result) return false; - testMap = AddKeysOperation::addKeys(testMap, testKvpList); + testMap = AddKeysData{testKvpList}.addKeys(testMap); // quick sanity check if (testMap.count() != 3 && testDataList.count() != 2 && testKvpList.count() != 3) return false; // successful adding of values - result = appendListToMap(testMap, "test/bar", valueList); + result = AddValueData{"test/bar", valueList}.appendListToMap(testMap); if (!result) return false; @@ -165,30 +164,28 @@ bool AddValueOperation::test() const } #endif -bool AddValueOperation::appendListToMap(QVariantMap &map, - const QString &key, - const QVariantList &values) +bool AddValueData::appendListToMap(QVariantMap &map) const { - const auto data = GetOperation::get(map, key); + const QVariant data = GetOperation::get(map, m_key); if (!data.isValid() || data.isNull()) { - std::cerr << "Error: Could not retrieve value for key " << std::quoted(key.toStdString()) + std::cerr << "Error: Could not retrieve value for key " << std::quoted(m_key.toStdString()) << std::endl; return false; } if (data.type() != QVariant::List) { - std::cerr << "Error: Data stored in " << std::quoted(key.toStdString()) + std::cerr << "Error: Data stored in " << std::quoted(m_key.toStdString()) << " is not a QVariantList." << std::endl; return false; } auto newList = qvariant_cast(data); - newList.append(values); + newList.append(m_values); - map = RmKeysOperation::rmKeys(map, {key}); - map = AddKeysOperation::addKeys(map, {Operation::KeyValuePair(key, newList)}); + map = RmKeysOperation::rmKeys(map, {m_key}); + map = AddKeysData{{{m_key, newList}}}.addKeys(map); return true; } diff --git a/src/tools/sdktool/addvalueoperation.h b/src/tools/sdktool/addvalueoperation.h index fe1910a2272..df19f1f2357 100644 --- a/src/tools/sdktool/addvalueoperation.h +++ b/src/tools/sdktool/addvalueoperation.h @@ -28,25 +28,30 @@ #include "operation.h" -class AddValueOperation : public Operation +class AddValueData { public: - QString name() const override; - QString helpText() const override; - QString argumentsHelpText() const override; + bool appendListToMap(QVariantMap &map) const; - bool setArguments(const QStringList &args) override; - - int execute() const override; - -#ifdef WITH_TESTS - bool test() const override; -#endif - - static bool appendListToMap(QVariantMap &map, const QString &key, const QVariantList &values); - -private: - QString m_file; QString m_key; QVariantList m_values; }; + +class AddValueOperation : public Operation, public AddValueData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif + +private: + QString m_file; +}; diff --git a/src/tools/sdktool/findkeyoperation.h b/src/tools/sdktool/findkeyoperation.h index f6365c7ebd8..e8138fa7865 100644 --- a/src/tools/sdktool/findkeyoperation.h +++ b/src/tools/sdktool/findkeyoperation.h @@ -30,18 +30,17 @@ class FindKeyOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif - static QStringList findKey(const QVariant &in, const QString &key, const QString &prefix = QString()); diff --git a/src/tools/sdktool/findvalueoperation.cpp b/src/tools/sdktool/findvalueoperation.cpp index e59a0fa115e..2ed856c608b 100644 --- a/src/tools/sdktool/findvalueoperation.cpp +++ b/src/tools/sdktool/findvalueoperation.cpp @@ -53,7 +53,7 @@ bool FindValueOperation::setArguments(const QStringList &args) continue; } - QVariant v = Operation::valueFromString(current); + QVariant v = valueFromString(current); if (!v.isValid()) { std::cerr << "Value for key '" << qPrintable(current) << "' is not valid." << std::endl << std::endl; return false; diff --git a/src/tools/sdktool/findvalueoperation.h b/src/tools/sdktool/findvalueoperation.h index 2d49678b666..f53dae125b0 100644 --- a/src/tools/sdktool/findvalueoperation.h +++ b/src/tools/sdktool/findvalueoperation.h @@ -30,16 +30,16 @@ class FindValueOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QStringList findValue(const QVariant &in, const QVariant &value, diff --git a/src/tools/sdktool/getoperation.h b/src/tools/sdktool/getoperation.h index 6d9b018ad04..56b7970ca35 100644 --- a/src/tools/sdktool/getoperation.h +++ b/src/tools/sdktool/getoperation.h @@ -30,16 +30,16 @@ class GetOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QVariant get(const QVariantMap &map, const QString &key); diff --git a/src/tools/sdktool/operation.cpp b/src/tools/sdktool/operation.cpp index 44af491b867..4c1eec03d96 100644 --- a/src/tools/sdktool/operation.cpp +++ b/src/tools/sdktool/operation.cpp @@ -34,7 +34,7 @@ #include -QVariant Operation::valueFromString(const QString &v) +QVariant valueFromString(const QString &v) { int pos = v.indexOf(QLatin1Char(':')); if (pos <= 0) @@ -62,23 +62,23 @@ QVariant Operation::valueFromString(const QString &v) return QVariant(); } -Operation::KeyValuePair::KeyValuePair(const QString &k, const QString &v) : +KeyValuePair::KeyValuePair(const QString &k, const QString &v) : value(valueFromString(v)) { key = k.split(QLatin1Char('/')); } -Operation::KeyValuePair::KeyValuePair(const QString &k, const QVariant &v) : +KeyValuePair::KeyValuePair(const QString &k, const QVariant &v) : value(v) { key = k.split(QLatin1Char('/')); } -Operation::KeyValuePair::KeyValuePair(const QStringList &k, const QString &v) : +KeyValuePair::KeyValuePair(const QStringList &k, const QString &v) : key(k), value(valueFromString(v)) { } -Operation::KeyValuePair::KeyValuePair(const QStringList &k, const QVariant &v) : +KeyValuePair::KeyValuePair(const QStringList &k, const QVariant &v) : key(k), value(v) { } diff --git a/src/tools/sdktool/operation.h b/src/tools/sdktool/operation.h index 99077fb2160..cc489ce0757 100644 --- a/src/tools/sdktool/operation.h +++ b/src/tools/sdktool/operation.h @@ -30,21 +30,25 @@ #include #include +class KeyValuePair +{ +public: + KeyValuePair(const QString &k, const QString &v); + KeyValuePair(const QString &k, const QVariant &v); + KeyValuePair(const QStringList &k, const QString &v); + KeyValuePair(const QStringList &k, const QVariant &v); + + QStringList key; + QVariant value; +}; + +using KeyValuePairList = QList; + +QVariant valueFromString(const QString &v); + class Operation { public: - class KeyValuePair { - public: - KeyValuePair(const QString &k, const QString &v); - KeyValuePair(const QString &k, const QVariant &v); - KeyValuePair(const QStringList &k, const QString &v); - KeyValuePair(const QStringList &k, const QVariant &v); - - QStringList key; - QVariant value; - }; - typedef QList KeyValuePairList; - virtual ~Operation() { } virtual QString name() const = 0; @@ -61,6 +65,4 @@ public: static QVariantMap load(const QString &file); bool save(const QVariantMap &map, const QString &file) const; - - static QVariant valueFromString(const QString &v); }; diff --git a/src/tools/sdktool/rmcmakeoperation.cpp b/src/tools/sdktool/rmcmakeoperation.cpp index a5583c3f843..423abdbc695 100644 --- a/src/tools/sdktool/rmcmakeoperation.cpp +++ b/src/tools/sdktool/rmcmakeoperation.cpp @@ -85,7 +85,7 @@ int RmCMakeOperation::execute() const if (map.isEmpty()) return 0; - QVariantMap result = rmCMake(map, m_id); + QVariantMap result = RmCMakeData{m_id}.rmCMake(map); if (result == map) return 2; @@ -98,20 +98,20 @@ bool RmCMakeOperation::test() const // Add cmakes: QVariantMap map = AddCMakeOperation::initializeCMake(); const QVariantMap emptyMap = map; - map = AddCMakeOperation::addCMake(map, "testId", "name", "/tmp/test", - KeyValuePairList({KeyValuePair("ExtraKey", QVariant("ExtraValue"))})); - map = AddCMakeOperation::addCMake(map, "testId2", "other name", "/tmp/test2", KeyValuePairList()); + map = AddCMakeData{"testId", "name", "/tmp/test", + {{"ExtraKey", QVariant("ExtraValue")}}}.addCMake(map); + map = AddCMakeData{"testId2", "other name", "/tmp/test2", {}}.addCMake(map); - QVariantMap result = rmCMake(QVariantMap(), "nonexistent"); + QVariantMap result = RmCMakeData{"nonexistent"}.rmCMake(QVariantMap()); if (!result.isEmpty()) return false; - result = rmCMake(map, "nonexistent"); + result = RmCMakeData{"nonexistent"}.rmCMake(map); if (result != map) return false; // Remove from map with both testId and testId2: - result = rmCMake(map, "testId2"); + result = RmCMakeData{"testId2"}.rmCMake(map); if (result == map || result.value(COUNT, 0).toInt() != 1 || !result.contains(QString::fromLatin1(PREFIX) + "0") @@ -119,7 +119,7 @@ bool RmCMakeOperation::test() const return false; // Remove from map with both testId and testId2: - result = rmCMake(map, "testId"); + result = RmCMakeData{"testId"}.rmCMake(map); if (result == map || result.value(COUNT, 0).toInt() != 1 || !result.contains(QString::fromLatin1(PREFIX) + "0") @@ -127,7 +127,7 @@ bool RmCMakeOperation::test() const return false; // Remove from map without testId! - result = rmCMake(result, "testId2"); + result = RmCMakeData{"testId2"}.rmCMake(result); if (result != emptyMap) return false; @@ -135,7 +135,7 @@ bool RmCMakeOperation::test() const } #endif -QVariantMap RmCMakeOperation::rmCMake(const QVariantMap &map, const QString &id) +QVariantMap RmCMakeData::rmCMake(const QVariantMap &map) const { // Find count of cmakes: bool ok; @@ -148,7 +148,7 @@ QVariantMap RmCMakeOperation::rmCMake(const QVariantMap &map, const QString &id) QVariantList cmList; for (int i = 0; i < count; ++i) { QVariantMap cmData = GetOperation::get(map, QString::fromLatin1(PREFIX) + QString::number(i)).toMap(); - if (cmData.value(ID).toString() != id) + if (cmData.value(ID).toString() != m_id) cmList.append(cmData); } diff --git a/src/tools/sdktool/rmcmakeoperation.h b/src/tools/sdktool/rmcmakeoperation.h index 1a292a3fd6e..98d9f7847a0 100644 --- a/src/tools/sdktool/rmcmakeoperation.h +++ b/src/tools/sdktool/rmcmakeoperation.h @@ -27,25 +27,26 @@ #include "operation.h" -#include - -class RmCMakeOperation : public Operation +class RmCMakeData { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QVariantMap rmCMake(const QVariantMap &map) const; - bool setArguments(const QStringList &args); - - int execute() const; - -#ifdef WITH_TESTS - bool test() const; -#endif - - static QVariantMap rmCMake(const QVariantMap &map, const QString &id); - -private: QString m_id; }; + +class RmCMakeOperation : public Operation, public RmCMakeData +{ +public: + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; + + bool setArguments(const QStringList &args) final; + + int execute() const final; + +#ifdef WITH_TESTS + bool test() const final; +#endif +}; diff --git a/src/tools/sdktool/rmdebuggeroperation.cpp b/src/tools/sdktool/rmdebuggeroperation.cpp index 8c2a6bea0d9..5ed3ec6a86e 100644 --- a/src/tools/sdktool/rmdebuggeroperation.cpp +++ b/src/tools/sdktool/rmdebuggeroperation.cpp @@ -95,16 +95,15 @@ bool RmDebuggerOperation::test() const { QVariantMap map = - AddDebuggerOperation::addDebugger(AddDebuggerOperation::initializeDebuggers(), - QLatin1String("id1"), QLatin1String("Name1"), - 2, QLatin1String("/tmp/debugger1"), - QStringList() << QLatin1String("test11") << QLatin1String("test12"), - KeyValuePairList()); - map = - AddDebuggerOperation::addDebugger(map, QLatin1String("id2"), QLatin1String("Name2"), - 2, QLatin1String("/tmp/debugger2"), - QStringList() << QLatin1String("test21") << QLatin1String("test22"), - KeyValuePairList()); + AddDebuggerData{QLatin1String("id1"), QLatin1String("Name1"), + 2, QLatin1String("/tmp/debugger1"), + {"test11", "test12"}, {}} + .addDebugger(AddDebuggerOperation::initializeDebuggers()); + + map = AddDebuggerData{QLatin1String("id2"), QLatin1String("Name2"), + 2, QLatin1String("/tmp/debugger2"), + {"test21", "test22"}, {}} + .addDebugger(map); QVariantMap result = rmDebugger(map, QLatin1String("id2")); if (result.count() != 3 @@ -178,6 +177,6 @@ QVariantMap RmDebuggerOperation::rmDebugger(const QVariantMap &map, const QStrin debuggerList.at(i)); } - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } diff --git a/src/tools/sdktool/rmkitoperation.cpp b/src/tools/sdktool/rmkitoperation.cpp index 4e7487f40b0..306cfc3bd75 100644 --- a/src/tools/sdktool/rmkitoperation.cpp +++ b/src/tools/sdktool/rmkitoperation.cpp @@ -98,40 +98,40 @@ int RmKitOperation::execute() const bool RmKitOperation::test() const { QVariantMap tcMap = AddToolChainOperation::initializeToolChains(); - tcMap = AddToolChainOperation::addToolChain(tcMap, "{tc-id}", "langId", "TC", "/usr/bin/gcc", - "x86-linux-generic-elf-32bit", - "x86-linux-generic-elf-32bit", - KeyValuePairList()); + tcMap = AddToolChainData{"{tc-id}", "langId", "TC", "/usr/bin/gcc", + "x86-linux-generic-elf-32bit", "x86-linux-generic-elf-32bit", {}} + .addToolChain(tcMap); - QVariantMap qtMap = AddQtOperation::initializeQtVersions(); - qtMap = AddQtOperation::addQt(qtMap, "{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", - KeyValuePairList(), QStringList()); + QVariantMap qtMap = AddQtData::initializeQtVersions(); + qtMap = AddQtData{"{qt-id}", "Qt", "desktop-qt", "/usr/bin/qmake", {}, {}}.addQt(qtMap); QVariantMap devMap = AddDeviceOperation::initializeDevices(); - devMap = AddDeviceOperation::addDevice(devMap, "{dev-id}", "Dev", 0, 0, - "HWplatform", "SWplatform", - "localhost", "10000-11000", "localhost", "", 42, - "desktop", "", 22, 10000, "uname", 1, - KeyValuePairList()); + devMap = AddDeviceData{"{dev-id}", "Dev", 0, 0, + "HWplatform", "SWplatform", + "localhost", "10000-11000", "localhost", "", 42, + "desktop", "", 22, 10000, "uname", 1, + KeyValuePairList()} + .addDevice(devMap); QHash tcs; tcs.insert("Cxx", "{tc-id}"); QVariantMap map = - AddKitOperation::addKit(AddKitOperation::initializeKits(), tcMap, qtMap, devMap, - QVariantMap(), - "testId", "Test Qt Version", "/tmp/icon.png", QString(), 1, - "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, - "{qt-id}", "unsupported/mkspec", - QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), - KeyValuePairList() << KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue"))); - map = - AddKitOperation::addKit(map, tcMap, qtMap, devMap, QVariantMap(), "testId2", "Test Qt Version", - "/tmp/icon2.png", QString(), 1, "/usr/bin/gdb-test2", - "Desktop", QString(), QString(), tcs, "{qt-id}", - "unsupported/mkspec2", - QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), - KeyValuePairList() << KeyValuePair("PE.Profile.Data/extraData", QVariant("extraValue2"))); + AddKitData{"testId", "Test Qt Version", "/tmp/icon.png", QString(), 1, + "/usr/bin/gdb-test", "Desktop", QString(), QString(), tcs, + "{qt-id}", "unsupported/mkspec", + QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), + {{"PE.Profile.Data/extraData", QVariant("extraValue")}}} + .addKit(AddKitData::initializeKits(), tcMap, qtMap, devMap, {}); + + + map = AddKitData{"testId2", "Test Qt Version", + "/tmp/icon2.png", QString(), 1, "/usr/bin/gdb-test2", + "Desktop", QString(), QString(), tcs, "{qt-id}", + "unsupported/mkspec2", + QString(), QString(), QString(), QString(), QString(), QStringList(), QStringList(), + {{"PE.Profile.Data/extraData", QVariant("extraValue2")}}} + .addKit(map, tcMap, qtMap, devMap, {}); QVariantMap result = rmKit(map, "testId"); if (result.count() != 4 @@ -212,5 +212,5 @@ QVariantMap RmKitOperation::rmKit(const QVariantMap &map, const QString &id) data << KeyValuePair(QString::fromLatin1(PREFIX) + QString::number(i), profileList.at(i)); - return AddKeysOperation::addKeys(result, data); + return AddKeysData{data}.addKeys(result); } diff --git a/src/tools/sdktool/rmqtoperation.cpp b/src/tools/sdktool/rmqtoperation.cpp index 53f3b760015..bad6c923060 100644 --- a/src/tools/sdktool/rmqtoperation.cpp +++ b/src/tools/sdktool/rmqtoperation.cpp @@ -95,19 +95,17 @@ int RmQtOperation::execute() const bool RmQtOperation::test() const { // Add toolchain: - QVariantMap map = AddQtOperation::initializeQtVersions(); + QVariantMap map = AddQtData::initializeQtVersions(); QVariantMap result = rmQt(QVariantMap(), QLatin1String("nonexistant")); if (result != map) return false; - map = AddQtOperation::addQt(map, QLatin1String("testId"), QLatin1String("name"), QLatin1String("type"), - QLatin1String("/tmp/test"), - KeyValuePairList() << KeyValuePair(QLatin1String("ExtraKey"), QVariant(QLatin1String("ExtraValue"))), - QStringList()); - map = AddQtOperation::addQt(map, QLatin1String("testId2"), QLatin1String("other name"), QLatin1String("type"), - QLatin1String("/tmp/test2"), - KeyValuePairList(), QStringList()); + map = AddQtData{"testId", "name", "type", "/tmp/test", {}, + {{QLatin1String("ExtraKey"), QVariant(QLatin1String("ExtraValue"))}}} + .addQt(map); + + map = AddQtData{"testId2", "other name", "type", "/tmp/test2", {}, {}}.addQt(map); result = rmQt(map, QLatin1String("nonexistant")); if (result != map) @@ -149,7 +147,7 @@ QVariantMap RmQtOperation::rmQt(const QVariantMap &map, const QString &id) qtList.append(qtData); } - QVariantMap newMap = AddQtOperation::initializeQtVersions(); + QVariantMap newMap = AddQtData::initializeQtVersions(); for (int i = 0; i < qtList.count(); ++i) newMap.insert(QString::fromLatin1(PREFIX) + QString::number(i), qtList.at(i)); diff --git a/src/tools/sdktool/rmtoolchainoperation.cpp b/src/tools/sdktool/rmtoolchainoperation.cpp index 1cefe020609..bf71ec5cfe9 100644 --- a/src/tools/sdktool/rmtoolchainoperation.cpp +++ b/src/tools/sdktool/rmtoolchainoperation.cpp @@ -97,11 +97,13 @@ bool RmToolChainOperation::test() const { // Add toolchain: QVariantMap map = AddToolChainOperation::initializeToolChains(); - map = AddToolChainOperation::addToolChain(map, "testId", "langId", "name", "/tmp/test", "test-abi", - "test-abi,test-abi2", - KeyValuePairList({KeyValuePair("ExtraKey", QVariant("ExtraValue"))})); - map = AddToolChainOperation::addToolChain(map, "testId2", "langId", "other name", "/tmp/test2", "test-abi", - "test-abi,test-abi2", KeyValuePairList()); + map = AddToolChainData{"testId", "langId", "name", "/tmp/test", "test-abi", + "test-abi,test-abi2", {{"ExtraKey", QVariant("ExtraValue")}}} + .addToolChain(map); + + map = AddToolChainData{"testId2", "langId", "other name", "/tmp/test2", "test-abi", + "test-abi,test-abi2", {}} + .addToolChain(map); QVariantMap result = rmToolChain(QVariantMap(), "nonexistent"); if (!result.isEmpty()) diff --git a/src/tools/sdktool/rmtoolchainoperation.h b/src/tools/sdktool/rmtoolchainoperation.h index 3755320710b..cf4d12d1e5e 100644 --- a/src/tools/sdktool/rmtoolchainoperation.h +++ b/src/tools/sdktool/rmtoolchainoperation.h @@ -32,16 +32,16 @@ class RmToolChainOperation : public Operation { public: - QString name() const; - QString helpText() const; - QString argumentsHelpText() const; + QString name() const final; + QString helpText() const final; + QString argumentsHelpText() const final; - bool setArguments(const QStringList &args); + bool setArguments(const QStringList &args) final; - int execute() const; + int execute() const final; #ifdef WITH_TESTS - bool test() const; + bool test() const final; #endif static QVariantMap rmToolChain(const QVariantMap &map, const QString &id); diff --git a/tests/auto/extensionsystem/pluginspec/CMakeLists.txt b/tests/auto/extensionsystem/pluginspec/CMakeLists.txt index 670412bfd84..ad91750f287 100644 --- a/tests/auto/extensionsystem/pluginspec/CMakeLists.txt +++ b/tests/auto/extensionsystem/pluginspec/CMakeLists.txt @@ -4,7 +4,7 @@ add_qtc_test(tst_pluginspec DEFINES PLUGIN_DIR="${CMAKE_CURRENT_BINARY_DIR}" PLUGINSPEC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - DLL_INFIX="d${PROJECT_VERSION_MAJOR}" + DLL_INFIX="$<$:d>" DEPENDS ExtensionSystem SOURCES tst_pluginspec.cpp diff --git a/tests/auto/extensionsystem/pluginspec/test.qbs b/tests/auto/extensionsystem/pluginspec/test.qbs index 88a009982f6..b8196f93e67 100644 --- a/tests/auto/extensionsystem/pluginspec/test.qbs +++ b/tests/auto/extensionsystem/pluginspec/test.qbs @@ -10,7 +10,7 @@ QtcAutotest { cpp.defines: outer.concat([ 'PLUGIN_DIR="' + destinationDirectory + '"', 'PLUGINSPEC_DIR="' + sourceDirectory + '"', - 'DLL_INFIX=""' + 'DLL_INFIX="' + (qbs.buildVariant === "debug" ? "d" : "") + '"' ]) } diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp index c8c81453197..26b8ddcf8e3 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp @@ -1234,6 +1234,115 @@ void tst_TestCore::testRewriterForGradientMagic() transaction.commit(); } +void tst_TestCore::testStatesVersionFailing() +{ + char qmlString[] = "import QtQuick\n" + "Rectangle {\n" + "id: root;\n" + "Rectangle {\n" + "id: rect1;\n" + "}\n" + "Rectangle {\n" + "id: rect2;\n" + "}\n" + "states: [\n" + "State {\n" + "name: \"state1\"\n" + "PropertyChanges {\n" + "target: rect1\n" + "}\n" + "}\n" + "]\n" + "}\n"; + + Exception::setShouldAssert(true); + + QPlainTextEdit textEdit; + textEdit.setPlainText(QLatin1String(qmlString)); + NotIndentingTextEditModifier textModifier(&textEdit); + + QScopedPointer model(Model::create("QtQuick.Item")); + QVERIFY(model.data()); + + QScopedPointer view(new TestView(model.data())); + QVERIFY(view.data()); + model->attachView(view.data()); + + ModelNode rootModelNode(view->rootModelNode()); + QVERIFY(rootModelNode.isValid()); + QCOMPARE(rootModelNode.type(), QmlDesigner::TypeName("QtQuick.Item")); + QScopedPointer testRewriterView(new TestRewriterView()); + testRewriterView->setTextModifier(&textModifier); + + model->attachView(testRewriterView.data()); + QVERIFY(rootModelNode.isValid()); + QCOMPARE(rootModelNode.type(), QmlDesigner::TypeName("QtQuick.Rectangle")); + + QCOMPARE(QmlItemNode(rootModelNode).states().allStates().count(), 1); + QCOMPARE(QmlItemNode(rootModelNode).states().names().count(), 1); + QCOMPARE(QmlItemNode(rootModelNode).states().names().first(), QString("state1")); + + QmlModelState state = QmlItemNode(rootModelNode).states().state("state1"); + ModelNode stateNode = QmlItemNode(rootModelNode).states().state("state1").modelNode(); + QVERIFY(stateNode.isValid()); + + NodeMetaInfo stateInfo = stateNode.metaInfo(); + + QVERIFY(stateInfo.isValid()); + QmlModelState newState = state.duplicate("state2"); + + QCOMPARE(QmlItemNode(rootModelNode).states().allStates().count(), 2); + QCOMPARE(QmlItemNode(rootModelNode).states().names().count(), 2); + QCOMPARE(QmlItemNode(rootModelNode).states().names().last(), QString("state2")); + + QCOMPARE(QmlItemNode(rootModelNode).states().state("state2"), newState); + + QCOMPARE(stateInfo.majorVersion(), newState.modelNode().majorVersion()); + QCOMPARE(stateInfo.minorVersion(), newState.modelNode().minorVersion()); + + ModelNode rect1Node = view->modelNodeForId("rect1"); + QVERIFY(rect1Node.isValid()); + QmlObjectNode rect1(rect1Node); + QmlPropertyChanges changes = newState.propertyChanges(rect1Node); + QVERIFY(changes.isValid()); + + NodeMetaInfo changeInfo = changes.modelNode().metaInfo(); + QVERIFY(changeInfo.isValid()); + + QVERIFY(!changes.modelNode().hasProperty("x")); + + view->setCurrentState(newState); + + QVERIFY(view->currentState() == newState); + + QString oldText = textEdit.toPlainText(); + + rect1.setVariantProperty("x", 100); + QVERIFY(changes.modelNode().hasProperty("x")); + QVERIFY(oldText != textEdit.toPlainText()); + + ModelNode rect2Node = view->modelNodeForId("rect2"); + QVERIFY(rect2Node.isValid()); + QmlObjectNode rect2(rect2Node); + QVERIFY(!newState.hasPropertyChanges(rect2Node)); + QmlPropertyChanges changes2 = newState.propertyChanges(rect2Node); + + QVERIFY(changes2.isValid()); + + QVERIFY(view->currentState() == newState); + + oldText = textEdit.toPlainText(); + + rect2.setVariantProperty("x", 100); + changes2 = newState.propertyChanges(rect2Node); + QVERIFY(changes2.isValid()); + QVERIFY(changes2.modelNode().hasProperty("x")); + QVERIFY(oldText != textEdit.toPlainText()); + + QCOMPARE(changeInfo.majorVersion(), changes2.modelNode().majorVersion()); + QCOMPARE(changeInfo.minorVersion(), changes2.modelNode().minorVersion()); +} + void tst_TestCore::loadSubItems() { QFile file(QString(TESTSRCDIR) + "/../data/fx/topitem.qml"); diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h index d052bf950e5..9a8aeb6450b 100644 --- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h +++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h @@ -199,6 +199,7 @@ private slots: void reparentingNodeLikeDragAndDrop(); void testRewriterForGradientMagic(); + void testStatesVersionFailing(); // // old tests diff --git a/tests/auto/tracing/flamegraphview/flamegraphview.qbs b/tests/auto/tracing/flamegraphview/flamegraphview.qbs index 0be52f5d7ab..711e955014f 100644 --- a/tests/auto/tracing/flamegraphview/flamegraphview.qbs +++ b/tests/auto/tracing/flamegraphview/flamegraphview.qbs @@ -4,6 +4,7 @@ import "../tracingautotest.qbs" as TracingAutotest TracingAutotest { name: "FlameGraphView autotest" + Depends { name: "Utils" } Depends { name: "Qt.quickwidgets" } Group { diff --git a/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp b/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp index cf384e5691e..9e217216870 100644 --- a/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp +++ b/tests/auto/tracing/flamegraphview/tst_flamegraphview.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -55,6 +56,8 @@ class tst_FlameGraphView : public QObject public: tst_FlameGraphView() { Utils::setCreatorTheme(&theme); } + static void initMain(); + private slots: void initTestCase(); void testZoom(); @@ -67,6 +70,15 @@ private: DummyTheme theme; }; +void tst_FlameGraphView::initMain() +{ + if (Utils::HostOsInfo::isWindowsHost()) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) + qputenv("QSG_RHI_BACKEND", "opengl"); +#endif // Qt >= 6.2 + } +} + void tst_FlameGraphView::initTestCase() { model.fill(); diff --git a/tests/auto/tracing/tracing.qbs b/tests/auto/tracing/tracing.qbs index 643d25f31ab..84000d731fe 100644 --- a/tests/auto/tracing/tracing.qbs +++ b/tests/auto/tracing/tracing.qbs @@ -5,6 +5,7 @@ Project { references: [ "flamegraph/flamegraph.qbs", + "flamegraphview/flamegraphview.qbs", "timelinemodel/timelinemodel.qbs", "timelinemodelaggregator/timelinemodelaggregator.qbs", "timelinenotesmodel/timelinenotesmodel.qbs", diff --git a/tests/manual/docker/README.md b/tests/manual/docker/README.md index 42833b0aecc..d9ef944d46f 100644 --- a/tests/manual/docker/README.md +++ b/tests/manual/docker/README.md @@ -1,13 +1,11 @@ Limitations: -- Only Linux development hosts supported, as the docker container - contents is accessed via the local file system. - -- It currently unconditionally mounts /data and /opt, - source code has to live in either. - -- Kit items are auto-detected, but Kits themselves need to be - fixed up manually. +- Linux, Mac, Windows hosts are supported in principle, + Linux is recommended. +- Only Kit items in selected directories are auto-detected. +- Kits themselves need to be fixed up manually. +- Shared mounts are restricted to locations on the host system + that can end up on the same absolute location in the container What works: @@ -25,7 +23,10 @@ What works: For testing: -- build docker containers from this directory (tests/manual/docker) by +- Optional: Set QT_LOGGING_RULES=qtc.docker.device=true + This will show a large part of the communication with the docker CLI client. + +- Build docker containers from this directory (tests/manual/docker) by running ./build.sh. This builds a docker image containing a Desktop Qt build setup (including compiler etc) and second docker image container containing a run environment without the build tools, but e.g. with gdb @@ -40,6 +41,11 @@ For testing: but using the Run container gives a more restricted setup closer to a real world scenario. +- MAKE SURE there's something sensible in "Paths to Mount". + These paths are shared between your host system and the docker device. + These should contain at the very least your sources, otherwise a build + in the container can't access it. + - Try to auto-detect kit items by pressing "Auto Detect Kit Items" for the Build container (only Build, not Run) diff --git a/tests/manual/pluginview/plugindialog.cpp b/tests/manual/pluginview/plugindialog.cpp index 9a0af5d449e..05e9bede88e 100644 --- a/tests/manual/pluginview/plugindialog.cpp +++ b/tests/manual/pluginview/plugindialog.cpp @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) QObject::connect(&app, &QCoreApplication::aboutToQuit, &manager, &ExtensionSystem::PluginManager::shutdown); PluginDialog dialog; - manager.setPluginPaths(QStringList() << "plugins"); + manager.setPluginPaths(QStringList() << app.applicationDirPath() + "/plugins"); manager.loadPlugins(); dialog.show(); app.exec(); diff --git a/tests/manual/pluginview/plugins/plugin1/plugin1.qbs b/tests/manual/pluginview/plugins/plugin1/plugin1.qbs index 631d08088d3..e709f0208ae 100644 --- a/tests/manual/pluginview/plugins/plugin1/plugin1.qbs +++ b/tests/manual/pluginview/plugins/plugin1/plugin1.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin1" targetName: "plugin1" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } Depends { name: "Manual test plugin2"} diff --git a/tests/manual/pluginview/plugins/plugin2/plugin2.qbs b/tests/manual/pluginview/plugins/plugin2/plugin2.qbs index f2cb5036f1b..4c97412990c 100644 --- a/tests/manual/pluginview/plugins/plugin2/plugin2.qbs +++ b/tests/manual/pluginview/plugins/plugin2/plugin2.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin2" targetName: "plugin2" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } diff --git a/tests/manual/pluginview/plugins/plugin3/plugin3.qbs b/tests/manual/pluginview/plugins/plugin3/plugin3.qbs index 884b850c6f9..659fcda5063 100644 --- a/tests/manual/pluginview/plugins/plugin3/plugin3.qbs +++ b/tests/manual/pluginview/plugins/plugin3/plugin3.qbs @@ -1,7 +1,10 @@ +import qbs.FileInfo + QtcManualtest { name: "Manual test plugin3" targetName: "plugin3" type: [ "dynamiclibrary" ] + destinationDirectory: FileInfo.cleanPath(FileInfo.joinPaths(base , "..")) Depends { name: "ExtensionSystem" } Depends { name: "Manual test plugin2" } diff --git a/tests/system/README b/tests/system/README index 05fe472d5ad..61847485fbf 100644 --- a/tests/system/README +++ b/tests/system/README @@ -5,6 +5,7 @@ Squish tests inside this folder have several prerequisites to get them running. First - and most important - you have to own a valid Squish license. At least Squish 6.0 is required. Second - some of the test suites/test cases expect a build of Qt 4.8.7 to be available: +[ this is optional and if Qt4 is not available some Qt5 will be tried to use instead ] 1. Download the source code from: * Windows: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.zip * Other: https://download.qt.io/archive/qt/4.8/4.8.7/qt-everywhere-opensource-src-4.8.7.tar.gz diff --git a/tests/system/shared/classes.py b/tests/system/shared/classes.py index a96a7e2d6e0..d43c15a63a3 100644 --- a/tests/system/shared/classes.py +++ b/tests/system/shared/classes.py @@ -48,7 +48,9 @@ class Targets: @staticmethod def availableTargetClasses(): availableTargets = set(Targets.ALL_TARGETS) - if platform.system() in ('Windows', 'Microsoft'): + if not qt4Available: + availableTargets.remove(Targets.DESKTOP_4_8_7_DEFAULT) + if not qt4Available or platform.system() in ('Windows', 'Microsoft'): availableTargets.remove(Targets.EMBEDDED_LINUX) elif platform.system() == 'Darwin': availableTargets.remove(Targets.DESKTOP_5_4_1_GCC) diff --git a/tests/system/shared/project.py b/tests/system/shared/project.py index c6015586f8e..85d8c1d5e6c 100644 --- a/tests/system/shared/project.py +++ b/tests/system/shared/project.py @@ -69,7 +69,10 @@ def openCmakeProject(projectPath, buildDir): invokeMenuItem("File", "Open File or Project...") selectFromFileDialog(projectPath) __chooseTargets__([]) # uncheck all - __chooseTargets__([Targets.DESKTOP_4_8_7_DEFAULT], additionalFunc=additionalFunction) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT # FIXME make the intended target a parameter + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + __chooseTargets__([targetToChoose], additionalFunc=additionalFunction) clickButton(waitForObject(":Qt Creator.Configure Project_QPushButton")) return True @@ -524,7 +527,8 @@ def __getSupportedPlatforms__(text, templateName, getAsStrings=False): result = set() if 'Desktop' in supports: if (version == None or version < "5.0") and not templateName.startswith("Qt Quick 2"): - result.add(Targets.DESKTOP_4_8_7_DEFAULT) + if qt4Available: + result.add(Targets.DESKTOP_4_8_7_DEFAULT) if platform.system() in ("Linux", "Darwin"): result.add(Targets.EMBEDDED_LINUX) result = result.union(set([Targets.DESKTOP_5_10_1_DEFAULT, Targets.DESKTOP_5_14_1_DEFAULT])) diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index 0618ce273da..4c9646ffb6d 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -39,6 +39,13 @@ try: except ImportError: import builtins as __builtin__ # Python 3 + +# ensure global variables are defined before including shared scripts +qt4Path = os.path.expanduser("~/Qt4.8.7") +if platform.system() in ('Windows', 'Microsoft'): + qt4Path = "C:\\Qt\\Qt4.8.7" + +qt4Available = os.path.exists(qt4Path) srcPath = '' SettingsPath = [] tmpSettingsDir = '' @@ -329,10 +336,8 @@ def copySettingsToTmpDir(destination=None, omitFiles=[]): # current dir is directory holding qtcreator.py origSettingsDir = os.path.abspath(os.path.join(os.getcwd(), "..", "..", "settings")) -qt4Path = os.path.expanduser("~/Qt4.8.7") if platform.system() in ('Windows', 'Microsoft'): - qt4Path = "C:\\Qt\\Qt4.8.7" origSettingsDir = os.path.join(origSettingsDir, "windows") elif platform.system() == 'Darwin': origSettingsDir = os.path.join(origSettingsDir, "mac") diff --git a/tests/system/suite_CSUP/tst_CSUP03/test.py b/tests/system/suite_CSUP/tst_CSUP03/test.py index 53b532c05de..a20ac19ea4f 100644 --- a/tests/system/suite_CSUP/tst_CSUP03/test.py +++ b/tests/system/suite_CSUP/tst_CSUP03/test.py @@ -78,8 +78,10 @@ def main(): continue if not startCreatorVerifyingClang(useClang): continue - projectName = createNewNonQtProject(tempDir(), "project-csup03", - [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + projectName = createNewNonQtProject(tempDir(), "project-csup03", [targetToChoose]) checkCodeModelSettings(useClang) openDocument("%s.Sources.main\\.cpp" % projectName) editor = getEditorForFileSuffix("main.cpp") diff --git a/tests/system/suite_HELP/tst_HELP04/test.py b/tests/system/suite_HELP/tst_HELP04/test.py index 18e3ee45639..83941679b9f 100644 --- a/tests/system/suite_HELP/tst_HELP04/test.py +++ b/tests/system/suite_HELP/tst_HELP04/test.py @@ -69,7 +69,8 @@ def main(): startQC() if not startedWithoutPluginError(): return - addHelpDocumentation([os.path.join(qt4Path, "doc", "qch", "qt.qch")]) + if qt4Available: + addHelpDocumentation([os.path.join(qt4Path, "doc", "qch", "qt.qch")]) # switch to help mode switchViewTo(ViewConstants.HELP) # verify that search widget is accessible diff --git a/tests/system/suite_general/tst_build_speedcrunch/test.py b/tests/system/suite_general/tst_build_speedcrunch/test.py index 8ba749b1680..e98a9b0e9a5 100644 --- a/tests/system/suite_general/tst_build_speedcrunch/test.py +++ b/tests/system/suite_general/tst_build_speedcrunch/test.py @@ -41,7 +41,10 @@ def main(): startQC() if not startedWithoutPluginError(): return - openQmakeProject(SpeedCrunchPath, [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + openQmakeProject(SpeedCrunchPath, [targetToChoose]) waitForProjectParsing() fancyToolButton = waitForObject(":*Qt Creator_Core::Internal::FancyToolButton") diff --git a/tests/system/suite_general/tst_openqt_creator/test.py b/tests/system/suite_general/tst_openqt_creator/test.py index ad1f4b52a25..6ff0bfb345e 100644 --- a/tests/system/suite_general/tst_openqt_creator/test.py +++ b/tests/system/suite_general/tst_openqt_creator/test.py @@ -36,7 +36,10 @@ def main(): return runButton = findObject(':*Qt Creator.Run_Core::Internal::FancyToolButton') - openQmakeProject(pathSpeedcrunch, [Targets.DESKTOP_4_8_7_DEFAULT]) + targetToChoose = Targets.DESKTOP_4_8_7_DEFAULT + if not qt4Available: + targetToChoose = Targets.DESKTOP_5_14_1_DEFAULT + openQmakeProject(pathSpeedcrunch, [targetToChoose]) # Wait for parsing to complete waitFor("runButton.enabled", 30000) # Starting before opening, because this is where Creator froze (QTCREATORBUG-10733)