diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-11-01 15:31:19 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-11-01 15:31:19 +0100 |
commit | 04bd6e39c8991fcb89ab15728f622a5a3ae8f0b2 (patch) | |
tree | 0517ecde8091d1680651853a4a9d209c0636cffd | |
parent | c92c255d1043f11478a61c1caae4069e7ef47114 (diff) | |
parent | a1d22fd2f79afab8b2379f6d93bcb417b9c8e7d5 (diff) | |
download | qt-creator-04bd6e39c8991fcb89ab15728f622a5a3ae8f0b2.tar.gz |
Merge remote-tracking branch 'origin/4.11'
Conflicts:
share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp
Change-Id: I8ea57eba526ab830608fd928c28771c5441749f8
170 files changed, 2590 insertions, 524 deletions
diff --git a/dist/changes-4.11.0.md b/dist/changes-4.11.0.md index 8babf0c81e..a85f8e5c3d 100644 --- a/dist/changes-4.11.0.md +++ b/dist/changes-4.11.0.md @@ -18,6 +18,11 @@ you can check out from the public Git repository. For example: * Made update notification less intrusive and more informative (QTCREATORBUG-22817) * Made wizards remember user choices (QTCREATORBUG-16657) +## Help + +* Fixed that removing Qt version only unregistered its documentation after + restart (QTCREATORBUG-16631) + ## Editing * Added option to change line ending style via editor tool bar @@ -90,6 +95,7 @@ you can check out from the public Git repository. For example: * Fixed handling of boolean semantics (`OFF`, `NO`, `FALSE`, and so on) * Fixed `Build` > `Run CMake` (QTCREATORBUG-19704) * Fixed registering `CMake.app` from official installer on macOS +* Fixed code model issues when using precompiled headers (QTCREATORBUG-22888) ### Qbs @@ -106,6 +112,12 @@ you can check out from the public Git repository. For example: * Added option to remove directories directly from project tree (QTCREATORBUG-16575) * Added support for Framework paths (QTCREATORBUG-20099) +## Debugging + +### CDB + +* Fixed assigning negative values to variables (QTCREATORBUG-17269) + ## Analyzer * Added viewer for Chrome trace report files @@ -148,6 +160,10 @@ you can check out from the public Git repository. For example: * Added settings per project (QTCREATORBUG-16704) * Added option to run tests after successful build +### Boost + +* Fixed running multiple tests (QTCREATORBUG-23091) + ## Platforms ### Windows @@ -184,6 +200,7 @@ you can check out from the public Git repository. For example: * Fixed that it was not possible to add custom deployment steps (QTCREATORBUG-22977) ## Credits for these changes go to: + Aleksei German Alessandro Portale Andre Hartmann @@ -211,6 +228,9 @@ Miikka Heikkinen Milian Wolff Nikolai Kosjar Orgad Shaneh +Pasi Keränen +Richard Weickelt +Robert Löhning Sergey Levin Sona Kurazyan Tasuku Suzuki diff --git a/doc/images/icons/download-icon.png b/doc/images/icons/download-icon.png Binary files differnew file mode 100644 index 0000000000..59de1e81e9 --- /dev/null +++ b/doc/images/icons/download-icon.png diff --git a/doc/images/qtcreator-android-build-steps.png b/doc/images/qtcreator-android-build-steps.png Binary files differnew file mode 100644 index 0000000000..dda97e83cc --- /dev/null +++ b/doc/images/qtcreator-android-build-steps.png diff --git a/doc/images/qtcreator-android-certificate.png b/doc/images/qtcreator-android-certificate.png Binary files differindex 2b4d235549..1798a91eb7 100644 --- a/doc/images/qtcreator-android-certificate.png +++ b/doc/images/qtcreator-android-certificate.png diff --git a/doc/images/qtcreator-android-cmake-settings.png b/doc/images/qtcreator-android-cmake-settings.png Binary files differnew file mode 100644 index 0000000000..6776e4fcba --- /dev/null +++ b/doc/images/qtcreator-android-cmake-settings.png diff --git a/doc/images/qtcreator-android-deploy-configurations.png b/doc/images/qtcreator-android-deploy-configurations.png Binary files differindex b09cbce6de..c4602a8538 100644 --- a/doc/images/qtcreator-android-deploy-configurations.png +++ b/doc/images/qtcreator-android-deploy-configurations.png diff --git a/doc/images/qtcreator-android-manifest-editor.png b/doc/images/qtcreator-android-manifest-editor.png Binary files differindex 90fdb6a42b..67424baae3 100644 --- a/doc/images/qtcreator-android-manifest-editor.png +++ b/doc/images/qtcreator-android-manifest-editor.png diff --git a/doc/images/qtcreator-git-commit-actions.png b/doc/images/qtcreator-git-commit-actions.png Binary files differnew file mode 100644 index 0000000000..37295e48fc --- /dev/null +++ b/doc/images/qtcreator-git-commit-actions.png diff --git a/doc/images/qtcreator-options-android1.png b/doc/images/qtcreator-options-android1.png Binary files differindex b3806a361d..81a94cb5e4 100644 --- a/doc/images/qtcreator-options-android1.png +++ b/doc/images/qtcreator-options-android1.png diff --git a/doc/images/qtcreator-options-android2.png b/doc/images/qtcreator-options-android2.png Binary files differindex 176b2cd3a1..5289c4b1b0 100644 --- a/doc/images/qtcreator-options-android2.png +++ b/doc/images/qtcreator-options-android2.png diff --git a/doc/images/qtcreator-vcs-gitbranch.png b/doc/images/qtcreator-vcs-gitbranch.png Binary files differindex aae80201bc..f6a5586eac 100644 --- a/doc/images/qtcreator-vcs-gitbranch.png +++ b/doc/images/qtcreator-vcs-gitbranch.png diff --git a/doc/images/studio-curve-editor.png b/doc/images/studio-curve-editor.png Binary files differindex f1f82e0abe..cdb675c881 100644 --- a/doc/images/studio-curve-editor.png +++ b/doc/images/studio-curve-editor.png diff --git a/doc/images/studio-curve-picker.png b/doc/images/studio-curve-picker.png Binary files differdeleted file mode 100644 index 37f1af0a39..0000000000 --- a/doc/images/studio-curve-picker.png +++ /dev/null diff --git a/doc/images/studio-easing-curve-editor.png b/doc/images/studio-easing-curve-editor.png Binary files differnew file mode 100644 index 0000000000..57d70f86cd --- /dev/null +++ b/doc/images/studio-easing-curve-editor.png diff --git a/doc/images/studio-edit-keyframe.png b/doc/images/studio-edit-keyframe.png Binary files differnew file mode 100644 index 0000000000..446187d141 --- /dev/null +++ b/doc/images/studio-edit-keyframe.png diff --git a/doc/src/android/androiddev.qdoc b/doc/src/android/androiddev.qdoc index ac2a77a3fe..00737d5ef2 100644 --- a/doc/src/android/androiddev.qdoc +++ b/doc/src/android/androiddev.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -66,10 +66,10 @@ \note Android SDK Tools have issues with JDK versions later than 8. \li \l{http://www.gradle.org}{Gradle} for building application packages - for Android devices (APK). Gradle is delivered with Qt 5.9, and - later. Because Gradle scripts are not delivered with Android SDK - Tools since version 26.0.0, they are delivered with Qt 5.9 and - 5.6.3. + (APK) and app bundles (AAB) for Android devices. Gradle is delivered + with Qt 5.9, and later. Because Gradle scripts are not delivered + with Android SDK tools since version 26.0.0, they are delivered + with Qt 5.9 and 5.6.3. \note Using Ant to build APKs is no longer supported. @@ -77,6 +77,9 @@ by the \l{http://developer.android.com/tools/sdk/ndk/index.html} {Android NDK} from Google. + \note To develop with Qt 5.14.0 or later, you need Android NDK r20 + or later. + \li \l{http://developer.android.com/sdk/index.html}{Android SDK Tools} The following Android SDK packages and tools are required for @@ -167,7 +170,7 @@ \li In the \uicontrol {JDK location} field, add the path to the JDK. - You can use the \inlineimage download.png + Select the \inlineimage icons/download-icon.png (\uicontrol Download) button to go to the site where you can download the JDK. \QC checks the JDK installation and reports errors. @@ -175,9 +178,8 @@ \li In the \uicontrol {Android Settings} group, add paths to the Android NDK and SDK. - You can use the \inlineimage download.png - (\uicontrol Download) buttons to go to the sites where you can download - the Android NDK and SDK. + Select \inlineimage icons/download-icon.png + to go to the sites where you can download the Android NDK and SDK. The SDK Manager checks the Android NDK and SDK installations, reports errors, and offers to install the necessary packages. @@ -192,7 +194,8 @@ \li Select \uicontrol File > \uicontrol {New File or Project} > \uicontrol Application > \uicontrol {Qt Quick Application} > \uicontrol Choose, and - follow the instructions of the wizard. For more information, see + follow the instructions of the wizard to create a project. For more + information, see \if defined(qtcreator) \l{Creating Qt Quick Projects}. \else diff --git a/doc/src/android/deploying-android.qdoc b/doc/src/android/deploying-android.qdoc index 998cc7f210..7690b435a6 100644 --- a/doc/src/android/deploying-android.qdoc +++ b/doc/src/android/deploying-android.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -32,9 +32,19 @@ \title Deploying Applications to Android Devices - On Android, applications are distributed in a specially structured type of - ZIP package called an APK. \QC supports the following methods of deployment - for Android applications: + On Android, applications are distributed in specially structured types of + ZIP packages called Application Packages (APK) or Android App Bundles (AAB). + APK files can be downloaded to and executed on a device, whereas AAB is + intended to be interpreted by the Google Play store and is used to generate + APK files. + + \l{Qt for Android} has binaries for armv7a, arm64-v8a, x86, and x86-64. + To support several different ABIs in your application, build an AAB that + contains binaries for each of the ABIs. The Google Play store uses the + AAB to generate optimized APK packages for the devices issuing the download + request and automatically signs them with your publisher key. + + \QC supports the following methods of deployment for Android applications: \list @@ -44,6 +54,9 @@ The Ministro tool downloads the necessary Qt libraries from a repository of your choice. + \li Since Qt 5.14.0, as an app bundle (AAB), intended for distribution + in the Google Play store. + \endlist To specify settings for application packages, select \uicontrol Projects > @@ -137,6 +150,23 @@ the \uicontrol {Compile Output} pane. To view additional information, select the \uicontrol {Verbose output} check box. + \section3 Building AABs + + For testing the application locally, use the APK format, because + the package can be uploaded directly to the device and run. For + distribution to the Google Play store, create an AAB by selecting + the \uicontrol {Build .aab (Android App Bundle)} check box. + + When building with CMake, you can select the ABIs to build the application + for in the \uicontrol CMake settings: + + \image qtcreator-android-cmake-settings.png "CMake settings for building AABs" + + When building with qmake, you can select the ABIs in the \uicontrol ABIs + field in the \uicontrol {Build Steps}: + + \image qtcreator-android-build-steps.png "Android Build Steps" + \section3 Selecting API Level In the \uicontrol {Android build SDK} field, you can select the API level to use diff --git a/doc/src/debugger/creator-debugger-common.qdocinc b/doc/src/debugger/creator-debugger-common.qdocinc index 5437b0d2a5..e5366aa968 100644 --- a/doc/src/debugger/creator-debugger-common.qdocinc +++ b/doc/src/debugger/creator-debugger-common.qdocinc @@ -398,7 +398,7 @@ entry. You can enable tooltips in the main editor displaying this information. - For more information, see \l{Showing Tooltips in Debug Mode}. + For more information, see \l{See the value of variables in tooltips while debugging}. //! [debugger-qt-basic-objects] */ diff --git a/doc/src/howto/creator-only/creator-tips.qdoc b/doc/src/howto/creator-only/creator-how-tos.qdoc index 5e481b42f2..d210b00618 100644 --- a/doc/src/howto/creator-only/creator-tips.qdoc +++ b/doc/src/howto/creator-only/creator-how-tos.qdoc @@ -32,12 +32,41 @@ /*! \contentspage index.html \previouspage creator-faq.html - \page creator-tips.html + \page creator-how-tos.html \nextpage creator-known-issues.html - \title Tips and Tricks + \title How-tos - \section1 Switching Between Modes + How do I: + + \list + \li \l {Switch between modes} + \li \l {Move between open files} + \li \l {Switch to Edit mode} + \li \l {Find a specific setting} + \li \l {Open output panes} + \li \l {Find keyboard shortcuts} + \li \l {Run \QC from the command line} + \li \l {Show and hide sidebars} + \li \l {Move to symbols} + \li \l {Inspect signal-slot connections while debugging} + \li \l {Display low-level data in the debugger} + \li \l {See the value of variables in tooltips while debugging} + \li \l {Quickly locate files using the keyboard} + \li \l {Perform calculations} + \li \l {Jump to a function in QML code} + \li \l {Add a license header template for C++ code} + \li \l {Paste text from my clipboard history} + \li \l {Sort lines alphabetically} + \li \l {Enclose selected code in curly braces, parentheses, or double quotes} + \li \l {Select the enclosing block in C++} + \li \l {Add my own code snippets to the auto-complete menu} + \li \l {Quickly write down notes somewhere} + \li \l {Configure the amount of recent files shown} + \li \l {Search and replace across files using a regular expression} + \endlist + + \section1 Switch between modes \QC uses different modes for different purposes. You can quickly switch between these modes with the following keyboard shortcuts: @@ -55,7 +84,7 @@ For more information about \QC modes, see \l {Selecting Modes}. - \section1 Moving Between Open Files + \section1 Move between open files To quickly move between currently open files, press \key Ctrl+Tab. @@ -66,7 +95,7 @@ to jump to a symbol in the same file, you can jump back to your original location in that file by pressing \key {Alt+Left}. - \section1 Moving To the Edit Mode + \section1 Switch to Edit mode To move to the \uicontrol Edit mode and currently active file, press \key Esc. @@ -81,12 +110,12 @@ \endlist - \section1 Using the Filter in Options Dialog + \section1 Find a specific setting To find specific settings you require in \uicontrol{Tools} > \uicontrol{Options} use the filter located at the top left of the \uicontrol Options dialog box. - \section1 Opening Output Panes + \section1 Open output panes The output panes provide a list of errors and warnings encountered during a build, detailed output from the compiler, status of a program when it is @@ -112,7 +141,7 @@ For more information about output panes, see \l{Viewing Output}. - \section1 Using Keyboard Shortcuts + \section1 Find keyboard shortcuts \QC provides \l{Keyboard Shortcuts}{many useful keyboard shortcuts}. You can see the keyboard shortcut for a menu command in the menu @@ -121,7 +150,7 @@ To customize, import or export keyboard shortcuts, select \uicontrol Tools > \uicontrol Options > \uicontrol Environment > \uicontrol Keyboard. - \section1 Running \QC From Command Line + \section1 Run \QC from the command line You can launch \QC from command line using the name of an existing session or \c .pro file by giving the name as the command @@ -132,7 +161,7 @@ For more information, see \l{Using Command Line Options}. - \section1 Showing and Hiding Sidebars + \section1 Show and hide sidebars You can toggle the left and right sidebar in some \QC modes. @@ -147,7 +176,7 @@ For more information on using the sidebars, see \l {Browsing Project Contents}. - \section1 Moving To Symbols + \section1 Move to symbols To move straight to a symbol used in a project, select the symbol in the \uicontrol Editor toolbar drop-down menu. For more information on the editor @@ -163,7 +192,7 @@ cursor on the symbol and press \key {F2}. For more information, see \l{Moving to Symbol Definition or Declaration}. - \section1 Displaying Signals and Slots + \section1 Inspect signal-slot connections while debugging If an instance of a class is derived from QObject, and you would like to find all other objects connected to one of your object's slots using @@ -177,7 +206,7 @@ For more information about the \uicontrol{Locals} view, see \l{Local Variables and Function Parameters}. - \section1 Displaying Low Level Data + \section1 Display low-level data in the debugger If special debugging of Qt objects fails due to data corruption within the debugged objects, you can switch off the debugging helpers. When debugging @@ -193,7 +222,7 @@ \endlist - \section1 Showing Tooltips in Debug Mode + \section1 See the value of variables in tooltips while debugging To inspect the value of variables from the editor, you can turn on tooltips. Tooltips are hidden by default for performance reasons. @@ -218,7 +247,7 @@ select \uicontrol {Close Editor Tooltips} in the context menu in the \uicontrol {Locals} view. - \section1 Locating Files + \section1 Quickly locate files using the keyboard The \uicontrol Locator provides one of the easiest ways in \QC to browse through projects, files, classes, functions, documentation and file systems. @@ -230,7 +259,20 @@ For more information, see \l{Creating Locator Filters}. - \section1 Adding a License Header Template for C++ Code + \section1 Perform calculations + + Open the \uicontrol Locator with \key {Ctrl+K} and type =, followed by a space. + You can now do basic calculations, with options to copy the results to the clipboard + by navigating through the entries and pressing \key {Enter}. + + For more information, see \l{Executing JavaScript}. + + \section1 Jump to a function in QML code + + Open the \uicontrol Locator with \key {Ctrl+K} and type m, followed by a space. + You can now go directly to any QML method in the file. + + \section1 Add a license header template for C++ code A file containing a license header for C++ can be specified under \uicontrol{Tools > Options > C++ > License Template}. It may contain special @@ -250,16 +292,85 @@ \endlist - \section1 Pasting from Clipboard History + \section1 Paste text from my clipboard history \QC stores copied text in clipboard history. To retrieve clips from the history, press \key {Ctrl+Shift+V} until the clip appears. The number of clips in the history is fixed to 10. - \section1 Sorting Lines Alphabetically + \section1 Sort lines alphabetically To sort selected lines alphabetically, select \uicontrol Edit > \uicontrol Advanced > \uicontrol {Sort Selected Lines} or press \key {Alt+Shift+S} (or \key Ctrl+Shift+S on \macos). + \section1 Enclose selected code in curly braces, parentheses, or double quotes + + Press \key {Shift} and then the opening character. + + \list + \li Curly braces: \key {Shift+\{} + \li Parentheses: \key {Shift+(} + \li Double quotes: \key {Shift+"} + \endlist + + \section1 Select the enclosing block in C++ + + Press \key {Ctrl+U}. + + \section1 Add my own code snippets to the auto-complete menu + + You can add, modify, and remove snippets in the snippet editor. + To open the editor, select \uicontrol Tools > \uicontrol Options + > \uicontrol {Text Editor} > \uicontrol Snippets. + + For more information, see \l {Adding and Editing Snippets}. + + \section1 Quickly write down notes somewhere + + Select \uicontrol File > \uicontrol {New File or Project} > + \uicontrol {Files and Classes} > \uicontrol General > \uicontrol {Scratch Buffer}. + Alternatively, \key {Ctrl+N} can be used to open this dialog, which is + fully navigable via keyboard by using the up and down arrow keys and the + tab key. + + This creates a new empty text file and saves it to the temporary directory + on your machine. You can use it to write down notes without having to worry + about deleting the file afterwards. The operating system will eventually + remove the file automatically. If you want to keep the file, you can easily + save it as a new file somewhere else. If you accidentally close the file, + you can find it in the \uicontrol File > \uicontrol {Recent Files} menu. + + \section1 Configure the amount of recent files shown + + Select \uicontrol Tools > \uicontrol Options, and change the value of the + list under \uicontrol Environment > \uicontrol System + > \uicontrol {Maximum number of entries in "Recent Files"}. + + \section1 Search and replace across files using a regular expression + + As an example, say you want to replace equality checks (\c {foo == bar}) + with a function (\c {foo.equals(bar)}): + + \list 1 + \li Ensure that any work you have done is committed to version control, + as the changes cannot be undone. + \li Press \key {Ctrl+Shift+F} to bring up the \uicontrol {Advanced Find} + form. + \li Change the scope to whatever is appropriate for your search. + \li Under the \uicontrol {Search for} text field, select + the \uicontrol {Use regular expressions} check box. + \li Enter the following text in the \uicontrol {Search for} text field: + \badcode + if \((.*) == (.*)\) + \endcode + \li Press \uicontrol {Search & Replace} to see a list of search results. + \li In the \uicontrol {Replace with} text field, enter the following text: + \badcode + if (\1.strictlyEquals(\2)) + \endcode + \li Press \uicontrol Replace to replace all instances of the text. + \endlist + + For more information, see \l {Advanced Search}. */ diff --git a/doc/src/howto/creator-only/qtcreator-faq.qdoc b/doc/src/howto/creator-only/qtcreator-faq.qdoc index 712d81aeda..87bd22d00d 100644 --- a/doc/src/howto/creator-only/qtcreator-faq.qdoc +++ b/doc/src/howto/creator-only/qtcreator-faq.qdoc @@ -27,13 +27,13 @@ \contentspage index.html \previouspage creator-help.html \page creator-faq.html - \nextpage creator-tips.html + \nextpage creator-how-tos.html \title FAQ This section contains answers to some frequently asked questions about \QC. You might also find answers to your questions in the - \l{Known Issues} and \l{Tips and Tricks} sections, or the Troubleshooting + \l{Known Issues} and \l{How-tos} sections, or the Troubleshooting sections for a special area, such as \l{Troubleshooting Debugger}{debugging}. diff --git a/doc/src/howto/creator-ui.qdoc b/doc/src/howto/creator-ui.qdoc index adc38a0cf3..8e6a23b317 100644 --- a/doc/src/howto/creator-ui.qdoc +++ b/doc/src/howto/creator-ui.qdoc @@ -107,7 +107,7 @@ \section1 Useful Features For a list of useful \QC features described in other parts of the - documentation, see \l{Tips and Tricks}. + documentation, see \l{How-tos}. \endif \section1 Changing Languages @@ -404,6 +404,9 @@ \if defined(qtdesignstudio) \li \uicontrol {Asset Importer Error} - Errors and warnings encountered while importing assets from a design tool. + \else + \li \uicontrol Autotests - Errors and warnings encountered while running + tests. \endif \li \uicontrol {Build System} - Errors and warnings encountered during a diff --git a/doc/src/overview/creator-only/creator-help-overview.qdoc b/doc/src/overview/creator-only/creator-help-overview.qdoc index dd8c47dc25..fd16ed3e9f 100644 --- a/doc/src/overview/creator-only/creator-help-overview.qdoc +++ b/doc/src/overview/creator-only/creator-help-overview.qdoc @@ -53,7 +53,7 @@ Contains answers to some frequently asked questions about \QC. - \li \l{Tips and Tricks} + \li \l{How-tos} Lists useful \QC features. diff --git a/doc/src/overview/creator-only/creator-issues.qdoc b/doc/src/overview/creator-only/creator-issues.qdoc index 16c5263aee..bbbd71002f 100644 --- a/doc/src/overview/creator-only/creator-issues.qdoc +++ b/doc/src/overview/creator-only/creator-issues.qdoc @@ -31,7 +31,7 @@ /*! \contentspage index.html - \previouspage creator-tips.html + \previouspage creator-how-tos.html \page creator-known-issues.html \nextpage creator-glossary.html diff --git a/doc/src/projects/creator-only/creator-projects-build-systems.qdocinc b/doc/src/projects/creator-only/creator-projects-build-systems.qdocinc index e11cf0c340..b383c94e99 100644 --- a/doc/src/projects/creator-only/creator-projects-build-systems.qdocinc +++ b/doc/src/projects/creator-only/creator-projects-build-systems.qdocinc @@ -45,7 +45,7 @@ configuration. qmake is installed and configured when you install Qt. To use one of the other supported build systems, you need to set it up. - \l {CMake Manual}{CMake} is an alternative to qmake for automating the + \l {Build with CMake}{CMake} is an alternative to qmake for automating the generation of build configurations. For more information, see \l {Setting Up CMake}. diff --git a/doc/src/projects/creator-only/creator-projects-compilers.qdoc b/doc/src/projects/creator-only/creator-projects-compilers.qdoc index b91d5b7d9e..30d39dbffa 100644 --- a/doc/src/projects/creator-only/creator-projects-compilers.qdoc +++ b/doc/src/projects/creator-only/creator-projects-compilers.qdoc @@ -63,8 +63,9 @@ Windows applications on Windows. MinGW is distributed together with \QC and Qt installers for Windows. - \li Linux ICC (Intel C++ Compiler) is a group of C and C++ compilers - for Linux. + \li ICC (Intel C++ Compiler) is a group of C and C++ compilers. + Only the GCC-compatible variant, available for Linux and \macos, + is currently supported by \QC. \li Clang is a C, C++, Objective C, and Objective C++ front-end for the LLVM compiler for Windows, Linux, and \macos. @@ -87,7 +88,8 @@ \li \l{https://www.iar.com/iar-embedded-workbench/}{IAREW} is a group of C and C++ bare-metal compilers from the various IAR Embedded Workbench development environments. - \note Currently supported architectures are \c 8051, \c AVR, and \c ARM. + \note Currently supported architectures are \c 8051, \c AVR, \c ARM, + \c STM8, and \c MSP430. \li \l{https://www.keil.com}{KEIL} is a group of C and C++ bare-metal compilers from the various KEIL development environments. @@ -95,7 +97,7 @@ \li \l{https://sdcc.sourceforge.net}{SDCC} is a retargetable, optimizing C bare-metal compiler for various architectures. - \note Currently supported architecture is \c 8051. + \note Currently supported architectures are \c 8051 and \c STM8. \endlist diff --git a/doc/src/qtcreator-toc.qdoc b/doc/src/qtcreator-toc.qdoc index f0bd3f9e02..fb796ae8bf 100644 --- a/doc/src/qtcreator-toc.qdoc +++ b/doc/src/qtcreator-toc.qdoc @@ -231,7 +231,7 @@ \list \li \l{Using the Help Mode} \li \l{FAQ} - \li \l{Tips and Tricks} + \li \l{How-tos} \li \l{Known Issues} \li \l{Glossary} \li \l{Technical Support} diff --git a/doc/src/qtcreator.qdoc b/doc/src/qtcreator.qdoc index 5401ecc442..58db763d76 100644 --- a/doc/src/qtcreator.qdoc +++ b/doc/src/qtcreator.qdoc @@ -123,7 +123,7 @@ \list \li \l{Using the Help Mode} \li \l{FAQ} - \li \l{Tips and Tricks} + \li \l{How-tos} \li \l{Known Issues} \li \l{Glossary} \endlist diff --git a/doc/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc b/doc/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc index 6f8b571bf8..6b09066b87 100644 --- a/doc/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc +++ b/doc/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc @@ -73,7 +73,7 @@ The main view of the application displays an SVG bubble image that moves around the screen when you tilt the device. - To use \l{accelbubble/Bluebubble.svg}{Bluebubble.svg} in your project, + To use \e {Bluebubble.svg} in your project, copy it to the project directory (same subdirectory as the QML file). The image appears in \uicontrol Resources. You can also use any other image or a QML type, instead. @@ -140,9 +140,8 @@ \QC creates a reference to the Bubble type in \e Page1Form.ui.qml. - To check your code, you can compare \e Page1Form.ui.qml with the - \l{accelbubble/Page1Form.ui.qml}{Page1Form.ui.qml} example file and - \e Bubble.qml with the \l{accelbubble/Bubble.qml}{Bubble.qml} example file. + To check your code, you can compare your \e Page1Form.ui.qml and + \e {Bubble.qml} with the corresponding example files. The UI is now ready and you can switch to editing the \e Bubble.qml and \e main.qml files in the \uicontrol {Text Editor}, as described in the diff --git a/doc/src/qtquick/creator-only/creator-tutorial-create-qq-project.qdocinc b/doc/src/qtquick/creator-only/creator-tutorial-create-qq-project.qdocinc index b3f2bc67a1..04826f69fa 100644 --- a/doc/src/qtquick/creator-only/creator-tutorial-create-qq-project.qdocinc +++ b/doc/src/qtquick/creator-only/creator-tutorial-create-qq-project.qdocinc @@ -45,7 +45,7 @@ \l {Setting Up CMake}{CMake}, or \l {Setting Up Qbs}{Qbs}. \li In the \uicontrol {Qt Quick Controls Style} field, select one of - the predefined \l{Styling Qt Quick Controls 2}{UI styles} to use, + the predefined \l{Styling Qt Quick Controls}{UI styles} to use, and then select \uicontrol Next. \li Select \l{glossary-buildandrun-kit}{kits} for the platforms that diff --git a/doc/src/qtquick/creator-only/qtquick-app-tutorial.qdoc b/doc/src/qtquick/creator-only/qtquick-app-tutorial.qdoc index 55fe9f421c..0d93f62c9f 100644 --- a/doc/src/qtquick/creator-only/qtquick-app-tutorial.qdoc +++ b/doc/src/qtquick/creator-only/qtquick-app-tutorial.qdoc @@ -188,9 +188,9 @@ \endlist - To check your code, you can view \e Page1Form.ui.qml in the - \uicontrol {Text Editor} and compare it with the \l{transitions/Page1Form.ui.qml} - {Page1Form.ui.qml} example file. + To check your code, you can view your \e {Page1Form.ui.qml} file in the + \uicontrol {Text Editor} and compare it with the \e {Page1Form.ui.qml} + example file. The new project wizard adds boilerplate code to the \e Page1.qml file to create menu items and push buttons. Modify the boilerplate code by removing diff --git a/doc/src/qtquick/creator-only/qtquick-creating.qdoc b/doc/src/qtquick/creator-only/qtquick-creating.qdoc index d37992ed2e..1e633f803c 100644 --- a/doc/src/qtquick/creator-only/qtquick-creating.qdoc +++ b/doc/src/qtquick/creator-only/qtquick-creating.qdoc @@ -172,7 +172,7 @@ \l {Setting Up CMake}{CMake}, or \l {Setting Up Qbs}{Qbs}. \li In the \uicontrol {Qt Quick Controls Style} field, select one of - the predefined \l{Styling Qt Quick Controls 2}{UI styles} to use, + the predefined \l{Styling Qt Quick Controls}{UI styles} to use, and then select \uicontrol Next. \li Select the \uicontrol {Use Qt Virtual Keyboard} check box to add diff --git a/doc/src/qtquick/qtquick-components.qdoc b/doc/src/qtquick/qtquick-components.qdoc index d8327fd2f8..e7908915ff 100644 --- a/doc/src/qtquick/qtquick-components.qdoc +++ b/doc/src/qtquick/qtquick-components.qdoc @@ -458,7 +458,7 @@ user interfaces for \l{glossary-device}{devices}. Qt Quick Controls 2 achieve improved efficiency by employing a simplified - \l {Styling Qt Quick Controls 2}{styling architecture} when compared to + \l {Styling Qt Quick Controls}{styling architecture} when compared to Qt Quick Controls, on which the module is based. The visual editor reads the \c qtquickcontrols2.conf file that specifies the preferred style and some style-specific arguments. To change the style, select another style from diff --git a/doc/src/qtquick/qtquick-timeline.qdoc b/doc/src/qtquick/qtquick-timeline.qdoc index b3b40a8167..59eda721c0 100644 --- a/doc/src/qtquick/qtquick-timeline.qdoc +++ b/doc/src/qtquick/qtquick-timeline.qdoc @@ -199,12 +199,15 @@ To remove all the changes you recorded for a property, right-click the property name on the timeline and select \uicontrol {Remove Property}. - Keyframes a marked on the timeline by using markers of different colors and + Keyframes are marked on the timeline by using markers of different colors and shapes, depending on whether they are active or inactive or whether you have applied easing curves to them, for example. - To edit the value of the selected keyframe, select - \uicontrol {Edit Value for Keyframe} in the context menu. + To edit the value of a keyframe, double-click a keyframe marker or select + \uicontrol {Edit Keyframe} in the context menu. In the \uicontrol Frame + field, you can set the frame and the value: + + \image studio-edit-keyframe.png "Edit Keyframe dialog" You can copy the keyframes from the keyframe track for an item and paste them to the keyframe track of another item. To copy all @@ -241,13 +244,14 @@ components can appear to pick up speed, slow down, or bounce back at the end of the animation. By default, the animations you specify on the timeline are \e linear, which means that they move from the beginning to - the end at a constant speed. You can use the \e {curve picker} to edit the - easing curve between two keyframes. You can also use the more advanced - \e {curve editor} to edit the curves for the whole animation. + the end at a constant speed. You can use the \uicontrol {Easing Curve Editor} + to edit the easing curve between two keyframes. You can also use the more + advanced \uicontrol {Curve Editor (C)} to edit the curves for the whole + animation. \section2 Attaching Easing Curves to Keyframes - \image studio-curve-picker.png + \image studio-easing-curve-editor.png "Easing Curve Editor" You can use the preset curves or modify them by dragging the curve handlers around. You can add points to the curve and drag them and the point handlers @@ -255,22 +259,21 @@ custom curve. For more information about easing curve types, see the documentation for \l [QML] {PropertyAnimation}{easing curves}. - To zoom into and out of the easing curve picker, use the mouse roller. To + To zoom into and out of the easing curve editor, use the mouse roller. To reset the zoom factor, right-click in the picker and select \uicontrol {Reset Zoom}. To attach easing curves to keyframes: \list 1 - \li Select a keyframe on the timeline. - \li Select \uicontrol {Curve Picker (C)} on the toolbar, or press - \key C to open the curve picker. + \li Right-click a keyframe on the timeline and select + \uicontrol {Easing Curve Editor} in the context menu. \li Select an easing curve in the \uicontrol Presets tab. \li In the \uicontrol {Duration (ms)} field, select the duration of the easing function in milliseconds. \li Select \uicontrol Preview to preview the curve. \li Select \uicontrol OK to attach the easing curve to the keyframe - and to close the curve picker. + and to close the easing curve editor. \endlist When you attach easing curves to keyframes, the shape of the keyframe @@ -283,8 +286,8 @@ To customize easing curves: \list 1 - \li In the curve picker, select an easing curve in the - \uicontrol Presets tab. + \li In the \uicontrol {Easing Curve Editor}, select an easing curve in + the \uicontrol Presets tab. \li Drag the curve handlers to modify the curve. \li Right-click in the editor, and select \uicontrol {Add Point} to add points to the curve. @@ -297,7 +300,7 @@ \uicontrol Custom tab. \endlist - To paste easing curve definitions to the curve picker as text, select + To paste easing curve definitions to the easing curve editor as text, select the \uicontrol Text tab. \section1 Editing Animation Curves @@ -307,9 +310,9 @@ modify the curve. You can modify the appearance of the curve in the style editor. - You can also edit easing curves that you added with the curve picker. + You can also edit easing curves that you added with the easing curve editor. - \image studio-curve-editor.png + \image studio-curve-editor.png "Curve Editor" To edit animation curves: diff --git a/doc/src/vcs/creator-vcs-git.qdoc b/doc/src/vcs/creator-vcs-git.qdoc index 8705df4939..ec6b1a2ebe 100644 --- a/doc/src/vcs/creator-vcs-git.qdoc +++ b/doc/src/vcs/creator-vcs-git.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -224,6 +224,13 @@ branch is shown in bold and underlined in the list of branches in the \uicontrol {Git Branches} sidebar view. + \image qtcreator-vcs-gitbranch.png "Git Branches sidebar view" + + Old entries and tags are filtered out of the list of branches + by default. To include them, select \inlineimage filtericon.png + (\uicontrol {Filter Tree}), and then select + \uicontrol {Include Old Entries} and \uicontrol {Include Tags}. + If you checked out a specific commit, the list of branches displays a \e {Detached HEAD} entry. @@ -233,8 +240,6 @@ To refresh the list of branches, click \inlineimage reload_gray.png (\uicontrol Refresh). - \image qtcreator-vcs-gitbranch.png "Git Branches sidebar view" - The following operations are supported in the context-menu for a branch: \table @@ -249,7 +254,8 @@ \li Remove a local branch. You cannot delete remote branches. \row \li \uicontrol Rename - \li Rename a local branch. You cannot rename remote branches. + \li Rename a local branch or a tag. You cannot rename remote + branches. \row \li \uicontrol{Checkout} \li Check out the selected branch and make it current. You can stash @@ -302,12 +308,12 @@ \li Description \row \li \uicontrol{Fetch} - \li Fetches all the branches and changes information from a + \li Fetch all the branches and changes information from a specific remote repository, or from all remotes if applied to \uicontrol {Remote Branches}. \row \li \uicontrol{Manage Remotes} - \li Opens the \uicontrol Remotes dialog. + \li Open the \uicontrol Remotes dialog. \endtable \section3 Configuring Merge Tools @@ -357,11 +363,33 @@ To browse a directory or the commit history and to apply actions on the commits, select \uicontrol Tools > \uicontrol Git > - \uicontrol {Actions on Commits}. You can checkout, revert, or cherry-pick - commits or view them in the diff editor. + \uicontrol {Actions on Commits}. \image creator-git-commit-actions.png "Select a Git Commit dialog" + You can apply the following actions on commits: + + \table + \header + \li Menu Item + \li Description + \row + \li \uicontrol Archive + \li Package the commit as a ZIP or tarball. + \row + \li \uicontrol Checkout + \li Check out the change in a headless state. + \row + \li \uicontrol {Cherry Pick} + \li Cherry-pick the selected change to the local repository. + \row + \li \uicontrol Revert + \li Revert back to the state of the last commit. + \row + \li \uicontrol Show + \li Show the commit in the diff editor. + \endtable + \section1 Initializing Git Repositories To start controlling a project directory that is currently not under diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh index 1b312b0820..47c7613002 100755 --- a/scripts/deployqtHelper_mac.sh +++ b/scripts/deployqtHelper_mac.sh @@ -56,6 +56,19 @@ if [ ! -d "$designerDestDir" ]; then done fi +# collect 3d assetimporter plugins +assetimporterDestDir="$app_path/Contents/PlugIns/assetimporters" +assetimporterSrcDir="$plugin_src/assetimporters" +if [ -d "$assetimporterSrcDir" ]; then + if [ ! -d "$assetimporterDestDir" ]; then + echo "- Copying 3d assetimporter plugins" + mkdir -p "$assetimporterDestDir" + for plugin in "$assetimporterSrcDir"/*.dylib; do + cp "$plugin" "$assetimporterDestDir"/ || exit 1 + done + fi +fi + # copy Qt Quick 1 imports importsDir="$app_path/Contents/Imports/qtquick1" if [ -d "$quick1_src" ]; then diff --git a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h index 5be50903df..3428944f68 100644 --- a/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h +++ b/share/qtcreator/qml/qmlpuppet/commands/valueschangedcommand.h @@ -39,7 +39,7 @@ class ValuesChangedCommand friend bool operator ==(const ValuesChangedCommand &first, const ValuesChangedCommand &second); public: - enum TransactionOption { Start, End, None }; + enum TransactionOption { Start = 1, End = 2, None = 0 }; ValuesChangedCommand(); explicit ValuesChangedCommand(const QVector<PropertyValueContainer> &valueChangeVector); diff --git a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp index 19265df035..c460bbc712 100644 --- a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp +++ b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.cpp @@ -74,12 +74,29 @@ TypeName PropertyValueContainer::dynamicTypeName() const return m_dynamicTypeName; } +// The reflection flag indicates that a property change notification +// is reflected. This means that the notification is the reaction to a +// property change original done by the puppet itself. +// In the Qt5InformationNodeInstanceServer such notification are +// therefore ignored. + +void PropertyValueContainer::setReflectionFlag(bool b) +{ + m_isReflected = b; +} + +bool PropertyValueContainer::isReflected() const +{ + return m_isReflected; +} + QDataStream &operator<<(QDataStream &out, const PropertyValueContainer &container) { out << container.instanceId(); out << container.name(); out << container.value(); out << container.dynamicTypeName(); + out << container.isReflected(); return out; } @@ -90,6 +107,7 @@ QDataStream &operator>>(QDataStream &in, PropertyValueContainer &container) in >> container.m_name; in >> container.m_value; in >> container.m_dynamicTypeName; + in >> container.m_isReflected; return in; } @@ -99,7 +117,8 @@ bool operator ==(const PropertyValueContainer &first, const PropertyValueContain return first.m_instanceId == second.m_instanceId && first.m_name == second.m_name && first.m_value == second.m_value - && first.m_dynamicTypeName == second.m_dynamicTypeName; + && first.m_dynamicTypeName == second.m_dynamicTypeName + && first.m_isReflected == second.m_isReflected; } bool operator <(const PropertyValueContainer &first, const PropertyValueContainer &second) diff --git a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h index 4d30f3fb7e..8770355cfd 100644 --- a/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h +++ b/share/qtcreator/qml/qmlpuppet/container/propertyvaluecontainer.h @@ -50,12 +50,15 @@ public: QVariant value() const; bool isDynamic() const; TypeName dynamicTypeName() const; + void setReflectionFlag(bool b); + bool isReflected() const; private: qint32 m_instanceId; PropertyName m_name; QVariant m_value; TypeName m_dynamicTypeName; + bool m_isReflected = false; }; QDataStream &operator<<(QDataStream &out, const PropertyValueContainer &container); diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml index dc2fee6454..0176a55dfa 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Arrow.qml @@ -30,12 +30,12 @@ import MouseArea3D 1.0 Model { id: arrow rotationOrder: Node.XYZr - source: "meshes/Arrow.mesh" + source: "meshes/arrow.mesh" property View3D view3D property alias color: material.emissiveColor property Node targetNode: null - property bool isDragging: false + property bool dragging: false readonly property bool hovering: mouseAreaYZ.hovering || mouseAreaXZ.hovering @@ -43,10 +43,11 @@ Model { property var _targetStartPos signal positionCommit() + signal positionMove() materials: DefaultMaterial { id: material - emissiveColor: mouseAreaFront.hovering ? "white" : Qt.rgba(1.0, 0.0, 0.0, 1.0) + emissiveColor: "white" lighting: DefaultMaterial.NoLighting } @@ -59,7 +60,7 @@ Model { _pointerPosPressed = mouseArea.mapPositionToScene(maskedPosition); var sp = targetNode.scenePosition; _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); - isDragging = true; + dragging = true; } function posInParent(mouseArea, pointerPosition) @@ -85,6 +86,7 @@ Model { return; targetNode.position = posInParent(mouseArea, pointerPosition); + arrow.positionMove(); } function handleReleased(mouseArea, pointerPosition) @@ -93,7 +95,7 @@ Model { return; targetNode.position = posInParent(mouseArea, pointerPosition); - isDragging = false; + dragging = false; arrow.positionCommit(); } @@ -104,7 +106,7 @@ Model { y: -1.5 width: 12 height: 3 - rotation: Qt.vector3d(0, 90, 0) + rotation: Qt.vector3d(0, 0, 90) grabsMouse: targetNode onPressed: arrow.handlePressed(mouseAreaYZ, pointerPosition) onDragged: arrow.handleDragged(mouseAreaYZ, pointerPosition) @@ -118,12 +120,11 @@ Model { y: -1.5 width: 12 height: 3 - rotation: Qt.vector3d(90, 90, 0) + rotation: Qt.vector3d(0, 90, 90) grabsMouse: targetNode onPressed: arrow.handlePressed(mouseAreaXZ, pointerPosition) onDragged: arrow.handleDragged(mouseAreaXZ, pointerPosition) onReleased: arrow.handleReleased(mouseAreaXZ, pointerPosition) } - } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml index 2e8425016d..9ffd3aa85b 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/AutoScaleHelper.qml @@ -39,11 +39,17 @@ Node { onSceneTransformChanged: updateScale() onAutoScaleChanged: updateScale() + Connections { target: view3D.camera onSceneTransformChanged: updateScale() } + Connections { + target: designStudioNativeCameraControlHelper + onOverlayUpdateNeeded: updateScale() + } + function getScale(baseScale) { return Qt.vector3d(baseScale.x * relativeScale, baseScale.y * relativeScale, diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml new file mode 100644 index 0000000000..14e45951ae --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/CameraGizmo.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +IconGizmo { + id: cameraGizmo + + iconSource: "qrc:///qtquickplugin/mockfiles/images/camera-pick-icon.png" + gizmoModel.source: "#Cube" + gizmoModel.materials: [ + DefaultMaterial { + id: defaultMaterial + emissiveColor: "blue" + lighting: DefaultMaterial.NoLighting + } + ] +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml index a0a9c0e599..e19e75acb8 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/EditView3D.qml @@ -44,23 +44,65 @@ Window { property Node selectedNode: null + property var lightGizmos: [] + property var cameraGizmos: [] + signal objectClicked(var object) signal commitObjectPosition(var object) + signal moveObjectPosition(var object) function selectObject(object) { selectedNode = object; } + function emitObjectClicked(object) { + selectObject(object); + objectClicked(object); + } + + function addLightGizmo(obj) + { + var component = Qt.createComponent("LightGizmo.qml"); + if (component.status === Component.Ready) { + var gizmo = component.createObject(overlayScene, + {"view3D": overlayView, "targetNode": obj}); + lightGizmos[lightGizmos.length] = gizmo; + gizmo.selected.connect(emitObjectClicked); + } + } + + function addCameraGizmo(obj) + { + var component = Qt.createComponent("CameraGizmo.qml"); + if (component.status === Component.Ready) { + var gizmo = component.createObject(overlayScene, + {"view3D": overlayView, "targetNode": obj}); + cameraGizmos[cameraGizmos.length] = gizmo; + gizmo.selected.connect(emitObjectClicked); + } + } + + // Work-around the fact that the projection matrix for the camera is not calculated until + // the first frame is rendered, so any initial calls to mapFrom3DScene() will fail. + Component.onCompleted: designStudioNativeCameraControlHelper.requestOverlayUpdate(); + + onWidthChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate(); + onHeightChanged: designStudioNativeCameraControlHelper.requestOverlayUpdate(); + Node { id: overlayScene - Camera { - id: overlayCamera - projectionMode: usePerspectiveCheckbox.checked ? Camera.Perspective - : Camera.Orthographic - clipFar: editCamera.clipFar - position: editCamera.position - rotation: editCamera.rotation + PerspectiveCamera { + id: overlayPerspectiveCamera + clipFar: editPerspectiveCamera.clipFar + position: editPerspectiveCamera.position + rotation: editPerspectiveCamera.rotation + } + + OrthographicCamera { + id: overlayOrthoCamera + position: editOrthoCamera.position + rotation: editOrthoCamera.rotation } MoveGizmo { @@ -70,14 +112,12 @@ Window { targetNode: viewWindow.selectedNode position: viewWindow.selectedNode ? viewWindow.selectedNode.scenePosition : Qt.vector3d(0, 0, 0) - rotation: globalControl.checked || !viewWindow.selectedNode - ? Qt.vector3d(0, 0, 0) - : viewWindow.selectedNode.sceneRotation - + globalOrientation: globalControl.checked visible: selectedNode view3D: overlayView onPositionCommit: viewWindow.commitObjectPosition(selectedNode) + onPositionMove: viewWindow.moveObjectPosition(selectedNode) } AutoScaleHelper { @@ -97,15 +137,14 @@ Window { onTapped: { var pickResult = editView.pick(eventPoint.scenePosition.x, eventPoint.scenePosition.y); - viewWindow.objectClicked(pickResult.objectHit); - selectObject(pickResult.objectHit); + emitObjectClicked(pickResult.objectHit); } } View3D { id: editView anchors.fill: parent - camera: editCamera + camera: usePerspective ? editPerspectiveCamera : editOrthoCamera Node { id: mainSceneHelpers @@ -119,15 +158,21 @@ Window { PointLight { id: pointLight visible: showEditLight - position: editCamera.position + position: usePerspective ? editPerspectiveCamera.position + : editOrthoCamera.position } - Camera { - id: editCamera + PerspectiveCamera { + id: editPerspectiveCamera y: 200 z: -300 clipFar: 100000 - projectionMode: usePerspective ? Camera.Perspective : Camera.Orthographic + } + + OrthographicCamera { + id: editOrthoCamera + y: 200 + z: -300 } } } @@ -135,7 +180,7 @@ Window { View3D { id: overlayView anchors.fill: parent - camera: overlayCamera + camera: usePerspective ? overlayPerspectiveCamera : overlayOrthoCamera scene: overlayScene } @@ -145,7 +190,7 @@ Window { targetView: overlayView offsetX: 0 offsetY: 45 - visible: moveGizmo.isDragging + visible: moveGizmo.dragging Rectangle { color: "white" @@ -204,7 +249,7 @@ Window { CheckBox { id: globalControl checked: true - text: qsTr("Use global orientation") + text: qsTr("Use Global Orientation") onCheckedChanged: cameraControl.forceActiveFocus() } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml new file mode 100644 index 0000000000..56bec4ae0c --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/IconGizmo.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +Node { + id: iconGizmo + + property View3D view3D + property bool highlightOnHover: true + property Node targetNode: null + + property alias gizmoModel: gizmoModel + property alias iconSource: iconImage.source + + signal positionCommit() + signal selected(Node node) + + position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0) + rotation: targetNode ? targetNode.sceneRotation : Qt.vector3d(0, 0, 0) + visible: targetNode ? targetNode.visible : false + + Model { + id: gizmoModel + scale: Qt.vector3d(0.05, 0.05, 0.05) + visible: iconGizmo.visible + } + Overlay2D { + id: gizmoLabel + targetNode: gizmoModel + targetView: view3D + offsetX: 0 + offsetY: 0 + visible: iconGizmo.visible && !isBehindCamera + parent: view3D + + Rectangle { + width: 24 + height: 24 + x: -width / 2 + y: -height + color: "transparent" + border.color: "#7777ff" + border.width: highlightOnHover && iconMouseArea.containsMouse ? 2 : 0 + radius: 5 + Image { + id: iconImage + anchors.fill: parent + MouseArea { + id: iconMouseArea + anchors.fill: parent + onClicked: selected(targetNode) + hoverEnabled: highlightOnHover + } + } + } + } +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml new file mode 100644 index 0000000000..d3a5932b39 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/LightGizmo.qml @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick3D 1.0 + +IconGizmo { + id: lightGizmo + + iconSource: "qrc:///qtquickplugin/mockfiles/images/light-pick-icon.png" + gizmoModel.source: "#Sphere" + gizmoModel.materials: [ + DefaultMaterial { + id: defaultMaterial + emissiveColor: "yellow" + lighting: DefaultMaterial.NoLighting + } + ] +} diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml index 73b80018a9..7ad5a2a011 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/MoveGizmo.qml @@ -25,56 +25,131 @@ import QtQuick 2.0 import QtQuick3D 1.0 +import MouseArea3D 1.0 Node { - id: arrows + id: moveGizmo property View3D view3D property bool highlightOnHover: false property Node targetNode: null - readonly property bool isDragging: arrowX.isDragging || arrowY.isDragging || arrowZ.isDragging + property bool globalOrientation: true + readonly property bool dragging: arrowX.dragging || arrowY.dragging || arrowZ.dragging + || centerMouseArea.dragging - scale: Qt.vector3d(5, 5, 5) + signal positionCommit() + signal positionMove() - property alias arrowX: arrowX - property alias arrowY: arrowY - property alias arrowZ: arrowZ + Node { + rotation: globalOrientation || !targetNode ? Qt.vector3d(0, 0, 0) : targetNode.sceneRotation - signal positionCommit() + Arrow { + id: arrowX + objectName: "Arrow X" + rotation: Qt.vector3d(0, 0, -90) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) + : Qt.rgba(1, 0, 0, 1) + view3D: moveGizmo.view3D - Arrow { - id: arrowX - objectName: "Arrow X" - rotation: Qt.vector3d(0, -90, 0) - targetNode: arrows.targetNode - color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(1, 0, 0, 1)) - : Qt.rgba(1, 0, 0, 1) - view3D: arrows.view3D + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } - onPositionCommit: arrows.positionCommit() - } + Arrow { + id: arrowY + objectName: "Arrow Y" + rotation: Qt.vector3d(0, 0, 0) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) + : Qt.rgba(0, 0, 1, 1) + view3D: moveGizmo.view3D + + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } - Arrow { - id: arrowY - objectName: "Arrow Y" - rotation: Qt.vector3d(90, 0, 0) - targetNode: arrows.targetNode - color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0, 1, 1)) - : Qt.rgba(0, 0, 1, 1) - view3D: arrows.view3D + Arrow { + id: arrowZ + objectName: "Arrow Z" + rotation: Qt.vector3d(90, 0, 0) + targetNode: moveGizmo.targetNode + color: highlightOnHover && (hovering || dragging) ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) + : Qt.rgba(0, 0.6, 0, 1) + view3D: moveGizmo.view3D + + onPositionCommit: moveGizmo.positionCommit() + onPositionMove: moveGizmo.positionMove() + } - onPositionCommit: arrows.positionCommit() } - Arrow { - id: arrowZ - objectName: "Arrow Z" - rotation: Qt.vector3d(0, 180, 0) - targetNode: arrows.targetNode - color: highlightOnHover && hovering ? Qt.lighter(Qt.rgba(0, 0.6, 0, 1)) - : Qt.rgba(0, 0.6, 0, 1) - view3D: arrows.view3D + Model { + id: centerBall + + source: "#Sphere" + scale: Qt.vector3d(0.024, 0.024, 0.024) + materials: DefaultMaterial { + id: material + emissiveColor: highlightOnHover + && (centerMouseArea.hovering || centerMouseArea.dragging) + ? Qt.lighter(Qt.rgba(0.5, 0.5, 0.5, 1)) + : Qt.rgba(0.5, 0.5, 0.5, 1) + lighting: DefaultMaterial.NoLighting + } + + MouseArea3D { + id: centerMouseArea + view3D: moveGizmo.view3D + x: -60 + y: -60 + width: 120 + height: 120 + rotation: view3D.camera.rotation + grabsMouse: moveGizmo.targetNode + priority: 1 + + property var _pointerPosPressed + property var _targetStartPos + + function posInParent(pointerPosition) + { + var scenePointerPos = mapPositionToScene(pointerPosition); + var sceneRelativeDistance = Qt.vector3d( + scenePointerPos.x - _pointerPosPressed.x, + scenePointerPos.y - _pointerPosPressed.y, + scenePointerPos.z - _pointerPosPressed.z); + + var newScenePos = Qt.vector3d( + _targetStartPos.x + sceneRelativeDistance.x, + _targetStartPos.y + sceneRelativeDistance.y, + _targetStartPos.z + sceneRelativeDistance.z); + + return moveGizmo.targetNode.parent.mapPositionFromScene(newScenePos); + } + + onPressed: { + if (!moveGizmo.targetNode) + return; + + _pointerPosPressed = mapPositionToScene(pointerPosition); + var sp = moveGizmo.targetNode.scenePosition; + _targetStartPos = Qt.vector3d(sp.x, sp.y, sp.z); + } + onDragged: { + if (!moveGizmo.targetNode) + return; + + moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.positionMove(); + } + onReleased: { + if (!moveGizmo.targetNode) + return; - onPositionCommit: arrows.positionCommit() + moveGizmo.targetNode.position = posInParent(pointerPosition); + moveGizmo.positionCommit(); + } + } } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml index 7e1e231133..1392c60cb2 100644 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/Overlay2D.qml @@ -34,6 +34,8 @@ Item { property real offsetX: 0 property real offsetY: 0 + property bool isBehindCamera + onTargetNodeChanged: updateOverlay() Connections { @@ -46,13 +48,20 @@ Item { onSceneTransformChanged: updateOverlay() } + Connections { + target: designStudioNativeCameraControlHelper + onOverlayUpdateNeeded: updateOverlay() + } + function updateOverlay() { - var scenePos = targetNode.scenePosition; + var scenePos = targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0); var scenePosWithOffset = Qt.vector3d(scenePos.x + offsetX, scenePos.y + offsetY, scenePos.z); - var viewPos = targetView.mapFrom3DScene(scenePosWithOffset); + var viewPos = targetView ? targetView.mapFrom3DScene(scenePosWithOffset) + : Qt.vector3d(0, 0, 0); root.x = viewPos.x; root.y = viewPos.y; - root.z = 100000 - viewPos.z; // flip left-handed to right-handed + + isBehindCamera = viewPos.z <= 0; } } diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon.png Binary files differnew file mode 100644 index 0000000000..47610f5450 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon@2x.png Binary files differnew file mode 100644 index 0000000000..769934ae01 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/camera-pick-icon@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon.png Binary files differnew file mode 100644 index 0000000000..b6ac242cbd --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon@2x.png b/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon@2x.png Binary files differnew file mode 100644 index 0000000000..d3b041a604 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/images/light-pick-icon@2x.png diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh Binary files differdeleted file mode 100644 index f872b5e008..0000000000 --- a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/Arrow.mesh +++ /dev/null diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/arrow.mesh b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/arrow.mesh Binary files differnew file mode 100644 index 0000000000..be5f4df3b8 --- /dev/null +++ b/share/qtcreator/qml/qmlpuppet/mockfiles/meshes/arrow.mesh diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp index c05e8230bf..d681e10698 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.cpp @@ -30,10 +30,14 @@ namespace Internal { CameraControlHelper::CameraControlHelper() : QObject() { - m_timer.setInterval(16); - m_timer.setSingleShot(false); - QObject::connect(&m_timer, &QTimer::timeout, + m_inputUpdateTimer.setInterval(16); + QObject::connect(&m_inputUpdateTimer, &QTimer::timeout, this, &CameraControlHelper::handleUpdateTimer); + + m_overlayUpdateTimer.setInterval(16); + m_overlayUpdateTimer.setSingleShot(true); + QObject::connect(&m_overlayUpdateTimer, &QTimer::timeout, + this, &CameraControlHelper::overlayUpdateNeeded); } bool CameraControlHelper::enabled() @@ -49,11 +53,17 @@ void CameraControlHelper::handleUpdateTimer() void CameraControlHelper::setEnabled(bool enabled) { if (enabled) - m_timer.start(); + m_inputUpdateTimer.start(); else - m_timer.stop(); + m_inputUpdateTimer.stop(); m_enabled = enabled; } +void CameraControlHelper::requestOverlayUpdate() +{ + if (!m_overlayUpdateTimer.isActive()) + m_overlayUpdateTimer.start(); +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h index 87ef1025ff..be00596ce8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/cameracontrolhelper.h @@ -41,16 +41,20 @@ public: bool enabled(); void setEnabled(bool enabled); + Q_INVOKABLE void requestOverlayUpdate(); + public slots: void handleUpdateTimer(); signals: void updateInputs(); void enabledChanged(bool enabled); + void overlayUpdateNeeded(); private: bool m_enabled = false; - QTimer m_timer; + QTimer m_inputUpdateTimer; + QTimer m_overlayUpdateTimer; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp index e3ec5c704b..4c1fdcc78e 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.cpp @@ -80,6 +80,11 @@ qreal MouseArea3D::height() const return m_height; } +int MouseArea3D::priority() const +{ + return m_priority; +} + void MouseArea3D::setView3D(QQuick3DViewport *view3D) { if (m_view3D == view3D) @@ -134,6 +139,15 @@ void MouseArea3D::setHeight(qreal height) emit heightChanged(height); } +void MouseArea3D::setPriority(int level) +{ + if (m_priority == level) + return; + + m_priority = level; + emit priorityChanged(level); +} + void MouseArea3D::componentComplete() { if (!m_view3D) { @@ -193,51 +207,94 @@ QVector3D MouseArea3D::getMousePosInPlane(const QPointF &mousePosInView) const bool MouseArea3D::eventFilter(QObject *, QEvent *event) { + if (m_grabsMouse && s_mouseGrab && s_mouseGrab != this + && (m_priority <= s_mouseGrab->m_priority || s_mouseGrab->m_dragging)) { + return false; + } + + auto mouseOnTopOfMouseArea = [this](const QVector3D &mousePosInPlane) -> bool { + return !qFuzzyCompare(mousePosInPlane.z(), -1) + && mousePosInPlane.x() >= float(m_x) + && mousePosInPlane.x() <= float(m_x + m_width) + && mousePosInPlane.y() >= float(m_y) + && mousePosInPlane.y() <= float(m_y + m_height); + }; + switch (event->type()) { + case QEvent::MouseButtonPress: { + auto const mouseEvent = static_cast<QMouseEvent *>(event); + if (mouseEvent->button() == Qt::LeftButton) { + m_mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); + if (mouseOnTopOfMouseArea(m_mousePosInPlane)) { + setDragging(true); + emit pressed(m_mousePosInPlane); + if (m_grabsMouse) { + if (s_mouseGrab && s_mouseGrab != this) { + s_mouseGrab->setDragging(false); + s_mouseGrab->setHovering(false); + } + s_mouseGrab = this; + setHovering(true); + } + event->accept(); + return true; + } + } + break; + } + case QEvent::MouseButtonRelease: { + auto const mouseEvent = static_cast<QMouseEvent *>(event); + if (mouseEvent->button() == Qt::LeftButton) { + if (m_dragging) { + QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); + if (qFuzzyCompare(mousePosInPlane.z(), -1)) + mousePosInPlane = m_mousePosInPlane; + setDragging(false); + emit released(mousePosInPlane); + if (m_grabsMouse) { + if (s_mouseGrab && s_mouseGrab != this) { + s_mouseGrab->setDragging(false); + s_mouseGrab->setHovering(false); + } + if (mouseOnTopOfMouseArea(mousePosInPlane)) { + s_mouseGrab = this; + setHovering(true); + } else { + s_mouseGrab = nullptr; + setHovering(false); + } + } + event->accept(); + return true; + } + } + break; + } + case QEvent::MouseMove: case QEvent::HoverMove: { - if (m_grabsMouse && s_mouseGrab && s_mouseGrab != this) - break; - auto const mouseEvent = static_cast<QMouseEvent *>(event); const QVector3D mousePosInPlane = getMousePosInPlane(mouseEvent->pos()); - if (qFuzzyCompare(mousePosInPlane.z(), -1)) - break; - - const bool mouseOnTopOfMouseArea = - mousePosInPlane.x() >= float(m_x) && - mousePosInPlane.x() <= float(m_x + m_width) && - mousePosInPlane.y() >= float(m_y) && - mousePosInPlane.y() <= float(m_y + m_height); + const bool hasMouse = mouseOnTopOfMouseArea(mousePosInPlane); - const bool buttonPressed = QGuiApplication::mouseButtons().testFlag(Qt::LeftButton); + setHovering(hasMouse); - // The filter will detect a mouse press on the view, but not a mouse release, since the - // former is not accepted by the view, which means that the release will end up being - // sent elsewhere. So we need this extra logic inside HoverMove, rather than in - // MouseButtonRelease, which would otherwise be more elegant. + if (m_grabsMouse) { + if (m_hovering && s_mouseGrab && s_mouseGrab != this) + s_mouseGrab->setHovering(false); - if (m_hovering != mouseOnTopOfMouseArea) { - m_hovering = mouseOnTopOfMouseArea; - emit hoveringChanged(); + if (m_hovering || m_dragging) + s_mouseGrab = this; + else if (s_mouseGrab == this) + s_mouseGrab = nullptr; } - if (!m_dragging && m_hovering && buttonPressed) { - m_dragging = true; - emit pressed(mousePosInPlane); - emit draggingChanged(); - } else if (m_dragging && !buttonPressed) { - m_dragging = false; - emit released(mousePosInPlane); - emit draggingChanged(); - } - - if (m_grabsMouse) - s_mouseGrab = m_hovering || m_dragging ? this : nullptr; - - if (m_dragging) + if (m_dragging && !qFuzzyCompare(mousePosInPlane.z(), -1)) { + m_mousePosInPlane = mousePosInPlane; emit dragged(mousePosInPlane); + } - break; } + break; + } default: break; } @@ -245,6 +302,24 @@ bool MouseArea3D::eventFilter(QObject *, QEvent *event) return false; } +void MouseArea3D::setDragging(bool enable) +{ + if (m_dragging == enable) + return; + + m_dragging = enable; + emit draggingChanged(); +} + +void MouseArea3D::setHovering(bool enable) +{ + if (m_hovering == enable) + return; + + m_hovering = enable; + emit hoveringChanged(); +} + } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h index b42b438b47..99a34be353 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/mousearea3d.h @@ -48,6 +48,7 @@ class MouseArea3D : public QQuick3DNode Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged) Q_PROPERTY(bool hovering READ hovering NOTIFY hoveringChanged) Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) + Q_PROPERTY(int priority READ priority WRITE setPriority NOTIFY priorityChanged) Q_INTERFACES(QQmlParserStatus) @@ -60,6 +61,7 @@ public: qreal y() const; qreal width() const; qreal height() const; + int priority() const; bool hovering() const; bool dragging() const; @@ -73,6 +75,7 @@ public slots: void setY(qreal y); void setWidth(qreal width); void setHeight(qreal height); + void setPriority(int level); Q_INVOKABLE QVector3D rayIntersectsPlane(const QVector3D &rayPos0, const QVector3D &rayPos1, @@ -86,6 +89,7 @@ signals: void yChanged(qreal y); void widthChanged(qreal width); void heightChanged(qreal height); + void priorityChanged(int level); void hoveringChanged(); void draggingChanged(); @@ -100,6 +104,9 @@ protected: bool eventFilter(QObject *obj, QEvent *event) override; private: + void setDragging(bool enable); + void setHovering(bool enable); + Q_DISABLE_COPY(MouseArea3D) QQuick3DViewport *m_view3D = nullptr; @@ -107,6 +114,7 @@ private: qreal m_y; qreal m_width; qreal m_height; + int m_priority = 0; bool m_hovering = false; bool m_dragging = false; @@ -115,6 +123,7 @@ private: static MouseArea3D *s_mouseGrab; bool m_grabsMouse; + QVector3D m_mousePosInPlane; }; } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 2f0244ddeb..83382fb198 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -396,6 +396,11 @@ void ObjectNodeInstance::setHideInEditor(bool) { } +void ObjectNodeInstance::setModifiedFlag(bool b) +{ + m_isModified = b; +} + QVariant ObjectNodeInstance::convertEnumToValue(const QVariant &value, const PropertyName &name) { Q_ASSERT(value.canConvert<Enumeration>()); @@ -420,6 +425,9 @@ void ObjectNodeInstance::setPropertyVariant(const PropertyName &name, const QVar if (ignoredProperties().contains(name)) return; + if (m_isModified) + return; + QQmlProperty property(object(), QString::fromUtf8(name), context()); if (!property.isValid()) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index 8aa7ce4ad4..ced76dee58 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -195,6 +195,8 @@ public: void virtual setHideInEditor(bool b); + void setModifiedFlag(bool b); + protected: explicit ObjectNodeInstance(QObject *object); void doResetProperty(const PropertyName &propertyName); @@ -220,6 +222,7 @@ private: qint32 m_instanceId; bool m_deleteHeldInstance; bool m_isInLayoutable; + bool m_isModified = false; static QHash<EnumerationName, QVariant> m_enumationValueHash; }; diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index b1fa8be60d..d97cc2d503 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -56,6 +56,7 @@ #include "tokencommand.h" #include "removesharedmemorycommand.h" #include "changeselectioncommand.h" +#include "objectnodeinstance.h" #include "dummycontextobject.h" #include "../editor3d/cameracontrolhelper.h" @@ -98,6 +99,10 @@ QObject *Qt5InformationNodeInstanceServer::createEditView3D(QQmlEngine *engine) QObject::connect(window, SIGNAL(objectClicked(QVariant)), this, SLOT(objectClicked(QVariant))); QObject::connect(window, SIGNAL(commitObjectPosition(QVariant)), this, SLOT(handleObjectPositionCommit(QVariant))); + QObject::connect(window, SIGNAL(moveObjectPosition(QVariant)), + this, SLOT(handleObjectPositionMove(QVariant))); + QObject::connect(&m_moveTimer, &QTimer::timeout, + this, &Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout); //For macOS we have to use the 4.1 core profile QSurfaceFormat surfaceFormat = window->requestedFormat(); @@ -149,21 +154,62 @@ Qt5InformationNodeInstanceServer::vectorToPropertyValue( return result; } -void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) +void Qt5InformationNodeInstanceServer::modifyVariantValue( + const QVariant &node, + const PropertyName &propertyName, + ValuesModifiedCommand::TransactionOption option) { - auto *obj = object.value<QObject *>(); + PropertyName targetPopertyName; + + // Position is a special case, because the position can be 'position.x 'or simply 'x'. + // We prefer 'x'. + if (propertyName != "position") + targetPopertyName = propertyName; + + auto *obj = node.value<QObject *>(); + if (obj) { - /* We do have to split position into position.x, position.y, position.z */ - nodeInstanceClient()->valuesModified(createValuesModifiedCommand(vectorToPropertyValue( - instanceForObject(obj), - "position", - obj->property("position")))); + ServerNodeInstance instance = instanceForObject(obj); + + if (option == ValuesModifiedCommand::TransactionOption::Start) + instance.setModifiedFlag(true); + else if (option == ValuesModifiedCommand::TransactionOption::End) + instance.setModifiedFlag(false); + + // We do have to split position into position.x, position.y, position.z + ValuesModifiedCommand command = createValuesModifiedCommand(vectorToPropertyValue( + instance, + targetPopertyName, + obj->property(propertyName))); + + command.transactionOption = option; + + nodeInstanceClient()->valuesModified(command); } } +void Qt5InformationNodeInstanceServer::handleObjectPositionCommit(const QVariant &object) +{ + modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::End); + m_movedNode = {}; + m_moveTimer.stop(); +} + +void Qt5InformationNodeInstanceServer::handleObjectPositionMove(const QVariant &object) +{ + if (m_movedNode.isNull()) { + modifyVariantValue(object, "position", ValuesModifiedCommand::TransactionOption::Start); + } else { + if (!m_moveTimer.isActive()) + m_moveTimer.start(); + } + m_movedNode = object; +} + Qt5InformationNodeInstanceServer::Qt5InformationNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : Qt5NodeInstanceServer(nodeInstanceClient) { + m_moveTimer.setInterval(100); } void Qt5InformationNodeInstanceServer::sendTokenBack() @@ -236,6 +282,11 @@ void Qt5InformationNodeInstanceServer::modifyProperties( nodeInstanceClient()->valuesModified(createValuesModifiedCommand(properties)); } +void Qt5InformationNodeInstanceServer::handleObjectPositionMoveTimeout() +{ + modifyVariantValue(m_movedNode, "position", ValuesModifiedCommand::TransactionOption::None); +} + QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( const QList<ServerNodeInstance> &instanceList) const { @@ -252,6 +303,19 @@ QObject *Qt5InformationNodeInstanceServer::findRootNodeOf3DViewport( return nullptr; } +void Qt5InformationNodeInstanceServer::findCamerasAndLights( + const QList<ServerNodeInstance> &instanceList, + QObjectList &cameras, QObjectList &lights) const +{ + QObjectList objList; + for (const ServerNodeInstance &instance : instanceList) { + if (instance.isSubclassOf("QQuick3DCamera")) + cameras << instance.internalObject(); + else if (instance.isSubclassOf("QQuick3DAbstractLight")) + lights << instance.internalObject(); + } +} + void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeInstance> &instanceList) { ServerNodeInstance root = rootNodeInstance(); @@ -279,6 +343,19 @@ void Qt5InformationNodeInstanceServer::setup3DEditView(const QList<ServerNodeIns parentProperty.write(objectToVariant(m_editView3D)); QQmlProperty completeSceneProperty(m_editView3D, "showLight", context()); completeSceneProperty.write(showCustomLight); + + // Create camera and light gizmos + QObjectList cameras; + QObjectList lights; + findCamerasAndLights(instanceList, cameras, lights); + for (auto &obj : qAsConst(cameras)) { + QMetaObject::invokeMethod(m_editView3D, "addCameraGizmo", + Q_ARG(QVariant, objectToVariant(obj))); + } + for (auto &obj : qAsConst(lights)) { + QMetaObject::invokeMethod(m_editView3D, "addLightGizmo", + Q_ARG(QVariant, objectToVariant(obj))); + } } } @@ -471,4 +548,21 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm } } +void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command) +{ + bool hasDynamicProperties = false; + const QVector<PropertyValueContainer> values = command.valueChanges(); + for (const PropertyValueContainer &container : values) { + if (!container.isReflected()) { + hasDynamicProperties |= container.isDynamic(); + setInstancePropertyVariant(container); + } + } + + if (hasDynamicProperties) + refreshBindings(); + + startRenderTimer(); +} + } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index c574a6ed11..e8a0291a9f 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -27,6 +27,10 @@ #include "qt5nodeinstanceserver.h" #include "tokencommand.h" +#include "valueschangedcommand.h" + +#include <QTimer> +#include <QVariant> namespace QmlDesigner { @@ -43,10 +47,12 @@ public: void token(const TokenCommand &command) override; void removeSharedMemory(const RemoveSharedMemoryCommand &command) override; void changeSelection(const ChangeSelectionCommand &command) override; + void changePropertyValues(const ChangeValuesCommand &command) override; private slots: void objectClicked(const QVariant &object); void handleObjectPositionCommit(const QVariant &object); + void handleObjectPositionMove(const QVariant &object); protected: void collectItemChangesAndSendChangeCommands() override; @@ -58,17 +64,25 @@ protected: void modifyProperties(const QVector<InstancePropertyValueTriple> &properties); private: + void handleObjectPositionMoveTimeout(); QObject *createEditView3D(QQmlEngine *engine); void setup3DEditView(const QList<ServerNodeInstance> &instanceList); QObject *findRootNodeOf3DViewport(const QList<ServerNodeInstance> &instanceList) const; + void findCamerasAndLights( const QList<ServerNodeInstance> &instanceList, + QObjectList &cameras, QObjectList &lights) const; QVector<InstancePropertyValueTriple> vectorToPropertyValue(const ServerNodeInstance &instance, const PropertyName &propertyName, const QVariant &variant); + void modifyVariantValue(const QVariant &node, + const PropertyName &propertyName, + ValuesModifiedCommand::TransactionOption option); QObject *m_editView3D = nullptr; QSet<ServerNodeInstance> m_parentChangedSet; QList<ServerNodeInstance> m_completedComponentList; QList<TokenCommand> m_tokenList; + QTimer m_moveTimer; + QVariant m_movedNode; }; } // namespace QmlDesigner diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp index 376ca29524..b128161aee 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.cpp @@ -129,6 +129,11 @@ bool ServerNodeInstance::isSubclassOf(QObject *object, const QByteArray &superTy return Internal::QmlPrivateGate::isSubclassOf(object, superTypeName); } +void ServerNodeInstance::setModifiedFlag(bool b) +{ + m_nodeInstance->setModifiedFlag(b); +} + void ServerNodeInstance::setNodeSource(const QString &source) { m_nodeInstance->setNodeSource(source); diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h index 7e72878dca..86003b51b6 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/servernodeinstance.h @@ -165,6 +165,8 @@ public: static bool isSubclassOf(QObject *object, const QByteArray &superTypeName); + void setModifiedFlag(bool b); + private: // functions ServerNodeInstance(const QSharedPointer<Internal::ObjectNodeInstance> &abstractInstance); diff --git a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc index 03931c280e..4bbd30e8fc 100644 --- a/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc +++ b/share/qtcreator/qml/qmlpuppet/qmlpuppet.qrc @@ -11,7 +11,14 @@ <file>mockfiles/Arrow.qml</file> <file>mockfiles/AutoScaleHelper.qml</file> <file>mockfiles/MoveGizmo.qml</file> + <file>mockfiles/CameraGizmo.qml</file> + <file>mockfiles/LightGizmo.qml</file> + <file>mockfiles/IconGizmo.qml</file> <file>mockfiles/Overlay2D.qml</file> - <file>mockfiles/meshes/Arrow.mesh</file> + <file>mockfiles/meshes/arrow.mesh</file> + <file>mockfiles/images/camera-pick-icon.png</file> + <file>mockfiles/images/camera-pick-icon@2x.png</file> + <file>mockfiles/images/light-pick-icon.png</file> + <file>mockfiles/images/light-pick-icon@2x.png</file> </qresource> </RCC> diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml index c8eb572141..389a9b02d2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml @@ -295,6 +295,315 @@ Rectangle { backendValueRightMargin: backendValues.Layout_rightMargin backendValueMargins: backendValues.Layout_margins } + + Section { + visible: !anchorBackend.isInLayout + anchors.left: parent.left + anchors.right: parent.right + caption: qsTr("Align") + + ColumnLayout { + width: parent.width + enabled: alignDistribute.multiSelection && + !alignDistribute.selectionHasAnchors && + alignDistribute.selectionExclusivlyItems && + !alignDistribute.selectionContainsRootItem + + AlignDistribute { + id: alignDistribute + modelNodeBackendProperty: modelNodeBackend + } + + Label { + text: qsTr("Align objects") + width: 120 + } + RowLayout { + Row { + spacing: -StudioTheme.Values.border + AbstractButton { + buttonIcon: StudioTheme.Constants.alignLeft + tooltip: qsTr("Align objects to left edge") + onClicked: alignDistribute.alignObjects(AlignDistribute.Left, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.alignCenterHorizontal + tooltip: qsTr("Align objects horizontal center") + onClicked: alignDistribute.alignObjects(AlignDistribute.CenterH, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.alignRight + tooltip: qsTr("Align objects to right edge") + onClicked: alignDistribute.alignObjects(AlignDistribute.Right, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + } + + Row { + spacing: -StudioTheme.Values.border + AbstractButton { + buttonIcon: StudioTheme.Constants.alignTop + tooltip: qsTr("Align objects to top edge") + onClicked: alignDistribute.alignObjects(AlignDistribute.Top, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.alignCenterVertical + tooltip: qsTr("Align objects vertical center") + onClicked: alignDistribute.alignObjects(AlignDistribute.CenterV, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.alignBottom + tooltip: qsTr("Align objects to bottom edge") + onClicked: alignDistribute.alignObjects(AlignDistribute.Bottom, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + } + } + + Label { + text: qsTr("Distribute objects") + width: 120 + } + RowLayout { + Row { + spacing: -StudioTheme.Values.border + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeLeft + tooltip: qsTr("Distribute objects left edge") + onClicked: alignDistribute.distributeObjects(AlignDistribute.Left, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeCenterHorizontal + tooltip: qsTr("Distribute objects horizontal center") + onClicked: alignDistribute.distributeObjects(AlignDistribute.CenterH, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeRight + tooltip: qsTr("Distribute objects right edge") + onClicked: alignDistribute.distributeObjects(AlignDistribute.Right, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + } + + Row { + spacing: -StudioTheme.Values.border + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeTop + tooltip: qsTr("Distribute objects top edge") + onClicked: alignDistribute.distributeObjects(AlignDistribute.Top, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeCenterVertical + tooltip: qsTr("Distribute objects vertical center") + onClicked: alignDistribute.distributeObjects(AlignDistribute.CenterV, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeBottom + tooltip: qsTr("Distribute objects bottom edge") + onClicked: alignDistribute.distributeObjects(AlignDistribute.Bottom, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText) + } + } + } + + Label { + text: qsTr("Distribute spacing") + width: 120 + } + RowLayout { + Row { + spacing: -StudioTheme.Values.border + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeSpacingHorizontal + tooltip: qsTr("Distribute spacing horizontal") + onClicked: alignDistribute.distributeSpacing(AlignDistribute.X, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText, + distanceSpinBox.realValue, + buttonRow.getDistributeDirection()) + } + AbstractButton { + buttonIcon: StudioTheme.Constants.distributeSpacingVertical + tooltip: qsTr("Distribute spacing vertical") + onClicked: alignDistribute.distributeSpacing(AlignDistribute.Y, + alignToComboBox.currentEnum, + keyObjectComboBox.currentText, + distanceSpinBox.realValue, + buttonRow.getDistributeDirection()) + } + } + + StudioControls.ButtonRow { + id: buttonRow + actionIndicatorVisible: false + + StudioControls.ButtonGroup { + id: group + } + + function getDistributeDirection() + { + if (buttonLeftToRight.checked) + return AlignDistribute.TopLeft + else if (buttonCenter.checked) + return AlignDistribute.Center + else if (buttonRightToLeft.checked) + return AlignDistribute.BottomRight + else + return AlignDistribute.None + } + + AbstractButton { + id: buttonNone + checked: true // default state + buttonIcon: StudioTheme.Constants.distributeOriginNone + checkable: true + StudioControls.ButtonGroup.group: group + } + AbstractButton { + id: buttonLeftToRight + buttonIcon: StudioTheme.Constants.distributeOriginTopLeft + checkable: true + StudioControls.ButtonGroup.group: group + } + AbstractButton { + id: buttonCenter + buttonIcon: StudioTheme.Constants.distributeOriginCenter + checkable: true + StudioControls.ButtonGroup.group: group + } + AbstractButton { + id: buttonRightToLeft + buttonIcon: StudioTheme.Constants.distributeOriginBottomRight + checkable: true + StudioControls.ButtonGroup.group: group + } + + StudioControls.RealSpinBox { + id: distanceSpinBox + width: 64 + actionIndicatorVisible: false + realFrom: -1000 + realTo: 1000 + enabled: !buttonNone.checked + } + } + } + + SectionLayout { + columns: 2 + + ItemFilterModel { + id: itemFilterModel + modelNodeBackendProperty: modelNodeBackend + selectionOnly: true + } + + Label { + text: qsTr("Align to") + } + ComboBox { + id: alignToComboBox + Layout.fillWidth: true + property int currentEnum: alignTargets.get(alignToComboBox.currentIndex).value + textRole: "text" + model: ListModel { + id: alignTargets + ListElement { text: "Selection"; value: AlignDistribute.Selection } + ListElement { text: "Root"; value: AlignDistribute.Root } + ListElement { text: "Key object"; value: AlignDistribute.KeyObject } + } + } + + Label { + text: qsTr("Key object") + } + ComboBox { + id: keyObjectComboBox + enabled: alignToComboBox.currentIndex === 2 + model: itemFilterModel.itemModel + Layout.fillWidth: true + property string lastSelectedItem: "" + onCompressedActivated: lastSelectedItem = keyObjectComboBox.currentText + onModelChanged: { + var idx = model.indexOf(keyObjectComboBox.lastSelectedItem) + if (idx !== -1) + keyObjectComboBox.currentIndex = idx + else + lastSelectedItem = "" // TODO + } + } + } + + SectionLayout { + columns: 1 + Layout.topMargin: 30 + visible: alignDistribute.multiSelection && + (alignDistribute.selectionHasAnchors || + !alignDistribute.selectionExclusivlyItems || + alignDistribute.selectionContainsRootItem) + + Text { + id: warningTitle + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.myFontSize + font.weight: Font.Bold + color: StudioTheme.Values.themeTextColor + text: qsTr("Warning") + } + Text { + id: warningRoot + visible: alignDistribute.selectionContainsRootItem + Layout.fillWidth: true + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.myFontSize + color: StudioTheme.Values.themeTextColor + wrapMode: Text.WordWrap + text: qsTr("- The selection contains the root item.") + } + Text { + id: warningNonVisual + visible: !alignDistribute.selectionExclusivlyItems + Layout.fillWidth: true + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.myFontSize + color: StudioTheme.Values.themeTextColor + wrapMode: Text.WordWrap + text: qsTr("- The selection contains a non visual item.") + } + Text { + id: warningAnchors + visible: alignDistribute.selectionHasAnchors + Layout.fillWidth: true + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.myFontSize + color: StudioTheme.Values.themeTextColor + wrapMode: Text.WordWrap + text: qsTr("- An item in the selection uses anchors.") + } + } + } + } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index a3f0d2cdca..3c314cfea6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -26,6 +26,7 @@ import QtQuick 2.1 import HelperWidgets 2.0 import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 @@ -145,8 +146,7 @@ RowLayout { } StudioControls.AbstractButton { - buttonIcon: "..." - iconFont: StudioTheme.Constants.font.family + buttonIcon: StudioTheme.Constants.addFile iconColor: urlChooser.textColor onClicked: { fileModel.openFileDialog() diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml index 18adbdb68a..421dabf757 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Constants.qml @@ -38,29 +38,50 @@ QtObject { readonly property string actionIcon: "\u0021" readonly property string actionIconBinding: "\u0022" - readonly property string anchorBaseline: "\u0023" - readonly property string anchorBottom: "\u0024" - readonly property string anchorFill: "\u0025" - readonly property string anchorLeft: "\u0026" - readonly property string anchorRight: "\u0027" - readonly property string anchorTop: "\u0028" - readonly property string centerHorizontal: "\u002A" - readonly property string centerVertical: "\u0029" - readonly property string closeCross: "\u002B" - readonly property string fontStyleBold: "\u002C" - readonly property string fontStyleItalic: "\u002D" - readonly property string fontStyleStrikethrough: "\u002E" - readonly property string fontStyleUnderline: "\u002F" - readonly property string textAlignBottom: "\u0030" - readonly property string textAlignCenter: "\u0031" - readonly property string textAlignLeft: "\u0032" - readonly property string textAlignMiddle: "\u0033" - readonly property string textAlignRight: "\u0034" - readonly property string textAlignTop: "\u0035" - readonly property string tickIcon: "\u0036" - readonly property string triState: "\u0037" - readonly property string upDownIcon: "\u0038" - readonly property string upDownSquare2: "\u0039" + readonly property string addFile: "\u0023" + readonly property string alignBottom: "\u0024" + readonly property string alignCenterHorizontal: "\u0025" + readonly property string alignCenterVertical: "\u0026" + readonly property string alignLeft: "\u0027" + readonly property string alignRight: "\u0028" + readonly property string alignTo: "\u0029" + readonly property string alignTop: "\u002A" + readonly property string anchorBaseline: "\u002B" + readonly property string anchorBottom: "\u002C" + readonly property string anchorFill: "\u002D" + readonly property string anchorLeft: "\u002E" + readonly property string anchorRight: "\u002F" + readonly property string anchorTop: "\u0030" + readonly property string centerHorizontal: "\u0031" + readonly property string centerVertical: "\u0032" + readonly property string closeCross: "\u0033" + readonly property string distributeBottom: "\u0034" + readonly property string distributeCenterHorizontal: "\u0035" + readonly property string distributeCenterVertical: "\u0036" + readonly property string distributeLeft: "\u0037" + readonly property string distributeOriginBottomRight: "\u0038" + readonly property string distributeOriginCenter: "\u0039" + readonly property string distributeOriginNone: "\u003A" + readonly property string distributeOriginTopLeft: "\u003B" + readonly property string distributeRight: "\u003C" + readonly property string distributeSpacingHorizontal: "\u003D" + readonly property string distributeSpacingVertical: "\u003E" + readonly property string distributeTop: "\u003F" + readonly property string fontStyleBold: "\u0040" + readonly property string fontStyleItalic: "\u0041" + readonly property string fontStyleStrikethrough: "\u0042" + readonly property string fontStyleUnderline: "\u0043" + readonly property string testIcon: "\u0044" + readonly property string textAlignBottom: "\u0045" + readonly property string textAlignCenter: "\u0046" + readonly property string textAlignLeft: "\u0047" + readonly property string textAlignMiddle: "\u0048" + readonly property string textAlignRight: "\u0049" + readonly property string textAlignTop: "\u004A" + readonly property string tickIcon: "\u004B" + readonly property string triState: "\u004C" + readonly property string upDownIcon: "\u004D" + readonly property string upDownSquare2: "\u004E" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf Binary files differindex 9658c01782..289326b3a5 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt index 53f928153c..71e5cbd380 100644 --- a/src/libs/extensionsystem/CMakeLists.txt +++ b/src/libs/extensionsystem/CMakeLists.txt @@ -12,5 +12,8 @@ add_qtc_library(ExtensionSystem pluginmanager.cpp pluginmanager.h pluginmanager_p.h pluginspec.cpp pluginspec.h pluginspec_p.h pluginview.cpp pluginview.h + EXPLICIT_MOC + pluginmanager.h + pluginmanager_p.h SKIP_AUTOMOC pluginmanager.cpp ) diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 0e19dba5e9..e1e75148fd 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -338,9 +338,7 @@ bool BuildableHelperLibrary::buildHelper(const BuildHelperArguments &arguments, log->append(QCoreApplication::translate("ProjectExplorer::BuildableHelperLibrary", "Running %1 %2 ...\n") .arg(makeFullPath.toUserOutput(), arguments.makeArguments.join(QLatin1Char(' ')))); - if (!runBuildProcess(proc, makeFullPath, arguments.makeArguments, 120, false, log, errorMessage)) - return false; - return true; + return runBuildProcess(proc, makeFullPath, arguments.makeArguments, 120, false, log, errorMessage); } bool BuildableHelperLibrary::getHelperFileInfoFor(const QStringList &validBinaryFilenames, diff --git a/src/libs/utils/detailsbutton.cpp b/src/libs/utils/detailsbutton.cpp index abceff7b2d..07c27d3b70 100644 --- a/src/libs/utils/detailsbutton.cpp +++ b/src/libs/utils/detailsbutton.cpp @@ -110,6 +110,14 @@ bool DetailsButton::event(QEvent *e) return false; } +void DetailsButton::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::EnabledChange) { + m_checkedPixmap = QPixmap(); + m_uncheckedPixmap = QPixmap(); + } +} + void DetailsButton::paintEvent(QPaintEvent *e) { QWidget::paintEvent(e); diff --git a/src/libs/utils/detailsbutton.h b/src/libs/utils/detailsbutton.h index dabbe75918..3c7286e9ee 100644 --- a/src/libs/utils/detailsbutton.h +++ b/src/libs/utils/detailsbutton.h @@ -71,6 +71,7 @@ public: protected: void paintEvent(QPaintEvent *e) override; bool event(QEvent *e) override; + void changeEvent(QEvent *e) override; private: QPixmap cacheRendering(const QSize &size, bool checked); diff --git a/src/libs/utils/detailswidget.cpp b/src/libs/utils/detailswidget.cpp index dd02d1a4a5..06159b101e 100644 --- a/src/libs/utils/detailswidget.cpp +++ b/src/libs/utils/detailswidget.cpp @@ -229,6 +229,16 @@ void DetailsWidget::setUseCheckBox(bool b) d->updateControls(); } +void DetailsWidget::setCheckable(bool b) +{ + d->m_summaryCheckBox->setEnabled(b); +} + +void DetailsWidget::setExpandable(bool b) +{ + d->m_detailsButton->setEnabled(b); +} + void DetailsWidget::setChecked(bool b) { d->m_summaryCheckBox->setChecked(b); diff --git a/src/libs/utils/detailswidget.h b/src/libs/utils/detailswidget.h index f96f0f549d..e9c55c9eaf 100644 --- a/src/libs/utils/detailswidget.h +++ b/src/libs/utils/detailswidget.h @@ -78,6 +78,8 @@ public: bool useCheckBox(); void setUseCheckBox(bool b); + void setCheckable(bool b); + void setExpandable(bool b); void setIcon(const QIcon &icon); static QPixmap createBackground(const QSize &size, int topHeight, QWidget *widget); diff --git a/src/libs/utils/differ.cpp b/src/libs/utils/differ.cpp index 16fc0ced01..74ec99c78c 100644 --- a/src/libs/utils/differ.cpp +++ b/src/libs/utils/differ.cpp @@ -236,16 +236,12 @@ static int cleanupSemanticsScore(const QString &text1, const QString &text2) static bool isWhitespace(const QChar &c) { - if (c == ' ' || c == '\t') - return true; - return false; + return c == ' ' || c == '\t'; } static bool isNewLine(const QChar &c) { - if (c == '\n') - return true; - return false; + return c == '\n'; } /* @@ -719,9 +715,7 @@ static bool diffWithWhitespaceExpandedInEqualities(const QList<Diff> &leftInput, return false; *rightOutput = decodeExpandedWhitespace(rightDiffList, commonRightCodeMap, &ok); - if (!ok) - return false; - return true; + return ok; } static void appendWithEqualitiesSquashed(const QList<Diff> &leftInput, diff --git a/src/libs/utils/json.cpp b/src/libs/utils/json.cpp index 104cf571b9..b195e134d4 100644 --- a/src/libs/utils/json.cpp +++ b/src/libs/utils/json.cpp @@ -225,17 +225,13 @@ bool JsonSchema::typeMatches(const QString &expected, const QString &actual) bool JsonSchema::isCheckableType(const QString &s) { - if (s == QLatin1String("string") - || s == QLatin1String("number") - || s == QLatin1String("integer") - || s == QLatin1String("boolean") - || s == QLatin1String("object") - || s == QLatin1String("array") - || s == QLatin1String("null")) { - return true; - } - - return false; + return s == QLatin1String("string") + || s == QLatin1String("number") + || s == QLatin1String("integer") + || s == QLatin1String("boolean") + || s == QLatin1String("object") + || s == QLatin1String("array") + || s == QLatin1String("null"); } QStringList JsonSchema::validTypes() const diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp index 09a9855784..210791157c 100644 --- a/src/libs/utils/reloadpromptutils.cpp +++ b/src/libs/utils/reloadpromptutils.cpp @@ -102,22 +102,14 @@ QTCREATOR_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, } QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer - fileDeletedPrompt(const QString &fileName, bool triggerExternally, QWidget *parent) + fileDeletedPrompt(const QString &fileName, QWidget *parent) { const QString title = QCoreApplication::translate("Utils::fileDeletedPrompt", "File Has Been Removed"); - QString msg; - if (triggerExternally) { - msg = QCoreApplication::translate("Utils::fileDeletedPrompt", - "The file %1 has been removed from disk. " - "Do you want to save it under a different name, or close " - "the editor?").arg(QDir::toNativeSeparators(fileName)); - } else { - msg = QCoreApplication::translate("Utils::fileDeletedPrompt", - "The file %1 has been removed from disk. " - "Do you want to save it under a different name, or close " - "the editor?").arg(QDir::toNativeSeparators(fileName)); - } + QString msg = QCoreApplication::translate("Utils::fileDeletedPrompt", + "The file %1 has been removed from disk. " + "Do you want to save it under a different name, or close " + "the editor?").arg(QDir::toNativeSeparators(fileName)); QMessageBox box(QMessageBox::Question, title, msg, QMessageBox::NoButton, parent); QPushButton *close = box.addButton(QCoreApplication::translate("Utils::fileDeletedPrompt", "&Close"), diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h index 82aa409cf5..5b06596cd4 100644 --- a/src/libs/utils/reloadpromptutils.h +++ b/src/libs/utils/reloadpromptutils.h @@ -62,7 +62,6 @@ enum FileDeletedPromptAnswer { }; QTCREATOR_UTILS_EXPORT FileDeletedPromptAnswer fileDeletedPrompt(const QString &fileName, - bool triggerExternally, QWidget *parent); } // namespace Utils diff --git a/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp b/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp index 3e9bc558d0..8d623b6680 100644 --- a/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp +++ b/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp @@ -80,7 +80,7 @@ void QdbMessageTracker::handleWatchMessage(const QJsonDocument &document) } m_messageCache.append(message); - showMessage(tr("Qdb message: %1").arg(message), true); + showMessage(tr("QDB message: %1").arg(message), true); } } diff --git a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp index e5a9b5c2ef..ee2b091fd3 100644 --- a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp +++ b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp @@ -109,7 +109,7 @@ void QdbWatcher::handleWatchError(QLocalSocket::LocalSocketError error) if (m_retried) { stop(); - emit watcherError(tr("Could not connect to QDB host server even after trying to start it")); + emit watcherError(tr("Could not connect to QDB host server even after trying to start it.")); return; } retry(); @@ -142,7 +142,7 @@ void QdbWatcher::forkHostServer() return; } if (QProcess::startDetached(qdbFilePath.toString(), {"server"})) - showMessage(tr("QDB host server started"), false); + showMessage(tr("QDB host server started."), false); else showMessage(tr("Could not start QDB host server in %1").arg(qdbFilePath.toString()), true); } @@ -153,7 +153,7 @@ void QdbWatcher::retry() { QMutexLocker lock(&s_startMutex); if (!s_startedServer) { - showMessage(tr("Starting QDB host server"), false); + showMessage(tr("Starting QDB host server."), false); forkHostServer(); s_startedServer = true; } diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index c6e388878d..e8b8186b50 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -93,7 +93,7 @@ public: Runnable r; r.setCommandLine(command); m_appRunner.start(r, device); - showMessage(QdbDevice::tr("Starting command '%1' on device '%2'.") + showMessage(QdbDevice::tr("Starting command \"%1\" on device \"%2\".") .arg(command.toUserOutput(), m_deviceName)); } @@ -112,18 +112,18 @@ private: if (!success) { QString errorString; if (!m_error.isEmpty()) { - errorString = QdbDevice::tr("Command failed on device '%1': %2") + errorString = QdbDevice::tr("Command failed on device \"%1\": %2") .arg(m_deviceName, m_error); } else { - errorString = QdbDevice::tr("Command failed on device '%1'.").arg(m_deviceName); + errorString = QdbDevice::tr("Command failed on device \"%1\".").arg(m_deviceName); } showMessage(errorString, true); if (!m_stdout.isEmpty()) - showMessage(QdbDevice::tr("stdout was: '%1'").arg(m_stdout)); + showMessage(QdbDevice::tr("stdout was: \"%1\"").arg(m_stdout)); if (!m_stderr.isEmpty()) - showMessage(QdbDevice::tr("stderr was: '%1'").arg(m_stderr)); + showMessage(QdbDevice::tr("stderr was: \"%1\"").arg(m_stderr)); } else { - showMessage(QdbDevice::tr("Commands on device '%1' finished successfully.") + showMessage(QdbDevice::tr("Commands on device \"%1\" finished successfully.") .arg(m_deviceName)); } deleteLater(); diff --git a/src/plugins/boot2qt/qdbmakedefaultappservice.cpp b/src/plugins/boot2qt/qdbmakedefaultappservice.cpp index fc7212b910..9512ac8f7d 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappservice.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappservice.cpp @@ -77,7 +77,7 @@ void QdbMakeDefaultAppService::handleProcessFinished(const QString &error) QByteArray processOutput = d->processRunner->readAllStandardOutput(); if (d->makeDefault) - emit progressMessage(tr("Application made as the default one.")); + emit progressMessage(tr("Application set as the default one.")); else emit progressMessage(tr("Reset the default application.")); diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 6b645ad952..607b78680c 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -495,12 +495,13 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection, }); m_perspective.select(); - m_diagnosticModel->clear(); - setToolBusy(true); m_diagnosticFilterModel->setProject(project); + m_applyFixitsButton->setEnabled(false); m_running = true; + + setToolBusy(true); handleStateUpdate(); updateRunActions(); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 6d870d93c8..e58b77a769 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -227,6 +227,7 @@ ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl, const FileInfos &fileInfos, bool preventBuild) : RunWorker(runControl) + , m_runSettings(runSettings) , m_diagnosticConfig(diagnosticConfig) , m_fileInfos(fileInfos) , m_temporaryDir("clangtools-XXXXXX") @@ -305,7 +306,7 @@ void ClangToolRunWorker::start() // Create log dir if (!m_temporaryDir.isValid()) { const QString errorMessage - = tr("%1: Failed to create temporary dir, stop.").arg(toolName); + = tr("%1: Failed to create temporary directory. Stopped.").arg(toolName); appendMessage(errorMessage, Utils::ErrorMessageFormat); TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); @@ -390,7 +391,7 @@ void ClangToolRunWorker::analyzeNextFile() const QString executable = runner->executable(); if (!isFileExecutable(executable)) { - const QString errorMessage = tr("%1: Invalid executable \"%2\", stop.") + const QString errorMessage = tr("%1: Invalid executable \"%2\". Stopped.") .arg(runner->name(), executable); TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp index 6ac802d973..6608bb3ea4 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp @@ -101,10 +101,10 @@ QDebug operator<<(QDebug debug, const Diagnostic &d) void ClangToolsDiagnosticModel::addDiagnostics(const Diagnostics &diagnostics) { - const auto onFixitStatusChanged = [this](FixitStatus newStatus) { + const auto onFixitStatusChanged = [this](FixitStatus oldStatus, FixitStatus newStatus) { if (newStatus == FixitStatus::Scheduled) ++m_fixItsToApplyCount; - else + else if (oldStatus == FixitStatus::Scheduled) --m_fixItsToApplyCount; emit fixItsToApplyCountChanged(m_fixItsToApplyCount); }; @@ -463,7 +463,7 @@ void DiagnosticItem::setFixItStatus(const FixitStatus &status) m_fixitStatus = status; update(); if (m_onFixitStatusChanged && status != oldStatus) - m_onFixitStatusChanged(status); + m_onFixitStatusChanged(oldStatus, status); } void DiagnosticItem::setFixitOperations(const ReplacementOperations &replacements) diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h index 3ac1df0d0c..d9fb8b4cfb 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h @@ -71,8 +71,9 @@ private: class DiagnosticItem : public Utils::TreeItem { public: - using OnFixitStatusChanged = std::function<void(FixitStatus newStatus)>; - DiagnosticItem(const Diagnostic &diag, const OnFixitStatusChanged &onFixitStatusChanged, + using OnFixitStatusChanged = std::function<void(FixitStatus oldStatus, FixitStatus newStatus)>; + DiagnosticItem(const Diagnostic &diag, + const OnFixitStatusChanged &onFixitStatusChanged, ClangToolsDiagnosticModel *parent); ~DiagnosticItem() override; diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp index 4408a597b7..769266b5e0 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp @@ -283,7 +283,7 @@ bool DiagnosticView::eventFilter(QObject *watched, QEvent *event) return true; } default: - return QObject::eventFilter(watched, event); + return QAbstractItemView::eventFilter(watched, event); } } diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.cpp b/src/plugins/clangtools/clangtoolsprojectsettings.cpp index 005897b49c..c7d692704e 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettings.cpp @@ -105,7 +105,7 @@ void ClangToolsProjectSettings::load() // Load map QVariantMap map = m_project->namedSettings(SETTINGS_KEY_MAIN).toMap(); - bool write; + bool write = false; if (map.isEmpty()) { if (!m_project->namedSettings(SETTINGS_KEY_SELECTED_DIRS).isNull()) { map = convertToMapFromVersionBefore410(m_project); diff --git a/src/plugins/classview/classviewparsertreeitem.cpp b/src/plugins/classview/classviewparsertreeitem.cpp index eb2009c5ed..e80dc3e25b 100644 --- a/src/plugins/classview/classviewparsertreeitem.cpp +++ b/src/plugins/classview/classviewparsertreeitem.cpp @@ -333,11 +333,7 @@ bool ParserTreeItem::canFetchMore(QStandardItem *item) const int storedChildren = item->rowCount(); int internalChildren = d->symbolInformations.count(); - - if (storedChildren < internalChildren) - return true; - - return false; + return storedChildren < internalChildren; } /*! diff --git a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp index eca893b8ea..eb9ae0c76f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp @@ -45,10 +45,7 @@ bool CMakeAutoCompleter::isInComment(const QTextCursor &cursor) const // NOTE: This doesn't handle '#' inside quotes, nor multi-line comments QTextCursor moved = cursor; moved.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); - if (moved.selectedText().contains(QLatin1Char('#'))) - return true; - else - return false; + return moved.selectedText().contains(QLatin1Char('#')); } bool CMakeAutoCompleter::isInString(const QTextCursor &cursor) const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index c1d5f04142..ae1e20972f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -151,7 +151,6 @@ void CMakeBuildSystem::handleTreeScanningFinished() qDeleteAll(m_allFiles); m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; }); - m_combinedScanAndParseResult = m_combinedScanAndParseResult && true; m_waitingForScan = false; combineScanAndParse(); @@ -165,7 +164,6 @@ void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc) QTC_ASSERT(m_waitingForParse, return ); m_waitingForParse = false; - m_combinedScanAndParseResult = m_combinedScanAndParseResult && true; combineScanAndParse(); } diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index e5d20de5dd..8517a5ee7f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -215,12 +215,12 @@ void CMakeProcess::handleProcessFinished(int code, QProcess::ExitStatus status) QString msg; if (status != QProcess::NormalExit) { if (m_processWasCanceled) { - msg = tr("*** cmake process was canceled by the user."); + msg = tr("CMake process was canceled by the user."); } else { - msg = tr("*** cmake process crashed."); + msg = tr("CMake process crashed."); } } else if (code != 0) { - msg = tr("*** cmake process exited with exit code %1.").arg(code); + msg = tr("CMake process exited with exit code %1.").arg(code); } if (!msg.isEmpty()) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 4739d0f808..9943ca5784 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -88,7 +88,7 @@ void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::P "\nCopy the path to the source files to the clipboard?"), "Remember My Choice", &checkValue, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes); - if (true == checkValue) { + if (checkValue) { if (QDialogButtonBox::Yes == reply) settings->setAfterAddFileSetting(AfterAddFileAction::COPY_FILE_PATH); else if (QDialogButtonBox::No == reply) diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index 657f798ceb..25dc5d701e 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -57,7 +57,7 @@ static void reportFileApiSetupFailure() { Core::MessageManager::write(QCoreApplication::translate( "CMakeProjectManager::Internal", - "Failed to set up cmake fileapi support. Creator can not extract project information.")); + "Failed to set up CMake file API support. Qt Creator can not extract project information.")); } static std::pair<int, int> cmakeVersion(const QJsonObject &obj) @@ -112,7 +112,7 @@ static ReplyFileContents readReplyFile(const QFileInfo &fi, QString &errorMessag { const QJsonDocument document = readJsonFile(fi.filePath()); static const QString msg = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid reply file created by cmake."); + "Invalid reply file created by CMake."); ReplyFileContents result; if (document.isNull() || document.isEmpty() || !document.isObject()) { @@ -175,7 +175,7 @@ static CMakeConfig readCacheFile(const QString &cacheFile, QString &errorMessage if (!checkJsonObject(root, "cache", 2)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid cache file generated by cmake."); + "Invalid cache file generated by CMake."); return {}; } @@ -221,7 +221,7 @@ std::vector<CMakeFileInfo> readCMakeFilesFile(const QString &cmakeFilesFile, QSt if (!checkJsonObject(root, "cmakeFiles", 1)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid cmakeFiles file generated by cmake."); + "Invalid cmakeFiles file generated by CMake."); return {}; } @@ -252,7 +252,7 @@ std::vector<Directory> extractDirectories(const QJsonArray &directories, QString if (directories.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No directories."); + "Invalid codemodel file generated by CMake: No directories."); return {}; } @@ -262,7 +262,7 @@ std::vector<Directory> extractDirectories(const QJsonArray &directories, QString if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty directory object."); + "Invalid codemodel file generated by CMake: Empty directory object."); continue; } Directory dir; @@ -284,7 +284,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (projects.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No projects."); + "Invalid codemodel file generated by CMake: No projects."); return {}; } @@ -294,7 +294,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty project object."); + "Invalid codemodel file generated by CMake: Empty project object."); continue; } Project project; @@ -309,7 +309,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (project.name.isEmpty() || project.directories.empty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken project data."); + "Invalid codemodel file generated by CMake: Broken project data."); continue; } @@ -323,7 +323,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er if (targets.isEmpty()) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No targets."); + "Invalid codemodel file generated by CMake: No targets."); return {}; } @@ -333,7 +333,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty target object."); + "Invalid codemodel file generated by CMake: Empty target object."); continue; } Target target; @@ -347,7 +347,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er || target.directory == -1 || target.project == -1) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken target data."); + "Invalid codemodel file generated by CMake: Broken target data."); continue; } @@ -448,7 +448,7 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (configs.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No configurations."); + "Invalid codemodel file generated by CMake: No configurations."); return {}; } @@ -458,7 +458,7 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty configuration object."); + "Invalid codemodel file generated by CMake: Empty configuration object."); continue; } Configuration config; @@ -471,8 +471,8 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (!validateIndexes(config)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken " - "indexes in directories/projects/targets."); + "Invalid codemodel file generated by CMake: Broken " + "indexes in directories, projects, or targets."); return {}; } @@ -489,7 +489,7 @@ static std::vector<Configuration> readCodemodelFile(const QString &codemodelFile if (!checkJsonObject(root, "codemodel", 2)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake."); + "Invalid codemodel file generated by CMake."); return {}; } @@ -787,7 +787,7 @@ TargetDetails readTargetFile(const QString &targetFile, QString &errorMessage) if (errorMessage.isEmpty() && !validateTargetDetails(result)) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid target file generated by cmake: Broken indexes in target details."); + "Invalid target file generated by CMake: Broken indexes in target details."); } return result; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index 1affca78fa..7d045f329e 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -28,6 +28,7 @@ #include <projectexplorer/headerpath.h> #include <projectexplorer/projectmacro.h> +#include <utils/algorithm.h> #include <utils/hostosinfo.h> #include <utils/optional.h> @@ -155,14 +156,16 @@ void filteredFlags(const QString &fileName, continue; } - if ((flag.startsWith("-I") || flag.startsWith("-isystem") || flag.startsWith("/I")) - && flag != "-I" && flag != "-isystem" && flag != "/I") { - bool userInclude = flag.startsWith("-I"); - const QString pathStr = updatedPathFlag(flag.mid(userInclude ? 2 : 8), - workingDir); - headerPaths.append({pathStr, userInclude - ? HeaderPathType::User - : HeaderPathType::System}); + const QStringList userIncludeFlags{"-I", "/I"}; + const QStringList systemIncludeFlags{"-isystem", "-imsvc", "/imsvc"}; + const QStringList allIncludeFlags = QStringList(userIncludeFlags) << systemIncludeFlags; + const QString includeOpt = Utils::findOrDefault(allIncludeFlags, [flag](const QString &opt) { + return flag.startsWith(opt) && flag != opt; + }); + if (!includeOpt.isEmpty()) { + const QString pathStr = updatedPathFlag(flag.mid(includeOpt.length()), workingDir); + headerPaths.append({pathStr, userIncludeFlags.contains(includeOpt) + ? HeaderPathType::User : HeaderPathType::System}); continue; } @@ -174,8 +177,12 @@ void filteredFlags(const QString &fileName, continue; } - if (flag == "-I" || flag == "-isystem" || flag == "/I") { - includePathType = (flag != "-isystem") ? HeaderPathType::User : HeaderPathType::System; + if (userIncludeFlags.contains(flag)) { + includePathType = HeaderPathType::User; + continue; + } + if (systemIncludeFlags.contains(flag)) { + includePathType = HeaderPathType::System; continue; } diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 43760ed547..e1308ca8fe 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -1199,7 +1199,6 @@ void DocumentManager::checkForReload() if (previousDeletedAnswer != FileDeletedCloseAll) { previousDeletedAnswer = fileDeletedPrompt(document->filePath().toString(), - trigger == IDocument::TriggerExternal, ICore::dialogParent()); } switch (previousDeletedAnswer) { diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 0be92efe8a..5ec572e5a0 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2427,9 +2427,7 @@ IEditor *EditorManager::currentEditor() bool EditorManager::closeAllEditors(bool askAboutModifiedEditors) { DocumentModelPrivate::removeAllSuspendedEntries(); - if (closeDocuments(DocumentModel::openedDocuments(), askAboutModifiedEditors)) - return true; - return false; + return closeDocuments(DocumentModel::openedDocuments(), askAboutModifiedEditors); } void EditorManager::closeOtherDocuments(IDocument *document) diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 732f485824..94e5aa78fe 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -131,6 +131,7 @@ MainWindow::MainWindow() QCoreApplication::setApplicationName(QLatin1String(Constants::IDE_CASED_ID)); QCoreApplication::setApplicationVersion(QLatin1String(Constants::IDE_VERSION_LONG)); QCoreApplication::setOrganizationName(QLatin1String(Constants::IDE_SETTINGSVARIANT_STR)); + QGuiApplication::setApplicationDisplayName(QLatin1String(Constants::IDE_DISPLAY_NAME)); QString baseName = QApplication::style()->objectName(); // Sometimes we get the standard windows 95 style as a fallback if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost() diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 544f57ad3e..f64275d332 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -273,10 +273,7 @@ void ManhattanStyle::polish(QWidget *widget) widget->setContentsMargins(0, 0, 0, 0); widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); - if (qobject_cast<QToolButton*>(widget)) { - widget->setAttribute(Qt::WA_Hover); - widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2); - } else if (qobject_cast<QLineEdit*>(widget)) { + if (qobject_cast<QToolButton*>(widget) || qobject_cast<QLineEdit*>(widget)) { widget->setAttribute(Qt::WA_Hover); widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2); } else if (qobject_cast<QLabel*>(widget)) { @@ -303,12 +300,11 @@ void ManhattanStyle::unpolish(QWidget *widget) QProxyStyle::unpolish(widget); if (panelWidget(widget)) { widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); - if (qobject_cast<QTabBar*>(widget)) - widget->setAttribute(Qt::WA_Hover, false); - else if (qobject_cast<QToolBar*>(widget)) - widget->setAttribute(Qt::WA_Hover, false); - else if (qobject_cast<QComboBox*>(widget)) + if (qobject_cast<QTabBar*>(widget) + || qobject_cast<QToolBar*>(widget) + || qobject_cast<QComboBox*>(widget)) { widget->setAttribute(Qt::WA_Hover, false); + } } } diff --git a/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp b/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp index 65c3dc9769..bb656d1900 100644 --- a/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp +++ b/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp @@ -88,10 +88,7 @@ bool isPreviousLineCppStyleComment(const QTextCursor &cursor) return false; const QString text = actual.text().trimmed(); - if (text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!"))) - return true; - - return false; + return text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!")); } /// Check if next line is a CppStyle Doxygen Comment @@ -106,10 +103,7 @@ bool isNextLineCppStyleComment(const QTextCursor &cursor) return false; const QString text = actual.text().trimmed(); - if (text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!"))) - return true; - - return false; + return text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!")); } bool isCppStyleContinuation(const QTextCursor& cursor) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index beb2e2aaf7..7368ecb416 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -442,9 +442,7 @@ static bool canReplaceSpecifier(TranslationUnit *translationUnit, SpecifierAST * return false; } } - if (specifier->asAttributeSpecifier()) - return false; - return true; + return !specifier->asAttributeSpecifier(); } static SpecifierAST *findFirstReplaceableSpecifier(TranslationUnit *translationUnit, SpecifierListAST *list) diff --git a/src/plugins/cppeditor/cppminimizableinfobars.cpp b/src/plugins/cppeditor/cppminimizableinfobars.cpp index f90ae64227..7e65829219 100644 --- a/src/plugins/cppeditor/cppminimizableinfobars.cpp +++ b/src/plugins/cppeditor/cppminimizableinfobars.cpp @@ -156,7 +156,7 @@ static InfoBarEntry createMinimizableInfo(const Id &id, void MinimizableInfoBars::addNoProjectConfigurationEntry(const Id &id) { const QString text = tr("<b>Warning</b>: This file is not part of any project. " - "The code model might have issues to parse this file properly."); + "The code model might have issues parsing this file properly."); m_infoBar.addInfo(createMinimizableInfo(id, text, []() { settings()->setShowNoProjectInfoBar(false); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 7689e960e0..d384322bdd 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -581,21 +581,11 @@ static bool checkDeclarationForSplit(SimpleDeclarationAST *declaration) for (SpecifierListAST *it = declaration->decl_specifier_list; it; it = it->next) { SpecifierAST *specifier = it->value; - - if (specifier->asEnumSpecifier() != nullptr) - return false; - - else if (specifier->asClassSpecifier() != nullptr) + if (specifier->asEnumSpecifier() || specifier->asClassSpecifier()) return false; } - if (!declaration->declarator_list) - return false; - - else if (!declaration->declarator_list->next) - return false; - - return true; + return declaration->declarator_list && declaration->declarator_list->next; } namespace { @@ -3502,9 +3492,7 @@ public: bool preVisit(AST *) override { - if (m_done) - return false; - return true; + return !m_done; } void statement(StatementAST *stmt) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index aafcd35b37..ee534757ea 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -329,9 +329,14 @@ void CompilerOptionsBuilder::addPrecompiledHeaderOptions(UsePrecompiledHeaders u for (const QString &pchFile : m_projectPart.precompiledHeaders) { // Bail if build system precomiple header artifacts exists // Clang cannot handle foreign PCH files. - if (QFile::exists(pchFile + ".gch") || QFile::exists(pchFile + ".pch")) + if (QFile::exists(pchFile + ".gch") || QFile::exists(pchFile + ".pch")) { usePrecompiledHeaders = UsePrecompiledHeaders::No; + // In case of Clang compilers, remove the pch-inclusion arguments + remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".gch"}); + remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".pch"}); + } + if (usePrecompiledHeaders == UsePrecompiledHeaders::No) { // CMake PCH will already have force included the header file in // command line options, remove it if exists. diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index f4458bd059..b42875492a 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -461,11 +461,7 @@ Scope *CheckSymbols::enclosingScope() const bool CheckSymbols::preVisit(AST *ast) { _astStack.append(ast); - - if (isCanceled()) - return false; - - return true; + return !isCanceled(); } void CheckSymbols::postVisit(AST *) @@ -1256,13 +1252,12 @@ bool CheckSymbols::maybeAddTypeOrStatic(const QList<LookupItem> &candidates, Nam Symbol *c = r.declaration(); if (c->isUsingDeclaration()) // skip using declarations... continue; - else if (c->isUsingNamespaceDirective()) // ... and using namespace directives. + if (c->isUsingNamespaceDirective()) // ... and using namespace directives. continue; - else if (c->isTypedef() || c->isNamespace() || - c->isStatic() || //consider also static variable - c->isClass() || c->isEnum() || isTemplateClass(c) || - c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != nullptr) { - + if (c->isTypedef() || c->isNamespace() || + c->isStatic() || //consider also static variable + c->isClass() || c->isEnum() || isTemplateClass(c) || + c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum()) { int line, column; getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); @@ -1298,11 +1293,11 @@ bool CheckSymbols::maybeAddField(const QList<LookupItem> &candidates, NameAST *a Symbol *c = r.declaration(); if (!c) continue; - else if (!c->isDeclaration()) + if (!c->isDeclaration()) return false; - else if (!(c->enclosingScope() && c->enclosingScope()->isClass())) + if (!(c->enclosingScope() && c->enclosingScope()->isClass())) return false; // shadowed - else if (c->isTypedef() || (c->type() && c->type()->isFunctionType())) + if (c->isTypedef() || (c->type() && c->type()->isFunctionType())) return false; // shadowed int line, column; diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index fca7998ece..413a5fde7b 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -179,8 +179,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) switch (kind) { case T_LBRACE: enter(brace_list_open); break; case T_RBRACE: leave(true); continue; - case T_SEMICOLON: leave(); continue; - case T_RPAREN: leave(); continue; + case T_SEMICOLON: + case T_RPAREN: case T_COMMA: leave(); continue; default: enter(assign_open); continue; } break; @@ -205,8 +205,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) case assign_open: switch (kind) { case T_RBRACE: leave(true); continue; - case T_SEMICOLON: leave(); continue; - case T_RPAREN: leave(); continue; + case T_SEMICOLON: + case T_RPAREN: case T_COMMA: leave(); continue; default: tryExpression(); break; } break; diff --git a/src/plugins/cpptools/cppcompletionassistprovider.cpp b/src/plugins/cpptools/cppcompletionassistprovider.cpp index a06c4c7b42..08100dba44 100644 --- a/src/plugins/cpptools/cppcompletionassistprovider.cpp +++ b/src/plugins/cpptools/cppcompletionassistprovider.cpp @@ -51,9 +51,7 @@ bool CppCompletionAssistProvider::isActivationCharSequence(const QString &sequen const QChar &ch = sequence.at(2); const QChar &ch2 = sequence.at(1); const QChar &ch3 = sequence.at(0); - if (activationSequenceChar(ch, ch2, ch3, nullptr, true, false) != 0) - return true; - return false; + return activationSequenceChar(ch, ch2, ch3, nullptr, true, false); } bool CppCompletionAssistProvider::isContinuationChar(const QChar &c) const diff --git a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp index 9a66467951..ded069a96e 100644 --- a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp @@ -374,7 +374,7 @@ Symbol *findDefinition(Symbol *symbol, const Snapshot &snapshot, SymbolFinder *s if (symbol->isFunction()) return nullptr; // symbol is a function definition. - else if (!symbol->type()->isFunctionType()) + if (!symbol->type()->isFunctionType()) return nullptr; // not a function declaration return symbolFinder->findMatchingDefinition(symbol, snapshot); diff --git a/src/plugins/cpptools/cpprefactoringchanges.cpp b/src/plugins/cpptools/cpprefactoringchanges.cpp index 4d16dd4813..c063e1efdd 100644 --- a/src/plugins/cpptools/cpprefactoringchanges.cpp +++ b/src/plugins/cpptools/cpprefactoringchanges.cpp @@ -172,10 +172,7 @@ bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const int start = startOf(tokenIndex); int end = endOf(tokenIndex); - if (cursorBegin >= start && cursorBegin <= end) - return true; - - return false; + return cursorBegin >= start && cursorBegin <= end; } bool CppRefactoringFile::isCursorOn(const AST *ast) const @@ -186,10 +183,7 @@ bool CppRefactoringFile::isCursorOn(const AST *ast) const int start = startOf(ast); int end = endOf(ast); - if (cursorBegin >= start && cursorBegin <= end) - return true; - - return false; + return cursorBegin >= start && cursorBegin <= end; } Utils::ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp index 5c7c8110ca..2fdce4c743 100644 --- a/src/plugins/cpptools/semantichighlighter.cpp +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -87,7 +87,7 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) { if (documentRevision() != m_revision) return; // outdated - else if (!m_watcher || m_watcher->isCanceled()) + if (!m_watcher || m_watcher->isCanceled()) return; // aborted qCDebug(log) << "onHighlighterResultAvailable()" << from << to; diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 90dd8f3c86..6015f29dec 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1065,6 +1065,7 @@ QVariant BreakpointItem::data(int column, int role) const if (role == Qt::DisplayRole) { if (!m_parameters.functionName.isEmpty()) return simplifyType(m_parameters.functionName); + if (m_parameters.type == BreakpointAtMain || m_parameters.type == BreakpointAtThrow || m_parameters.type == BreakpointAtCatch @@ -1073,15 +1074,13 @@ QVariant BreakpointItem::data(int column, int role) const //|| m_response.type == BreakpointAtVFork || m_parameters.type == BreakpointAtSysCall) return typeToString(m_parameters.type); - if (m_parameters.type == WatchpointAtAddress) { - quint64 address = m_parameters.address ? m_parameters.address : m_parameters.address; - return BreakHandler::tr("Data at 0x%1").arg(address, 0, 16); - } - if (m_parameters.type == WatchpointAtExpression) { - QString expression = !m_parameters.expression.isEmpty() - ? m_parameters.expression : m_parameters.expression; - return BreakHandler::tr("Data at %1").arg(expression); - } + + if (m_parameters.type == WatchpointAtAddress) + return BreakHandler::tr("Data at 0x%1").arg(m_parameters.address, 0, 16); + + if (m_parameters.type == WatchpointAtExpression) + return BreakHandler::tr("Data at %1").arg(m_parameters.expression); + return empty; } break; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 4e04a02fc4..798013ed42 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -394,14 +394,7 @@ void CdbEngine::setupEngine() if (!sourcePaths.isEmpty()) debugger.addArgs({"-srcpath", sourcePaths.join(';')}); - QStringList symbolPaths = stringListSetting(CdbSymbolPaths); - QString symbolPath = sp.inferior.environment.expandedValueForKey("_NT_ALT_SYMBOL_PATH"); - if (!symbolPath.isEmpty()) - symbolPaths += symbolPath; - symbolPath = sp.inferior.environment.expandedValueForKey("_NT_SYMBOL_PATH"); - if (!symbolPath.isEmpty()) - symbolPaths += symbolPath; - debugger.addArgs({"-y", symbolPaths.join(';')}); + debugger.addArgs({"-y", QChar('"') + stringListSetting(CdbSymbolPaths).join(';') + '"'}); switch (sp.startMode) { case StartInternal: @@ -501,6 +494,16 @@ void CdbEngine::handleInitialSessionIdle() } // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only? BreakpointManager::claimBreakpointsForEngine(this); + + QStringList symbolPaths = stringListSetting(CdbSymbolPaths); + QString symbolPath = rp.inferior.environment.expandedValueForKey("_NT_ALT_SYMBOL_PATH"); + if (!symbolPath.isEmpty()) + symbolPaths += symbolPath; + symbolPath = rp.inferior.environment.expandedValueForKey("_NT_SYMBOL_PATH"); + if (!symbolPath.isEmpty()) + symbolPaths += symbolPath; + + runCommand({QString(".sympath \"") + symbolPaths.join(';') + '"'}); runCommand({".symopt+0x8000"}); // disable searching public symbol table - improving the symbol lookup speed runCommand({"sxn 0x4000001f", NoFlags}); // Do not break on WowX86 exceptions. runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints. diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 0fcd7a165a..3287095d82 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -381,6 +381,11 @@ static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &t return DebuggerItem::DoesNotMatch; // We have at least 'Matches well' now. Mark the combinations we really like. + if (HostOsInfo::isWindowsHost() && engineType == CdbEngineType + && targetAbi.osFlavor() >= Abi::WindowsMsvc2005Flavor + && targetAbi.osFlavor() <= Abi::WindowsLastMsvcFlavor) { + return DebuggerItem::MatchesPerfectly; + } if (HostOsInfo::isWindowsHost() && engineType == GdbEngineType && targetAbi.osFlavor() == Abi::WindowsMSysFlavor) return DebuggerItem::MatchesPerfectly; if (HostOsInfo::isLinuxHost() && engineType == GdbEngineType && targetAbi.os() == Abi::LinuxOS) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ff0197c225..6cf048420e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -806,7 +806,7 @@ void GdbEngine::runCommand(const DebuggerCommand &command) int GdbEngine::commandTimeoutTime() const { int time = action(GdbWatchdogTimeout)->value().toInt(); - return 1000 * qMax(40, time); + return 1000 * qMax(20, time); } void GdbEngine::commandTimeout() diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 9cb88b077e..4fd1e40669 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -111,9 +111,6 @@ QVariant ModuleItem::data(int column, int role) const "information.\nStepping into the module or setting " "breakpoints by file and line will not work."); case PlainSymbols: - return tr("This module contains debug information.\nStepping " - "into the module or setting breakpoints by file and " - "line is expected to work."); case FastSymbols: return tr("This module contains debug information.\nStepping " "into the module or setting breakpoints by file and " diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp index 0a29750b85..8af763f426 100644 --- a/src/plugins/help/localhelpmanager.cpp +++ b/src/plugins/help/localhelpmanager.cpp @@ -544,12 +544,9 @@ void LocalHelpManager::updateFilterModel() bool LocalHelpManager::canOpenOnlineHelp(const QUrl &url) { const QString address = url.toString(); - if (address.startsWith("qthelp://org.qt-project.") - || address.startsWith("qthelp://com.nokia.") - || address.startsWith("qthelp://com.trolltech.")) { - return true; - } - return false; + return address.startsWith("qthelp://org.qt-project.") + || address.startsWith("qthelp://com.nokia.") + || address.startsWith("qthelp://com.trolltech."); } bool LocalHelpManager::openOnlineHelp(const QUrl &url) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 83b67eadbc..defbd0bdac 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -459,7 +459,7 @@ void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *doc void LanguageClientManager::documentClosed(Core::IDocument *document) { if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) { - for (Client *client : reachableClients()) + for (Client *client : m_clients) client->closeDocument(textDocument); m_clientForDocument.remove(textDocument); } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index c476aaabcf..22c43650ee 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -213,6 +213,7 @@ void updateEditorToolBar(Core::IEditor *editor) } else { widget->toolBar()->removeAction(action); actions.remove(widget); + delete action; } } else if (client) { const QIcon icon = Utils::Icon({{":/languageclient/images/languageclient.png", diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index c61a3b6f6d..9cbd8a5a83 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -234,11 +234,26 @@ static PackageOptions *createQulPackage() static PackageOptions *createArmGccPackage() { - const QString defaultPath = - Utils::HostOsInfo::isWindowsHost() ? - QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles(x86)")) - + "/GNU Tools ARM Embedded/" - : QString("%{Env:ARMGCC_DIR}"); + const char envVar[] = "ARMGCC_DIR"; + + QString defaultPath; + if (qEnvironmentVariableIsSet(envVar)) + defaultPath = qEnvironmentVariable(envVar); + if (defaultPath.isEmpty() && Utils::HostOsInfo::isWindowsHost()) { + const QDir installDir( + qEnvironmentVariable("ProgramFiles(x86)") + "/GNU Tools ARM Embedded/"); + if (installDir.exists()) { + // If GNU Tools installation dir has only one sub dir, + // select the sub dir, otherwise the installation dir. + const QFileInfoList subDirs = + installDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + if (subDirs.count() == 1) + defaultPath = subDirs.first().filePath() + '/'; + } + } + if (defaultPath.isEmpty()) + defaultPath = QDir::homePath(); + auto result = new PackageOptions( PackageOptions::tr("GNU Arm Embedded Toolchain"), defaultPath, @@ -246,7 +261,7 @@ static PackageOptions *createArmGccPackage() Constants::SETTINGS_KEY_PACKAGE_ARMGCC); result->setDownloadUrl( "https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads"); - result->setEnvironmentVariableName("ARMGCC_DIR"); + result->setEnvironmentVariableName(envVar); return result; } @@ -286,8 +301,8 @@ static PackageOptions *createStm32CubeProgrammerPackage() static PackageOptions *createEvkbImxrt1050SdkPackage() { auto result = new PackageOptions( - PackageOptions::tr("NXP EVKB-IMXRT1050 SDK"), - "%{Env:EVKB_IMXRT1050_SDK_PATH}", + PackageOptions::tr("NXP i.MXRT SDK"), + "%{Env:EVKB_IMXRT1050_SDK_PATH}", // TODO: Try to not use 1050 specifics "EVKB-IMXRT1050_manifest_v3_5.xml", "evkbImxrt1050Sdk"); result->setDownloadUrl("https://mcuxpresso.nxp.com/en/welcome"); @@ -306,6 +321,7 @@ static PackageOptions *createSeggerJLinkPackage() Utils::HostOsInfo::withExecutableSuffix("JLink"), "seggerJLink"); result->setDownloadUrl("https://www.segger.com/downloads/jlink"); + result->setEnvironmentVariableName("SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH"); return result; } @@ -454,10 +470,11 @@ static void setKitEnvironment(ProjectExplorer::Kit *k, const BoardOptions* board changes.append({package->environmentVariableName(), QDir::toNativeSeparators(package->path())}); } - if (!pathAdditions.isEmpty()) { - pathAdditions.append("${Path}"); - changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); - } + pathAdditions.append("${Path}"); + if (Utils::HostOsInfo::isWindowsHost()) + pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath())); // for jom + pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath() + "/clang/bin")); + changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); EnvironmentKitAspect::setEnvironmentChanges(k, changes); } @@ -470,6 +487,8 @@ static void setKitCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* boar ("%{CurrentBuild:Env:Qul_DIR}/" + board->toolChainFile()).toUtf8())); CMakeConfigurationKitAspect::setConfiguration(k, config); + if (Utils::HostOsInfo::isWindowsHost()) + CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM"); } ProjectExplorer::Kit *McuSupportOptions::kit(const BoardOptions* board) diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 1396d4226f..9057e2a054 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -68,7 +68,7 @@ McuSupportOptionsWidget::McuSupportOptionsWidget(const McuSupportOptions *option auto mainLayout = new QVBoxLayout(this); auto boardChooserlayout = new QHBoxLayout; - auto boardChooserLabel = new QLabel(McuSupportOptionsPage::tr("MCU board:")); + auto boardChooserLabel = new QLabel(McuSupportOptionsPage::tr("Target:")); boardChooserlayout->addWidget(boardChooserLabel); auto boardComboBox = new QComboBox; boardChooserLabel->setBuddy(boardComboBox); diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp index 92dcb4181f..4ec72227e1 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp @@ -94,6 +94,7 @@ public: r.workingDirectory = target->activeBuildConfiguration()->buildDirectory().toUserOutput(); r.setCommandLine(cmd); + r.environment = target->activeBuildConfiguration()->environment(); SimpleTargetRunner::doStart(r, {}); }); } diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 420a10ba98..42a34bbcdc 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -209,7 +209,6 @@ static Abi macAbiForCpu(quint32 type) { case 0x01000000 + 7: // CPU_TYPE_X86_64 return Abi(Abi::X86Architecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 64); case 18: // CPU_TYPE_POWERPC - return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 32); case 0x01000000 + 18: // CPU_TYPE_POWERPC64 return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 32); case 12: // CPU_TYPE_ARM @@ -515,9 +514,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple) if (flavor == UnknownFlavor) flavor = GenericFlavor; format = ElfFormat; - } else if (p == "android") { - flavor = AndroidLinuxFlavor; - } else if (p == "androideabi") { + } else if (p == "android" || p == "androideabi") { flavor = AndroidLinuxFlavor; } else if (p.startsWith("freebsd")) { os = BsdOS; diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 21794d5be7..47605b10e6 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -97,6 +97,7 @@ public: WindowsMsvc2015Flavor, WindowsMsvc2017Flavor, WindowsMsvc2019Flavor, + WindowsLastMsvcFlavor = WindowsMsvc2019Flavor, WindowsMSysFlavor, WindowsCEFlavor, diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e761647398..c5fb985707 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -221,8 +221,12 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, const QStringList arguments = extraArgs; arguments << "-dumpmachine"; QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); - if (machine.isEmpty()) + if (machine.isEmpty()) { + // ICC does not implement the -dumpmachine option on macOS. + if (HostOsInfo::isMacHost() && (path.fileName() == "icc" || path.fileName() == "icpc")) + return GccToolChain::DetectedAbisResult({Abi::hostAbi()}); return GccToolChain::DetectedAbisResult(); // no need to continue if running failed once... + } return GccToolChain::DetectedAbisResult(guessGccAbi(machine, macros), machine); } @@ -660,7 +664,7 @@ ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner extraHeaderPathsFunction, flags, sysRoot, - /*target=*/""); // Target must be empty for gcc. + /*originalTargetTriple=*/""); // Must be empty for gcc. }; } @@ -1335,9 +1339,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange() // Find a good ABI for the new compiler: Abi newAbi; - if (customAbi) - newAbi = currentAbi; - else if (abiList.contains(currentAbi)) + if (customAbi || abiList.contains(currentAbi)) newAbi = currentAbi; m_abiWidget->setAbis(abiList, newAbi); @@ -1833,7 +1835,7 @@ QList<ToolChain *> MingwToolChainFactory::detectForImport(const ToolChainDescrip LinuxIccToolChain::LinuxIccToolChain() : GccToolChain(Constants::LINUXICC_TOOLCHAIN_TYPEID) { - setTypeDisplayName(LinuxIccToolChainFactory::tr("Linux ICC")); + setTypeDisplayName(LinuxIccToolChainFactory::tr("ICC")); } /** @@ -1874,7 +1876,7 @@ QStringList LinuxIccToolChain::suggestedMkspecList() const LinuxIccToolChainFactory::LinuxIccToolChainFactory() { - setDisplayName(tr("Linux ICC")); + setDisplayName(tr("ICC")); setSupportedToolChainType(Constants::LINUXICC_TOOLCHAIN_TYPEID); setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID}); setToolchainConstructor([] { return new LinuxIccToolChain; }); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 432a22fec1..dbae037260 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -977,9 +977,7 @@ bool ListField::validate(MacroExpander *expander, QString *message) return false; updateIndex(); - if (selectionModel()->hasSelection()) - return true; - return false; + return selectionModel()->hasSelection(); } void ListField::initializeData(MacroExpander *expander) @@ -1116,11 +1114,8 @@ void ComboBoxField::setup(JsonFieldPage *page, const QString &name) selectionModel()->blockSignals(true); w->blockSignals(false); }); - page->registerObjectAsFieldWithName<QItemSelectionModel>(name, selectionModel(), &QItemSelectionModel::selectionChanged, [this]() { - const QModelIndex i = selectionModel()->currentIndex(); - if (i.isValid()) - return i.data(ValueRole); - return QVariant(); + page->registerObjectAsFieldWithName<QComboBox>(name, w, QOverload<int>::of(&QComboBox::activated), [w]() { + return w->currentData(ValueRole); }); QObject::connect(selectionModel(), &QItemSelectionModel::selectionChanged, page, [page]() { emit page->completeChanged(); @@ -1143,6 +1138,13 @@ void ComboBoxField::initializeData(MacroExpander *expander) w->setCurrentIndex(selectionModel()->currentIndex().row()); } +QVariant ComboBoxField::toSettings() const +{ + if (auto w = qobject_cast<QComboBox*>(widget())) + return w->currentData(ValueRole); + return {}; +} + void IconListField::setup(JsonFieldPage *page, const QString &name) { auto w = qobject_cast<QListView*>(widget()); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h index 62db37aff6..6e91500b8e 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h @@ -236,10 +236,11 @@ private: class ComboBoxField : public ListField { -public: +private: void setup(JsonFieldPage *page, const QString &name) override; QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; void initializeData(Utils::MacroExpander *expander) override; + QVariant toSettings() const override; }; class IconListField : public ListField diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index fb3e912a65..4d7aee5fc8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2790,9 +2790,7 @@ bool ProjectExplorerPlugin::coreAboutToClose() if (box.clickedButton() != closeAnyway) return false; } - if (!dd->m_outputPane.aboutToClose()) - return false; - return true; + return dd->m_outputPane.aboutToClose(); } void ProjectExplorerPlugin::handleCommandLineArguments(const QStringList &arguments) diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 8f4d5adef7..b3ae5756e7 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -382,10 +382,7 @@ Node *ProjectTreeWidget::nodeForFile(const FilePath &fileName) if (ProjectNode *projectNode = project->rootProjectNode()) { projectNode->forEachGenericNode([&](Node *node) { if (node->filePath() == fileName) { - if (!bestNode) { - bestNode = node; - bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); - } else if (priority(node) < priority(bestNode)) { + if (!bestNode || priority(node) < priority(bestNode)) { bestNode = node; bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); } else if (priority(node) == priority(bestNode)) { diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 0f2bfb4dc3..8d74b3f648 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -82,7 +82,6 @@ QVariant ProjectModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return data.second; case Qt::ToolTipRole: - return data.first; case FilePathRole: return data.first; case PrettyFilePathRole: diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index 96cfc251d3..dfa20793e3 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -213,8 +213,6 @@ public: { switch (role) { case Qt::DisplayRole: - return m_project->displayName(); - case ProjectDisplayNameRole: return m_project->displayName(); diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index e1345cb50e..79cfe02fdb 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -669,8 +669,7 @@ TargetGroupItem::TargetGroupItem(const QString &displayName, Project *project) { d->m_displayName = displayName; QObject::connect(project, &Project::addedTarget, - d.get(), &TargetGroupItemPrivate::handleTargetAdded, - Qt::QueuedConnection); + d.get(), &TargetGroupItemPrivate::handleTargetAdded); QObject::connect(project, &Project::removedTarget, d.get(), &TargetGroupItemPrivate::handleTargetRemoved); QObject::connect(project, &Project::activeTargetChanged, diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index d80b2689c1..a200b9233d 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -101,7 +101,7 @@ public: noValidKitLabel = new QLabel(setupTargetPage); noValidKitLabel->setWordWrap(true); noValidKitLabel->setText(TargetSetupPage::tr("<span style=\" font-weight:600;\">No suitable kits found.</span><br/>" - "Please add a kit in the <a href=\"buildandrun\">options</a> " + "Add a kit in the <a href=\"buildandrun\">options</a> " "or via the maintenance tool of the SDK.")); noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); noValidKitLabel->setVisible(false); diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp index cc5257fabc..ddcda6d8ff 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.cpp +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -122,7 +122,7 @@ bool TargetSetupWidget::isKitSelected() const void TargetSetupWidget::setKitSelected(bool b) { // Only check target if there are build configurations possible - b &= !selectedBuildInfoList().isEmpty(); + b &= hasSelectedBuildConfigurations(); m_ignoreChange = true; m_detailsWidget->setChecked(b); m_detailsWidget->widget()->setEnabled(b); @@ -187,9 +187,12 @@ void TargetSetupWidget::targetCheckBoxToggled(bool b) if (m_ignoreChange) return; m_detailsWidget->widget()->setEnabled(b); - m_detailsWidget->setState(b && Utils::contains(m_infoStore, &BuildInfoStore::hasIssues) - ? Utils::DetailsWidget::Expanded - : Utils::DetailsWidget::Collapsed); + if (b && (contains(m_infoStore, &BuildInfoStore::hasIssues) + || !contains(m_infoStore, &BuildInfoStore::isEnabled))) { + m_detailsWidget->setState(DetailsWidget::Expanded); + } else if (!b) { + m_detailsWidget->setState(Utils::DetailsWidget::Collapsed); + } emit selectedToggled(); } @@ -230,12 +233,13 @@ void TargetSetupWidget::update(const Kit::Predicate &predicate) // Kits that don't fulfill the project predicate are not selectable, because we cannot // guarantee that we can handle the project sensibly (e.g. qmake project without Qt). if (predicate && !predicate(kit())) { - setEnabled(false); + toggleEnabled(false); + m_infoStore.clear(); m_detailsWidget->setToolTip(tr("You cannot use this kit, because it does not fulfill " "the project's prerequisites.")); return; } - setEnabled(true); + toggleEnabled(true); m_detailsWidget->setIcon(kit()->isValid() ? kit()->icon() : Icons::CRITICAL.icon()); m_detailsWidget->setToolTip(m_kit->toHtml()); updateDefaultBuildDirectories(); @@ -251,6 +255,22 @@ const QList<BuildInfo> TargetSetupWidget::buildInfoList(const Kit *k, const File return {info}; } +bool TargetSetupWidget::hasSelectedBuildConfigurations() const +{ + return !selectedBuildInfoList().isEmpty(); +} + +void TargetSetupWidget::toggleEnabled(bool enabled) +{ + m_detailsWidget->widget()->setEnabled(enabled && hasSelectedBuildConfigurations()); + m_detailsWidget->setCheckable(enabled); + m_detailsWidget->setExpandable(enabled); + if (!enabled) { + m_detailsWidget->setState(DetailsWidget::Collapsed); + m_detailsWidget->setChecked(false); + } +} + const QList<BuildInfo> TargetSetupWidget::selectedBuildInfoList() const { QList<BuildInfo> result; @@ -276,6 +296,7 @@ void TargetSetupWidget::updateDefaultBuildDirectories() for (const BuildInfo &buildInfo : buildInfoList(m_kit, m_projectPath)) { if (!buildInfo.factory()) continue; + bool found = false; for (BuildInfoStore &buildInfoStore : m_infoStore) { if (buildInfoStore.buildInfo.typeName == buildInfo.typeName) { if (!buildInfoStore.customBuildDir) { @@ -283,9 +304,12 @@ void TargetSetupWidget::updateDefaultBuildDirectories() buildInfoStore.pathChooser->setFileName(buildInfo.buildDirectory); m_ignoreChange = false; } + found = true; break; } } + if (!found) // the change of the kit may have produced more build information than before + addBuildInfo(buildInfo, false); } } diff --git a/src/plugins/projectexplorer/targetsetupwidget.h b/src/plugins/projectexplorer/targetsetupwidget.h index 80f64ad918..6534baf700 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.h +++ b/src/plugins/projectexplorer/targetsetupwidget.h @@ -78,6 +78,9 @@ signals: private: static const QList<BuildInfo> buildInfoList(const Kit *k, const Utils::FilePath &projectPath); + bool hasSelectedBuildConfigurations() const; + + void toggleEnabled(bool enabled); void checkBoxToggled(bool b); void pathChanged(); void targetCheckBoxToggled(bool b); diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 676bcf7990..5f3c3692b7 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -799,7 +799,7 @@ QVariant UserFileVersion19Upgrader::process(const QVariant &entry, const QString "ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory", "Qbs.RunConfiguration.WorkingDirectory", "Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory", - "RemoteLinux.CustomRunConfig.WorkingDirectory" + "RemoteLinux.CustomRunConfig.WorkingDirectory", "RemoteLinux.RunConfig.WorkingDirectory", "WorkingDir"}; static const QStringList termKeys = {"CMakeProjectManager.CMakeRunConfiguration.UseTerminal", diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 4477f11cb1..41386ef611 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -257,8 +257,10 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Core::Id id) connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, interpreterAspect, &InterpreterAspect::updateInterpreters); - interpreterAspect->updateInterpreters(PythonSettings::interpreters()); - interpreterAspect->setDefaultInterpreter(PythonSettings::defaultInterpreter()); + QList<Interpreter> interpreters = PythonSettings::detectPythonVenvs(project()->projectDirectory()); + aspect<InterpreterAspect>()->updateInterpreters(PythonSettings::interpreters()); + aspect<InterpreterAspect>()->setDefaultInterpreter( + interpreters.isEmpty() ? PythonSettings::defaultInterpreter() : interpreters.first()); auto scriptAspect = addAspect<MainScriptAspect>(); scriptAspect->setSettingsKey("PythonEditor.RunConfiguation.Script"); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index d9ab47093c..acb7a50ddd 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -211,6 +211,7 @@ public: InterpreterOptionsPage(); void setInterpreter(const QList<Interpreter> &interpreters) { m_interpreters = interpreters; } + void addInterpreter(const Interpreter &interpreter) { m_interpreters << interpreter; } QList<Interpreter> interpreters() const { return m_interpreters; } void setDefaultInterpreter(const QString &defaultId) { m_defaultInterpreterId = defaultId; } @@ -278,6 +279,7 @@ Interpreter::Interpreter(const FilePath &python, const QString &defaultName, boo { SynchronousProcess pythonProcess; pythonProcess.setProcessChannelMode(QProcess::MergedChannels); + pythonProcess.setTimeoutS(1); SynchronousProcessResponse response = pythonProcess.runBlocking( CommandLine(python, {"--version"})); if (response.result == SynchronousProcessResponse::Finished) @@ -465,11 +467,21 @@ void PythonSettings::init() void PythonSettings::setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId) { + if (defaultId == interpreterOptionsPage().defaultInterpreter().id + && interpreters == interpreterOptionsPage().interpreters()) { + return; + } interpreterOptionsPage().setInterpreter(interpreters); interpreterOptionsPage().setDefaultInterpreter(defaultId); - toSettings(Core::ICore::settings(), {interpreters, defaultId}); - if (QTC_GUARD(settingsInstance)) - emit settingsInstance->interpretersChanged(interpreters, defaultId); + saveSettings(); +} + +void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault) +{ + interpreterOptionsPage().addInterpreter(interpreter); + if (isDefault) + interpreterOptionsPage().setDefaultInterpreter(interpreter.id); + saveSettings(); } PythonSettings *PythonSettings::instance() @@ -478,6 +490,52 @@ PythonSettings *PythonSettings::instance() return settingsInstance; } +QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path) +{ + QList<Interpreter> result; + QDir dir = path.toFileInfo().isDir() ? QDir(path.toString()) : path.toFileInfo().dir(); + if (dir.exists()) { + const QString venvPython = HostOsInfo::withExecutableSuffix("python"); + const QString activatePath = HostOsInfo::isWindowsHost() ? QString{"Scripts"} + : QString{"bin"}; + do { + for (const QString &directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (dir.cd(directory)) { + if (dir.cd(activatePath)) { + if (dir.exists("activate") && dir.exists(venvPython)) { + FilePath python = FilePath::fromString(dir.absoluteFilePath(venvPython)); + dir.cdUp(); + const QString defaultName = QString("Python (%1 Virtual Environment)") + .arg(dir.dirName()); + Interpreter interpreter + = Utils::findOrDefault(PythonSettings::interpreters(), + Utils::equal(&Interpreter::command, python)); + if (interpreter.command.isEmpty()) { + interpreter = Interpreter(python, defaultName); + PythonSettings::addInterpreter(interpreter); + } + result << interpreter; + } else { + dir.cdUp(); + } + } + dir.cdUp(); + } + } + } while (dir.cdUp()); + } + return result; +} + +void PythonSettings::saveSettings() +{ + const QList<Interpreter> &interpreters = interpreterOptionsPage().interpreters(); + const QString &defaultId = interpreterOptionsPage().defaultInterpreter().id; + toSettings(Core::ICore::settings(), {interpreters, defaultId}); + if (QTC_GUARD(settingsInstance)) + emit settingsInstance->interpretersChanged(interpreters, defaultId); +} + QList<Interpreter> PythonSettings::interpreters() { return interpreterOptionsPage().interpreters(); diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 7ca5218ae3..0ef6c62a0f 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -26,6 +26,7 @@ #pragma once #include <utils/fileutils.h> +#include <utils/optional.h> #include <QUuid> @@ -43,6 +44,11 @@ public: const QString &name, const Utils::FilePath &command); + inline bool operator==(const Interpreter &other) const + { + return id == other.id && name == other.name && command == other.command; + } + QString id = QUuid::createUuid().toString(); QString name; Utils::FilePath command; @@ -57,13 +63,18 @@ public: static QList<Interpreter> interpreters(); static Interpreter defaultInterpreter(); static void setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId); + static void addInterpreter(const Interpreter &interpreter, bool isDefault = false); static PythonSettings *instance(); + static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path); + signals: void interpretersChanged(const QList<Interpreter> &interpreters, const QString &defaultId); private: PythonSettings(); + + static void saveSettings(); }; } // namespace Internal diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 03096ee96e..aa7051b396 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -175,6 +175,11 @@ static FilePath detectPython(const FilePath &documentPath) } } + // check whether this file is inside a python virtual environment + QList<Interpreter> venvInterpreters = PythonSettings::detectPythonVenvs(documentPath); + if (!python.exists()) + python = venvInterpreters.value(0).command; + if (!python.exists()) python = PythonSettings::defaultInterpreter().command; @@ -248,9 +253,15 @@ public: ? QString{"python-language-server[pyflakes]"} : QString{"python-language-server[all]"}; - m_process.start(m_python.toString(), {"-m", "pip", "install", "--user", pylsVersion}); + QStringList arguments = {"-m", "pip", "install", pylsVersion}; + + // add --user to global pythons, but skip it for venv pythons + if (!QDir(m_python.parentDir().toString()).exists("activate")) + arguments << "--user"; + + m_process.start(m_python.toString(), arguments); - Core::MessageManager::write(tr("Running '%1 %2' to install python language server") + Core::MessageManager::write(tr("Running \"%1 %2\" to install Python language server") .arg(m_process.program(), m_process.arguments().join(' '))); m_killTimer.setSingleShot(true); @@ -261,7 +272,7 @@ private: void cancel() { SynchronousProcess::stopProcess(m_process); - Core::MessageManager::write(tr("The Python language server installation canceled by %1.") + Core::MessageManager::write(tr("The Python language server installation was canceled by %1.") .arg(m_killTimer.isActive() ? tr("user") : tr("time out"))); } @@ -371,7 +382,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, && infoBar->canInfoBeAdded(installPylsInfoBarId)) { auto message = tr("Install and set up Python language server (PyLS) for %1 (%2). " - "The language server provides Python specific completions and annotations.") + "The language server provides Python specific completion and annotation.") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(installPylsInfoBarId, message, @@ -383,7 +394,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, } else if (lsState.state == PythonLanguageServerState::AlreadyInstalled && infoBar->canInfoBeAdded(startPylsInfoBarId)) { auto message = tr("Found a Python language server for %1 (%2). " - "Should this one be set up for this document?") + "Set it up for this document?") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(startPylsInfoBarId, message, diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index c645a96774..df5d381511 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -298,6 +298,7 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/propertyeditor SOURCES + aligndistribute.cpp aligndistribute.h designerpropertymap.cpp designerpropertymap.h fileresourcesmodel.cpp fileresourcesmodel.h itemfiltermodel.cpp itemfiltermodel.h diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index d06ea3c495..72bdf4be13 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -113,9 +113,20 @@ QToolBar *CurveEditor::createToolBar() durationWidget->setLayout(durationBox); bar->addWidget(durationWidget); + auto *cfspin = new QSpinBox; + cfspin->setMinimum(0); + cfspin->setMaximum(std::numeric_limits<int>::max()); + + auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged); + connect(cfspin, intSignal, [this](int val) { m_view->setCurrentFrame(val, false); }); + connect(m_view, &GraphicsView::notifyFrameChanged, [cfspin](int val) { + QSignalBlocker blocker(cfspin); + cfspin->setValue(val); + }); + auto *positionBox = new QHBoxLayout; positionBox->addWidget(new QLabel(tr("Current Frame"))); - positionBox->addWidget(new QSpinBox); + positionBox->addWidget(cfspin); auto *positionWidget = new QWidget; positionWidget->setLayout(positionBox); bar->addWidget(positionWidget); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 7a711923cc..f225128a01 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -184,11 +184,14 @@ void GraphicsView::setZoomY(double zoom, const QPoint &pivot) viewport()->update(); } -void GraphicsView::setCurrentFrame(int frame) +void GraphicsView::setCurrentFrame(int frame, bool notify) { int clampedFrame = clamp(frame, m_model->minimumTime(), m_model->maximumTime()); m_playhead.moveToFrame(clampedFrame, this); viewport()->update(); + + if (notify) + notifyFrameChanged(frame); } void GraphicsView::scrollContent(double x, double y) @@ -251,6 +254,7 @@ void GraphicsView::mousePressEvent(QMouseEvent *event) QPointF pos = mapToScene(event->pos()); if (timeScaleRect().contains(pos)) { setCurrentFrame(std::round(mapXtoTime(pos.x()))); + m_playhead.setMoving(true); event->accept(); return; } diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h index af138429bf..d7c2f14da0 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h @@ -45,6 +45,9 @@ class GraphicsView : public QGraphicsView friend class Playhead; +signals: + void notifyFrameChanged(int frame); + public: GraphicsView(CurveEditorModel *model, QWidget *parent = nullptr); @@ -94,7 +97,7 @@ public: void setZoomY(double zoom, const QPoint &pivot = QPoint()); - void setCurrentFrame(int frame); + void setCurrentFrame(int frame, bool notify = true); void scrollContent(double x, double y); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp index e2e6d21274..7b25bbb9af 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp @@ -56,6 +56,11 @@ int Playhead::currentFrame() const return m_frame; } +void Playhead::setMoving(bool moving) +{ + m_moving = moving; +} + void Playhead::moveToFrame(int frame, GraphicsView *view) { m_frame = frame; diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h index 3a785624bd..9f6295c34a 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h @@ -45,6 +45,8 @@ public: void paint(QPainter *painter, GraphicsView *view) const; + void setMoving(bool moving); + void moveToFrame(int frame, GraphicsView *view); void resize(GraphicsView *view); diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png Binary files differindex 1a69afa777..bbdafae887 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png +++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png Binary files differindex d3aa02218b..7ab1e27ac3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png +++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index e82fbe9770..98735e5120 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -257,14 +257,15 @@ void static appendForcedNodes(const NodeListProperty &property, QList<ModelNode> QList<ModelNode> filteredList(const NodeListProperty &property, bool filter) { - if (!filter) - return property.toModelNodeList(); - QList<ModelNode> list; - list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { - return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); - })); + if (filter) { + list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { + return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); + })); + } else { + list = property.toModelNodeList(); + } appendForcedNodes(property, list); diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp new file mode 100644 index 0000000000..d6ef557388 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp @@ -0,0 +1,696 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "aligndistribute.h" + +#include <nodeabstractproperty.h> +#include <qmldesignerplugin.h> +#include <qmlmodelnodeproxy.h> + +#include <modelnode.h> +#include <variantproperty.h> + +#include <coreplugin/icore.h> + +#include <utils/algorithm.h> +#include <utils/checkablemessagebox.h> +#include <utils/qtcassert.h> + +#include <cmath> + +namespace QmlDesigner { + +AlignDistribute::AlignDistribute(QObject *parent) + : QObject(parent) +{} + +bool AlignDistribute::multiSelection() const +{ + if (!m_qmlObjectNode.isValid()) + return false; + + return m_qmlObjectNode.view()->selectedModelNodes().count() > 1; +} + +bool AlignDistribute::selectionHasAnchors() const +{ + if (!m_qmlObjectNode.isValid()) + return true; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + QmlItemNode itemNode(modelNode); + if (itemNode.instanceHasAnchors()) + return true; + } + return false; +} + +bool AlignDistribute::selectionExclusivlyItems() const +{ + if (!m_qmlObjectNode.isValid()) + return false; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + if (!QmlItemNode::isValidQmlItemNode(modelNode)) + return false; + } + return true; +} + +bool AlignDistribute::selectionContainsRootItem() const +{ + if (!m_qmlObjectNode.isValid()) + return true; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + QmlItemNode itemNode(modelNode); + if (itemNode.isRootNode()) + return true; + } + return false; +} + +void AlignDistribute::setModelNodeBackend(const QVariant &modelNodeBackend) +{ + auto modelNodeBackendObject = modelNodeBackend.value<QObject *>(); + const auto backendObjectCasted = qobject_cast<const QmlModelNodeProxy *>(modelNodeBackendObject); + + if (backendObjectCasted) + m_qmlObjectNode = backendObjectCasted->qmlObjectNode(); + + emit modelNodeBackendChanged(); +} + +// The purpose of this function is to suppress the following warning: +// Warning: Property declaration modelNodeBackendProperty has no READ accessor +// function or associated MEMBER variable. The property will be invalid. +QVariant AlignDistribute::getModelNodeBackend() const +{ + return {}; +} + +void AlignDistribute::registerDeclarativeType() +{ + qmlRegisterType<AlignDistribute>("HelperWidgets", 2, 0, "AlignDistribute"); +} + +// utility functions + +inline qreal width(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().width(); +} +inline qreal halfWidth(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().width() * 0.5; +} +inline qreal height(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().height(); +} +inline qreal halfHeight(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().height() * 0.5; +} +inline qreal left(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x(); +} +inline qreal centerHorizontal(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x() + halfWidth(qmlItemNode); +} +inline qreal right(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x() + width(qmlItemNode); +} +inline qreal top(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y(); +} +inline qreal centerVertical(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y() + halfHeight(qmlItemNode); +} +inline qreal bottom(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y() + height(qmlItemNode); +} + +bool compareByLeft(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return left(itemNode1) < left(itemNode2); + return false; +} + +bool compareByCenterH(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return centerHorizontal(itemNode1) < centerHorizontal(itemNode2); + return false; +} + +bool compareByRight(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return right(itemNode1) < right(itemNode2); + return false; +} + +bool compareByTop(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return top(itemNode1) < top(itemNode2); + return false; +} + +bool compareByCenterV(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return centerVertical(itemNode1) < centerVertical(itemNode2); + return false; +} + +bool compareByBottom(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return bottom(itemNode1) < bottom(itemNode2); + return false; +} + +unsigned getDepth(const ModelNode &node) +{ + if (node.isRootNode()) + return 0; + + return 1 + getDepth(node.parentProperty().parentModelNode()); +} + +bool compareByDepth(const ModelNode &node1, const ModelNode &node2) +{ + if (node1.isValid() && node2.isValid()) + return getDepth(node1) < getDepth(node2); + return false; +} + +static inline QRectF getBoundingRect(const QList<ModelNode> &modelNodeList) +{ + QRectF boundingRect; + for (const ModelNode &modelNode : modelNodeList) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + boundingRect = boundingRect.united(qmlItemNode.instanceSceneBoundingRect()); + } + } + return boundingRect; +} + +static inline QSizeF getSummedSize(const QList<ModelNode> &modelNodeList) +{ + QSizeF summedSize = QSizeF(0, 0); + for (const ModelNode &modelNode : modelNodeList) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + summedSize += qmlItemNode.instanceSize(); + } + } + return summedSize; +} + +static inline qreal getInstanceSceneX(const QmlItemNode &qmlItemNode) +{ + const qreal x = qmlItemNode.modelValue("x").toReal(); + if (qmlItemNode.hasInstanceParentItem()) + return x + getInstanceSceneX(qmlItemNode.instanceParentItem()); + return x; +} + +static inline qreal getInstanceSceneY(const QmlItemNode &qmlItemNode) +{ + const qreal y = qmlItemNode.modelValue("y").toReal(); + if (qmlItemNode.hasInstanceParentItem()) + return y + getInstanceSceneY(qmlItemNode.instanceParentItem()); + return y; +} + +// utility functions + +void AlignDistribute::alignObjects(Target target, AlignTo alignTo, const QString &keyObject) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + QmlItemNode keyObjectQmlItemNode; + + switch (alignTo) { + case AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + keyObjectQmlItemNode = keyObjectModelNode; + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = "align" + QVariant::fromValue(target).toByteArray(); + auto alignPosition = + [](Target target, const QRectF &boundingRect, const QmlItemNode &qmlItemNode) { + switch (target) { + case Target::Left: + return boundingRect.left(); + case Target::CenterH: + return boundingRect.center().x() - halfWidth(qmlItemNode); + case Target::Right: + return boundingRect.right() - width(qmlItemNode); + case Target::Top: + return boundingRect.top(); + case Target::CenterV: + return boundingRect.center().y() - halfHeight(qmlItemNode); + case Target::Bottom: + return boundingRect.bottom() - height(qmlItemNode); + } + return 0.0; + }; + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal myPos; + qreal parentPos; + QByteArray propertyName; + switch (getDimension(target)) { + case Dimension::X: { + myPos = qmlItemNode.instanceScenePosition().x(); + parentPos = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + myPos = qmlItemNode.instanceScenePosition().y(); + parentPos = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + if (alignTo == AlignTo::KeyObject && qmlItemNode == keyObjectQmlItemNode) + qmlItemNode.setVariantProperty(propertyName, myPos - parentPos); + else + qmlItemNode.setVariantProperty(propertyName, + qRound(alignPosition(target, + boundingRect, + qmlItemNode)) + - parentPos); + } + } + }); +} + +void AlignDistribute::distributeObjects(Target target, AlignTo alignTo, const QString &keyObject) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + + switch (alignTo) { + case AlignDistribute::AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignDistribute::AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignDistribute::AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + // Remove key object from selected nodes list and set bounding box according to key object. + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + selectedNodes.removeOne(keyObjectModelNode); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, getCompareFunction(target)); + + auto getMargins = [](Target target, const QList<ModelNode> &nodes) { + switch (target) { + case Target::Left: + return QMarginsF(0, 0, width(QmlItemNode(nodes.last())), 0); + case Target::CenterH: + return QMarginsF(halfWidth(QmlItemNode(nodes.first())), + 0, + halfWidth(QmlItemNode(nodes.last())), + 0); + case Target::Right: + return QMarginsF(width(QmlItemNode(nodes.first())), 0, 0, 0); + case Target::Top: + return QMarginsF(0, 0, 0, height(QmlItemNode(nodes.last()))); + case Target::CenterV: + return QMarginsF(0, + halfHeight(QmlItemNode(nodes.first())), + 0, + halfHeight(QmlItemNode(nodes.last()))); + case Target::Bottom: + return QMarginsF(0, height(QmlItemNode(nodes.first())), 0, 0); + } + return QMarginsF(); + }; + + boundingRect -= getMargins(target, selectedNodes); + + auto distributePosition = [](Target target, const QmlItemNode &node) { + switch (target) { + case Target::Left: + return 0.0; + case Target::CenterH: + return halfWidth(node); + case Target::Right: + return width(node); + case Target::Top: + return 0.0; + case Target::CenterV: + return halfHeight(node); + case Target::Bottom: + return height(node); + } + return 0.0; + }; + + QPointF position = boundingRect.topLeft(); + const qreal equidistant = (getDimension(target) == Dimension::X) + ? boundingRect.width() / (selectedNodes.size() - 1) + : boundingRect.height() / (selectedNodes.size() - 1); + qreal tmp; + if (std::modf(equidistant, &tmp) != 0.0) { + if (!executePixelPerfectDialog()) + return; + } + + for (const ModelNode &modelNode : selectedNodes) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal currentPosition; + if (getDimension(target) == Dimension::X) { + currentPosition = position.x(); + position.rx() += equidistant; + } else { + currentPosition = position.y(); + position.ry() += equidistant; + } + modelNode.setAuxiliaryData("tmp", + qRound(currentPosition + - distributePosition(target, qmlItemNode))); + } + } + + // Append key object to selected nodes list again. This needs to be done, so relative distribution + // will also work on nested item targets. Otherwise change of parents position will move the inner + // objects too. To compensate for that, the absolute parent position needs to be substracted. + if (alignTo == AlignTo::KeyObject) { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + const auto scenePosition = keyObjectQmlItemNode.instanceScenePosition(); + keyObjectModelNode.setAuxiliaryData("tmp", + (getDimension(target) == Dimension::X + ? scenePosition.x() + : scenePosition.y())); + selectedNodes.append(keyObjectModelNode); + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = "distribute" + QVariant::fromValue(target).toByteArray(); + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal parentPosition; + QByteArray propertyName; + switch (getDimension(target)) { + case Dimension::X: { + parentPosition = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + parentPosition = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + qmlItemNode.setVariantProperty(propertyName, + modelNode.auxiliaryData("tmp").toReal() + - parentPosition); + modelNode.removeAuxiliaryData("tmp"); + } + } + }); +} + +void AlignDistribute::distributeSpacing(Dimension dimension, + AlignTo alignTo, + const QString &keyObject, + const qreal &distance, + DistributeOrigin distributeOrigin) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + + switch (alignTo) { + case AlignDistribute::AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignDistribute::AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignDistribute::AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + // Remove key object from selected nodes list and set bounding box according to key object. + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + selectedNodes.removeOne(keyObjectModelNode); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, (dimension == Dimension::X) ? compareByCenterH : compareByCenterV); + + // Calculate the space between the items and set a proper start position for the different + // distribution directions/origins. + QPointF position = boundingRect.topLeft(); + const QSizeF summedSize = getSummedSize(selectedNodes); + qreal equidistant = distance; + + if (distributeOrigin == DistributeOrigin::None) { + const qreal lengthDifference = (dimension == Dimension::X) + ? (boundingRect.width() - summedSize.width()) + : (boundingRect.height() - summedSize.height()); + equidistant = lengthDifference / (selectedNodes.size() - 1); + qreal tmp; + if (std::modf(equidistant, &tmp) != 0.0) { + if (!executePixelPerfectDialog()) + return; + } + } else if (distributeOrigin == DistributeOrigin::Center + || distributeOrigin == DistributeOrigin::BottomRight) { + const qreal multiplier = (distributeOrigin == DistributeOrigin::Center) ? 0.5 : 1.0; + if (dimension == Dimension::X) { + const qreal totalLength = summedSize.width() + (distance * (selectedNodes.size() - 1)); + position.rx() -= (totalLength - boundingRect.width()) * multiplier; + } else { + const qreal totalLength = summedSize.height() + (distance * (selectedNodes.size() - 1)); + position.ry() -= (totalLength - boundingRect.height()) * multiplier; + } + } + + for (const ModelNode &modelNode : selectedNodes) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + qreal currentPosition; + if (dimension == Dimension::X) { + currentPosition = position.x(); + position.rx() += width(qmlItemNode) + equidistant; + } else { + currentPosition = position.y(); + position.ry() += height(qmlItemNode) + equidistant; + } + modelNode.setAuxiliaryData("tmp", qRound(currentPosition)); + } + } + + // Append key object to selected nodes list again. This needs to be done, so relative distribution + // will also work on nested item targets. Otherwise change of parents position will move the inner + // objects too. To compensate for that, the absolute parent position needs to be substracted. + if (alignTo == AlignTo::KeyObject) { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + const auto scenePosition = keyObjectQmlItemNode.instanceScenePosition(); + keyObjectModelNode.setAuxiliaryData("tmp", + (dimension == Dimension::X ? scenePosition.x() + : scenePosition.y())); + selectedNodes.append(keyObjectModelNode); + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = (dimension == Dimension::X) ? "distributeSpacingHorizontal" + : "distributeSpacingVertical"; + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal parentPos; + QByteArray propertyName; + switch (dimension) { + case Dimension::X: { + parentPos = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + parentPos = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + qmlItemNode.setVariantProperty(propertyName, + modelNode.auxiliaryData("tmp").toReal() - parentPos); + modelNode.removeAuxiliaryData("tmp"); + } + } + }); +} + +AlignDistribute::CompareFunction AlignDistribute::getCompareFunction(Target target) const +{ + static const std::map<Target, CompareFunction> cmpMap = {{Target::Left, compareByLeft}, + {Target::CenterH, compareByCenterH}, + {Target::Right, compareByRight}, + {Target::Top, compareByTop}, + {Target::CenterV, compareByCenterV}, + {Target::Bottom, compareByBottom}}; + return cmpMap.at(target); +} + +AlignDistribute::Dimension AlignDistribute::getDimension(Target target) const +{ + switch (target) { + case Target::Left: + case Target::CenterH: + case Target::Right: { + return Dimension::X; + } + case Target::Top: + case Target::CenterV: + case Target::Bottom: { + return Dimension::Y; + } + } + return Dimension::X; +} + +bool AlignDistribute::executePixelPerfectDialog() const +{ + QDialogButtonBox::StandardButton pressed = Utils::CheckableMessageBox::doNotAskAgainQuestion( + Core::ICore::dialogParent(), + tr("Cannot distribute perfectly"), + tr("These objects cannot be distributed to equal pixel values. " + "Do you want to distribute to the nearest possible values?"), + Core::ICore::settings(), + "WarnAboutPixelPerfectDistribution"); + return (pressed == QDialogButtonBox::Yes) ? true : false; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h new file mode 100644 index 0000000000..1b2714f750 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#ifndef ALIGNDISTRIBUTE_H +#define ALIGNDISTRIBUTE_H + +#include <QtQml> + +#include <selectioncontext.h> +#include <qmlitemnode.h> + +namespace QmlDesigner { + +class AlignDistribute : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool multiSelection READ multiSelection NOTIFY modelNodeBackendChanged) + Q_PROPERTY(bool selectionHasAnchors READ selectionHasAnchors NOTIFY modelNodeBackendChanged) + Q_PROPERTY( + bool selectionExclusivlyItems READ selectionExclusivlyItems NOTIFY modelNodeBackendChanged) + Q_PROPERTY(bool selectionContainsRootItem READ selectionContainsRootItem NOTIFY + modelNodeBackendChanged) + + Q_PROPERTY(QVariant modelNodeBackendProperty READ getModelNodeBackend WRITE setModelNodeBackend + NOTIFY modelNodeBackendChanged) + +public: + explicit AlignDistribute(QObject *parent = nullptr); + + enum AlignTo { Selection, Root, KeyObject }; + Q_ENUM(AlignTo) + + enum DistributeOrigin { None, TopLeft, Center, BottomRight }; + Q_ENUM(DistributeOrigin) + + enum Dimension { X, Y }; + Q_ENUM(Dimension) + + enum Target { Left, CenterH, Right, Top, CenterV, Bottom }; + Q_ENUM(Target) + + bool multiSelection() const; + bool selectionHasAnchors() const; + bool selectionExclusivlyItems() const; + bool selectionContainsRootItem() const; + + void setModelNodeBackend(const QVariant &modelNodeBackend); + QVariant getModelNodeBackend() const; + + static void registerDeclarativeType(); + + Q_INVOKABLE void alignObjects(Target target, AlignTo alignTo, const QString &keyObject); + Q_INVOKABLE void distributeObjects(Target target, AlignTo alignTo, const QString &keyObject); + Q_INVOKABLE void distributeSpacing(Dimension dimension, + AlignTo alignTo, + const QString &keyObject, + const qreal &distance, + DistributeOrigin distributeOrigin); + +signals: + void modelNodeBackendChanged(); + +private: + using CompareFunction = std::function<bool(const ModelNode &, const ModelNode &)>; + + CompareFunction getCompareFunction(Target target) const; + Dimension getDimension(Target target) const; + bool executePixelPerfectDialog() const; + + QmlObjectNode m_qmlObjectNode; +}; + +} // namespace QmlDesigner + +QML_DECLARE_TYPE(QmlDesigner::AlignDistribute) + +#endif //ALIGNDISTRIBUTE_H diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp index fab5366e6d..fab8cde66e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp @@ -34,7 +34,7 @@ #include <qmlmodelnodeproxy.h> ItemFilterModel::ItemFilterModel(QObject *parent) : - QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false) + QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false), m_selectionOnly(false) { } @@ -61,11 +61,24 @@ void ItemFilterModel::setTypeFilter(const QString &filter) } } +void ItemFilterModel::setSelectionOnly(bool value) +{ + if (m_selectionOnly != value) { + m_selectionOnly = value; + setupModel(); + } +} + QString ItemFilterModel::typeFilter() const { return m_typeFilter; } +bool ItemFilterModel::selectionOnly() const +{ + return m_selectionOnly; +} + void ItemFilterModel::registerDeclarativeType() { qmlRegisterType<ItemFilterModel>("HelperWidgets",2,0,"ItemFilterModel"); @@ -85,7 +98,9 @@ void ItemFilterModel::setupModel() m_lock = true; m_model.clear(); - for (const QmlDesigner::ModelNode &node : m_modelNode.view()->allModelNodes()) { + const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes() : m_modelNode.view()->allModelNodes(); + + for (const QmlDesigner::ModelNode &node : nodes) { if (node.hasId() && node.metaInfo().isValid() && node.metaInfo().isSubclassOf(m_typeFilter.toUtf8())) m_model.append(node.id()); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h index 032bd2baff..a26cacc685 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h @@ -40,13 +40,16 @@ class ItemFilterModel : public QObject Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QStringList itemModel READ itemModel NOTIFY itemModelChanged) + Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged) public: explicit ItemFilterModel(QObject *parent = nullptr); void setModelNodeBackend(const QVariant &modelNodeBackend); void setTypeFilter(const QString &typeFilter); + void setSelectionOnly(bool value); QString typeFilter() const; + bool selectionOnly() const; void setupModel(); QStringList itemModel() const; @@ -55,6 +58,7 @@ public: signals: void modelNodeBackendChanged(); void itemModelChanged(); + void selectionOnlyChanged(); private: QVariant modelNodeBackend() const; @@ -64,6 +68,7 @@ private: bool m_lock; QStringList m_model; QmlDesigner::ModelNode m_modelNode; + bool m_selectionOnly; }; QML_DECLARE_TYPE(ItemFilterModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri index 0777202db4..1fb9a3981f 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri @@ -19,7 +19,8 @@ SOURCES += propertyeditorview.cpp \ simplecolorpalette.cpp \ simplecolorpalettemodel.cpp \ simplecolorpalettesingleton.cpp \ - itemfiltermodel.cpp + itemfiltermodel.cpp \ + aligndistribute.cpp HEADERS += propertyeditorview.h \ qmlanchorbindingproxy.h \ @@ -40,6 +41,7 @@ HEADERS += propertyeditorview.h \ simplecolorpalette.h \ simplecolorpalettemodel.h \ simplecolorpalettesingleton.h \ - itemfiltermodel.h + itemfiltermodel.h \ + aligndistribute.h QT += qml quick diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 7ff25cad8e..3987435802 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -35,6 +35,7 @@ #include "bindingeditor/bindingeditor.h" #include "qmlanchorbindingproxy.h" #include "theme.h" +#include "aligndistribute.h" namespace QmlDesigner { @@ -59,6 +60,7 @@ void Quick2PropertyEditorView::registerQmlTypes() SimpleColorPaletteModel::registerDeclarativeType(); Internal::QmlAnchorBindingProxy::registerDeclarativeType(); BindingEditor::registerDeclarativeType(); + AlignDistribute::registerDeclarativeType(); } } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index 8ad8499d17..a233e19aad 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -272,7 +272,7 @@ void TimelineToolBar::createLeftControls() auto *curveEditorAction = createAction(TimelineConstants::C_CURVE_EDITOR, TimelineIcons::CURVE_EDITORDIALOG.icon(), - tr("Curve Editor"), + tr("Animation Curve Editor"), QKeySequence(Qt::Key_C)); connect(curveEditorAction, @@ -396,10 +396,10 @@ void TimelineToolBar::createCenterControls() auto *curvePicker = createAction(TimelineConstants::C_CURVE_PICKER, TimelineIcons::CURVE_EDITOR.icon(), - tr("Curve Picker"), + tr("Easing Curve Editor"), QKeySequence(Qt::Key_C)); - curvePicker->setObjectName("Curve Picker"); + curvePicker->setObjectName("Easing Curve Editor"); connect(curvePicker, &QAction::triggered, this, &TimelineToolBar::openEasingCurveEditor); addAction(curvePicker); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 2d19cf6b95..ba2f6b283c 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -46,7 +46,7 @@ class Target; namespace QmlDesigner { -class NodeInstanceServerInterface; +class NodeInstanceServerProxy; class CreateSceneCommand; class CreateInstancesCommand; class ClearSceneCommand; @@ -195,7 +195,7 @@ private: //variables QHash<ModelNode, NodeInstance> m_nodeInstanceHash; QHash<ModelNode, QImage> m_statePreviewImage; - QPointer<NodeInstanceServerInterface> m_nodeInstanceServer; + QPointer<NodeInstanceServerProxy> m_nodeInstanceServer; QImage m_baseStatePreviewImage; QElapsedTimer m_lastCrashTime; NodeInstanceServerInterface::RunModus m_runModus; diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h index 88afc72cb1..0c6693f505 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h @@ -98,6 +98,7 @@ public: bool modelIsInLayout() const; QRectF instanceBoundingRect() const; + QRectF instanceSceneBoundingRect() const; QRectF instancePaintedBoundingRect() const; QRectF instanceContentItemBoundingRect() const; QTransform instanceTransform() const; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index c51b40f728..899dc5caee 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1074,11 +1074,14 @@ ChangeValuesCommand NodeInstanceView::createChangeValueCommand(const QList<Varia { QVector<PropertyValueContainer> containerList; + const bool reflectionFlag = m_puppetTransaction.isValid(); + foreach (const VariantProperty &property, propertyList) { ModelNode node = property.parentModelNode(); if (node.isValid() && hasInstanceForModelNode(node)) { NodeInstance instance = instanceForModelNode(node); PropertyValueContainer container(instance.instanceId(), property.name(), property.value(), property.dynamicTypeName()); + container.setReflectionFlag(reflectionFlag); containerList.append(container); } @@ -1222,8 +1225,6 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) if (command.transactionOption == ValuesModifiedCommand::TransactionOption::Start) startPuppetTransaction(); - else if (command.transactionOption == ValuesModifiedCommand::TransactionOption::End) - endPuppetTransaction(); for (const PropertyValueContainer &container : command.valueChanges()) { if (hasInstanceForId(container.instanceId())) { @@ -1236,6 +1237,9 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) } } } + + if (command.transactionOption == ValuesModifiedCommand::TransactionOption::End) + endPuppetTransaction(); } void NodeInstanceView::pixmapChanged(const PixmapChangedCommand &command) diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 0b33aa655a..2fc530ff10 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -384,6 +384,11 @@ QRectF QmlItemNode::instanceBoundingRect() const return QRectF(QPointF(0, 0), nodeInstance().size()); } +QRectF QmlItemNode::instanceSceneBoundingRect() const +{ + return QRectF(instanceScenePosition(), nodeInstance().size()); +} + QRectF QmlItemNode::instancePaintedBoundingRect() const { return nodeInstance().boundingRect(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 69bc9ff0f9..a05c3b674a 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -355,11 +355,14 @@ bool compareJavaScriptExpression(const QString &expression1, const QString &expr } bool smartVeryFuzzyCompare(const QVariant &value1, const QVariant &value2) -{ //we ignore slight changes on doubles and only check three digits - if ((value1.type() == QMetaType::Double) - || (value2.type() == QMetaType::Double) - || (value1.type() == QMetaType::Float) - || (value2.type() == QMetaType::Float)) { +{ + //we ignore slight changes on doubles and only check three digits + const auto type1 = static_cast<QMetaType::Type>(value1.type()); + const auto type2 = static_cast<QMetaType::Type>(value2.type()); + if (type1 == QMetaType::Double + || type2 == QMetaType::Double + || type1 == QMetaType::Float + || type2 == QMetaType::Float) { bool ok1, ok2; qreal a = value1.toDouble(&ok1); qreal b = value2.toDouble(&ok2); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 5870927d52..f1afe3cf66 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -77,6 +77,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false); restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW, false); restoreValue(settings, DesignerSettingsKey::SIMPLE_COLOR_PALETTE_CONTENT, QStringList()); + restoreValue(settings, DesignerSettingsKey::ALWAYS_DESIGN_MODE, true); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 410abc267e..ec4dc1f7e5 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -66,6 +66,7 @@ const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The setting const char STANDALONE_MODE[] = "StandAloneMode"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; const char SIMPLE_COLOR_PALETTE_CONTENT[] = "SimpleColorPaletteContent"; +const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode"; } class DesignerSettings : public QHash<QByteArray, QVariant> diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 3ce4512fe1..2dbf40a7bb 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -96,7 +96,9 @@ QtQuickDesignerFactory::QtQuickDesignerFactory() addMimeType(QmlJSTools::Constants::QMLUI_MIMETYPE); setDocumentCreator([this]() { auto document = new QmlJSEditor::QmlJSEditorDocument(id()); - document->setIsDesignModePreferred(true); + document->setIsDesignModePreferred( + QmlDesigner::DesignerSettings::getValue( + QmlDesigner::DesignerSettingsKey::ALWAYS_DESIGN_MODE).toBool()); return document; }); } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 0d7b54c68e..f2fdd76598 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -568,6 +568,8 @@ Project { "navigator/navigatorview.h", "navigator/navigatorwidget.cpp", "navigator/navigatorwidget.h", + "propertyeditor/aligndistribute.cpp", + "propertyeditor/aligndistribute.h", "propertyeditor/designerpropertymap.cpp", "propertyeditor/designerpropertymap.h", "propertyeditor/fileresourcesmodel.cpp", diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index a7d6bc2bb0..6cfc1ebf45 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -161,6 +161,8 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.showWarnExceptionsCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW, m_ui.featureTimelineEditorCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::ALWAYS_DESIGN_MODE, + m_ui.designerAlwaysDesignModeCheckBox->isChecked()); return settings; } @@ -226,13 +228,15 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text()); + m_ui.designerAlwaysDesignModeCheckBox->setChecked(settings.value( + DesignerSettingsKey::ALWAYS_DESIGN_MODE).toBool()); m_ui.featureTimelineEditorCheckBox->setChecked(settings.value( DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()); if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { m_ui.emulationGroupBox->hide(); m_ui.debugGroupBox->hide(); - m_ui.featuresGroupBox->hide(); + m_ui.featureTimelineEditorCheckBox->hide(); } } diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index 7da62b300a..dabe3df734 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>685</width> - <height>555</height> + <width>960</width> + <height>840</height> </rect> </property> <property name="windowTitle"> @@ -415,14 +415,21 @@ <property name="title"> <string>Features</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="1"> <widget class="QCheckBox" name="featureTimelineEditorCheckBox"> <property name="text"> <string>Enable Timeline editor</string> </property> </widget> </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="designerAlwaysDesignModeCheckBox"> + <property name="text"> + <string>Always open ui.qml files in Design mode</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 4644823ed5..c602136ef2 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -193,7 +193,7 @@ void UpdateInfoPlugin::checkForUpdatesFinished() d->m_progress->setKeepOnFinish(FutureProgress::HideOnFinish); emit newUpdatesAvailable(true); Core::InfoBarEntry info(InstallUpdates, - tr("New updates are available. Do you want to start the update?")); + tr("New updates are available. Start the update?")); info.setCustomButtonInfo(tr("Start Update"), [this] { Core::ICore::infoBar()->removeInfo(InstallUpdates); startUpdater(); @@ -202,7 +202,7 @@ void UpdateInfoPlugin::checkForUpdatesFinished() info.setDetailsWidgetCreator([updates]() -> QWidget * { const QString updateText = updates.join("</li><li>"); auto label = new QLabel; - label->setText("<qt><p>" + tr("Available Updates:") + "<ul><li>" + updateText + label->setText("<qt><p>" + tr("Available updates:") + "<ul><li>" + updateText + "</li></ul></p></qt>"); label->setContentsMargins(0, 0, 0, 8); return label; diff --git a/src/tools/qtcdebugger/CMakeLists.txt b/src/tools/qtcdebugger/CMakeLists.txt index af367a60b3..ff550d8910 100644 --- a/src/tools/qtcdebugger/CMakeLists.txt +++ b/src/tools/qtcdebugger/CMakeLists.txt @@ -3,7 +3,7 @@ if (NOT WIN32) endif() add_qtc_executable(qtcdebugger - DEPENDS Qt5::Widgets registryaccess psapi + DEPENDS Qt5::Widgets registryaccess psapi app_version SOURCES main.cpp PROPERTIES WIN32_EXECUTABLE ON diff --git a/tests/system/objects.map b/tests/system/objects.map index 27e82838e7..407acfb5cd 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -158,7 +158,7 @@ :Qt Creator_Issues_Core::Internal::OutputPaneToggleButton {occurrence='1' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_QHelpContentWidget {type='Utils::NavigationTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_QmlJSEditor::Internal::QmlJSOutlineTreeView {type='QmlJSEditor::Internal::QmlJSOutlineTreeView' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} -:Qt Creator_QmlJSEditor::QmlJSTextEditorWidget {type='QmlJSEditor::Internal::QmlJSEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} +:Qt Creator_QmlJSEditor::QmlJSTextEditorWidget {type='QmlJSEditor::QmlJSEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_SearchResult_Core::Internal::OutputPaneToggleButton {occurrence='2' type='Core::Internal::OutputPaneToggleButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_TextEditor::TextEditorWidget {type='TextEditor::TextEditorWidget' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} :Qt Creator_Utils::BuildDirectoryLineEdit {name='LineEdit' type='Utils::FancyLineEdit' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py index b27000701e..db1b11c6c4 100644 --- a/tests/system/shared/build_utils.py +++ b/tests/system/shared/build_utils.py @@ -225,7 +225,6 @@ def runVerify(): test.fatal("Haven't found build configurations, quitting") invokeMenuItem("File", "Save All") invokeMenuItem("File", "Exit") - # select debug configuration for kit, config in availableConfigs: selectBuildConfig(kit, config) test.log("Using build config '%s'" % config) diff --git a/tests/system/suite_general/tst_create_proj_wizard/test.py b/tests/system/suite_general/tst_create_proj_wizard/test.py index 1d822c7ca5..69d1c4de4d 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -62,7 +62,8 @@ def main(): template = template.replace(".", "\\.") # skip non-configurable if template not in ["Qt Quick UI Prototype", "Auto Test Project", # FIXME - "Qt for Python - Empty", "Qt for Python - Window"]: + "Qt for Python - Empty", "Qt for Python - Window", + "Qt Quick 2 Extension Plugin"]: availableProjectTypes.append({category:template}) safeClickButton("Cancel") for current in availableProjectTypes: |