diff options
author | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2019-04-07 20:40:29 +0300 |
---|---|---|
committer | Orgad Shaneh <orgad.shaneh@audiocodes.com> | 2019-04-07 23:13:17 +0300 |
commit | 39ba01da711c07c43abe8aeacedd98990874ba82 (patch) | |
tree | 4a1c8853bd8db754fbf57eac5fff21b7e7342c8a | |
parent | a33386e014db5fdf65903654e9b1ae542ee36c0f (diff) | |
parent | 5273ef2a8aa3c8d268b107edc770b53e1aed7803 (diff) |
Merge remote-tracking branch 'origin/4.9'
Change-Id: I7d1912cd5c4d824fd40d3454c5f1bb796f2c21d8
92 files changed, 1143 insertions, 480 deletions
@@ -8,7 +8,7 @@ The standalone binary packages support the following platforms: * Windows 7 or later * (K)Ubuntu Linux 16.04 (64-bit) or later -* macOS 10.11 or later +* macOS 10.12 or later ## Contributing diff --git a/dist/changes-4.9.0.md b/dist/changes-4.9.0.md index 71db3a3479..7f9892cf01 100644 --- a/dist/changes-4.9.0.md +++ b/dist/changes-4.9.0.md @@ -221,6 +221,11 @@ Remote Linux (QTCREATORBUG-21225) * Fixed issue with killing remote process (QTCREATORBUG-19941) +Boot to Qt + +* Removed ADB-based Boot to Qt plugin that provided support for + Boot to Qt versions 5.8, and earlier. + Credits for these changes go to: Aaron Barany Alessandro Portale diff --git a/dist/copyright_template.txt b/dist/copyright_template.txt index df6e436ddb..885b74b116 100644 --- a/dist/copyright_template.txt +++ b/dist/copyright_template.txt @@ -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 Qt Creator. diff --git a/doc/config/qtcreator-project.qdocconf b/doc/config/qtcreator-project.qdocconf index 58fceb2740..b43166e8ad 100644 --- a/doc/config/qtcreator-project.qdocconf +++ b/doc/config/qtcreator-project.qdocconf @@ -20,7 +20,8 @@ imagedirs = ../images \ ../../src/plugins/qmldesigner/components/formeditor \ ../../src/plugins/qmldesigner/components/navigator \ ../../src/plugins/scxmleditor/common/images \ - ../../src/plugins/texteditor/images + ../../src/plugins/texteditor/images \ + ../../src/plugins/valgrind/images exampledirs = ../examples examples.fileextensions += *.qml *.svg diff --git a/doc/images/qtcreator-analyzer-settings.png b/doc/images/qtcreator-analyzer-settings.png Binary files differindex ce321e520a..2097cb2469 100644 --- a/doc/images/qtcreator-analyzer-settings.png +++ b/doc/images/qtcreator-analyzer-settings.png diff --git a/doc/images/qtcreator-code-style-clang-format.png b/doc/images/qtcreator-code-style-clang-format.png Binary files differindex f44c0ea47b..d803d551a1 100644 --- a/doc/images/qtcreator-code-style-clang-format.png +++ b/doc/images/qtcreator-code-style-clang-format.png diff --git a/doc/images/qtcreator-code-style-settings-edit-cpp.png b/doc/images/qtcreator-code-style-settings-edit-cpp.png Binary files differindex 3d15ac12e4..ff52a41b8f 100644 --- a/doc/images/qtcreator-code-style-settings-edit-cpp.png +++ b/doc/images/qtcreator-code-style-settings-edit-cpp.png diff --git a/doc/images/qtcreator-code-style-settings-edit-qtquick.png b/doc/images/qtcreator-code-style-settings-edit-qtquick.png Binary files differindex 0063f69e59..276ce1cbab 100644 --- a/doc/images/qtcreator-code-style-settings-edit-qtquick.png +++ b/doc/images/qtcreator-code-style-settings-edit-qtquick.png diff --git a/doc/images/qtcreator-options-build-run-debuggers.png b/doc/images/qtcreator-options-build-run-debuggers.png Binary files differindex b249ddbbee..f6a56fbe4f 100644 --- a/doc/images/qtcreator-options-build-run-debuggers.png +++ b/doc/images/qtcreator-options-build-run-debuggers.png diff --git a/doc/images/qtcreator-projects-code-style.png b/doc/images/qtcreator-projects-code-style.png Binary files differnew file mode 100644 index 0000000000..90fb3b4fcd --- /dev/null +++ b/doc/images/qtcreator-projects-code-style.png diff --git a/doc/images/qtcreator-python-run-settings-custom-executable.png b/doc/images/qtcreator-python-run-settings-custom-executable.png Binary files differnew file mode 100644 index 0000000000..3db0379f57 --- /dev/null +++ b/doc/images/qtcreator-python-run-settings-custom-executable.png diff --git a/doc/images/qtcreator-python-run-settings.png b/doc/images/qtcreator-python-run-settings.png Binary files differnew file mode 100644 index 0000000000..f5abe19861 --- /dev/null +++ b/doc/images/qtcreator-python-run-settings.png diff --git a/doc/images/qtcreator-valgrind-callgrind-options.png b/doc/images/qtcreator-valgrind-callgrind-options.png Binary files differindex eb7956c57b..82684f645b 100644 --- a/doc/images/qtcreator-valgrind-callgrind-options.png +++ b/doc/images/qtcreator-valgrind-callgrind-options.png diff --git a/doc/images/qtcreator-valgrind-callgrind.png b/doc/images/qtcreator-valgrind-callgrind.png Binary files differindex 34396a5663..e57038a151 100755 --- a/doc/images/qtcreator-valgrind-callgrind.png +++ b/doc/images/qtcreator-valgrind-callgrind.png diff --git a/doc/src/analyze/creator-valgrind.qdoc b/doc/src/analyze/creator-valgrind.qdoc index fb22f8632c..92c42fd48c 100644 --- a/doc/src/analyze/creator-valgrind.qdoc +++ b/doc/src/analyze/creator-valgrind.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. @@ -149,13 +149,17 @@ You can use the Callgrind tool included in the \l{http://valgrind.org/info/tools.html}{Valgrind tool suite} to detect - problems that are related to executing functions. + problems that are related to executing functions. In addition, you + can load the data files generated by Callgrind into the + \l{https://kcachegrind.github.io/html/Home.html}{KCachegrind} + profile data visualization tool for browsing the performance results. - After you download and install Valgrind tools, you can use Callgrind from - \QC. + After you download and install Valgrind tools and KCachegrind, you can use + Callgrind and KCachegrind from \QC. - \note You can install and run Callgrind locally on Linux. You can run - it on a remote Linux machine or device from any development machine. + \note You can install and run Callgrind and KCachegrind locally on Linux. + You can run Callgrind on a remote Linux machine or device from any + development machine. To analyze applications: @@ -207,6 +211,10 @@ \image qtcreator-valgrind-callgrind.png "Profile view" + To view the data in KCachegrind, select the \inlineimage kcachegrind.png + (\uicontrol {Open Results in KCachegrind}) button on the toolbar. \QC + launches KCachegrind and loads the data into it for visualization. + \section1 Selecting Profiling Options You can specify analyzer settings either globally for all projects or @@ -218,6 +226,9 @@ \image qtcreator-valgrind-callgrind-options.png "Valgrind options" + In the \uicontrol {KCachegrind executable} field, enter the path to the + KCachegrind executable to launch. + In the \uicontrol {Result view: Minimum event cost} field, limit the amount of results the profiler gives you to increase profiler performance. diff --git a/doc/src/editors/creator-clangformat.qdocinc b/doc/src/editors/creator-clangformat.qdocinc index 8a4b757399..705f4067bb 100644 --- a/doc/src/editors/creator-clangformat.qdocinc +++ b/doc/src/editors/creator-clangformat.qdocinc @@ -28,7 +28,7 @@ \section2 Automatic Formatting and Indentation - The experimental Clang Format plugin uses the + The Clang Format plugin uses the \l{https://clang.llvm.org/docs/LibFormat.html}{LibFormat} library for automatic formatting and indentation. diff --git a/doc/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/src/editors/creator-only/creator-clang-codemodel.qdoc index f8e2b890c1..fe582d342d 100644 --- a/doc/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -112,7 +112,7 @@ \list \li Clang code model (globally or at project level) - \li Clang tools (globally or at project level) + \li \l{Using Clang Tools}{Clang tools} (globally or at project level) \endlist \section1 Configuring Clang Code Model diff --git a/doc/src/editors/creator-only/creator-code-pasting.qdoc b/doc/src/editors/creator-only/creator-code-pasting.qdoc index 587ce158e5..803a15e64a 100644 --- a/doc/src/editors/creator-only/creator-code-pasting.qdoc +++ b/doc/src/editors/creator-only/creator-code-pasting.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. @@ -97,6 +97,6 @@ retrieve the code snippet by selecting \uicontrol Tools > \uicontrol {Code Pasting} > \uicontrol {Fetch Snippet}. If they have the project currently opened in \QC, they can apply and test the change by - choosing \uicontrol Tools > \uicontrol Git > \uicontrol {Patch} > - \uicontrol {Apply from Editor}. + choosing \uicontrol Tools > \uicontrol Git > \uicontrol {Local Repository} + > \uicontrol Patch > \uicontrol {Apply from Editor}. */ diff --git a/doc/src/howto/creator-sidebar-views.qdocinc b/doc/src/howto/creator-sidebar-views.qdocinc index 1a6af5a398..ff287b4525 100644 --- a/doc/src/howto/creator-sidebar-views.qdocinc +++ b/doc/src/howto/creator-sidebar-views.qdocinc @@ -145,6 +145,9 @@ \li To hide source files which are automatically generated by the build system, select \uicontrol {Filter Tree > Hide Generated Files}. + \li To hide directories that do not contain any files, select + \uicontrol {Filter Tree} > \uicontrol {Hide Empty Directories}. + \li To stop synchronizing the position in the project tree with the file currently opened in the editor, deselect \inlineimage linkicon.png (\uicontrol {Synchronize with Editor}). You can specify a keyboard @@ -190,7 +193,8 @@ For managing files and directories, the same functions are available as in the \uicontrol {File System} view. In addition, you can remove and rename - files. + files, as well as compare the selected file with the currently open file + in the diff editor. For more information, see \l{Comparing Files}. //! [projects view] diff --git a/doc/src/overview/creator-only/creator-configuring.qdoc b/doc/src/overview/creator-only/creator-configuring.qdoc index 0a3096737b..d6a91039ed 100644 --- a/doc/src/overview/creator-only/creator-configuring.qdoc +++ b/doc/src/overview/creator-only/creator-configuring.qdoc @@ -124,10 +124,11 @@ For more information, see \l{Defining Color Schemes}. - Generic highlighting is based on highlight definition files that are - provided by the - \l{http://kate-editor.org/2005/03/24/writing-a-syntax-highlighting-file/} - {Kate Editor}. You can download highlight definition files for use with \QC. + Generic highlighting is provided by + \l{https://api.kde.org/frameworks/syntax-highlighting/html/index.html} + {KSyntaxHighlighting}, which is the syntax highlighting engine for Kate + syntax definitions. \QC comes with most of the commonly used syntax files, + and you can download additional files. To download and use highlight definition files, select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > \uicontrol {Generic Highlighter}. diff --git a/doc/src/overview/creator-only/creator-overview.qdoc b/doc/src/overview/creator-only/creator-overview.qdoc index c732d2d3d8..1f6f31936d 100644 --- a/doc/src/overview/creator-only/creator-overview.qdoc +++ b/doc/src/overview/creator-only/creator-overview.qdoc @@ -79,6 +79,10 @@ languages as code, not just as plain text. This enables it to provide you with useful features, such as semantic highlighting, checking code syntax, code completion, and refactoring actions. + In addition, the experimental language server plugin provides + some of these services for other programming languages, such as + Python, for which a \e {language server} is available that + provides information about the code to IDEs. For more information, see \l{Coding}. \row \li \inlineimage creator_buildingrunning.png diff --git a/doc/src/overview/creator-only/creator-supported-platforms.qdoc b/doc/src/overview/creator-only/creator-supported-platforms.qdoc index b91b67803f..a64947d802 100644 --- a/doc/src/overview/creator-only/creator-supported-platforms.qdoc +++ b/doc/src/overview/creator-only/creator-supported-platforms.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. @@ -101,7 +101,7 @@ \endlist - \li \macos 10.11 or later with the following: + \li \macos 10.12 or later with the following: \list @@ -117,9 +117,9 @@ Either Windows 7 or later or Ubuntu Linux 64-bit 12.04 LTS or later is required to install and use Qt for Device Creation. For more information about the requirements for the development host, see the - \l{http://doc.qt.io/QtForDeviceCreation/qtee-installation-guide.html} - {Installation Guide} in the - \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} + \l{https://doc.qt.io/QtForDeviceCreation/b2qt-installation-guides.html} + {Installation Guides} in the + \l{https://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} documentation. \section1 Compiling from Source diff --git a/doc/src/overview/creator-only/creator-target-platforms.qdocinc b/doc/src/overview/creator-only/creator-target-platforms.qdocinc index 3e0153e09d..a936ae7a9a 100644 --- a/doc/src/overview/creator-only/creator-target-platforms.qdocinc +++ b/doc/src/overview/creator-only/creator-target-platforms.qdocinc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 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. @@ -56,9 +56,13 @@ hardware. For more information about the supported device groups and reference devices, - see \l{http://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html} - {Supported Platforms} in the \l{http://doc.qt.io/QtForDeviceCreation/index.html} - {Qt for Device Creation} documentation. + see \l{https://doc.qt.io/QtForDeviceCreation/qtee-supported-platforms.html} + {Reference Target Devices and Development Hosts} in the + \l{https://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} + documentation. + + \note Since \QC 4.9, only Boot to Qt version 5.9 and later are supported. + To develop for earlier Boot to Qt versions, use \QC 4.8. \section2 Mobile Devices diff --git a/doc/src/projects/creator-only/creator-projects-compilers.qdoc b/doc/src/projects/creator-only/creator-projects-compilers.qdoc index 0e3f89c326..5387e4c680 100644 --- a/doc/src/projects/creator-only/creator-projects-compilers.qdoc +++ b/doc/src/projects/creator-only/creator-projects-compilers.qdoc @@ -64,6 +64,10 @@ \li Clang is a C, C++, Objective C, and Objective C++ front-end for the LLVM compiler for Windows, Linux, and \macos. + \li \l{https://clang.llvm.org/docs/UsersManual.html#clang-cl}{clang-cl} + is an alternative command-line interface to Clang that is compatible + with the Visual C++ compiler, \c cl.exe. + \li Nim is the Nim Compiler for Windows, Linux, and \macos. \li QCC is the interface for compiling C++ applications for QNX. @@ -76,6 +80,12 @@ versions. You can also create a custom ABI definition. For QCC, also specify the path to the QNX Software Development Platform (SDP). + To enable Microsoft Visual C++ Compilers (MSVC) and clang-cl to find system + headers, libraries, and the linker, \QC executes them inside a command + prompt where the environment has been set up using \c {vcvarsall.bat}. For + these compilers, you also specify the path to the script that sets up the + command prompt. + You specify the compiler to use for each kit in \uicontrol Tools > \uicontrol Options > \uicontrol Kits. diff --git a/doc/src/projects/creator-only/creator-projects-debuggers.qdoc b/doc/src/projects/creator-only/creator-projects-debuggers.qdoc index 6e9b3013f9..ebd1f6c366 100644 --- a/doc/src/projects/creator-only/creator-projects-debuggers.qdoc +++ b/doc/src/projects/creator-only/creator-projects-debuggers.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. @@ -86,4 +86,8 @@ the shell or the device. Usually, you can leave this field empty. \endlist + + To remove the selected manually added debugger, select \uicontrol Remove. + The debugger is removed from the list when you select \uicontrol Apply. + Until then, you can cancel the deletion by clicking \uicontrol Restore. */ diff --git a/doc/src/projects/creator-only/creator-projects-opening.qdoc b/doc/src/projects/creator-only/creator-projects-opening.qdoc index 7fe17582ef..6298c896b5 100644 --- a/doc/src/projects/creator-only/creator-projects-opening.qdoc +++ b/doc/src/projects/creator-only/creator-projects-opening.qdoc @@ -1,7 +1,7 @@ /**************************************************************************** ** -** 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. @@ -58,6 +58,10 @@ select the \uicontrol Options link, or select \uicontrol Tools > \uicontrol Options > \uicontrol Kits. + Qt for Python projects rely on the \l{Using Language Servers} + {experimental language server client} for code completion, + highlighting, and other useful features. + If \QC cannot find an existing build for a particular \l{glossary-buildandrun-kit}{kit}, it starts out from a clean slate, and creates new debug and release build configurations @@ -79,8 +83,8 @@ \li Select \uicontrol File > \uicontrol {Open File or Project} (\key Ctrl+O or \key Cmd+O on \macos) and select the project file for the project to open: \e {.pro} (qmake), \e {CMakeLists.txt} - (CMake), \e {.qbs} (Qbs), or \e {Makefile.am} (Autotools, - experimental). + (CMake), \e {.qbs} (Qbs), \e {pyproject} (Python), or + \e {Makefile.am} (Autotools, experimental). \li In the \uicontrol {Configure Project} tab, select kits for building and running your project, and click \uicontrol {Configure Project}. diff --git a/doc/src/projects/creator-only/creator-projects-settings-code-style.qdoc b/doc/src/projects/creator-only/creator-projects-settings-code-style.qdoc index 4e3841b4d2..525e7965f4 100644 --- a/doc/src/projects/creator-only/creator-projects-settings-code-style.qdoc +++ b/doc/src/projects/creator-only/creator-projects-settings-code-style.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. @@ -48,6 +48,16 @@ switch between them. In addition, you can import and export code style settings. + \image qtcreator-projects-code-style.png "Code Style settings in Projects mode" + + Alternatively, you can enable the Clang Format plugin to enforce + the code style specified in a \c {.clang-format} file. It uses the + \l{https://clang.llvm.org/docs/LibFormat.html}{LibFormat} library for + automatic code formatting and indentation. For more information, see + \l {Automatic Formatting and Indentation}. + + \image qtcreator-code-style-clang-format.png "Clang Format Code Style settings in Projects mode" + To specify global code style settings sets for C++ files, select \uicontrol {Tools > Options > C++}. diff --git a/doc/src/projects/creator-only/creator-projects-settings-run.qdoc b/doc/src/projects/creator-only/creator-projects-settings-run.qdoc index 1010186a3f..a67b2052fd 100644 --- a/doc/src/projects/creator-only/creator-projects-settings-run.qdoc +++ b/doc/src/projects/creator-only/creator-projects-settings-run.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. @@ -117,4 +117,6 @@ \image qmldesigner-run-custom-exe.png "Run settings for custom executables" \include qtquick/creator-projects-settings-run-qtquick.qdocinc run settings qt quick ui + \include python/creator-python-run.qdocinc run settings python + */ diff --git a/doc/src/projects/creator-only/creator-projects-targets.qdoc b/doc/src/projects/creator-only/creator-projects-targets.qdoc index b3a4229f14..1d6101b02f 100644 --- a/doc/src/projects/creator-only/creator-projects-targets.qdoc +++ b/doc/src/projects/creator-only/creator-projects-targets.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. @@ -53,6 +53,10 @@ \li Bare Metal Device + \li Boot2Qt Device (commercial only) + + \li \l {Emulator}{Boot2Qt Emulator Device} (commercial only) + \li Generic Linux Device \li iOS Device @@ -61,6 +65,12 @@ \li QNX Device + \li Windows Phone + + \li Windows Phone Emulator + + \li Windows Runtime (local) + \endlist To add kits: @@ -95,6 +105,9 @@ \li In the \uicontrol Device field, select a device. + \li In the \uicontrol {Emulator skin} field, select the skin to use for + the \l {Emulator}{Boot2Qt Emulator Device}. + \li In the \uicontrol Sysroot field, specify the directory where the device image is located. If you are not cross-compiling, leave this field empty. diff --git a/doc/src/projects/creator-projects-running.qdoc b/doc/src/projects/creator-projects-running.qdoc index caca6bb636..85cb0b287c 100644 --- a/doc/src/projects/creator-projects-running.qdoc +++ b/doc/src/projects/creator-projects-running.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. @@ -85,5 +85,6 @@ \if defined(qtcreator) \include qnx/creator-projects-running-qnx.qdocinc running on qnx + \include python/creator-python-run.qdocinc running python \endif */ diff --git a/doc/src/python/creator-python-run.qdocinc b/doc/src/python/creator-python-run.qdocinc new file mode 100644 index 0000000000..cc9b19698c --- /dev/null +++ b/doc/src/python/creator-python-run.qdocinc @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Creator documentation. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** +****************************************************************************/ + +/*! +//! [running python] + \section1 Running Python Projects + + You can execute Qt for Python applications directly from \QC. If you + used the \l{Creating Qt for Python Applications}{new project wizard} + to create the application project, the \c main.py file is automatically + executed when you select the \uicontrol Run button. + + You can specify another file to execute in the + \l{Specifying Run Settings for Python Projects}{run settings} + of the project. + +//! [running python] + + +//! [run settings python] + + \section1 Specifying Run Settings for Python Projects + + You can specify settings for running Qt for Python applications: + + \image qtcreator-python-run-settings.png + + \list + \li In the \uicontrol Interpreter field, specify the path to the + Python executable. + \li In the \uicontrol Script field, you can see the path to the + main file of the project that will be run. + \li In the \uicontrol {Command line arguments} field, specify + command line arguments to be passed to the executable. + \endlist + + If you want to run some other Python file than \c main.py, create a custom + executable run configuration: + + \image qtcreator-python-run-settings-custom-executable.png + + \list 1 + \li Select \uicontrol Add > \uicontrol {Custom Executable}. + \li In the \uicontrol Executable field, specify the path to the + Python executable. + \li In the \uicontrol {Command line arguments} field, select + the Python file to run. + \endlist + +//! [run settings python] +*/ diff --git a/doc/src/qtquick/qtquick-profiler.qdoc b/doc/src/qtquick/qtquick-profiler.qdoc index cd934eb55d..f94f4f0b25 100644 --- a/doc/src/qtquick/qtquick-profiler.qdoc +++ b/doc/src/qtquick/qtquick-profiler.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. @@ -212,6 +212,11 @@ To zoom into an event range, double-click it. + To narrow down the current range in the \uicontrol Timeline, + \uicontrol Statistics, and \uicontrol {Flame Graph} views, right-click + the range and select \uicontrol {Analyze Current Range}. To return to + the full range, select \uicontrol {Analyze Full Range} in the context menu. + To remove an event range, close the \uicontrol Selection dialog. \section2 Understanding the Data @@ -556,10 +561,9 @@ Click on an event to move to it in the source code in the code editor. - When you select an event in the \uicontrol Timeline view, information about it is - displayed in the \uicontrol Statistics view. To view an event range in the - \uicontrol Statistics view, select \uicontrol {Analyze Current Range} - in the context menu in the \uicontrol Timeline view. + When you select an event in the \uicontrol Timeline view, information about + it is displayed in the \uicontrol Statistics and \uicontrol {Flame Graph} + views. To copy the contents of one view or row to the clipboard, select \uicontrol {Copy Table} or \uicontrol {Copy Row} in the context menu. diff --git a/doc/src/vcs/creator-only/creator-vcs-cvs.qdoc b/doc/src/vcs/creator-only/creator-vcs-cvs.qdoc index 738db2b7bb..030fd73240 100644 --- a/doc/src/vcs/creator-only/creator-vcs-cvs.qdoc +++ b/doc/src/vcs/creator-only/creator-vcs-cvs.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. @@ -41,9 +41,16 @@ In addition to the standard version control system functions described in \l {Using Common Functions}, you can select \uicontrol Tools > - \uicontrol CVS > \uicontrol Edit to open a file for editing. + \uicontrol CVS > \uicontrol Edit to set a file as writable, notify + watchers that the file is being edited, and watch for actions performed + on the file by other users. - To discard the changes that you made in a file, select \uicontrol Unedit. + To discard the changes that you made in a file, notify watchers that + the file is no longer being edited, and set the file as read-only, + select \uicontrol Unedit. + + To unedit files in the local directory, as well as recursively in all + subdirectories, select \uicontrol {Unedit Repository}. To specify the CVS root directory, select \uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} > \uicontrol CVS, and then diff --git a/doc/src/vcs/creator-only/creator-vcs.qdoc b/doc/src/vcs/creator-only/creator-vcs.qdoc index c7f3c0dc94..b0e7502ad2 100644 --- a/doc/src/vcs/creator-only/creator-vcs.qdoc +++ b/doc/src/vcs/creator-only/creator-vcs.qdoc @@ -72,6 +72,11 @@ \li \l{Using Perforce}{Perforce} \li \l{http://www.perforce.com} \li Server version 2006.1 and later + + Disabled by default. To enable the plugin, select + \uicontrol Help > \uicontrol {About Plugins} > + \uicontrol {Version Control} > \uicontrol Perforce, + and then restart \QC. \row \li \l{Using Subversion}{Subversion} \li \l{http://subversion.apache.org/} diff --git a/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json b/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json index 844e1075ef..9f797b4a26 100644 --- a/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json +++ b/share/qtcreator/qml-type-descriptions/qt5QtQuick2-bundle.json @@ -50,7 +50,7 @@ "QtCharts 2.3", "QtDataVisualization 1.0", "QtDataVisualization 1.3", - "QtGamePad 1.12", + "QtGamepad 1.12", "QtGraphicalEffects 1.0", "QtMultimedia 5.0", "QtMultimedia 5.2", diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression.png b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression.png Binary files differindex 8e6d13d7d9..a34365ae6e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression.png +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression.png diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression@2x.png b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression@2x.png Binary files differindex ec5e85b953..b4bdd9f94e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression@2x.png +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/images/expression@2x.png diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json index b19188a3c8..098456a431 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/scroll/wizard.json @@ -80,7 +80,6 @@ "name": "QtVersion", "trDisplayName": "Minimal required Qt version:", "type": "ComboBox", - "visible": false, "data": { "index": 1, diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 874d74c900..08890a7c2f 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -41,6 +41,7 @@ DoubleTabWidget2ndTabInactiveTextColor=ff000000 EditorPlaceholderColor=ffe0dcd8 FancyToolBarSeparatorColor=60ffffff FancyTabBarBackgroundColor=ffff0000 +FancyTabBarSelectedBackgroundColor=ffff0000 FancyTabWidgetDisabledSelectedTextColor=textDisabled FancyTabWidgetDisabledUnselectedTextColor=textDisabled FancyTabWidgetEnabledSelectedTextColor=ff3c3c3c diff --git a/share/qtcreator/translations/qtcreator_de.ts b/share/qtcreator/translations/qtcreator_de.ts index 0000669c6f..1553ca0d32 100644 --- a/share/qtcreator/translations/qtcreator_de.ts +++ b/share/qtcreator/translations/qtcreator_de.ts @@ -18536,11 +18536,11 @@ Gibt an, wie sich die Rücktaste bezüglich Einrückung verhält. </message> <message> <source>Show help tooltips using keyboard shortcut (Alt)</source> - <translation>Zeige Tooltips mit Hilfe unter Verwendung des Tastaturkürzels (Alt-Taste)</translation> + <translation>Hilfe-Tooltips mit der Tastatur aufrufen (Alt-Taste)</translation> </message> <message> <source>Show help tooltips using the mouse:</source> - <translation>Zeige Tooltips mit Hilfe unter Verwendung der Maus:</translation> + <translation>Hilfe-Tooltips mit der Maus aufrufen:</translation> </message> <message> <source>Cleans whitespace in entire document instead of only for changed parts.</source> diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index ae26ba1d90..e95ff2f339 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -921,12 +921,11 @@ protected: bool visit(PatternElement *ast) override { - if (!ast->isVariableDeclaration()) - return false; out(ast->identifierToken); if (ast->initializer) { - out(" = "); + if (ast->isVariableDeclaration()) + out(" = "); accept(ast->initializer); } return false; diff --git a/src/libs/qmljs/qmljstypedescriptionreader.cpp b/src/libs/qmljs/qmljstypedescriptionreader.cpp index 1cf16eaa07..80ec498d8f 100644 --- a/src/libs/qmljs/qmljstypedescriptionreader.cpp +++ b/src/libs/qmljs/qmljstypedescriptionreader.cpp @@ -232,7 +232,7 @@ void TypeDescriptionReader::readComponent(UiObjectDefinition *ast) } else if (name == QLatin1String("exports")) { readExports(script, fmo); } else if (name == QLatin1String("exportMetaObjectRevisions")) { - //readMetaObjectRevisions(script, fmo); + readMetaObjectRevisions(script, fmo); } else if (name == QLatin1String("attachedType")) { fmo->setAttachedTypeName(readStringBinding(script)); } else if (name == QLatin1String("isSingleton")) { diff --git a/src/libs/utils/basetreeview.cpp b/src/libs/utils/basetreeview.cpp index 254f2e9131..352b17bb4b 100644 --- a/src/libs/utils/basetreeview.cpp +++ b/src/libs/utils/basetreeview.cpp @@ -28,6 +28,7 @@ #include "progressindicator.h" #include "treemodel.h" +#include <utils/algorithm.h> #include <utils/qtcassert.h> #include <QDebug> @@ -39,6 +40,7 @@ #include <QMenu> #include <QMouseEvent> #include <QSettings> +#include <QSortFilterProxyModel> #include <QTimer> namespace Utils { @@ -596,11 +598,23 @@ ItemViewEvent::ItemViewEvent(QEvent *ev, QAbstractItemView *view) m_selectedRows.append(current); } } + + auto fixIndex = [view](QModelIndex idx) { + QAbstractItemModel *model = view->model(); + while (auto proxy = qobject_cast<QSortFilterProxyModel *>(model)) { + idx = proxy->mapToSource(idx); + model = proxy->sourceModel(); + } + return idx; + }; + + m_sourceModelIndex = fixIndex(m_index); + m_selectedRows = Utils::transform(m_selectedRows, fixIndex); } QModelIndexList ItemViewEvent::currentOrSelectedRows() const { - return m_selectedRows.isEmpty() ? QModelIndexList() << m_index : m_selectedRows; + return m_selectedRows.isEmpty() ? QModelIndexList() << m_sourceModelIndex : m_selectedRows; } } // namespace Utils diff --git a/src/libs/utils/basetreeview.h b/src/libs/utils/basetreeview.h index fdf6f61937..de68685b6a 100644 --- a/src/libs/utils/basetreeview.h +++ b/src/libs/utils/basetreeview.h @@ -135,6 +135,7 @@ public: QPoint pos() const { return m_pos; } QPoint globalPos() const { return m_view->mapToGlobal(m_pos); } QModelIndex index() const { return m_index; } + QModelIndex sourceModelIndex() const { return m_sourceModelIndex; } QModelIndexList selectedRows() const { return m_selectedRows; } QModelIndexList currentOrSelectedRows() const; @@ -143,6 +144,7 @@ private: QWidget *m_view = nullptr; QPoint m_pos; QModelIndex m_index; + QModelIndex m_sourceModelIndex; QModelIndexList m_selectedRows; }; diff --git a/src/libs/utils/fancymainwindow.cpp b/src/libs/utils/fancymainwindow.cpp index de73c6edaa..9a5c84894c 100644 --- a/src/libs/utils/fancymainwindow.cpp +++ b/src/libs/utils/fancymainwindow.cpp @@ -523,6 +523,21 @@ bool FancyMainWindow::autoHideTitleBars() const return d->m_autoHideTitleBars.isChecked(); } +void FancyMainWindow::setAutoHideTitleBars(bool on) +{ + d->m_autoHideTitleBars.setChecked(on); +} + +bool FancyMainWindow::isCentralWidgetShown() const +{ + return d->m_showCentralWidget.isChecked(); +} + +void FancyMainWindow::showCentralWidget(bool on) +{ + d->m_showCentralWidget.setChecked(on); +} + void FancyMainWindow::addDockActionsToMenu(QMenu *menu) { QList<QAction *> actions; diff --git a/src/libs/utils/fancymainwindow.h b/src/libs/utils/fancymainwindow.h index 623ef42408..4424b1c8bb 100644 --- a/src/libs/utils/fancymainwindow.h +++ b/src/libs/utils/fancymainwindow.h @@ -66,6 +66,10 @@ public: void addDockActionsToMenu(QMenu *menu); bool autoHideTitleBars() const; + void setAutoHideTitleBars(bool on); + + bool isCentralWidgetShown() const; + void showCentralWidget(bool on); signals: // Emitted by resetLayoutAction(). Connect to a slot diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index aaa642e215..e3cd476924 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -86,7 +86,7 @@ void GTestOutputReader::processOutputLine(const QByteArray &outputLineWithNewLin m_description = line; if (m_iteration > 1) m_description.append(' ' + tr("(iteration %1)").arg(m_iteration)); - TestResultPtr testResult = TestResultPtr(new GTestResult(m_projectFile)); + TestResultPtr testResult = TestResultPtr(new GTestResult(id(), m_projectFile, QString())); testResult->setResult(Result::MessageInternal); testResult->setDescription(m_description); reportResult(testResult); diff --git a/src/plugins/autotest/gtest/gtestresult.cpp b/src/plugins/autotest/gtest/gtestresult.cpp index 06ef721951..51eb81a455 100644 --- a/src/plugins/autotest/gtest/gtestresult.cpp +++ b/src/plugins/autotest/gtest/gtestresult.cpp @@ -72,7 +72,7 @@ bool GTestResult::isDirectParentOf(const TestResult *other, bool *needsIntermedi if (m_testSetName == gtOther->m_testSetName) { const Result::Type otherResult = other->result(); if (otherResult == Result::MessageInternal || otherResult == Result::MessageLocation) - return result() != Result::MessageLocation; + return result() != Result::MessageInternal && result() != Result::MessageLocation; } if (m_iteration != gtOther->m_iteration) return false; diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 2e039c5ec1..c7968a5c1c 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -47,6 +47,7 @@ void adjustFormatStyleForLineBreak(clang::format::FormatStyle &style, // This is a separate pass, don't do it unless it's the full formatting. style.FixNamespaceComments = false; + style.AlignTrailingComments = false; if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) return; @@ -118,13 +119,11 @@ void trimRHSWhitespace(const QTextBlock &block) const int extraSpaceCount = static_cast<int>(std::distance(initialText.rbegin(), lastNonSpace)); QTextCursor cursor(block); - cursor.beginEditBlock(); cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, initialText.size() - extraSpaceCount); cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, extraSpaceCount); cursor.removeSelectedText(); - cursor.endEditBlock(); } QTextBlock reverseFindLastEmptyBlock(QTextBlock start) @@ -139,7 +138,13 @@ QTextBlock reverseFindLastEmptyBlock(QTextBlock start) return start; } -enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown }; +enum class CharacterContext { + AfterComma, + LastAfterComma, + NewStatementOrContinuation, + IfOrElseWithoutScope, + Unknown +}; QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) { @@ -150,10 +155,42 @@ QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null; } +int findMatchingOpeningParen(const QTextBlock &blockEndingWithClosingParen) +{ + const QTextDocument *doc = blockEndingWithClosingParen.document(); + int currentPos = blockEndingWithClosingParen.position() + + blockEndingWithClosingParen.text().lastIndexOf(')'); + int parenBalance = 1; + + while (currentPos > 0 && parenBalance > 0) { + --currentPos; + if (doc->characterAt(currentPos) == ')') + ++parenBalance; + if (doc->characterAt(currentPos) == '(') + --parenBalance; + } + + if (parenBalance == 0) + return currentPos; + + return -1; +} + +bool comesDirectlyAfterIf(const QTextDocument *doc, int pos) +{ + --pos; + while (pos > 0 && doc->characterAt(pos).isSpace()) + --pos; + return pos > 0 && doc->characterAt(pos) == 'f' && doc->characterAt(pos - 1) == 'i'; +} + CharacterContext characterContext(const QTextBlock ¤tBlock, const QTextBlock &previousNonEmptyBlock) { const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + if (prevLineText.isEmpty()) + return CharacterContext::NewStatementOrContinuation; + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); if (prevLineText.endsWith(',')) { // We don't need to add comma in case it's the last argument. @@ -162,12 +199,15 @@ CharacterContext characterContext(const QTextBlock ¤tBlock, return CharacterContext::AfterComma; } - if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}') - || firstNonWhitespaceChar == QChar::Null) { - return CharacterContext::NewStatement; + if (prevLineText.endsWith("else")) + return CharacterContext::IfOrElseWithoutScope; + if (prevLineText.endsWith(')')) { + const int pos = findMatchingOpeningParen(previousNonEmptyBlock); + if (pos >= 0 && comesDirectlyAfterIf(previousNonEmptyBlock.document(), pos)) + return CharacterContext::IfOrElseWithoutScope; } - return CharacterContext::Continuation; + return CharacterContext::NewStatementOrContinuation; } bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) @@ -181,20 +221,18 @@ bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock) { - if (closingBraceBlock - && (context == CharacterContext::NewStatement - || context == CharacterContext::Continuation)) { + if (closingBraceBlock && context == CharacterContext::NewStatementOrContinuation) return QByteArray(); - } switch (context) { case CharacterContext::AfterComma: return "a,"; - case CharacterContext::NewStatement: - return "a;"; - case CharacterContext::Continuation: case CharacterContext::LastAfterComma: - return "& a &"; + return "a"; + case CharacterContext::IfOrElseWithoutScope: + return ";"; + case CharacterContext::NewStatementOrContinuation: + return "/**/"; case CharacterContext::Unknown: default: QTC_ASSERT(false, return "";); @@ -202,7 +240,7 @@ QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock) } // Add extra text in case of the empty line or the line starting with ')'. -// Track such extra pieces of text in isInsideModifiedLine(). +// Track such extra pieces of text in isInsideDummyTextInLine(). int forceIndentWithExtraText(QByteArray &buffer, CharacterContext &charContext, const QTextBlock &block, @@ -265,7 +303,7 @@ int forceIndentWithExtraText(QByteArray &buffer, return extraLength; } -bool isInsideModifiedLine(const QString &originalLine, const QString &modifiedLine, int column) +bool isInsideDummyTextInLine(const QString &originalLine, const QString &modifiedLine, int column) { // Detect the cases when we have inserted extra text into the line to get the indentation. return originalLine.length() < modifiedLine.length() && column != modifiedLine.length() + 1 @@ -291,7 +329,7 @@ TextEditor::Replacements utf16Replacements(const QTextDocument *doc, const QString bufferLineText = Utils::Text::utf16LineTextInUtf8Buffer(utf8Buffer, static_cast<int>(replacement.getOffset())); - if (isInsideModifiedLine(lineText, bufferLineText, lineColUtf16.column)) + if (isInsideDummyTextInLine(lineText, bufferLineText, lineColUtf16.column)) continue; lineColUtf16.column = std::min(lineColUtf16.column, lineText.length() + 1); @@ -319,14 +357,12 @@ void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &repla int fullOffsetShift = 0; QTextCursor editCursor(doc); for (const TextEditor::Replacement &replacement : replacements) { - editCursor.beginEditBlock(); editCursor.setPosition(replacement.offset + fullOffsetShift); editCursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, replacement.length); editCursor.removeSelectedText(); editCursor.insertText(replacement.text); - editCursor.endEditBlock(); fullOffsetShift += replacement.text.length() - replacement.length; } } @@ -510,8 +546,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges); clang::format::FormattingAttemptStatus status; - const clang::tooling::Replacements formatReplacements - = reformat(style, *changedCode, ranges, m_fileName.toString().toStdString(), &status); + const clang::tooling::Replacements formatReplacements = reformat(style, + *changedCode, + ranges, + assumedFileName, + &status); clangReplacements = clangReplacements.merge(formatReplacements); const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); @@ -533,7 +572,7 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo startBlock = reverseFindLastEmptyBlock(startBlock); const int startBlockPosition = startBlock.position(); - if (startBlock.position() > 0) { + if (startBlockPosition > 0) { trimRHSWhitespace(startBlock.previous()); if (cursorPositionInEditor >= 0) cursorPositionInEditor += startBlock.position() - startBlockPosition; @@ -548,9 +587,9 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo // Format before current position only in case the cursor is inside the indented block. // So if cursor position is less then the block position then the current line is before // the indented block - don't trigger extra formatting in this case. - // cursorPositionInEditor == -1 means the consition matches automatically. + // cursorPositionInEditor == -1 means the condition matches automatically. - // Format only before newline or complete statement not to break code. + // Format only before complete statement not to break code. replacementsToKeep = ReplacementsToKeep::IndentAndBefore; } diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 72e1778999..4f2d77a6f7 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -125,11 +125,17 @@ void ClangFormatConfigWidget::initialize() if (lastItem->spacerItem()) m_ui->verticalLayout->removeItem(lastItem); + m_ui->clangFormatOptionsTable->setEnabled(true); if (!m_ui->overrideDefault->isChecked()) { - m_ui->clangFormatOptionsTable->hide(); - m_preview->hide(); - m_ui->verticalLayout->addStretch(1); - return; + if (m_project) { + m_ui->clangFormatOptionsTable->hide(); + m_preview->hide(); + m_ui->verticalLayout->addStretch(1); + return; + } else { + // Show the fallback configuration only globally. + m_ui->clangFormatOptionsTable->setEnabled(false); + } } m_ui->clangFormatOptionsTable->show(); @@ -145,6 +151,7 @@ void ClangFormatConfigWidget::initialize() if (!currentProject || !projectConfigExists()) { m_ui->projectHasClangFormat->hide(); } else { + m_ui->projectHasClangFormat->show(); m_ui->projectHasClangFormat->setText( tr("Current project has its own overridden .clang-format file " "and can be configured in Projects > Code Style > C++.")); @@ -189,7 +196,7 @@ void ClangFormatConfigWidget::apply() } settings.write(); - if (!m_ui->overrideDefault->isChecked()) + if (!m_ui->clangFormatOptionsTable->isVisible()) return; const QString text = m_ui->clangFormatOptionsTable->toPlainText(); diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 61e9386282..09a3150c89 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -293,8 +293,11 @@ static QByteArray configBaseStyleName(const QString &configFile) static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool checkForSettings) { QString configFile = configForFile(fileName, checkForSettings); - if (configFile.isEmpty()) - return constructStyle(); + if (configFile.isEmpty()) { + // If no configuration is found create a global one (if it does not yet exist) and use it. + createStyleFileIfNeeded(true); + configFile = globalPath().appendPath(Constants::SETTINGS_FILE_NAME).toString(); + } fileName = assumedPathForConfig(configFile); Expected<FormatStyle> style = format::getStyle("file", diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp index e46a7e70aa..684b47bd15 100644 --- a/src/plugins/coreplugin/fancytabwidget.cpp +++ b/src/plugins/coreplugin/fancytabwidget.cpp @@ -215,10 +215,13 @@ void FancyTabBar::mousePressEvent(QMouseEvent *event) // menu arrow clicked emit menuTriggered(index, event); } else { - m_currentIndex = index; - update(); - // update tab bar before showing widget - QTimer::singleShot(0, this, [this]() { emit currentChanged(m_currentIndex); }); + if (index != m_currentIndex) { + emit currentAboutToChange(index); + m_currentIndex = index; + update(); + // update tab bar before showing widget + QTimer::singleShot(0, this, [this]() { emit currentChanged(m_currentIndex); }); + } } } break; @@ -396,6 +399,7 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const void FancyTabBar::setCurrentIndex(int index) { if (isTabEnabled(index) && index != m_currentIndex) { + emit currentAboutToChange(index); m_currentIndex = index; update(); emit currentChanged(m_currentIndex); @@ -520,6 +524,7 @@ FancyTabWidget::FancyTabWidget(QWidget *parent) mainLayout->addLayout(vlayout); setLayout(mainLayout); + connect(m_tabBar, &FancyTabBar::currentAboutToChange, this, &FancyTabWidget::currentAboutToShow); connect(m_tabBar, &FancyTabBar::currentChanged, this, &FancyTabWidget::showWidget); connect(m_tabBar, &FancyTabBar::menuTriggered, this, &FancyTabWidget::menuTriggered); } @@ -598,7 +603,7 @@ void FancyTabWidget::addCornerWidget(QWidget *widget) int FancyTabWidget::currentIndex() const { - return m_modesStack->currentIndex(); + return m_tabBar->currentIndex(); } QStatusBar *FancyTabWidget::statusBar() const @@ -613,7 +618,6 @@ void FancyTabWidget::setCurrentIndex(int index) void FancyTabWidget::showWidget(int index) { - emit currentAboutToShow(index); m_modesStack->setCurrentIndex(index); QWidget *w = m_modesStack->currentWidget(); if (QTC_GUARD(w)) { diff --git a/src/plugins/coreplugin/fancytabwidget.h b/src/plugins/coreplugin/fancytabwidget.h index 19038add89..c9a7264d80 100644 --- a/src/plugins/coreplugin/fancytabwidget.h +++ b/src/plugins/coreplugin/fancytabwidget.h @@ -125,6 +125,7 @@ public: QRect tabRect(int index) const; signals: + void currentAboutToChange(int index); void currentChanged(int index); void menuTriggered(int index, QMouseEvent *event); diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index 6da4ac43fc..85c10e8f0c 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -44,10 +44,12 @@ #include <projectexplorer/session.h> #include <texteditor/icodestylepreferencesfactory.h> +#include <texteditor/storagesettings.h> #include <texteditor/textdocumentlayout.h> #include <texteditor/texteditorsettings.h> #include <coreplugin/editormanager/editormanager.h> +#include <utils/executeondestruction.h> #include <utils/mimetypes/mimedatabase.h> #include <utils/qtcassert.h> #include <utils/runextensions.h> @@ -448,6 +450,8 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave) { + Utils::ExecuteOnDestruction resetSettingsOnScopeExit; + if (indenter()->formatOnSave() && !autoSave) { auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout()); const int documentRevision = layout->lastSaveRevision; @@ -479,6 +483,12 @@ bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool indenter()->format(editedRanges); cursor.endEditBlock(); } + + TextEditor::StorageSettings settings = storageSettings(); + resetSettingsOnScopeExit.reset( + [this, defaultSettings = settings]() { setStorageSettings(defaultSettings); }); + settings.m_cleanWhitespace = false; + setStorageSettings(settings); } return TextEditor::TextDocument::save(errorString, fileName, autoSave); diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index d4cd874a4b..6e0ac9a7ff 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1661,8 +1661,8 @@ bool BreakHandler::contextMenuEvent(const ItemViewEvent &ev) // Delete by file: Find indices of breakpoints of the same file. QList<Breakpoint> breakpointsInFile; QString file; - if (Breakpoint bp = itemForIndexAtLevel<1>(ev.index())) { - const QModelIndex index = ev.index().sibling(ev.index().row(), BreakpointFileColumn); + if (Breakpoint bp = itemForIndexAtLevel<1>(ev.sourceModelIndex())) { + const QModelIndex index = ev.sourceModelIndex().sibling(ev.sourceModelIndex().row(), BreakpointFileColumn); if (!file.isEmpty()) { for (int i = 0; i != rowCount(); ++i) if (index.data().toString() == file) @@ -2626,7 +2626,7 @@ bool BreakpointManager::contextMenuEvent(const ItemViewEvent &ev) // Delete by file: Find indices of breakpoints of the same file. GlobalBreakpoints breakpointsInFile; QString file; - if (GlobalBreakpoint gbp = itemForIndexAtLevel<1>(ev.index())) { + if (GlobalBreakpoint gbp = itemForIndexAtLevel<1>(ev.sourceModelIndex())) { if (!file.isEmpty()) { for (int i = 0; i != rowCount(); ++i) if (gbp->markerFileName() == file) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 8c742bf281..a492b4eaed 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -61,6 +61,7 @@ #include <coreplugin/icore.h> #include <coreplugin/idocument.h> #include <coreplugin/messagebox.h> +#include <coreplugin/modemanager.h> #include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/futureprogress.h> @@ -280,12 +281,16 @@ public: m_disassemblerAgent(engine), m_toolTipManager(engine) { - m_logWindow = new LogWindow(m_engine); // Needed before start() - m_logWindow->setObjectName(DOCKWIDGET_OUTPUT); m_debuggerName = DebuggerEngine::tr("Debugger"); - connect(action(EnableReverseDebugging), &SavedAction::valueChanged, - this, [this] { updateState(true); }); + m_logWindow = new LogWindow(m_engine); // Needed before start() + m_logWindow->setObjectName("Debugger.Dock.Output"); + + connect(action(EnableReverseDebugging), &SavedAction::valueChanged, this, [this] { + updateState(); + if (m_companionEngine) + m_companionEngine->d->updateState(); + }); static int contextCount = 0; m_context = Context(Id("Debugger.Engine.").withSuffix(++contextCount)); @@ -370,17 +375,15 @@ public: if (!m_perspective) return; - delete m_perspective; + Perspective *perspective = m_perspective; m_perspective = nullptr; EngineManager::unregisterEngine(m_engine); - // Give up ownership on claimed breakpoints. - m_breakHandler.releaseAllBreakpoints(); - m_toolTipManager.deregisterEngine(); - m_memoryAgents.handleDebuggerFinished(); - - setBusyCursor(false); + // This triggers activity in the EngineManager which + // recognizes the rampdown by the m_perpective == nullptr above. + perspective->destroy(); + delete perspective; } void updateReturnViewHeader(int section, int, int newSize) @@ -446,13 +449,13 @@ public: void setInitialActionStates(); void setBusyCursor(bool on); void cleanupViews(); - void updateState(bool alsoUpdateCompanion); + void updateState(); void updateReverseActions(); DebuggerEngine *m_engine = nullptr; // Not owned. QString m_runId; QString m_debuggerName; - Perspective *m_perspective = nullptr; + QPointer<Perspective> m_perspective; DebuggerRunParameters m_runParameters; IDevice::ConstPtr m_device; @@ -550,16 +553,17 @@ public: void DebuggerEnginePrivate::setupViews() { const DebuggerRunParameters &rp = m_runParameters; + const QString engineId = EngineManager::registerEngine(m_engine); QTC_CHECK(!m_perspective); - m_perspective = new Perspective("Debugger.Perspective." + m_runId + '.' + m_debuggerName, + const QString perspectiveId = "Debugger.Perspective." + m_runId + '.' + m_debuggerName; + const QString settingsId = "Debugger.Perspective." + m_debuggerName; + + m_perspective = new Perspective(perspectiveId, m_engine->displayName(), Debugger::Constants::PRESET_PERSPECTIVE_ID, - m_debuggerName); - m_perspective->setShouldPersistChecker([this] { - return EngineManager::isLastOf(m_debuggerName); - }); + settingsId); m_progress.setProgressRange(0, 1000); FutureProgress *fp = ProgressManager::addTask(m_progress.future(), @@ -627,7 +631,7 @@ void DebuggerEnginePrivate::setupViews() m_engine, &DebuggerEngine::reloadModules, Qt::QueuedConnection); m_modulesWindow = addSearch(m_modulesView); - m_modulesWindow->setObjectName(DOCKWIDGET_MODULES); + m_modulesWindow->setObjectName("Debugger.Dock.Modules." + engineId); m_modulesWindow->setWindowTitle(tr("&Modules")); m_registerView = new BaseTreeView; @@ -638,7 +642,7 @@ void DebuggerEnginePrivate::setupViews() m_engine, &DebuggerEngine::reloadRegisters, Qt::QueuedConnection); m_registerWindow = addSearch(m_registerView); - m_registerWindow->setObjectName(DOCKWIDGET_REGISTER); + m_registerWindow->setObjectName("Debugger.Dock.Register." + engineId); m_registerWindow->setWindowTitle(tr("Reg&isters")); m_stackView = new StackTreeView; @@ -646,7 +650,7 @@ void DebuggerEnginePrivate::setupViews() m_stackView->setSettings(settings, "Debugger.StackView"); m_stackView->setIconSize(QSize(10, 10)); m_stackWindow = addSearch(m_stackView); - m_stackWindow->setObjectName(DOCKWIDGET_STACK); + m_stackWindow->setObjectName("Debugger.Dock.Stack." + engineId); m_stackWindow->setWindowTitle(tr("&Stack")); m_sourceFilesView = new BaseTreeView; @@ -657,7 +661,7 @@ void DebuggerEnginePrivate::setupViews() m_engine, &DebuggerEngine::reloadSourceFiles, Qt::QueuedConnection); m_sourceFilesWindow = addSearch(m_sourceFilesView); - m_sourceFilesWindow->setObjectName(DOCKWIDGET_SOURCE_FILES); + m_sourceFilesWindow->setObjectName("Debugger.Dock.SourceFiles." + engineId); m_sourceFilesWindow->setWindowTitle(tr("Source Files")); m_threadsView = new BaseTreeView; @@ -667,7 +671,7 @@ void DebuggerEnginePrivate::setupViews() m_threadsView->setIconSize(QSize(10, 10)); m_threadsView->setSpanColumn(ThreadData::FunctionColumn); m_threadsWindow = addSearch(m_threadsView); - m_threadsWindow->setObjectName(DOCKWIDGET_THREADS); + m_threadsWindow->setObjectName("Debugger.Dock.Threads." + engineId); m_threadsWindow->setWindowTitle(tr("&Threads")); m_returnView = new WatchTreeView{ReturnType}; @@ -681,26 +685,26 @@ void DebuggerEnginePrivate::setupViews() m_localsView->setModel(m_watchHandler.model()); m_localsView->setSettings(settings, "Debugger.LocalsView"); m_localsWindow = addSearch(m_localsView); - m_localsWindow->setObjectName("CppDebugLocals"); + m_localsWindow->setObjectName("Debugger.Dock.Locals." + engineId); m_localsWindow->setWindowTitle(tr("Locals")); m_inspectorView = new WatchTreeView{InspectType}; m_inspectorView->setModel(m_watchHandler.model()); m_inspectorView->setSettings(settings, "Debugger.LocalsView"); // sic! same as locals view. m_inspectorWindow = addSearch(m_inspectorView); - m_inspectorWindow->setObjectName("Inspector"); + m_inspectorWindow->setObjectName("Debugger.Dock.Inspector." + engineId); m_inspectorWindow->setWindowTitle(tr("Locals")); m_watchersView = new WatchTreeView{WatchersType}; m_watchersView->setModel(m_watchHandler.model()); m_watchersView->setSettings(settings, "Debugger.WatchersView"); m_watchersWindow = addSearch(m_watchersView); - m_watchersWindow->setObjectName("CppDebugWatchers"); + m_watchersWindow->setObjectName("Debugger.Dock.Watchers." + engineId); m_watchersWindow->setWindowTitle(tr("&Expressions")); m_localsAndInspectorWindow = new LocalsAndInspectorWindow( m_localsWindow, m_inspectorWindow, m_returnWindow); - m_localsAndInspectorWindow->setObjectName(DOCKWIDGET_LOCALS_AND_INSPECTOR); + m_localsAndInspectorWindow->setObjectName("Debugger.Dock.LocalsAndInspector." + engineId); m_localsAndInspectorWindow->setWindowTitle(m_localsWindow->windowTitle()); // Locals @@ -718,7 +722,7 @@ void DebuggerEnginePrivate::setupViews() m_breakView->setModel(m_breakHandler.model()); m_breakView->setRootIsDecorated(true); m_breakWindow = addSearch(m_breakView); - m_breakWindow->setObjectName(DOCKWIDGET_BREAK); + m_breakWindow->setObjectName("Debugger.Dock.Break." + engineId); m_breakWindow->setWindowTitle(tr("&Breakpoints")); m_perspective->useSubPerspectiveSwitcher(EngineManager::engineChooser()); @@ -845,7 +849,6 @@ void DebuggerEnginePrivate::setupViews() DebuggerEngine::DebuggerEngine() : d(new DebuggerEnginePrivate(this)) { - updateState(false); } DebuggerEngine::~DebuggerEngine() @@ -1018,7 +1021,6 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool) void DebuggerEngine::start() { - EngineManager::registerEngine(this); d->m_watchHandler.resetWatchers(); d->setInitialActionStates(); setState(EngineSetupRequested); @@ -1114,7 +1116,7 @@ void DebuggerEngine::abortDebugger() void DebuggerEngine::updateUi(bool isCurrentEngine) { - updateState(false); + updateState(); if (isCurrentEngine) { gotoCurrentLocation(); } else { @@ -1317,7 +1319,7 @@ void DebuggerEngine::notifyInferiorSpontaneousStop() { showMessage("NOTE: INFERIOR SPONTANEOUS STOP"); QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state()); - EngineManager::activateEngine(this); + d->m_perspective->select(); showMessage(tr("Stopped."), StatusBar); setState(InferiorStopOk); if (boolSetting(RaiseOnInterrupt)) @@ -1384,10 +1386,12 @@ void DebuggerEnginePrivate::setInitialActionStates() m_threadLabel->setEnabled(false); } -void DebuggerEnginePrivate::updateState(bool alsoUpdateCompanion) +void DebuggerEnginePrivate::updateState() { - if (!m_perspective) + // Can happen in mixed debugging. + if (!m_threadLabel) return; + QTC_ASSERT(m_threadLabel, return); const DebuggerState state = m_state; const bool companionPreventsAction = m_engine->companionPreventsActions(); @@ -1397,7 +1401,7 @@ void DebuggerEnginePrivate::updateState(bool alsoUpdateCompanion) // visible, possibly disabled. if (state == DebuggerNotReady) { // Happens when companion starts, otherwise this should not happen. - QTC_CHECK(m_companionEngine); + //QTC_CHECK(m_companionEngine); m_interruptAction.setVisible(true); m_interruptAction.setEnabled(false); m_continueAction.setVisible(false); @@ -1527,9 +1531,6 @@ void DebuggerEnginePrivate::updateState(bool alsoUpdateCompanion) || state == DebuggerFinished || state == InferiorUnrunnable; setBusyCursor(!notbusy); - - if (alsoUpdateCompanion && m_companionEngine) - m_companionEngine->updateState(false); } void DebuggerEnginePrivate::updateReverseActions() @@ -1688,9 +1689,9 @@ void DebuggerEngine::notifyInferiorExited() d->doShutdownEngine(); } -void DebuggerEngine::updateState(bool alsoUpdateCompanion) +void DebuggerEngine::updateState() { - d->updateState(alsoUpdateCompanion); + d->updateState(); } WatchTreeView *DebuggerEngine::inspectorView() @@ -1791,17 +1792,28 @@ void DebuggerEngine::setState(DebuggerState state, bool forced) if (!forced && !isAllowedTransition(oldState, state)) qDebug() << "*** UNEXPECTED STATE TRANSITION: " << this << msg; - if (state == EngineRunRequested) + if (state == EngineRunRequested) { emit engineStarted(); + d->m_perspective->select(); + } showMessage(msg, LogDebug); - d->updateState(true); + d->updateState(); + if (d->m_companionEngine) + d->m_companionEngine->d->updateState(); if (oldState != d->m_state) emit EngineManager::instance()->engineStateChanged(this); if (state == DebuggerFinished) { + d->setBusyCursor(false); + + // Give up ownership on claimed breakpoints. + d->m_breakHandler.releaseAllBreakpoints(); + d->m_toolTipManager.deregisterEngine(); + d->m_memoryAgents.handleDebuggerFinished(); + d->destroyPerspective(); emit engineFinished(); } diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index caa1b67b19..54eb9fa22a 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -445,7 +445,7 @@ protected: void notifyInferiorStopFailed(); public: - void updateState(bool alsoUpdateCompanion); + void updateState(); QString formatStartParameters() const; WatchTreeView *inspectorView(); void updateLocalsWindow(bool showReturn); diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index 7e1cf857df..7137a9100c 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -28,24 +28,6 @@ #include <QtGlobal> namespace Debugger { -namespace Internal { - -// DebuggerMainWindow dock widget names -const char DOCKWIDGET_BREAKPOINTMANAGER[] = "Debugger.Docks.BreakpointManager"; -const char DOCKWIDGET_ENGINEMANAGER[] = "Debugger.Docks.Snapshots"; -const char DOCKWIDGET_GLOBALLOG[] = "Debugger.Docks.GlobalLog"; - -const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; -const char DOCKWIDGET_MODULES[] = "Debugger.Docks.Modules"; -const char DOCKWIDGET_REGISTER[] = "Debugger.Docks.Register"; -const char DOCKWIDGET_OUTPUT[] = "Debugger.Docks.Output"; -const char DOCKWIDGET_STACK[] = "Debugger.Docks.Stack"; -const char DOCKWIDGET_SOURCE_FILES[] = "Debugger.Docks.SourceFiles"; -const char DOCKWIDGET_THREADS[] = "Debugger.Docks.Threads"; -const char DOCKWIDGET_LOCALS_AND_INSPECTOR[] = "Debugger.Docks.LocalsAndInspector"; - -} // namespace Internal - namespace Constants { diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index c6e88b1116..ad26012b05 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -49,9 +49,10 @@ #include <QAction> #include <QComboBox> -#include <QDebug> +#include <QContextMenuEvent> #include <QDockWidget> #include <QHBoxLayout> +#include <QLoggingCategory> #include <QMenu> #include <QScrollArea> #include <QStackedWidget> @@ -62,37 +63,57 @@ using namespace Debugger; using namespace Core; +Q_LOGGING_CATEGORY(perspectivesLog, "qtc.utils.perspectives", QtWarningMsg) + namespace Utils { +const int SettingsVersion = 3; + const char LAST_PERSPECTIVE_KEY[] = "LastPerspective"; -const char OWNED_BY_PERSPECTIVE[] = "OwnedByPerspective"; +const char MAINWINDOW_KEY[] = "Debugger.MainWindow"; +const char AUTOHIDE_TITLEBARS_KEY[] = "AutoHideTitleBars"; +const char SHOW_CENTRALWIDGET_KEY[] = "ShowCentralWidget"; +const char STATE_KEY[] = "State"; +const char CHANGED_DOCK_KEY[] = "ChangedDocks"; static DebuggerMainWindow *theMainWindow = nullptr; class DockOperation { public: + void setupLayout(); + QString name() const { QTC_ASSERT(widget, return QString()); return widget->objectName(); } + + Core::Id commandId; QPointer<QWidget> widget; - QString anchorDockId; + QPointer<QDockWidget> dock; + QPointer<QWidget> anchorWidget; Perspective::OperationType operationType = Perspective::Raise; bool visibleByDefault = true; + bool visibleByUser = true; Qt::DockWidgetArea area = Qt::BottomDockWidgetArea; }; class PerspectivePrivate { public: - void showToolBar(); - void hideToolBar(); + void showInnerToolBar(); + void hideInnerToolBar(); void restoreLayout(); void saveLayout(); + void resetPerspective(); + void populatePerspective(); + void depopulatePerspective(); + void saveAsLastUsedPerspective(); + Context context() const; + QString settingsId() const; QToolButton *setupToolButton(QAction *action); QString m_id; QString m_name; QString m_parentPerspectiveId; - QString m_subPerspectiveType; + QString m_settingsId; QVector<DockOperation> m_dockOperations; QPointer<QWidget> m_centralWidget; Perspective::Callback m_aboutToActivateCallback; @@ -100,8 +121,6 @@ public: QHBoxLayout *m_innerToolBarLayout = nullptr; QPointer<QWidget> m_switcher; QString m_lastActiveSubPerspectiveId; - QHash<QString, QVariant> m_nonPersistenSettings; - Perspective::ShouldPersistChecker m_shouldPersistChecker; }; class DebuggerMainWindowPrivate : public QObject @@ -118,20 +137,30 @@ public: void registerPerspective(Perspective *perspective); void resetCurrentPerspective(); int indexInChooser(Perspective *perspective) const; - void fixupLayoutIfNeeded(); void updatePerspectiveChooserWidth(); + void cleanDocks(); + void setCentralWidget(QWidget *widget); + + QDockWidget *dockForWidget(QWidget *widget) const; + + void setCurrentPerspective(Perspective *perspective) + { + m_currentPerspective = perspective; + } + DebuggerMainWindow *q = nullptr; - Perspective *m_currentPerspective = nullptr; + QPointer<Perspective> m_currentPerspective = nullptr; QComboBox *m_perspectiveChooser = nullptr; QStackedWidget *m_centralWidgetStack = nullptr; QHBoxLayout *m_subPerspectiveSwitcherLayout = nullptr; QHBoxLayout *m_innerToolsLayout = nullptr; - QWidget *m_editorPlaceHolder = nullptr; + QPointer<QWidget> m_editorPlaceHolder; Utils::StatusLabel *m_statusLabel = nullptr; QDockWidget *m_toolBarDock = nullptr; - QList<Perspective *> m_perspectives; + QList<QPointer<Perspective>> m_perspectives; + QSet<QString> m_persistentChangedDocks; }; DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) @@ -211,10 +240,9 @@ DebuggerMainWindowPrivate::DebuggerMainWindowPrivate(DebuggerMainWindow *parent) m_toolBarDock = dock; q->addDockWidget(Qt::BottomDockWidgetArea, m_toolBarDock); - connect(viewButton, &QAbstractButton::clicked, [this, viewButton] { - QMenu menu; - q->addDockActionsToMenu(&menu); - menu.exec(viewButton->mapToGlobal(QPoint())); + connect(viewButton, &QAbstractButton::clicked, this, [this, viewButton] { + ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS); + viewsMenu->menu()->exec(viewButton->mapToGlobal(QPoint())); }); connect(closeButton, &QAbstractButton::clicked, [] { @@ -256,6 +284,19 @@ DebuggerMainWindow::DebuggerMainWindow() "Debugger.Views.ResetSimple", debugcontext); cmd->setAttribute(Command::CA_Hide); viewsMenu->addAction(cmd, Core::Constants::G_DEFAULT_THREE); + + connect(ICore::instance(), &ICore::saveSettingsRequested, this, [this] { + // There's one saveSettings triggered after plugin loading intentionally. + // We do not want to save anything at that time. + static bool firstOne = true; + if (firstOne) { + qCDebug(perspectivesLog) << "FIRST SAVE SETTINGS REQUEST IGNORED"; + firstOne = false; + } else { + qCDebug(perspectivesLog) << "SAVING SETTINGS"; + savePersistentSettings(); + } + }); } DebuggerMainWindow::~DebuggerMainWindow() @@ -263,6 +304,12 @@ DebuggerMainWindow::~DebuggerMainWindow() delete d; } +void DebuggerMainWindow::contextMenuEvent(QContextMenuEvent *ev) +{ + ActionContainer *viewsMenu = ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS); + viewsMenu->menu()->exec(ev->globalPos()); +} + void DebuggerMainWindow::ensureMainWindowExists() { if (!theMainWindow) @@ -271,6 +318,8 @@ void DebuggerMainWindow::ensureMainWindowExists() void DebuggerMainWindow::doShutdown() { + QTC_ASSERT(theMainWindow, return); + delete theMainWindow; theMainWindow = nullptr; } @@ -286,9 +335,12 @@ void DebuggerMainWindowPrivate::registerPerspective(Perspective *perspective) void DebuggerMainWindowPrivate::destroyPerspective(Perspective *perspective) { - if (perspective == m_currentPerspective) { - depopulateCurrentPerspective(); - m_currentPerspective = nullptr; + qCDebug(perspectivesLog) << "ABOUT TO DESTROY PERSPECTIVE" << perspective->id(); + + const bool wasCurrent = perspective == m_currentPerspective; + if (wasCurrent) { + qCDebug(perspectivesLog) << "RAMPING IT DOWN FIRST AS IT WAS CURRENT" << perspective->id(); + perspective->rampDownAsCurrent(); } m_perspectives.removeAll(perspective); @@ -298,6 +350,31 @@ void DebuggerMainWindowPrivate::destroyPerspective(Perspective *perspective) const int idx = indexInChooser(perspective); if (idx != -1) m_perspectiveChooser->removeItem(idx); + + for (DockOperation &op : perspective->d->m_dockOperations) { + if (op.commandId.isValid()) + ActionManager::unregisterAction(op.dock->toggleViewAction(), op.commandId); + if (op.dock) { + theMainWindow->removeDockWidget(op.dock); + op.widget->setParent(nullptr); // Prevent deletion + op.dock->setParent(nullptr); + delete op.dock; + op.dock = nullptr; + } + } + + if (wasCurrent) { + if (Perspective *parent = Perspective::findPerspective(perspective->d->m_parentPerspectiveId)) { + qCDebug(perspectivesLog) << "RAMPING UP PARENT PERSPECTIVE" << parent->id(); + parent->rampUpAsCurrent(); + } else { + qCDebug(perspectivesLog) << "RAMPED DOWN WAS ACTION, BUT NO PARENT AVAILABLE. TAKE FIRST BEST"; + if (QTC_GUARD(!m_perspectives.isEmpty())) + m_perspectives.first()->rampUpAsCurrent(); + } + } + + qCDebug(perspectivesLog) << "DESTROYED PERSPECTIVE" << perspective->id(); } void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS) @@ -309,36 +386,122 @@ void DebuggerMainWindow::showStatusMessage(const QString &message, int timeoutMS void DebuggerMainWindow::enterDebugMode() { theMainWindow->setDockActionsVisible(true); - Perspective *perspective = theMainWindow->d->m_currentPerspective; - if (!perspective) { - const QSettings *settings = ICore::settings(); - const QString lastPerspectiveId = settings->value(LAST_PERSPECTIVE_KEY).toString(); - perspective = Perspective::findPerspective(lastPerspectiveId); - // If we don't find a perspective with the stored name, pick any. - // This can happen e.g. when a plugin was disabled that provided - // the stored perspective, or when the save file was modified externally. - if (!perspective && !theMainWindow->d->m_perspectives.isEmpty()) - perspective = theMainWindow->d->m_perspectives.first(); - } + theMainWindow->restorePersistentSettings(); + QTC_CHECK(theMainWindow->d->m_currentPerspective == nullptr); + + QSettings *settings = ICore::settings(); + const QString lastPerspectiveId = settings->value(LAST_PERSPECTIVE_KEY).toString(); + Perspective *perspective = Perspective::findPerspective(lastPerspectiveId); + // If we don't find a perspective with the stored name, pick any. + // This can happen e.g. when a plugin was disabled that provided + // the stored perspective, or when the save file was modified externally. + if (!perspective && !theMainWindow->d->m_perspectives.isEmpty()) + perspective = theMainWindow->d->m_perspectives.first(); + // There's at least the debugger preset perspective that should be found above. QTC_ASSERT(perspective, return); - perspective->select(); + + if (auto sub = Perspective::findPerspective(perspective->d->m_lastActiveSubPerspectiveId)) { + qCDebug(perspectivesLog) << "SWITCHING TO SUBPERSPECTIVE" << sub->d->m_id; + perspective = sub; + } + + perspective->rampUpAsCurrent(); } void DebuggerMainWindow::leaveDebugMode() { - if (Perspective *perspective = theMainWindow->d->m_currentPerspective) - perspective->d->saveLayout(); + theMainWindow->savePersistentSettings(); + + if (theMainWindow->d->m_currentPerspective) + theMainWindow->d->m_currentPerspective->rampDownAsCurrent(); + QTC_CHECK(theMainWindow->d->m_currentPerspective == nullptr); theMainWindow->setDockActionsVisible(false); // Hide dock widgets manually in case they are floating. for (QDockWidget *dockWidget : theMainWindow->dockWidgets()) { if (dockWidget->isFloating()) - dockWidget->hide(); + dockWidget->setVisible(false); } } +void DebuggerMainWindow::restorePersistentSettings() +{ + qCDebug(perspectivesLog) << "RESTORE PERSISTENT"; + QSettings *settings = ICore::settings(); + settings->beginGroup(MAINWINDOW_KEY); + const bool res = theMainWindow->restoreState(settings->value(STATE_KEY).toByteArray(), + SettingsVersion); + if (!res) + qCDebug(perspectivesLog) << "NO READABLE PERSISTENT SETTINGS FOUND, ASSUMING NEW CLEAN SETTINGS"; + + theMainWindow->setAutoHideTitleBars(settings->value(AUTOHIDE_TITLEBARS_KEY, true).toBool()); + theMainWindow->showCentralWidget(settings->value(SHOW_CENTRALWIDGET_KEY, true).toBool()); + theMainWindow->d->m_persistentChangedDocks + = QSet<QString>::fromList(settings->value(CHANGED_DOCK_KEY).toStringList()); + settings->endGroup(); + + qCDebug(perspectivesLog) << "LOADED DOCKS:" << theMainWindow->d->m_persistentChangedDocks; + + for (Perspective *perspective : theMainWindow->d->m_perspectives) { + qCDebug(perspectivesLog) << "RESTORING PERSPECTIVE" << perspective->d->m_id; + for (DockOperation &op : perspective->d->m_dockOperations) { + if (op.operationType != Perspective::Raise) { + QTC_ASSERT(op.dock, continue); + QTC_ASSERT(op.widget, continue); + if (theMainWindow->d->m_persistentChangedDocks.contains(op.name())) { + qCDebug(perspectivesLog) << "DOCK " << op.name() << "*** UNUSUAL"; + op.visibleByUser = !op.visibleByDefault; + } else { + qCDebug(perspectivesLog) << "DOCK " << op.name() << "NORMAL"; + QTC_CHECK(op.visibleByUser == op.visibleByDefault); + } + } + } + } +} + +Perspective *DebuggerMainWindow::currentPerspective() +{ + return theMainWindow->d->m_currentPerspective; +} + +void DebuggerMainWindow::savePersistentSettings() +{ + // The current one might have active, non saved changes. + if (Perspective *perspective = theMainWindow->d->m_currentPerspective) + perspective->d->saveLayout(); + + qCDebug(perspectivesLog) << "SAVE PERSISTENT"; + + QSet<QString> changedDocks = theMainWindow->d->m_persistentChangedDocks; + for (Perspective *perspective : theMainWindow->d->m_perspectives) { + qCDebug(perspectivesLog) << "SAVE PERSPECTIVE" << perspective->d->m_id; + for (const DockOperation &op : perspective->d->m_dockOperations) { + if (op.operationType != Perspective::Raise) { + QTC_ASSERT(op.dock, continue); + QTC_ASSERT(op.widget, continue); + qCDebug(perspectivesLog) << "DOCK " << op.name() << "ACTIVE: " << op.visibleByUser; + if (op.visibleByUser != op.visibleByDefault) + changedDocks.insert(op.name()); + else + changedDocks.remove(op.name()); + } + } + } + theMainWindow->d->m_persistentChangedDocks = changedDocks; + qCDebug(perspectivesLog) << "CHANGED DOCKS:" << changedDocks; + + QSettings *settings = ICore::settings(); + settings->beginGroup(MAINWINDOW_KEY); + settings->setValue(CHANGED_DOCK_KEY, QStringList(changedDocks.toList())); + settings->setValue(STATE_KEY, theMainWindow->saveState(SettingsVersion)); + settings->setValue(AUTOHIDE_TITLEBARS_KEY, theMainWindow->autoHideTitleBars()); + settings->setValue(SHOW_CENTRALWIDGET_KEY, theMainWindow->isCentralWidgetShown()); + settings->endGroup(); +} + QWidget *DebuggerMainWindow::centralWidgetStack() { return theMainWindow ? theMainWindow->d->m_centralWidgetStack : nullptr; @@ -358,67 +521,100 @@ DebuggerMainWindow *DebuggerMainWindow::instance() Perspective *Perspective::findPerspective(const QString &perspectiveId) { - return Utils::findOr(theMainWindow->d->m_perspectives, nullptr, [&](Perspective *perspective) { - return perspective->d->m_id == perspectiveId; + QTC_ASSERT(theMainWindow, return nullptr); + return Utils::findOr(theMainWindow->d->m_perspectives, nullptr, + [perspectiveId](Perspective *perspective) { + return perspective && perspective->d->m_id == perspectiveId; }); } -void DebuggerMainWindowPrivate::resetCurrentPerspective() +bool Perspective::isCurrent() const { - if (m_currentPerspective) { - m_currentPerspective->d->m_nonPersistenSettings.clear(); - m_currentPerspective->d->hideToolBar(); - } - depopulateCurrentPerspective(); - populateCurrentPerspective(); - if (m_currentPerspective) - m_currentPerspective->d->saveLayout(); + return theMainWindow->d->m_currentPerspective == this; } -int DebuggerMainWindowPrivate::indexInChooser(Perspective *perspective) const +QDockWidget *DebuggerMainWindowPrivate::dockForWidget(QWidget *widget) const { - return perspective ? m_perspectiveChooser->findData(perspective->d->m_id) : -1; + QTC_ASSERT(widget, return nullptr); + + for (QDockWidget *dock : q->dockWidgets()) { + if (dock->widget() == widget) + return dock; + } + + return nullptr; } -void DebuggerMainWindowPrivate::fixupLayoutIfNeeded() +void DebuggerMainWindowPrivate::resetCurrentPerspective() { - // Evil workaround for QTCREATORBUG-21455: In some so far unknown situation - // the saveLayout/restoreLayout process leads to a situation where some docks - // do not end up below the perspective toolbar even though they were there - // initially, leading to an awkward dock layout. - // This here tries to detect the situation (sonmething else in the bottom - // area is at the right of the toolbar) "corrects" that by restoring the - // default layout. + QTC_ASSERT(m_currentPerspective, return); + cleanDocks(); + m_currentPerspective->d->resetPerspective(); + setCentralWidget(m_currentPerspective->d->m_centralWidget); +} - if (m_toolBarDock->width() != q->width()) { - qDebug() << "Scrambled dock layout found. Resetting it."; - resetCurrentPerspective(); +void DebuggerMainWindowPrivate::setCentralWidget(QWidget *widget) +{ + if (widget) { + m_centralWidgetStack->addWidget(widget); + q->showCentralWidgetAction()->setText(widget->windowTitle()); + } else { + m_centralWidgetStack->addWidget(m_editorPlaceHolder); + q->showCentralWidgetAction()->setText(DebuggerMainWindow::tr("Editor")); } } -void DebuggerMainWindowPrivate::selectPerspective(Perspective *perspective) +void PerspectivePrivate::resetPerspective() { - QTC_ASSERT(perspective, return); + showInnerToolBar(); - if (m_currentPerspective) { - m_currentPerspective->d->saveLayout(); - m_currentPerspective->d->hideToolBar(); + for (DockOperation &op : m_dockOperations) { + if (op.operationType == Perspective::Raise) { + QTC_ASSERT(op.dock, qCDebug(perspectivesLog) << op.name(); continue); + op.dock->raise(); + } else { + op.setupLayout(); + op.dock->setVisible(op.visibleByDefault); + qCDebug(perspectivesLog) << "SETTING " << op.name() + << " TO ACTIVE: " << op.visibleByDefault; + } } +} - depopulateCurrentPerspective(); - - m_currentPerspective = perspective; - - perspective->aboutToActivate(); - - populateCurrentPerspective(); +void DockOperation::setupLayout() +{ + QTC_ASSERT(widget, return); + QTC_ASSERT(operationType != Perspective::Raise, return); + QTC_ASSERT(dock, return); - if (m_currentPerspective) { - m_currentPerspective->d->restoreLayout(); - fixupLayoutIfNeeded(); + QDockWidget *anchor = nullptr; + if (anchorWidget) + anchor = theMainWindow->d->dockForWidget(anchorWidget); + else if (area == Qt::BottomDockWidgetArea) + anchor = theMainWindow->d->m_toolBarDock; + + if (anchor) { + switch (operationType) { + case Perspective::AddToTab: + theMainWindow->tabifyDockWidget(anchor, dock); + break; + case Perspective::SplitHorizontal: + theMainWindow->splitDockWidget(anchor, dock, Qt::Horizontal); + break; + case Perspective::SplitVertical: + theMainWindow->splitDockWidget(anchor, dock, Qt::Vertical); + break; + default: + break; + } + } else { + theMainWindow->addDockWidget(area, dock); } +} - updatePerspectiveChooserWidth(); +int DebuggerMainWindowPrivate::indexInChooser(Perspective *perspective) const +{ + return perspective ? m_perspectiveChooser->findData(perspective->d->m_id) : -1; } void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth() @@ -445,111 +641,72 @@ void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth() } } -void DebuggerMainWindowPrivate::depopulateCurrentPerspective() +void DebuggerMainWindowPrivate::cleanDocks() { - // Clean up old perspective. + m_statusLabel->clear(); + for (QDockWidget *dock : q->dockWidgets()) { - if (dock->property(OWNED_BY_PERSPECTIVE).toBool()) { - // Prevent deletion of plugin-owned widgets. - if (dock->widget()) - dock->widget()->setParent(nullptr); - ActionManager::unregisterAction(dock->toggleViewAction(), - Id("Dock.").withSuffix(dock->objectName())); - delete dock; - } + if (dock != m_toolBarDock) + dock->setVisible(false); } +} + +void PerspectivePrivate::depopulatePerspective() +{ + ICore::removeAdditionalContext(context()); + theMainWindow->d->m_centralWidgetStack + ->removeWidget(m_centralWidget ? m_centralWidget : theMainWindow->d->m_editorPlaceHolder); - if (m_currentPerspective) { - ICore::removeAdditionalContext(m_currentPerspective->context()); - QWidget *central = m_currentPerspective->centralWidget(); - m_centralWidgetStack->removeWidget(central ? central : m_editorPlaceHolder); + theMainWindow->d->m_statusLabel->clear(); + + for (QDockWidget *dock : theMainWindow->dockWidgets()) { + if (dock != theMainWindow->d->m_toolBarDock) + dock->setVisible(false); } + + hideInnerToolBar(); } -void DebuggerMainWindowPrivate::populateCurrentPerspective() -{ - // Create dock widgets wrapping ther perspective's widgets. - QHash<QString, QDockWidget *> dockForDockId; - for (const DockOperation &op : m_currentPerspective->d->m_dockOperations) { - if (op.operationType == Perspective::Raise) - continue; - QTC_ASSERT(op.widget, continue); - const QString dockId = op.widget->objectName(); - QTC_CHECK(!dockId.isEmpty()); - QTC_ASSERT(!dockForDockId.contains(dockId), continue); - QDockWidget *dock = q->addDockForWidget(op.widget); - dock->setProperty(OWNED_BY_PERSPECTIVE, true); - dockForDockId[dockId] = dock; - q->addDockWidget(op.area, dock); - - QAction *toggleViewAction = dock->toggleViewAction(); - toggleViewAction->setText(dock->windowTitle()); - - Command *cmd = ActionManager::registerAction(toggleViewAction, - Id("Dock.").withSuffix(dock->objectName()), - m_currentPerspective->context()); - cmd->setAttribute(Command::CA_Hide); - ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd); - } +void PerspectivePrivate::saveAsLastUsedPerspective() +{ + if (Perspective *parent = Perspective::findPerspective(m_parentPerspectiveId)) + parent->d->m_lastActiveSubPerspectiveId = m_id; + else + m_lastActiveSubPerspectiveId.clear(); - m_currentPerspective->d->showToolBar(); + const QString &lastKey = m_parentPerspectiveId.isEmpty() ? m_id : m_parentPerspectiveId; + qCDebug(perspectivesLog) << "SAVE LAST USED PERSPECTIVE" << lastKey; + ICore::settings()->setValue(LAST_PERSPECTIVE_KEY, lastKey); +} - // Pre-arrange dock widgets. - for (const DockOperation &op : m_currentPerspective->d->m_dockOperations) { - QTC_ASSERT(op.widget, continue); - const QString dockId = op.widget->objectName(); - QDockWidget *dock = dockForDockId.value(dockId); - QTC_ASSERT(dock, continue); - if (op.operationType == Perspective::Raise) { - dock->raise(); - continue; - } - QDockWidget *anchor = dockForDockId.value(op.anchorDockId); - if (!anchor && op.area == Qt::BottomDockWidgetArea) { - anchor = m_toolBarDock; - } +void PerspectivePrivate::populatePerspective() +{ + showInnerToolBar(); - if (anchor) { - switch (op.operationType) { - case Perspective::AddToTab: - q->tabifyDockWidget(anchor, dock); - break; - case Perspective::SplitHorizontal: - q->splitDockWidget(anchor, dock, Qt::Horizontal); - break; - case Perspective::SplitVertical: - q->splitDockWidget(anchor, dock, Qt::Vertical); - break; - default: - break; - } - } - dock->setVisible(op.visibleByDefault); + if (m_centralWidget) { + theMainWindow->d->m_centralWidgetStack->addWidget(m_centralWidget); + theMainWindow->showCentralWidgetAction()->setText(m_centralWidget->windowTitle()); + } else { + theMainWindow->d->m_centralWidgetStack->addWidget(theMainWindow->d->m_editorPlaceHolder); + theMainWindow->showCentralWidgetAction()->setText(DebuggerMainWindow::tr("Editor")); } - QWidget *central = m_currentPerspective->centralWidget(); - m_centralWidgetStack->addWidget(central ? central : m_editorPlaceHolder); - q->showCentralWidgetAction()->setText(central ? central->windowTitle() - : DebuggerMainWindow::tr("Editor")); - - m_statusLabel->clear(); + ICore::addAdditionalContext(context()); - ICore::addAdditionalContext(m_currentPerspective->context()); + restoreLayout(); } // Perspective Perspective::Perspective(const QString &id, const QString &name, const QString &parentPerspectiveId, - const QString &subPerspectiveType) + const QString &settingsId) : d(new PerspectivePrivate) { - const bool shouldPersist = parentPerspectiveId.isEmpty(); d->m_id = id; d->m_name = name; d->m_parentPerspectiveId = parentPerspectiveId; - d->m_subPerspectiveType = subPerspectiveType; - d->m_shouldPersistChecker = [shouldPersist] { return shouldPersist; }; + d->m_settingsId = settingsId; DebuggerMainWindow::ensureMainWindowExists(); theMainWindow->d->registerPerspective(this); @@ -566,12 +723,8 @@ Perspective::Perspective(const QString &id, const QString &name, Perspective::~Perspective() { if (theMainWindow) { - d->saveLayout(); - delete d->m_innerToolBar; d->m_innerToolBar = nullptr; - - theMainWindow->d->destroyPerspective(this); } delete d; } @@ -597,12 +750,6 @@ void Perspective::setAboutToActivateCallback(const Perspective::Callback &cb) d->m_aboutToActivateCallback = cb; } -void Perspective::aboutToActivate() const -{ - if (d->m_aboutToActivateCallback) - d->m_aboutToActivateCallback(); -} - void Perspective::setEnabled(bool enabled) { QTC_ASSERT(theMainWindow, return); @@ -655,34 +802,24 @@ void Perspective::addToolbarSeparator() d->m_innerToolBarLayout->addWidget(new StyledSeparator(d->m_innerToolBar)); } -void Perspective::setShouldPersistChecker(const ShouldPersistChecker &checker) -{ - d->m_shouldPersistChecker = checker; -} - QWidget *Perspective::centralWidget() const { return d->m_centralWidget; } -Perspective *Perspective::currentPerspective() -{ - return theMainWindow ? theMainWindow->d->m_currentPerspective : nullptr; -} - -Context Perspective::context() const +Context PerspectivePrivate::context() const { - return Context(Id::fromName(d->m_id.toUtf8())); + return Context(Id::fromName(m_id.toUtf8())); } -void PerspectivePrivate::showToolBar() +void PerspectivePrivate::showInnerToolBar() { m_innerToolBar->setVisible(true); if (m_switcher) m_switcher->setVisible(true); } -void PerspectivePrivate::hideToolBar() +void PerspectivePrivate::hideInnerToolBar() { QTC_ASSERT(m_innerToolBar, return); m_innerToolBar->setVisible(false); @@ -699,63 +836,131 @@ void Perspective::addWindow(QWidget *widget, QTC_ASSERT(widget, return); DockOperation op; op.widget = widget; - if (anchorWidget) - op.anchorDockId = anchorWidget->objectName(); op.operationType = type; + op.anchorWidget = anchorWidget; op.visibleByDefault = visibleByDefault; op.area = area; + + if (op.operationType != Perspective::Raise) { + qCDebug(perspectivesLog) << "CREATING DOCK " << op.name() + << "DEFAULT: " << op.visibleByDefault; + op.dock = theMainWindow->addDockForWidget(op.widget); + op.commandId = Id("Dock.").withSuffix(op.name()); + if (theMainWindow->restoreDockWidget(op.dock)) { + qCDebug(perspectivesLog) << "RESTORED SUCCESSFULLY"; + } else { + qCDebug(perspectivesLog) << "COULD NOT RESTORE"; + op.setupLayout(); + } + op.dock->setVisible(false); + op.dock->toggleViewAction()->setText(op.dock->windowTitle()); + + QObject::connect(op.dock->toggleViewAction(), &QAction::changed, op.dock, [this, op] { + qCDebug(perspectivesLog) << "CHANGED: " << op.name() + << "ACTION CHECKED: " << op.dock->toggleViewAction()->isChecked(); + }); + + Command *cmd = ActionManager::registerAction(op.dock->toggleViewAction(), + op.commandId, d->context()); + cmd->setAttribute(Command::CA_Hide); + ActionManager::actionContainer(Core::Constants::M_WINDOW_VIEWS)->addAction(cmd); + } + + op.visibleByUser = op.visibleByDefault; + if (theMainWindow->d->m_persistentChangedDocks.contains(op.name())) { + op.visibleByUser = !op.visibleByUser; + qCDebug(perspectivesLog) << "*** NON-DEFAULT USER: " << op.visibleByUser; + } else { + qCDebug(perspectivesLog) << "DEFAULT USER"; + } + d->m_dockOperations.append(op); } +void Perspective::destroy() +{ + theMainWindow->d->destroyPerspective(this); +} + +void Perspective::rampDownAsCurrent() +{ + QTC_ASSERT(this == theMainWindow->d->m_currentPerspective, return); + d->saveLayout(); + d->depopulatePerspective(); + theMainWindow->d->setCurrentPerspective(nullptr); + + Debugger::Internal::EngineManager::updatePerspectives(); +} + +void Perspective::rampUpAsCurrent() +{ + if (d->m_aboutToActivateCallback) + d->m_aboutToActivateCallback(); + + QTC_ASSERT(theMainWindow->d->m_currentPerspective == nullptr, return); + theMainWindow->d->setCurrentPerspective(this); + QTC_ASSERT(theMainWindow->d->m_currentPerspective == this, return); + + d->populatePerspective(); + + theMainWindow->d->updatePerspectiveChooserWidth(); + + d->saveAsLastUsedPerspective(); + + Debugger::Internal::EngineManager::updatePerspectives(); +} + void Perspective::select() { Debugger::Internal::EngineManager::activateDebugMode(); - if (Perspective::currentPerspective() == this) + + if (theMainWindow->d->m_currentPerspective == this) return; - theMainWindow->d->selectPerspective(this); - if (Perspective *parent = Perspective::findPerspective(d->m_parentPerspectiveId)) - parent->d->m_lastActiveSubPerspectiveId = d->m_id; - else - d->m_lastActiveSubPerspectiveId.clear(); - const QString &lastKey = d->m_parentPerspectiveId.isEmpty() ? d->m_id : d->m_parentPerspectiveId; - ICore::settings()->setValue(LAST_PERSPECTIVE_KEY, lastKey); + if (theMainWindow->d->m_currentPerspective) + theMainWindow->d->m_currentPerspective->rampDownAsCurrent(); + QTC_CHECK(theMainWindow->d->m_currentPerspective == nullptr); + + rampUpAsCurrent(); } void PerspectivePrivate::restoreLayout() { - if (m_nonPersistenSettings.isEmpty()) { - //qDebug() << "PERSPECTIVE" << m_id << "RESTORE PERSISTENT FROM " << settingsId(); - QSettings *settings = ICore::settings(); - settings->beginGroup(settingsId()); - theMainWindow->restoreSettings(settings); - settings->endGroup(); - m_nonPersistenSettings = theMainWindow->saveSettings(); - } else { - //qDebug() << "PERSPECTIVE" << m_id << "RESTORE FROM LOCAL TEMP"; - theMainWindow->restoreSettings(m_nonPersistenSettings); + qCDebug(perspectivesLog) << "PERSPECTIVE" << m_id << "RESTORING LAYOUT FROM " << settingsId(); + for (DockOperation &op : m_dockOperations) { + if (op.operationType != Perspective::Raise) { + QTC_ASSERT(op.dock, continue); + const bool active = op.visibleByUser; + op.dock->toggleViewAction()->setChecked(active); + op.dock->setVisible(active); + qCDebug(perspectivesLog) << "RESTORE DOCK " << op.name() << "ACTIVE: " << active + << (active == op.visibleByDefault ? "DEFAULT USER" : "*** NON-DEFAULT USER"); + } } } void PerspectivePrivate::saveLayout() { - //qDebug() << "PERSPECTIVE" << m_id << "SAVE LOCAL TEMP"; - m_nonPersistenSettings = theMainWindow->saveSettings(); - - if (m_shouldPersistChecker()) { - //qDebug() << "PERSPECTIVE" << m_id << "SAVE PERSISTENT TO " << settingsId(); - QSettings *settings = ICore::settings(); - settings->beginGroup(settingsId()); - theMainWindow->saveSettings(settings); - settings->endGroup(); - } else { - //qDebug() << "PERSPECTIVE" << m_id << "NOT PERSISTENT"; + qCDebug(perspectivesLog) << "PERSPECTIVE" << m_id << "SAVE LAYOUT TO " << settingsId(); + for (DockOperation &op : m_dockOperations) { + if (op.operationType != Perspective::Raise) { + QTC_ASSERT(op.dock, continue); + QTC_ASSERT(op.widget, continue); + const bool active = op.dock->toggleViewAction()->isChecked(); + op.visibleByUser = active; + if (active == op.visibleByDefault) + theMainWindow->d->m_persistentChangedDocks.remove(op.name()); + else + theMainWindow->d->m_persistentChangedDocks.insert(op.name()); + qCDebug(perspectivesLog) << "SAVE DOCK " << op.name() << "ACTIVE: " << active + << (active == op.visibleByDefault ? "DEFAULT USER" : "*** NON-DEFAULT USER"); + } } } QString PerspectivePrivate::settingsId() const { - return m_parentPerspectiveId.isEmpty() ? m_id : (m_parentPerspectiveId + '.' + m_subPerspectiveType); + return m_settingsId.isEmpty() ? m_id : m_settingsId; } // ToolbarAction diff --git a/src/plugins/debugger/debuggermainwindow.h b/src/plugins/debugger/debuggermainwindow.h index 98ff0a37d1..116eb73717 100644 --- a/src/plugins/debugger/debuggermainwindow.h +++ b/src/plugins/debugger/debuggermainwindow.h @@ -59,12 +59,12 @@ public: QPointer<QToolButton> m_toolButton; }; -class DEBUGGER_EXPORT Perspective +class DEBUGGER_EXPORT Perspective : public QObject { public: Perspective(const QString &id, const QString &name, const QString &parentPerspectiveId = QString(), - const QString &subPerspectiveType = QString()); + const QString &settingId = QString()); ~Perspective(); enum OperationType { SplitVertical, SplitHorizontal, AddToTab, Raise }; @@ -92,26 +92,26 @@ public: using Callback = std::function<void()>; void setAboutToActivateCallback(const Callback &cb); - void aboutToActivate() const; void setEnabled(bool enabled); void select(); + void destroy(); - static Perspective *currentPerspective(); static Perspective *findPerspective(const QString &perspectiveId); - Core::Context context() const; - - void showToolBar(); - void hideToolBar(); + bool isCurrent() const; private: + void rampDownAsCurrent(); + void rampUpAsCurrent(); + Perspective(const Perspective &) = delete; void operator=(const Perspective &) = delete; friend class DebuggerMainWindow; friend class DebuggerMainWindowPrivate; + friend class PerspectivePrivate; class PerspectivePrivate *d = nullptr; }; @@ -132,12 +132,20 @@ public: static QWidget *centralWidgetStack(); void addSubPerspectiveSwitcher(QWidget *widget); + static void savePersistentSettings(); + static void restorePersistentSettings(); + + static Perspective *currentPerspective(); + private: DebuggerMainWindow(); ~DebuggerMainWindow() override; + void contextMenuEvent(QContextMenuEvent *ev) override; + friend class Perspective; friend class PerspectivePrivate; + friend class DockOperation; class DebuggerMainWindowPrivate *d = nullptr; }; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index a18f0a652c..51ef9293c6 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1052,7 +1052,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, m_breakpointManagerView->setSpanColumn(BreakpointFunctionColumn); m_breakpointManagerWindow = addSearch(m_breakpointManagerView); m_breakpointManagerWindow->setWindowTitle(tr("Breakpoint Preset")); - m_breakpointManagerWindow->setObjectName(DOCKWIDGET_BREAKPOINTMANAGER); + m_breakpointManagerWindow->setObjectName("Debugger.Docks.BreakpointManager"); addLabel(m_breakpointManagerWindow, m_breakpointManagerWindow->windowTitle()); @@ -1064,7 +1064,7 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, m_engineManagerView->setModel(m_engineManager.model()); m_engineManagerWindow = addSearch(m_engineManagerView); m_engineManagerWindow->setWindowTitle(tr("Debugger Perspectives")); - m_engineManagerWindow->setObjectName(DOCKWIDGET_ENGINEMANAGER); + m_engineManagerWindow->setObjectName("Debugger.Docks.Snapshots"); addLabel(m_engineManagerWindow, m_engineManagerWindow->windowTitle()); // Logging @@ -1366,7 +1366,8 @@ bool DebuggerPluginPrivate::initialize(const QStringList &arguments, DebuggerMainWindow::leaveDebugMode(); }); - connect(ModeManager::instance(), &ModeManager::currentModeChanged, this, [](Id mode) { + connect(ModeManager::instance(), &ModeManager::currentModeChanged, [](Id mode, Id oldMode) { + QTC_ASSERT(mode != oldMode, return); if (mode == MODE_DEBUG) { DebuggerMainWindow::enterDebugMode(); if (IEditor *editor = EditorManager::currentEditor()) @@ -1531,7 +1532,7 @@ void DebuggerPluginPrivate::updatePresetState() } else { // The startup phase should be over once we are here. // But treat it as 'undisturbable if we are here by accident. - QTC_CHECK(state != DebuggerNotReady); + //QTC_CHECK(state != DebuggerNotReady); // Everything else is "undisturbable". m_startAction.setEnabled(false); m_debugWithoutDeployAction.setEnabled(false); @@ -1569,7 +1570,7 @@ void DebuggerPluginPrivate::onStartupProjectChanged(Project *project) } for (DebuggerEngine *engine : EngineManager::engines()) { // Run controls might be deleted during exit. - engine->updateState(false); + engine->updateState(); } updatePresetState(); @@ -2022,11 +2023,9 @@ void DebuggerPluginPrivate::aboutToShutdown() m_shutdownTimer.setInterval(0); m_shutdownTimer.setSingleShot(true); connect(&m_shutdownTimer, &QTimer::timeout, this, &DebuggerPluginPrivate::doShutdown); - for (DebuggerEngine *engine : m_engineManager.engines()) { - if (engine && engine->state() != Debugger::DebuggerNotReady) { - engine->abortDebugger(); - m_shutdownTimer.setInterval(3000); - } + if (EngineManager::shutDown()) { + // If any engine is aborting we give them extra three seconds. + m_shutdownTimer.setInterval(3000); } m_shutdownTimer.start(); } diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 19b4011338..27460f2222 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -730,8 +730,6 @@ void DebuggerRunTool::stop() void DebuggerRunTool::handleEngineStarted(DebuggerEngine *engine) { - EngineManager::activateEngine(engine); - // Correct: // if (--d->engineStartsNeeded == 0) { // EngineManager::activateDebugMode(); diff --git a/src/plugins/debugger/enginemanager.cpp b/src/plugins/debugger/enginemanager.cpp index 3d659b589f..b03ac37f26 100644 --- a/src/plugins/debugger/enginemanager.cpp +++ b/src/plugins/debugger/enginemanager.cpp @@ -155,16 +155,18 @@ public: } EngineItem *findEngineItem(DebuggerEngine *engine); - void activateEngine(DebuggerEngine *engine); void activateEngineItem(EngineItem *engineItem); void activateEngineByIndex(int index); void selectUiForCurrentEngine(); void updateEngineChooserVisibility(); + void updatePerspectives(); TreeModel<TypedTreeItem<EngineItem>, EngineItem> m_engineModel; - QPointer<EngineItem> m_currentItem; + QPointer<EngineItem> m_currentItem; // The primary information is DebuggerMainWindow::d->m_currentPerspective Core::Id m_previousMode; QPointer<QComboBox> m_engineChooser; + bool m_shuttingDown = false; + Context m_currentAdditionalContext; }; //////////////////////////////////////////////////////////////////////// @@ -192,6 +194,11 @@ QWidget *EngineManager::engineChooser() return d->m_engineChooser; } +void EngineManager::updatePerspectives() +{ + d->updatePerspectives(); +} + EngineManager::~EngineManager() { theEngineManager = nullptr; @@ -208,11 +215,6 @@ QAbstractItemModel *EngineManager::model() return &d->m_engineModel; } -void EngineManager::activateEngine(DebuggerEngine *engine) -{ - d->activateEngine(engine); -} - QVariant EngineItem::data(int column, int role) const { if (m_engine) { @@ -273,7 +275,7 @@ bool EngineItem::setData(int row, const QVariant &value, int role) if (role == BaseTreeView::ItemActivatedRole) { EngineItem *engineItem = d->findEngineItem(m_engine); - d->activateEngineItem(engineItem); + d->activateEngineByIndex(engineItem->indexInParent()); return true; } @@ -316,21 +318,27 @@ bool EngineItem::setData(int row, const QVariant &value, int role) void EngineManagerPrivate::activateEngineByIndex(int index) { - activateEngineItem(m_engineModel.rootItem()->childAt(index)); + // The actual activation is triggered indirectly via the perspective change. + Perspective *perspective = nullptr; + if (index == 0) { + perspective = Perspective::findPerspective(Debugger::Constants::PRESET_PERSPECTIVE_ID); + } else { + EngineItem *engineItem = m_engineModel.rootItem()->childAt(index); + QTC_ASSERT(engineItem, return); + QTC_ASSERT(engineItem->m_engine, return); + perspective = engineItem->m_engine->perspective(); + } + + QTC_ASSERT(perspective, return); + perspective->select(); } void EngineManagerPrivate::activateEngineItem(EngineItem *engineItem) { - Context previousContext; - if (m_currentItem) { - if (DebuggerEngine *engine = m_currentItem->m_engine) { - previousContext.add(engine->languageContext()); - previousContext.add(engine->debuggerContext()); - } else { - previousContext.add(Context(Constants::C_DEBUGGER_NOTRUNNING)); - } - } + if (m_currentItem == engineItem) + return; + QTC_ASSERT(engineItem, return); m_currentItem = engineItem; Context newContext; @@ -343,7 +351,13 @@ void EngineManagerPrivate::activateEngineItem(EngineItem *engineItem) } } - ICore::updateAdditionalContexts(previousContext, newContext); + ICore::updateAdditionalContexts(m_currentAdditionalContext, newContext); + m_currentAdditionalContext = newContext; + + // In case this was triggered externally by some Perspective::select() call. + const int idx = engineItem->indexInParent(); + m_engineChooser->setCurrentIndex(idx); + selectUiForCurrentEngine(); } @@ -352,12 +366,7 @@ void EngineManagerPrivate::selectUiForCurrentEngine() if (ModeManager::currentModeId() != Constants::MODE_DEBUG) return; - Perspective *perspective = nullptr; int row = 0; - - if (m_currentItem && m_currentItem->m_engine) - perspective = m_currentItem->m_engine->perspective(); - if (m_currentItem) row = m_engineModel.rootItem()->indexOf(m_currentItem); @@ -371,12 +380,6 @@ void EngineManagerPrivate::selectUiForCurrentEngine() QStyle::CT_ComboBox, &option, sz).width(); m_engineChooser->setFixedWidth(width); - if (!perspective) - perspective = Perspective::findPerspective(Debugger::Constants::PRESET_PERSPECTIVE_ID); - - QTC_ASSERT(perspective, return); - perspective->select(); - m_engineModel.rootItem()->forFirstLevelChildren([this](EngineItem *engineItem) { if (engineItem && engineItem->m_engine) engineItem->m_engine->updateUi(engineItem == m_currentItem); @@ -392,12 +395,6 @@ EngineItem *EngineManagerPrivate::findEngineItem(DebuggerEngine *engine) }); } -void EngineManagerPrivate::activateEngine(DebuggerEngine *engine) -{ - EngineItem *engineItem = findEngineItem(engine); - activateEngineItem(engineItem); -} - void EngineManagerPrivate::updateEngineChooserVisibility() { // Show it if there's more than one option (i.e. not the preset engine only) @@ -407,12 +404,48 @@ void EngineManagerPrivate::updateEngineChooserVisibility() } } -void EngineManager::registerEngine(DebuggerEngine *engine) +void EngineManagerPrivate::updatePerspectives() +{ + d->updateEngineChooserVisibility(); + + Perspective *current = DebuggerMainWindow::currentPerspective(); + if (!current) { + return; + } + + m_engineModel.rootItem()->forFirstLevelChildren([this, current](EngineItem *engineItem) { + if (engineItem == m_currentItem) + return; + + bool shouldBeActive = false; + if (engineItem->m_engine) { + // Normal engine. + shouldBeActive = engineItem->m_engine->perspective()->isCurrent(); + } else { + // Preset. + shouldBeActive = current->id() == Debugger::Constants::PRESET_PERSPECTIVE_ID; + } + + if (shouldBeActive && engineItem != m_currentItem) + activateEngineItem(engineItem); + }); +} + +QString EngineManager::registerEngine(DebuggerEngine *engine) { auto engineItem = new EngineItem; engineItem->m_engine = engine; d->m_engineModel.rootItem()->appendChild(engineItem); d->updateEngineChooserVisibility(); + return QString::number(d->m_engineModel.rootItem()->childCount()); +} + +void EngineManager::unregisterEngine(DebuggerEngine *engine) +{ + EngineItem *engineItem = d->findEngineItem(engine); + QTC_ASSERT(engineItem, return); + d->m_engineModel.destroyItem(engineItem); + d->updateEngineChooserVisibility(); } void EngineManager::activateDebugMode() @@ -435,33 +468,6 @@ void EngineManager::deactivateDebugMode() } } -bool EngineManager::isLastOf(const QString &type) -{ - int count = 0; - d->m_engineModel.rootItem()->forFirstLevelChildren([&](EngineItem *engineItem) { - if (engineItem && engineItem->m_engine) - count += (engineItem->m_engine->debuggerName() == type); - }); - return count == 1; -} - -void EngineManager::unregisterEngine(DebuggerEngine *engine) -{ - if (ModeManager::currentModeId() == Constants::MODE_DEBUG) { - if (Perspective *parent = Perspective::findPerspective(Constants::PRESET_PERSPECTIVE_ID)) - parent->select(); - } - - d->activateEngineItem(d->m_engineModel.rootItem()->childAt(0)); // Preset. - - // Could be that the run controls died before it was appended. - if (auto engineItem = d->findEngineItem(engine)) - d->m_engineModel.destroyItem(engineItem); - - d->updateEngineChooserVisibility(); - emit theEngineManager->currentEngineChanged(); -} - QList<QPointer<DebuggerEngine>> EngineManager::engines() { QList<QPointer<DebuggerEngine>> result; @@ -477,5 +483,18 @@ QPointer<DebuggerEngine> EngineManager::currentEngine() return d->m_currentItem ? d->m_currentItem->m_engine : nullptr; } +bool EngineManager::shutDown() +{ + d->m_shuttingDown = true; + bool anyEngineAborting = false; + for (DebuggerEngine *engine : EngineManager::engines()) { + if (engine && engine->state() != Debugger::DebuggerNotReady) { + engine->abortDebugger(); + anyEngineAborting = true; + } + } + return anyEngineAborting; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/enginemanager.h b/src/plugins/debugger/enginemanager.h index a1ee76c60b..08549ba711 100644 --- a/src/plugins/debugger/enginemanager.h +++ b/src/plugins/debugger/enginemanager.h @@ -45,17 +45,19 @@ public: static EngineManager *instance(); static QAbstractItemModel *model(); - static void registerEngine(DebuggerEngine *engine); + static QString registerEngine(DebuggerEngine *engine); static void unregisterEngine(DebuggerEngine *engine); - static void activateEngine(DebuggerEngine *engine); + static void activateDebugMode(); static void deactivateDebugMode(); - static bool isLastOf(const QString &type); static QList<QPointer<DebuggerEngine> > engines(); static QPointer<DebuggerEngine> currentEngine(); static QWidget *engineChooser(); + static void updatePerspectives(); + + static bool shutDown(); // Return true if some engine is being forced to shut down. signals: void engineStateChanged(DebuggerEngine *engine); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ad153f9e76..aa25b65297 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2952,7 +2952,7 @@ void GdbEngine::handleThreadInfo(const DebuggerResponse &response) if (response.resultClass == ResultDone) { ThreadsHandler *handler = threadsHandler(); handler->setThreads(response.data); - updateState(false); // Adjust Threads combobox. + updateState(); // Adjust Threads combobox. if (boolSetting(ShowThreadNames)) { runCommand({"threadnames " + action(MaximalStackDepth)->value().toString(), Discardable, CB(handleThreadNames)}); @@ -2992,7 +2992,7 @@ void GdbEngine::handleThreadNames(const DebuggerResponse &response) thread.name = decodeData(name["value"].data(), name["valueencoded"].data()); handler->updateThread(thread); } - updateState(false); + updateState(); } } diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 05bfcd96db..9cb88b077e 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -171,7 +171,7 @@ public: bool ModulesModel::contextMenuEvent(const ItemViewEvent &ev) { - ModuleItem *item = itemForIndexAtLevel<1>(ev.index()); + ModuleItem *item = itemForIndexAtLevel<1>(ev.sourceModelIndex()); const bool enabled = engine->debuggerActionsEnabled(); const bool canReload = engine->hasCapability(ReloadModuleCapability); diff --git a/src/plugins/debugger/registerhandler.cpp b/src/plugins/debugger/registerhandler.cpp index 65477ac83f..7614bc413c 100644 --- a/src/plugins/debugger/registerhandler.cpp +++ b/src/plugins/debugger/registerhandler.cpp @@ -679,8 +679,8 @@ bool RegisterHandler::contextMenuEvent(const ItemViewEvent &ev) const DebuggerState state = m_engine->state(); const bool actionsEnabled = m_engine->debuggerActionsEnabled(); - RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.index()); - RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.index()); + RegisterItem *registerItem = itemForIndexAtLevel<1>(ev.sourceModelIndex()); + RegisterSubItem *registerSubItem = itemForIndexAtLevel<2>(ev.sourceModelIndex()); const quint64 address = registerItem ? registerItem->addressValue() : 0; const QString registerName = registerItem ? registerItem->m_reg.name : QString(); diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index 653ec7ec6c..4d134792bd 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -367,7 +367,7 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) { auto menu = new QMenu; - const int row = ev.index().row(); + const int row = ev.sourceModelIndex().row(); StackFrame frame; if (row >= 0 && row < stackSize()) frame = frameAt(row); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 6ec3a26d58..8087e77638 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1638,7 +1638,7 @@ void WatchModel::inputNewExpression() bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) { - WatchItem *item = itemForIndex(ev.index()); + WatchItem *item = itemForIndex(ev.sourceModelIndex()); const QString exp = item ? item->expression() : QString(); const QString name = item ? item->name : QString(); diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 2a2d706db5..b621031131 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -756,10 +756,16 @@ void QbsProject::updateDocuments(const QSet<QString> &files) } } QSet<IDocument *> toAdd; - foreach (const QString &f, filesToAdd) - toAdd.insert(new ProjectDocument(Constants::MIME_TYPE, FileName::fromString(f), - [this]() { delayParsing(); })); - + const FileName buildDir = FileName::fromString(m_projectData.buildDirectory()); + for (const QString &f : qAsConst(filesToAdd)) { + // A changed qbs file (project, module etc) should trigger a re-parse, but not if + // the file was generated by qbs itself, in which case that might cause an infinite loop. + const FileName fp = FileName::fromString(f); + static const ProjectDocument::ProjectCallback noOpCallback = []{}; + const ProjectDocument::ProjectCallback reparseCallback = [this]() { delayParsing(); }; + toAdd.insert(new ProjectDocument(Constants::MIME_TYPE, fp, fp.isChildOf(buildDir) + ? noOpCallback : reparseCallback)); + } m_qbsDocuments.unite(toAdd); } diff --git a/src/plugins/qmakeprojectmanager/qmakestep.cpp b/src/plugins/qmakeprojectmanager/qmakestep.cpp index 5455c1e2df..b7230c9b04 100644 --- a/src/plugins/qmakeprojectmanager/qmakestep.cpp +++ b/src/plugins/qmakeprojectmanager/qmakestep.cpp @@ -166,6 +166,7 @@ QMakeStepConfig QMakeStep::deducedArguments() const bool QMakeStep::init() { + m_wasSuccess = true; QmakeBuildConfiguration *qmakeBc = qmakeBuildConfiguration(); const BaseQtVersion *qtVersion = QtKitAspect::qtVersion(target()->kit()); diff --git a/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp b/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp index ff01ccd97d..a1ca4a42dc 100644 --- a/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp +++ b/src/plugins/qmldesigner/components/componentcore/qmldesignericonprovider.cpp @@ -69,7 +69,8 @@ QPixmap QmlDesignerIconProvider::getPixmap(const QString &id) else if (id == "plus") result = Utils::Icons::PLUS_TOOLBAR.pixmap(); else if (id == "expression") - result = Icon(iconPath() + "expression.png").pixmap(); + result = Icon({ + { iconPath() + QLatin1String("expression.png"), Theme::QmlDesigner_HighlightColor}}).pixmap(); else if (id == "placeholder") result = Icon(iconPath() + "placeholder.png").pixmap(); else if (id == "submenu") diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp index a79006423c..34863477f0 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp @@ -28,6 +28,8 @@ #include <qmlanchors.h> #include <nodeabstractproperty.h> #include <variantproperty.h> +#include <utils/qtcassert.h> + #include <QtQml> #include <QDebug> @@ -108,13 +110,18 @@ void QmlAnchorBindingProxy::invalidate(const QmlItemNode &fxItemNode) m_ignoreQml = true; + auto parentModelNode = [](const QmlItemNode &node) { + QTC_ASSERT(node.modelNode().hasParentProperty(), return ModelNode()); + return node.modelNode().parentProperty().parentModelNode(); + }; + m_verticalTarget = m_horizontalTarget = m_topTarget = m_bottomTarget = m_leftTarget = m_rightTarget = - m_qmlItemNode.modelNode().parentProperty().parentModelNode(); + parentModelNode(m_qmlItemNode); setupAnchorTargets(); diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp index a2bd639949..97ff27dfd5 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp @@ -172,7 +172,8 @@ void TextEditorView::nodeIdChanged(const ModelNode& /*node*/, const QString &/*n void TextEditorView::selectedNodesChanged(const QList<ModelNode> &/*selectedNodeList*/, const QList<ModelNode> &/*lastSelectedNodeList*/) { - m_widget->jumpTextCursorToSelectedModelNode(); + if (!m_errorState) + m_widget->jumpTextCursorToSelectedModelNode(); } void TextEditorView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList<ModelNode> &/*nodeList*/, const QList<QVariant> &/*data*/) @@ -187,9 +188,11 @@ void TextEditorView::documentMessagesChanged(const QList<DocumentMessage> &error { if (errors.isEmpty()) { m_widget->clearStatusBar(); + m_errorState = false; } else { const DocumentMessage &error = errors.constFirst(); m_widget->setStatusText(QString("%1 (Line: %2)").arg(error.description()).arg(error.line())); + m_errorState = true; } } diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.h b/src/plugins/qmldesigner/components/texteditor/texteditorview.h index 170edaaa5b..345af0052b 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.h @@ -103,6 +103,7 @@ public: private: QPointer<TextEditorWidget> m_widget; Internal::TextEditorContext *m_textEditorContext; + bool m_errorState = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index e7c1903ca4..d47505d70e 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -108,15 +108,20 @@ void TextEditorWidget::updateSelectionByCursorPosition() const int cursorPosition = m_textEditor->editorWidget()->textCursor().position(); RewriterView *rewriterView = m_textEditorView->model()->rewriterView(); + m_blockRoundTrip = true; if (rewriterView) { ModelNode modelNode = rewriterView->nodeAtTextCursorPosition(cursorPosition); if (modelNode.isValid() && !m_textEditorView->isSelectedModelNode(modelNode)) m_textEditorView->setSelectedModelNode(modelNode); } + m_blockRoundTrip = false; } void TextEditorWidget::jumpTextCursorToSelectedModelNode() { + if (m_blockRoundTrip) + return; + ModelNode selectedNode; if (hasFocus()) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h index ef6f6cd110..8f0ba40e47 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h @@ -72,6 +72,7 @@ private: QTimer m_updateSelectionTimer; TextEditorStatusBar *m_statusBar; bool m_blockCursorSelectionSynchronisation = false; + bool m_blockRoundTrip = false; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png Binary files differindex a75ee209d5..df4b60327e 100644 --- a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png +++ b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon.png diff --git a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png Binary files differindex c70f845e70..ffef790cdc 100644 --- a/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png +++ b/src/plugins/qmldesigner/componentsplugin/images/column-layouts-icon@2x.png diff --git a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png Binary files differindex df4b60327e..a75ee209d5 100644 --- a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png +++ b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon.png diff --git a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png Binary files differindex ffef790cdc..c70f845e70 100644 --- a/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png +++ b/src/plugins/qmldesigner/componentsplugin/images/row-layouts-icon@2x.png diff --git a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png Binary files differindex c70f845e70..68db302e96 100644 --- a/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png +++ b/src/plugins/qmldesigner/qtquickplugin/images/column-positioner-icon@2x.png diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp index 100cf04020..e07c819275 100644 --- a/src/plugins/remotelinux/genericdirectuploadservice.cpp +++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp @@ -191,7 +191,7 @@ void GenericDirectUploadService::stopDeployment() QList<DeployableFile> GenericDirectUploadService::collectFilesToUpload( const DeployableFile &deployable) const { - QList<DeployableFile> collected({deployable}); + QList<DeployableFile> collected; QFileInfo fileInfo = deployable.localFilePath().toFileInfo(); if (fileInfo.isDir()) { const QStringList files = QDir(deployable.localFilePath().toString()) @@ -203,6 +203,8 @@ QList<DeployableFile> GenericDirectUploadService::collectFilesToUpload( + fileInfo.fileName(); collected.append(collectFilesToUpload(DeployableFile(localFilePath, remoteDir))); } + } else { + collected << deployable; } return collected; } diff --git a/src/shared/qbs b/src/shared/qbs -Subproject e0ada9c8aeef0a1adc2328c622c1a7aba6a93af +Subproject e0c6f88fe51186eb6fc697ba74f60136bf2106e diff --git a/tests/auto/qml/qmldesigner/data/fx/attributes.qml b/tests/auto/qml/qmldesigner/data/fx/attributes.qml index f56ffd2b02..659a258105 100644 --- a/tests/auto/qml/qmldesigner/data/fx/attributes.qml +++ b/tests/auto/qml/qmldesigner/data/fx/attributes.qml @@ -23,7 +23,7 @@ ** ****************************************************************************/ -import Qt 4.7 +import QtQuick 2.0 Item { id: id; diff --git a/tests/auto/qml/qmldesigner/data/fx/empty.qml b/tests/auto/qml/qmldesigner/data/fx/empty.qml index 4b9e826d36..62221ea919 100644 --- a/tests/auto/qml/qmldesigner/data/fx/empty.qml +++ b/tests/auto/qml/qmldesigner/data/fx/empty.qml @@ -23,7 +23,7 @@ ** ****************************************************************************/ -import Qt 4.7 +import QtQuick 2.0 Item { } diff --git a/tests/auto/qml/qmldesigner/data/fx/helloworld.qml b/tests/auto/qml/qmldesigner/data/fx/helloworld.qml index 81980f966b..65b232de9b 100644 --- a/tests/auto/qml/qmldesigner/data/fx/helloworld.qml +++ b/tests/auto/qml/qmldesigner/data/fx/helloworld.qml @@ -23,7 +23,7 @@ ** ****************************************************************************/ -import Qt 4.7 +import QtQuick 2.0 Rectangle { width: 200 diff --git a/tests/auto/qml/qmldesigner/data/fx/properties.qml b/tests/auto/qml/qmldesigner/data/fx/properties.qml index 2a38819230..ffeb68a0ea 100644 --- a/tests/auto/qml/qmldesigner/data/fx/properties.qml +++ b/tests/auto/qml/qmldesigner/data/fx/properties.qml @@ -23,7 +23,7 @@ ** ****************************************************************************/ -import Qt 4.7 +import QtQuick 2.0 Item { property bool pushed diff --git a/tests/auto/qml/qmldesigner/data/fx/states.qml b/tests/auto/qml/qmldesigner/data/fx/states.qml index 91e7348d24..b0dd3f3d38 100644 --- a/tests/auto/qml/qmldesigner/data/fx/states.qml +++ b/tests/auto/qml/qmldesigner/data/fx/states.qml @@ -23,7 +23,7 @@ ** ****************************************************************************/ -import Qt 4.7 +import QtQuick 2.0 Rectangle { id: rect 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 2c71b21c83..194d90aa9c 100644 --- a/tests/system/suite_general/tst_create_proj_wizard/test.py +++ b/tests/system/suite_general/tst_create_proj_wizard/test.py @@ -125,9 +125,7 @@ def handleBuildSystemVerifyKits(category, template, kits, displayedPlatforms, test.log("Using build system '%s'" % buildSystem) selectFromCombo(combo, buildSystem) clickButton(waitForObject(":Next_QPushButton")) - if template == "Qt Quick Application - Scroll": - clickButton(waitForObject(":Next_QPushButton")) - elif specialHandlingFunc: + if specialHandlingFunc: specialHandlingFunc(displayedPlatforms, *args) verifyKitCheckboxes(kits, displayedPlatforms) safeClickButton("Cancel") diff --git a/tests/system/suite_general/tst_opencreator_qbs/testdata/projecttree_creator.tsv b/tests/system/suite_general/tst_opencreator_qbs/testdata/projecttree_creator.tsv index 1ac1dac7fd..6e594bcb6c 100644 --- a/tests/system/suite_general/tst_opencreator_qbs/testdata/projecttree_creator.tsv +++ b/tests/system/suite_general/tst_opencreator_qbs/testdata/projecttree_creator.tsv @@ -12646,8 +12646,6 @@ "bundledqt.qbs:4" "3" "QPA plugin" "3" "bundledqt.qbs:65" "4" -"Qt libraries" "3" -"bundledqt.qbs:30" "4" "qt.conf" "3" "bundledqt.qbs:22" "4" "qt.conf" "4" diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index ad2c8bf3e3..44217b9876 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -404,6 +404,39 @@ TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) " && b)")); } +TEST_F(ClangFormat, IndentInsideIf) +{ + insertLines({"if (a && b", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a && b", + " )")); +} + +TEST_F(ClangFormat, IndentInsideIf2) +{ + insertLines({"if (a && b &&", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a && b &&", + " )")); +} + +TEST_F(ClangFormat, IndentInsideIf3) +{ + insertLines({"if (a || b", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a || b", + " )")); +} + TEST_F(ClangFormat, EmptyLineInInitializerList) { insertLines({"Bar foo{a,", @@ -441,6 +474,31 @@ TEST_F(ClangFormat, DoNotIndentClosingBraceAfterSemicolon) "}")); } +TEST_F(ClangFormat, IndentAfterIf) +{ + insertLines({"if (a)", + ""}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a)", + " ")); +} + +TEST_F(ClangFormat, IndentAfterElse) +{ + insertLines({"if (a)", + " foo();", + "else", + ""}); + indenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a)", + " foo();", + "else", + " ")); +} + TEST_F(ClangFormat, SameIndentAfterSecondNewLineAfterIf) { insertLines({"if (a)", @@ -504,6 +562,102 @@ TEST_F(ClangFormat, SameIndentsOnNewLinesAfterComments) "")); } +TEST_F(ClangFormat, IndentAfterEmptyLineAfterAngledIncludeDirective) +{ + insertLines({"#include <string>", + "", + "using namespace std;"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("#include <string>", + "", + "using namespace std;")); +} + +TEST_F(ClangFormat, IndentAfterEmptyLineAfterQuotedIncludeDirective) +{ + insertLines({"#include \"foo.h\"", + "", + "using namespace std;"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("#include \"foo.h\"", + "", + "using namespace std;")); +} + +TEST_F(ClangFormat, IndentAfterLineComment) +{ + insertLines({"int foo()", + "{", + " // Comment", + " ", + " if (", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(4), '(', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("int foo()", + "{", + " // Comment", + " ", + " if (", + "}")); +} + +TEST_F(ClangFormat, IndentAfterBlockComment) +{ + insertLines({"int foo()", + "{", + " bar(); /* Comment */", + " ", + " if (", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(4), '(', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("int foo()", + "{", + " bar(); /* Comment */", + " ", + " if (", + "}")); +} + +TEST_F(ClangFormat, IndentAfterIfdef) +{ + insertLines({"int foo()", + "{", + "#ifdef FOO", + "#endif", + " ", + " if (", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(5), '(', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("int foo()", + "{", + "#ifdef FOO", + "#endif", + " ", + " if (", + "}")); +} + +TEST_F(ClangFormat, IndentAfterEmptyLineInTheFileBeginning) +{ + insertLines({"", + "void foo()"}); + + indenter.indentBlock(doc.findBlockByNumber(1), ')', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("", + "void foo()")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", |