diff --git a/dist/changelog/changes-13.0.0.md b/dist/changelog/changes-13.0.0.md index bd3fc5e3d51..793e47e97f2 100644 --- a/dist/changelog/changes-13.0.0.md +++ b/dist/changelog/changes-13.0.0.md @@ -34,18 +34,18 @@ General dock area * Added the option to show file paths relative to the active project to the search results view - (QTCREATORBUG-29462) + ([QTCREATORBUG-29462](https://bugreports.qt.io/browse/QTCREATORBUG-29462)) * Added a `Current` button for selecting the directory of the current document for searching in `Files in File System` * Added `Copy to Clipboard` to the `About Qt Creator` dialog - (QTCREATORBUG-29886) + ([QTCREATORBUG-29886](https://bugreports.qt.io/browse/QTCREATORBUG-29886)) Editing ------- * Made syntax highlighting asynchronous * Fixed that `Shift+Tab` did not always unindent - (QTCREATORBUG-29742) + ([QTCREATORBUG-29742](https://bugreports.qt.io/browse/QTCREATORBUG-29742)) * Fixed that `Surround text selection with brackets` did nothing for `<` * Fixed following links without a file name in documents without a file name @@ -53,34 +53,39 @@ Editing * Added the `Move Definition Here` refactoring action that moves an existing function definition to its declaration - (QTCREATORBUG-9515) + ([QTCREATORBUG-9515](https://bugreports.qt.io/browse/QTCREATORBUG-9515)) +* Added the `Enclose in QByteArrayLiteral` refactoring action + ([QTCREATORBUG-12995](https://bugreports.qt.io/browse/QTCREATORBUG-12995)) * Enabled the completion inside comments and strings by falling back to the built-in code model - (QTCREATORBUG-20828) + ([QTCREATORBUG-20828](https://bugreports.qt.io/browse/QTCREATORBUG-20828)) * Improved the position of headers inserted by refactoring operations - (QTCREATORBUG-21826) + ([QTCREATORBUG-21826](https://bugreports.qt.io/browse/QTCREATORBUG-21826)) * Improved the coding style settings by separating Clang Format and other coding style settings, and using a plain text editor for custom Clang Format settings * Fixed that the class wizards used the class name for the include guard instead of the file name - (QTCREATORBUG-30140) + ([QTCREATORBUG-30140](https://bugreports.qt.io/browse/QTCREATORBUG-30140)) * Fixed that renaming classes did not change the include directive for the renamed header in the source file - (QTCREATORBUG-30154) + ([QTCREATORBUG-30154](https://bugreports.qt.io/browse/QTCREATORBUG-30154)) * Fixed issues with refactoring template functions - (QTCREATORBUG-29408) + ([QTCREATORBUG-29408](https://bugreports.qt.io/browse/QTCREATORBUG-29408)) +* Fixed the `Add Definition` refactoring action for member functions of a + template class in a namespace + ([QTCREATORBUG-22076](https://bugreports.qt.io/browse/QTCREATORBUG-22076)) * Clangd * Fixed that `Follow Symbol Under Cursor` only worked for exact matches - (QTCREATORBUG-29814) + ([QTCREATORBUG-29814](https://bugreports.qt.io/browse/QTCREATORBUG-29814)) ### QML * Added navigation from QML components to the C++ code in the project - (QTCREATORBUG-28086) + ([QTCREATORBUG-28086](https://bugreports.qt.io/browse/QTCREATORBUG-28086)) * Added a button for launching the QML Preview on the current document to the editor tool bar * Added color previews when hovering Qt color functions - (QTCREATORBUG-29966) + ([QTCREATORBUG-29966](https://bugreports.qt.io/browse/QTCREATORBUG-29966)) ### Python @@ -95,7 +100,7 @@ Editing ### Widget Designer * Fixed the indentation of the code that is inserted by `Go to slot` - (QTCREATORBUG-11730) + ([QTCREATORBUG-11730](https://bugreports.qt.io/browse/QTCREATORBUG-11730)) ### Compiler Explorer @@ -108,6 +113,10 @@ Editing endings) to the tool bar * Added support for following links to the text editor +### Binary Files + +* Fixed issues with large addresses + Projects -------- @@ -115,41 +124,62 @@ Projects was configured for kits that have vanished, as a replacement for the automatic creation of "Replacement" kits * Added the status of devices to the device lists - (QTCREATORBUG-20941) + ([QTCREATORBUG-20941](https://bugreports.qt.io/browse/QTCREATORBUG-20941)) * Added the `Preferences > Build & Run > General > Application environment` option for globally modifying the environment for all run configurations - (QTCREATORBUG-29530) + ([QTCREATORBUG-29530](https://bugreports.qt.io/browse/QTCREATORBUG-29530)) * Added a file wizard for Qt translation (`.ts`) files - (QTCREATORBUG-29775) + ([QTCREATORBUG-29775](https://bugreports.qt.io/browse/QTCREATORBUG-29775)) * Increased the maximum width of the target selector - (QTCREATORBUG-30038) + ([QTCREATORBUG-30038](https://bugreports.qt.io/browse/QTCREATORBUG-30038)) * Fixed that the `Left` cursor key did not always collapse the current item - (QTBUG-118515) + ([QTBUG-118515](https://bugreports.qt.io/browse/QTBUG-118515)) * Fixed inconsistent folder hierarchies in the project tree - (QTCREATORBUG-29923) + ([QTCREATORBUG-29923](https://bugreports.qt.io/browse/QTCREATORBUG-29923)) ### CMake * Added support for custom output parsers for the configuration of projects - (QTCREATORBUG-29992) + ([QTCREATORBUG-29992](https://bugreports.qt.io/browse/QTCREATORBUG-29992)) * Made cache variables available even if project configuration failed +* CMake Presets + * Fixed `Reload CMake Presets` if the project was not configured yet + ([QTCREATORBUG-30238](https://bugreports.qt.io/browse/QTCREATORBUG-30238)) + * Fixed that kits were accumulating on the project setup page + ([QTCREATORBUG-29535](https://bugreports.qt.io/browse/QTCREATORBUG-29535)) + * Fixed that `binaryDir` was not handled for all presets + ([QTCREATORBUG-30236](https://bugreports.qt.io/browse/QTCREATORBUG-30236)) + * Fixed a freeze with nested presets + ([QTCREATORBUG-30288](https://bugreports.qt.io/browse/QTCREATORBUG-30288)) +* Conan + * Fixed that backslashes were wrongly used for paths on Windows + ([QTCREATORBUG-30326](https://bugreports.qt.io/browse/QTCREATORBUG-30326)) + +### Qbs + +* Added support for code completion with the Qbs language server + (QBS-395) ### Python * Added `Generate Kit` to the Python interpreter preferences for generating a Python kit with this interpreter * Added the target setup page when loading unconfigured Python projects +* Added a `requirements.txt` file to the application wizard * Fixed that the same Python interpreter could be auto-detected multiple times under different names Debugging --------- +* Added a `dr` locator filter for debugging a project + ### C++ +* Added a pretty printer for `std::tuple` * Fixed that breakpoints were not hit while the message dialog about missing debug information was shown - (QTCREATORBUG-30168) + ([QTCREATORBUG-30168](https://bugreports.qt.io/browse/QTCREATORBUG-30168)) ### Debug Adapter Protocol @@ -161,7 +191,7 @@ Analyzer ### Clang * Added `Edit Checks as Strings` for Clazy - (QTCREATORBUG-24846) + ([QTCREATORBUG-24846](https://bugreports.qt.io/browse/QTCREATORBUG-24846)) ### Axivion @@ -171,16 +201,19 @@ Terminal -------- * Added `Select All` to the context menu - (QTCREATORBUG-29922) + ([QTCREATORBUG-29922](https://bugreports.qt.io/browse/QTCREATORBUG-29922)) * Fixed the startup performance on Windows - (QTCREATORBUG-29840) + ([QTCREATORBUG-29840](https://bugreports.qt.io/browse/QTCREATORBUG-29840)) * Fixed the integration of the `fish` shell * Fixed that `Ctrl+W` closed the terminal even when shortcuts were blocked - (QTCREATORBUG-30070) + ([QTCREATORBUG-30070](https://bugreports.qt.io/browse/QTCREATORBUG-30070)) +* Fixed issues with Windows Powershell Version Control Systems ----------------------- +* Added support for remote version control operations + ### Git * Added the upstream status for untracked branches to `Branches` view @@ -195,22 +228,27 @@ Test Integration Platforms --------- +### Windows + +* Fixed Clang compiler ABI detection for WOA64 + ([QTCREATORBUG-30060](https://bugreports.qt.io/browse/QTCREATORBUG-30060)) + ### Android * Add support for target-based android-build directories (??? is that ready? Qt 6.8+ ???) - (QTBUG-117443) + ([QTBUG-117443](https://bugreports.qt.io/browse/QTBUG-117443)) ### iOS * Fixed the detection of iOS 17 devices * Fixed deployment and running applications for iOS 17 devices (application output, debugging, and profiling are not supported) - (QTCREATORBUG-29682) + ([QTCREATORBUG-29682](https://bugreports.qt.io/browse/QTCREATORBUG-29682)) ### Remote Linux * Fixed that debugging unnecessarily downloaded files from the remote system - (QTCREATORBUG-29614) + ([QTCREATORBUG-29614](https://bugreports.qt.io/browse/QTCREATORBUG-29614)) Credits for these changes go to: -------------------------------- @@ -238,6 +276,7 @@ Esa Törmänen Fabian Kosmale Friedemann Kleint Henning Gruendl +Ilya Kulakov Jaroslaw Kobus Johanna Vanhatapio Karim Abdelrahman @@ -249,6 +288,7 @@ Marcus Tillmanns Mathias Hasselmann Mats Honkamaa Mehdi Salem +Michael Weghorn Miikka Heikkinen Mitch Curtis Olivier De Cannière @@ -257,6 +297,7 @@ Pranta Dastider Robert Löhning Sami Shalayel Samuel Jose Raposo Vieira Mira +Samuel Mira Serg Kryvonos Shrief Gabr Sivert Krøvel diff --git a/doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp b/doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp new file mode 100644 index 00000000000..f8eaa1dac52 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-code-style-built-in-indenter.webp differ diff --git a/doc/qtcreator/images/qtcreator-code-style-clang-format-global.webp b/doc/qtcreator/images/qtcreator-code-style-clang-format-global.webp index c012f83ce9a..ddfc428e8c4 100644 Binary files a/doc/qtcreator/images/qtcreator-code-style-clang-format-global.webp and b/doc/qtcreator/images/qtcreator-code-style-clang-format-global.webp differ diff --git a/doc/qtcreator/images/qtcreator-code-style-clang-format-project.webp b/doc/qtcreator/images/qtcreator-code-style-clang-format-project.webp index dc4aefecd15..5c210034ec8 100644 Binary files a/doc/qtcreator/images/qtcreator-code-style-clang-format-project.webp and b/doc/qtcreator/images/qtcreator-code-style-clang-format-project.webp differ diff --git a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png b/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png deleted file mode 100644 index 34473e4bd89..00000000000 Binary files a/doc/qtcreator/images/qtcreator-code-style-settings-edit-qtquick.png and /dev/null differ diff --git a/doc/qtcreator/images/qtcreator-new-file-ts.webp b/doc/qtcreator/images/qtcreator-new-file-ts.webp new file mode 100644 index 00000000000..3ad21a25d91 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-new-file-ts.webp differ diff --git a/doc/qtcreator/images/qtcreator-options-code-style-qml.png b/doc/qtcreator/images/qtcreator-options-code-style-qml.png deleted file mode 100644 index 93bf1bdfb8b..00000000000 Binary files a/doc/qtcreator/images/qtcreator-options-code-style-qml.png and /dev/null differ diff --git a/doc/qtcreator/images/qtcreator-preferences-nim-code-style.webp b/doc/qtcreator/images/qtcreator-preferences-nim-code-style.webp index d6937200c4e..8fa9bb08376 100644 Binary files a/doc/qtcreator/images/qtcreator-preferences-nim-code-style.webp and b/doc/qtcreator/images/qtcreator-preferences-nim-code-style.webp differ diff --git a/doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp b/doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp new file mode 100644 index 00000000000..574f30dd64d Binary files /dev/null and b/doc/qtcreator/images/qtcreator-preferences-qtquick-code-style.webp differ diff --git a/doc/qtcreator/images/qtcreator-project-kits.png b/doc/qtcreator/images/qtcreator-project-kits.png deleted file mode 100644 index 16bf3a0dad0..00000000000 Binary files a/doc/qtcreator/images/qtcreator-project-kits.png and /dev/null differ diff --git a/doc/qtcreator/images/qtcreator-projects-kits.webp b/doc/qtcreator/images/qtcreator-projects-kits.webp index 6f863df9a50..827037b0223 100644 Binary files a/doc/qtcreator/images/qtcreator-projects-kits.webp and b/doc/qtcreator/images/qtcreator-projects-kits.webp differ diff --git a/doc/qtcreator/images/qtcreator-projects-vanished-targets.webp b/doc/qtcreator/images/qtcreator-projects-vanished-targets.webp new file mode 100644 index 00000000000..f4acd354b1c Binary files /dev/null and b/doc/qtcreator/images/qtcreator-projects-vanished-targets.webp differ diff --git a/doc/qtcreator/src/editors/creator-code-completion.qdoc b/doc/qtcreator/src/editors/creator-code-completion.qdoc index 522565eecbd..4281f77b672 100644 --- a/doc/qtcreator/src/editors/creator-code-completion.qdoc +++ b/doc/qtcreator/src/editors/creator-code-completion.qdoc @@ -183,8 +183,7 @@ skipped when you type, and removed when you press \key Backspace. \if defined(qtcreator) - \sa {Complete CMake code}, - {Enclose selected code in curly braces, parentheses, or double quotes}, {Nim} + \sa {Complete CMake code}, {Enclose code in brackets or quotes}, {Nim} \endif \sa {Complete code}, {Snippets} diff --git a/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc b/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc index 44622426af8..56e413b7e93 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-preferences-cpp-code-style.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -18,30 +18,39 @@ To specify global indentation settings for the C++ editor: \list 1 - \li Select \preferences > \uicontrol {C++}. + \li Go to \preferences > \uicontrol {C++}. \image qtcreator-code-style-clang-format-global.webp {Code Style preferences} \li In \uicontrol {Formatting mode}, select: \list \li \uicontrol {Indenting Only} to only indent code. \li \uicontrol {Full Formatting} to use the \key {Ctrl+I} keyboard shortcut to format code instead of indenting. - \li \uicontrol Disable to turn off ClangFormat. + \li \uicontrol {Use Built-In Indenter} to turn off ClangFormat. \endlist + \li Select \uicontrol {Ignore files greater than} to make parsing faster + by ignoring big files. Specify the maximum size of files to parse. \li To apply the formatting while you type, select \uicontrol {Format while typing}. \li To apply the formatting to the edited code when you save the file, select \uicontrol {Format edited code on file save}. \li To change the ClangFormat style globally for all projects, - select \uicontrol {Override ClangFormat configuration file}. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. - \li Give a name to the settings and click \uicontrol OK. - \li Click \uicontrol Edit to set + select \uicontrol {Use custom settings}. + \li In \uicontrol {Custom settings}, select the settings to change, and + then select \uicontrol Copy. + \li Give a name to the settings, and select \uicontrol OK. + \li In \uicontrol ClangFormat, edit the \l{https://clang.llvm.org/docs/ClangFormatStyleOptions.html} - {ClangFormat Style Options}. + {ClangFormat Style Options}. The live preview shows how the + preferences change the indentation. + If you enter invalid values, you see warning messages. \endlist - In the other tabs, you can specify how to: + \section1 Using Built-In Indenter + + \image qtcreator-code-style-built-in-indenter.webp {Code Style preferences for built-in indenter} + + If you select \uicontrol {Use Built-In Indenter} in + \uicontrol {Formatting mode}, you can specify how to: \list \li Interpret the \key Tab and \key Backspace key presses. @@ -52,12 +61,9 @@ \li Bind pointers (*) and references (&) in types and declarations to identifiers, type names, or left or right \c const or \c volatile keywords. - \li Name getter functions. \endlist - Use the live preview to see how the preferences change the indentation. - - \section1 Specifying Settings for Content + \section2 Specifying Settings for Content You can indent public, protected, and private statements and declarations related to them within classes. @@ -67,24 +73,24 @@ \image qtcreator-code-style-content.png {Content preferences} - \section1 Specifying Settings for Braces + \section2 Specifying Settings for Braces You can indent class, namespace, enum and function declarations and code blocks. \image qtcreator-code-style-braces.png {Braces preferences} - \section1 Specifying Settings for Switch Statements + \section2 Specifying Settings for Switch Statements You can indent case or default statements, or statements or blocks related to them within switch statements. \image qtcreator-code-style-switch.png {Switch preferences} - \section1 Specifying Alignment + \section2 Specifying Alignment To align continuation lines to tokens after assignments, such as \c = or - \c +=, select the \uicontrol {Align after assignments} check box. You can + \c +=, select \uicontrol {Align after assignments}. You can specify additional settings for aligning continuation lines in the \uicontrol General tab. @@ -94,7 +100,7 @@ \image qtcreator-code-style-alignment.png {Alignment preferences} - \section1 Binding Pointers and References + \section2 Binding Pointers and References To bind pointers (\c *) and references (\c &) in types and declarations to identifiers, type names, or left or right \c const or \c volatile keywords, @@ -105,15 +111,6 @@ \image qtcreator-pointers-references.png {Pointers and References preferences} - \section1 Creating Project-Specific ClangFormat Files - - To override the \c {.clang-format} file for a particular project, create a - copy of the built-in style and edit its settings by selecting - \uicontrol Projects > \uicontrol {Project Settings} > - \uicontrol {Code Style} > \uicontrol Copy > \uicontrol Edit > - \uicontrol {ClangFormat} > - \uicontrol {Override ClangFormat configuration file}. - \section1 Creating ClangFormat Files from Command Line You can create \c {.clang-format} files that have the configuration @@ -124,5 +121,6 @@ clang-format -style=llvm -dump-config > .clang-format \endcode - \sa {Indent text or code}, {Behavior}, {Qt Quick Code Style}, {Nim} + \sa {Indent text or code}, {Specify code style}, {Behavior}, + {Qt Quick Code Style}, {Nim} */ diff --git a/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc b/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc index fa84ef87ca7..b5a62ae20c4 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-preferences-nim.qdoc @@ -16,11 +16,11 @@ To specify preferences for the Nim editor (experimental): \list 1 - \li Select \preferences > \uicontrol Nim. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. + \li Go to \preferences > \uicontrol Nim. + \li In \uicontrol {Custom settings}, select the settings to + modify, and then select \uicontrol Copy. \image qtcreator-preferences-nim-code-style.webp {Nim Code Style preferences} - \li Give a name to the settings and click \uicontrol OK. + \li Give a name to the settings, and select \uicontrol OK. \li Specify how to interpret the \key Tab key presses and how to align continuation lines. \li Select \uicontrol OK to save the settings. @@ -36,7 +36,7 @@ completion. To use Nimsuggest, you must install it on the development PC and enter the - path to the tool executable in the \uicontrol Path field. + path to the tool executable in \uicontrol Path. \image qtcreator-preferences-nim-tools.webp diff --git a/doc/qtcreator/src/howto/creator-external-tools.qdoc b/doc/qtcreator/src/howto/creator-external-tools.qdoc index 3f29dfc57bf..dda7eeb62ae 100644 --- a/doc/qtcreator/src/howto/creator-external-tools.qdoc +++ b/doc/qtcreator/src/howto/creator-external-tools.qdoc @@ -134,18 +134,30 @@ \title Use Qt Linguist + Most of the text to translate in an application consists of either single + words or short phrases. These typically appear as window titles, menu items, + tooltips, and labels to buttons, checkboxes, and radio buttons. + + You mark the phrases as translatable in the QML and C++ source code. Qt + localization tools provide context information for each of the phrases to + help the translator understand their meaning. You can add comments to the + phrases. + + Translation files contain all the user-visible text and keyboard shortcuts + in an application and translations of that text. + When you \l{Creating Projects}{create a new project}, you can automatically - generate a translation source file (TS) for one language. You can add other - languages later by editing the project file. + generate a translation source file (TS) for one language. To add other + languages, edit the project file or go to \uicontrol File > + \uicontrol {New File}. To open TS files in Qt Linguist, right-click a TS file in the - \uicontrol Projects or \uicontrol {File System} view and select + \uicontrol Projects or \uicontrol {File System} view and go to \uicontrol {Open With} > \uicontrol {Qt Linguist} in the context menu. - For more information about Qt Linguist, see \l{Qt Linguist Manual}. \section1 Use lupdate and lrelease - You can use the Qt Linguist release manager tools, lupdate and lrelease, + Use the Qt Linguist release manager tools, lupdate and lrelease, directly from \QC. The lupdate tool synchronizes source code and translations. The lrelease tool creates run-time translation files for use by the released application. @@ -156,22 +168,27 @@ {Qt6::LinguistTools}. By default, the project .pro file is passed to the tools as an argument. To - specify other command-line arguments for the tools, select \uicontrol Tools > + specify other command-line arguments for the tools, go to \uicontrol Tools > \uicontrol External > \uicontrol Configure. \section2 Synchronize TS files To synchronize TS files from a translator with the - application code, select \uicontrol Tools > \uicontrol External > + application code, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Update Translations (lupdate)}. \section2 Generate QM files To generate from the TS files Qt message (QM) files that can be used by an - application, select \uicontrol Tools > \uicontrol External > + application, go to \uicontrol Tools > \uicontrol External > \uicontrol Linguist > \uicontrol {Release Translations (lrelease)}. - \sa {Use external tools} + \if defined(qtcreator) + \sa {Add translation files} + \endif + + \sa {Use external tools}, {Internationalization with Qt}, + {Qt Linguist Manual} */ /*! diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc new file mode 100644 index 00000000000..93b8844f240 --- /dev/null +++ b/doc/qtcreator/src/howto/creator-only/creator-how-to-contact-qt.qdoc @@ -0,0 +1,49 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-contact-qt.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-use + + \title Contact Qt + + To report bugs and tell us what you think about \QC and Qt, + go to \uicontrol Help. + + \section1 Report bugs and suggest improvements + + To report bugs and add suggestions for improvement to the + \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}, + go to \uicontrol Help > \uicontrol {Report Bug}. + + To copy information about your \QC version that you can paste to the bug + report, go to \uicontrol Help > \uicontrol {About \QC} and select + \uicontrol {Copy and Close}. + + To copy detailed information about your system that you can paste to the bug + report, go to \uicontrol Help > \uicontrol {System Information} and select + \uicontrol {Copy to Clipboard}. + + To get commercial Qt support, go to \uicontrol Help > + \uicontrol {Commercial Qt Support} and create a service request. + To check your licenses and services, go to \uicontrol Help > + \uicontrol {Qt Account}. + + \section1 Give feedback + + To rate \QC and send us feedback, go to \uicontrol Help > + \uicontrol {Give Feedback}. + + Or, give feedback from your Qt account. + + \section1 Join discussions + + To join the \l{https://lists.qt-project.org/listinfo/qt-creator} + {\QC mailing list} or \l{https://web.libera.chat/#qt-creator} + {#qt-creator} channel on Libera.Chat IRC, go to \uicontrol Help > + \uicontrol Contact. + + \sa {Pasting and Fetching Code Snippets}, {Technical Support} +*/ diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc index 8de74cf8420..0643c3a1525 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-tos.qdoc @@ -77,7 +77,7 @@ \generatelist creator-how-to-projects-create - \section2 Create Files + \section2 Add Files \generatelist creator-how-to-projects-files @@ -288,16 +288,18 @@ \ingroup creator-how-to-edit - \title Enclose selected code in curly braces, parentheses, or double quotes + \title Enclose code in brackets or quotes - When you have selected code and enter one of the following opening - characters, the matching closing character is added automatically - at the end of the selection: + Select code and enter one of the following opening characters to add + the matching closing character at the end of the selection: \list - \li { \li ( + \li { + \li [ + \li < \li " + \li ' \endlist To specify whether to automatically insert matching characters, diff --git a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc index db2af2c5ebf..de7c8b45d3d 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-issues.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -8,20 +8,22 @@ // ********************************************************************** /*! - \previouspage creator-how-tos.html \page creator-known-issues.html - \nextpage creator-glossary.html + \previouspage creator-reference.html + + \ingroup creator-reference \title Known Issues - This section lists known issues in \QC version \qtcversion. The development - team is aware of them, and therefore, you do not need to report them as - bugs. + \brief Known issues in \QC version \qtcversion. - For a list of fixed issues and added features, see the changelog file in - the \c{qtcreator\dist} folder or the \l{https://bugreports.qt.io} + The \QC development team is aware of the issues described here, and + therefore, you do not need to report them in the \l{https://bugreports.qt.io} {Qt Project Bug Tracker}. + For a list of fixed issues and added features, go to \uicontrol Help > + \uicontrol {Change Log}. + \section1 General Issues \list diff --git a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc index 6b953d4401d..d03263d4625 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-files-creating.qdoc @@ -43,8 +43,8 @@ \li \uicontrol {Qt} \li Source and header files for item, table, or list models, \QD forms and a matching classes for Qt Widgets - projects, Qt resource files, as well as QML and JavaScript files - for Qt Quick projects. + projects, Qt resource and translation files, as well as QML and + JavaScript files for Qt Quick projects. \row \li \uicontrol {Compiler Explorer} \li Example setup for using Compiler Explorer to compile C++ or Python @@ -74,9 +74,7 @@ \li Empty Nim source and script files. \endtable - \sa {Create compiler explorer sessions}, {Create C++ classes}, - {Create OpenGL fragment and vertex shaders}, {Create resource files}, - {Create UML-style models}, {Create vcpkg manifest files}, + \sa {Add Files}{How To: Add Files}, {Create UML-style models}, {Use project wizards} */ diff --git a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc new file mode 100644 index 00000000000..cb4471aeb5d --- /dev/null +++ b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-ts-files.qdoc @@ -0,0 +1,30 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \page creator-how-to-add-ts-files.html + \previouspage creator-how-tos.html + + \ingroup creator-how-to-projects-files + + \title Add translation files + + When you \l{Creating Projects}{create a new project}, you can automatically + generate a translation source file (TS) for one language. To add other + languages later, use a file wizard. + + To create a translation source (TS) file for a language: + + \list 1 + \li Go to \uicontrol File > \uicontrol {New File}. + \li Select \uicontrol Qt > \uicontrol {Qt Translation File} > + \uicontrol Choose. + \li In \uicontrol Language, select a language and territory (\e locale). + \image qtcreator-new-file-ts.webp {Select language for a TS file} + \endlist + + You can see the file name in \uicontrol {Translation file}. + + \sa {Create files}, {Use project wizards}, {Use Qt Linguist}, + {Internationalization with Qt}, {Qt Linguist Manual} +*/ diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc index e60d5c49c52..88e0354aaa9 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-code-style.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only // ********************************************************************** @@ -19,16 +19,15 @@ and editor the file opens in. \QC opens C++ files in \uicontrol Edit mode in the C++ code editor and QML files in the Qt Quick editor. - You can specify indentation for: + Specify indentation for: \list \li C++ files \li QML files \li Nim files - \li Other text files \endlist - You can specify code style either globally or separately for each project. + Specify code style either globally or separately for each project. You can specify several sets of code style settings and easily switch between them. In addition, you can import and export code style settings. @@ -36,31 +35,30 @@ \list 1 - \li Select \uicontrol Projects > \uicontrol {Project Settings} > + \li Go to \uicontrol Projects > \uicontrol {Project Settings} > \uicontrol {Code Style}. \image qtcreator-code-style-clang-format-project.webp {Code Style settings in Projects mode} - \li In the \uicontrol Language field, select \uicontrol C++, + \li In \uicontrol Language, select \uicontrol C++, \uicontrol {Qt Quick}, or \uicontrol Nim. - \li Deselect the \uicontrol {Use global settings} check box. + \li For C++, clear \uicontrol {Use global settings} to use the + \c {.clang-format} file for the project. - \li In the \uicontrol {Current settings} field, select the settings to modify - and click \uicontrol Copy. - - \li Give a name to the settings and click \uicontrol OK. - - \li Click \uicontrol Edit to specify a code style for the project. + \li To override the project's \c {.clang-format} file, + select \uicontrol {Use custom settings}. + \li In \uicontrol {Custom settings}, select the settings to use for the + project. \endlist In rare cases, ClangFormat can trip over a code construct and trigger a \QC crash. If that happens for your project, select - \uicontrol Disable as the formatting mode to switch - ClangFormat off for the project. If you can reproduce the crash, - please select \uicontrol Help > \uicontrol {Report Bug} to report - the bug and and attach the code that triggers the crash. + \uicontrol {Use Built-In Indenter} in \uicontrol {Formatting mode} to + turn off ClangFormat for the project. If you can reproduce the crash, + go to \uicontrol Help > \uicontrol {Report Bug} to report + the bug and attach the code that triggers the crash to the bug report. \sa {Indent text or code}, {Edit MIME types}, {C++ Code Style}, {Qt Quick Code Style}, {Nim} diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc index 6a883e8666d..3f200320fc1 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-environment.qdoc @@ -87,7 +87,25 @@ To run in a clean system environment, select \uicontrol {Clean Environment}. - \section2 Run on devices + \section2 Set the environment for all run configurations + + To set environment variables for running and debugging applications, so + that they don't affect \QC itself, set environment variables for run + configurations of all projects: + + \list 1 + \li Go to \preferences > \uicontrol {Build & Run} > \uicontrol General. + \li Select \uicontrol Change in \uicontrol {Application environment}. + \li Set environment variables in \uicontrol {Edit Environment}. + \image qtcreator-edit-environment.webp {Edit Environment dialog} + \endlist + + For example, set \c QT_FORCE_STDERR_LOGGING=1 to see application output + in \l {Application Output} instead of a journal or system log. + + Or, set \c QT_MESSAGE_PATTERN to add information to debugging messages. + + \section2 Use device environment When running on a mobile device connected to the development host, \QC fetches information about the \uicontrol {Device Environment} from the device. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc index 458e21c0a0d..27ff2fccff9 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc @@ -112,21 +112,13 @@ lists the kits that are compatible with your project. To activate one or more kits, click them. - \image qtcreator-project-kits.png {List of kits in Projects mode sidebar} + \image qtcreator-projects-kits.webp {List of kits in Projects mode sidebar} The list displays kits from \preferences > \uicontrol Kits. Warning and error icons indicate that the kit configuration is not suitable for the project type. To view the warning and error messages, move the mouse pointer over the kit name. - In the list of kits, you may see entries described as \e {Replacement for - }. \QC generates them to save your project-specific settings, - such as custom build flags or run configuration arguments that would - disappear if the corresponding kits were simply removed when you remove - Qt versions while updating your Qt installation. You can modify the kit - configuration to use a currently installed Qt version and save the kit - under a new name. - \section1 Manage kits To modify kit configuration or to \l{Add kits}{add kits} to the list or to @@ -134,10 +126,11 @@ Each kit consists of a set of values that define one environment, such as a \l{glossary-device}{device}, \l{Add compilers}{compiler}, - \l{Add debuggers}{debugger}, and \l{Add Qt versions}{Qt version}. + \l{Add debuggers}{debugger}, and \l{Add Qt versions}{Qt version}, as well + as steps for building, deploying, and running applications. - To copy the build and run settings for a kit to another kit, select - \uicontrol {Copy Steps from Other Kit} in the context menu. + To copy the build, deploy, and run steps from another kit, select + \uicontrol {Copy Steps from Another Kit} in the context menu. To deactivate a kit, select \uicontrol {Disable Kit for Project} in the context menu. @@ -148,5 +141,32 @@ To import an existing build for the project, select \uicontrol {Import Existing Build}. + \section1 Copy custom settings from vanished targets + + \QC creates a list of \uicontrol {Vanished Targets} to save project-specific + settings, such as custom build flags or run configuration arguments, that + would disappear if \QOI removes the corresponding kits when you update your + Qt installation. + + \image qtcreator-projects-vanished-targets.webp {Vanished Targets in Projects} + + Go to one of the following options in the context menu to restore the + project's settings: + + \list + \li \uicontrol {Create a New Kit} creates a new kit with the same name + for the same device type, with the original build, deploy, and run + steps. Other kit settings are not restored. + \li \uicontrol {Copy Steps to Another Kit} copies the build, deploy, and + run steps to another kit. + \endlist + + To remove vanished targets, go to \uicontrol {Remove Vanished Target} or + \uicontrol {Remove All Vanished Targets} in the context menu. + + \note Since version 13.0, \QC does not create \e {replacement kits}, but you + might still see them listed for existing projects. You can copy the build, + deploy, and run steps from them to other kits. + \sa {Add kits}, {Configuring Projects}, {kits-tab}{Kits} */ diff --git a/doc/qtcreator/src/qtcreator-toc.qdoc b/doc/qtcreator/src/qtcreator-toc.qdoc index 5f2daf2737f..ec8408795fc 100644 --- a/doc/qtcreator/src/qtcreator-toc.qdoc +++ b/doc/qtcreator/src/qtcreator-toc.qdoc @@ -157,7 +157,7 @@ \list \li Create Projects \generatelist creator-how-to-projects-create - \li Create Files + \li Add Files \generatelist creator-how-to-projects-files \li Configure Projects \generatelist creator-how-to-projects-configure diff --git a/doc/qtcreator/src/qtcreator.qdoc b/doc/qtcreator/src/qtcreator.qdoc index 840ef3805bc..7c2d8ce775e 100644 --- a/doc/qtcreator/src/qtcreator.qdoc +++ b/doc/qtcreator/src/qtcreator.qdoc @@ -86,6 +86,7 @@ \endlist \li \b {\l{Reference}} \list + \li \l {Acknowledgements} \li \l {Build Systems} \li \l {Command-Line Options} \li \l {Custom Wizards} @@ -94,21 +95,5 @@ \li \l {Supported Platforms} \li \l {Reference}{See More...} \endlist - \row - \li {4,1} \b {Contact Us} - \list - \li To report bugs and suggestions to the - \l{https://bugreports.qt.io/}{Qt Project Bug Tracker}, - select \uicontrol Help > \uicontrol {Report Bug}. - \li To copy and paste detailed information about your - system to the bug report, select \uicontrol Help > - \uicontrol {System Information}. - \li To join the \l{https://lists.qt-project.org/listinfo/qt-creator} - {\QC mailing list} or \l{https://web.libera.chat/#qt-creator} - {#qt-creator} channel on Libera.Chat IRC, select - \uicontrol Help > \uicontrol Contact. - \li For credits and a list of third-party libraries, see - \l {Acknowledgements}. - \endlist \endtable */ diff --git a/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc b/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc index 6ea13251620..70655b99edd 100644 --- a/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc +++ b/doc/qtcreator/src/qtquick/creator-preferences-qtquick-code-style.qdoc @@ -19,21 +19,17 @@ To specify QML code style globally: \list 1 - \li Select \preferences > \uicontrol {Qt Quick}. - \li In the \uicontrol {Current settings} field, select the settings to - modify and click \uicontrol Copy. - \image qtcreator-options-code-style-qml.png {QML Code Style preferences} - \li Give a name to the settings and click \uicontrol OK. - \li Click \uicontrol Edit to specify code style settings for the project. - \image qtcreator-code-style-settings-edit-qtquick.png {Edit Code Style dialog} + \li Go to \preferences > \uicontrol {Qt Quick} > \uicontrol {Code Style}. + \li In \uicontrol {Custom settings}, select the settings to + modify, and then select \uicontrol Copy. + \image qtcreator-preferences-qtquick-code-style.webp {Qt Quick Code Style preferences} + \li Give a name to the settings, and select \uicontrol OK. + \li Specify how to interpret the \key Tab key presses and how to align + continuation lines. + \li In \uicontrol {Line length}, set the maximum line length for + code lines. \endlist - You can specify how to interpret the \key Tab key presses and how to align - continuation lines. - - In \uicontrol {Line length}, you can adjust the maximum line length for - code lines. - To override the global preferences for a particular project, select \uicontrol Projects > \uicontrol {Code Style}. diff --git a/share/qtcreator/debugger/creatortypes.py b/share/qtcreator/debugger/creatortypes.py index 24c16ce0094..ba5b53450b0 100644 --- a/share/qtcreator/debugger/creatortypes.py +++ b/share/qtcreator/debugger/creatortypes.py @@ -204,7 +204,7 @@ def qdump__CPlusPlus__Internal__Value(d, value): def qdump__Utils__FilePath(d, value): data, path_len, scheme_len, host_len = d.split("{@QString}IHH", value) - elided, enc = d.encodeStringHelper(data, d.displayStringLimit) + length, enc = d.encodeStringHelper(data, d.displayStringLimit) # enc is concatenated path + scheme + host if scheme_len: scheme_pos = path_len * 4 @@ -221,7 +221,7 @@ def qdump__Utils__FilePath(d, value): val += path_enc else: val = enc - d.putValue(val, "utf16", elided=elided) + d.putValue(val, "utf16", length=length) d.putPlainChildren(value) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 1fd42848d4e..ad25ad2dbeb 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -44,15 +44,15 @@ class ReportItem(): subsequent better guesses during a putItem() run. """ - def __init__(self, value=None, encoding=None, priority=-100, elided=None): + def __init__(self, value=None, encoding=None, priority=-100, length=None): self.value = value self.priority = priority self.encoding = encoding - self.elided = elided + self.length = length def __str__(self): - return 'Item(value: %s, encoding: %s, priority: %s, elided: %s)' \ - % (self.value, self.encoding, self.priority, self.elided) + return 'Item(value: %s, encoding: %s, priority: %s, length: %s)' \ + % (self.value, self.encoding, self.priority, self.length) class Timer(): @@ -349,8 +349,8 @@ class DumperBase(): else: if self.currentValue.encoding is not None: self.put('valueencoded="%s",' % self.currentValue.encoding) - if self.currentValue.elided: - self.put('valueelided="%s",' % self.currentValue.elided) + if self.currentValue.length: + self.put('valuelen="%s",' % self.currentValue.length) self.put('value="%s",' % self.currentValue.value) except: pass @@ -376,7 +376,7 @@ class DumperBase(): b = bytes(bytearray.fromhex(value)) value = codecs.decode(b, 'utf-16') self.put('"%s"' % value) - if self.currentValue.elided: + if self.currentValue.length: self.put('...') if self.currentType.value: @@ -545,40 +545,40 @@ class DumperBase(): # assume no Qt 3 support by default return False - # Clamps size to limit. - def computeLimit(self, size, limit): + # Clamps length to limit. + def computeLimit(self, length, limit=0): if limit == 0: limit = self.displayStringLimit - if limit is None or size <= limit: - return 0, size - return size, limit + if limit is None or length <= limit: + return length + return limit def vectorData(self, value): if self.qtVersion() >= 0x060000: - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) elif self.qtVersion() >= 0x050000: vector_data_ptr = self.extractPointer(value) if self.ptrSize() == 4: - (ref, size, alloc, offset) = self.split('IIIp', vector_data_ptr) + (ref, length, alloc, offset) = self.split('IIIp', vector_data_ptr) else: - (ref, size, alloc, pad, offset) = self.split('IIIIp', vector_data_ptr) + (ref, length, alloc, pad, offset) = self.split('IIIIp', vector_data_ptr) alloc = alloc & 0x7ffffff data = vector_data_ptr + offset else: vector_data_ptr = self.extractPointer(value) - (ref, alloc, size) = self.split('III', vector_data_ptr) + (ref, alloc, length) = self.split('III', vector_data_ptr) data = vector_data_ptr + 16 - self.check(0 <= size and size <= alloc and alloc <= 1000 * 1000 * 1000) - return data, size + self.check(0 <= length and length <= alloc and alloc <= 1000 * 1000 * 1000) + return data, length def qArrayData(self, value): if self.qtVersion() >= 0x60000: - dd, data, size = self.split('ppp', value) + dd, data, length = self.split('ppp', value) if dd: _, _, alloc = self.split('iip', dd) else: # fromRawData - alloc = size - return data, size, alloc + alloc = length + return data, length, alloc return self.qArrayDataHelper(self.extractPointer(value)) def qArrayDataHelper(self, array_data_ptr): @@ -586,10 +586,10 @@ class DumperBase(): if self.qtVersion() >= 0x050000: # QTypedArray: # - QtPrivate::RefCount ref - # - int size + # - int length # - uint alloc : 31, capacityReserved : 1 # - qptrdiff offset - (ref, size, alloc, offset) = self.split('IIpp', array_data_ptr) + (ref, length, alloc, offset) = self.split('IIpp', array_data_ptr) alloc = alloc & 0x7ffffff data = array_data_ptr + offset if self.ptrSize() == 4: @@ -599,43 +599,42 @@ class DumperBase(): elif self.qtVersion() >= 0x040000: # Data: # - QBasicAtomicInt ref; - # - int alloc, size; + # - int alloc, length; # - [padding] # - char *data; if self.ptrSize() == 4: - (ref, alloc, size, data) = self.split('IIIp', array_data_ptr) + (ref, alloc, length, data) = self.split('IIIp', array_data_ptr) else: - (ref, alloc, size, pad, data) = self.split('IIIIp', array_data_ptr) + (ref, alloc, length, pad, data) = self.split('IIIIp', array_data_ptr) else: # Data: # - QShared count; # - QChar *unicode # - char *ascii # - uint len: 30 - (dummy, dummy, dummy, size) = self.split('IIIp', array_data_ptr) - size = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff - alloc = size # pretend. + (dummy, dummy, dummy, length) = self.split('IIIp', array_data_ptr) + length = self.extractInt(array_data_ptr + 3 * self.ptrSize()) & 0x3ffffff + alloc = length # pretend. data = self.extractPointer(array_data_ptr + self.ptrSize()) - return data, size, alloc + return data, length, alloc def encodeStringHelper(self, value, limit): - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) if alloc != 0: - self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) - elided, shown = self.computeLimit(2 * size, 2 * limit) - return elided, self.readMemory(data, shown) + self.check(0 <= length and length <= alloc and alloc <= 100 * 1000 * 1000) + shown = self.computeLimit(2 * length, 2 * limit) + return length, self.readMemory(data, shown) def encodeByteArrayHelper(self, value, limit): - data, size, alloc = self.qArrayData(value) + data, length, alloc = self.qArrayData(value) if alloc != 0: - self.check(0 <= size and size <= alloc and alloc <= 100 * 1000 * 1000) - elided, shown = self.computeLimit(size, limit) - return elided, self.readMemory(data, shown) + self.check(0 <= length and length <= alloc and alloc <= 100 * 1000 * 1000) + shown = self.computeLimit(length, limit) + return length, self.readMemory(data, shown) - def putCharArrayValue(self, data, size, charSize, + def putCharArrayValue(self, data, length, charSize, displayFormat=DisplayFormat.Automatic): - bytelen = size * charSize - elided, shown = self.computeLimit(bytelen, self.displayStringLimit) + shown = self.computeLimit(length, self.displayStringLimit) mem = self.readMemory(data, shown) if charSize == 1: if displayFormat in (DisplayFormat.Latin1String, DisplayFormat.SeparateLatin1String): @@ -650,13 +649,13 @@ class DumperBase(): encodingType = 'ucs4' #childType = 'int' - self.putValue(mem, encodingType, elided=elided) + self.putValue(mem, encodingType, length=length) if displayFormat in ( DisplayFormat.SeparateLatin1String, DisplayFormat.SeparateUtf8String, DisplayFormat.Separate): - elided, shown = self.computeLimit(bytelen, 100000) + shown = self.computeLimit(length, 100000) self.putDisplay(encodingType + ':separate', self.readMemory(data, shown)) def putCharArrayHelper(self, data, size, charType, @@ -676,15 +675,15 @@ class DumperBase(): return self.hexencode(bytes(self.readRawMemory(addr, size))) def encodeByteArray(self, value, limit=0): - elided, data = self.encodeByteArrayHelper(value, limit) + _, data = self.encodeByteArrayHelper(value, limit) return data def putByteArrayValue(self, value): - elided, data = self.encodeByteArrayHelper(value, self.displayStringLimit) - self.putValue(data, 'latin1', elided=elided) + length, data = self.encodeByteArrayHelper(value, self.displayStringLimit) + self.putValue(data, 'latin1', length=length) def encodeString(self, value, limit=0): - elided, data = self.encodeStringHelper(value, limit) + _, data = self.encodeStringHelper(value, limit) return data def encodedUtf16ToUtf8(self, s): @@ -730,8 +729,8 @@ class DumperBase(): return inner def putStringValue(self, value): - elided, data = self.encodeStringHelper(value, self.displayStringLimit) - self.putValue(data, 'utf16', elided=elided) + length, data = self.encodeStringHelper(value, self.displayStringLimit) + self.putValue(data, 'utf16', length=length) def putPtrItem(self, name, value): with SubItem(self, name): @@ -900,12 +899,12 @@ class DumperBase(): if not self.isInt(thing): raise RuntimeError('Expected an integral value, got %s' % type(thing)) - def readToFirstZero(self, base, tsize, maximum): + def readToFirstZero(self, base, typesize, maximum): self.checkIntType(base) - self.checkIntType(tsize) + self.checkIntType(typesize) self.checkIntType(maximum) - code = self.packCode + (None, 'b', 'H', None, 'I')[tsize] + code = self.packCode + (None, 'b', 'H', None, 'I')[typesize] #blob = self.readRawMemory(base, 1) blob = bytes() while maximum > 1: @@ -916,8 +915,8 @@ class DumperBase(): maximum = int(maximum / 2) self.warn('REDUCING READING MAXIMUM TO %s' % maximum) - #DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, tsize, maximum)) - for i in range(0, maximum, tsize): + #DumperBase.warn('BASE: 0x%x TSIZE: %s MAX: %s' % (base, typesize, maximum)) + for i in range(0, maximum, typesize): t = struct.unpack_from(code, blob, i)[0] if t == 0: return 0, i, self.hexencode(blob[:i]) @@ -925,9 +924,9 @@ class DumperBase(): # Real end is unknown. return -1, maximum, self.hexencode(blob[:maximum]) - def encodeCArray(self, p, tsize, limit): - elided, shown, blob = self.readToFirstZero(p, tsize, limit) - return elided, blob + def encodeCArray(self, p, typesize, limit): + length, shown, blob = self.readToFirstZero(p, typesize, limit) + return length, blob def putItemCount(self, count, maximum=1000000000): # This needs to override the default value, so don't use 'put' directly. @@ -1043,12 +1042,12 @@ class DumperBase(): self.currentType.value = typish.name self.currentType.priority = priority - def putValue(self, value, encoding=None, priority=0, elided=None): + def putValue(self, value, encoding=None, priority=0, length=None): # Higher priority values override lower ones. - # elided = 0 indicates all data is available in value, + # length = None indicates all data is available in value, # otherwise it's the true length. if priority >= self.currentValue.priority: - self.currentValue = ReportItem(value, encoding, priority, elided) + self.currentValue = ReportItem(value, encoding, priority, length) def putSpecialValue(self, encoding, value='', children=None): self.putValue(value, encoding) @@ -1226,13 +1225,13 @@ class DumperBase(): return False - def putSimpleCharArray(self, base, size=None): - if size is None: - elided, shown, data = self.readToFirstZero(base, 1, self.displayStringLimit) + def putSimpleCharArray(self, base, length=None): + if length is None: + length, shown, data = self.readToFirstZero(base, 1, self.displayStringLimit) else: - elided, shown = self.computeLimit(int(size), self.displayStringLimit) + shown = self.computeLimit(length) data = self.readMemory(base, shown) - self.putValue(data, 'latin1', elided=elided) + self.putValue(data, 'latin1', length=length) def putDisplay(self, editFormat, value): self.putField('editformat', editFormat) @@ -1248,8 +1247,8 @@ class DumperBase(): if targetType.name in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'): # Use UTF-8 as default for char *. self.putType(typeName) - (elided, shown, data) = self.readToFirstZero(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, shown, data) = self.readToFirstZero(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) if self.isExpanded(): self.putArrayData(ptr, shown, innerType) return True @@ -1257,55 +1256,55 @@ class DumperBase(): if targetType.name in ('wchar_t', 'WCHAR'): self.putType(typeName) charSize = self.lookupType('wchar_t').size() - (elided, data) = self.encodeCArray(ptr, charSize, limit) + (length, data) = self.encodeCArray(ptr, charSize, limit) if charSize == 2: - self.putValue(data, 'utf16', elided=elided) + self.putValue(data, 'utf16', length=length) else: - self.putValue(data, 'ucs4', elided=elided) + self.putValue(data, 'ucs4', length=length) return True if displayFormat == DisplayFormat.Latin1String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'latin1', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) return True if displayFormat == DisplayFormat.SeparateLatin1String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'latin1', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'latin1', length=length) self.putDisplay('latin1:separate', data) return True if displayFormat == DisplayFormat.Utf8String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) return True if displayFormat == DisplayFormat.SeparateUtf8String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'utf8', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'utf8', length=length) self.putDisplay('utf8:separate', data) return True if displayFormat == DisplayFormat.Local8BitString: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 1, limit) - self.putValue(data, 'local8bit', elided=elided) + (length, data) = self.encodeCArray(ptr, 1, limit) + self.putValue(data, 'local8bit', length=length) return True if displayFormat == DisplayFormat.Utf16String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 2, limit) - self.putValue(data, 'utf16', elided=elided) + (length, data) = self.encodeCArray(ptr, 2, limit) + self.putValue(data, 'utf16', length=length) return True if displayFormat == DisplayFormat.Ucs4String: self.putType(typeName) - (elided, data) = self.encodeCArray(ptr, 4, limit) - self.putValue(data, 'ucs4', elided=elided) + (length, data) = self.encodeCArray(ptr, 4, limit) + self.putValue(data, 'ucs4', length=length) return True return False @@ -2577,17 +2576,17 @@ class DumperBase(): def extractQStringFromQDataStream(self, buf, offset): """ Read a QString from the stream """ - size = struct.unpack_from('!I', buf, offset)[0] + length = struct.unpack_from('!I', buf, offset)[0] offset += 4 - string = buf[offset:offset + size].decode('utf-16be') - return (string, offset + size) + string = buf[offset:offset + length].decode('utf-16be') + return (string, offset + length) def extractQByteArrayFromQDataStream(self, buf, offset): """ Read a QByteArray from the stream """ - size = struct.unpack_from('!I', buf, offset)[0] + length = struct.unpack_from('!I', buf, offset)[0] offset += 4 - string = buf[offset:offset + size].decode('latin1') - return (string, offset + size) + string = buf[offset:offset + length].decode('latin1') + return (string, offset + length) def extractIntFromQDataStream(self, buf, offset): """ Read an int from the stream """ diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index b08f60a9bb3..06e7d473254 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -28,46 +28,46 @@ def qform__QByteArray(): def qedit__QByteArray(d, value, data): d.call('void', value, 'resize', str(len(data))) - (base, size, alloc) = d.stringData(value) + (base, length, alloc) = d.stringData(value) d.setValues(base, 'char', [ord(c) for c in data]) def qdump__QByteArray(d, value): if d.qtVersion() >= 0x60000: - dd, data, size = value.split('ppi') + dd, data, length = value.split('ppi') if dd: _, _, alloc = d.split('iii', dd) else: # fromRawData - alloc = size + alloc = length else: - data, size, alloc = d.qArrayData(value) + data, length, alloc = d.qArrayData(value) - d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000)) - if size > 0: + d.check(alloc == 0 or (0 <= length and length <= alloc and alloc <= 100000000)) + if length > 0: d.putExpandable() - elided, shown = d.computeLimit(size, d.displayStringLimit) + shown = d.computeLimit(length, d.displayStringLimit) p = d.readMemory(data, shown) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Automatic or displayFormat == DisplayFormat.Latin1String: - d.putValue(p, 'latin1', elided=elided) + d.putValue(p, 'latin1', length=length) elif displayFormat == DisplayFormat.SeparateLatin1String: - d.putValue(p, 'latin1', elided=elided) + d.putValue(p, 'latin1', length=length) d.putDisplay('latin1:separate', d.encodeByteArray(value, limit=100000)) elif displayFormat == DisplayFormat.Utf8String: - d.putValue(p, 'utf8', elided=elided) + d.putValue(p, 'utf8', length=length) elif displayFormat == DisplayFormat.SeparateUtf8String: - d.putValue(p, 'utf8', elided=elided) + d.putValue(p, 'utf8', length=length) d.putDisplay('utf8:separate', d.encodeByteArray(value, limit=100000)) if d.isExpanded(): - d.putArrayData(data, size, d.charType()) + d.putArrayData(data, length, d.charType()) #def qdump__QArrayData(d, value): -# data, size, alloc = d.qArrayDataHelper(value.address()) -# d.check(alloc == 0 or (0 <= size and size <= alloc and alloc <= 100000000)) -# d.putValue(d.readMemory(data, size), 'latin1') +# data, length, alloc = d.qArrayDataHelper(value.address()) +# d.check(alloc == 0 or (0 <= length and length <= alloc and alloc <= 100000000)) +# d.putValue(d.readMemory(data, length), 'latin1') # d.putPlainChildren(value) @@ -81,10 +81,10 @@ def qdump__QBitArray(d, value): else: data, basize, _ = d.qArrayData(value['d']) unused = d.extractByte(data) if data else 0 - size = basize * 8 - unused - d.putItemCount(size) + length = basize * 8 - unused + d.putItemCount(length) if d.isExpanded(): - with Children(d, size, maxNumChild=10000): + with Children(d, length, maxNumChild=10000): for i in d.childRange(): q = data + 1 + int(i / 8) with SubItem(d, i): @@ -1621,17 +1621,17 @@ def qdumpHelper_QSet45(d, value): ptrSize = d.ptrSize() dptr = d.extractPointer(value) - (fakeNext, buckets, ref, size, nodeSize, userNumBits, numBits, numBuckets) = \ + (fakeNext, buckets, ref, length, nodeSize, userNumBits, numBits, numBuckets) = \ d.split('ppiiihhi', dptr) - d.check(0 <= size and size <= 100 * 1000 * 1000) + d.check(0 <= length and length <= 100 * 1000 * 1000) d.check(-1 <= ref and ref < 100000) - d.putItemCount(size) + d.putItemCount(length) if d.isExpanded(): keyType = value.type[0] isShort = d.qtVersion() < 0x050000 and keyType.name == 'int' - with Children(d, size, childType=keyType): + with Children(d, length, childType=keyType): node = hashDataFirstNode() for i in d.childRange(): if isShort: @@ -1714,15 +1714,15 @@ def qdump__QStack(d, value): def qdump__QPolygonF(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPointF')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPointF')) def qdump__QPolygon(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPoint')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPoint')) def qdump__QGraphicsPolygonItem(d, value): @@ -1741,14 +1741,14 @@ def qdump__QGraphicsPolygonItem(d, value): offset = 328 if d.isMsvcTarget() else 320 else: offset = 308 - data, size = d.vectorData(dptr + offset) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QPointF')) + data, length = d.vectorData(dptr + offset) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QPointF')) def qedit__QString(d, value, data): d.call('void', value, 'resize', str(len(data))) - (base, size, alloc) = d.stringData(value) + (base, length, alloc) = d.stringData(value) d.setValues(base, 'short', [ord(c) for c in data]) @@ -1758,14 +1758,14 @@ def qform__QString(): def qdump__QString(d, value): d.putStringValue(value) - data, size, _ = d.stringData(value) + data, length, _ = d.stringData(value) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Separate: d.putDisplay('utf16:separate', d.encodeString(value, limit=100000)) - if (size > 0): + if (length > 0): d.putExpandable() if d.isExpanded(): - d.putArrayData(data, size, d.createType('@QChar')) + d.putArrayData(data, length, d.createType('@QChar')) def qdump__QSettingsKey(d, value): @@ -1774,8 +1774,8 @@ def qdump__QSettingsKey(d, value): def qdump__QStaticStringData(d, value): - size = value.type[0] - (ref, size, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * size)) + length = value.type[0] + (ref, length, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * length)) d.putValue(d.hexencode(data), 'utf16') d.putPlainChildren(value) @@ -1788,28 +1788,28 @@ def qdump__QTypedArrayData(d, value): def qdump__QStringData(d, value): - (ref, size, alloc, pad, offset) = value.split('III@p') - elided, shown = d.computeLimit(size, d.displayStringLimit) + (ref, length, alloc, pad, offset) = value.split('III@p') + shown = d.computeLimit(length, d.displayStringLimit) data = d.readMemory(value.address() + offset, shown * 2) - d.putValue(data, 'utf16', elided=elided) + d.putValue(data, 'utf16', length=length) d.putPlainChildren(value) def qdump__QAnyStringView(d, value): - data, size = value.split('pp') + data, length = value.split('pp') bits = d.ptrSize() * 8 - 2 - tag = size >> bits - size = size & (2**bits - 1) - elided, shown = d.computeLimit(size, d.displayStringLimit) + tag = length >> bits + length = length & (2**bits - 1) + shown = d.computeLimit(length, d.displayStringLimit) if tag == 0: mem = d.readMemory(data, shown) - d.putValue(mem, 'utf8', elided=elided) + d.putValue(mem, 'utf8', length=length) elif tag == 1: mem = d.readMemory(data, shown) - d.putValue(mem, 'latin1', elided=elided) + d.putValue(mem, 'latin1', length=length) elif tag == 2: mem = d.readMemory(data, shown * 2) - d.putValue(mem, 'utf16', elided=elided) + d.putValue(mem, 'utf16', length=length) else: d.putSpecialValue('empty') d.putPlainChildren(value) @@ -1825,16 +1825,15 @@ def qdump__QStringView(d, value): if idata == 0: d.putValue('(null)') return - size = value['m_size'] - isize = size.integer() - elided, shown = d.computeLimit(isize, d.displayStringLimit) + length = value['m_size'].integer() + shown = d.computeLimit(length, d.displayStringLimit) mem = d.readMemory(idata, shown * 2) - d.putValue(mem, 'utf16', elided=elided) + d.putValue(mem, 'utf16', length=length) if d.currentItemFormat() == DisplayFormat.Separate: d.putDisplay('utf16:separate', mem) d.putExpandable() if d.isExpanded(): - d.putArrayData(idata, isize, d.createType('char16_t')) + d.putArrayData(idata, length, d.createType('char16_t')) def qdump__QHashedString(d, value): @@ -1848,12 +1847,12 @@ def qdump__QQmlRefCount(d, value): def qdump__QStringRef(d, value): - (stringptr, pos, size) = value.split('pii') + (stringptr, pos, length) = value.split('pii') if stringptr == 0: d.putValue('(null)') return data, ssize, alloc = d.stringData(d.createValue(stringptr, '@QString')) - d.putValue(d.readMemory(data + 2 * pos, 2 * size), 'utf16') + d.putValue(d.readMemory(data + 2 * pos, 2 * length), 'utf16') d.putPlainChildren(value) @@ -1937,7 +1936,7 @@ def qdump__QUrl(d, value): userNameEnc = d.encodeString(userName) hostEnc = d.encodeString(host) - elided, pathEnc = d.encodeStringHelper(path, d.displayStringLimit) + length, pathEnc = d.encodeStringHelper(path, d.displayStringLimit) url = d.encodeString(scheme) url += '3a002f002f00' # '://' if len(userNameEnc): @@ -1946,7 +1945,7 @@ def qdump__QUrl(d, value): if port >= 0: url += '3a00' + ''.join(['%02x00' % ord(c) for c in str(port)]) url += pathEnc - d.putValue(url, 'utf16', elided=elided) + d.putValue(url, 'utf16', length=length) displayFormat = d.currentItemFormat() if displayFormat == DisplayFormat.Separate: @@ -2162,7 +2161,7 @@ def qdumpHelper__QVariant6(d, value): qdumpHelper_QVariant_0(d, value) return - revision, alignment, size, flags, variantType, metaObjectPtr, name = \ + revision, alignment, length, flags, variantType, metaObjectPtr, name = \ d.split('HHIIIpp', metaTypeInterface) # Well-known simple type. @@ -2241,7 +2240,7 @@ def qdumpHelper__QVariant45(d, value): base1 = d.extractPointer(value) #DumperBase.warn('BASE 1: %s %s' % (base1, innert)) base = d.extractPointer(base1) - #DumperBase.warn('SIZE 1: %s' % size) + #DumperBase.warn('SIZE 1: %s' % length) val = d.createValue(base, innerType) else: #DumperBase.warn('DIRECT ITEM 1: %s' % innerType) @@ -2268,7 +2267,7 @@ def qdumpHelper__QVariant45(d, value): d.putSpecialValue('notcallable') return None ptr = p.pointer() - (elided, blob) = d.encodeCArray(ptr, 1, 100) + (_, blob) = d.encodeCArray(ptr, 1, 100) innerType = d.hexdecode(blob) # Prefer namespaced version. @@ -2303,34 +2302,34 @@ def qform__QVector(): def qdump__QVector(d, value): if d.qtVersion() >= 0x060000: - data, size = d.listData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType(value.type.ltarget[0])) + data, length = d.listData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType(value.type.ltarget[0])) # g++ 9.3 does not add the template parameter list to the debug info. # Fake it for the common case: if value.type.name == d.qtNamespace() + "QVector": d.putBetterType(value.type.name + '<' + value.type.ltarget[0].name + '>') else: - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType(value.type[0])) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType(value.type[0])) if False: def qdump__QObjectConnectionList(d, value): - data, size = d.vectorData(value) - d.putItemCount(size) - d.putPlotData(data, size, d.createType('@QObjectPrivate::ConnectionList')) + data, length = d.vectorData(value) + d.putItemCount(length) + d.putPlotData(data, length, d.createType('@QObjectPrivate::ConnectionList')) def qdump__QVarLengthArray(d, value): if d.qtVersion() >= 0x060000: - cap, size, data = value.split('QQp') + cap, length, data = value.split('QQp') else: - cap, size, data = value.split('iip') - d.check(0 <= size) - d.putItemCount(size) - d.putPlotData(data, size, value.type[0]) + cap, length, data = value.split('iip') + d.check(0 <= length) + d.putItemCount(length) + d.putPlotData(data, length, value.type[0]) def qdump__QSharedPointer(d, value): @@ -2401,20 +2400,20 @@ def qdump__QXmlAttributes(d, value): def qdump__QXmlStreamStringRef(d, value): s = value['m_string'] - (data, size, alloc) = d.stringData(s) + (data, length, alloc) = d.stringData(s) data += 2 * int(value['m_position']) - size = int(value['m_size']) - s = d.readMemory(data, 2 * size) + length = int(value['m_size']) + s = d.readMemory(data, 2 * length) d.putValue(s, 'utf16') d.putPlainChildren(value) def qdump__QXmlStreamAttribute(d, value): s = value['m_name']['m_string'] - (data, size, alloc) = d.stringData(s) + (data, length, alloc) = d.stringData(s) data += 2 * int(value['m_name']['m_position']) - size = int(value['m_name']['m_size']) - s = d.readMemory(data, 2 * size) + length = int(value['m_name']['m_size']) + s = d.readMemory(data, 2 * length) d.putValue(s, 'utf16') d.putPlainChildren(value) @@ -2505,8 +2504,8 @@ def qdump__QV4__ExecutionContext(d, value): def qdump__QQmlSourceLocation(d, value): (sourceFile, line, col) = value.split('pHH') - (data, size, alloc) = d.stringData(value) - d.putValue(d.readMemory(data, 2 * size), 'utf16') + (data, length, alloc) = d.stringData(value) + d.putValue(d.readMemory(data, 2 * length), 'utf16') d.putField('valuesuffix', ':%s:%s' % (line, col)) d.putPlainChildren(value) @@ -3345,9 +3344,7 @@ def qdump__QJsonValue(d, value): return if t == 3: d.putType('QJsonValue (String)') - string = value.split('{@QString}')[0] - elided, base = d.encodeString(string, d.displayStringLimit) - d.putValue(base, 'utf16', elided=elided) + d.putStringValue(value.split('{@QString}')[0]) return if t == 4: d.putType('QJsonValue (Array)') @@ -3472,9 +3469,9 @@ def qdumpHelper_QCbor_string(d, container_ptr, element_index, is_bytes): bytedata_len = d.extractInt(bytedata) bytedata_data = bytedata + 4 # sizeof(QtCbor::ByteData) header part - elided, shown = d.computeLimit(bytedata_len, d.displayStringLimit) + shown = d.computeLimit(bytedata_len, d.displayStringLimit) res = d.readMemory(bytedata_data, shown) - d.putValue(res, enc, elided=elided) + d.putValue(res, enc, length=bytedata_len) def qdumpHelper_QCborArray_valueAt(d, container_ptr, elements_data_ptr, idx, bytedata, is_cbor): diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 1c98c767258..bc4bb84dcbb 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -697,6 +697,36 @@ def qdump__std__pair(d, value): d.putValue('(%s, %s)' % (key, value)) +def qdumpHelper_get_tuple_elements(d, tuple, value_typename, value_member): + """ + Helper method that returns the elements of a tuple. + """ + elems = [] + other_members = [] + for member in tuple.members(True): + if not member.type.templateArguments(): + continue + if member.type.name.startswith(value_typename): + elems.append(member[value_member]) + else: + other_members.append(member) + for member in other_members: + sub_elems = qdumpHelper_get_tuple_elements(d, member, value_typename, value_member) + elems = elems + sub_elems + return elems + + +def qdump__std__tuple(d, value): + if d.isMsvcTarget(): + elems = qdumpHelper_get_tuple_elements(d, value, "std::_Tuple_val", "_Val") + else: + elems = qdumpHelper_get_tuple_elements(d, value, "std::_Head_base", "_M_head_impl") + d.putItemCount(len(elems)) + with Children(d): + for elem in elems: + d.putSubItem(0, elem) + + def qform__std__unordered_map(): return [DisplayFormat.CompactMap] diff --git a/src/libs/3rdparty/qtkeychain/qtkeychain.qbs b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs new file mode 100644 index 00000000000..4a532363f0b --- /dev/null +++ b/src/libs/3rdparty/qtkeychain/qtkeychain.qbs @@ -0,0 +1,86 @@ +QtcLibrary { + name: "qtkeychain" + + property bool useWinCredentialsStore: qbs.targetOS.contains("windows") + + Depends { name: "cpp" } + Depends { name: "Qt.core" } + Depends { name: "Qt.dbus"; condition: qbs.targetOS.contains("linux") } + Depends { name: "libsecret-1"; required: false } + + cpp.defines: base.concat(["QTKEYCHAIN_LIBRARY"]) + + Properties { + condition: useWinCredentialsStore + cpp.defines: outer.concat(["USE_CREDENTIAL_STORE=1"]) + cpp.dynamicLibraries: ["advapi32"] + } + + Properties { + condition: qbs.targetOS.contains("windows") && !useWinCredentialsStore + cpp.dynamicLibraries: ["crypt32"] + } + + Properties { + condition: qbs.targetOS.contains("macos") + cpp.frameworks: [ "Foundation", "Security" ] + } + + files: [ + "keychain.cpp", + "keychain.h", + "keychain_p.h", + "qkeychain_export.h", + ] + + Group { + name: "qtkeychain Windows files" + condition: qbs.targetOS.contains("windows") + files: [ + "keychain_win.cpp", + "plaintextstore_p.h", + ] + + Group { + name: "qtkeychain Windows no credentials store" + condition: !product.useWinCredentialsStore + files: [ "plaintextstore.cpp" ] + } + } + + Group { + name: "qtkeychain macOS files" + condition: qbs.targetOS.contains("macos") + files: [ "keychain_apple.mm" ] + } + + Group { + name: "qtkeychain Linux files" + condition: qbs.targetOS.contains("linux") + + Group { + name: "qtkeychain libsecret support" + condition: "libsecret-1".present + cpp.defines: outer.concat(["HAVE_LIBSECRET=1"]) + } + Group { + name: "dbus sources" + fileTags: "qt.dbus.interface" + files: ["org.kde.KWallet.xml"] + } + + Group { + name: "qtkeychain dbus support" + cpp.defines: outer.concat(["KEYCHAIN_DBUS=1"]) + files: [ + "gnomekeyring.cpp", + "gnomekeyring_p.h", + "keychain_unix.cpp", + "libsecret.cpp", + "libsecret_p.h", + "plaintextstore.cpp", + "plaintextstore_p.h", + ] + } + } +} diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp index 7ae1aa3397b..0e7ba193427 100644 --- a/src/libs/cplusplus/TypePrettyPrinter.cpp +++ b/src/libs/cplusplus/TypePrettyPrinter.cpp @@ -363,12 +363,11 @@ void TypePrettyPrinter::visit(Function *type) { bool showTemplateParameters = _overview->showTemplateParameters; QStringList nameParts = _name.split("::"); - int i = nameParts.length() - 1; Scope *s = type->enclosingScope(); if (s && s->asTemplate()) s = s->enclosingScope(); - for (; s && i >= 0; s = s->enclosingScope()) { + for (int i = nameParts.length() - 1; s && i >= 0; s = s->enclosingScope()) { if (s->asClass()) showTemplateParameters = true; @@ -433,7 +432,8 @@ void TypePrettyPrinter::visit(Function *type) } if (_overview->showEnclosingTemplate) { - for (Scope *s = type->enclosingScope(); s && i >= 0; s = s->enclosingScope()) { + for (auto [s, i] = std::tuple{type->enclosingScope(), nameParts.length() - 1}; s && i >= 0; + s = s->enclosingScope()) { if (Template *templ = s->asTemplate()) { QString templateScope = "template<"; const int paramCount = templ->templateParameterCount(); diff --git a/src/libs/libs.qbs b/src/libs/libs.qbs index ffc3017cba0..a6426d4ae47 100644 --- a/src/libs/libs.qbs +++ b/src/libs/libs.qbs @@ -26,6 +26,7 @@ Project { "utils/utils.qbs", "3rdparty/libptyqt/ptyqt.qbs", "3rdparty/libvterm/vterm.qbs", + "3rdparty/qtkeychain/qtkeychain.qbs", "3rdparty/syntax-highlighting/syntax-highlighting.qbs", "3rdparty/winpty/winpty.qbs", "3rdparty/yaml-cpp/yaml-cpp.qbs", diff --git a/src/libs/nanotrace/CMakeLists.txt b/src/libs/nanotrace/CMakeLists.txt index f2fa830e2d3..8652a817985 100644 --- a/src/libs/nanotrace/CMakeLists.txt +++ b/src/libs/nanotrace/CMakeLists.txt @@ -3,7 +3,6 @@ add_qtc_library(Nanotrace SOURCES nanotraceglobals.h nanotrace.cpp nanotrace.h - nanotracehr.cpp nanotracehr.h PUBLIC_DEPENDS Qt::Core Qt::Gui PROPERTIES CXX_VISIBILITY_PRESET default @@ -16,3 +15,9 @@ extend_qtc_library(Nanotrace CONDITION DESIGN_STUDIO_USE_NANOTRACE PUBLIC_DEFINES NANOTRACE_DESIGNSTUDIO_ENABLED ) + +option(NANOTRACEHR_ENABLED "Enables collecting high resolution performance data" OFF) +extend_qtc_library(Nanotrace + SOURCES + nanotracehr.cpp nanotracehr.h +) diff --git a/src/libs/nanotrace/nanotracehr.h b/src/libs/nanotrace/nanotracehr.h index d49e12a87a0..74b1381b064 100644 --- a/src/libs/nanotrace/nanotracehr.h +++ b/src/libs/nanotrace/nanotracehr.h @@ -34,7 +34,7 @@ enum class Tracing { IsDisabled, IsEnabled }; constexpr Tracing tracingStatus() { -#ifdef NANOTRACE_ENABLED +#ifdef NANOTRACEHR_ENABLED return Tracing::IsEnabled; #else return Tracing::IsDisabled; @@ -1569,7 +1569,7 @@ template Tracer(typename Category::ArgumentType name, Category &category, Arguments &&...) -> Tracer; -#ifdef NANOTRACE_ENABLED +#ifdef NANOTRACEHR_ENABLED class GlobalTracer { public: diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index aac0de9ab1e..a525c6c3054 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -317,6 +317,16 @@ void ModelManagerInterface::setDefaultProject(const ModelManagerInterface::Proje }); } +void ModelManagerInterface::cancelAllThreads() +{ + m_cppQmlTypesUpdater.cancel(); + // Don't execute the scheduled updates for the old session anymore + m_updateCppQmlTypesTimer->stop(); + m_asyncResetTimer->stop(); + QMutexLocker locker(&m_futuresMutex); + m_futureSynchronizer.cancelAllFutures(); +} + Snapshot ModelManagerInterface::snapshot() const { return m_syncedData.readLocked()->m_validSnapshot; diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index c57cba7e46e..ae3d8e0e6c4 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -238,7 +238,7 @@ protected: void updateImportPaths(); void loadQmlTypeDescriptionsInternal(const QString &path); void setDefaultProject(const ProjectInfo &pInfo, ProjectExplorer::Project *p); - + void cancelAllThreads(); private: void joinAllThreads(bool cancelOnWait = false); void iterateQrcFiles(ProjectExplorer::Project *project, diff --git a/src/libs/solutions/tasking/networkquery.cpp b/src/libs/solutions/tasking/networkquery.cpp index b02bb9cea1c..335f79afd94 100644 --- a/src/libs/solutions/tasking/networkquery.cpp +++ b/src/libs/solutions/tasking/networkquery.cpp @@ -19,7 +19,20 @@ void NetworkQuery::start() emit done(DoneResult::Error); return; } - m_reply.reset(m_manager->get(m_request)); + switch (m_operation) { + case NetworkOperation::Get: + m_reply.reset(m_manager->get(m_request)); + break; + case NetworkOperation::Put: + m_reply.reset(m_manager->put(m_request, m_writeData)); + break; + case NetworkOperation::Post: + m_reply.reset(m_manager->post(m_request, m_writeData)); + break; + case NetworkOperation::Delete: + m_reply.reset(m_manager->deleteResource(m_request)); + break; + } connect(m_reply.get(), &QNetworkReply::finished, this, [this] { disconnect(m_reply.get(), &QNetworkReply::finished, this, nullptr); emit done(toDoneResult(m_reply->error() == QNetworkReply::NoError)); diff --git a/src/libs/solutions/tasking/networkquery.h b/src/libs/solutions/tasking/networkquery.h index bf08bd1e7b5..dd099dc7a88 100644 --- a/src/libs/solutions/tasking/networkquery.h +++ b/src/libs/solutions/tasking/networkquery.h @@ -22,6 +22,8 @@ namespace Tasking { // is independent on Qt::Network. // Possibly, it could be placed inside Qt::Network library, as a wrapper around QNetworkReply. +enum class NetworkOperation { Get, Put, Post, Delete }; + class TASKING_EXPORT NetworkQuery final : public QObject { Q_OBJECT @@ -29,6 +31,8 @@ class TASKING_EXPORT NetworkQuery final : public QObject public: ~NetworkQuery(); void setRequest(const QNetworkRequest &request) { m_request = request; } + void setOperation(NetworkOperation operation) { m_operation = operation; } + void setWriteData(const QByteArray &data) { m_writeData = data; } void setNetworkAccessManager(QNetworkAccessManager *manager) { m_manager = manager; } QNetworkReply *reply() const { return m_reply.get(); } void start(); @@ -39,6 +43,8 @@ signals: private: QNetworkRequest m_request; + NetworkOperation m_operation = NetworkOperation::Get; + QByteArray m_writeData; // Used by Put and Post QNetworkAccessManager *m_manager = nullptr; std::unique_ptr m_reply; }; diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt index 9f11f3fc83c..eb2eaed9ddc 100644 --- a/src/libs/utils/CMakeLists.txt +++ b/src/libs/utils/CMakeLists.txt @@ -43,8 +43,8 @@ add_qtc_library(Utils elidinglabel.cpp elidinglabel.h environment.cpp environment.h environmentdialog.cpp environmentdialog.h - environmentfwd.h environmentmodel.cpp environmentmodel.h + environmentfwd.h execmenu.cpp execmenu.h expected.h externalterminalprocessimpl.cpp externalterminalprocessimpl.h @@ -103,12 +103,7 @@ add_qtc_library(Utils namevaluedictionary.cpp namevaluedictionary.h namevaluedictionary.cpp namevaluedictionary.h namevalueitem.cpp namevalueitem.h - namevalueitem.cpp namevalueitem.h - namevaluemodel.cpp namevaluemodel.h - namevaluemodel.cpp namevaluemodel.h namevaluesdialog.cpp namevaluesdialog.h - namevaluesdialog.cpp namevaluesdialog.h - namevaluevalidator.cpp namevaluevalidator.h namevaluevalidator.cpp namevaluevalidator.h navigationtreeview.cpp navigationtreeview.h networkaccessmanager.cpp networkaccessmanager.h diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 1e8ccbac71f..2098c68d1c0 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -7,6 +7,7 @@ #include "checkablemessagebox.h" #include "environment.h" #include "fancylineedit.h" +#include "guard.h" #include "iconbutton.h" #include "layoutbuilder.h" #include "passworddialog.h" @@ -1181,13 +1182,12 @@ void StringAspect::addToLayout(LayoutItem &parent) connect(lineEditDisplay, &FancyLineEdit::validChanged, this, &StringAspect::validChanged); bufferToGui(); if (isAutoApply() && d->m_autoApplyOnEditingFinished) { - connect(lineEditDisplay, - &FancyLineEdit::editingFinished, - this, - [this, lineEditDisplay] { - d->undoable.set(undoStack(), lineEditDisplay->text()); - handleGuiChanged(); - }); + connect(lineEditDisplay, &FancyLineEdit::editingFinished, this, [this, lineEditDisplay] { + if (lineEditDisplay->text() != d->undoable.get()) { + d->undoable.set(undoStack(), lineEditDisplay->text()); + handleGuiChanged(); + } + }); } else { connect(lineEditDisplay, &QLineEdit::textChanged, this, [this, lineEditDisplay] { d->undoable.set(undoStack(), lineEditDisplay->text()); @@ -1386,6 +1386,8 @@ public: bool m_autoApplyOnEditingFinished = false; bool m_allowPathFromDevice = true; bool m_validatePlaceHolder = false; + + Guard m_editFinishedGuard; }; FilePathAspect::FilePathAspect(AspectContainer *container) @@ -1559,8 +1561,12 @@ void FilePathAspect::addToLayout(Layouting::LayoutItem &parent) connect(d->m_pathChooserDisplay, &PathChooser::validChanged, this, &FilePathAspect::validChanged); bufferToGui(); if (isAutoApply() && d->m_autoApplyOnEditingFinished) { - connect(d->m_pathChooserDisplay, &PathChooser::editingFinished, - this, &FilePathAspect::handleGuiChanged); + connect(d->m_pathChooserDisplay, &PathChooser::editingFinished, this, [this] { + if (d->m_editFinishedGuard.isLocked()) + return; + GuardLocker lk(d->m_editFinishedGuard); + handleGuiChanged(); + }); connect(d->m_pathChooserDisplay, &PathChooser::browsingFinished, this, &FilePathAspect::handleGuiChanged); } else { diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 0486ece19e9..39bdc736e09 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -878,52 +878,73 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const // UnixDeviceAccess +static Utils::unexpected make_unexpected_disconnected() +{ + return make_unexpected(Tr::tr("Device is not connected")); +} + UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; bool UnixDeviceFileAccess::runInShellSuccess(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return false; return runInShell(cmdLine, stdInData).exitCode == 0; } bool UnixDeviceFileAccess::isExecutableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-x", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; if (filePath.isRootPath()) return true; @@ -933,12 +954,16 @@ bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const bool UnixDeviceFileAccess::isSymLink(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-h", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const { + if (disconnected()) + return false; const QStringList args = statArgs(filePath, "%h", "%l"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong() > 1; @@ -946,29 +971,39 @@ bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"touch", {path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::createDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"mkdir", {"-p", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::exists(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-e", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeFile(const FilePath &filePath) const { + if (disconnected()) + return false; return runInShellSuccess({"rm", {filePath.path()}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const { + if (disconnected()) + return false; QTC_ASSERT(filePath.path().startsWith('/'), return false); const QString path = filePath.cleanPath().path(); @@ -989,6 +1024,8 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString * expected_str UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return make_unexpected_disconnected(); const RunResult result = runInShell( {"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux}); @@ -1003,11 +1040,17 @@ expected_str UnixDeviceFileAccess::copyFile(const FilePath &filePath, bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return false; + return runInShellSuccess({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); } FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); @@ -1018,6 +1061,9 @@ expected_str UnixDeviceFileAccess::fileContents(const FilePath &file qint64 limit, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"if=" + filePath.path()}; if (limit > 0 || offset > 0) { const qint64 gcd = std::gcd(limit, offset); @@ -1045,6 +1091,9 @@ expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &fil const QByteArray &data, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"of=" + filePath.path()}; if (offset != 0) { args.append("bs=1"); @@ -1061,6 +1110,9 @@ expected_str UnixDeviceFileAccess::writeFileContents(const FilePath &fil expected_str UnixDeviceFileAccess::createTempFile(const FilePath &filePath) { + if (disconnected()) + return make_unexpected_disconnected(); + if (!m_hasMkTemp.has_value()) m_hasMkTemp = runInShellSuccess({"which", {"mktemp"}, OsType::OsTypeLinux}); @@ -1120,6 +1172,9 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux}); qint64 secs = result.stdOut.toLongLong(); @@ -1131,6 +1186,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { + if (disconnected()) + return {}; + return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); @@ -1138,6 +1196,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const { + if (disconnected()) + return {}; + QStringList args = statArgs(filePath, "%a", "%p"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1161,6 +1222,9 @@ QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) c bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const { + if (disconnected()) + return false; + const int flags = int(perms); return runInShellSuccess( {"chmod", {QString::number(flags, 16), filePath.path()}, OsType::OsTypeLinux}); @@ -1168,6 +1232,9 @@ bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permi qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const { + if (disconnected()) + return -1; + const QStringList args = statArgs(filePath, "%s", "%z"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong(); @@ -1175,12 +1242,18 @@ qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const { + if (disconnected()) + return -1; + const RunResult result = runInShell({"df", {"-k", filePath.path()}, OsType::OsTypeLinux}); return FileUtils::bytesAvailableFromDFOutput(result.stdOut); } QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const { + if (disconnected()) + return {}; + const QStringList args = statArgs(filePath, "%D:%i", "%d:%i"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1192,6 +1265,9 @@ QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const { + if (disconnected()) + return {}; + if (filePath.path() == "/") // TODO: Add FilePath::isRoot() { const FilePathInfo r{4096, @@ -1218,6 +1294,9 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, const FileFilter &filter, const FilePath::IterateDirCallback &callBack) const { + if (disconnected()) + return false; + QTC_CHECK(filePath.isAbsolutePath()); CommandLine cmdLine{"find", filter.asFindArguments(filePath.path()), OsType::OsTypeLinux}; @@ -1290,6 +1369,9 @@ void UnixDeviceFileAccess::findUsingLs(const QString ¤t, QStringList *found, const QString &start) const { + if (disconnected()) + return; + const RunResult result = runInShell( {"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux}); const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts); @@ -1349,6 +1431,9 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, const FilePath::IterateDirCallback &callBack, const FileFilter &filter) const { + if (disconnected()) + return; + // We try to use 'find' first, because that can filter better directly. // Unfortunately, it's not installed on all devices by default. if (m_tryUseFind) { @@ -1366,9 +1451,17 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, Environment UnixDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + const RunResult result = runInShell({"env", {}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); return Environment(out.split('\n', Qt::SkipEmptyParts), OsTypeLinux); } +bool UnixDeviceFileAccess::disconnected() const +{ + return false; +} + } // namespace Utils diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 5b7c766a8a7..ba484541275 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -188,6 +188,8 @@ protected: QStringList *found, const QString &start) const; + virtual bool disconnected() const; + private: bool iterateWithFind(const FilePath &filePath, const FileFilter &filter, diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp index b1143c7fab4..be43f2a2062 100644 --- a/src/libs/utils/environment.cpp +++ b/src/libs/utils/environment.cpp @@ -50,7 +50,7 @@ Environment::Environment(const NameValueDictionary &dict) m_changeItems.append(dict); } -NameValueItems Environment::diff(const Environment &other, bool checkAppendPrepend) const +EnvironmentItems Environment::diff(const Environment &other, bool checkAppendPrepend) const { const NameValueDictionary &dict = resolved(); const NameValueDictionary &otherDict = other.resolved(); @@ -393,7 +393,7 @@ void Environment::unset(const QString &key) addItem(Item{std::in_place_index_t(), key}); } -void Environment::modify(const NameValueItems &items) +void Environment::modify(const EnvironmentItems &items) { addItem(Item{std::in_place_index_t(), items}); } @@ -485,7 +485,7 @@ const NameValueDictionary &Environment::resolved() const break; } case Modify: { - NameValueItems items = std::get(item); + EnvironmentItems items = std::get(item); m_dict.modify(items); break; } diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h index 542343aa2a9..1b6b7d2c0e0 100644 --- a/src/libs/utils/environment.h +++ b/src/libs/utils/environment.h @@ -37,7 +37,7 @@ public: void set(const QString &key, const QString &value, bool enabled = true); void setFallback(const QString &key, const QString &value); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); bool hasChanges() const; @@ -79,7 +79,7 @@ public: QStringList expandVariables(const QStringList &input) const; NameValueDictionary toDictionary() const; // FIXME: avoid - NameValueItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid + EnvironmentItems diff(const Environment &other, bool checkAppendPrepend = false) const; // FIXME: avoid struct Entry { QString key; QString value; bool enabled; }; using FindResult = std::optional; @@ -117,7 +117,7 @@ public: QString, // UnsetValue (key) std::tuple, // PrependOrSet (key, value, separator) std::tuple, // AppendOrSet (key, value, separator) - NameValueItems, // Modify + EnvironmentItems, // Modify std::monostate, // SetupEnglishOutput FilePath // SetupSudoAskPass (file path of qtc-askpass or ssh-askpass) >; diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h index 8a2c444cc42..376d1ea08c5 100644 --- a/src/libs/utils/environmentfwd.h +++ b/src/libs/utils/environmentfwd.h @@ -7,19 +7,10 @@ namespace Utils { -class NameValueDictionary; -class NameValueItem; -using NameValueItems = QList; - class Environment; -using EnvironmentItem = NameValueItem; -using EnvironmentItems = NameValueItems; +class EnvironmentItem; +using EnvironmentItems = QList; -class PreprocessorMacroDictionary; -using PreprocessorMacroItem = NameValueItem; -using PreprocessorMacroItems = NameValueItems; - -class NameValueModel; -class EnvironmentModel; +class NameValueDictionary; } // namespace Utils diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp index 13329597846..6ac9b356406 100644 --- a/src/libs/utils/environmentmodel.cpp +++ b/src/libs/utils/environmentmodel.cpp @@ -1,20 +1,458 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "environmentmodel.h" +#include "algorithm.h" #include "environment.h" +#include "hostosinfo.h" +#include "namevaluedictionary.h" +#include "namevalueitem.h" +#include "qtcassert.h" +#include "utilstr.h" + +#include +#include +#include +#include +#include namespace Utils { -Environment EnvironmentModel::baseEnvironment() const +namespace Internal { + +class EnvironmentModelPrivate { - return Environment(baseNameValueDictionary()); +public: + void updateResultNameValueDictionary() + { + m_resultNameValueDictionary = m_baseNameValueDictionary; + m_resultNameValueDictionary.modify(m_items); + // Add removed variables again and mark them as "" so + // that the user can actually see those removals: + for (const EnvironmentItem &item : std::as_const(m_items)) { + if (item.operation == EnvironmentItem::Unset) + m_resultNameValueDictionary.set(item.name, Tr::tr("")); + } + } + + int findInChanges(const QString &name) const + { + for (int i = 0; i < m_items.size(); ++i) + if (m_items.at(i).name.compare(name, + m_baseNameValueDictionary.nameCaseSensitivity()) == 0) { + return i; + } + return -1; + } + + int findInResultInsertPosition(const QString &name) const + { + NameValueDictionary::const_iterator it; + int i = 0; + for (it = m_resultNameValueDictionary.constBegin(); + it != m_resultNameValueDictionary.constEnd(); + ++it, ++i) + if (it.key() > DictKey(name, m_resultNameValueDictionary.nameCaseSensitivity())) + return i; + return m_resultNameValueDictionary.size(); + } + + int findInResult(const QString &name) const + { + NameValueDictionary::const_iterator it; + int i = 0; + for (it = m_resultNameValueDictionary.constBegin(); + it != m_resultNameValueDictionary.constEnd(); + ++it, ++i) + if (m_resultNameValueDictionary.key(it) + .compare(name, m_resultNameValueDictionary.nameCaseSensitivity()) == 0) { + return i; + } + return -1; + } + + NameValueDictionary m_baseNameValueDictionary; + NameValueDictionary m_resultNameValueDictionary; + EnvironmentItems m_items; +}; + +} // namespace Internal + +EnvironmentModel::EnvironmentModel(QObject *parent) + : QAbstractTableModel(parent) + , d(std::make_unique()) +{} + +EnvironmentModel::~EnvironmentModel() = default; + +QString EnvironmentModel::indexToVariable(const QModelIndex &index) const +{ + const auto it = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); + return d->m_resultNameValueDictionary.key(it); } void EnvironmentModel::setBaseEnvironment(const Environment &env) { - setBaseNameValueDictionary(env.toDictionary()); + const NameValueDictionary dictionary = env.toDictionary(); + if (d->m_baseNameValueDictionary == dictionary) + return; + beginResetModel(); + d->m_baseNameValueDictionary = dictionary; + d->updateResultNameValueDictionary(); + endResetModel(); +} + +int EnvironmentModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return d->m_resultNameValueDictionary.size(); +} +int EnvironmentModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return 2; +} + +bool EnvironmentModel::changes(const QString &name) const +{ + return d->findInChanges(name) >= 0; +} + +Environment EnvironmentModel::baseEnvironment() const +{ + return Environment(d->m_baseNameValueDictionary); +} + +QVariant EnvironmentModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + const auto resultIterator = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); + + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + case Qt::ToolTipRole: + if (index.column() == 0) + return d->m_resultNameValueDictionary.key(resultIterator); + if (index.column() == 1) { + // Do not return "" when editing a previously unset variable: + if (role == Qt::EditRole) { + int pos = d->findInChanges(indexToVariable(index)); + if (pos != -1 && d->m_items.at(pos).operation == EnvironmentItem::Unset) + return QString(); + } + QString value = d->m_resultNameValueDictionary.value(resultIterator); + if (role == Qt::ToolTipRole && value.length() > 80) { + if (currentEntryIsPathList(index)) { + // For path lists, display one entry per line without separator + const QChar sep = Utils::HostOsInfo::pathListSeparator(); + value = value.replace(sep, '\n'); + } else { + // Use html to enable text wrapping + value = value.toHtmlEscaped(); + value.prepend(QLatin1String("")); + value.append(QLatin1String("")); + } + } + return value; + } + break; + case Qt::FontRole: { + QFont f; + f.setStrikeOut(!d->m_resultNameValueDictionary.isEnabled(resultIterator)); + return f; + } + case Qt::ForegroundRole: { + const QPalette p = QGuiApplication::palette(); + return p.color(changes(d->m_resultNameValueDictionary.key(resultIterator)) + ? QPalette::Link : QPalette::Text); + } + } + return QVariant(); +} + +Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const +{ + Q_UNUSED(index) + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + return section == 0 ? Tr::tr("Variable") : Tr::tr("Value"); +} + +/// ***************** +/// Utility functions +/// ***************** +QModelIndex EnvironmentModel::variableToIndex(const QString &name) const +{ + int row = d->findInResult(name); + if (row == -1) + return QModelIndex(); + return index(row, 0); +} + +bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || role != Qt::EditRole) + return false; + + // ignore changes to already set values: + if (data(index, role) == value) + return true; + + const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString(); + const QString oldValue = data(this->index(index.row(), 1, QModelIndex()), Qt::EditRole).toString(); + int changesPos = d->findInChanges(oldName); + + if (index.column() == 0) { + //fail if a variable with the same name already exists + const QString &newName = HostOsInfo::isWindowsHost() ? value.toString().toUpper() + : value.toString(); + if (newName.isEmpty() || newName.contains('=')) + return false; + // Does the new name exist already? + if (d->m_resultNameValueDictionary.hasKey(newName) || newName.isEmpty()) + return false; + + EnvironmentItem newVariable(newName, oldValue); + + if (changesPos != -1) + resetVariable(oldName); // restore the original base variable again + + QModelIndex newIndex = addVariable(newVariable); // add the new variable + emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value + return true; + } else if (index.column() == 1) { + // We are changing an existing value: + const QString stringValue = value.toString(); + if (changesPos != -1) { + const auto oldIt = d->m_baseNameValueDictionary.constFind(oldName); + const auto newIt = d->m_resultNameValueDictionary.constFind(oldName); + // We have already changed this value + if (oldIt != d->m_baseNameValueDictionary.constEnd() + && stringValue == d->m_baseNameValueDictionary.value(oldIt) + && d->m_baseNameValueDictionary.isEnabled(oldIt) + == d->m_resultNameValueDictionary.isEnabled(newIt)) { + // ... and now went back to the base value + d->m_items.removeAt(changesPos); + } else { + // ... and changed it again + d->m_items[changesPos].value = stringValue; + if (d->m_items[changesPos].operation == EnvironmentItem::Unset) + d->m_items[changesPos].operation = EnvironmentItem::SetEnabled; + } + } else { + // Add a new change item: + d->m_items.append(EnvironmentItem(oldName, stringValue)); + } + d->updateResultNameValueDictionary(); + emit dataChanged(index, index); + emit userChangesChanged(); + return true; + } + return false; +} + +QModelIndex EnvironmentModel::addVariable() +{ + return addVariable(EnvironmentItem("NEWVAR", "VALUE")); +} + +QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item) +{ + // Return existing index if the name is already in the result set: + int pos = d->findInResult(item.name); + if (pos >= 0 && pos < d->m_resultNameValueDictionary.size()) + return index(pos, 0, QModelIndex()); + + int insertPos = d->findInResultInsertPosition(item.name); + int changePos = d->findInChanges(item.name); + if (d->m_baseNameValueDictionary.hasKey(item.name)) { + // We previously unset this! + Q_ASSERT(changePos >= 0); + // Do not insert a line here as we listed the variable as before! + Q_ASSERT(d->m_items.at(changePos).name == item.name); + Q_ASSERT(d->m_items.at(changePos).operation == EnvironmentItem::Unset); + Q_ASSERT(d->m_items.at(changePos).value.isEmpty()); + d->m_items[changePos] = item; + emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex())); + } else { + // We add something that is not in the base dictionary + // Insert a new line! + beginInsertRows(QModelIndex(), insertPos, insertPos); + Q_ASSERT(changePos < 0); + d->m_items.append(item); + d->updateResultNameValueDictionary(); + endInsertRows(); + } + emit userChangesChanged(); + return index(insertPos, 0, QModelIndex()); +} + +void EnvironmentModel::resetVariable(const QString &name) +{ + int rowInChanges = d->findInChanges(name); + if (rowInChanges < 0) + return; + + int rowInResult = d->findInResult(name); + if (rowInResult < 0) + return; + + if (d->m_baseNameValueDictionary.hasKey(name)) { + d->m_items.removeAt(rowInChanges); + d->updateResultNameValueDictionary(); + emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex())); + emit userChangesChanged(); + } else { + // Remove the line completely! + beginRemoveRows(QModelIndex(), rowInResult, rowInResult); + d->m_items.removeAt(rowInChanges); + d->updateResultNameValueDictionary(); + endRemoveRows(); + emit userChangesChanged(); + } +} + +void EnvironmentModel::unsetVariable(const QString &name) +{ + // This does not change the number of rows as we will display a + // in place of the original variable! + int row = d->findInResult(name); + if (row < 0) + return; + + // look in d->m_items for the variable + int pos = d->findInChanges(name); + if (pos != -1) { + d->m_items[pos].operation = EnvironmentItem::Unset; + d->m_items[pos].value.clear(); + d->updateResultNameValueDictionary(); + emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); + emit userChangesChanged(); + return; + } + d->m_items.append(EnvironmentItem(name, QString(), EnvironmentItem::Unset)); + d->updateResultNameValueDictionary(); + emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); + emit userChangesChanged(); +} + +void EnvironmentModel::toggleVariable(const QModelIndex &idx) +{ + const QString name = indexToVariable(idx); + const auto newIt = d->m_resultNameValueDictionary.constFind(name); + QTC_ASSERT(newIt != d->m_resultNameValueDictionary.constEnd(), return); + const auto op = d->m_resultNameValueDictionary.isEnabled(newIt) + ? EnvironmentItem::SetDisabled : EnvironmentItem::SetEnabled; + const int changesPos = d->findInChanges(name); + if (changesPos != -1) { + const auto oldIt = d->m_baseNameValueDictionary.constFind(name); + if (oldIt == d->m_baseNameValueDictionary.constEnd() + || oldIt.value().first != newIt.value().first) { + d->m_items[changesPos].operation = op; + } else { + d->m_items.removeAt(changesPos); + } + } else { + d->m_items.append({name, d->m_resultNameValueDictionary.value(newIt), op}); + } + d->updateResultNameValueDictionary(); + emit dataChanged(index(idx.row(), 0), index(idx.row(), 1)); + emit userChangesChanged(); +} + +bool EnvironmentModel::isUnset(const QString &name) +{ + const int pos = d->findInChanges(name); + return pos == -1 ? false : d->m_items.at(pos).operation == EnvironmentItem::Unset; +} + +bool EnvironmentModel::isEnabled(const QString &name) const +{ + return d->m_resultNameValueDictionary.isEnabled(d->m_resultNameValueDictionary.constFind(name)); +} + +bool EnvironmentModel::canReset(const QString &name) +{ + return d->m_baseNameValueDictionary.hasKey(name); +} + +EnvironmentItems EnvironmentModel::userChanges() const +{ + return d->m_items; +} + +void EnvironmentModel::setUserChanges(const EnvironmentItems &items) +{ + EnvironmentItems filtered = Utils::filtered(items, [](const EnvironmentItem &i) { + return i.name != "export " && !i.name.contains('='); + }); + // We assume nobody is reordering the items here. + if (filtered == d->m_items) + return; + beginResetModel(); + d->m_items = filtered; + for (EnvironmentItem &item : d->m_items) { + QString &name = item.name; + name = name.trimmed(); + if (name.startsWith("export ")) + name = name.mid(7).trimmed(); + if (d->m_baseNameValueDictionary.osType() == OsTypeWindows) { + // NameValueDictionary variable names are case-insensitive under windows, but we still + // want to preserve the case of pre-existing variables. + auto it = d->m_baseNameValueDictionary.constFind(name); + if (it != d->m_baseNameValueDictionary.constEnd()) + name = d->m_baseNameValueDictionary.key(it); + } + } + + d->updateResultNameValueDictionary(); + endResetModel(); + emit userChangesChanged(); +} + +bool EnvironmentModel::currentEntryIsPathList(const QModelIndex ¤t) const +{ + if (!current.isValid()) + return false; + + // Look at the name first and check it against some well-known path variables. Extend as needed. + const QString varName = indexToVariable(current); + if (varName.compare("PATH", Utils::HostOsInfo::fileNameCaseSensitivity()) == 0) + return true; + if (Utils::HostOsInfo::isMacHost() && varName == "DYLD_LIBRARY_PATH") + return true; + if (Utils::HostOsInfo::isAnyUnixHost() && varName == "LD_LIBRARY_PATH") + return true; + if (varName == "PKG_CONFIG_DIR") + return true; + if (Utils::HostOsInfo::isWindowsHost() + && QStringList{"INCLUDE", "LIB", "LIBPATH"}.contains(varName)) { + return true; + } + + // Now check the value: If it's a list of strings separated by the platform's path separator + // and at least one of the strings is an existing directory, then that's enough proof for us. + QModelIndex valueIndex = current; + if (valueIndex.column() == 0) + valueIndex = valueIndex.siblingAtColumn(1); + const QStringList entries = data(valueIndex).toString() + .split(Utils::HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); + if (entries.length() < 2) + return false; + return Utils::anyOf(entries, [](const QString &d) { return QFileInfo(d).isDir(); }); } } // namespace Utils diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h index 82bf98d43f5..07670bd13fc 100644 --- a/src/libs/utils/environmentmodel.h +++ b/src/libs/utils/environmentmodel.h @@ -1,19 +1,64 @@ -// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once #include "utils_global.h" -#include "namevaluemodel.h" +#include "environmentfwd.h" + +#include + +#include namespace Utils { -class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel +namespace Internal { class EnvironmentModelPrivate; } + +class QTCREATOR_UTILS_EXPORT EnvironmentModel : public QAbstractTableModel { + Q_OBJECT + public: + explicit EnvironmentModel(QObject *parent = nullptr); + ~EnvironmentModel() override; + + int rowCount(const QModelIndex &parent) const override; + int columnCount(const QModelIndex &parent) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + QVariant headerData(int section, + Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + Environment baseEnvironment() const; void setBaseEnvironment(const Environment &env); + + QModelIndex addVariable(); + QModelIndex addVariable(const EnvironmentItem &item); + void resetVariable(const QString &name); + void unsetVariable(const QString &name); + void toggleVariable(const QModelIndex &index); + bool isUnset(const QString &name); + bool isEnabled(const QString &name) const; + bool canReset(const QString &name); + QString indexToVariable(const QModelIndex &index) const; + QModelIndex variableToIndex(const QString &name) const; + bool changes(const QString &key) const; + EnvironmentItems userChanges() const; + void setUserChanges(const EnvironmentItems &items); + bool currentEntryIsPathList(const QModelIndex ¤t) const; + +signals: + void userChangesChanged(); + /// Hint to the view where it should make sense to focus on next + // This is a hack since there is no way for a model to suggest + // the next interesting place to focus on to the view. + void focusIndex(const QModelIndex &index); + +private: + std::unique_ptr d; }; } // namespace Utils diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 5678be86b2b..562f3247bd8 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -2334,12 +2334,30 @@ QTCREATOR_UTILS_EXPORT bool operator!=(const FilePath &first, const FilePath &se QTCREATOR_UTILS_EXPORT bool operator<(const FilePath &first, const FilePath &second) { - const int cmp = first.pathView().compare(second.pathView(), first.caseSensitivity()); - if (cmp != 0) - return cmp < 0; - if (first.host() != second.host()) - return first.host() < second.host(); - return first.scheme() < second.scheme(); + const bool firstNeedsDevice = first.needsDevice(); + const bool secondNeedsDevice = second.needsDevice(); + + // If either needs a device, we have to compare host and scheme first. + if (firstNeedsDevice || secondNeedsDevice) { + // Paths needing a device are "larger" than those not needing one. + if (firstNeedsDevice < secondNeedsDevice) + return true; + else if (firstNeedsDevice > secondNeedsDevice) + return false; + + // First we sort by scheme ... + const int s = first.scheme().compare(second.scheme()); + if (s != 0) + return s < 0; + + // than by host ... + const int h = first.host().compare(second.host()); + if (h != 0) + return h < 0; + } + + const int p = first.pathView().compare(second.pathView(), first.caseSensitivity()); + return p < 0; } QTCREATOR_UTILS_EXPORT bool operator<=(const FilePath &first, const FilePath &second) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 4530ea206b8..a2998e2f07d 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -238,6 +238,11 @@ bool FileSaver::finalize() } TempFileSaver::TempFileSaver(const QString &templ) +{ + initFromString(templ); +} + +void TempFileSaver::initFromString(const QString &templ) { m_file.reset(new QTemporaryFile{}); auto tempFile = static_cast(m_file.get()); @@ -253,6 +258,29 @@ TempFileSaver::TempFileSaver(const QString &templ) m_filePath = FilePath::fromString(tempFile->fileName()); } +TempFileSaver::TempFileSaver(const FilePath &templ) +{ + if (templ.isEmpty() || !templ.needsDevice()) { + initFromString(templ.path()); + } else { + expected_str result = templ.createTempFile(); + if (!result) { + m_errorString = Tr::tr("Cannot create temporary file %1: %2") + .arg(templ.toUserOutput(), result.error()); + m_hasError = true; + return; + } + + m_file.reset(new QFile(result->toFSPathString())); + if (!m_file->open(QIODevice::WriteOnly)) { + m_errorString = Tr::tr("Cannot create temporary file %1: %2") + .arg(result->toUserOutput(), m_file->errorString()); + m_hasError = true; + } + m_filePath = *result; + } +} + TempFileSaver::~TempFileSaver() { m_file.reset(); diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index 316030b0397..b20f7568dbe 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -222,10 +222,14 @@ class QTCREATOR_UTILS_EXPORT TempFileSaver : public FileSaverBase { public: explicit TempFileSaver(const QString &templ = QString()); + explicit TempFileSaver(const FilePath &templ); ~TempFileSaver() override; void setAutoRemove(bool on) { m_autoRemove = on; } +protected: + void initFromString(const QString &templ); + private: bool m_autoRemove = true; }; diff --git a/src/libs/utils/namevaluedictionary.cpp b/src/libs/utils/namevaluedictionary.cpp index 05ff4761dd1..d93298b3f15 100644 --- a/src/libs/utils/namevaluedictionary.cpp +++ b/src/libs/utils/namevaluedictionary.cpp @@ -97,34 +97,34 @@ int NameValueDictionary::size() const return m_values.size(); } -void NameValueDictionary::modify(const NameValueItems &items) +void NameValueDictionary::modify(const EnvironmentItems &items) { NameValueDictionary resultKeyValueDictionary = *this; - for (const NameValueItem &item : items) + for (const EnvironmentItem &item : items) item.apply(&resultKeyValueDictionary); *this = resultKeyValueDictionary; } -NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const +EnvironmentItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const { NameValueMap::const_iterator thisIt = constBegin(); NameValueMap::const_iterator otherIt = other.constBegin(); - NameValueItems result; + EnvironmentItems result; while (thisIt != constEnd() || otherIt != other.constEnd()) { if (thisIt == constEnd()) { result.append({other.key(otherIt), other.value(otherIt), - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else if (otherIt == other.constEnd()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() < otherIt.key()) { - result.append(NameValueItem(key(thisIt), QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(key(thisIt), QString(), EnvironmentItem::Unset)); ++thisIt; } else if (thisIt.key() > otherIt.key()) { result.append({other.key(otherIt), otherIt.value().first, - otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + otherIt.value().second ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); ++otherIt; } else { const QString &oldValue = thisIt.value().first; @@ -137,16 +137,16 @@ NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool QString appended = newValue.right(newValue.size() - oldValue.size()); if (appended.startsWith(OsSpecificAspects::pathListSeparator(osType()))) appended.remove(0, 1); - result.append(NameValueItem(other.key(otherIt), appended, NameValueItem::Append)); + result.append(EnvironmentItem(other.key(otherIt), appended, EnvironmentItem::Append)); } else if (checkAppendPrepend && newValue.endsWith(oldValue) && oldEnabled == newEnabled) { QString prepended = newValue.left(newValue.size() - oldValue.size()); if (prepended.endsWith(OsSpecificAspects::pathListSeparator(osType()))) prepended.chop(1); - result.append(NameValueItem(other.key(otherIt), prepended, NameValueItem::Prepend)); + result.append(EnvironmentItem(other.key(otherIt), prepended, EnvironmentItem::Prepend)); } else { result.append({other.key(otherIt), newValue, newEnabled - ? NameValueItem::SetEnabled : NameValueItem::SetDisabled}); + ? EnvironmentItem::SetEnabled : EnvironmentItem::SetDisabled}); } } ++otherIt; diff --git a/src/libs/utils/namevaluedictionary.h b/src/libs/utils/namevaluedictionary.h index 722558f8912..87d81249704 100644 --- a/src/libs/utils/namevaluedictionary.h +++ b/src/libs/utils/namevaluedictionary.h @@ -48,9 +48,9 @@ public: QString value(const QString &key) const; void set(const QString &key, const QString &value, bool enabled = true); void unset(const QString &key); - void modify(const NameValueItems &items); + void modify(const EnvironmentItems &items); /// Return the KeyValueDictionary changes necessary to modify this into the other environment. - NameValueItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; + EnvironmentItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const; bool hasKey(const QString &key) const; OsType osType() const; Qt::CaseSensitivity nameCaseSensitivity() const; diff --git a/src/libs/utils/namevalueitem.cpp b/src/libs/utils/namevalueitem.cpp index adc7ff5afc9..3f4cdbd4b2c 100644 --- a/src/libs/utils/namevalueitem.cpp +++ b/src/libs/utils/namevalueitem.cpp @@ -10,34 +10,34 @@ namespace Utils { -void NameValueItem::sort(NameValueItems *list) +void EnvironmentItem::sort(EnvironmentItems *list) { - Utils::sort(*list, &NameValueItem::name); + Utils::sort(*list, &EnvironmentItem::name); } -NameValueItems NameValueItem::fromStringList(const QStringList &list) +EnvironmentItems EnvironmentItem::fromStringList(const QStringList &list) { - NameValueItems result; + EnvironmentItems result; for (const QString &string : list) { int pos = string.indexOf("+="); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Append}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Append}); continue; } pos = string.indexOf("=+"); if (pos != -1) { - result.append({string.left(pos), string.mid(pos + 2), NameValueItem::Prepend}); + result.append({string.left(pos), string.mid(pos + 2), EnvironmentItem::Prepend}); continue; } pos = string.indexOf('=', 1); if (pos == -1) { - result.append(NameValueItem(string, QString(), NameValueItem::Unset)); + result.append(EnvironmentItem(string, QString(), EnvironmentItem::Unset)); continue; } const int hashPos = string.indexOf('#'); if (hashPos != -1 && hashPos < pos) { result.append({string.mid(hashPos + 1, pos - hashPos - 1), string.mid(pos + 1), - NameValueItem::SetDisabled}); + EnvironmentItem::SetDisabled}); } else { result.append({string.left(pos), string.mid(pos + 1)}); } @@ -45,49 +45,49 @@ NameValueItems NameValueItem::fromStringList(const QStringList &list) return result; } -QStringList NameValueItem::toStringList(const NameValueItems &list) +QStringList EnvironmentItem::toStringList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { switch (item.operation) { - case NameValueItem::Unset: + case EnvironmentItem::Unset: return item.name; - case NameValueItem::Append: + case EnvironmentItem::Append: return QString(item.name + "+=" + item.value); - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: return QString(item.name + "=+" + item.value); - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: return QString('#' + item.name + '=' + item.value); - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: return QString(item.name + '=' + item.value); } return QString(); }); } -NameValueItems NameValueItem::itemsFromVariantList(const QVariantList &list) +EnvironmentItems EnvironmentItem::itemsFromVariantList(const QVariantList &list) { - return Utils::transform(list, [](const QVariant &item) { + return Utils::transform(list, [](const QVariant &item) { return itemFromVariantList(item.toList()); }); } -QVariantList NameValueItem::toVariantList(const NameValueItems &list) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItems &list) { - return Utils::transform(list, [](const NameValueItem &item) { + return Utils::transform(list, [](const EnvironmentItem &item) { return QVariant(toVariantList(item)); }); } -NameValueItem NameValueItem::itemFromVariantList(const QVariantList &list) +EnvironmentItem EnvironmentItem::itemFromVariantList(const QVariantList &list) { - QTC_ASSERT(list.size() == 3, return NameValueItem("", "")); + QTC_ASSERT(list.size() == 3, return EnvironmentItem("", "")); QString key = list.value(0).toString(); Operation operation = Operation(list.value(1).toInt()); QString value = list.value(2).toString(); - return NameValueItem(key, value, operation); + return EnvironmentItem(key, value, operation); } -QVariantList NameValueItem::toVariantList(const NameValueItem &item) +QVariantList EnvironmentItem::toVariantList(const EnvironmentItem &item) { return QVariantList() << item.name << item.operation << item.value; } @@ -118,7 +118,7 @@ static QString expand(const NameValueDictionary *dictionary, QString value) return value; } -void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const +void EnvironmentItem::apply(NameValueDictionary *dictionary, Operation op) const { switch (op) { case SetEnabled: @@ -173,26 +173,26 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const } } -QDebug operator<<(QDebug debug, const NameValueItem &i) +QDebug operator<<(QDebug debug, const EnvironmentItem &i) { QDebugStateSaver saver(debug); debug.noquote(); debug.nospace(); debug << "KeyValueItem("; switch (i.operation) { - case NameValueItem::SetEnabled: + case EnvironmentItem::SetEnabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"'; break; - case NameValueItem::SetDisabled: + case EnvironmentItem::SetDisabled: debug << "set \"" << i.name << "\" to \"" << i.value << '"' << "[disabled]"; break; - case NameValueItem::Unset: + case EnvironmentItem::Unset: debug << "unset \"" << i.name << '"'; break; - case NameValueItem::Prepend: + case EnvironmentItem::Prepend: debug << "prepend to \"" << i.name << "\":\"" << i.value << '"'; break; - case NameValueItem::Append: + case EnvironmentItem::Append: debug << "append to \"" << i.name << "\":\"" << i.value << '"'; break; } diff --git a/src/libs/utils/namevalueitem.h b/src/libs/utils/namevalueitem.h index 62ba9d25baf..6ad5ed03791 100644 --- a/src/libs/utils/namevalueitem.h +++ b/src/libs/utils/namevalueitem.h @@ -13,12 +13,12 @@ namespace Utils { -class QTCREATOR_UTILS_EXPORT NameValueItem +class QTCREATOR_UTILS_EXPORT EnvironmentItem { public: enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled }; - NameValueItem() = default; - NameValueItem(const QString &key, const QString &value, Operation operation = SetEnabled) + EnvironmentItem() = default; + EnvironmentItem(const QString &key, const QString &value, Operation operation = SetEnabled) : name(key) , value(value) , operation(operation) @@ -26,25 +26,25 @@ public: void apply(NameValueDictionary *dictionary) const { apply(dictionary, operation); } - static void sort(NameValueItems *list); - static NameValueItems fromStringList(const QStringList &list); - static QStringList toStringList(const NameValueItems &list); - static NameValueItems itemsFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItems &list); - static NameValueItem itemFromVariantList(const QVariantList &list); - static QVariantList toVariantList(const NameValueItem &item); + static void sort(EnvironmentItems *list); + static EnvironmentItems fromStringList(const QStringList &list); + static QStringList toStringList(const EnvironmentItems &list); + static EnvironmentItems itemsFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItems &list); + static EnvironmentItem itemFromVariantList(const QVariantList &list); + static QVariantList toVariantList(const EnvironmentItem &item); - friend bool operator==(const NameValueItem &first, const NameValueItem &second) + friend bool operator==(const EnvironmentItem &first, const EnvironmentItem &second) { return first.operation == second.operation && first.name == second.name && first.value == second.value; } - friend bool operator!=(const NameValueItem &first, const NameValueItem &second) + friend bool operator!=(const EnvironmentItem &first, const EnvironmentItem &second) { return !(first == second); } - friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const NameValueItem &i); + friend QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const EnvironmentItem &i); public: QString name; diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/namevaluemodel.cpp deleted file mode 100644 index 57327c4ebed..00000000000 --- a/src/libs/utils/namevaluemodel.cpp +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "namevaluemodel.h" - -#include "algorithm.h" -#include "hostosinfo.h" -#include "namevaluedictionary.h" -#include "namevalueitem.h" -#include "qtcassert.h" -#include "utilstr.h" - -#include -#include -#include -#include -#include - -namespace Utils { - -namespace Internal { - -class NameValueModelPrivate -{ -public: - void updateResultNameValueDictionary() - { - m_resultNameValueDictionary = m_baseNameValueDictionary; - m_resultNameValueDictionary.modify(m_items); - // Add removed variables again and mark them as "" so - // that the user can actually see those removals: - for (const NameValueItem &item : std::as_const(m_items)) { - if (item.operation == NameValueItem::Unset) - m_resultNameValueDictionary.set(item.name, Tr::tr("")); - } - } - - int findInChanges(const QString &name) const - { - for (int i = 0; i < m_items.size(); ++i) - if (m_items.at(i).name.compare(name, - m_baseNameValueDictionary.nameCaseSensitivity()) == 0) { - return i; - } - return -1; - } - - int findInResultInsertPosition(const QString &name) const - { - NameValueDictionary::const_iterator it; - int i = 0; - for (it = m_resultNameValueDictionary.constBegin(); - it != m_resultNameValueDictionary.constEnd(); - ++it, ++i) - if (it.key() > DictKey(name, m_resultNameValueDictionary.nameCaseSensitivity())) - return i; - return m_resultNameValueDictionary.size(); - } - - int findInResult(const QString &name) const - { - NameValueDictionary::const_iterator it; - int i = 0; - for (it = m_resultNameValueDictionary.constBegin(); - it != m_resultNameValueDictionary.constEnd(); - ++it, ++i) - if (m_resultNameValueDictionary.key(it) - .compare(name, m_resultNameValueDictionary.nameCaseSensitivity()) == 0) { - return i; - } - return -1; - } - - NameValueDictionary m_baseNameValueDictionary; - NameValueDictionary m_resultNameValueDictionary; - NameValueItems m_items; -}; - -} // namespace Internal - -NameValueModel::NameValueModel(QObject *parent) - : QAbstractTableModel(parent) - , d(std::make_unique()) -{} - -NameValueModel::~NameValueModel() = default; - -QString NameValueModel::indexToVariable(const QModelIndex &index) const -{ - const auto it = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); - return d->m_resultNameValueDictionary.key(it); -} - -void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dictionary) -{ - if (d->m_baseNameValueDictionary == dictionary) - return; - beginResetModel(); - d->m_baseNameValueDictionary = dictionary; - d->updateResultNameValueDictionary(); - endResetModel(); -} - -int NameValueModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - - return d->m_resultNameValueDictionary.size(); -} -int NameValueModel::columnCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - - return 2; -} - -bool NameValueModel::changes(const QString &name) const -{ - return d->findInChanges(name) >= 0; -} - -const NameValueDictionary &NameValueModel::baseNameValueDictionary() const -{ - return d->m_baseNameValueDictionary; -} - -QVariant NameValueModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - const auto resultIterator = std::next(d->m_resultNameValueDictionary.constBegin(), index.row()); - - switch (role) { - case Qt::DisplayRole: - case Qt::EditRole: - case Qt::ToolTipRole: - if (index.column() == 0) - return d->m_resultNameValueDictionary.key(resultIterator); - if (index.column() == 1) { - // Do not return "" when editing a previously unset variable: - if (role == Qt::EditRole) { - int pos = d->findInChanges(indexToVariable(index)); - if (pos != -1 && d->m_items.at(pos).operation == NameValueItem::Unset) - return QString(); - } - QString value = d->m_resultNameValueDictionary.value(resultIterator); - if (role == Qt::ToolTipRole && value.length() > 80) { - if (currentEntryIsPathList(index)) { - // For path lists, display one entry per line without separator - const QChar sep = Utils::HostOsInfo::pathListSeparator(); - value = value.replace(sep, '\n'); - } else { - // Use html to enable text wrapping - value = value.toHtmlEscaped(); - value.prepend(QLatin1String("")); - value.append(QLatin1String("")); - } - } - return value; - } - break; - case Qt::FontRole: { - QFont f; - f.setStrikeOut(!d->m_resultNameValueDictionary.isEnabled(resultIterator)); - return f; - } - case Qt::ForegroundRole: { - const QPalette p = QGuiApplication::palette(); - return p.color(changes(d->m_resultNameValueDictionary.key(resultIterator)) - ? QPalette::Link : QPalette::Text); - } - } - return QVariant(); -} - -Qt::ItemFlags NameValueModel::flags(const QModelIndex &index) const -{ - Q_UNUSED(index) - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; -} - -QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Vertical || role != Qt::DisplayRole) - return QVariant(); - return section == 0 ? Tr::tr("Variable") : Tr::tr("Value"); -} - -/// ***************** -/// Utility functions -/// ***************** -QModelIndex NameValueModel::variableToIndex(const QString &name) const -{ - int row = d->findInResult(name); - if (row == -1) - return QModelIndex(); - return index(row, 0); -} - -bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (!index.isValid() || role != Qt::EditRole) - return false; - - // ignore changes to already set values: - if (data(index, role) == value) - return true; - - const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString(); - const QString oldValue = data(this->index(index.row(), 1, QModelIndex()), Qt::EditRole).toString(); - int changesPos = d->findInChanges(oldName); - - if (index.column() == 0) { - //fail if a variable with the same name already exists - const QString &newName = HostOsInfo::isWindowsHost() ? value.toString().toUpper() - : value.toString(); - if (newName.isEmpty() || newName.contains('=')) - return false; - // Does the new name exist already? - if (d->m_resultNameValueDictionary.hasKey(newName) || newName.isEmpty()) - return false; - - NameValueItem newVariable(newName, oldValue); - - if (changesPos != -1) - resetVariable(oldName); // restore the original base variable again - - QModelIndex newIndex = addVariable(newVariable); // add the new variable - emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value - return true; - } else if (index.column() == 1) { - // We are changing an existing value: - const QString stringValue = value.toString(); - if (changesPos != -1) { - const auto oldIt = d->m_baseNameValueDictionary.constFind(oldName); - const auto newIt = d->m_resultNameValueDictionary.constFind(oldName); - // We have already changed this value - if (oldIt != d->m_baseNameValueDictionary.constEnd() - && stringValue == d->m_baseNameValueDictionary.value(oldIt) - && d->m_baseNameValueDictionary.isEnabled(oldIt) - == d->m_resultNameValueDictionary.isEnabled(newIt)) { - // ... and now went back to the base value - d->m_items.removeAt(changesPos); - } else { - // ... and changed it again - d->m_items[changesPos].value = stringValue; - if (d->m_items[changesPos].operation == NameValueItem::Unset) - d->m_items[changesPos].operation = NameValueItem::SetEnabled; - } - } else { - // Add a new change item: - d->m_items.append(NameValueItem(oldName, stringValue)); - } - d->updateResultNameValueDictionary(); - emit dataChanged(index, index); - emit userChangesChanged(); - return true; - } - return false; -} - -QModelIndex NameValueModel::addVariable() -{ - return addVariable(NameValueItem("NEWVAR", "VALUE")); -} - -QModelIndex NameValueModel::addVariable(const NameValueItem &item) -{ - // Return existing index if the name is already in the result set: - int pos = d->findInResult(item.name); - if (pos >= 0 && pos < d->m_resultNameValueDictionary.size()) - return index(pos, 0, QModelIndex()); - - int insertPos = d->findInResultInsertPosition(item.name); - int changePos = d->findInChanges(item.name); - if (d->m_baseNameValueDictionary.hasKey(item.name)) { - // We previously unset this! - Q_ASSERT(changePos >= 0); - // Do not insert a line here as we listed the variable as before! - Q_ASSERT(d->m_items.at(changePos).name == item.name); - Q_ASSERT(d->m_items.at(changePos).operation == NameValueItem::Unset); - Q_ASSERT(d->m_items.at(changePos).value.isEmpty()); - d->m_items[changePos] = item; - emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex())); - } else { - // We add something that is not in the base dictionary - // Insert a new line! - beginInsertRows(QModelIndex(), insertPos, insertPos); - Q_ASSERT(changePos < 0); - d->m_items.append(item); - d->updateResultNameValueDictionary(); - endInsertRows(); - } - emit userChangesChanged(); - return index(insertPos, 0, QModelIndex()); -} - -void NameValueModel::resetVariable(const QString &name) -{ - int rowInChanges = d->findInChanges(name); - if (rowInChanges < 0) - return; - - int rowInResult = d->findInResult(name); - if (rowInResult < 0) - return; - - if (d->m_baseNameValueDictionary.hasKey(name)) { - d->m_items.removeAt(rowInChanges); - d->updateResultNameValueDictionary(); - emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex())); - emit userChangesChanged(); - } else { - // Remove the line completely! - beginRemoveRows(QModelIndex(), rowInResult, rowInResult); - d->m_items.removeAt(rowInChanges); - d->updateResultNameValueDictionary(); - endRemoveRows(); - emit userChangesChanged(); - } -} - -void NameValueModel::unsetVariable(const QString &name) -{ - // This does not change the number of rows as we will display a - // in place of the original variable! - int row = d->findInResult(name); - if (row < 0) - return; - - // look in d->m_items for the variable - int pos = d->findInChanges(name); - if (pos != -1) { - d->m_items[pos].operation = NameValueItem::Unset; - d->m_items[pos].value.clear(); - d->updateResultNameValueDictionary(); - emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); - emit userChangesChanged(); - return; - } - d->m_items.append(NameValueItem(name, QString(), NameValueItem::Unset)); - d->updateResultNameValueDictionary(); - emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex())); - emit userChangesChanged(); -} - -void NameValueModel::toggleVariable(const QModelIndex &idx) -{ - const QString name = indexToVariable(idx); - const auto newIt = d->m_resultNameValueDictionary.constFind(name); - QTC_ASSERT(newIt != d->m_resultNameValueDictionary.constEnd(), return); - const auto op = d->m_resultNameValueDictionary.isEnabled(newIt) - ? NameValueItem::SetDisabled : NameValueItem::SetEnabled; - const int changesPos = d->findInChanges(name); - if (changesPos != -1) { - const auto oldIt = d->m_baseNameValueDictionary.constFind(name); - if (oldIt == d->m_baseNameValueDictionary.constEnd() - || oldIt.value().first != newIt.value().first) { - d->m_items[changesPos].operation = op; - } else { - d->m_items.removeAt(changesPos); - } - } else { - d->m_items.append({name, d->m_resultNameValueDictionary.value(newIt), op}); - } - d->updateResultNameValueDictionary(); - emit dataChanged(index(idx.row(), 0), index(idx.row(), 1)); - emit userChangesChanged(); -} - -bool NameValueModel::isUnset(const QString &name) -{ - const int pos = d->findInChanges(name); - return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset; -} - -bool NameValueModel::isEnabled(const QString &name) const -{ - return d->m_resultNameValueDictionary.isEnabled(d->m_resultNameValueDictionary.constFind(name)); -} - -bool NameValueModel::canReset(const QString &name) -{ - return d->m_baseNameValueDictionary.hasKey(name); -} - -NameValueItems NameValueModel::userChanges() const -{ - return d->m_items; -} - -void NameValueModel::setUserChanges(const NameValueItems &items) -{ - NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) { - return i.name != "export " && !i.name.contains('='); - }); - // We assume nobody is reordering the items here. - if (filtered == d->m_items) - return; - beginResetModel(); - d->m_items = filtered; - for (NameValueItem &item : d->m_items) { - QString &name = item.name; - name = name.trimmed(); - if (name.startsWith("export ")) - name = name.mid(7).trimmed(); - if (d->m_baseNameValueDictionary.osType() == OsTypeWindows) { - // NameValueDictionary variable names are case-insensitive under windows, but we still - // want to preserve the case of pre-existing variables. - auto it = d->m_baseNameValueDictionary.constFind(name); - if (it != d->m_baseNameValueDictionary.constEnd()) - name = d->m_baseNameValueDictionary.key(it); - } - } - - d->updateResultNameValueDictionary(); - endResetModel(); - emit userChangesChanged(); -} - -bool NameValueModel::currentEntryIsPathList(const QModelIndex ¤t) const -{ - if (!current.isValid()) - return false; - - // Look at the name first and check it against some well-known path variables. Extend as needed. - const QString varName = indexToVariable(current); - if (varName.compare("PATH", Utils::HostOsInfo::fileNameCaseSensitivity()) == 0) - return true; - if (Utils::HostOsInfo::isMacHost() && varName == "DYLD_LIBRARY_PATH") - return true; - if (Utils::HostOsInfo::isAnyUnixHost() && varName == "LD_LIBRARY_PATH") - return true; - if (varName == "PKG_CONFIG_DIR") - return true; - if (Utils::HostOsInfo::isWindowsHost() - && QStringList{"INCLUDE", "LIB", "LIBPATH"}.contains(varName)) { - return true; - } - - // Now check the value: If it's a list of strings separated by the platform's path separator - // and at least one of the strings is an existing directory, then that's enough proof for us. - QModelIndex valueIndex = current; - if (valueIndex.column() == 0) - valueIndex = valueIndex.siblingAtColumn(1); - const QStringList entries = data(valueIndex).toString() - .split(Utils::HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts); - if (entries.length() < 2) - return false; - return Utils::anyOf(entries, [](const QString &d) { return QFileInfo(d).isDir(); }); -} - -} // namespace Utils diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/namevaluemodel.h deleted file mode 100644 index 84c1f2cece9..00000000000 --- a/src/libs/utils/namevaluemodel.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2019 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "utils_global.h" - -#include "environmentfwd.h" - -#include - -#include - -namespace Utils { - -namespace Internal { -class NameValueModelPrivate; -} - -class QTCREATOR_UTILS_EXPORT NameValueModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - explicit NameValueModel(QObject *parent = nullptr); - ~NameValueModel() override; - - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant headerData(int section, - Qt::Orientation orientation, - int role = Qt::DisplayRole) const override; - - QModelIndex addVariable(); - QModelIndex addVariable(const NameValueItem &item); - void resetVariable(const QString &name); - void unsetVariable(const QString &name); - void toggleVariable(const QModelIndex &index); - bool isUnset(const QString &name); - bool isEnabled(const QString &name) const; - bool canReset(const QString &name); - QString indexToVariable(const QModelIndex &index) const; - QModelIndex variableToIndex(const QString &name) const; - bool changes(const QString &key) const; - const NameValueDictionary &baseNameValueDictionary() const; - void setBaseNameValueDictionary(const NameValueDictionary &dictionary); - NameValueItems userChanges() const; - void setUserChanges(const NameValueItems &items); - bool currentEntryIsPathList(const QModelIndex ¤t) const; - -signals: - void userChangesChanged(); - /// Hint to the view where it should make sense to focus on next - // This is a hack since there is no way for a model to suggest - // the next interesting place to focus on to the view. - void focusIndex(const QModelIndex &index); - -private: - std::unique_ptr d; -}; - -} // namespace Utils diff --git a/src/libs/utils/namevaluesdialog.cpp b/src/libs/utils/namevaluesdialog.cpp index 4f9537655ef..43511fe57f0 100644 --- a/src/libs/utils/namevaluesdialog.cpp +++ b/src/libs/utils/namevaluesdialog.cpp @@ -70,7 +70,7 @@ NameValueItemsWidget::NameValueItemsWidget(QWidget *parent) layout->addWidget(new QLabel(helpText, this)); const auto checkForItemChange = [this] { - const NameValueItems newItems = environmentItems(); + const EnvironmentItems newItems = environmentItems(); if (newItems != m_originalItems) { m_originalItems = newItems; emit userChangedItems(newItems); @@ -190,8 +190,8 @@ void NameValuesDialog::setPlaceholderText(const QString &text) m_editor->setPlaceholderText(text); } -std::optional NameValuesDialog::getNameValueItems(QWidget *parent, - const NameValueItems &initial, +std::optional NameValuesDialog::getNameValueItems(QWidget *parent, + const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher, const QString &windowTitle) diff --git a/src/libs/utils/namevaluesdialog.h b/src/libs/utils/namevaluesdialog.h index af847bb5a1d..a1e884fe5b5 100644 --- a/src/libs/utils/namevaluesdialog.h +++ b/src/libs/utils/namevaluesdialog.h @@ -34,20 +34,20 @@ signals: private: Internal::TextEditHelper *m_editor; - NameValueItems m_originalItems; + EnvironmentItems m_originalItems; }; class QTCREATOR_UTILS_EXPORT NameValuesDialog : public QDialog { public: - void setNameValueItems(const NameValueItems &items); - NameValueItems nameValueItems() const; + void setNameValueItems(const EnvironmentItems &items); + EnvironmentItems nameValueItems() const; void setPlaceholderText(const QString &text); using Polisher = std::function; - static std::optional getNameValueItems(QWidget *parent = nullptr, - const NameValueItems &initial = {}, + static std::optional getNameValueItems(QWidget *parent = nullptr, + const EnvironmentItems &initial = {}, const QString &placeholderText = {}, Polisher polish = {}, const QString &windowTitle = {}); diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp index ef2ccbc9a08..620adc137c3 100644 --- a/src/libs/utils/namevaluevalidator.cpp +++ b/src/libs/utils/namevaluevalidator.cpp @@ -2,7 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "namevaluevalidator.h" -#include "namevaluemodel.h" + +#include "environmentmodel.h" #include "tooltip/tooltip.h" #include @@ -10,7 +11,7 @@ namespace Utils { NameValueValidator::NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText) diff --git a/src/libs/utils/namevaluevalidator.h b/src/libs/utils/namevaluevalidator.h index bf0f1b27f74..e06560f1896 100644 --- a/src/libs/utils/namevaluevalidator.h +++ b/src/libs/utils/namevaluevalidator.h @@ -16,13 +16,13 @@ QT_END_NAMESPACE namespace Utils { -class NameValueModel; +class EnvironmentModel; class QTCREATOR_UTILS_EXPORT NameValueValidator : public QValidator { public: NameValueValidator(QWidget *parent, - NameValueModel *model, + EnvironmentModel *model, QTreeView *view, const QModelIndex &index, const QString &toolTipText); @@ -33,7 +33,7 @@ public: private: const QString m_toolTipText; - NameValueModel *m_model; + EnvironmentModel *m_model; QTreeView *m_view; QPersistentModelIndex m_index; mutable QTimer m_hideTipTimer; diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp index b710e68723b..1f32cce6bcc 100644 --- a/src/libs/utils/projectintropage.cpp +++ b/src/libs/utils/projectintropage.cpp @@ -82,6 +82,7 @@ ProjectIntroPage::ProjectIntroPage(QWidget *parent) : d->m_pathChooser->setObjectName("baseFolder"); // used by Squish d->m_pathChooser->setExpectedKind(PathChooser::Directory); d->m_pathChooser->setDisabled(d->m_forceSubProject); + d->m_pathChooser->setAllowPathFromDevice(true); d->m_projectsDirectoryCheckBox = new QCheckBox(Tr::tr("Use as default project location")); d->m_projectsDirectoryCheckBox->setObjectName("projectsDirectoryCheckBox"); diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index de3f57145cc..0d5a3be0203 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -420,6 +420,7 @@ void TerminalInterface::start() connect(d->stubConnectTimeoutTimer.get(), &QTimer::timeout, this, [this] { killInferiorProcess(); killStubProcess(); + emitFinished(-1, QProcess::ExitStatus::CrashExit); }); d->stubConnectTimeoutTimer->setSingleShot(true); d->stubConnectTimeoutTimer->start(10000); diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index d7ccd1d6761..7bf55d8f247 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -198,8 +198,6 @@ QtcLibrary { "namevaluedictionary.h", "namevalueitem.cpp", "namevalueitem.h", - "namevaluemodel.cpp", - "namevaluemodel.h", "namevaluesdialog.cpp", "namevaluesdialog.h", "namevaluevalidator.cpp", diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 2b0bd9492e0..21a20ff645c 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1479,9 +1479,12 @@ FilePath AndroidConfig::getJdkPath() // Look for Android Studio's jdk first const FilePath androidStudioSdkPath = androidStudioPath(); if (!androidStudioSdkPath.isEmpty()) { - const FilePath androidStudioSdkJrePath = androidStudioSdkPath / "jre"; - if (androidStudioSdkJrePath.exists()) - jdkHome = androidStudioSdkJrePath; + const QStringList allVersions{"jbr", "jre"}; + for (const QString &version : allVersions) { + const FilePath androidStudioSdkJbrPath = androidStudioSdkPath / version; + if (androidStudioSdkJbrPath.exists()) + return androidStudioSdkJbrPath; + } } if (jdkHome.isEmpty()) { diff --git a/src/plugins/android/androidsdkdownloader.cpp b/src/plugins/android/androidsdkdownloader.cpp index 6ff39dc4170..7246b5b9a3d 100644 --- a/src/plugins/android/androidsdkdownloader.cpp +++ b/src/plugins/android/androidsdkdownloader.cpp @@ -100,8 +100,8 @@ void AndroidSdkDownloader::downloadAndExtractSdk() m_progressDialog->setFixedSize(m_progressDialog->sizeHint()); m_progressDialog->setAutoClose(false); connect(m_progressDialog.get(), &QProgressDialog::canceled, this, [this] { - m_progressDialog.release()->deleteLater(); m_taskTreeRunner.reset(); + m_progressDialog.release()->deleteLater(); }); Storage> storage; @@ -116,6 +116,8 @@ void AndroidSdkDownloader::downloadAndExtractSdk() return; connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 received, qint64 max) { + if (!m_progressDialog) + return; m_progressDialog->setRange(0, max); m_progressDialog->setValue(received); }); diff --git a/src/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp index ec5ae042292..a9fb3a4e3f4 100644 --- a/src/plugins/axivion/axivionoutputpane.cpp +++ b/src/plugins/axivion/axivionoutputpane.cpp @@ -35,6 +35,8 @@ #include +using namespace Core; +using namespace ProjectExplorer; using namespace Tasking; using namespace Utils; @@ -199,11 +201,11 @@ public: if (role == BaseTreeView::ItemActivatedRole && !m_links.isEmpty()) { // TODO for now only simple - just the first.. Link link = m_links.first(); - ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + Project *project = ProjectManager::startupProject(); FilePath baseDir = project ? project->projectDirectory() : FilePath{}; link.targetFilePath = baseDir.resolvePath(link.targetFilePath); if (link.targetFilePath.exists()) - Core::EditorManager::openEditorAt(link); + EditorManager::openEditorAt(link); return true; } return StaticTreeItem::setData(column, value, role); @@ -591,7 +593,7 @@ void IssuesWidget::fetchMoreIssues() } AxivionOutputPane::AxivionOutputPane(QObject *parent) - : Core::IOutputPane(parent) + : IOutputPane(parent) { setId("Axivion"); setDisplayName(Tr::tr("Axivion")); @@ -702,7 +704,7 @@ void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) browser->setText(ruleHtml); if (!ruleHtml.isEmpty()) { m_outputWidget->setCurrentIndex(2); - popup(Core::IOutputPane::NoModeSwitch); + popup(IOutputPane::NoModeSwitch); } } } diff --git a/src/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp index 26f5196a9ad..cd8fca0a0c5 100644 --- a/src/plugins/axivion/axivionplugin.cpp +++ b/src/plugins/axivion/axivionplugin.cpp @@ -53,21 +53,6 @@ using namespace Utils; namespace Axivion::Internal { -class Issue -{ -public: - QString id; - QString state; - QString errorNumber; - QString message; - QString entity; - QString filePath; - QString severity; - int lineNumber = 0; -}; - -using Issues = QList; - QIcon iconForIssue(const QString &prefix) { static QHash prefixToIcon; @@ -154,7 +139,7 @@ public: void onDocumentOpened(IDocument *doc); void onDocumentClosed(IDocument * doc); void clearAllMarks(); - void handleIssuesForFile(const Issues &issues); + void handleIssuesForFile(const Dto::FileViewDto &fileView); void fetchIssueInfo(const QString &id); NetworkAccessManager m_networkAccessManager; @@ -173,18 +158,18 @@ static AxivionPluginPrivate *dd = nullptr; class AxivionTextMark : public TextMark { public: - AxivionTextMark(const FilePath &filePath, const Issue &issue) - : TextMark(filePath, issue.lineNumber, {Tr::tr("Axivion"), AxivionTextMarkId}) + AxivionTextMark(const FilePath &filePath, const Dto::LineMarkerDto &issue) + : TextMark(filePath, issue.startLine, {Tr::tr("Axivion"), AxivionTextMarkId}) { - const QString markText = issue.entity.isEmpty() ? issue.message - : issue.entity + ": " + issue.message; - setToolTip(issue.errorNumber + " " + markText); - setIcon(iconForIssue("SV")); // FIXME adapt to the issue + const QString markText = issue.description; + const QString id = issue.kind + QString::number(issue.id.value_or(-1)); + setToolTip(id + markText); + setIcon(iconForIssue(issue.kind)); setPriority(TextMark::NormalPriority); setLineAnnotation(markText); - setActionsProvider([id = issue.id] { + setActionsProvider([id] { auto action = new QAction; - action->setIcon(Utils::Icons::INFO.icon()); + action->setIcon(Icons::INFO.icon()); action->setToolTip(Tr::tr("Show rule details")); QObject::connect(action, &QAction::triggered, dd, [id] { dd->fetchIssueInfo(id); }); return QList{action}; @@ -281,8 +266,8 @@ static QUrl urlForProject(const QString &projectName) } static constexpr int httpStatusCodeOk = 200; -static const QLatin1String jsonContentType{ "application/json" }; -static const QLatin1String htmlContentType{ "text/html" }; +constexpr char s_htmlContentType[] = "text/html"; +constexpr char s_jsonContentType[] = "application/json"; static Group fetchHtmlRecipe(const QUrl &url, const std::function &handler) { @@ -299,15 +284,11 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::functioncredentials); - const QByteArray ua = QByteArrayLiteral("Axivion") - + QCoreApplication::applicationName().toUtf8() - + QByteArrayLiteral("Plugin/") - + QCoreApplication::applicationVersion().toUtf8(); - request.setRawHeader(QByteArrayLiteral("X-Axivion-User-Agent"), ua); + request.setRawHeader("Accept", s_htmlContentType); + request.setRawHeader("Authorization", storage->credentials); + const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); + request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); }; @@ -322,11 +303,10 @@ static Group fetchHtmlRecipe(const QUrl &url, const std::functionreadAll()); return DoneResult::Success; } - return DoneResult::Error; }; @@ -355,22 +335,19 @@ static Group fetchDataRecipe(const QUrl &url, storage->credentials = QByteArrayLiteral("AxToken ") + settings().server.token.toUtf8(); }; - const auto onQuerySetup = [storage, url](NetworkQuery &query) { + const auto onNetworkQuerySetup = [storage, url](NetworkQuery &query) { QNetworkRequest request(url); - request.setRawHeader(QByteArrayLiteral("Accept"), - QByteArray(jsonContentType.data(), jsonContentType.size())); - request.setRawHeader(QByteArrayLiteral("Authorization"), - storage->credentials); - const QByteArray ua = QByteArrayLiteral("Axivion") - + QCoreApplication::applicationName().toUtf8() - + QByteArrayLiteral("Plugin/") - + QCoreApplication::applicationVersion().toUtf8(); - request.setRawHeader(QByteArrayLiteral("X-Axivion-User-Agent"), ua); + request.setRawHeader("Accept", s_jsonContentType); + request.setRawHeader("Authorization", storage->credentials); + const QByteArray ua = "Axivion" + QCoreApplication::applicationName().toUtf8() + + "Plugin/" + QCoreApplication::applicationVersion().toUtf8(); + request.setRawHeader("X-Axivion-User-Agent", ua); query.setRequest(request); query.setNetworkAccessManager(&dd->m_networkAccessManager); + return SetupResult::Continue; }; - const auto onQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) { + const auto onNetworkQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) { QNetworkReply *reply = query.reply(); const QNetworkReply::NetworkError error = reply->error(); const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -381,13 +358,13 @@ static Group fetchDataRecipe(const QUrl &url, .trimmed() .toLower(); if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk - && contentType == jsonContentType) { + && contentType == s_jsonContentType) { storage->serializableData = reply->readAll(); return DoneResult::Success; } const auto getError = [&]() -> Error { - if (contentType == jsonContentType) { + if (contentType == s_jsonContentType) { try { return DashboardError(reply->url(), statusCode, reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(), @@ -404,8 +381,7 @@ static Group fetchDataRecipe(const QUrl &url, return NetworkError(reply->url(), error, reply->errorString()); }; - MessageManager::writeFlashing( - QStringLiteral("Axivion: %1").arg(getError().message())); + MessageManager::writeFlashing(QStringLiteral("Axivion: %1").arg(getError().message())); return DoneResult::Error; }; @@ -426,7 +402,7 @@ static Group fetchDataRecipe(const QUrl &url, const Group recipe { storage, Sync(onCredentialSetup), - NetworkQueryTask(onQuerySetup, onQueryDone), + NetworkQueryTask(onNetworkQuerySetup, onNetworkQueryDone), AsyncTask(onDeserializeSetup, onDeserializeDone) }; @@ -495,6 +471,17 @@ Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &h return fetchDataRecipe(url, handler); } +Group lineMarkerRecipe(const FilePath &filePath, const LineMarkerHandler &handler) +{ + QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? + QTC_ASSERT(!filePath.isEmpty(), return {}); // TODO: Call handler with unexpected? + + const QString fileName = QString::fromUtf8(QUrl::toPercentEncoding(filePath.path())); + const QUrl url = urlForProject(dd->m_currentProjectInfo.value().name + '/') + .resolved(QString("files?filename=" + fileName)); + return fetchDataRecipe(url, handler); +} + Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler) { QTC_ASSERT(dd->m_currentProjectInfo, return {}); // TODO: Call handler with unexpected? @@ -569,7 +556,7 @@ void AxivionPluginPrivate::fetchIssueInfo(const QString &id) dd->m_axivionOutputPane.updateAndShowRule(QString::fromUtf8(fixedHtml)); }; - m_issueInfoRunner.start(issueHtmlRecipe(QString("SV") + id, ruleHandler)); + m_issueInfoRunner.start(issueHtmlRecipe(id, ruleHandler)); } void AxivionPluginPrivate::handleOpenedDocs() @@ -591,41 +578,16 @@ void AxivionPluginPrivate::onDocumentOpened(IDocument *doc) if (!doc || !m_currentProjectInfo || !m_project || !m_project->isKnownFile(doc->filePath())) return; - IssueListSearch search; - search.kind = "SV"; - search.filter_path = doc->filePath().relativeChildPath(m_project->projectDirectory()).path(); - search.limit = 0; + const FilePath filePath = doc->filePath().relativeChildPath(m_project->projectDirectory()); + QTC_ASSERT(!filePath.isEmpty(), return); - const auto issuesHandler = [this](const Dto::IssueTableDto &dto) { - Issues issues; - const std::vector> &rows = dto.rows; - for (const auto &row : rows) { - Issue issue; - for (auto it = row.cbegin(); it != row.cend(); ++it) { - if (it->first == "id") - issue.id = anyToSimpleString(it->second); - else if (it->first == "state") - issue.state = anyToSimpleString(it->second); - else if (it->first == "errorNumber") - issue.errorNumber = anyToSimpleString(it->second); - else if (it->first == "message") - issue.message = anyToSimpleString(it->second); - else if (it->first == "entity") - issue.entity = anyToSimpleString(it->second); - else if (it->first == "path") - issue.filePath = anyToSimpleString(it->second); - else if (it->first == "severity") - issue.severity = anyToSimpleString(it->second); - else if (it->first == "line") - issue.lineNumber = anyToSimpleString(it->second).toInt(); - } - issues << issue; - } - handleIssuesForFile(issues); + const auto handler = [this](const Dto::FileViewDto &data) { + if (data.lineMarkers.empty()) + return; + handleIssuesForFile(data); }; - TaskTree *taskTree = new TaskTree; - taskTree->setRecipe(issueTableRecipe(search, issuesHandler)); + taskTree->setRecipe(lineMarkerRecipe(filePath, handler)); m_docMarksTrees.insert_or_assign(doc, std::unique_ptr(taskTree)); connect(taskTree, &TaskTree::done, this, [this, doc] { const auto it = m_docMarksTrees.find(doc); @@ -653,24 +615,22 @@ void AxivionPluginPrivate::onDocumentClosed(IDocument *doc) } } -void AxivionPluginPrivate::handleIssuesForFile(const Issues &issues) +void AxivionPluginPrivate::handleIssuesForFile(const Dto::FileViewDto &fileView) { - if (issues.isEmpty()) + if (fileView.lineMarkers.empty()) return; Project *project = ProjectManager::startupProject(); if (!project) return; - const FilePath filePath = project->projectDirectory() - .pathAppended(issues.first().filePath); + const FilePath filePath = project->projectDirectory().pathAppended(fileView.fileName); - const Id axivionId(AxivionTextMarkId); - for (const Issue &issue : issues) { + for (const Dto::LineMarkerDto &marker : std::as_const(fileView.lineMarkers)) { // FIXME the line location can be wrong (even the whole issue could be wrong) // depending on whether this line has been changed since the last axivion run and the // current state of the file - some magic has to happen here - new AxivionTextMark(filePath, issue); + new AxivionTextMark(filePath, marker); } } diff --git a/src/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h index a8090c6b7a6..1d5245a5034 100644 --- a/src/plugins/axivion/axivionplugin.h +++ b/src/plugins/axivion/axivionplugin.h @@ -19,6 +19,8 @@ namespace ProjectExplorer { class Project; } namespace Tasking { class Group; } +namespace Utils { class FilePath; } + namespace Axivion::Internal { struct IssueListSearch @@ -57,6 +59,10 @@ Tasking::Group tableInfoRecipe(const QString &prefix, const TableInfoHandler &ha using IssueTableHandler = std::function; Tasking::Group issueTableRecipe(const IssueListSearch &search, const IssueTableHandler &handler); +// TODO: Wrap into expected_str<>? +using LineMarkerHandler = std::function; +Tasking::Group lineMarkerRecipe(const Utils::FilePath &filePath, const LineMarkerHandler &handler); + using HtmlHandler = std::function; Tasking::Group issueHtmlRecipe(const QString &issueId, const HtmlHandler &handler); diff --git a/src/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp index a3e3e3f3bc6..14d47eca53a 100644 --- a/src/plugins/axivion/axivionprojectsettings.cpp +++ b/src/plugins/axivion/axivionprojectsettings.cpp @@ -33,7 +33,7 @@ const char PSK_PROJECTNAME[] = "Axivion.ProjectName"; class AxivionProjectSettingsHandler : public QObject { public: - AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project) + AxivionProjectSettings *projectSettings(Project *project) { auto &settings = m_axivionProjectSettings[project]; if (!settings) @@ -47,7 +47,7 @@ public: m_axivionProjectSettings.clear(); } - QHash m_axivionProjectSettings; + QHash m_axivionProjectSettings; }; static AxivionProjectSettingsHandler &projectSettingsHandler() @@ -58,17 +58,15 @@ static AxivionProjectSettingsHandler &projectSettingsHandler() // AxivionProjectSettings -AxivionProjectSettings::AxivionProjectSettings(ProjectExplorer::Project *project) +AxivionProjectSettings::AxivionProjectSettings(Project *project) : m_project{project} { load(); - connect(project, &ProjectExplorer::Project::settingsLoaded, - this, &AxivionProjectSettings::load); - connect(project, &ProjectExplorer::Project::aboutToSaveSettings, - this, &AxivionProjectSettings::save); + connect(project, &Project::settingsLoaded, this, &AxivionProjectSettings::load); + connect(project, &Project::aboutToSaveSettings, this, &AxivionProjectSettings::save); } -AxivionProjectSettings *AxivionProjectSettings::projectSettings(ProjectExplorer::Project *project) +AxivionProjectSettings *AxivionProjectSettings::projectSettings(Project *project) { return projectSettingsHandler().projectSettings(project); } @@ -90,10 +88,10 @@ void AxivionProjectSettings::save() // AxivionProjectSettingsWidget -class AxivionProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +class AxivionProjectSettingsWidget : public ProjectSettingsWidget { public: - explicit AxivionProjectSettingsWidget(ProjectExplorer::Project *project); + explicit AxivionProjectSettingsWidget(Project *project); private: void fetchProjects(); @@ -109,11 +107,11 @@ private: QPushButton *m_fetchProjects = nullptr; QPushButton *m_link = nullptr; QPushButton *m_unlink = nullptr; - Utils::InfoLabel *m_infoLabel = nullptr; + InfoLabel *m_infoLabel = nullptr; TaskTreeRunner m_taskTreeRunner; }; -AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Project *project) +AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(Project *project) : m_projectSettings(projectSettingsHandler().projectSettings(project)) { setUseGlobalSettingsCheckBoxVisible(false); @@ -132,7 +130,7 @@ AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Proj verticalLayout->addWidget(new QLabel(Tr::tr("Dashboard projects:"))); verticalLayout->addWidget(m_dashboardProjects); - m_infoLabel = new Utils::InfoLabel(this); + m_infoLabel = new InfoLabel(this); m_infoLabel->setVisible(false); verticalLayout->addWidget(m_infoLabel); @@ -171,7 +169,7 @@ void AxivionProjectSettingsWidget::fetchProjects() const auto onDashboardInfo = [this](const expected_str &info) { if (!info) { m_infoLabel->setText(info.error()); - m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setType(InfoLabel::Error); m_infoLabel->setVisible(true); } else { for (const QString &project : info->projects) @@ -234,19 +232,19 @@ void AxivionProjectSettingsWidget::updateEnabledStates() if (!hasDashboardSettings) { m_infoLabel->setText(Tr::tr("Incomplete or misconfigured settings.")); - m_infoLabel->setType(Utils::InfoLabel::NotOk); + m_infoLabel->setType(InfoLabel::NotOk); m_infoLabel->setVisible(true); } } -class AxivionProjectPanelFactory : public ProjectExplorer::ProjectPanelFactory +class AxivionProjectPanelFactory : public ProjectPanelFactory { public: AxivionProjectPanelFactory() { setPriority(250); setDisplayName(Tr::tr("Axivion")); - setCreateWidgetFunction([](ProjectExplorer::Project *project) { + setCreateWidgetFunction([](Project *project) { return new AxivionProjectSettingsWidget(project); }); } diff --git a/src/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp index d85178df544..3d95673b9c0 100644 --- a/src/plugins/axivion/axivionsettings.cpp +++ b/src/plugins/axivion/axivionsettings.cpp @@ -20,11 +20,12 @@ #include #include +using namespace Core; using namespace Utils; namespace Axivion::Internal { -AxivionServer::AxivionServer(const Utils::Id &id, const QString &dashboard, +AxivionServer::AxivionServer(const Id &id, const QString &dashboard, const QString &description, const QString &token) : id(id) , dashboard(dashboard) @@ -68,17 +69,17 @@ AxivionServer AxivionServer::fromJson(const QJsonObject &json) const QJsonValue token = json.value("token"); if (token == QJsonValue::Undefined) return invalidServer; - return { Utils::Id::fromString(id.toString()), dashboard.toString(), + return { Id::fromString(id.toString()), dashboard.toString(), description.toString(), token.toString() }; } -static Utils::FilePath tokensFilePath() +static FilePath tokensFilePath() { - return Utils::FilePath::fromString(Core::ICore::settings()->fileName()).parentDir() + return FilePath::fromString(ICore::settings()->fileName()).parentDir() .pathAppended("qtcreator/axivion.json"); } -static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer &server) +static void writeTokenFile(const FilePath &filePath, const AxivionServer &server) { QJsonDocument doc; doc.setObject(server.toJson()); @@ -87,11 +88,11 @@ static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer filePath.setPermissions(QFile::ReadUser | QFile::WriteUser); } -static AxivionServer readTokenFile(const Utils::FilePath &filePath) +static AxivionServer readTokenFile(const FilePath &filePath) { if (!filePath.exists()) return {}; - Utils::expected_str contents = filePath.fileContents(); + expected_str contents = filePath.fileContents(); if (!contents) return {}; const QJsonDocument doc = QJsonDocument::fromJson(*contents); @@ -120,7 +121,7 @@ AxivionSettings::AxivionSettings() void AxivionSettings::toSettings() const { writeTokenFile(tokensFilePath(), server); - Utils::AspectContainer::writeSettings(); + AspectContainer::writeSettings(); } // AxivionSettingsPage @@ -214,7 +215,7 @@ AxivionServer DashboardSettingsWidget::dashboardServer() const if (m_id.isValid()) result.id = m_id; else - result.id = m_mode == Edit ? Utils::Id::fromName(QUuid::createUuid().toByteArray()) : m_id; + result.id = m_mode == Edit ? Id::fromName(QUuid::createUuid().toByteArray()) : m_id; result.dashboard = m_dashboardUrl(); result.description = m_description(); result.token = m_token(); @@ -234,7 +235,7 @@ bool DashboardSettingsWidget::isValid() const return !m_token().isEmpty() && !m_description().isEmpty() && isUrlValid(m_dashboardUrl()); } -class AxivionSettingsWidget : public Core::IOptionsPageWidget +class AxivionSettingsWidget : public IOptionsPageWidget { public: AxivionSettingsWidget(); @@ -299,7 +300,7 @@ void AxivionSettingsWidget::showEditServerDialog() // AxivionSettingsPage -class AxivionSettingsPage : public Core::IOptionsPage +class AxivionSettingsPage : public IOptionsPage { public: AxivionSettingsPage() diff --git a/src/plugins/bazaar/bazaarplugin.cpp b/src/plugins/bazaar/bazaarplugin.cpp index a3b9c22d0c6..9a75fbf3b3c 100644 --- a/src/plugins/bazaar/bazaarplugin.cpp +++ b/src/plugins/bazaar/bazaarplugin.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,6 @@ namespace Bazaar::Internal { // Submit editor parameters const char COMMIT_ID[] = "Bazaar Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.bazaar.commit"; // Menu items @@ -89,27 +89,6 @@ const char COMMIT[] = "Bazaar.Action.Commit"; const char UNCOMMIT[] = "Bazaar.Action.UnCommit"; const char CREATE_REPOSITORY[] = "Bazaar.Action.CreateRepository"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, // type - Constants::FILELOG_ID, // id - Constants::FILELOG_DISPLAY_NAME, // display name - Constants::LOGAPP // mime type -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - class RevertDialog : public QDialog { public: @@ -220,23 +199,32 @@ public: FilePath m_submitRepository; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, // type + Constants::FILELOG_ID, // id + VcsBase::Tr::tr("Bazaar File Log Editor"), + Constants::LOGAPP,// mime type [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + VcsBase::Tr::tr("Bazaar Annotation Editor"), + Constants::ANNOTATEAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + VcsBase::Tr::tr("Bazaar Diff Editor"), + Constants::DIFFAPP, [] { return new BazaarEditorWidget; }, std::bind(&BazaarPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; class UnCommitDialog : public QDialog @@ -492,7 +480,7 @@ BazaarPluginPrivate::BazaarPluginPrivate() setupVcsSubmitEditor(this, { COMMITMIMETYPE, COMMIT_ID, - COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Bazaar Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); @@ -963,10 +951,10 @@ VcsCommand *BazaarPluginPrivate::createInitialCheckoutCommand(const QString &url args << m_client.vcsCommandString(BazaarClient::CloneCommand) << extraArgs << url << localName; - Environment env = m_client.processEnvironment(); + Environment env = m_client.processEnvironment(baseDirectory); env.set("BZR_PROGRESS_BAR", "text"); auto command = VcsBaseClient::createVcsCommand(baseDirectory, env); - command->addJob({m_client.vcsBinary(), args}, -1); + command->addJob({m_client.vcsBinary(baseDirectory), args}, -1); return command; } diff --git a/src/plugins/bazaar/constants.h b/src/plugins/bazaar/constants.h index e2cdb549bb3..9672d063442 100644 --- a/src/plugins/bazaar/constants.h +++ b/src/plugins/bazaar/constants.h @@ -3,8 +3,6 @@ #pragma once -#include - namespace Bazaar::Constants { const char BAZAAR[] = "bazaar"; @@ -23,15 +21,12 @@ const char ANNOTATE_CHANGESET_ID[] = "([.0-9]+)"; // Base editor parameters const char FILELOG_ID[] = "Bazaar File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.bazaar.log"; const char ANNOTATELOG_ID[] = "Bazaar Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.bazaar.annotation"; const char DIFFLOG_ID[] = "Bazaar Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Bazaar Diff Editor"); const char DIFFAPP[] = "text/x-patch"; // File status hint diff --git a/src/plugins/bineditor/bineditorplugin.cpp b/src/plugins/bineditor/bineditorplugin.cpp index 5410385f9df..f3a5ed9879f 100644 --- a/src/plugins/bineditor/bineditorplugin.cpp +++ b/src/plugins/bineditor/bineditorplugin.cpp @@ -79,7 +79,7 @@ public: m_widget->highlightSearchResults(QByteArray()); } - int find(const QByteArray &pattern, int pos, FindFlags findFlags, bool *wrapped) + qint64 find(const QByteArray &pattern, qint64 pos, FindFlags findFlags, bool *wrapped) { if (wrapped) *wrapped = false; @@ -88,7 +88,7 @@ public: return pos; } - int res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); + qint64 res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); if (res < 0) { pos = (findFlags & FindBackward) ? -1 : 0; res = m_widget->find(pattern, pos, Utils::textDocumentFlagsForFindFlags(findFlags)); @@ -111,7 +111,7 @@ public: if (m_contPos == -1) m_contPos = m_incrementalStartPos; bool wrapped; - int found = find(pattern, m_contPos, findFlags, &wrapped); + qint64 found = find(pattern, m_contPos, findFlags, &wrapped); if (wrapped != m_incrementalWrappedState && (found >= 0)) { m_incrementalWrappedState = wrapped; showWrapIndicator(m_widget); @@ -147,7 +147,7 @@ public: m_contPos = m_widget->selectionStart()-1; } bool wrapped; - int found = find(pattern, m_contPos, findFlags, &wrapped); + qint64 found = find(pattern, m_contPos, findFlags, &wrapped); if (wrapped) showWrapIndicator(m_widget); Result result; diff --git a/src/plugins/bineditor/bineditorwidget.cpp b/src/plugins/bineditor/bineditorwidget.cpp index 1d4765b3ca1..90e6855ef76 100644 --- a/src/plugins/bineditor/bineditorwidget.cpp +++ b/src/plugins/bineditor/bineditorwidget.cpp @@ -238,16 +238,16 @@ bool BinEditorWidget::requestOldDataAt(qint64 pos) const char BinEditorWidget::dataAt(qint64 pos, bool old) const { - qint64 block = pos / m_blockSize; - int offset = static_cast(pos - block * m_blockSize); + const qint64 block = pos / m_blockSize; + const qint64 offset = pos - block * m_blockSize; return blockData(block, old).at(offset); } void BinEditorWidget::changeDataAt(qint64 pos, char c) { - qint64 block = pos / m_blockSize; + const qint64 block = pos / m_blockSize; BlockMap::iterator it = m_modifiedData.find(block); - int offset = static_cast(pos - block * m_blockSize); + const qint64 offset = pos - block * m_blockSize; if (it != m_modifiedData.end()) { it.value()[offset] = c; } else { @@ -262,7 +262,7 @@ void BinEditorWidget::changeDataAt(qint64 pos, char c) d->announceChangedData(m_baseAddr + pos, QByteArray(1, c)); } -QByteArray BinEditorWidget::dataMid(qint64 from, int length, bool old) const +QByteArray BinEditorWidget::dataMid(qint64 from, qint64 length, bool old) const { qint64 end = from + length; qint64 block = from / m_blockSize; @@ -581,20 +581,20 @@ void BinEditorWidget::updateLines() updateLines(m_cursorPosition, m_cursorPosition); } -void BinEditorWidget::updateLines(int fromPosition, int toPosition) +void BinEditorWidget::updateLines(qint64 fromPosition, qint64 toPosition) { - int topLine = verticalScrollBar()->value(); - int firstLine = qMin(fromPosition, toPosition) / m_bytesPerLine; - int lastLine = qMax(fromPosition, toPosition) / m_bytesPerLine; - int y = (firstLine - topLine) * m_lineHeight; - int h = (lastLine - firstLine + 1 ) * m_lineHeight; + const qint64 topLine = verticalScrollBar()->value(); + const qint64 firstLine = qMin(fromPosition, toPosition) / m_bytesPerLine; + const qint64 lastLine = qMax(fromPosition, toPosition) / m_bytesPerLine; + const int y = (firstLine - topLine) * m_lineHeight; + const int h = (lastLine - firstLine + 1 ) * m_lineHeight; viewport()->update(0, y, viewport()->width(), h); } -int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const +qint64 BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const { - int trailing = pattern.size(); + qint64 trailing = pattern.size(); if (trailing > m_blockSize) return -1; @@ -603,7 +603,7 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca QByteArrayMatcher matcher(pattern); qint64 block = from / m_blockSize; - const int end = qMin(from + SearchStride, m_size); + const qint64 end = qMin(from + SearchStride, m_size); while (from < end) { if (!requestDataAt(block * m_blockSize)) return -1; @@ -615,7 +615,7 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca if (!caseSensitive) buffer = buffer.toLower(); - int pos = matcher.indexIn(buffer, from - (block * m_blockSize) + trailing); + qint64 pos = matcher.indexIn(buffer, from - (block * m_blockSize) + trailing); if (pos >= 0) return pos + block * m_blockSize - trailing; ++block; @@ -624,9 +624,9 @@ int BinEditorWidget::dataIndexOf(const QByteArray &pattern, qint64 from, bool ca return end == m_size ? -1 : -2; } -int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const +qint64 BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive) const { - int trailing = pattern.size(); + qint64 trailing = pattern.size(); if (trailing > m_blockSize) return -1; @@ -635,10 +635,10 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo if (from == -1) from = m_size; - int block = from / m_blockSize; - const int lowerBound = qMax(qint64(0), from - SearchStride); + qint64 block = from / m_blockSize; + const qint64 lowerBound = qMax(0, from - SearchStride); while (from > lowerBound) { - if (!requestDataAt(qint64(block) * m_blockSize)) + if (!requestDataAt(block * m_blockSize)) return -1; QByteArray data = blockData(block); char *b = buffer.data(); @@ -648,18 +648,19 @@ int BinEditorWidget::dataLastIndexOf(const QByteArray &pattern, qint64 from, boo if (!caseSensitive) buffer = buffer.toLower(); - int pos = buffer.lastIndexOf(pattern, from - (block * m_blockSize)); + qint64 pos = buffer.lastIndexOf(pattern, from - (block * m_blockSize)); if (pos >= 0) return pos + block * m_blockSize; --block; - from = qint64(block) * m_blockSize + (m_blockSize-1) + trailing; + from = block * m_blockSize + (m_blockSize-1) + trailing; } return lowerBound == 0 ? -1 : -2; } -int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, - QTextDocument::FindFlags findFlags) +qint64 BinEditorWidget::find(const QByteArray &pattern_arg, + qint64 from, + QTextDocument::FindFlags findFlags) { if (pattern_arg.isEmpty()) return 0; @@ -672,14 +673,14 @@ int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, pattern = pattern.toLower(); bool backwards = (findFlags & QTextDocument::FindBackward); - int found = backwards ? dataLastIndexOf(pattern, from, caseSensitiveSearch) - : dataIndexOf(pattern, from, caseSensitiveSearch); + qint64 found = backwards ? dataLastIndexOf(pattern, from, caseSensitiveSearch) + : dataIndexOf(pattern, from, caseSensitiveSearch); - int foundHex = -1; + qint64 foundHex = -1; QByteArray hexPattern = calculateHexPattern(pattern_arg); if (!hexPattern.isEmpty()) { foundHex = backwards ? dataLastIndexOf(hexPattern, from) - : dataIndexOf(hexPattern, from); + : dataIndexOf(hexPattern, from); } qint64 pos = foundHex == -1 || (found >= 0 && (foundHex == -2 || found < foundHex)) @@ -695,15 +696,16 @@ int BinEditorWidget::find(const QByteArray &pattern_arg, qint64 from, return pos; } -int BinEditorWidget::findPattern(const QByteArray &data, const QByteArray &dataHex, - int from, int offset, int *match) +qint64 BinEditorWidget::findPattern(const QByteArray &data, const QByteArray &dataHex, + qint64 from, qint64 offset, qint64 *match) { if (m_searchPattern.isEmpty()) return -1; - int normal = m_searchPattern.isEmpty() - ? -1 : data.indexOf(m_searchPattern, from - offset); - int hex = m_searchPatternHex.isEmpty() - ? -1 : dataHex.indexOf(m_searchPatternHex, from - offset); + + qint64 normal = m_searchPattern.isEmpty() + ? -1 : data.indexOf(m_searchPattern, from - offset); + qint64 hex = m_searchPatternHex.isEmpty() + ? -1 : dataHex.indexOf(m_searchPatternHex, from - offset); if (normal >= 0 && (hex < 0 || normal < hex)) { if (match) @@ -787,10 +789,10 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) painter.fillRect(e->rect() & r, palette().alternateBase()); } - int matchLength = 0; + qint64 matchLength = 0; QByteArray patternData, patternDataHex; - int patternOffset = qMax(0, topLine*m_bytesPerLine - m_searchPattern.size()); + qint64 patternOffset = qMax(0, topLine * m_bytesPerLine - m_searchPattern.size()); if (!m_searchPattern.isEmpty()) { patternData = dataMid(patternOffset, m_numVisibleLines * m_bytesPerLine + (topLine*m_bytesPerLine - patternOffset)); patternDataHex = patternData; @@ -798,9 +800,9 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) patternData = patternData.toLower(); } - int foundPatternAt = findPattern(patternData, patternDataHex, patternOffset, patternOffset, &matchLength); + qint64 foundPatternAt = findPattern(patternData, patternDataHex, patternOffset, patternOffset, &matchLength); - int selStart, selEnd; + qint64 selStart, selEnd; if (m_cursorPosition >= m_anchorPosition) { selStart = m_anchorPosition; selEnd = m_cursorPosition; @@ -817,13 +819,13 @@ void BinEditorWidget::paintEvent(QPaintEvent *e) painter.setPen(palette().text().color()); const QFontMetrics &fm = painter.fontMetrics(); - for (int i = 0; i <= m_numVisibleLines; ++i) { + for (qint64 i = 0; i <= m_numVisibleLines; ++i) { qint64 line = topLine + i; if (line >= m_numLines) break; const quint64 lineAddress = m_baseAddr + line * m_bytesPerLine; - int y = i * m_lineHeight + m_ascent; + qint64 y = i * m_lineHeight + m_ascent; if (y - m_ascent > e->rect().bottom()) break; if (y + m_descent < e->rect().top()) @@ -1006,7 +1008,7 @@ qint64 BinEditorWidget::cursorPosition() const void BinEditorWidget::setCursorPosition(qint64 pos, MoveMode moveMode) { pos = qMin(m_size - 1, qMax(qint64(0), pos)); - int oldCursorPosition = m_cursorPosition; + qint64 oldCursorPosition = m_cursorPosition; m_lowNibble = false; m_cursorPosition = pos; @@ -1377,33 +1379,34 @@ void BinEditorWidget::keyPressEvent(QKeyEvent *e) break; case Qt::Key_PageUp: case Qt::Key_PageDown: { - int line = qMax(qint64(0), m_cursorPosition / m_bytesPerLine - verticalScrollBar()->value()); + qint64 line = qMax(qint64(0), m_cursorPosition / m_bytesPerLine - verticalScrollBar()->value()); verticalScrollBar()->triggerAction(e->key() == Qt::Key_PageUp ? QScrollBar::SliderPageStepSub : QScrollBar::SliderPageStepAdd); if (!ctrlPressed) setCursorPosition((verticalScrollBar()->value() + line) * m_bytesPerLine + m_cursorPosition % m_bytesPerLine, moveMode); - } break; - + break; + } case Qt::Key_Home: { - int pos; + qint64 pos; if (ctrlPressed) pos = 0; else - pos = m_cursorPosition/m_bytesPerLine * m_bytesPerLine; + pos = m_cursorPosition / m_bytesPerLine * m_bytesPerLine; setCursorPosition(pos, moveMode); - } break; + break; + } case Qt::Key_End: { - int pos; + qint64 pos; if (ctrlPressed) pos = m_size; else - pos = m_cursorPosition/m_bytesPerLine * m_bytesPerLine + 15; + pos = m_cursorPosition / m_bytesPerLine * m_bytesPerLine + 15; setCursorPosition(pos, moveMode); - } break; - default: + break; + } + default: { if (m_readOnly) break; - { QString text = e->text(); for (int i = 0; i < text.length(); ++i) { QChar c = text.at(i); @@ -1461,9 +1464,9 @@ void BinEditorWidget::zoomF(float delta) void BinEditorWidget::copy(bool raw) { - int selStart = selectionStart(); - int selEnd = selectionEnd(); - const int selectionLength = selEnd - selStart + 1; + const qint64 selStart = selectionStart(); + const qint64 selEnd = selectionEnd(); + const qint64 selectionLength = selEnd - selStart + 1; if (selectionLength >> 22) { QMessageBox::warning(this, Tr::tr("Copying Failed"), Tr::tr("You cannot copy more than 4 MB of binary data.")); @@ -1479,7 +1482,7 @@ void BinEditorWidget::copy(bool raw) QString hexString; const char * const hex = "0123456789abcdef"; hexString.reserve(3 * data.size()); - for (int i = 0; i < data.size(); ++i) { + for (qint64 i = 0; i < data.size(); ++i) { const uchar val = static_cast(data[i]); hexString.append(QLatin1Char(hex[val >> 4])).append(QLatin1Char(hex[val & 0xf])).append(QLatin1Char(' ')); } @@ -1499,7 +1502,7 @@ void BinEditorWidget::highlightSearchResults(const QByteArray &pattern, QTextDoc viewport()->update(); } -void BinEditorWidget::changeData(int position, uchar character, bool highNibble) +void BinEditorWidget::changeData(qint64 position, uchar character, bool highNibble) { if (!requestDataAt(position)) return; @@ -1572,8 +1575,8 @@ void BinEditorWidget::redo() void BinEditorWidget::contextMenuEvent(QContextMenuEvent *event) { - const int selStart = selectionStart(); - const int byteCount = selectionEnd() - selStart + 1; + const qint64 selStart = selectionStart(); + const qint64 byteCount = selectionEnd() - selStart + 1; QPointer contextMenu(new QMenu(this)); @@ -1717,12 +1720,12 @@ void BinEditorWidget::asDouble(qint64 offset, double &value, bool old) const value = *f; } -void BinEditorWidget::asIntegers(qint64 offset, int count, quint64 &bigEndianValue, - quint64 &littleEndianValue, bool old) const +void BinEditorWidget::asIntegers(qint64 offset, qint64 count, quint64 &bigEndianValue, + quint64 &littleEndianValue, bool old) const { bigEndianValue = littleEndianValue = 0; const QByteArray &data = dataMid(offset, count, old); - for (int pos = 0; pos < data.size(); ++pos) { + for (qint64 pos = 0; pos < data.size(); ++pos) { const quint64 val = static_cast(data.at(pos)) & 0xff; littleEndianValue += val << (pos * 8); bigEndianValue += val << ((count - pos - 1) * 8); diff --git a/src/plugins/bineditor/bineditorwidget.h b/src/plugins/bineditor/bineditorwidget.h index 2ad78e51310..5fb6f2a3fbd 100644 --- a/src/plugins/bineditor/bineditorwidget.h +++ b/src/plugins/bineditor/bineditorwidget.h @@ -79,7 +79,7 @@ public: void setReadOnly(bool); bool isReadOnly() const; - int find(const QByteArray &pattern, qint64 from = 0, QTextDocument::FindFlags findFlags = {}); + qint64 find(const QByteArray &pattern, qint64 from = 0, QTextDocument::FindFlags findFlags = {}); void selectAll(); void clear(); @@ -90,8 +90,8 @@ public: Core::IEditor *editor() const { return m_ieditor; } void setEditor(Core::IEditor *ieditor) { m_ieditor = ieditor; } - int selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); } - int selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); } + qint64 selectionStart() const { return qMin(m_anchorPosition, m_cursorPosition); } + qint64 selectionEnd() const { return qMax(m_anchorPosition, m_cursorPosition); } bool event(QEvent*) override; @@ -146,20 +146,20 @@ private: QByteArray m_lowerBlock; qint64 m_size = 0; - int dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; - int dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; + qint64 dataIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; + qint64 dataLastIndexOf(const QByteArray &pattern, qint64 from, bool caseSensitive = true) const; bool requestDataAt(qint64 pos) const; bool requestOldDataAt(qint64 pos) const; char dataAt(qint64 pos, bool old = false) const; char oldDataAt(qint64 pos) const; void changeDataAt(qint64 pos, char c); - QByteArray dataMid(qint64 from, int length, bool old = false) const; + QByteArray dataMid(qint64 from, qint64 length, bool old = false) const; QByteArray blockData(qint64 block, bool old = false) const; QPoint offsetToPos(qint64 offset) const; - void asIntegers(qint64 offset, int count, quint64 &bigEndianValue, quint64 &littleEndianValue, - bool old = false) const; + void asIntegers(qint64 offset, qint64 count, quint64 &bigEndianValue, quint64 &littleEndianValue, + bool old = false) const; void asFloat(qint64 offset, float &value, bool old) const; void asDouble(qint64 offset, double &value, bool old) const; QString toolTip(const QHelpEvent *helpEvent) const; @@ -198,14 +198,14 @@ private: bool inTextArea(const QPoint &pos) const; QRect cursorRect() const; void updateLines(); - void updateLines(int fromPosition, int toPosition); + void updateLines(qint64 fromPosition, qint64 toPosition); void ensureCursorVisible(); void setBlinkingCursorEnabled(bool enable); - void changeData(int position, uchar character, bool highNibble = false); + void changeData(qint64 position, uchar character, bool highNibble = false); - int findPattern(const QByteArray &data, const QByteArray &dataHex, - int from, int offset, int *match); + qint64 findPattern(const QByteArray &data, const QByteArray &dataHex, + qint64 from, qint64 offset, qint64 *match); void drawItems(QPainter *painter, int x, int y, const QString &itemString); void drawChanges(QPainter *painter, int x, int y, const char *changes); diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 9f9ea8ac94e..2de357b1124 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -849,7 +849,7 @@ clang::format::FormatStyle ClangFormatBaseIndenterPrivate::customSettingsStyle( return currentQtStyle(preferences); clang::format::FormatStyle currentSettingsStyle; - bool success = parseConfigurationFile(filePath, currentSettingsStyle); + const Utils::expected_str success = parseConfigurationFile(filePath, currentSettingsStyle); QTC_ASSERT(success, return currentQtStyle(preferences)); return currentSettingsStyle; diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index c546cc0d21f..98de3370228 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include #include @@ -105,8 +107,7 @@ private: Guard m_ignoreChanges; QLabel *m_clangVersion; - QLabel *m_clangFileIsCorrectText; - QLabel *m_clangFileIsCorrectIcon; + InfoLabel *m_clangFileIsCorrectText; ClangFormatIndenter *m_indenter; }; @@ -137,7 +138,7 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(TextEditor::ICodeStylePreferenc Column { m_clangVersion, Row { m_editorScrollArea, m_preview }, - Row {m_clangFileIsCorrectIcon, m_clangFileIsCorrectText, st} + Row {m_clangFileIsCorrectText, st} }.attachTo(this); connect(codeStyle, &TextEditor::ICodeStylePreferences::currentPreferencesChanged, @@ -194,46 +195,28 @@ void ClangFormatConfigWidget::initEditor(TextEditor::ICodeStylePreferences *code m_editorScrollArea->setWidget(m_editor->widget()); m_editorScrollArea->setWidgetResizable(true); - m_clangFileIsCorrectText = new QLabel(Tr::tr("Clang-Format is configured correctly.")); - QPalette paletteCorrect = m_clangFileIsCorrectText->palette(); - paletteCorrect.setColor(QPalette::WindowText, Qt::darkGreen); - m_clangFileIsCorrectText->setPalette(paletteCorrect); - - m_clangFileIsCorrectIcon = new QLabel(this); - m_clangFileIsCorrectIcon->setPixmap(Icons::OK.icon().pixmap(16, 16)); + m_clangFileIsCorrectText = new InfoLabel("", Utils::InfoLabel::Ok); + m_clangFileIsCorrectText->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + m_clangFileIsCorrectText->hide(); m_clangVersion = new QLabel(Tr::tr("Current ClangFormat version: %1.").arg(LLVM_VERSION_STRING), this); connect(m_editor->document(), &TextEditor::TextDocument::contentsChanged, this, [this] { clang::format::FormatStyle currentSettingsStyle; - const bool success + const Utils::expected_str success = parseConfigurationContent(m_editor->document()->contents().toStdString(), currentSettingsStyle); - QString text; - Qt::GlobalColor currentColor; - QPixmap pixmap; if (success) { - text = Tr::tr("Clang-Format is configured correctly."); - currentColor = Qt::darkGreen; - pixmap = Icons::OK.icon().pixmap(16, 16); - } else { - text = Tr::tr("Clang-Format is not configured correctly."); - currentColor = Qt::red; - pixmap = Icons::WARNING.icon().pixmap(16, 16); - } - - m_clangFileIsCorrectText->setText(text); - QPalette paletteCorrect = m_clangFileIsCorrectText->palette(); - paletteCorrect.setColor(QPalette::WindowText, currentColor); - m_clangFileIsCorrectText->setPalette(paletteCorrect); - m_clangFileIsCorrectIcon->setPixmap(pixmap); - - if (!success) + m_clangFileIsCorrectText->hide(); + m_indenter->setOverriddenStyle(currentSettingsStyle); + updatePreview(); return; - m_indenter->setOverriddenStyle(currentSettingsStyle); - updatePreview(); + } + m_clangFileIsCorrectText->show(); + m_clangFileIsCorrectText->setText(Tr::tr("Warning: ") + success.error()); + m_clangFileIsCorrectText->setType(Utils::InfoLabel::Warning); }); QShortcut *completionSC = new QShortcut(QKeySequence("Ctrl+Space"), this); @@ -347,8 +330,9 @@ void ClangFormatConfigWidget::apply() return; clang::format::FormatStyle currentSettingsStyle; - const bool success = parseConfigurationContent(m_editor->document()->contents().toStdString(), - currentSettingsStyle); + const Utils::expected_str success + = parseConfigurationContent(m_editor->document()->contents().toStdString(), + currentSettingsStyle); auto saveSettings = [this] { QString errorString; diff --git a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp index 973271b8c3c..7027511868e 100644 --- a/src/plugins/clangformat/clangformatglobalconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatglobalconfigwidget.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -68,7 +69,7 @@ private: QCheckBox *m_formatOnSave; QCheckBox *m_useCustomSettingsCheckBox; QCheckBox *m_useGlobalSettings; - QLabel *m_currentProjectLabel; + InfoLabel *m_currentProjectLabel; }; ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferences *codeStyle, @@ -95,10 +96,10 @@ ClangFormatGlobalConfigWidget::ClangFormatGlobalConfigWidget(ICodeStylePreferenc m_useGlobalSettings->hide(); m_useCustomSettings = ClangFormatSettings::instance().useCustomSettings(); - m_currentProjectLabel = new QLabel( + m_currentProjectLabel = new Utils::InfoLabel( Tr::tr("Please note that the current project includes a .clang-format file, which will be " - "used for code indenting and formatting.")); - m_currentProjectLabel->setStyleSheet("QLabel { color : red; }"); + "used for code indenting and formatting."), + Utils::InfoLabel::Warning); m_currentProjectLabel->setWordWrap(true); using namespace Layouting; diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index b1e8090ece2..6d16ebe9aa1 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -19,6 +19,7 @@ #include #include +#include #include @@ -417,15 +418,30 @@ Utils::FilePath filePathToCurrentSettings(const TextEditor::ICodeStylePreference / QLatin1String(Constants::SETTINGS_FILE_NAME); } -bool parseConfigurationContent(const std::string &fileContent, clang::format::FormatStyle &style) +static QString s_errorMessage; +Utils::expected_str parseConfigurationContent(const std::string &fileContent, + clang::format::FormatStyle &style) { - style.Language = clang::format::FormatStyle::LK_Cpp; - const std::error_code error = parseConfiguration(fileContent, &style); + auto diagHandler = [](const llvm::SMDiagnostic &diag, void * /*context*/) { + s_errorMessage = QString::fromStdString(diag.getMessage().str()) + " " + + QString::number(diag.getLineNo()) + ":" + + QString::number(diag.getColumnNo()); + }; - return error.value() == static_cast(ParseError::Success); + style.Language = clang::format::FormatStyle::LK_Cpp; + const std::error_code error = parseConfiguration(llvm::MemoryBufferRef(fileContent, "YAML"), + &style, + false, + diagHandler, + nullptr); + + if (error) + return make_unexpected(s_errorMessage); + return {}; } -bool parseConfigurationFile(const Utils::FilePath &filePath, clang::format::FormatStyle &style) +Utils::expected_str parseConfigurationFile(const Utils::FilePath &filePath, + clang::format::FormatStyle &style) { return parseConfigurationContent(filePath.fileContents().value_or(QByteArray()).toStdString(), style); diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index a4ff429b3e8..019414b11f5 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -48,7 +48,9 @@ clang::format::FormatStyle currentQtStyle(const TextEditor::ICodeStylePreference Utils::FilePath filePathToCurrentSettings(const TextEditor::ICodeStylePreferences *codeStyle); -bool parseConfigurationContent(const std::string &fileContent, clang::format::FormatStyle &style); -bool parseConfigurationFile(const Utils::FilePath &filePath, clang::format::FormatStyle &style); +Utils::expected_str parseConfigurationContent(const std::string &fileContent, + clang::format::FormatStyle &style); +Utils::expected_str parseConfigurationFile(const Utils::FilePath &filePath, + clang::format::FormatStyle &style); } // ClangFormat diff --git a/src/plugins/clearcase/clearcaseconstants.h b/src/plugins/clearcase/clearcaseconstants.h index fe42967e555..97d57eb9bda 100644 --- a/src/plugins/clearcase/clearcaseconstants.h +++ b/src/plugins/clearcase/clearcaseconstants.h @@ -11,7 +11,6 @@ namespace Constants { const char VCS_ID_CLEARCASE[] = "E.ClearCase"; const char CLEARCASE_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.clearcase.submit"; const char CLEARCASECHECKINEDITOR_ID[] = "ClearCase Check In Editor"; -const char CLEARCASECHECKINEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Check In Editor"); const char TASK_INDEX[] = "ClearCase.Task.Index"; const char KEEP_ACTIVITY[] = "__KEEP__"; enum { debug = 0 }; diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 56949f65621..f566b8223d4 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -99,26 +100,9 @@ const char CMD_ID_UPDATE_VIEW[] = "ClearCase.UpdateView"; const char CMD_ID_CHECKIN_ALL[] = "ClearCase.CheckInAll"; const char CMD_ID_STATUS[] = "ClearCase.Status"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - "ClearCase File Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase File Log Editor"), // display_name - "text/vnd.qtcreator.clearcase.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - "ClearCase Annotation Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Annotation Editor"), // display_name - "text/vnd.qtcreator.clearcase.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - "ClearCase Diff Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "ClearCase Diff Editor"), // display_name - "text/x-patch" -}; +const char LOG_EDITOR_ID[] = "ClearCase File Log Editor"; +const char ANNOTATION_EDITOR_ID[] = "ClearCase Annotation Editor"; +const char DIFF_EDITOR_ID[] = "ClearCase Diff Editor"; static QString debugCodec(const QTextCodec *c) { @@ -311,23 +295,32 @@ public: ClearCaseSettingsPage m_settingsPage; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + LOG_EDITOR_ID, + VcsBase::Tr::tr("ClearCase File Log Editor"), // display_name + "text/vnd.qtcreator.clearcase.log", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + ANNOTATION_EDITOR_ID, + VcsBase::Tr::tr("ClearCase Annotation Editor"), // display_name + "text/vnd.qtcreator.clearcase.annotation", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + DIFF_EDITOR_ID, + VcsBase::Tr::tr("ClearCase Diff Editor"), // display_name + "text/x-patch", [] { return new ClearCaseEditorWidget; }, std::bind(&ClearCasePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; #ifdef WITH_TESTS bool m_fakeClearTool = false; @@ -740,7 +733,7 @@ ClearCasePluginPrivate::ClearCasePluginPrivate() setupVcsSubmitEditor(this, { Constants::CLEARCASE_SUBMIT_MIMETYPE, Constants::CLEARCASECHECKINEDITOR_ID, - Constants::CLEARCASECHECKINEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("ClearCase Check In Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new ClearCaseSubmitEditor; } }); @@ -1218,7 +1211,7 @@ void ClearCasePluginPrivate::ccDiffWithPred(const FilePath &workingDir, const QS diffname = QDir::toNativeSeparators(files.first()); } const QString title = QString::fromLatin1("cc diff %1").arg(diffname); - IEditor *editor = showOutputInEditor(title, result, diffEditorParameters.id, source, codec); + IEditor *editor = showOutputInEditor(title, result, DIFF_EDITOR_ID, source, codec); setWorkingDirectory(editor, workingDir); VcsBaseEditor::tagEditor(editor, tag); auto diffEditorWidget = qobject_cast(editor->widget()); @@ -1299,7 +1292,7 @@ void ClearCasePluginPrivate::diffActivity() } m_diffPrefix.clear(); const QString title = QString::fromLatin1("%1.patch").arg(activity); - IEditor *editor = showOutputInEditor(title, result, diffEditorParameters.id, + IEditor *editor = showOutputInEditor(title, result, DIFF_EDITOR_ID, FilePath::fromString(activity), nullptr); setWorkingDirectory(editor, topLevel); } @@ -1461,7 +1454,7 @@ void ClearCasePluginPrivate::history(const FilePath &workingDir, const QString title = QString::fromLatin1("cc history %1").arg(id); const FilePath source = VcsBaseEditor::getSource(workingDir, files); IEditor *newEditor = showOutputInEditor(title, result.cleanedStdOut(), - logEditorParameters.id, source, codec); + LOG_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(newEditor)->setFileLogAnnotateEnabled(true); @@ -1564,7 +1557,7 @@ void ClearCasePluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, const EditorManager::activateEditor(editor); } else { const QString title = QString::fromLatin1("cc annotate %1").arg(id); - IEditor *newEditor = showOutputInEditor(title, res, annotateEditorParameters.id, source, codec); + IEditor *newEditor = showOutputInEditor(title, res, ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } @@ -1598,7 +1591,7 @@ void ClearCasePluginPrivate::vcsDescribe(const FilePath &source, const QString & EditorManager::activateEditor(editor); } else { const QString title = QString::fromLatin1("cc describe %1").arg(id); - IEditor *newEditor = showOutputInEditor(title, description, diffEditorParameters.id, source, codec); + IEditor *newEditor = showOutputInEditor(title, description, DIFF_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); } } diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 3a79e4a376e..7318c7a791f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -89,6 +89,21 @@ PresetsData CMakeProject::presetsData() const return m_presetsData; } +template +static QStringList recursiveInheritsList(const T &presetsHash, const QStringList &inheritsList) +{ + QStringList result; + for (const QString &inheritFrom : inheritsList) { + result << inheritFrom; + if (presetsHash.contains(inheritFrom)) { + auto item = presetsHash[inheritFrom]; + if (item.inherits) + result << recursiveInheritsList(presetsHash, item.inherits.value()); + } + } + return result; +} + Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakePresetsData, Internal::PresetsData &cmakeUserPresetsData) { @@ -135,12 +150,14 @@ Internal::PresetsData CMakeProject::combinePresets(Internal::PresetsData &cmakeP if (!p.inherits) continue; - for (const QString &inheritFromName : p.inherits.value()) { - if (presetsHash.contains(inheritFromName)) { - p.inheritFrom(presetsHash[inheritFromName]); + const QStringList inheritsList = recursiveInheritsList(presetsHash, + p.inherits.value()); + Utils::reverseForeach(inheritsList, [&presetsHash, &p](const QString &inheritFrom) { + if (presetsHash.contains(inheritFrom)) { + p.inheritFrom(presetsHash[inheritFrom]); presetsHash[p.name] = p; } - } + }); } }; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 2d9631eb400..450d1540102 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -147,20 +147,31 @@ static QString displayPresetName(const QString &presetName) FilePaths CMakeProjectImporter::importCandidates() { - FilePaths candidates; + FilePaths candidates = presetCandidates(); - candidates << scanDirectory(projectFilePath().absolutePath(), "build"); + if (candidates.isEmpty()) { + candidates << scanDirectory(projectFilePath().absolutePath(), "build"); - const QList kits = KitManager::kits(); - for (const Kit *k : kits) { - FilePath shadowBuildDirectory - = CMakeBuildConfiguration::shadowBuildDirectory(projectFilePath(), - k, - QString(), - BuildConfiguration::Unknown); - candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString()); + const QList kits = KitManager::kits(); + for (const Kit *k : kits) { + FilePath shadowBuildDirectory + = CMakeBuildConfiguration::shadowBuildDirectory(projectFilePath(), + k, + QString(), + BuildConfiguration::Unknown); + candidates << scanDirectory(shadowBuildDirectory.absolutePath(), QString()); + } } + const FilePaths finalists = Utils::filteredUnique(candidates); + qCInfo(cmInputLog) << "import candidates:" << finalists; + return finalists; +} + +FilePaths CMakeProjectImporter::presetCandidates() +{ + FilePaths candidates; + for (const auto &configPreset : m_project->presetsData().configurePresets) { if (configPreset.hidden.value()) continue; @@ -190,9 +201,9 @@ FilePaths CMakeProjectImporter::importCandidates() } } - const FilePaths finalists = Utils::filteredUnique(candidates); - qCInfo(cmInputLog) << "import candidates:" << finalists; - return finalists; + m_hasCMakePresets = !candidates.isEmpty(); + + return candidates; } Target *CMakeProjectImporter::preferredTarget(const QList &possibleTargets) @@ -210,6 +221,22 @@ Target *CMakeProjectImporter::preferredTarget(const QList &possibleTar return ProjectImporter::preferredTarget(possibleTargets); } +bool CMakeProjectImporter::filter(ProjectExplorer::Kit *k) const +{ + if (!m_hasCMakePresets) + return true; + + const auto presetConfigItem = CMakeConfigurationKitAspect::cmakePresetConfigItem(k); + if (presetConfigItem.isNull()) + return false; + + const QString presetName = presetConfigItem.expandedValue(k); + return std::find_if(m_project->presetsData().configurePresets.cbegin(), + m_project->presetsData().configurePresets.cend(), + [&presetName](const auto &preset) { return presetName == preset.name; }) + != m_project->presetsData().configurePresets.cend(); +} + static CMakeConfig configurationFromPresetProbe( const FilePath &importPath, const FilePath &sourceDirectory, diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h index ba8af4d61bc..82e1835ba7b 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.h @@ -24,7 +24,9 @@ public: Utils::FilePaths importCandidates() final; ProjectExplorer::Target *preferredTarget(const QList &possibleTargets) final; + bool filter(ProjectExplorer::Kit *k) const final; + Utils::FilePaths presetCandidates(); private: QList examineDirectory(const Utils::FilePath &importPath, QString *warningMessage) const final; @@ -47,6 +49,7 @@ private: const CMakeProject *m_project; Utils::TemporaryDirectory m_presetsTempDir; + bool m_hasCMakePresets = false; }; #ifdef WITH_TESTS diff --git a/src/plugins/coreplugin/iversioncontrol.cpp b/src/plugins/coreplugin/iversioncontrol.cpp index 4cbc8050a26..f70e4be492e 100644 --- a/src/plugins/coreplugin/iversioncontrol.cpp +++ b/src/plugins/coreplugin/iversioncontrol.cpp @@ -14,44 +14,40 @@ #include #include -/*! - \class Core::IVersionControl::TopicCache - \inheaderfile coreplugin/iversioncontrol.h - \inmodule QtCreator - - \brief The TopicCache class stores a cache which maps a directory to a topic. - - A VCS topic is typically the current active branch name, but it can also have other - values (for example the latest tag) when there is no active branch. - - It is displayed: - \list - \li In the project tree, next to each root project - corresponding to the project. - \li In the main window title - corresponding to the current active editor. - \endlist - - In order to enable topic display, an IVersionControl subclass needs to create - an instance of the TopicCache subclass with appropriate overrides for its - pure virtual functions, and pass this instance to IVersionControl's constructor. - - The cache tracks a file in the repository, which is expected to change when the - topic changes. When the file is modified, the cache is refreshed. - For example: for Git this file is typically /.git/HEAD - */ - -/*! - \fn Utils::FilePath Core::IVersionControl::TopicCache::trackFile(const Utils::FilePath &repository) - Returns the path to the file that invalidates the cache for \a repository when - the file is modified. - - \fn QString Core::IVersionControl::TopicCache::refreshTopic(const Utils::FilePath &repository) - Returns the current topic for \a repository. - */ - using namespace Utils; namespace Core { +namespace Internal { + +class TopicData +{ +public: + QDateTime timeStamp; + QString topic; +}; + +class IVersionControlPrivate +{ +public: + IVersionControl::FileTracker m_fileTracker; + IVersionControl::TopicRefresher m_topicRefresher; + QHash m_topicCache; +}; + +} // Internal + +IVersionControl::IVersionControl() + : d(new Internal::IVersionControlPrivate) +{ + Core::VcsManager::addVersionControl(this); +} + +IVersionControl::~IVersionControl() +{ + delete d; +} + QString IVersionControl::vcsOpenText() const { return Tr::tr("Open with VCS (%1)").arg(displayName()); @@ -111,24 +107,83 @@ IVersionControl::RepoUrl IVersionControl::getRepoUrl(const QString &location) co return RepoUrl(location); } -void IVersionControl::setTopicCache(TopicCache *topicCache) +FilePath IVersionControl::trackFile(const FilePath &repository) { - m_topicCache = topicCache; + QTC_ASSERT(d->m_fileTracker, return {}); + return d->m_fileTracker(repository); } +QString IVersionControl::refreshTopic(const FilePath &repository) +{ + QTC_ASSERT(d->m_topicRefresher, return {}); + return d->m_topicRefresher(repository); +} + +/*! + Returns the topic for repository under \a topLevel. + + A VCS topic is typically the current active branch name, but it can also have other + values (for example the latest tag) when there is no active branch. + + It is displayed: + \list + \li In the project tree, next to each root project - corresponding to the project. + \li In the main window title - corresponding to the current active editor. + \endlist + + In order to enable topic display, an IVersionControl subclass needs to create + an instance of the TopicCache subclass with appropriate overrides for its + pure virtual functions, and pass this instance to IVersionControl's constructor. + + The cache tracks a file in the repository, which is expected to change when the + topic changes. When the file is modified, the cache is refreshed. + For example: for Git this file is typically /.git/HEAD + + The base implementation features a cache. If the cache for \a topLevel is valid, + it will be used. Otherwise it will be refreshed using the items provided by + \c setTopicFileTracker() and \c setTopicRefresher(). + + \sa setTopicFileTracker(), setTopicRefresher(). + */ + QString IVersionControl::vcsTopic(const FilePath &topLevel) { - return m_topicCache ? m_topicCache->topic(topLevel) : QString(); + QTC_ASSERT(!topLevel.isEmpty(), return QString()); + Internal::TopicData &data = d->m_topicCache[topLevel]; + const FilePath file = trackFile(topLevel); + + if (file.isEmpty()) + return QString(); + const QDateTime lastModified = file.lastModified(); + if (lastModified == data.timeStamp) + return data.topic; + data.timeStamp = lastModified; + return data.topic = refreshTopic(topLevel); } -IVersionControl::IVersionControl() +/*! + Provides the \a fileTracker function object for use in \c vscTopic() cache handling. + + The parameter object takes a repository as input and returns the file + that should trigger topic refresh (e.g. .git/HEAD for Git). + + Modification of this file will invalidate the internal topic cache for the repository. +*/ + +void IVersionControl::setTopicFileTracker(const FileTracker &fileTracker) { - Core::VcsManager::addVersionControl(this); + d->m_fileTracker = fileTracker; } -IVersionControl::~IVersionControl() +/*! + Provides the \a topicRefresher function object for use in \c vscTopic() cache handling. + + The parameter object takes a repository as input and returns its current topic. + */ + +void IVersionControl::setTopicRefresher(const TopicRefresher &topicRefresher) { - delete m_topicCache; + d->m_topicRefresher = topicRefresher; } FilePaths IVersionControl::unmanagedFiles(const FilePaths &filePaths) const @@ -143,29 +198,6 @@ IVersionControl::OpenSupportMode IVersionControl::openSupportMode(const FilePath Q_UNUSED(filePath) return NoOpen; } - -IVersionControl::TopicCache::~TopicCache() = default; - -/*! - Returns the topic for repository under \a topLevel. - - If the cache for \a topLevel is valid, it will be used. Otherwise it will be refreshed. - */ -QString IVersionControl::TopicCache::topic(const FilePath &topLevel) -{ - QTC_ASSERT(!topLevel.isEmpty(), return QString()); - TopicData &data = m_cache[topLevel]; - const FilePath file = trackFile(topLevel); - - if (file.isEmpty()) - return QString(); - const QDateTime lastModified = file.lastModified(); - if (lastModified == data.timeStamp) - return data.topic; - data.timeStamp = lastModified; - return data.topic = refreshTopic(topLevel); -} - void IVersionControl::fillLinkContextMenu(QMenu *, const FilePath &, const QString &) { } diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index e97749ca1b2..31e35437770 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -8,16 +8,15 @@ #include #include -#include #include -#include #include -#include QT_FORWARD_DECLARE_CLASS(QMenu); namespace Core { +namespace Internal { class IVersionControlPrivate; } + class CORE_EXPORT IVersionControl : public QObject { Q_OBJECT @@ -43,28 +42,6 @@ public: OpenMandatory /*!< Files must always be opened by the VCS */ }; - class CORE_EXPORT TopicCache - { - public: - virtual ~TopicCache(); - QString topic(const Utils::FilePath &topLevel); - - protected: - virtual Utils::FilePath trackFile(const Utils::FilePath &repository) = 0; - virtual QString refreshTopic(const Utils::FilePath &repository) = 0; - - private: - class TopicData - { - public: - QDateTime timeStamp; - QString topic; - }; - - QHash m_cache; - - }; - IVersionControl(); ~IVersionControl() override; @@ -218,7 +195,14 @@ public: }; virtual RepoUrl getRepoUrl(const QString &location) const; - void setTopicCache(TopicCache *topicCache); + // Topic cache + using FileTracker = std::function; + Utils::FilePath trackFile(const Utils::FilePath &repository); + void setTopicFileTracker(const FileTracker &fileTracker); + + using TopicRefresher = std::function; + QString refreshTopic(const Utils::FilePath &repository); + void setTopicRefresher(const TopicRefresher &topicRefresher); signals: void repositoryChanged(const Utils::FilePath &repository); @@ -226,7 +210,7 @@ signals: void configurationChanged(); private: - TopicCache *m_topicCache = nullptr; + Internal::IVersionControlPrivate *d; }; } // namespace Core diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 50f8499708f..3eb63d80312 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -175,7 +175,6 @@ void WelcomePageButton::setSize(Size size) const int hMargin = size == SizeSmall ? 12 : 26; const int vMargin = size == SizeSmall ? 2 : 4; d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin); - d->m_label->setFont(size == SizeSmall ? font() : StyleHelper::uiFont(StyleHelper::UiElementH2)); } void WelcomePageButton::setWithAccentColor(bool withAccent) diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index 37874a9e46f..44fc75270dd 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -87,7 +87,6 @@ SearchBox::SearchBox(QWidget *parent) m_lineEdit = new FancyLineEdit; m_lineEdit->setFiltering(true); m_lineEdit->setFrame(false); - m_lineEdit->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); m_lineEdit->setMinimumHeight(33); m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); @@ -806,7 +805,6 @@ ListModel *SectionedGridView::addSection(const Section §ion, const QListsetContentsMargins(0, ItemGap, 0, 0); - sectionLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); auto scrollArea = qobject_cast(widget(0)); auto vbox = qobject_cast(scrollArea->widget()->layout()); @@ -877,7 +875,6 @@ void SectionedGridView::zoomInSection(const Section §ion) noMargin }.emerge(); sectionLabel->setContentsMargins(0, ItemGap, 0, 0); - sectionLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); auto gridView = new GridView(zoomedInWidget); gridView->setItemDelegate(m_itemDelegate); diff --git a/src/plugins/cppeditor/baseeditordocumentparser.h b/src/plugins/cppeditor/baseeditordocumentparser.h index 45f6b953990..dce82893848 100644 --- a/src/plugins/cppeditor/baseeditordocumentparser.h +++ b/src/plugins/cppeditor/baseeditordocumentparser.h @@ -34,11 +34,11 @@ public: QByteArray editorDefines; QString preferredProjectPartId; - bool operator==(const Configuration &other) + friend bool operator==(const Configuration &left, const Configuration &right) { - return usePrecompiledHeaders == other.usePrecompiledHeaders - && editorDefines == other.editorDefines - && preferredProjectPartId == other.preferredProjectPartId; + return left.usePrecompiledHeaders == right.usePrecompiledHeaders + && left.editorDefines == right.editorDefines + && left.preferredProjectPartId == right.preferredProjectPartId; } }; diff --git a/src/plugins/cppeditor/cppeditoroutline.cpp b/src/plugins/cppeditor/cppeditoroutline.cpp index 05c521e0d31..d630a7ad1c6 100644 --- a/src/plugins/cppeditor/cppeditoroutline.cpp +++ b/src/plugins/cppeditor/cppeditoroutline.cpp @@ -150,12 +150,6 @@ QWidget *CppEditorOutline::widget() const return m_combo; } -QSharedPointer getDocument(const Utils::FilePath &filePath) -{ - const CPlusPlus::Snapshot snapshot = CppModelManager::snapshot(); - return snapshot.document(filePath); -} - void CppEditorOutline::updateNow() { m_combo->view()->expandAll(); diff --git a/src/plugins/cppeditor/cppeditoroutline.h b/src/plugins/cppeditor/cppeditoroutline.h index d73c0fc363d..b7ac18dd0f4 100644 --- a/src/plugins/cppeditor/cppeditoroutline.h +++ b/src/plugins/cppeditor/cppeditoroutline.h @@ -5,7 +5,6 @@ #include "cppoutlinemodel.h" -#include #include #include @@ -16,7 +15,6 @@ class QSortFilterProxyModel; class QTimer; QT_END_NAMESPACE -namespace TextEditor { class TextEditorWidget; } namespace Utils { class TreeViewComboBox; } namespace CppEditor { diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp index b68c739f82e..c9185e372c1 100644 --- a/src/plugins/cppeditor/cppeditorplugin.cpp +++ b/src/plugins/cppeditor/cppeditorplugin.cpp @@ -323,6 +323,10 @@ void CppEditorPlugin::addPerSymbolActions() switchDeclDef.setTouchBarText(Tr::tr("Decl/Def", "text on macOS touch bar")); switchDeclDef.addToContainers(menus, Constants::G_SYMBOL); switchDeclDef.addToContainer(Core::Constants::TOUCH_BAR, Core::Constants::G_TOUCHBAR_NAVIGATION); + switchDeclDef.addOnTriggered(this, [] { + if (CppEditorWidget *editorWidget = currentCppEditorWidget()) + editorWidget->switchDeclarationDefinition(/*inNextSplit*/ false); + }); ActionBuilder openDeclDefSplit(this, Constants::OPEN_DECLARATION_DEFINITION_IN_NEXT_SPLIT); openDeclDefSplit.setText(Tr::tr("Open Function Declaration/Definition in Next Split")); diff --git a/src/plugins/cppeditor/cppmodelmanagersupport.h b/src/plugins/cppeditor/cppmodelmanagersupport.h index a43a1e0b02b..c2c463df59a 100644 --- a/src/plugins/cppeditor/cppmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppmodelmanagersupport.h @@ -9,9 +9,6 @@ #include -#include -#include - #include namespace Core { class SearchResult; } @@ -29,9 +26,6 @@ class RefactoringEngineInterface; class CPPEDITOR_EXPORT ModelManagerSupport { -public: - using Ptr = QSharedPointer; - public: virtual ~ModelManagerSupport() = 0; diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 80a4af36db1..48c9bbc68af 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -5008,19 +5008,19 @@ void QuickfixTest::testInsertDefFromDeclTemplateClassAndTemplateFunction() "class Foo\n" "{\n" " template\n" - " void fun@c();\n" + " T fun@c(U u);\n" "};\n"; QByteArray expected = "template" "class Foo\n" "{\n" " template\n" - " void fun@c();\n" + " T fun@c(U u);\n" "};\n" "\n" "template\n" "template\n" - "void Foo::func()\n" + "T Foo::func(U u)\n" "{\n" "\n" "}\n"; @@ -5029,6 +5029,39 @@ void QuickfixTest::testInsertDefFromDeclTemplateClassAndTemplateFunction() QuickFixOperationTest(singleDocument(original, expected), &factory); } +void QuickfixTest::testInsertDefFromDeclTemplateClassAndFunctionInsideNamespace() +{ + QByteArray original = + "namespace N {\n" + "template" + "class Foo\n" + "{\n" + " template\n" + " T fun@c(U u);\n" + "};\n" + "}\n"; + QByteArray expected = + "namespace N {\n" + "template" + "class Foo\n" + "{\n" + " template\n" + " T fun@c(U u);\n" + "};\n" + "\n" + "template\n" + "template\n" + "T Foo::func(U u)\n" + "{\n" + "\n" + "}\n" + "\n" + "}\n"; + + InsertDefFromDecl factory; + QuickFixOperationTest(singleDocument(original, expected), &factory); +} + void QuickfixTest::testInsertDefFromDeclFunctionWithSignedUnsignedArgument() { QByteArray original; diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h index e677d88af24..4d734c9c09c 100644 --- a/src/plugins/cppeditor/cppquickfix_test.h +++ b/src/plugins/cppeditor/cppquickfix_test.h @@ -137,6 +137,7 @@ private slots: void testInsertDefFromDeclTemplateClassWithValueParam(); void testInsertDefFromDeclTemplateFunction(); void testInsertDefFromDeclTemplateClassAndTemplateFunction(); + void testInsertDefFromDeclTemplateClassAndFunctionInsideNamespace(); void testInsertDefFromDeclFunctionWithSignedUnsignedArgument(); void testInsertDefFromDeclNotTriggeredForFriendFunc(); void testInsertDefFromDeclMinimalFunctionParameterType(); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index b2f01eaad47..90563ccd33d 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -141,7 +141,8 @@ enum DefPos { inline bool isQtStringLiteral(const QByteArray &id) { - return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral"; + return id == "QLatin1String" || id == "QLatin1Literal" || id == "QStringLiteral" + || id == "QByteArrayLiteral"; } inline bool isQtStringTranslation(const QByteArray &id) @@ -1117,21 +1118,20 @@ enum ActionFlags { EncloseInQLatin1CharAction = 0x1, EncloseInQLatin1StringAction = 0x2, EncloseInQStringLiteralAction = 0x4, - EncloseActionMask = EncloseInQLatin1CharAction - | EncloseInQLatin1StringAction | EncloseInQStringLiteralAction, - TranslateTrAction = 0x8, - TranslateQCoreApplicationAction = 0x10, - TranslateNoopAction = 0x20, - TranslationMask = TranslateTrAction - | TranslateQCoreApplicationAction | TranslateNoopAction, - RemoveObjectiveCAction = 0x40, - ConvertEscapeSequencesToCharAction = 0x100, - ConvertEscapeSequencesToStringAction = 0x200, - SingleQuoteAction = 0x400, - DoubleQuoteAction = 0x800 + EncloseInQByteArrayLiteralAction = 0x8, + EncloseActionMask = EncloseInQLatin1CharAction | EncloseInQLatin1StringAction + | EncloseInQStringLiteralAction | EncloseInQByteArrayLiteralAction, + TranslateTrAction = 0x10, + TranslateQCoreApplicationAction = 0x20, + TranslateNoopAction = 0x40, + TranslationMask = TranslateTrAction | TranslateQCoreApplicationAction | TranslateNoopAction, + RemoveObjectiveCAction = 0x100, + ConvertEscapeSequencesToCharAction = 0x200, + ConvertEscapeSequencesToStringAction = 0x400, + SingleQuoteAction = 0x800, + DoubleQuoteAction = 0x1000 }; - /* Convert single-character string literals into character literals with some * special cases "a" --> 'a', "'" --> '\'', "\n" --> '\n', "\"" --> '"'. */ static QByteArray stringToCharEscapeSequences(const QByteArray &content) @@ -1167,6 +1167,8 @@ static QString stringLiteralReplacement(unsigned actions) return QLatin1String("QLatin1String"); if (actions & EncloseInQStringLiteralAction) return QLatin1String("QStringLiteral"); + if (actions & EncloseInQByteArrayLiteralAction) + return QLatin1String("QByteArrayLiteral"); if (actions & TranslateTrAction) return QLatin1String("tr"); if (actions & TranslateQCoreApplicationAction) @@ -1357,6 +1359,9 @@ void WrapStringLiteral::doMatch(const CppQuickFixInterface &interface, QuickFixO actions = EncloseInQStringLiteralAction | objectiveCActions; result << new WrapStringLiteralOp(interface, priority, actions, msgQtStringLiteralDescription(stringLiteralReplacement(actions)), literal); + actions = EncloseInQByteArrayLiteralAction | objectiveCActions; + result << new WrapStringLiteralOp(interface, priority, actions, + msgQtStringLiteralDescription(stringLiteralReplacement(actions)), literal); } } diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 61851d9e4ee..4ca9dd83b39 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -88,35 +89,11 @@ const char CMD_ID_REPOSITORYUPDATE[] = "CVS.RepositoryUpdate"; const char CVS_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.cvs.submit"; const char CVSCOMMITEDITOR_ID[] = "CVS Commit Editor"; -const char CVSCOMMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Commit Editor"); -const VcsBaseEditorParameters commandLogEditorParameters { - OtherContent, - "CVS Command Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Command Log Editor"), // display name - "text/vnd.qtcreator.cvs.commandlog" -}; - -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - "CVS File Log Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS File Log Editor"), // display name - "text/vnd.qtcreator.cvs.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - "CVS Annotation Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Annotation Editor"), // display name - "text/vnd.qtcreator.cvs.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - "CVS Diff Editor", // id - QT_TRANSLATE_NOOP("QtC::VcsBase", "CVS Diff Editor"), // display name - "text/x-patch" -}; +const char CVS_COMMANDLOG_EDITOR_ID[] = "CVS Command Log Editor"; +const char CVS_FILELOG_EDITOR_ID[] = "CVS File Log Editor"; +const char CVS_ANNOTATION_EDITOR_ID[] = "CVS Annotation Editor"; +const char CVS_DIFF_EDITOR_ID[] = "CVS Diff Editor"; static inline bool messageBoxQuestion(const QString &title, const QString &question) { @@ -312,29 +289,41 @@ private: QAction *m_menuAction = nullptr; public: - VcsEditorFactory commandLogEditorFactory { - &commandLogEditorParameters, + VcsEditorFactory commandLogEditorFactory {{ + OtherContent, + CVS_COMMANDLOG_EDITOR_ID, + VcsBase::Tr::tr("CVS Command Log Editor"), // display name + "text/vnd.qtcreator.cvs.commandlog", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + CVS_FILELOG_EDITOR_ID, + VcsBase::Tr::tr("CVS File Log Editor"), // display name + "text/vnd.qtcreator.cvs.log", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + CVS_ANNOTATION_EDITOR_ID, + VcsBase::Tr::tr("CVS Annotation Editor"), // display name + "text/vnd.qtcreator.cvs.annotation", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + CVS_DIFF_EDITOR_ID, + VcsBase::Tr::tr("CVS Diff Editor"), // display name + "text/x-patch", [] { return new CvsEditorWidget; }, std::bind(&CvsPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; Utils::Id CvsPluginPrivate::id() const @@ -460,7 +449,7 @@ CvsPluginPrivate::CvsPluginPrivate() setupVcsSubmitEditor(this, { CVS_SUBMIT_MIMETYPE, CVSCOMMITEDITOR_ID, - CVSCOMMITEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("CVS Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CvsSubmitEditor; }, }); @@ -965,7 +954,7 @@ void CvsPluginPrivate::filelog(const FilePath &workingDir, } else { const QString title = QString::fromLatin1("cvs log %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - logEditorParameters.id, source, codec); + CVS_FILELOG_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(newEditor)->setFileLogAnnotateEnabled(true); @@ -1105,7 +1094,7 @@ void CvsPluginPrivate::annotate(const FilePath &workingDir, const QString &file, } else { const QString title = QString::fromLatin1("cvs annotate %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - annotateEditorParameters.id, source, codec); + CVS_ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } @@ -1119,7 +1108,7 @@ bool CvsPluginPrivate::status(const FilePath &topLevel, const QString &file, con const auto response = runCvs(topLevel, args); const bool ok = response.result() == ProcessResult::FinishedWithSuccess; if (ok) { - showOutputInEditor(title, response.cleanedStdOut(), commandLogEditorParameters.id, + showOutputInEditor(title, response.cleanedStdOut(), CVS_COMMANDLOG_EDITOR_ID, topLevel, nullptr); } return ok; @@ -1284,7 +1273,7 @@ bool CvsPluginPrivate::describe(const FilePath &repositoryPath, setDiffBaseDirectory(editor, repositoryPath); } else { const QString title = QString::fromLatin1("cvs describe %1").arg(commitId); - IEditor *newEditor = showOutputInEditor(title, output, diffEditorParameters.id, + IEditor *newEditor = showOutputInEditor(title, output, CVS_DIFF_EDITOR_ID, FilePath::fromString(entries.front().file), codec); VcsBaseEditor::tagEditor(newEditor, commitId); setDiffBaseDirectory(newEditor, repositoryPath); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index e49e429f775..d2647f3d7b9 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -787,9 +788,10 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(const QStringList &arguments) ICore::addAdditionalContext(debuggerNotRunning); m_arguments = arguments; - if (!m_arguments.isEmpty()) - connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::finishedInitialization, + if (!m_arguments.isEmpty()) { + connect(SessionManager::instance(), &SessionManager::startupSessionRestored, this, &DebuggerPluginPrivate::parseCommandLineArguments); + } // Menus m_menu = ActionManager::createMenu(M_DEBUG_ANALYZER); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 406b5524473..9efc98f24c3 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4093,7 +4093,7 @@ void GdbEngine::setEnvironmentVariables() Environment baseEnv = runParameters().debugger.environment; Environment runEnv = runParameters().inferior.environment; - const NameValueItems items = baseEnv.diff(runEnv); + const EnvironmentItems items = baseEnv.diff(runEnv); for (const EnvironmentItem &item : items) { // imitate the weird windows gdb behavior of setting the case of the path environment // variable name to an all uppercase PATH diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 7c907678aed..d271d15c5a5 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -208,7 +208,6 @@ public: bool unpausedEvaluate = false; bool contextEvaluate = false; bool supportChangeBreakpoint = false; - bool hasQuit = false; QTimer connectionTimer; QmlDebug::QDebugMessageClient *msgClient = nullptr; @@ -380,7 +379,7 @@ void QmlEngine::beginConnection() void QmlEngine::connectionStartupFailed() { - if (d->hasQuit) + if (isDying()) return; if (d->retryOnConnectFail) { @@ -502,8 +501,7 @@ void QmlEngine::startProcess() void QmlEngine::stopProcess() { - if (d->process.isRunning()) - d->process.close(); + d->process.close(); } void QmlEngine::shutdownInferior() @@ -937,15 +935,6 @@ bool QmlEngine::hasCapability(unsigned cap) const | AddWatcherCapability;*/ } -void QmlEngine::quitDebugger() -{ - d->automaticConnect = false; - d->retryOnConnectFail = false; - d->hasQuit = true; - stopProcess(); - closeConnection(); -} - void QmlEngine::doUpdateLocals(const UpdateParameters ¶ms) { d->updateLocals(params.qmlFocusOnFrame); diff --git a/src/plugins/debugger/qml/qmlengine.h b/src/plugins/debugger/qml/qmlengine.h index 2006ce081ff..7c609e12496 100644 --- a/src/plugins/debugger/qml/qmlengine.h +++ b/src/plugins/debugger/qml/qmlengine.h @@ -91,7 +91,6 @@ private: bool companionPreventsActions() const override; bool hasCapability(unsigned) const override; - void quitDebugger() override; void doUpdateLocals(const UpdateParameters ¶ms) override; Core::Context languageContext() const override; diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 8d0af0e4d31..120ce756122 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -151,8 +151,8 @@ QString WatchItem::toString() const if (!value.isEmpty()) str << "value=\"" << value << doubleQuoteComma; - if (elided) - str << "valueelided=\"" << elided << doubleQuoteComma; + if (valuelen) + str << "valuelen=\"" << valuelen << doubleQuoteComma; if (!editvalue.isEmpty()) str << "editvalue=\"<...>\","; @@ -300,9 +300,9 @@ void WatchItem::parseHelper(const GdbMi &input, bool maySort) if (mi.isValid()) id = mi.toInt(); - mi = input["valueelided"]; + mi = input["valuelen"]; if (mi.isValid()) - elided = mi.toInt(); + valuelen = mi.toInt(); mi = input["bitpos"]; if (mi.isValid()) diff --git a/src/plugins/debugger/watchdata.h b/src/plugins/debugger/watchdata.h index bb2e458bcd3..672ded5e7c6 100644 --- a/src/plugins/debugger/watchdata.h +++ b/src/plugins/debugger/watchdata.h @@ -72,7 +72,7 @@ public: uint bitsize = 0; // Size in case of bit fields uint autoDerefCount = 0; // number of levels of automatic dereferencing that has taken place (for pointer types) uint variablesReference = 0;// reference to the variable in the variables request DAP related - int elided = 0; // Full size if value was cut off, -1 if cut on unknown size, 0 otherwise + int valuelen = 0; // -1 if cut on unknown size, full size otherwise int arrayIndex = -1; // -1 if not an array member uchar sortGroup = 0; // 0 - ordinary member, 1 - vptr, 2 - base class bool wantsChildren = false; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index eef0ba5a3ba..841dc4d0156 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -818,14 +818,24 @@ static QString formattedValue(const WatchItem *item) return reformatInteger(integer, format, item->size, false); } - if (item->elided) { - QString v = item->value; - v.chop(1); - QString len = item->elided > 0 ? QString::number(item->elided) : "unknown length"; - return quoteUnprintable(v) + "\"... (" + len + ')'; + const int maxLength = settings().displayStringLimit(); + QString v = quoteUnprintable(item->value); + + if (v.endsWith('"')) { + if (item->valuelen > maxLength) { + v.chop(1); + v.append("...\""); + } + if (item->valuelen > 0) + v += QString(" (%1)").arg(item->valuelen); + return v; } - return quoteUnprintable(item->value); + if (v.size() > maxLength) { + v.truncate(maxLength); + v += QLatin1String("..."); + } + return v; } // Get a pointer address from pointer values reported by the debugger. @@ -886,18 +896,6 @@ QVariant WatchItem::editValue() const return QVariant(quoteUnprintable(stringValue)); } -// Truncate value for item view, maintaining quotes. -static QString truncateValue(QString v) -{ - enum { maxLength = 512 }; - if (v.size() < maxLength) - return v; - const bool isQuoted = v.endsWith('"'); // check for 'char* "Hallo"' - v.truncate(maxLength); - v += QLatin1String(isQuoted ? "...\"" : "..."); - return v; -} - static QString displayName(const WatchItem *item) { QString result; @@ -939,13 +937,9 @@ static QString displayName(const WatchItem *item) return result; } - void WatchItem::updateValueCache() const { - QString formatted = truncateValue(formattedValue(this)); - if (formatted.endsWith('"')) - formatted.append(QString(" (%1)").arg(this->value.length() - 2)); - valueCache = formatted; + valueCache = formattedValue(this); valueCache = watchModel(this)->removeNamespaces(valueCache); if (valueCache.isEmpty() && this->address) valueCache += QString::fromLatin1("@0x" + QByteArray::number(this->address, 16)); @@ -1303,7 +1297,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const // FIXME: Forcing types is not implemented yet. //if (idx.column() == 2) // return editable; // Watcher types can be set by force. - if (column == ValueColumn && item->valueEditable && !item->elided) + if (column == ValueColumn && item->valueEditable && item->valuelen >= 0) return editable; // Watcher values are sometimes editable. } } else if (item->isLocal()) { @@ -1311,7 +1305,7 @@ Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const return notEditable; if (isRunning && !m_engine->hasCapability(AddWatcherWhileRunningCapability)) return notEditable; - if (column == ValueColumn && item->valueEditable && !item->elided) + if (column == ValueColumn && item->valueEditable && item->valuelen >= 0) return editable; // Locals values are sometimes editable. if (column == ValueColumn && item->arrayIndex >= 0) return editable; diff --git a/src/plugins/diffeditor/diffeditor.h b/src/plugins/diffeditor/diffeditor.h index e00a6e0fe49..60f7a772140 100644 --- a/src/plugins/diffeditor/diffeditor.h +++ b/src/plugins/diffeditor/diffeditor.h @@ -79,12 +79,12 @@ private: QComboBox *m_entriesComboBox = nullptr; QSpinBox *m_contextSpinBox = nullptr; QAction *m_contextSpinBoxAction = nullptr; - QAction *m_toggleSyncAction; - QAction *m_whitespaceButtonAction; - QAction *m_toggleDescriptionAction; - QAction *m_reloadAction; + QAction *m_toggleSyncAction = nullptr; + QAction *m_whitespaceButtonAction = nullptr; + QAction *m_toggleDescriptionAction = nullptr; + QAction *m_reloadAction = nullptr; QAction *m_contextLabelAction = nullptr; - QAction *m_viewSwitcherAction; + QAction *m_viewSwitcherAction = nullptr; QPair m_currentFileChunk; int m_currentViewIndex = -1; int m_currentDiffFileIndex = -1; diff --git a/src/plugins/fossil/constants.h b/src/plugins/fossil/constants.h index 6dd6bd4d048..558c8fc3ed4 100644 --- a/src/plugins/fossil/constants.h +++ b/src/plugins/fossil/constants.h @@ -3,10 +3,7 @@ #pragma once -#include - -namespace Fossil { -namespace Constants { +namespace Fossil::Constants { const char VCS_ID_FOSSIL[] = "I.Fossil"; @@ -31,20 +28,16 @@ const char DIFFFILE_ID_EXACT[] = "[+]{3} (.*)\\s*"; // match and capture //BaseEditorParameters const char FILELOG_ID[] = "Fossil File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.fossil.log"; const char ANNOTATELOG_ID[] = "Fossil Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.fossil.annotation"; const char DIFFLOG_ID[] = "Fossil Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Diff Editor"); const char DIFFAPP[] = "text/x-patch"; //SubmitEditorParameters const char COMMIT_ID[] = "Fossil Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Fossil Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.fossil.commit"; //menu items @@ -85,5 +78,4 @@ const char FSTATUS_UNKNOWN[] = "Unknown"; // Fossil Json Wizards const char WIZARD_PATH[] = ":/fossil/wizard"; -} // namespace Constants -} // namespace Fossil +} // Fossil::Constants diff --git a/src/plugins/fossil/fossilclient.cpp b/src/plugins/fossil/fossilclient.cpp index e892978799e..d24935595a6 100644 --- a/src/plugins/fossil/fossilclient.cpp +++ b/src/plugins/fossil/fossilclient.cpp @@ -736,7 +736,7 @@ void FossilClient::annotate(const FilePath &workingDir, const QString &file, int lineNumber = -1; editor->setDefaultLineNumber(lineNumber); - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } bool FossilClient::isVcsFileOrDirectory(const FilePath &filePath) const @@ -833,7 +833,7 @@ void FossilClient::view(const FilePath &source, const QString &id, const QString VcsBaseEditor::getCodec(source), "view", id); editor->setWorkingDirectory(workingDirectory); - enqueueJob(createCommand(workingDirectory, editor), args + extraOptions); + enqueueJob(createCommand(workingDirectory, editor), args + extraOptions, source); } class FossilLogHighlighter : QSyntaxHighlighter @@ -935,7 +935,7 @@ void FossilClient::log(const FilePath &workingDir, const QStringList &files, args << effectiveArgs; if (!files.isEmpty()) args << "--path" << files; - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } void FossilClient::logCurrentFile(const FilePath &workingDir, const QStringList &files, @@ -989,7 +989,7 @@ void FossilClient::logCurrentFile(const FilePath &workingDir, const QStringList QStringList args(vcsCmdString); args << effectiveArgs << files; - enqueueJob(createCommand(workingDir, fossilEditor), args); + enqueueJob(createCommand(workingDir, fossilEditor), args, workingDir); } void FossilClient::revertFile(const FilePath &workingDir, @@ -1009,7 +1009,7 @@ void FossilClient::revertFile(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void FossilClient::revertAll(const FilePath &workingDir, const QString &revision, const QStringList &extraOptions) @@ -1033,7 +1033,7 @@ void FossilClient::revertAll(const FilePath &workingDir, const QString &revision if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(createCommand(workingDir), args); + enqueueJob(createCommand(workingDir), args, workingDir); } QString FossilClient::sanitizeFossilOutput(const QString &output) const diff --git a/src/plugins/fossil/fossilplugin.cpp b/src/plugins/fossil/fossilplugin.cpp index 46924462580..c4ea13b4464 100644 --- a/src/plugins/fossil/fossilplugin.cpp +++ b/src/plugins/fossil/fossilplugin.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -60,45 +61,6 @@ using namespace std::placeholders; namespace Fossil::Internal { -class FossilTopicCache final : public IVersionControl::TopicCache -{ -public: - FossilTopicCache() = default; - -protected: - FilePath trackFile(const FilePath &repository) final - { - return repository.pathAppended(Constants::FOSSILREPO); - } - - QString refreshTopic(const FilePath &repository) final - { - return fossilClient().synchronousTopic(repository); - } -}; - -const VcsBaseEditorParameters fileLogParameters { - LogOutput, - Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, - Constants::LOGAPP -}; - -const VcsBaseEditorParameters annotateLogParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - - class FossilPluginPrivate final : public VersionControlBase { public: @@ -171,23 +133,32 @@ public: bool pullOrPush(SyncMode mode); // Variables - VcsEditorFactory fileLogFactory { - &fileLogParameters, + VcsEditorFactory fileLogFactory {{ + LogOutput, + Constants::FILELOG_ID, + VcsBase::Tr::tr("Fossil File Log Editor"), + Constants::LOGAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateLogFactory { - &annotateLogParameters, + VcsEditorFactory annotateLogFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + VcsBase::Tr::tr("Fossil Annotation Editor"), + Constants::ANNOTATEAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffFactory { - &diffParameters, + VcsEditorFactory diffFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + VcsBase::Tr::tr("Fossil Diff Editor"), + Constants::DIFFAPP, [] { return new FossilEditorWidget; }, std::bind(&FossilPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; CommandLocator *m_commandLocator = nullptr; ActionContainer *m_fossilContainer = nullptr; @@ -234,7 +205,13 @@ FossilPluginPrivate::FossilPluginPrivate() { Context context(Constants::FOSSIL_CONTEXT); - setTopicCache(new FossilTopicCache); + setTopicFileTracker([](const FilePath &repository) { + return repository.pathAppended(Constants::FOSSILREPO); + }); + setTopicRefresher([](const FilePath &repository) { + return fossilClient().synchronousTopic(repository); + }); + connect(&fossilClient(), &VcsBaseClient::changed, this, &FossilPluginPrivate::changed); m_commandLocator = new CommandLocator("Fossil", "fossil", "fossil", this); @@ -251,7 +228,7 @@ FossilPluginPrivate::FossilPluginPrivate() setupVcsSubmitEditor(this, { Constants::COMMITMIMETYPE, Constants::COMMIT_ID, - Constants::COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Fossil Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); @@ -831,7 +808,7 @@ bool FossilPluginPrivate::managesFile(const FilePath &workingDirectory, const QS bool FossilPluginPrivate::isConfigured() const { - const FilePath binary = fossilClient().vcsBinary(); + const FilePath binary = fossilClient().vcsBinary({}); if (binary.isEmpty()) return false; @@ -950,7 +927,8 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou checkoutPath.createDir(); // Setup the wizard page command job - auto command = VcsBaseClient::createVcsCommand(checkoutPath, fossilClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(checkoutPath, + fossilClient().processEnvironment(checkoutPath)); if (!isLocalRepository && !cloneRepository.exists()) { @@ -986,7 +964,7 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou << extraOptions << sourceUrl << fossilFileNative; - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } // check out the cloned repository file into the working copy directory; @@ -995,20 +973,20 @@ VcsCommand *FossilPluginPrivate::createInitialCheckoutCommand(const QString &sou QStringList args({"open", fossilFileNative}); if (!checkoutBranch.isEmpty()) args << checkoutBranch; - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); // set user default to admin user if specified if (!isLocalRepository && !adminUser.isEmpty()) { const QStringList args({ "user", "default", adminUser, "--user", adminUser}); - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } // turn-off autosync if requested if (!isLocalRepository && disableAutosync) { const QStringList args({"settings", "autosync", "off"}); - command->addJob({fossilClient().vcsBinary(), args}, -1); + command->addJob({fossilClient().vcsBinary(checkoutPath), args}, -1); } return command; diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index fa9dee2cb37..99e6e010057 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -318,9 +318,12 @@ QVariant BranchModel::data(const QModelIndex &index, int role) const if (!node->isLocal() || !node->isLeaf()) break; - res += ' ' + arrowUp + QString::number(node->status.ahead); + if (node->status.ahead >= 0) + res += ' ' + arrowUp + QString::number(node->status.ahead); + if (!node->tracking.isEmpty()) { - res += ' ' + arrowDown + QString::number(node->status.behind); + if (node->status.behind >= 0) + res += ' ' + arrowDown + QString::number(node->status.behind); res += " [" + node->tracking + ']'; } break; @@ -911,13 +914,13 @@ void BranchModel::updateUpstreamStatus(BranchNode *node) return; Process *process = new Process(node); - process->setEnvironment(gitClient().processEnvironment()); + process->setEnvironment(gitClient().processEnvironment(d->workingDirectory)); QStringList parameters = {"rev-list", "--no-color", "--count"}; if (node->tracking.isEmpty()) - parameters += {"HEAD", "--not", "--remotes"}; + parameters += {node->fullRef(), "--not", "--remotes"}; else parameters += {"--left-right", node->fullRef() + "..." + node->tracking}; - process->setCommand({gitClient().vcsBinary(), parameters}); + process->setCommand({gitClient().vcsBinary(d->workingDirectory), parameters}); process->setWorkingDirectory(d->workingDirectory); connect(process, &Process::done, this, [this, process, node] { process->deleteLater(); diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index cf991e6e938..12cc91eddb3 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -33,8 +33,8 @@ ChangeSelectionDialog::ChangeSelectionDialog(const FilePath &workingDirectory, I QWidget *parent) : QDialog(parent) { - m_gitExecutable = gitClient().vcsBinary(); - m_gitEnvironment = gitClient().processEnvironment(); + m_gitExecutable = gitClient().vcsBinary(workingDirectory); + m_gitEnvironment = gitClient().processEnvironment(workingDirectory); resize(550, 350); setWindowTitle(Tr::tr("Select a Git Commit")); @@ -209,8 +209,9 @@ void ChangeSelectionDialog::recalculateCompletion() return; Process *process = new Process(this); - process->setEnvironment(gitClient().processEnvironment()); - process->setCommand({gitClient().vcsBinary(), {"for-each-ref", "--format=%(refname:short)"}}); + process->setEnvironment(gitClient().processEnvironment(workingDir)); + process->setCommand( + {gitClient().vcsBinary(workingDir), {"for-each-ref", "--format=%(refname:short)"}}); process->setWorkingDirectory(workingDir); process->setUseCtrlCStub(true); connect(process, &Process::done, this, [this, process] { diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index b11458393e8..8af786ac5e5 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -266,7 +266,6 @@ QueryContext::QueryContext(const QString &query, m_output.append(m_process.readAllRawStandardOutput()); }); connect(&m_process, &Process::done, this, &QueryContext::processDone); - m_process.setEnvironment(Git::Internal::gitClient().processEnvironment()); m_timer.setInterval(timeOutMS); m_timer.setSingleShot(true); @@ -286,6 +285,7 @@ void QueryContext::start() VcsOutputWindow::appendCommand(m_process.workingDirectory(), commandLine); m_timer.start(); m_process.setCommand(commandLine); + m_process.setEnvironment(Git::Internal::gitClient().processEnvironment(m_binary)); auto progress = new Core::ProcessProgress(&m_process); progress->setDisplayName(Git::Tr::tr("Querying Gerrit")); m_process.start(); diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 802c921409a..3ef90358b9b 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -101,7 +101,7 @@ FetchContext::FetchContext(const std::shared_ptr &change, VcsBase::VcsOutputWindow::append(QString::fromLocal8Bit(m_process.readAllRawStandardOutput())); }); m_process.setWorkingDirectory(repository); - m_process.setEnvironment(gitClient().processEnvironment()); + m_process.setEnvironment(gitClient().processEnvironment(repository)); } void FetchContext::start() @@ -279,7 +279,7 @@ QString GerritPlugin::branch(const FilePath &repository) void GerritPlugin::fetch(const std::shared_ptr &change, int mode) { // Locate git. - const Utils::FilePath git = gitClient().vcsBinary(); + const Utils::FilePath git = gitClient().vcsBinary(m_dialog->repositoryPath()); if (git.isEmpty()) { VcsBase::VcsOutputWindow::appendError(Git::Tr::tr("Git is not available.")); return; diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 6f9224dda04..eb857c46859 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -827,15 +827,12 @@ FilePath GitClient::findRepositoryForDirectory(const FilePath &directory) const { if (directory.isEmpty() || directory.endsWith("/.git") || directory.path().contains("/.git/")) return {}; - // QFileInfo is outside loop, because it is faster this way - QFileInfo fileInfo; FilePath parent; for (FilePath dir = directory; !dir.isEmpty(); dir = dir.parentDir()) { const FilePath gitName = dir.pathAppended(GIT_DIRECTORY); if (!gitName.exists()) continue; // parent might exist - fileInfo.setFile(gitName.toString()); - if (fileInfo.isFile()) + if (gitName.isFile()) return dir; if (gitName.pathAppended("config").exists()) return dir; @@ -929,8 +926,8 @@ void GitClient::requestReload(const QString &documentId, const FilePath &source, QTC_ASSERT(document, return); GitBaseDiffEditorController *controller = factory(document); QTC_ASSERT(controller, return); - controller->setVcsBinary(settings().gitExecutable()); - controller->setProcessEnvironment(processEnvironment()); + controller->setVcsBinary(vcsBinary(workingDirectory)); + controller->setProcessEnvironment(processEnvironment(workingDirectory)); controller->setWorkingDirectory(workingDirectory); using namespace std::placeholders; @@ -1047,9 +1044,8 @@ void GitClient::log(const FilePath &workingDirectory, const QString &fileName, const QString title = Tr::tr("Git Log \"%1\"").arg(msgArg); const Id editorId = Git::Constants::GIT_LOG_EDITOR_ID; const FilePath sourceFile = VcsBaseEditor::getSource(workingDir, fileName); - GitEditorWidget *editor = static_cast( - createVcsEditor(editorId, title, sourceFile, - encoding(EncodingLogOutput), "logTitle", msgArg)); + GitEditorWidget *editor = static_cast(createVcsEditor( + editorId, title, sourceFile, encoding(EncodingLogOutput, sourceFile), "logTitle", msgArg)); VcsBaseEditorConfig *argWidget = editor->editorConfig(); if (!argWidget) { argWidget = new GitLogArgumentsWidget(!fileName.isEmpty(), editor); @@ -2089,9 +2085,9 @@ bool GitClient::synchronousApplyPatch(const FilePath &workingDirectory, return false; } -Environment GitClient::processEnvironment() const +Environment GitClient::processEnvironment(const FilePath &appliedTo) const { - Environment environment = VcsBaseClientImpl::processEnvironment(); + Environment environment; environment.prependOrSetPath(settings().path()); if (HostOsInfo::isWindowsHost() && settings().winSetHomeEnvironment()) { QString homePath; @@ -2103,7 +2099,7 @@ Environment GitClient::processEnvironment() const environment.set("HOME", homePath); } environment.set("GIT_EDITOR", m_disableEditor ? "true" : m_gitQtcEditor); - return environment; + return environment.appliedToEnvironment(appliedTo.deviceEnvironment()); } bool GitClient::beginStashScope(const FilePath &workingDirectory, const QString &command, @@ -2387,7 +2383,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR void GitClient::launchGitK(const FilePath &workingDirectory, const QString &fileName) const { - tryLaunchingGitK(processEnvironment(), workingDirectory, fileName); + tryLaunchingGitK(processEnvironment(workingDirectory), workingDirectory, fileName); } void GitClient::launchRepositoryBrowser(const FilePath &workingDirectory) const @@ -2420,7 +2416,7 @@ void GitClient::tryLaunchingGitK(const Environment &env, const QString &fileName, GitClient::GitKLaunchTrial trial) const { - const FilePath gitBinDirectory = gitBinDir(trial, vcsBinary().parentDir()); + const FilePath gitBinDirectory = gitBinDir(trial, vcsBinary(workingDirectory).parentDir()); FilePath binary = gitBinDirectory.pathAppended("gitk").withExecutableSuffix(); QStringList arguments; if (HostOsInfo::isWindowsHost()) { @@ -2469,7 +2465,7 @@ void GitClient::handleGitKFailedToStart(const Environment &env, GitKLaunchTrial nextTrial = None; - if (oldTrial == Bin && vcsBinary().parentDir().fileName() == "bin") { + if (oldTrial == Bin && vcsBinary(workingDirectory).parentDir().fileName() == "bin") { nextTrial = ParentOfBin; } else if (oldTrial != SystemPath && !Environment::systemEnvironment().searchInPath("gitk").isEmpty()) { @@ -2486,7 +2482,7 @@ void GitClient::handleGitKFailedToStart(const Environment &env, bool GitClient::launchGitGui(const FilePath &workingDirectory) { bool success = true; - FilePath gitBinary = vcsBinary(); + FilePath gitBinary = vcsBinary(workingDirectory); if (gitBinary.isEmpty()) { success = false; } else { @@ -2501,7 +2497,7 @@ bool GitClient::launchGitGui(const FilePath &workingDirectory) { FilePath GitClient::gitBinDirectory() const { - const QString git = vcsBinary().toString(); + const QString git = vcsBinary({}).toString(); if (git.isEmpty()) return {}; @@ -2529,7 +2525,7 @@ FilePath GitClient::gitBinDirectory() const bool GitClient::launchGitBash(const FilePath &workingDirectory) { bool success = true; - const FilePath git = vcsBinary(); + const FilePath git = vcsBinary(workingDirectory); if (git.isEmpty()) { success = false; @@ -2544,13 +2540,19 @@ bool GitClient::launchGitBash(const FilePath &workingDirectory) return success; } -FilePath GitClient::vcsBinary() const +FilePath GitClient::vcsBinary(const FilePath &forDirectory) const { - bool ok; - Utils::FilePath binary = settings().gitExecutable(&ok); - if (!ok) - return {}; - return binary; + if (forDirectory.needsDevice()) { + auto it = m_gitExecutableCache.find(forDirectory.withNewPath({})); + if (it == m_gitExecutableCache.end()) { + const FilePath gitBin = forDirectory.withNewPath("git").searchInPath(); + it = m_gitExecutableCache.insert(forDirectory.withNewPath({}), + gitBin.isExecutableFile() ? gitBin : FilePath{}); + } + + return it.value(); + } + return settings().gitExecutable().value_or(FilePath{}); } // returns first line from log and removes it @@ -2757,7 +2759,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory, const GitSubmitEditorPanelData &data, CommitType commitType, const QString &amendSHA1, - const QString &messageFile, + const FilePath &messageFile, SubmitFileModel *model) { const QString renameSeparator = " -> "; @@ -2821,7 +2823,7 @@ bool GitClient::addAndCommit(const FilePath &repositoryDirectory, if (commitType == FixupCommit) { arguments << "--fixup" << amendSHA1; } else { - arguments << "-F" << QDir::toNativeSeparators(messageFile); + arguments << "-F" << messageFile.nativePath(); if (commitType == AmendCommit) arguments << "--amend"; const QString &authorString = data.authorString(); @@ -3247,7 +3249,7 @@ void GitClient::vcsExecAbortable(const FilePath &workingDirectory, const QString command->addFlags(RunFlags::ShowStdOut | RunFlags::ShowSuccessMessage); // For rebase, Git might request an editor (which means the process keeps running until the // user closes it), so run without timeout. - command->addJob({vcsBinary(), arguments}, isRebase ? 0 : vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, isRebase ? 0 : vcsTimeoutS()); const QObject *actualContext = context ? context : this; connect(command, &VcsCommand::done, actualContext, [=] { const CommandResult result = CommandResult(*command); @@ -3465,7 +3467,7 @@ QFuture GitClient::gitVersion() const // Do not execute repeatedly if that fails (due to git // not being installed) until settings are changed. - const FilePath newGitBinary = vcsBinary(); + const FilePath newGitBinary = vcsBinary({}); const bool needToRunGit = m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty(); if (needToRunGit) { auto proc = new Process(const_cast(this)); @@ -3480,7 +3482,7 @@ QFuture GitClient::gitVersion() const proc->deleteLater(); }); - proc->setEnvironment(processEnvironment()); + proc->setEnvironment(processEnvironment(newGitBinary)); proc->setCommand({newGitBinary, {"--version"}}); proc->start(); } else { diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 3f8368c62eb..823aae6736d 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -73,8 +73,8 @@ public: UpstreamStatus() = default; UpstreamStatus(int ahead, int behind) : ahead(ahead), behind(behind) {} - int ahead = 0; - int behind = 0; + int ahead = -1; + int behind = -1; }; struct Author { @@ -123,7 +123,7 @@ public: GitClient(); ~GitClient(); - Utils::FilePath vcsBinary() const override; + Utils::FilePath vcsBinary(const Utils::FilePath &forDirectory) const override; QFuture gitVersion() const; void vcsExecAbortable(const Utils::FilePath &workingDirectory, const QStringList &arguments, @@ -295,7 +295,7 @@ public: const GitSubmitEditorPanelData &data, CommitType commitType, const QString &amendSHA1, - const QString &messageFile, + const Utils::FilePath &messageFile, VcsBase::SubmitFileModel *model); enum StatusResult { StatusChanged, StatusUnchanged, StatusFailed }; @@ -318,7 +318,7 @@ public: QStringList synchronousRepositoryBranches(const QString &repositoryURL, const Utils::FilePath &workingDirectory = {}) const; - Utils::Environment processEnvironment() const override; + Utils::Environment processEnvironment(const Utils::FilePath &appliedTo) const override; bool beginStashScope(const Utils::FilePath &workingDirectory, const QString &command, StashFlag flag = Default, PushAction pushAction = NoPush); @@ -395,6 +395,7 @@ private: mutable Utils::FilePath m_gitVersionForBinary; mutable QVersionNumber m_cachedGitVersion; + mutable QMap m_gitExecutableCache; QString m_gitQtcEditor; QMap m_stashInfo; diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index 32d456ca165..ecd966c77c9 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -3,30 +3,20 @@ #pragma once -#include - -namespace Git { -namespace Constants { +namespace Git::Constants { const char GIT_PLUGIN[] = "GitPlugin"; const char GIT_SVN_LOG_EDITOR_ID[] = "Git SVN Log Editor"; -const char GIT_SVN_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git SVN Log Editor"); const char GIT_LOG_EDITOR_ID[] = "Git Log Editor"; -const char GIT_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Log Editor"); const char GIT_REFLOG_EDITOR_ID[] = "Git Reflog Editor"; -const char GIT_REFLOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Reflog Editor"); const char GIT_BLAME_EDITOR_ID[] = "Git Annotation Editor"; -const char GIT_BLAME_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Annotation Editor"); const char GIT_COMMIT_TEXT_EDITOR_ID[] = "Git Commit Editor"; -const char GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Commit Editor"); const char GIT_REBASE_EDITOR_ID[] = "Git Rebase Editor"; -const char GIT_REBASE_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Rebase Editor"); const char GIT_BRANCH_VIEW_ID[] = "Git Branches"; const char GIT_CONTEXT[] = "Git Context"; const char GITSUBMITEDITOR_ID[] = "Git Submit Editor"; -const char GITSUBMITEDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Git Submit Editor"); const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.git.submit"; const char C_GITEDITORID[] = "Git Editor"; @@ -38,5 +28,4 @@ const char DEFAULT_COMMENT_CHAR = '#'; const char TEXT_MARK_CATEGORY_BLAME[] = "Git.Mark.Blame"; -} // namespace Constants -} // namespace Git +} // Git::Constants diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index 2f1f0bda49a..5675fe0f484 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -134,8 +134,8 @@ static void runGitGrep(QPromise &promise, const FileFindParam const GitGrepParameters &gitParameters) { const auto setupProcess = [¶meters, gitParameters](Process &process) { - const FilePath vcsBinary = gitClient().vcsBinary(); - const Environment environment = gitClient().processEnvironment(); + const FilePath vcsBinary = gitClient().vcsBinary(parameters.searchDir); + const Environment environment = gitClient().processEnvironment(vcsBinary); QStringList arguments = { "-c", "color.grep.match=bold red", diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index d72b397f6e0..966abc40b8c 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -132,48 +133,6 @@ public: static const QVersionNumber minimumRequiredVersion{1, 9}; -const VcsBaseEditorParameters svnLogEditorParameters { - OtherContent, - Git::Constants::GIT_SVN_LOG_EDITOR_ID, - Git::Constants::GIT_SVN_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.svnlog" -}; - -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Git::Constants::GIT_LOG_EDITOR_ID, - Git::Constants::GIT_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.log" -}; - -const VcsBaseEditorParameters reflogEditorParameters { - LogOutput, - Git::Constants::GIT_REFLOG_EDITOR_ID, - Git::Constants::GIT_REFLOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.reflog" -}; - -const VcsBaseEditorParameters blameEditorParameters { - AnnotateOutput, - Git::Constants::GIT_BLAME_EDITOR_ID, - Git::Constants::GIT_BLAME_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.annotation" -}; - -const VcsBaseEditorParameters commitTextEditorParameters { - OtherContent, - Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID, - Git::Constants::GIT_COMMIT_TEXT_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.commit" -}; - -const VcsBaseEditorParameters rebaseEditorParameters { - OtherContent, - Git::Constants::GIT_REBASE_EDITOR_ID, - Git::Constants::GIT_REBASE_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.git.rebase" -}; - // GitPlugin class GitPluginPrivate final : public VersionControlBase @@ -322,7 +281,7 @@ public: const Context &context); void updateRepositoryBrowserAction(); - IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd); + IEditor *openSubmitEditor(const FilePath &fileName, const CommitData &cd); void cleanCommitMessageFile(); void cleanRepository(const FilePath &directory); void applyPatch(const FilePath &workingDirectory, QString file = {}); @@ -360,70 +319,69 @@ public: BranchViewFactory m_branchViewFactory; QPointer m_remoteDialog; FilePath m_submitRepository; - QString m_commitMessageFileName; + FilePath m_commitMessageFileName; InstantBlame m_instantBlame; GitGrep gitGrep; - VcsEditorFactory svnLogEditorFactory { - &svnLogEditorParameters, + VcsEditorFactory svnLogEditorFactory {{ + OtherContent, + Git::Constants::GIT_SVN_LOG_EDITOR_ID, + VcsBase::Tr::tr("Git SVN Log Editor"), + "text/vnd.qtcreator.git.svnlog", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Git::Constants::GIT_LOG_EDITOR_ID, + VcsBase::Tr::tr("Git Log Editor"), + "text/vnd.qtcreator.git.log", [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory reflogEditorFactory { - &reflogEditorParameters, - [] { return new GitLogEditorWidgetT; }, + VcsEditorFactory reflogEditorFactory {{ + LogOutput, + Git::Constants::GIT_REFLOG_EDITOR_ID, + VcsBase::Tr::tr("Git Reflog Editor"), + "text/vnd.qtcreator.git.reflog", + [] { return new GitLogEditorWidgetT; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory blameEditorFactory { - &blameEditorParameters, + VcsEditorFactory blameEditorFactory {{ + AnnotateOutput, + Git::Constants::GIT_BLAME_EDITOR_ID, + VcsBase::Tr::tr("Git Annotation Editor"), + "text/vnd.qtcreator.git.annotation", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory commitTextEditorFactory { - &commitTextEditorParameters, + VcsEditorFactory commitTextEditorFactory {{ + OtherContent, + Git::Constants::GIT_COMMIT_TEXT_EDITOR_ID, + VcsBase::Tr::tr("Git Commit Editor"), + "text/vnd.qtcreator.git.commit", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory rebaseEditorFactory { - &rebaseEditorParameters, + VcsEditorFactory rebaseEditorFactory {{ + OtherContent, + Git::Constants::GIT_REBASE_EDITOR_ID, + VcsBase::Tr::tr("Git Rebase Editor"), + "text/vnd.qtcreator.git.rebase", [] { return new GitEditorWidget; }, std::bind(&GitPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static GitPluginPrivate *dd = nullptr; -class GitTopicCache : public IVersionControl::TopicCache -{ -public: - GitTopicCache() {} - -protected: - FilePath trackFile(const FilePath &repository) override - { - const FilePath gitDir = gitClient().findGitDirForRepository(repository); - return gitDir.isEmpty() ? FilePath() : gitDir / "HEAD"; - } - - QString refreshTopic(const FilePath &repository) override - { - emit dd->repositoryChanged(repository); - return gitClient().synchronousTopic(repository); - } -}; - GitPluginPrivate::~GitPluginPrivate() { cleanCommitMessageFile(); @@ -433,11 +391,9 @@ void GitPluginPrivate::onApplySettings() { emit configurationChanged(); updateRepositoryBrowserAction(); - bool gitFoundOk; - QString errorMessage; - settings().gitExecutable(&gitFoundOk, &errorMessage); - if (!gitFoundOk) { - QTimer::singleShot(0, this, [errorMessage] { + const expected_str result = settings().gitExecutable(); + if (!result) { + QTimer::singleShot(0, this, [errorMessage = result.error()] { AsynchronousMessageBox::warning(Tr::tr("Git Settings"), errorMessage); }); } @@ -446,7 +402,7 @@ void GitPluginPrivate::onApplySettings() void GitPluginPrivate::cleanCommitMessageFile() { if (!m_commitMessageFileName.isEmpty()) { - QFile::remove(m_commitMessageFileName); + m_commitMessageFileName.removeFile(); m_commitMessageFileName.clear(); } } @@ -585,7 +541,14 @@ GitPluginPrivate::GitPluginPrivate() { dd = this; - setTopicCache(new GitTopicCache); + setTopicFileTracker([](const FilePath &repository) { + const FilePath gitDir = gitClient().findGitDirForRepository(repository); + return gitDir.isEmpty() ? FilePath() : gitDir / "HEAD"; + }); + setTopicRefresher([this](const FilePath &repository) { + emit repositoryChanged(repository); + return gitClient().synchronousTopic(repository); + }); m_fileActions.reserve(10); m_projectActions.reserve(10); @@ -957,7 +920,7 @@ GitPluginPrivate::GitPluginPrivate() setupVcsSubmitEditor(this, { Git::Constants::SUBMIT_MIMETYPE, Git::Constants::GITSUBMITEDITOR_ID, - Git::Constants::GITSUBMITEDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Git Submit Editor"), VcsBaseSubmitEditorParameters::DiffRows, [] { return new GitSubmitEditor; }, }); @@ -1023,8 +986,12 @@ void GitPluginPrivate::blameFile() const FilePath fileName = state.currentFile().canonicalPath(); FilePath topLevel; VcsManager::findVersionControlForDirectory(fileName.parentDir(), &topLevel); - gitClient().annotate(topLevel, fileName.relativeChildPath(topLevel).toString(), - lineNumber, {}, extraOptions, firstLine); + gitClient().annotate(topLevel, + fileName.relativeChildPath(topLevel).path(), + lineNumber, + {}, + extraOptions, + firstLine); } void GitPluginPrivate::logProject() @@ -1284,7 +1251,9 @@ void GitPluginPrivate::startCommit(CommitType commitType) m_submitRepository = data.panelInfo.repository; // Start new temp file with message template - TempFileSaver saver; + TempFileSaver saver( + data.panelInfo.repository.tmpDir().value_or(data.panelInfo.repository.withNewPath("")) + / "commit-msg.XXXXXX"); // Keep the file alive, else it removes self and forgets its name saver.setAutoRemove(false); saver.write(commitTemplate.toLocal8Bit()); @@ -1292,7 +1261,7 @@ void GitPluginPrivate::startCommit(CommitType commitType) VcsOutputWindow::appendError(saver.errorString()); return; } - m_commitMessageFileName = saver.filePath().toString(); + m_commitMessageFileName = saver.filePath(); openSubmitEditor(m_commitMessageFileName, data); } @@ -1321,10 +1290,9 @@ void GitPluginPrivate::instantBlameOnce() m_instantBlame.once(); } -IEditor *GitPluginPrivate::openSubmitEditor(const QString &fileName, const CommitData &cd) +IEditor *GitPluginPrivate::openSubmitEditor(const FilePath &fileName, const CommitData &cd) { - IEditor *editor = EditorManager::openEditor(FilePath::fromString(fileName), - Constants::GITSUBMITEDITOR_ID); + IEditor *editor = EditorManager::openEditor(fileName, Constants::GITSUBMITEDITOR_ID); auto submitEditor = qobject_cast(editor); QTC_ASSERT(submitEditor, return nullptr); setSubmitEditor(submitEditor); @@ -1357,10 +1325,9 @@ bool GitPluginPrivate::activateCommit() QTC_ASSERT(editorDocument, return true); // Submit editor closing. Make it write out the commit message // and retrieve files - const QFileInfo editorFile = editorDocument->filePath().toFileInfo(); - const QFileInfo changeFile(m_commitMessageFileName); + // Paranoia! - if (editorFile.absoluteFilePath() != changeFile.absoluteFilePath()) + if (!editorDocument->filePath().isSameFile(m_commitMessageFileName)) return true; auto model = qobject_cast(editor->fileModel()); @@ -1737,7 +1704,7 @@ bool GitPluginPrivate::isVcsFileOrDirectory(const FilePath &filePath) const bool GitPluginPrivate::isConfigured() const { - return !gitClient().vcsBinary().isEmpty(); + return !gitClient().vcsBinary({}).isEmpty(); } bool GitPluginPrivate::supportsOperation(Operation operation) const @@ -1802,9 +1769,10 @@ VcsCommand *GitPluginPrivate::createInitialCheckoutCommand(const QString &url, QStringList args = {"clone", "--progress"}; args << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, gitClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + gitClient().processEnvironment(baseDirectory)); command->addFlags(RunFlags::SuppressStdErr); - command->addJob({gitClient().vcsBinary(), args}, -1); + command->addJob({gitClient().vcsBinary(baseDirectory), args}, -1); return command; } diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 43b0e8ae6c7..95938a41d88 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -164,14 +164,8 @@ GitSettings::GitSettings() readSettings(); } -FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const +expected_str GitSettings::gitExecutable() const { - // Locate binary in path if one is specified, otherwise default to pathless binary. - if (ok) - *ok = true; - if (errorMessage) - errorMessage->clear(); - if (tryResolve) { resolvedBinPath = binaryPath(); if (!resolvedBinPath.isAbsolutePath()) @@ -180,11 +174,8 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const } if (resolvedBinPath.isEmpty()) { - if (ok) - *ok = false; - if (errorMessage) - *errorMessage = Tr::tr("The binary \"%1\" could not be located in the path \"%2\"") - .arg(binaryPath().toUserOutput(), path()); + return make_unexpected(Tr::tr("The binary \"%1\" could not be located in the path \"%2\"") + .arg(binaryPath().toUserOutput(), path())); } return resolvedBinPath; } diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index f6ec650c2e8..2932cc78c0a 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -44,7 +44,7 @@ public: mutable Utils::FilePath resolvedBinPath; mutable bool tryResolve = true; - Utils::FilePath gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const; + Utils::expected_str gitExecutable() const; static QString trIgnoreWhitespaceChanges(); static QString trIgnoreLineMoves(); diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index 8829c445180..d0a102c9df4 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -37,7 +37,7 @@ void MergeTool::start(const FilePath &workingDirectory, const QStringList &files { QStringList arguments; arguments << "mergetool" << "-y" << files; - const CommandLine cmd = {gitClient().vcsBinary(), arguments}; + const CommandLine cmd = {gitClient().vcsBinary(workingDirectory), arguments}; VcsOutputWindow::appendCommand(workingDirectory, cmd); m_process.setCommand(cmd); m_process.setWorkingDirectory(workingDirectory); diff --git a/src/plugins/mcusupport/mcukitaspect.cpp b/src/plugins/mcusupport/mcukitaspect.cpp index f53dcacfd04..8d497f209dd 100644 --- a/src/plugins/mcusupport/mcukitaspect.cpp +++ b/src/plugins/mcusupport/mcukitaspect.cpp @@ -32,19 +32,19 @@ Utils::Id McuDependenciesKitAspect::id() return "PE.Profile.McuCMakeDependencies"; } -Utils::NameValueItems McuDependenciesKitAspect::dependencies(const Kit *kit) +Utils::EnvironmentItems McuDependenciesKitAspect::dependencies(const Kit *kit) { if (kit) - return Utils::NameValueItem::fromStringList( + return Utils::EnvironmentItem::fromStringList( kit->value(McuDependenciesKitAspect::id()).toStringList()); - return Utils::NameValueItems(); + return Utils::EnvironmentItems(); } -void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::NameValueItems &dependencies) +void McuDependenciesKitAspect::setDependencies(Kit *k, const Utils::EnvironmentItems &dependencies) { if (k) k->setValue(McuDependenciesKitAspect::id(), - Utils::NameValueItem::toStringList(dependencies)); + Utils::EnvironmentItem::toStringList(dependencies)); } Utils::NameValuePairs McuDependenciesKitAspect::configuration(const Kit *kit) @@ -108,7 +108,7 @@ public: if (!variant.isNull() && !variant.canConvert(QVariant::List)) { qWarning("Kit \"%s\" has a wrong mcu dependencies value set.", qPrintable(kit->displayName())); - McuDependenciesKitAspect::setDependencies(kit, Utils::NameValueItems()); + McuDependenciesKitAspect::setDependencies(kit, Utils::EnvironmentItems()); } } diff --git a/src/plugins/mcusupport/mcukitaspect.h b/src/plugins/mcusupport/mcukitaspect.h index a86841a72aa..46256213488 100644 --- a/src/plugins/mcusupport/mcukitaspect.h +++ b/src/plugins/mcusupport/mcukitaspect.h @@ -11,8 +11,8 @@ class McuDependenciesKitAspect final { public: static Utils::Id id(); - static Utils::NameValueItems dependencies(const ProjectExplorer::Kit *kit); - static void setDependencies(ProjectExplorer::Kit *kit, const Utils::NameValueItems &dependencies); + static Utils::EnvironmentItems dependencies(const ProjectExplorer::Kit *kit); + static void setDependencies(ProjectExplorer::Kit *kit, const Utils::EnvironmentItems &dependencies); static Utils::NameValuePairs configuration(const ProjectExplorer::Kit *kit); }; diff --git a/src/plugins/mcusupport/mcukitmanager.cpp b/src/plugins/mcusupport/mcukitmanager.cpp index 456bdbdcdfc..08c9c8abb09 100644 --- a/src/plugins/mcusupport/mcukitmanager.cpp +++ b/src/plugins/mcusupport/mcukitmanager.cpp @@ -180,7 +180,7 @@ public: const McuTarget *mcuTarget, const McuPackagePtr &qtForMCUsSdkPackage) { - NameValueItems dependencies; + EnvironmentItems dependencies; auto processPackage = [&dependencies](const McuPackagePtr &package) { const auto cmakeVariableName = package->cmakeVariableName(); diff --git a/src/plugins/mercurial/constants.h b/src/plugins/mercurial/constants.h index e38871e4aa7..ee2738dbcac 100644 --- a/src/plugins/mercurial/constants.h +++ b/src/plugins/mercurial/constants.h @@ -3,8 +3,6 @@ #pragma once -#include - namespace Mercurial::Constants { enum { debug = 0 }; @@ -23,20 +21,16 @@ const char DIFFIDENTIFIER[] = "^(?:diff --git a/|[+-]{3} (?:/dev/null|[ab]/(.+$) // Base editor parameters const char FILELOG_ID[] = "Mercurial File Log Editor"; -const char FILELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial File Log Editor"); const char LOGAPP[] = "text/vnd.qtcreator.mercurial.log"; const char ANNOTATELOG_ID[] = "Mercurial Annotation Editor"; -const char ANNOTATELOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Annotation Editor"); const char ANNOTATEAPP[] = "text/vnd.qtcreator.mercurial.annotation"; const char DIFFLOG_ID[] = "Mercurial Diff Editor"; -const char DIFFLOG_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Diff Editor"); const char DIFFAPP[] = "text/x-patch"; // Submit editor parameters const char COMMIT_ID[] = "Mercurial Commit Log Editor"; -const char COMMIT_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Mercurial Commit Log Editor"); const char COMMITMIMETYPE[] = "text/vnd.qtcreator.mercurial.commit"; // File menu actions diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 81228964229..fd568c9741f 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -273,7 +273,7 @@ void MercurialClient::incoming(const FilePath &repositoryRoot, const QString &re VcsBaseEditorWidget *editor = createVcsEditor(Constants::DIFFLOG_ID, title, repositoryRoot, VcsBaseEditor::getCodec(repositoryRoot), "incoming", id); - enqueueJob(createCommand(FilePath::fromString(repository), editor), args); + enqueueJob(createCommand(FilePath::fromString(repository), editor), args, repositoryRoot); } void MercurialClient::outgoing(const FilePath &repositoryRoot) @@ -286,7 +286,7 @@ void MercurialClient::outgoing(const FilePath &repositoryRoot) VcsBaseEditorWidget *editor = createVcsEditor(Constants::DIFFLOG_ID, title, repositoryRoot, VcsBaseEditor::getCodec(repositoryRoot), "outgoing", repositoryRoot.toString()); - enqueueJob(createCommand(repositoryRoot, editor), args); + enqueueJob(createCommand(repositoryRoot, editor), args, repositoryRoot); } void MercurialClient::annotate(const Utils::FilePath &workingDir, const QString &file, @@ -424,7 +424,6 @@ void MercurialClient::requestReload(const QString &documentId, const FilePath &s QTC_ASSERT(document, return); auto controller = new MercurialDiffEditorController(document, args); controller->setVcsBinary(settings().binaryPath()); - controller->setProcessEnvironment(processEnvironment()); controller->setWorkingDirectory(workingDirectory); VcsBase::setSource(document, sourceCopy); diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp index 081a7a5e41c..76c8f2ba8c8 100644 --- a/src/plugins/mercurial/mercurialplugin.cpp +++ b/src/plugins/mercurial/mercurialplugin.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -50,44 +51,6 @@ using namespace std::placeholders; namespace Mercurial::Internal { -class MercurialTopicCache : public Core::IVersionControl::TopicCache -{ -public: - MercurialTopicCache() = default; - -protected: - FilePath trackFile(const FilePath &repository) override - { - return repository.pathAppended(".hg/branch"); - } - - QString refreshTopic(const FilePath &repository) override - { - return mercurialClient().branchQuerySync(repository.toString()); - } -}; - -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Constants::FILELOG_ID, - Constants::FILELOG_DISPLAY_NAME, - Constants::LOGAPP -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - Constants::ANNOTATELOG_ID, - Constants::ANNOTATELOG_DISPLAY_NAME, - Constants::ANNOTATEAPP -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - Constants::DIFFLOG_ID, - Constants::DIFFLOG_DISPLAY_NAME, - Constants::DIFFAPP -}; - class MercurialPluginPrivate final : public VcsBase::VersionControlBase { public: @@ -180,23 +143,32 @@ private: FilePath m_submitRepository; public: - VcsEditorFactory logEditorFactory { - &logEditorParameters, - [this] { return new MercurialEditorWidget; }, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Constants::FILELOG_ID, + VcsBase::Tr::tr("Mercurial File Log Editor"), + Constants::LOGAPP, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, - [this] { return new MercurialEditorWidget; }, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + Constants::ANNOTATELOG_ID, + VcsBase::Tr::tr("Mercurial Annotation Editor"), + Constants::ANNOTATEAPP, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, - [this] { return new MercurialEditorWidget; }, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + Constants::DIFFLOG_ID, + VcsBase::Tr::tr("Mercurial Diff Editor"), + Constants::DIFFAPP, + [] { return new MercurialEditorWidget; }, std::bind(&MercurialPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static MercurialPluginPrivate *dd = nullptr; @@ -209,12 +181,17 @@ MercurialPluginPrivate::MercurialPluginPrivate() setupVcsSubmitEditor(this, { Constants::COMMITMIMETYPE, Constants::COMMIT_ID, - Constants::COMMIT_DISPLAY_NAME, + VcsBase::Tr::tr("Mercurial Commit Log Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new CommitEditor; } }); - setTopicCache(new MercurialTopicCache); + setTopicFileTracker([](const FilePath &repository) { + return repository.pathAppended(".hg/branch"); + }); + setTopicRefresher([](const FilePath &repository) { + return mercurialClient().branchQuerySync(repository.toString()); + }); Core::Context context(Constants::MERCURIAL_CONTEXT); @@ -759,7 +736,9 @@ VcsCommand *MercurialPluginPrivate::createInitialCheckoutCommand(const QString & { QStringList args; args << QLatin1String("clone") << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, mercurialClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + mercurialClient().processEnvironment( + baseDirectory)); command->addJob({settings().binaryPath(), args}, -1); return command; } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 23d6071d7d5..42e2bbfcb18 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -62,16 +63,9 @@ const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.p4.submit"; const char PERFORCE_CONTEXT[] = "Perforce Context"; const char PERFORCE_SUBMIT_EDITOR_ID[] = "Perforce.SubmitEditor"; -const char PERFORCE_SUBMIT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce.SubmitEditor"); - const char PERFORCE_LOG_EDITOR_ID[] = "Perforce.LogEditor"; -const char PERFORCE_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Log Editor"); - const char PERFORCE_DIFF_EDITOR_ID[] = "Perforce.DiffEditor"; -const char PERFORCE_DIFF_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Diff Editor"); - const char PERFORCE_ANNOTATION_EDITOR_ID[] = "Perforce.AnnotationEditor"; -const char PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Perforce Annotation Editor"); // Ensure adding "..." to relative paths which is p4's convention // for the current directory @@ -128,27 +122,6 @@ struct PerforceResponse QString stdErr; }; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - PERFORCE_LOG_EDITOR_ID, - PERFORCE_LOG_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.p4.log" -}; - -const VcsBaseEditorParameters annotateEditorParameters { - AnnotateOutput, - PERFORCE_ANNOTATION_EDITOR_ID, - PERFORCE_ANNOTATION_EDITOR_DISPLAY_NAME, - "text/vnd.qtcreator.p4.annotation" -}; - -const VcsBaseEditorParameters diffEditorParameters { - DiffOutput, - PERFORCE_DIFF_EDITOR_ID, - PERFORCE_DIFF_EDITOR_DISPLAY_NAME, - "text/x-patch" -}; - // Flags for runP4Cmd. enum RunFlags { @@ -324,23 +297,32 @@ public: ManagedDirectoryCache m_managedDirectoryCache; - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + PERFORCE_LOG_EDITOR_ID, + VcsBase::Tr::tr("Perforce Log Editor"), + "text/vnd.qtcreator.p4.log", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory annotateEditorFactory { - &annotateEditorParameters, + VcsEditorFactory annotateEditorFactory {{ + AnnotateOutput, + PERFORCE_ANNOTATION_EDITOR_ID, + VcsBase::Tr::tr("Perforce Annotation Editor"), + "text/vnd.qtcreator.p4.annotation", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory diffEditorFactory { - &diffEditorParameters, + VcsEditorFactory diffEditorFactory {{ + DiffOutput, + PERFORCE_DIFF_EDITOR_ID, + VcsBase::Tr::tr("Perforce Diff Editor"), + "text/x-patch", [] { return new PerforceEditorWidget; }, std::bind(&PerforcePluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; static PerforcePluginPrivate *dd = nullptr; @@ -355,7 +337,7 @@ PerforcePluginPrivate::PerforcePluginPrivate() setupVcsSubmitEditor(this, { SUBMIT_MIMETYPE, PERFORCE_SUBMIT_EDITOR_ID, - PERFORCE_SUBMIT_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Perforce.SubmitEditor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new PerforceSubmitEditor; }, }); @@ -827,7 +809,7 @@ void PerforcePluginPrivate::annotate(const FilePath &workingDir, if (lineNumber < 1) lineNumber = VcsBaseEditor::lineNumberOfCurrentEditor(); IEditor *ed = showOutputInEditor(Tr::tr("p4 annotate %1").arg(id), - result.stdOut, annotateEditorParameters.id, + result.stdOut, PERFORCE_ANNOTATION_EDITOR_ID, source, codec); VcsBaseEditor::gotoLineOfEditor(ed, lineNumber); } @@ -878,7 +860,7 @@ void PerforcePluginPrivate::filelog(const FilePath &workingDir, const QString &f if (!result.error) { const FilePath source = VcsBaseEditor::getSource(workingDir, fileName); IEditor *editor = showOutputInEditor(Tr::tr("p4 filelog %1").arg(id), result.stdOut, - logEditorParameters.id, source, codec); + PERFORCE_LOG_EDITOR_ID, source, codec); if (enableAnnotationContextMenu) VcsBaseEditor::getVcsBaseEditor(editor)->setFileLogAnnotateEnabled(true); } @@ -900,7 +882,7 @@ void PerforcePluginPrivate::changelists(const FilePath &workingDir, const QStrin if (!result.error) { const FilePath source = VcsBaseEditor::getSource(workingDir, fileName); IEditor *editor = showOutputInEditor(Tr::tr("p4 changelists %1").arg(id), result.stdOut, - logEditorParameters.id, source, codec); + PERFORCE_LOG_EDITOR_ID, source, codec); VcsBaseEditor::gotoLineOfEditor(editor, 1); } } @@ -1376,7 +1358,7 @@ void PerforcePluginPrivate::p4Diff(const PerforceDiffParameters &p) } // Create new editor IEditor *editor = showOutputInEditor(Tr::tr("p4 diff %1").arg(id), result.stdOut, - diffEditorParameters.id, + PERFORCE_DIFF_EDITOR_ID, VcsBaseEditor::getSource(p.workingDir, p.files), codec); VcsBaseEditor::tagEditor(editor, tag); @@ -1400,7 +1382,7 @@ void PerforcePluginPrivate::vcsDescribe(const FilePath &source, const QString &n const PerforceResponse result = runP4Cmd(settings().topLevel(), args, CommandToWindow|StdErrToWindow|ErrorToWindow, {}, {}, codec); if (!result.error) - showOutputInEditor(Tr::tr("p4 describe %1").arg(n), result.stdOut, diffEditorParameters.id, source, codec); + showOutputInEditor(Tr::tr("p4 describe %1").arg(n), result.stdOut, PERFORCE_DIFF_EDITOR_ID, source, codec); } void PerforcePluginPrivate::cleanCommitMessageFile() diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp index 3d2e86d445f..a7405ef46e2 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp @@ -312,6 +312,9 @@ void DeviceSettingsWidget::testDevice() dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setModal(true); dlg->show(); + connect(dlg, &QObject::destroyed, this, [this, id = device->id()] { + handleDeviceUpdated(id); + }); } void DeviceSettingsWidget::handleDeviceUpdated(Id id) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 9a79347da13..0fcdae1c918 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -593,7 +593,7 @@ QString IDevice::deviceStateToString() const QPixmap IDevice::deviceStateIcon() const { - switch (d->deviceState) { + switch (deviceState()) { case IDevice::DeviceReadyToUse: return Icons::DEVICE_READY_INDICATOR.pixmap(); case IDevice::DeviceConnected: return Icons::DEVICE_CONNECTED_INDICATOR.pixmap(); case IDevice::DeviceDisconnected: return Icons::DEVICE_DISCONNECTED_INDICATOR.pixmap(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index c494387de46..6434b5b6dde 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -105,7 +105,7 @@ public: virtual ~IDevice(); - Ptr clone() const; + virtual Ptr clone() const; DeviceSettings *settings() const; @@ -154,9 +154,9 @@ public: virtual DeviceProcessSignalOperation::Ptr signalOperation() const; enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown }; - DeviceState deviceState() const; + virtual DeviceState deviceState() const; void setDeviceState(const DeviceState state); - QString deviceStateToString() const; + virtual QString deviceStateToString() const; QPixmap deviceStateIcon() const; static Utils::Id typeFromMap(const Utils::Store &map); diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 9a63d789ece..a34f8bc256e 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -481,25 +481,25 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked() d->m_editor.setEnvironmentItems(d->m_model->userChanges()); } -void EnvironmentWidget::amendPathList(Utils::NameValueItem::Operation op) +void EnvironmentWidget::amendPathList(Utils::EnvironmentItem::Operation op) { const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex()); const FilePath dir = FileUtils::getExistingDirectory(this, Tr::tr("Choose Directory")); if (dir.isEmpty()) return; - Utils::NameValueItems changes = d->m_model->userChanges(); + Utils::EnvironmentItems changes = d->m_model->userChanges(); changes.append({varName, dir.toUserOutput(), op}); setUserChanges(changes); } void EnvironmentWidget::appendPathButtonClicked() { - amendPathList(Utils::NameValueItem::Append); + amendPathList(Utils::EnvironmentItem::Append); } void EnvironmentWidget::prependPathButtonClicked() { - amendPathList(Utils::NameValueItem::Prepend); + amendPathList(Utils::EnvironmentItem::Prepend); } void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤t) diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h index a00e45bcda7..b1a26b036b3 100644 --- a/src/plugins/projectexplorer/environmentwidget.h +++ b/src/plugins/projectexplorer/environmentwidget.h @@ -57,7 +57,7 @@ private: void linkActivated(const QString &link); using PathListModifier = std::function; - void amendPathList(Utils::NameValueItem::Operation op); + void amendPathList(Utils::EnvironmentItem::Operation op); class Private; const std::unique_ptr d; diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 82e4c5b1813..bbf2b8be1dd 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -746,14 +746,10 @@ MiniProjectTargetSelector::MiniProjectTargetSelector(QAction *targetSelectorActi bool MiniProjectTargetSelector::event(QEvent *event) { - if (event->type() == QEvent::LayoutRequest) { - doLayout(true); + if (event->type() == QEvent::ShortcutOverride + && static_cast(event)->key() == Qt::Key_Escape) { + event->accept(); return true; - } else if (event->type() == QEvent::ShortcutOverride) { - if (static_cast(event)->key() == Qt::Key_Escape) { - event->accept(); - return true; - } } return QWidget::event(event); } @@ -856,7 +852,7 @@ QVector MiniProjectTargetSelector::listWidgetWidths(int minSize, int maxSiz } } -void MiniProjectTargetSelector::doLayout(bool keepSize) +void MiniProjectTargetSelector::doLayout() { // An unconfigured project shows empty build/deploy/run sections // if there's a configured project in the seesion @@ -867,15 +863,12 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) m_kitAreaWidget->move(0, 0); - int oldSummaryLabelY = m_summaryLabel->y(); - int kitAreaHeight = m_kitAreaWidget->isVisibleTo(this) ? m_kitAreaWidget->sizeHint().height() : 0; // 1. Calculate the summary label height int summaryLabelY = 1 + kitAreaHeight; int summaryLabelHeight = 0; - int oldSummaryLabelHeight = m_summaryLabel->height(); bool onlySummary = false; // Count the number of lines int visibleLineCount = m_projectListWidget->isVisibleTo(this) ? 0 : 1; @@ -894,9 +887,6 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) summaryLabelHeight = m_summaryLabel->sizeHint().height(); } - if (keepSize && oldSummaryLabelHeight > summaryLabelHeight) - summaryLabelHeight = oldSummaryLabelHeight; - m_summaryLabel->move(0, summaryLabelY); // Height to be aligned with side bar button @@ -915,16 +905,13 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) maxItemCount = qMax(maxItemCount, m_listWidgets[i]->maxCount()); int titleWidgetsHeight = m_titleWidgets.first()->height(); - if (keepSize) { - heightWithoutKitArea = height() - oldSummaryLabelY + 1; - } else { - // Clamp the size of the listwidgets to be at least as high as the sidebar button - // and at most half the height of the entire Qt Creator window. - heightWithoutKitArea = summaryLabelHeight - + qBound(alignedWithActionHeight, - maxItemCount * 30 + bottomMargin + titleWidgetsHeight, - Core::ICore::mainWindow()->height() / 2); - } + + // Clamp the size of the listwidgets to be at least as high as the sidebar button + // and at most half the height of the entire Qt Creator window. + heightWithoutKitArea = summaryLabelHeight + + qBound(alignedWithActionHeight, + maxItemCount * 30 + bottomMargin + titleWidgetsHeight, + Core::ICore::mainWindow()->height() / 2); int titleY = summaryLabelY + summaryLabelHeight; int listY = titleY + titleWidgetsHeight; @@ -933,15 +920,6 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) // list widget widths int minWidth = qMax(m_summaryLabel->sizeHint().width(), 250); minWidth = qMax(minWidth, m_kitAreaWidget->sizeHint().width()); - if (keepSize) { - // Do not make the widget smaller then it was before - int oldTotalListWidgetWidth = m_projectListWidget->isVisibleTo(this) ? - m_projectListWidget->width() : 0; - for (int i = TARGET; i < LAST; ++i) - oldTotalListWidgetWidth += m_listWidgets[i]->width(); - minWidth = qMax(minWidth, oldTotalListWidgetWidth); - } - QVector widths = listWidgetWidths(minWidth, Core::ICore::mainWindow()->width() * 0.9); const int runColumnWidth = widths[RUN] == -1 ? 0 : RunColumnWidth; @@ -969,10 +947,7 @@ void MiniProjectTargetSelector::doLayout(bool keepSize) m_kitAreaWidget->resize(x - 1, kitAreaHeight); newGeometry.setSize({x, heightWithoutKitArea + kitAreaHeight}); } else { - if (keepSize) - heightWithoutKitArea = height() - oldSummaryLabelY + 1; - else - heightWithoutKitArea = qMax(summaryLabelHeight + bottomMargin, alignedWithActionHeight); + heightWithoutKitArea = qMax(summaryLabelHeight + bottomMargin, alignedWithActionHeight); m_summaryLabel->resize(m_summaryLabel->sizeHint().width(), heightWithoutKitArea - bottomMargin); m_kitAreaWidget->resize(m_kitAreaWidget->sizeHint()); newGeometry.setSize({m_summaryLabel->width() + 1, heightWithoutKitArea + kitAreaHeight}); @@ -1359,7 +1334,7 @@ void MiniProjectTargetSelector::activeRunConfigurationChanged(RunConfiguration * void MiniProjectTargetSelector::setVisible(bool visible) { - doLayout(false); + doLayout(); QWidget::setVisible(visible); m_projectAction->setChecked(visible); if (visible) { @@ -1554,7 +1529,7 @@ void MiniProjectTargetSelector::updateSummary() } if (summary != m_summaryLabel->text()) { m_summaryLabel->setText(summary); - doLayout(false); + doLayout(); } } diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.h b/src/plugins/projectexplorer/miniprojecttargetselector.h index e28828ef4a5..81f98c4a451 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.h +++ b/src/plugins/projectexplorer/miniprojecttargetselector.h @@ -74,7 +74,7 @@ private: void paintEvent(QPaintEvent *) override; void mousePressEvent(QMouseEvent *) override; - void doLayout(bool keepSize); + void doLayout(); QVector listWidgetWidths(int minSize, int maxSize); QWidget *createTitleLabel(const QString &text); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index cd46c2a521c..7f2eee43db7 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -1063,13 +1063,13 @@ void Project::setNamedSettings(const Key &name, const QVariant &value) void Project::setAdditionalEnvironment(const EnvironmentItems &envItems) { - setNamedSettings(PROJECT_ENV_KEY, NameValueItem::toStringList(envItems)); + setNamedSettings(PROJECT_ENV_KEY, EnvironmentItem::toStringList(envItems)); emit environmentChanged(); } EnvironmentItems Project::additionalEnvironment() const { - return NameValueItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); + return EnvironmentItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); } bool Project::needsConfiguration() const diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index e8aa205abdc..4a9d1ef8aae 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1897,10 +1897,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er &ProjectWelcomePage::requestProject, m_instance, &ProjectExplorerPlugin::openProjectWelcomePage); - connect(SessionManager::instance(), - &SessionManager::startupSessionRestored, - m_instance, - &ProjectExplorerPlugin::finishedInitialization); dd->updateWelcomePage(); MacroExpander *expander = Utils::globalMacroExpander(); diff --git a/src/plugins/projectexplorer/projectexplorer.h b/src/plugins/projectexplorer/projectexplorer.h index eb33841dd9a..ffb5d1bcd3c 100644 --- a/src/plugins/projectexplorer/projectexplorer.h +++ b/src/plugins/projectexplorer/projectexplorer.h @@ -24,8 +24,6 @@ namespace Core { class OutputWindow; } // Core -namespace Utils { class CommandLine; } - namespace ProjectExplorer { class CustomParserSettings; class FolderNode; @@ -170,8 +168,6 @@ public: static Core::OutputWindow *buildSystemOutput(); signals: - void finishedInitialization(); - // Is emitted when a project has been added/removed, // or the file list of a specific project has changed. void fileListChanged(); diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 3e5ee74e730..feab87da1ba 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -89,6 +89,7 @@ QtcPlugin { "makestep.cpp", "makestep.h", "miniprojecttargetselector.cpp", "miniprojecttargetselector.h", "msvcparser.cpp", "msvcparser.h", + "msvctoolchain.cpp", "msvctoolchain.h", "namedwidget.cpp", "namedwidget.h", "osparser.cpp", "osparser.h", "panelswidget.cpp", "panelswidget.h", @@ -230,15 +231,6 @@ QtcPlugin { files: ["*.png"] } - Group { - name: "WindowsToolChains" - condition: qbs.targetOS.contains("windows") || qtc.withPluginTests - files: [ - "msvctoolchain.cpp", - "msvctoolchain.h", - ] - } - QtcTestFiles { files: ["outputparser_test.h", "outputparser_test.cpp"] } diff --git a/src/plugins/projectexplorer/projectimporter.h b/src/plugins/projectexplorer/projectimporter.h index 3e67f09c06d..6946054ca9e 100644 --- a/src/plugins/projectexplorer/projectimporter.h +++ b/src/plugins/projectexplorer/projectimporter.h @@ -36,6 +36,7 @@ public: virtual const QList import(const Utils::FilePath &importPath, bool silent = false); virtual Utils::FilePaths importCandidates() = 0; virtual Target *preferredTarget(const QList &possibleTargets); + virtual bool filter(Kit *) const { return true; } bool isUpdating() const { return m_isUpdating; } diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 11d27bf441b..45524bdb169 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -583,11 +583,9 @@ public: manageSessionsButton->setOnClicked([] { SessionManager::showSessionManager(); }); auto sessionsLabel = new QLabel(this); - sessionsLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); sessionsLabel->setText(Tr::tr("Sessions")); auto recentProjectsLabel = new QLabel(this); - recentProjectsLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); recentProjectsLabel->setText(Tr::tr("Projects")); auto sessionsList = new TreeView(this, "Sessions"); diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index 5e67d291323..72e77fd6644 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -304,6 +304,8 @@ void TargetSetupPagePrivate::setupWidgets(const QString &filterText) for (Kit *k : KitManager::sortedKits()) { if (!filterText.isEmpty() && !k->displayName().contains(filterText, Qt::CaseInsensitive)) continue; + if (m_importer && !m_importer->filter(k)) + continue; const auto widget = new TargetSetupWidget(k, m_projectPath); connect(widget, &TargetSetupWidget::selectedToggled, this, &TargetSetupPagePrivate::kitSelectionChanged); @@ -570,7 +572,6 @@ void TargetSetupPagePrivate::doInitializePage() setupImports(); selectAtLeastOneEnabledKit(); - updateVisibility(); } diff --git a/src/plugins/qbsprojectmanager/qbseditor.cpp b/src/plugins/qbsprojectmanager/qbseditor.cpp index 7eed6977a2c..08f6e0a8725 100644 --- a/src/plugins/qbsprojectmanager/qbseditor.cpp +++ b/src/plugins/qbsprojectmanager/qbseditor.cpp @@ -6,13 +6,23 @@ #include "qbslanguageclient.h" #include "qbsprojectmanagertr.h" +#include #include +#include +#include +#include +#include +#include #include #include +#include +#include + using namespace LanguageClient; using namespace QmlJSEditor; +using namespace TextEditor; using namespace Utils; namespace QbsProjectManager::Internal { @@ -26,11 +36,79 @@ private: bool inNextSplit = false) override; }; +class QbsCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor +{ +public: + QbsCompletionAssistProcessor(Client *client); + +private: + QList generateCompletionItems( + const QList &items) const override; +}; + +class MergedCompletionAssistProcessor : public IAssistProcessor +{ +public: + MergedCompletionAssistProcessor(const AssistInterface *interface) : m_interface(interface) {} + ~MergedCompletionAssistProcessor(); + +private: + IAssistProposal *perform() override; + bool running() override { return m_started && (!m_qmlProposal || !m_qbsProposal); } + void checkFinished(); + + const AssistInterface * const m_interface; + std::unique_ptr m_qmlProcessor; + std::unique_ptr m_qbsProcessor; + std::optional m_qmlProposal; + std::optional m_qbsProposal; + bool m_started = false; +}; + +class QbsCompletionAssistProvider : public QmlJSCompletionAssistProvider +{ +private: + IAssistProcessor *createProcessor(const AssistInterface *interface) const override + { + return new MergedCompletionAssistProcessor(interface); + } +}; + +class QbsCompletionItem : public LanguageClientCompletionItem +{ +public: + using LanguageClientCompletionItem::LanguageClientCompletionItem; + +private: + QIcon icon() const override; +}; + +class MergedProposalModel : public GenericProposalModel +{ +public: + MergedProposalModel(const QList &sourceModels); +}; + +static Client *clientForDocument(const TextDocument *doc) +{ + if (!doc) + return nullptr; + const QList &candidates = LanguageClientManager::clientsSupportingDocument(doc); + for (Client * const candidate : candidates) { + if (const auto qbsClient = qobject_cast(candidate); + qbsClient && qbsClient->isActive() && qbsClient->documentOpen(doc)) { + return qbsClient; + } + } + return nullptr; +} + QbsEditorFactory::QbsEditorFactory() : QmlJSEditorFactory("QbsEditor.QbsEditor") { setDisplayName(Tr::tr("Qbs Editor")); setMimeTypes({Utils::Constants::QBS_MIMETYPE}); setEditorWidgetCreator([] { return new QbsEditorWidget; }); + setCompletionAssistProvider(new QbsCompletionAssistProvider); } void QbsEditorWidget::findLinkAt(const QTextCursor &cursor, const LinkHandler &processLinkCallback, @@ -43,18 +121,103 @@ void QbsEditorWidget::findLinkAt(const QTextCursor &cursor, const LinkHandler &p if (!self) return; const auto doc = self->textDocument(); - if (!doc) - return; - const QList &candidates = LanguageClientManager::clientsSupportingDocument(doc); - for (Client * const candidate : candidates) { - const auto qbsClient = qobject_cast(candidate); - if (!qbsClient || !qbsClient->isActive() || !qbsClient->documentOpen(doc)) - continue; - qbsClient->findLinkAt(doc, cursor, processLinkCallback, resolveTarget, + if (Client * const client = clientForDocument(doc)) { + client->findLinkAt(doc, cursor, processLinkCallback, resolveTarget, LinkTarget::SymbolDef); } }; QmlJSEditorWidget::findLinkAt(cursor, extendedCallback, resolveTarget, inNextSplit); } +MergedCompletionAssistProcessor::~MergedCompletionAssistProcessor() +{ + if (m_qmlProposal) + delete *m_qmlProposal; + if (m_qbsProposal) + delete *m_qbsProposal; +} + +IAssistProposal *MergedCompletionAssistProcessor::perform() +{ + m_started = true; + if (Client *const qbsClient = clientForDocument( + TextDocument::textDocumentForFilePath(m_interface->filePath()))) { + m_qbsProcessor.reset(new QbsCompletionAssistProcessor(qbsClient)); + m_qbsProcessor->setAsyncCompletionAvailableHandler([this](IAssistProposal *proposal) { + m_qbsProposal = proposal; + checkFinished(); + }); + m_qbsProcessor->start(std::make_unique(m_interface->cursor(), + m_interface->filePath(), + ExplicitlyInvoked)); + } else { + m_qbsProposal = nullptr; + } + m_qmlProcessor.reset(QmlJSCompletionAssistProvider().createProcessor(m_interface)); + m_qmlProcessor->setAsyncCompletionAvailableHandler([this](IAssistProposal *proposal) { + m_qmlProposal = proposal; + checkFinished(); + }); + const auto qmlJsIface = static_cast(m_interface); + return m_qmlProcessor->start( + std::make_unique(qmlJsIface->cursor(), + qmlJsIface->filePath(), + ExplicitlyInvoked, + qmlJsIface->semanticInfo())); +} + +void MergedCompletionAssistProcessor::checkFinished() +{ + if (running()) + return; + + QList sourceModels; + int basePosition = -1; + for (const IAssistProposal * const proposal : {*m_qmlProposal, *m_qbsProposal}) { + if (proposal) { + if (const auto model = proposal->model().dynamicCast()) + sourceModels << model; + if (basePosition == -1) + basePosition = proposal->basePosition(); + else + QTC_CHECK(basePosition == proposal->basePosition()); + } + } + setAsyncProposalAvailable( + new GenericProposal(basePosition >= 0 ? basePosition : m_interface->position(), + GenericProposalModelPtr(new MergedProposalModel(sourceModels)))); +} + +MergedProposalModel::MergedProposalModel(const QList &sourceModels) +{ + QList items; + for (const GenericProposalModelPtr &model : sourceModels) { + items << model->originalItems(); + model->loadContent({}); + } + loadContent(items); +} + +QbsCompletionAssistProcessor::QbsCompletionAssistProcessor(Client *client) + : LanguageClientCompletionAssistProcessor(client, nullptr, {}) +{} + +QList QbsCompletionAssistProcessor::generateCompletionItems( + const QList &items) const +{ + return Utils::transform>( + items, [](const LanguageServerProtocol::CompletionItem &item) { + return new QbsCompletionItem(item); + }); +} + +QIcon QbsCompletionItem::icon() const +{ + if (!item().detail()) { + return ProjectExplorer::DirectoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_MODULES).icon(); + } + return CodeModelIcon::iconForType(CodeModelIcon::Property); +} + } // namespace QbsProjectManager::Internal diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index c8265d73544..36d0e657cf5 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -281,6 +282,8 @@ void ModelManager::delayedInitialization() this, &ModelManager::removeProjectInfo); connect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, &ModelManager::updateDefaultProjectInfo); + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, + this, &ModelManager::cancelAllThreads); ViewerContext qbsVContext; qbsVContext.language = Dialect::QmlQbs; diff --git a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp index 524150db41b..50d8596ae36 100644 --- a/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp +++ b/src/plugins/qmlprojectmanager/cmakegen/generatecmakelists.cpp @@ -286,7 +286,7 @@ const QString projectEnvironmentVariable(const QString &key) if (auto buildSystem = getBuildSystem()) { auto envItems = buildSystem->environment(); - auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](NameValueItem &item) { + auto confEnv = std::find_if(envItems.begin(), envItems.end(), [key](EnvironmentItem &item) { return item.name == key; }); if (confEnv != envItems.end()) diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp index 2a5e20fa48b..77bddffb055 100644 --- a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -90,9 +90,10 @@ public: return !tis.isEmpty(); } - virtual bool filterTarget(const TargetInformation &ti) const + virtual bool filterTarget(Target *target, const TargetInformation &ti) const { - return !ti.manifest.supportsDebugging(); + return !ti.manifest.supportsDebugging() || + DeviceKitAspect::device(target->kit())->osType() != OsType::OsTypeLinux; } QList availableCreators(Target *target) const @@ -102,8 +103,8 @@ public: Qt::UniqueConnection); const auto buildTargets = TargetInformation::readFromProject(target); - const auto filteredTargets = Utils::filtered(buildTargets, [this](const TargetInformation &ti){ - return filterTarget(ti); + const auto filteredTargets = Utils::filtered(buildTargets, [this, target](const TargetInformation &ti) { + return filterTarget(target, ti); }); auto result = Utils::transform(filteredTargets, [this, target](const TargetInformation &ti) { @@ -143,9 +144,9 @@ public: addSupportedTargetDeviceType(Qdb::Constants::QdbLinuxOsType); } - virtual bool filterTarget(const TargetInformation &ti) const final + virtual bool filterTarget(Target *target, const TargetInformation &ti) const final { - return ti.manifest.supportsDebugging(); + return !AppManagerRunConfigurationFactory::filterTarget(target, ti); } }; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 23a947c45f2..399efc3a1cd 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -382,9 +382,14 @@ QString QtVersion::defaultUnexpandedDisplayName() const } } - return detectionSource() == "PATH" ? - Tr::tr("Qt %{Qt:Version} in PATH (%2)").arg(location) : - Tr::tr("Qt %{Qt:Version} (%2)").arg(location); + QString result = detectionSource() == "PATH" + ? Tr::tr("Qt %{Qt:Version} in PATH (%2)").arg(location) + : Tr::tr("Qt %{Qt:Version} (%2)").arg(location); + + if (qmakeFilePath().needsDevice()) + result += QString(Tr::tr(" (on %1)")).arg(qmakeFilePath().host().toString()); + + return result; } QSet QtVersion::availableFeatures() const diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index a835ef30be7..b166b702d34 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -21,12 +21,15 @@ #include #include #include +#include #include +#include #include #include #include #include +#include #include #include #include @@ -292,6 +295,8 @@ public: Environment deviceEnvironment() const override; + bool disconnected() const override; + LinuxDevicePrivate *m_dev; }; @@ -307,7 +312,7 @@ public: explicit LinuxDevicePrivate(LinuxDevice *parent); ~LinuxDevicePrivate(); - bool setupShell(); + bool setupShell(const SshParameters &sshParameters); RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); void attachToSharedConnection(SshConnectionHandle *connectionHandle, @@ -319,6 +324,10 @@ public: void checkOsType(); void queryOsType(std::function run); + void setDisconnected(bool disconnected); + bool disconnected() const; + bool checkDisconnectedWithWarning(); + LinuxDevice *q = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; @@ -327,6 +336,7 @@ public: QReadWriteLock m_environmentCacheLock; std::optional m_environmentCache; + bool m_disconnected = false; }; void LinuxDevicePrivate::invalidateEnvironmentCache() @@ -358,14 +368,24 @@ Environment LinuxDevicePrivate::getEnvironment() RunResult LinuxDeviceFileAccess::runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return {-1, {}, Tr::tr("Device is disconnected.").toUtf8()}; return m_dev->runInShell(cmdLine, stdInData); } Environment LinuxDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + return m_dev->getEnvironment(); } +bool LinuxDeviceFileAccess::disconnected() const +{ + return m_dev->checkDisconnectedWithWarning(); +} + // SshProcessImpl class SshProcessInterfacePrivate : public QObject @@ -987,7 +1007,7 @@ LinuxDevice::LinuxDevice() setOpenTerminal([this](const Environment &env, const FilePath &workingDir) -> expected_str { - Process proc; + Process *proc = new Process; // If we will not set any environment variables, we can leave out the shell executable // as the "ssh ..." call will automatically launch the default shell if there are @@ -995,11 +1015,19 @@ LinuxDevice::LinuxDevice() // specify the shell executable. const QString shell = env.hasChanges() ? env.value_or("SHELL", "/bin/sh") : QString(); - proc.setCommand({filePath(shell), {}}); - proc.setTerminalMode(TerminalMode::Detached); - proc.setEnvironment(env); - proc.setWorkingDirectory(workingDir); - proc.start(); + proc->setCommand({filePath(shell), {}}); + proc->setTerminalMode(TerminalMode::Run); + proc->setEnvironment(env); + proc->setWorkingDirectory(workingDir); + proc->start(); + + QObject::connect(proc, &Process::done, proc, [proc](){ + if (proc->exitCode() != 0){ + qCWarning(linuxDeviceLog) << proc->exitMessage(); + Core::MessageManager::writeFlashing(proc->exitMessage()); + } + proc->deleteLater(); + }); return {}; }); @@ -1023,6 +1051,15 @@ LinuxDevice::~LinuxDevice() delete d; } +IDevice::Ptr LinuxDevice::clone() const +{ + IDevice::Ptr clone = IDevice::clone(); + Ptr linuxClone = std::dynamic_pointer_cast(clone); + QTC_ASSERT(linuxClone, return clone); + linuxClone->d->setDisconnected(d->disconnected()); + return clone; +} + IDeviceWidget *LinuxDevice::createWidget() { return new Internal::GenericLinuxDeviceConfigurationWidget(shared_from_this()); @@ -1106,15 +1143,31 @@ void LinuxDevicePrivate::queryOsType(std::function_setOsType(OsTypeLinux); } +void LinuxDevicePrivate::setDisconnected(bool disconnected) +{ + if (disconnected == m_disconnected) + return; + + m_disconnected = disconnected; + + if (m_disconnected) + m_handler->closeShell(); + +} + +bool LinuxDevicePrivate::disconnected() const +{ + return m_disconnected; +} + void LinuxDevicePrivate::checkOsType() { queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); } // Call me with shell mutex locked -bool LinuxDevicePrivate::setupShell() +bool LinuxDevicePrivate::setupShell(const SshParameters &sshParameters) { - const SshParameters sshParameters = q->sshParameters(); if (m_handler->isRunning(sshParameters)) return true; @@ -1126,8 +1179,12 @@ bool LinuxDevicePrivate::setupShell() }, Qt::BlockingQueuedConnection, &ok); if (ok) { + setDisconnected(false); queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + } else { + setDisconnected(true); } + return ok; } @@ -1135,11 +1192,43 @@ RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArra { QMutexLocker locker(&m_shellMutex); DEBUG(cmd.toUserOutput()); - const bool isSetup = setupShell(); + if (checkDisconnectedWithWarning()) + return {}; + const bool isSetup = setupShell(q->sshParameters()); + if (checkDisconnectedWithWarning()) + return {}; QTC_ASSERT(isSetup, return {}); return m_handler->runInShell(cmd, data); } +bool LinuxDevicePrivate::checkDisconnectedWithWarning() +{ + if (!disconnected()) + return false; + + QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] { + if (!Core::ICore::infoBar()->canInfoBeAdded(id)) + return; + const QString warnStr + = Tr::tr("Device \"%1\" is currently marked as disconnected.").arg(name); + InfoBarEntry info(id, warnStr, InfoBarEntry::GlobalSuppression::Enabled); + info.setDetailsWidgetCreator([] { + const auto label = new QLabel(Tr::tr( + "The device was not available when trying to connect previously.
" + "No further connection attempts will be made until the device is manually reset " + "by running a successful connection test via the " + "settings page.")); + label->setWordWrap(true); + QObject::connect(label, &QLabel::linkActivated, [] { + Core::ICore::showOptionsDialog(ProjectExplorer::Constants::DEVICE_SETTINGS_PAGE_ID); + }); + return label; + }); + Core::ICore::infoBar()->addInfo(info); + }); + return true; +} + void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { @@ -1522,6 +1611,37 @@ void LinuxDevice::checkOsType() d->checkOsType(); } +IDevice::DeviceState LinuxDevice::deviceState() const +{ + if (isDisconnected()) + return DeviceDisconnected; + return IDevice::deviceState(); +} + +QString LinuxDevice::deviceStateToString() const +{ + if (isDisconnected()) + return Tr::tr("Device is considered unconnected. Re-run device test to reset state."); + return IDevice::deviceStateToString(); +} + +bool LinuxDevice::isDisconnected() const +{ + return d->disconnected(); +} +void LinuxDevice::setDisconnected(bool disconnected) +{ + d->setDisconnected(disconnected); +} + +QFuture LinuxDevice::tryToConnect() +{ + return Utils::asyncRun([this] { + QMutexLocker locker(&d->m_shellMutex); + return d->setupShell(sshParameters()); + }); +} + namespace Internal { class LinuxDeviceFactory final : public IDeviceFactory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index a6625cdea2d..0bb2468eacb 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -20,6 +20,8 @@ public: static Ptr create() { return Ptr(new LinuxDevice); } + IDevice::Ptr clone() const override; + ProjectExplorer::IDeviceWidget *createWidget() override; bool canCreateProcessModel() const override { return true; } @@ -42,6 +44,14 @@ public: class LinuxDevicePrivate *connectionAccess() const; void checkOsType() override; + DeviceState deviceState() const override; + QString deviceStateToString() const override; + + bool isDisconnected() const; + void setDisconnected(bool disconnected); + + QFuture tryToConnect(); + protected: LinuxDevice(); diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 3d6c41cd657..f279bc0c382 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -3,6 +3,7 @@ #include "linuxdevicetester.h" +#include "linuxdevice.h" #include "remotelinuxtr.h" #include @@ -17,6 +18,8 @@ #include #include +#include + using namespace ProjectExplorer; using namespace Tasking; using namespace Utils; @@ -43,9 +46,13 @@ public: const Storage &storage) const; GroupItem transferTasks() const; GroupItem commandTasks() const; + void runCommandTests(); + + bool isRunning() const { return m_connectionTest || m_taskTreeRunner.isRunning(); } GenericLinuxDeviceTester *q = nullptr; - IDevice::Ptr m_device; + LinuxDevice::Ptr m_device; + QFutureWatcher *m_connectionTest = nullptr; TaskTreeRunner m_taskTreeRunner; QStringList m_extraCommands; QList m_extraTests; @@ -276,6 +283,20 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const return root; } +void GenericLinuxDeviceTesterPrivate::runCommandTests() +{ + const Group root { + echoTask("Hello"), // No quoting necessary + echoTask("Hello Remote World!"), // Checks quoting, too. + unameTask(), + gathererTask(), + transferTasks(), + m_extraTests, + commandTasks() + }; + m_taskTreeRunner.start(root); +} + } // namespace Internal using namespace Internal; @@ -302,26 +323,40 @@ void GenericLinuxDeviceTester::setExtraTests(const QList &extraTests) void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguration) { - QTC_ASSERT(!d->m_taskTreeRunner.isRunning(), return); + QTC_ASSERT(!d->isRunning(), return); - d->m_device = deviceConfiguration; + emit progressMessage(Tr::tr("Connecting to device...")); - const Group root { - d->echoTask("Hello"), // No quoting necessary - d->echoTask("Hello Remote World!"), // Checks quoting, too. - d->unameTask(), - d->gathererTask(), - d->transferTasks(), - d->m_extraTests, - d->commandTasks() - }; - d->m_taskTreeRunner.start(root); + d->m_device = std::static_pointer_cast(deviceConfiguration); + + d->m_connectionTest = new QFutureWatcher(this); + d->m_connectionTest->setFuture(d->m_device->tryToConnect()); + + connect(d->m_connectionTest, &QFutureWatcher::finished, this, [this] { + const bool success = d->m_connectionTest->result(); + d->m_connectionTest->deleteLater(); + d->m_connectionTest = nullptr; + if (success) { + emit progressMessage(Tr::tr("Connected. Now doing extended checks.\n")); + d->runCommandTests(); + } else { + emit errorMessage( + Tr::tr("Basic connectivity test failed, device is considered unusable.")); + emit finished(TestFailure); + } + }); } void GenericLinuxDeviceTester::stopTest() { - QTC_ASSERT(d->m_taskTreeRunner.isRunning(), return); - d->m_taskTreeRunner.reset(); + QTC_ASSERT(d->isRunning(), return); + if (d->m_connectionTest) { + d->m_connectionTest->disconnect(); + d->m_connectionTest->cancel(); + d->m_connectionTest = nullptr; + } else { + d->m_taskTreeRunner.reset(); + } emit finished(TestFailure); } diff --git a/src/plugins/squish/squishnavigationwidget.cpp b/src/plugins/squish/squishnavigationwidget.cpp index 95f37c67eaf..7921938c37a 100644 --- a/src/plugins/squish/squishnavigationwidget.cpp +++ b/src/plugins/squish/squishnavigationwidget.cpp @@ -47,6 +47,7 @@ private: void onRowsInserted(const QModelIndex &parent, int, int); void onRowsRemoved(const QModelIndex &parent, int, int); void onAddSharedFileTriggered(const QModelIndex &idx); + void onRemoveSharedFileTriggered(const QModelIndex &idx); void onRemoveSharedFolderTriggered(int row, const QModelIndex &parent); void onRemoveAllSharedFolderTriggered(); void onRecordTestCase(const QString &suiteName, const QString &testCase); @@ -161,6 +162,9 @@ void SquishNavigationWidget::contextMenuEvent(QContextMenuEvent *event) case SquishTestTreeItem::SquishSharedFile: { QAction *deleteSharedFile = new QAction(Tr::tr("Delete Shared File"), &menu); menu.addAction(deleteSharedFile); + connect(deleteSharedFile, &QAction::triggered, this, [this, idx] { + onRemoveSharedFileTriggered(idx); + }); break; } case SquishTestTreeItem::SquishSharedFolder: { @@ -325,6 +329,31 @@ void SquishNavigationWidget::onAddSharedFileTriggered(const QModelIndex &idx) m_view->edit(m_sortModel->mapFromSource(added)); } +void SquishNavigationWidget::onRemoveSharedFileTriggered(const QModelIndex &idx) +{ + const auto scriptFile = FilePath::fromVariant(idx.data(LinkRole)); + QTC_ASSERT(!scriptFile.isEmpty(), return); + + const QString detail = Tr::tr("Do you really want to delete \"%1\" permanently?") + .arg(scriptFile.toUserOutput()); + const QMessageBox::StandardButton pressed + = CheckableMessageBox::question(Core::ICore::dialogParent(), + Tr::tr("Remove Shared File"), + detail, + Key("RemoveSharedSquishScript")); + if (pressed != QMessageBox::Yes) + return; + + const QModelIndex &realIdx = m_sortModel->mapToSource(idx); + // close document silently if open + if (Core::IDocument *doc = Core::DocumentModel::documentForFilePath(scriptFile)) + Core::EditorManager::closeDocuments({doc}, false); + if (scriptFile.removeFile()) + m_model->removeTreeItem(realIdx.row(), realIdx.parent()); + else + SquishMessages::criticalMessage(Tr::tr("Failed to remove \"%1\".")); +} + void SquishNavigationWidget::onRemoveSharedFolderTriggered(int row, const QModelIndex &parent) { const auto folder = Utils::FilePath::fromVariant(m_sortModel->index(row, 0, parent).data(LinkRole)); diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 4f378731d4b..e30abd5bc81 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -57,7 +57,7 @@ bool SubversionClient::doCommit(const FilePath &repositoryRoot, const QString &commitMessageFile, const QStringList &extraOptions) const { - CommandLine args{vcsBinary()}; + CommandLine args{vcsBinary(repositoryRoot)}; args << vcsCommandString(CommitCommand) << extraOptions << AddAuthOptions() @@ -117,7 +117,7 @@ QString SubversionClient::synchronousTopic(const FilePath &repository) const { QStringList args; - QString svnVersionBinary = vcsBinary().toString(); + QString svnVersionBinary = vcsBinary(repository).toString(); int pos = svnVersionBinary.lastIndexOf('/'); if (pos < 0) svnVersionBinary.clear(); @@ -237,7 +237,7 @@ SubversionDiffEditorController *SubversionClient::findOrCreateDiffEditor(const Q if (!controller) { controller = new SubversionDiffEditorController(document); controller->setVcsBinary(settings().binaryPath()); - controller->setProcessEnvironment(processEnvironment()); + controller->setProcessEnvironment(processEnvironment(workingDirectory)); controller->setWorkingDirectory(workingDirectory); } VcsBase::setSource(document, source); diff --git a/src/plugins/subversion/subversionconstants.h b/src/plugins/subversion/subversionconstants.h index b0d6ce8f45a..2b834ed64ae 100644 --- a/src/plugins/subversion/subversionconstants.h +++ b/src/plugins/subversion/subversionconstants.h @@ -3,10 +3,7 @@ #pragma once -#include - -namespace Subversion { -namespace Constants { +namespace Subversion::Constants { const char SUBVERSION_PLUGIN[] = "SubversionPlugin"; @@ -16,16 +13,12 @@ enum { debug = 0 }; const char SUBVERSION_CONTEXT[] = "Subversion Context"; const char SUBVERSION_COMMIT_EDITOR_ID[] = "Subversion Commit Editor"; -const char SUBVERSION_COMMIT_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion Commit Editor"); const char SUBVERSION_SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.svn.submit"; const char SUBVERSION_LOG_EDITOR_ID[] = "Subversion File Log Editor"; -const char SUBVERSION_LOG_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion File Log Editor"); const char SUBVERSION_LOG_MIMETYPE[] = "text/vnd.qtcreator.svn.log"; const char SUBVERSION_BLAME_EDITOR_ID[] = "Subversion Annotation Editor"; -const char SUBVERSION_BLAME_EDITOR_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("QtC::VcsBase", "Subversion Annotation Editor"); const char SUBVERSION_BLAME_MIMETYPE[] = "text/vnd.qtcreator.svn.annotation"; -} // namespace Constants -} // namespace Subversion +} // Subversion::Constants diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index c70df10640d..fc9d5ed1222 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -85,20 +86,6 @@ const char CMD_ID_UPDATE[] = "Subversion.Update"; const char CMD_ID_COMMIT_PROJECT[] = "Subversion.CommitProject"; const char CMD_ID_DESCRIBE[] = "Subversion.Describe"; -const VcsBaseEditorParameters logEditorParameters { - LogOutput, - Constants::SUBVERSION_LOG_EDITOR_ID, - Constants::SUBVERSION_LOG_EDITOR_DISPLAY_NAME, - Constants::SUBVERSION_LOG_MIMETYPE -}; - -const VcsBaseEditorParameters blameEditorParameters { - AnnotateOutput, - Constants::SUBVERSION_BLAME_EDITOR_ID, - Constants::SUBVERSION_BLAME_EDITOR_DISPLAY_NAME, - Constants::SUBVERSION_BLAME_MIMETYPE -}; - static inline QString debugCodec(const QTextCodec *c) { return c ? QString::fromLatin1(c->name()) : QString::fromLatin1("Null codec"); @@ -139,24 +126,6 @@ static inline QStringList svnDirectories() return rc; } -class SubversionPluginPrivate; - -class SubversionTopicCache : public Core::IVersionControl::TopicCache -{ -public: - SubversionTopicCache(SubversionPluginPrivate *plugin) : - m_plugin(plugin) - { } - -protected: - FilePath trackFile(const FilePath &repository) override; - - QString refreshTopic(const FilePath &repository) override; - -private: - SubversionPluginPrivate *m_plugin; -}; - class SubversionPluginPrivate final : public VcsBase::VersionControlBase { public: @@ -276,17 +245,23 @@ private: QAction *m_menuAction = nullptr; public: - VcsEditorFactory logEditorFactory { - &logEditorParameters, + VcsEditorFactory logEditorFactory {{ + LogOutput, + Constants::SUBVERSION_LOG_EDITOR_ID, + VcsBase::Tr::tr("Subversion File Log Editor"), + Constants::SUBVERSION_LOG_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; - VcsEditorFactory blameEditorFactory { - &blameEditorParameters, + VcsEditorFactory blameEditorFactory {{ + AnnotateOutput, + Constants::SUBVERSION_BLAME_EDITOR_ID, + VcsBase::Tr::tr("Subversion Annotation Editor"), + Constants::SUBVERSION_BLAME_MIMETYPE, [] { return new SubversionEditorWidget; }, std::bind(&SubversionPluginPrivate::vcsDescribe, this, _1, _2) - }; + }}; }; @@ -319,7 +294,12 @@ SubversionPluginPrivate::SubversionPluginPrivate() { dd = this; - setTopicCache(new SubversionTopicCache(this)); + setTopicFileTracker([this](const FilePath &repository) { + return FilePath::fromString(monitorFile(repository)); + }); + setTopicRefresher([this](const FilePath &repository) { + return synchronousTopic(repository); + }); using namespace Constants; using namespace Core::Constants; @@ -488,7 +468,7 @@ SubversionPluginPrivate::SubversionPluginPrivate() setupVcsSubmitEditor(this, { Constants::SUBVERSION_SUBMIT_MIMETYPE, Constants::SUBVERSION_COMMIT_EDITOR_ID, - Constants::SUBVERSION_COMMIT_EDITOR_DISPLAY_NAME, + VcsBase::Tr::tr("Subversion Commit Editor"), VcsBaseSubmitEditorParameters::DiffFiles, [] { return new SubversionSubmitEditor; }, }); @@ -853,7 +833,7 @@ void SubversionPluginPrivate::vcsAnnotateHelper(const FilePath &workingDir, cons } else { const QString title = QString::fromLatin1("svn annotate %1").arg(id); IEditor *newEditor = showOutputInEditor(title, response.cleanedStdOut(), - blameEditorParameters.id, source, codec); + Constants::SUBVERSION_BLAME_EDITOR_ID, source, codec); VcsBaseEditor::tagEditor(newEditor, tag); VcsBaseEditor::gotoLineOfEditor(newEditor, lineNumber); } @@ -1155,21 +1135,13 @@ VcsCommand *SubversionPluginPrivate::createInitialCheckoutCommand(const QString args << SubversionClient::AddAuthOptions(); args << Subversion::Constants::NON_INTERACTIVE_OPTION << extraArgs << url << localName; - auto command = VcsBaseClient::createVcsCommand(baseDirectory, subversionClient().processEnvironment()); + auto command = VcsBaseClient::createVcsCommand(baseDirectory, + subversionClient().processEnvironment( + baseDirectory)); command->addJob(args, -1); return command; } -FilePath SubversionTopicCache::trackFile(const FilePath &repository) -{ - return FilePath::fromString(m_plugin->monitorFile(repository)); -} - -QString SubversionTopicCache::refreshTopic(const FilePath &repository) -{ - return m_plugin->synchronousTopic(repository); -} - #ifdef WITH_TESTS diff --git a/src/plugins/terminal/terminalpane.cpp b/src/plugins/terminal/terminalpane.cpp index 111e6d2d992..16486387134 100644 --- a/src/plugins/terminal/terminalpane.cpp +++ b/src/plugins/terminal/terminalpane.cpp @@ -106,6 +106,18 @@ void TerminalPane::openTerminal(const OpenTerminalParameters ¶meters) } } + if (parametersCopy.workingDirectory && parametersCopy.workingDirectory->needsDevice() + && !parametersCopy.shellCommand) { + const FilePath shell = parametersCopy.workingDirectory->withNewPath( + parametersCopy.environment + .value_or(parametersCopy.workingDirectory->deviceEnvironment()) + .value_or("SHELL", "/bin/sh")); + if (!shell.isExecutableFile()) + parametersCopy.workingDirectory.reset(); + else + parametersCopy.shellCommand = CommandLine{shell, {}}; + } + const auto terminalWidget = new TerminalWidget(&m_tabWidget, parametersCopy); using namespace Constants; diff --git a/src/plugins/texteditor/codeassist/genericproposalmodel.h b/src/plugins/texteditor/codeassist/genericproposalmodel.h index 610fab1a1fb..3107fae0d33 100644 --- a/src/plugins/texteditor/codeassist/genericproposalmodel.h +++ b/src/plugins/texteditor/codeassist/genericproposalmodel.h @@ -45,6 +45,7 @@ public: virtual int indexOf(const std::function &predicate) const; void loadContent(const QList &items); + const QList &originalItems() const { return m_originalItems; } bool isPerfectMatch(const QString &prefix) const; bool hasItemsToPropose(const QString &prefix, AssistReason reason) const; diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index e46c5b7c5b4..b5435ed5e91 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -98,7 +98,7 @@ public: visualizeWhitespace = new QCheckBox(Tr::tr("&Visualize whitespace")); visualizeWhitespace->setToolTip(Tr::tr("Shows tabs and spaces.")); - highlightSelection = new QCheckBox(Tr::tr("&Highlight Selection")); + highlightSelection = new QCheckBox(Tr::tr("&Highlight selection")); highlightSelection->setToolTip(Tr::tr("Adds a colored background and a marker to the " "scrollbar to occurrences of the selected text.")); diff --git a/src/plugins/texteditor/syntaxhighlighter.cpp b/src/plugins/texteditor/syntaxhighlighter.cpp index 8c9cc194371..0ed00af389d 100644 --- a/src/plugins/texteditor/syntaxhighlighter.cpp +++ b/src/plugins/texteditor/syntaxhighlighter.cpp @@ -60,7 +60,6 @@ public: QList formats; QList> formatCategories; QTextCharFormat whitespaceFormat; - bool noAutomaticHighlighting = false; QString mimeType; }; @@ -345,12 +344,11 @@ void SyntaxHighlighter::setDocument(QTextDocument *doc) d->doc = doc; documentChanged(oldDoc, d->doc); if (d->doc) { - if (!d->noAutomaticHighlighting) { - connect(d->doc, &QTextDocument::contentsChange, this, &SyntaxHighlighter::reformatBlocks); - d->rehighlightPending = true; - QMetaObject::invokeMethod(this, &SyntaxHighlighter::delayedRehighlight, - Qt::QueuedConnection); - } + connect(d->doc, &QTextDocument::contentsChange, this, &SyntaxHighlighter::reformatBlocks); + d->rehighlightPending = true; + QMetaObject::invokeMethod(this, + &SyntaxHighlighter::delayedRehighlight, + Qt::QueuedConnection); d->foldValidator.setup(qobject_cast(doc->documentLayout())); } } @@ -846,15 +844,6 @@ FontSettings SyntaxHighlighter::fontSettings() const Q_D(const SyntaxHighlighter); return d->fontSettings; } -/*! - The syntax highlighter is not anymore reacting to the text document if \a noAutomatic is - \c true. -*/ -void SyntaxHighlighter::setNoAutomaticHighlighting(bool noAutomatic) -{ - Q_D(SyntaxHighlighter); - d->noAutomaticHighlighting = noAutomatic; -} /*! Creates text format categories for the text styles themselves, so the highlighter can diff --git a/src/plugins/texteditor/syntaxhighlighter.h b/src/plugins/texteditor/syntaxhighlighter.h index dbd57a45884..94cee8a65ef 100644 --- a/src/plugins/texteditor/syntaxhighlighter.h +++ b/src/plugins/texteditor/syntaxhighlighter.h @@ -53,8 +53,6 @@ public: virtual void setFontSettings(const TextEditor::FontSettings &fontSettings); TextEditor::FontSettings fontSettings() const; - void setNoAutomaticHighlighting(bool noAutomatic); - enum State { InProgress, Done diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.cpp b/src/plugins/texteditor/syntaxhighlighterrunner.cpp index 0d5e32893ee..bf53d90561b 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.cpp +++ b/src/plugins/texteditor/syntaxhighlighterrunner.cpp @@ -27,26 +27,22 @@ class SyntaxHighlighterRunnerPrivate : public QObject { Q_OBJECT public: - SyntaxHighlighterRunnerPrivate(SyntaxHighlighterRunner::SyntaxHighlighterCreator creator, + SyntaxHighlighterRunnerPrivate(SyntaxHighlighter *highlighter, QTextDocument *document, - bool async, - const QString &mimeType, - FontSettings fontSettings) + bool async) + : m_highlighter(highlighter) { if (async) { m_document = new QTextDocument(this); m_document->setDocumentLayout(new TextDocumentLayout(m_document)); + m_highlighter->setParent(m_document); } else { m_document = document; } - m_highlighter.reset(creator()); - m_highlighter->setFontSettings(fontSettings); m_highlighter->setDocument(m_document); - m_highlighter->setMimeType(mimeType); - m_highlighter->setParent(m_document); - connect(m_highlighter.get(), + connect(m_highlighter, &SyntaxHighlighter::resultsReady, this, &SyntaxHighlighterRunnerPrivate::resultsReady); @@ -102,7 +98,7 @@ public: void rehighlight() { m_highlighter->rehighlight(); } - std::unique_ptr m_highlighter; + SyntaxHighlighter *m_highlighter = nullptr; QTextDocument *m_document = nullptr; signals: @@ -110,15 +106,13 @@ signals: }; -SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighterCreator creator, +SyntaxHighlighterRunner::SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, QTextDocument *document, - bool async, - const QString &mimeType, - const TextEditor::FontSettings &fontSettings) - : d(new SyntaxHighlighterRunnerPrivate(creator, document, async, mimeType, fontSettings)) + bool async) + : d(new SyntaxHighlighterRunnerPrivate(highlighter, document, async)) , m_document(document) { - m_useGenericHighlighter = qobject_cast(d->m_highlighter.get()); + m_useGenericHighlighter = qobject_cast(d->m_highlighter); if (async) { m_thread.emplace(); @@ -163,6 +157,7 @@ SyntaxHighlighterRunner::~SyntaxHighlighterRunner() m_thread->quit(); m_thread->wait(); } else { + delete d->m_highlighter; delete d; } } @@ -185,7 +180,7 @@ void SyntaxHighlighterRunner::applyFormatRanges(const QListformats()) { TextDocumentLayout::FoldValidator foldValidator; foldValidator.setup(qobject_cast(m_document->documentLayout())); docBlock.layout()->setFormats(result.m_formatRanges); diff --git a/src/plugins/texteditor/syntaxhighlighterrunner.h b/src/plugins/texteditor/syntaxhighlighterrunner.h index 7202ebf401d..ccb292ea086 100644 --- a/src/plugins/texteditor/syntaxhighlighterrunner.h +++ b/src/plugins/texteditor/syntaxhighlighterrunner.h @@ -24,12 +24,7 @@ class TEXTEDITOR_EXPORT SyntaxHighlighterRunner : public QObject public: using SyntaxHighlighterCreator = std::function; - SyntaxHighlighterRunner( - SyntaxHighlighterCreator creator, - QTextDocument *document, - bool async, - const QString &mimeType, - const TextEditor::FontSettings &fontSettings = TextEditorSettings::fontSettings()); + SyntaxHighlighterRunner(SyntaxHighlighter *highlighter, QTextDocument *document, bool async); virtual ~SyntaxHighlighterRunner(); void setExtraFormats(const QMap> &formats); diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index a60c729ed4a..cb421f2bf7c 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -921,10 +921,12 @@ void TextDocument::resetSyntaxHighlighter(const std::functionm_highlighterRunner = new SyntaxHighlighterRunner(creator, + SyntaxHighlighter *highlighter = creator(); + highlighter->setFontSettings(TextEditorSettings::fontSettings()); + highlighter->setMimeType(mimeType()); + d->m_highlighterRunner = new SyntaxHighlighterRunner(highlighter, document(), - threaded && envValue, - mimeType()); + threaded && envValue); } void TextDocument::cleanWhitespace(const QTextCursor &cursor) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 1184749e86e..c8ef69c63ef 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -25,7 +25,6 @@ #include "refactoroverlay.h" #include "snippets/snippetoverlay.h" #include "storagesettings.h" -#include "syntaxhighlighter.h" #include "tabsettings.h" #include "textdocument.h" #include "textdocumentlayout.h" @@ -9425,7 +9424,7 @@ public: TextEditorFactory::SyntaxHighLighterCreator m_syntaxHighlighterCreator; CommentDefinition m_commentDefinition; QList m_hoverHandlers; // owned - CompletionAssistProvider * m_completionAssistProvider = nullptr; // owned + std::unique_ptr m_completionAssistProvider; // owned std::unique_ptr m_textEditorActionHandler; bool m_useGenericHighlighter = false; bool m_duplicatedSupported = true; @@ -9445,7 +9444,6 @@ TextEditorFactory::TextEditorFactory() TextEditorFactory::~TextEditorFactory() { qDeleteAll(d->m_hoverHandlers); - delete d->m_completionAssistProvider; delete d; } @@ -9472,8 +9470,9 @@ void TextEditorFactory::setEditorCreator(const EditorCreator &creator) if (d->m_syntaxHighlighterCreator) doc->resetSyntaxHighlighter(d->m_syntaxHighlighterCreator); - doc->setCompletionAssistProvider(d->m_completionAssistProvider ? d->m_completionAssistProvider - : &basicSnippetProvider); + doc->setCompletionAssistProvider(d->m_completionAssistProvider + ? d->m_completionAssistProvider.get() + : &basicSnippetProvider); return d->createEditorHelper(doc); }); @@ -9511,7 +9510,7 @@ void TextEditorFactory::addHoverHandler(BaseHoverHandler *handler) void TextEditorFactory::setCompletionAssistProvider(CompletionAssistProvider *provider) { - d->m_completionAssistProvider = provider; + d->m_completionAssistProvider.reset(provider); } void TextEditorFactory::setCommentDefinition(CommentDefinition definition) diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index ea2ddcadc5d..81a816c0099 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -61,15 +61,18 @@ VcsBaseClientImpl::VcsBaseClientImpl(VcsBaseSettings *baseSettings) this, &VcsBaseClientImpl::saveSettings); } -FilePath VcsBaseClientImpl::vcsBinary() const +FilePath VcsBaseClientImpl::vcsBinary(const Utils::FilePath &forDirectory) const { + if (forDirectory.needsDevice()) + return {}; + return m_baseSettings->binaryPath(); } VcsCommand *VcsBaseClientImpl::createCommand(const FilePath &workingDirectory, VcsBaseEditorWidget *editor) const { - auto cmd = createVcsCommand(workingDirectory, processEnvironment()); + auto cmd = createVcsCommand(workingDirectory, processEnvironment(workingDirectory)); if (editor) { editor->setCommand(cmd); connect(cmd, &VcsCommand::done, editor, [editor, cmd] { @@ -88,24 +91,24 @@ void VcsBaseClientImpl::setupCommand(Utils::Process &process, const FilePath &workingDirectory, const QStringList &args) const { - process.setEnvironment(processEnvironment()); + process.setEnvironment(workingDirectory.deviceEnvironment()); process.setWorkingDirectory(workingDirectory); - process.setCommand({vcsBinary(), args}); + process.setCommand({vcsBinary(workingDirectory), args}); process.setUseCtrlCStub(true); } -void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, const QStringList &args, +void VcsBaseClientImpl::enqueueJob(VcsCommand *cmd, + const QStringList &args, + const Utils::FilePath &forDirectory, const ExitCodeInterpreter &interpreter) const { - cmd->addJob({vcsBinary(), args}, vcsTimeoutS(), {}, interpreter); + cmd->addJob({vcsBinary(forDirectory), args}, vcsTimeoutS(), {}, interpreter); cmd->start(); } -Environment VcsBaseClientImpl::processEnvironment() const +Environment VcsBaseClientImpl::processEnvironment(const FilePath &appliedTo) const { - Environment environment = Environment::systemEnvironment(); - VcsBase::setProcessEnvironment(&environment); - return environment; + return appliedTo.deviceEnvironment(); } QStringList VcsBaseClientImpl::splitLines(const QString &s) @@ -129,14 +132,18 @@ QString VcsBaseClientImpl::stripLastNewline(const QString &in) CommandResult VcsBaseClientImpl::vcsSynchronousExec(const FilePath &workingDir, const QStringList &args, RunFlags flags, int timeoutS, QTextCodec *codec) const { - return vcsSynchronousExec(workingDir, {vcsBinary(), args}, flags, timeoutS, codec); + return vcsSynchronousExec(workingDir, {vcsBinary(workingDir), args}, flags, timeoutS, codec); } CommandResult VcsBaseClientImpl::vcsSynchronousExec(const FilePath &workingDir, const CommandLine &cmdLine, RunFlags flags, int timeoutS, QTextCodec *codec) const { - return VcsCommand::runBlocking(workingDir, processEnvironment(), cmdLine, flags, - timeoutS > 0 ? timeoutS : vcsTimeoutS(), codec); + return VcsCommand::runBlocking(workingDir, + processEnvironment(workingDir), + cmdLine, + flags, + timeoutS > 0 ? timeoutS : vcsTimeoutS(), + codec); } void VcsBaseClientImpl::resetCachedVcsInfo(const FilePath &workingDir) @@ -166,7 +173,7 @@ void VcsBaseClientImpl::vcsExecWithHandler(const FilePath &workingDirectory, VcsCommand *command = createCommand(workingDirectory); command->addFlags(additionalFlags); command->setCodec(codec); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); if (handler) { const QObject *actualContext = context ? context : this; connect(command, &VcsCommand::done, actualContext, [command, handler] { @@ -182,7 +189,7 @@ void VcsBaseClientImpl::vcsExec(const FilePath &workingDirectory, { VcsCommand *command = createCommand(workingDirectory); command->addFlags(additionalFlags); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); command->start(); } @@ -192,7 +199,7 @@ void VcsBaseClientImpl::vcsExecWithEditor(const Utils::FilePath &workingDirector { VcsCommand *command = createCommand(workingDirectory, editor); command->setCodec(editor->codec()); - command->addJob({vcsBinary(), arguments}, vcsTimeoutS()); + command->addJob({vcsBinary(workingDirectory), arguments}, vcsTimeoutS()); command->start(); } @@ -350,7 +357,7 @@ void VcsBaseClient::annotate(const Utils::FilePath &workingDir, const QString &f VcsCommand *cmd = createCommand(workingDir, editor); editor->setDefaultLineNumber(lineNumber); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::diff(const FilePath &workingDir, const QStringList &files) @@ -387,7 +394,7 @@ void VcsBaseClient::diff(const FilePath &workingDir, const QStringList &files) : VcsBaseEditor::getCodec(source); VcsCommand *command = createCommand(workingDir, editor); command->setCodec(codec); - enqueueJob(command, args, exitCodeInterpreter(DiffCommand)); + enqueueJob(command, args, workingDir, exitCodeInterpreter(DiffCommand)); } void VcsBaseClient::log(const FilePath &workingDir, @@ -421,7 +428,7 @@ void VcsBaseClient::log(const FilePath &workingDir, } } - CommandLine args{vcsBinary(), {vcsCmdString}}; + CommandLine args{vcsBinary(workingDir), {vcsCmdString}}; if (addAuthOptions) addAuthOptions(args); if (editorConfig) @@ -448,7 +455,7 @@ void VcsBaseClient::revertFile(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::revertAll(const FilePath &workingDir, @@ -464,7 +471,7 @@ void VcsBaseClient::revertAll(const FilePath &workingDir, if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(files); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::status(const FilePath &workingDir, @@ -475,7 +482,7 @@ void VcsBaseClient::status(const FilePath &workingDir, args << extraOptions << file; VcsCommand *cmd = createCommand(workingDir); cmd->addFlags(RunFlags::ShowStdOut); - enqueueJob(cmd, args); + enqueueJob(cmd, args, workingDir); } void VcsBaseClient::emitParsedStatus(const FilePath &repository, const QStringList &extraOptions) @@ -484,7 +491,7 @@ void VcsBaseClient::emitParsedStatus(const FilePath &repository, const QStringLi args << extraOptions; VcsCommand *cmd = createCommand(repository); connect(cmd, &VcsCommand::done, this, [this, cmd] { statusParser(cmd->cleanedStdOut()); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repository); } QString VcsBaseClient::vcsCommandString(VcsCommandTag cmd) const @@ -525,7 +532,7 @@ void VcsBaseClient::import(const FilePath &repositoryRoot, { QStringList args(vcsCommandString(ImportCommand)); args << extraOptions << files; - enqueueJob(createCommand(repositoryRoot), args); + enqueueJob(createCommand(repositoryRoot), args, repositoryRoot); } void VcsBaseClient::view(const FilePath &source, @@ -541,7 +548,7 @@ void VcsBaseClient::view(const FilePath &source, VcsBaseEditor::getCodec(source), "view", id); const FilePath workingDirPath = source.isFile() ? source.absolutePath() : source; - enqueueJob(createCommand(workingDirPath, editor), args); + enqueueJob(createCommand(workingDirPath, editor), args, source); } void VcsBaseClient::update(const FilePath &repositoryRoot, const QString &revision, @@ -554,7 +561,7 @@ void VcsBaseClient::update(const FilePath &repositoryRoot, const QString &revisi if (cmd->result() == ProcessResult::FinishedWithSuccess) emit changed(repositoryRoot.toString()); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repositoryRoot); } void VcsBaseClient::commit(const FilePath &repositoryRoot, @@ -576,12 +583,12 @@ void VcsBaseClient::commit(const FilePath &repositoryRoot, cmd->addFlags(RunFlags::ShowStdOut); if (!commitMessageFile.isEmpty()) connect(cmd, &VcsCommand::done, [commitMessageFile] { QFile(commitMessageFile).remove(); }); - enqueueJob(cmd, args); + enqueueJob(cmd, args, repositoryRoot); } QString VcsBaseClient::vcsEditorTitle(const QString &vcsCmd, const QString &sourceId) const { - return vcsBinary().baseName() + QLatin1Char(' ') + vcsCmd + QLatin1Char(' ') + return vcsBinary({}).baseName() + QLatin1Char(' ') + vcsCmd + QLatin1Char(' ') + FilePath::fromString(sourceId).fileName(); } diff --git a/src/plugins/vcsbase/vcsbaseclient.h b/src/plugins/vcsbase/vcsbaseclient.h index f1db56ebeb9..99b818b59b7 100644 --- a/src/plugins/vcsbase/vcsbaseclient.h +++ b/src/plugins/vcsbase/vcsbaseclient.h @@ -41,7 +41,7 @@ public: explicit VcsBaseClientImpl(VcsBaseSettings *baseSettings); ~VcsBaseClientImpl() override = default; - virtual Utils::FilePath vcsBinary() const; + virtual Utils::FilePath vcsBinary(const Utils::FilePath &forDirectory) const; int vcsTimeoutS() const; static VcsCommand *createVcsCommand(const Utils::FilePath &defaultWorkingDir, @@ -59,10 +59,12 @@ public: const Utils::FilePath &workingDirectory, const QStringList &args) const; - void enqueueJob(VcsCommand *cmd, const QStringList &args, + void enqueueJob(VcsCommand *cmd, + const QStringList &args, + const Utils::FilePath &forDirectory, const ExitCodeInterpreter &interpreter = {}) const; - virtual Utils::Environment processEnvironment() const; + virtual Utils::Environment processEnvironment(const Utils::FilePath &appliedTo) const; // VCS functionality: virtual void annotate(const Utils::FilePath &workingDir, const QString &file, diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 729ee682c4d..b10758233a0 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -563,7 +563,6 @@ public: VcsBaseEditorConfig *m_config = nullptr; QList m_textCursorHandlers; QPointer m_command; - VcsBaseEditorWidget::DescribeFunc m_describeFunc = nullptr; ProgressIndicator *m_progressIndicator = nullptr; bool m_fileLogAnnotateEnabled = false; bool m_mouseDragging = false; @@ -723,14 +722,10 @@ int VcsBaseEditorWidget::lineNumberDigits() const return digits; } -void VcsBaseEditorWidget::setDescribeFunc(DescribeFunc describeFunc) -{ - d->m_describeFunc = describeFunc; -} - void VcsBaseEditorWidget::finalizeInitialization() { - connect(this, &VcsBaseEditorWidget::describeRequested, this, d->m_describeFunc); + QTC_CHECK(d->m_parameters.describeFunc); + connect(this, &VcsBaseEditorWidget::describeRequested, this, d->m_parameters.describeFunc); init(); } @@ -1332,7 +1327,7 @@ bool VcsBaseEditor::gotoLineOfEditor(IEditor *e, int lineNumber) // ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file'). FilePath VcsBaseEditor::getSource(const FilePath &workingDirectory, const QString &fileName) { - return workingDirectory.pathAppended(fileName); + return workingDirectory.resolvePath(fileName); } FilePath VcsBaseEditor::getSource(const FilePath &workingDirectory, const QStringList &fileNames) @@ -1653,30 +1648,26 @@ IEditor *VcsBaseEditor::locateEditorByTag(const QString &tag) \sa VcsBase::VcsBaseEditorWidget */ -VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters *parameters, - // Force copy, see QTCREATORBUG-13218 - const EditorWidgetCreator editorWidgetCreator, - std::function describeFunc) +VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters ¶meters) { - setId(parameters->id); - setDisplayName(Tr::tr(parameters->displayName)); - if (QLatin1String(parameters->mimeType) != QLatin1String(DiffEditor::Constants::DIFF_EDITOR_MIMETYPE)) - addMimeType(QLatin1String(parameters->mimeType)); + setId(parameters.id); + setDisplayName(parameters.displayName); + if (parameters.mimeType != DiffEditor::Constants::DIFF_EDITOR_MIMETYPE) + addMimeType(parameters.mimeType); setEditorActionHandlers(TextEditorActionHandler::None); setDuplicatedSupported(false); setDocumentCreator([parameters] { - auto document = new TextDocument(parameters->id); - document->setMimeType(QLatin1String(parameters->mimeType)); + auto document = new TextDocument(parameters.id); + document->setMimeType(parameters.mimeType); document->setSuspendAllowed(false); return document; }); - setEditorWidgetCreator([parameters=*parameters, editorWidgetCreator, describeFunc] { - auto widget = editorWidgetCreator(); + setEditorWidgetCreator([parameters] { + auto widget = parameters.editorWidgetCreator(); auto editorWidget = Aggregation::query(widget); - editorWidget->setDescribeFunc(describeFunc); editorWidget->setParameters(parameters); return widget; }); diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index b2a9a80cb32..04e698f4eae 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -42,9 +42,11 @@ class VCSBASE_EXPORT VcsBaseEditorParameters { public: EditorContentType type; - const char *id; - const char *displayName; - const char *mimeType; + Utils::Id id; + QString displayName; + QString mimeType; + std::function editorWidgetCreator; + std::function describeFunc; }; class VCSBASE_EXPORT DiffChunk @@ -145,8 +147,6 @@ public: void finalizeInitialization() override; // FIXME: Consolidate these into finalizeInitialization - void setDescribeFunc(DescribeFunc describeFunc); - // void virtual void init(); // void setParameters(const VcsBaseEditorParameters ¶meters); @@ -289,10 +289,7 @@ public: class VCSBASE_EXPORT VcsEditorFactory : public TextEditor::TextEditorFactory { public: - VcsEditorFactory(const VcsBaseEditorParameters *parameters, - const EditorWidgetCreator editorWidgetCreator, - std::function describeFunc); - + explicit VcsEditorFactory(const VcsBaseEditorParameters ¶meters); ~VcsEditorFactory(); }; diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index ee2ea428137..b506f0ed380 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -374,7 +374,7 @@ FilePath VcsBasePluginState::currentFileDirectory() const QString VcsBasePluginState::relativeCurrentFile() const { QTC_ASSERT(hasFile(), return {}); - return data->m_state.currentFile.relativeChildPath(data->m_state.currentFileTopLevel).toString(); + return data->m_state.currentFile.relativeChildPath(data->m_state.currentFileTopLevel).path(); } QString VcsBasePluginState::currentPatchFile() const diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 79dcddc3f95..4c29da91f2f 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -147,10 +147,10 @@ void VcsBaseSubmitEditor::setParameters(const VcsBaseSubmitEditorParameters &par { d->m_parameters = parameters; d->m_file.setId(parameters.id); - d->m_file.setMimeType(QLatin1String(parameters.mimeType)); + d->m_file.setMimeType(parameters.mimeType); setWidget(d->m_widget); - document()->setPreferredDisplayName(Tr::tr(d->m_parameters.displayName)); + document()->setPreferredDisplayName(d->m_parameters.displayName); // Message font according to settings CompletingTextEdit *descriptionEdit = d->m_widget->descriptionEdit(); @@ -643,8 +643,8 @@ public: .bindContextAction(&diffAction); setId(parameters.id); - setDisplayName(QLatin1String(parameters.displayName)); - addMimeType(QLatin1String(parameters.mimeType)); + setDisplayName(parameters.displayName); + addMimeType(parameters.mimeType); setEditorCreator([parameters, submitAction, diffAction, undoAction, redoAction] { VcsBaseSubmitEditor *editor = parameters.editorCreator(); editor->setParameters(parameters); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.h b/src/plugins/vcsbase/vcsbasesubmiteditor.h index 204ab9b6af5..b2eb958a792 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.h +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.h @@ -28,9 +28,9 @@ class VcsBaseSubmitEditorPrivate; class VCSBASE_EXPORT VcsBaseSubmitEditorParameters { public: - const char *mimeType; - const char *id; - const char *displayName; + QString mimeType; + Utils::Id id; + QString displayName; enum DiffType { DiffRows, DiffFiles } diffType; std::function editorCreator; }; diff --git a/src/plugins/vcsbase/vcscommand.h b/src/plugins/vcsbase/vcscommand.h index e9975dcb140..62711395445 100644 --- a/src/plugins/vcsbase/vcscommand.h +++ b/src/plugins/vcsbase/vcscommand.h @@ -82,9 +82,11 @@ public: void setProgressParser(const Core::ProgressParser &parser); static CommandResult runBlocking(const Utils::FilePath &workingDirectory, - const Utils::Environment &environmentconst, - const Utils::CommandLine &command, RunFlags flags, - int timeoutS, QTextCodec *codec); + const Utils::Environment &environment, + const Utils::CommandLine &command, + RunFlags flags, + int timeoutS, + QTextCodec *codec); void cancel(); QString cleanedStdOut() const; diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index fdd91a5ed0d..3ad77c9eb01 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -393,7 +393,7 @@ QString VcsOutputWindow::msgExecutionLogEntry(const FilePath &workingDir, const + ' ' + formatArguments(command.splitArguments()); if (workingDir.isEmpty()) return Tr::tr("Running: %1").arg(maskedCmdline) + '\n'; - return Tr::tr("Running in \"%1\": %2.").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; + return Tr::tr("Running in \"%1\": %2").arg(workingDir.toUserOutput(), maskedCmdline) + '\n'; } void VcsOutputWindow::appendShellCommandLine(const QString &text) diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index b7161fcb0dc..0590823ea63 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -245,7 +245,6 @@ public: vbox->addItem(newVBox); auto newLabel = new QLabel(Tr::tr("New to Qt?"), mainWidget); - newLabel->setFont(StyleHelper::uiFont(StyleHelper::UiElementH2)); newLabel->setAlignment(Qt::AlignHCenter); newVBox->addWidget(newLabel); diff --git a/src/share/3rdparty/package-manager/auto-setup.cmake b/src/share/3rdparty/package-manager/auto-setup.cmake index a2e30686f9f..628b69cc768 100644 --- a/src/share/3rdparty/package-manager/auto-setup.cmake +++ b/src/share/3rdparty/package-manager/auto-setup.cmake @@ -137,6 +137,7 @@ macro(qtc_auto_setup_conan) get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS) if (CONAN_INSTALL_SUCCESS) get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER) + file(TO_CMAKE_PATH \"\${CONAN_GENERATORS_FOLDER}\" CONAN_GENERATORS_FOLDER) file(WRITE \"${CMAKE_BINARY_DIR}/conan-dependencies/conan_paths.cmake\" \" list(PREPEND CMAKE_PREFIX_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") list(PREPEND CMAKE_MODULE_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") diff --git a/src/shared/qbs b/src/shared/qbs index 0d589c18b57..a30e54c2e7f 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 0d589c18b570ce895cf3d6e69545439c2f68ebac +Subproject commit a30e54c2e7fb7d9735a364497914a5df452dd1ad diff --git a/src/src.qbs b/src/src.qbs index fb7532b03c9..95f2e96dcc5 100644 --- a/src/src.qbs +++ b/src/src.qbs @@ -34,6 +34,7 @@ Project { qbsBaseDir + "/share/share.qbs", qbsBaseDir + "/src/app/apps.qbs", qbsBaseDir + "/src/shared/bundledqt/bundledqt.qbs", + qbsBaseDir + "/src/shared/lsp/lsp.qbs", qbsBaseDir + "/src/shared/json/json.qbs", qbsBaseDir + "/src/shared/variant/variant.qbs", ] diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 698147c4194..1cf8f1bbf2f 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -5264,7 +5264,12 @@ void tst_Dumpers::dumper_data() << Data("#include \n" "template\n" - "class myallocator : public std::allocator {};\n", + "class myallocator : public std::allocator {\n" + "template\n" + "struct rebind {\n" + "typedef myallocator<_Tp1> other;\n" + "};\n" + "};\n", "std::basic_string, myallocator> str(\"hello\");", @@ -5313,8 +5318,8 @@ void tst_Dumpers::dumper_data() "&view, &u16view, basicview, u16basicview") - + Check("view", "\"test\"", "std::string_view") - + Check("u16view", "\"test\"", "std::u16string_view") + + Check("view", "\"test\"", TypeDef("std::basic_string_view >", "std::string_view")) + + Check("u16view", "\"test\"", TypeDef("std::basic_string_view >", "std::u16string_view")) + Check("basicview", "\"test\"", "std::basic_string_view >") + Check("u16basicview", "\"test\"", "std::basic_string_view >"); @@ -5343,6 +5348,18 @@ void tst_Dumpers::dumper_data() + Check("v.0", "[0]", "\"foo\"", "std::string"); + QTest::newRow("StdTuple") + << Data("#include \n", + + "std::tuple tuple = std::make_tuple(123, std::string(\"hello\"), 456);\n", + + "&tuple") + + + Check("tuple.0", "[0]", "123", "int") + + Check("tuple.1", "[1]", "\"hello\"", "std::string") + + Check("tuple.2", "[2]", "456", "int"); + + QTest::newRow("StdValArray") << Data("#include \n" "#include \n", @@ -5418,6 +5435,10 @@ void tst_Dumpers::dumper_data() "template\n" "class myallocator : public std::allocator {\n" "using std::allocator::allocator;\n" + "template\n" + "struct rebind {\n" + "typedef myallocator<_Tp1> other;\n" + "};\n" "};\n", "std::vector v0, v1;\n" diff --git a/tests/auto/environment/tst_environment.cpp b/tests/auto/environment/tst_environment.cpp index 64dfe426487..3cf9c127a22 100644 --- a/tests/auto/environment/tst_environment.cpp +++ b/tests/auto/environment/tst_environment.cpp @@ -262,11 +262,11 @@ void tst_Environment::expansion() void tst_Environment::incrementalChanges() { const Environment origEnv({{"VAR1", "VALUE1"}, {"VAR2", "VALUE2"}, {"PATH", "/usr/bin"}}); - const NameValueItems changes({ - {"VAR1", QString(), NameValueItem::Unset}, - {"VAR2", "VALUE2", NameValueItem::SetDisabled}, - {"PATH", "/usr/local/bin", NameValueItem::Append}, - {"PATH", "/tmp", NameValueItem::Prepend}}); + const EnvironmentItems changes({ + {"VAR1", QString(), EnvironmentItem::Unset}, + {"VAR2", "VALUE2", EnvironmentItem::SetDisabled}, + {"PATH", "/usr/local/bin", EnvironmentItem::Append}, + {"PATH", "/tmp", EnvironmentItem::Prepend}}); // Check values after change application. Environment newEnv = origEnv; @@ -281,8 +281,8 @@ void tst_Environment::incrementalChanges() QString("/tmp").append(sep).append("/usr/bin").append(sep).append("/usr/local/bin")); // Check apply/diff round-trips. - const NameValueItems diff = origEnv.diff(newEnv); - const NameValueItems reverseDiff = newEnv.diff(origEnv); + const EnvironmentItems diff = origEnv.diff(newEnv); + const EnvironmentItems reverseDiff = newEnv.diff(origEnv); Environment newEnv2 = origEnv; newEnv2.modify(diff); QCOMPARE(newEnv, newEnv2); @@ -290,12 +290,12 @@ void tst_Environment::incrementalChanges() QCOMPARE(newEnv2, origEnv); // Check conversion round-trips. - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(changes)), changes); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(diff)), diff); - QCOMPARE(NameValueItem::fromStringList(NameValueItem::toStringList(reverseDiff)), reverseDiff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(changes)), changes); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(diff)), diff); - QCOMPARE(NameValueItem::itemsFromVariantList(NameValueItem::toVariantList(reverseDiff)), + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(changes)), changes); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(diff)), diff); + QCOMPARE(EnvironmentItem::fromStringList(EnvironmentItem::toStringList(reverseDiff)), reverseDiff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(changes)), changes); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(diff)), diff); + QCOMPARE(EnvironmentItem::itemsFromVariantList(EnvironmentItem::toVariantList(reverseDiff)), reverseDiff); } diff --git a/tests/auto/texteditor/highlighter/tst_highlighter.cpp b/tests/auto/texteditor/highlighter/tst_highlighter.cpp index aaba61161bc..9044065a019 100644 --- a/tests/auto/texteditor/highlighter/tst_highlighter.cpp +++ b/tests/auto/texteditor/highlighter/tst_highlighter.cpp @@ -58,9 +58,8 @@ Last)"; doc = new QTextDocument(); doc->setPlainText(text); - - highlighterRunner = new SyntaxHighlighterRunner( - [this] { return new SyntaxHighlighter(doc, fontsettings); }, doc, false, {}, fontsettings); + auto highlighter = new SyntaxHighlighter(doc, fontsettings); + highlighterRunner = new SyntaxHighlighterRunner(highlighter, doc, false); } static const HighlightingResults &highlightingResults() diff --git a/tests/auto/utils/filepath/tst_filepath.cpp b/tests/auto/utils/filepath/tst_filepath.cpp index 0cd0629609e..369fb6a2584 100644 --- a/tests/auto/utils/filepath/tst_filepath.cpp +++ b/tests/auto/utils/filepath/tst_filepath.cpp @@ -117,6 +117,11 @@ private slots: void isRootPath(); + void lessThan(); + void lessThan_data(); + + void asQMapKey(); + private: QTemporaryDir tempDir; QString rootPath; @@ -1666,6 +1671,42 @@ void tst_filepath::sort() QCOMPARE(sortedPaths, sorted); } +void tst_filepath::lessThan_data() +{ + QTest::addColumn("left"); + QTest::addColumn("right"); + QTest::addColumn("expected"); + + QTest::newRow("empty") << FilePath() << FilePath() << false; + QTest::newRow("simple") << FilePath("/a") << FilePath("/b") << true; + QTest::newRow("simple-2") << FilePath("/a") << FilePath("/a") << false; + QTest::newRow("simple-3") << FilePath("/b") << FilePath("/a") << false; + + QTest::newRow("remote-vs-local") << FilePath("docker://1234/a") << FilePath("/a") << false; + QTest::newRow("local-vs-remote") << FilePath("/a") << FilePath("docker://1234/a") << true; + + QTest::newRow("remote-vs-local-2") << FilePath("docker://1234/a") << FilePath("/b") << false; + QTest::newRow("local-vs-remote-2") << FilePath("/a") << FilePath("docker://1234/b") << true; +} + +void tst_filepath::lessThan() +{ + QFETCH(FilePath, left); + QFETCH(FilePath, right); + QFETCH(bool, expected); + + QCOMPARE(left < right, expected); +} + +void tst_filepath::asQMapKey() +{ + QMap map; + map.insert(FilePath::fromString("/Users/mtillmanns/projects/qt/qtc-work/fsengine"), 1); + + QCOMPARE(map.contains(FilePath::fromString("ssh://marcus@mad-ubuntu-23.local/tmp/untitled")), + false); +} + void tst_filepath::isRootPath() { FilePath localRoot = FilePath::fromString(QDir::rootPath()); diff --git a/tests/system/README b/tests/system/README index 1174b181876..7dff67a84d0 100644 --- a/tests/system/README +++ b/tests/system/README @@ -63,10 +63,7 @@ started. On Windows, this has the following prerequisites: Either: * have no firewall at all enabled (sure that's a bad idea) Or: - * run Windows with English UI - * have the Windows Firewall enabled (no other firewalls are handled by the scripts) - * run the Squish tests with administrator privileges - * additionally the UAC should be disabled, too + * have notifications disabled for the firewall when an application tries to access network Otherwise you'll have some trouble with popping up dialogs from the firewall. If you're using a different firewall - try to figure out and add a rule for this. diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index 6a2904286a3..c26634f61db 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -40,12 +40,6 @@ def getBuildIssues(ignoreCodeModel=True): # lines within the Issues output # param expectedToFail can be used to tell this function if the build was expected to fail or not def checkLastBuild(expectedToFail=False): - try: - # can't use waitForObject() 'cause visible is always 0 - findObject("{type='ProjectExplorer::Internal::BuildProgress' unnamed='1' }") - except LookupError: - test.log("checkLastBuild called without a build") - return buildIssues = getBuildIssues() types = [i[1] for i in buildIssues] errors = types.count("1") diff --git a/tests/system/shared/debugger.py b/tests/system/shared/debugger.py index bb6b4082b63..5ee31dec201 100644 --- a/tests/system/shared/debugger.py +++ b/tests/system/shared/debugger.py @@ -266,69 +266,3 @@ def verifyBreakPoint(bpToVerify): test.fatal("Expected a dict for bpToVerify - got '%s'" % className(bpToVerify)) return False -# helper to check whether win firewall is running or not -# this doesn't check for other firewalls! -def __isWinFirewallRunning__(): - if hasattr(__isWinFirewallRunning__, "fireWallState"): - return __isWinFirewallRunning__.fireWallState - if platform.system() not in ('Microsoft' 'Windows'): - __isWinFirewallRunning__.fireWallState = False - return False - result = getOutputFromCmdline(["netsh", "firewall", "show", "state"]) - for line in result.splitlines(): - if "Operational mode" in line: - __isWinFirewallRunning__.fireWallState = not "Disable" in line - return __isWinFirewallRunning__.fireWallState - return None - -# helper that can modify the win firewall to allow a program to communicate through it or delete it -# param addToFW defines whether to add (True) or delete (False) this program to/from the firewall -def __configureFW__(workingDir, projectName, isReleaseBuild, addToFW=True): - if isReleaseBuild == None: - if projectName[-4:] == ".exe": - projectName = projectName[:-4] - path = "%s%s%s" % (workingDir, os.sep, projectName) - elif isReleaseBuild: - path = "%s%s%s%srelease%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName) - else: - path = "%s%s%s%sdebug%s%s" % (workingDir, os.sep, projectName, os.sep, os.sep, projectName) - if addToFW: - mode = "add" - enable = "ENABLE" - else: - mode = "delete" - enable = "" - projectName = "" - # Needs admin privileges on Windows 7 - # Using the deprecated "netsh firewall" because the newer - # "netsh advfirewall" would need admin privileges on Windows Vista, too. - return subprocess.call(["netsh", "firewall", mode, "allowedprogram", - "%s.exe" % path, projectName, enable]) - -# function to add a program to allow communication through the win firewall -# param workingDir this directory is the parent of the project folder -# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable) -# param isReleaseBuild should currently always be set to True (will later add debug build testing) -def allowAppThroughWinFW(workingDir, projectName, isReleaseBuild=True): - if not __isWinFirewallRunning__(): - return - # WinFirewall seems to run - hopefully no other - result = __configureFW__(workingDir, projectName, isReleaseBuild) - if result == 0: - test.log("Added %s to firewall" % projectName) - else: - test.fatal("Could not add %s as allowed program to win firewall" % projectName) - -# function to delete a (former added) program from the win firewall -# param workingDir this directory is the parent of the project folder -# param projectName this is the name of the project (the folder inside workingDir as well as the name for the executable) -# param isReleaseBuild should currently always be set to True (will later add debug build testing) -def deleteAppFromWinFW(workingDir, projectName, isReleaseBuild=True): - if not __isWinFirewallRunning__(): - return - # WinFirewall seems to run - hopefully no other - result = __configureFW__(workingDir, projectName, isReleaseBuild, False) - if result == 0: - test.log("Deleted %s from firewall" % projectName) - else: - test.warning("Could not delete %s as allowed program from win firewall" % (projectName)) diff --git a/tests/system/suite_debugger/tst_simple_debug/test.py b/tests/system/suite_debugger/tst_simple_debug/test.py index e6301f941c5..518ac1b23b9 100644 --- a/tests/system/suite_debugger/tst_simple_debug/test.py +++ b/tests/system/suite_debugger/tst_simple_debug/test.py @@ -36,7 +36,7 @@ def main(): for kit, config in availableConfigs: test.log("Selecting '%s' as build config" % config) verifyBuildConfig(kit, config, True, True, True) - # explicitly build before start debugging for adding the executable as allowed program to WinFW + # explicitly build before start debugging selectFromLocator("t rebuild", "Rebuild All Projects") waitForCompile(300000) if not checkCompile(): @@ -52,7 +52,6 @@ def main(): buildDir = os.path.join(str(waitForObject(":Qt Creator_Utils::BuildDirectoryLineEdit").text), "debug") switchViewTo(ViewConstants.EDIT) - allowAppThroughWinFW(buildDir, projectName, None) if not doSimpleDebugging(kit, config, expectedBreakpointsOrder): try: stopB = findObject(':Qt Creator.Stop_QToolButton') @@ -60,8 +59,6 @@ def main(): clickButton(stopB) except: pass - if platform.system() in ('Microsoft' 'Windows'): - deleteAppFromWinFW(buildDir, projectName, None) # close application output window of current run to avoid mixing older output on the next run ensureChecked(":Qt Creator_AppOutput_Core::Internal::OutputPaneToggleButton") clickButton(waitForObject("{type='CloseButton' unnamed='1' visible='1' " diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py index 42473264f7e..17ce84d7522 100644 --- a/tests/system/suite_tools/tst_git_clone/test.py +++ b/tests/system/suite_tools/tst_git_clone/test.py @@ -47,7 +47,7 @@ def verifyVersionControlView(targetDir, canceled): "Searching for target directory in clone log") test.verify(" ".join(["clone", "--progress", cloneUrl, cloneDir]) in vcsLog, "Searching for git parameters in clone log") - test.compare(canceled, " terminated abnormally" in vcsLog, + test.compare(canceled, " was canceled after " in vcsLog, "Searching for result in clone log") clickButton(waitForObject(":*Qt Creator.Clear_QToolButton"))