diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 94fbb314343..1e03f53e27a 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -9,7 +9,7 @@ env: CMAKE_VERSION: 3.21.1 NINJA_VERSION: 1.10.2 BUILD_TYPE: Release - CCACHE_VERSION: 4.4 + CCACHE_VERSION: 4.5 QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject jobs: diff --git a/doc/qtcreator/images/qtcreator-autotests-options-ctest.png b/doc/qtcreator/images/qtcreator-autotests-options-ctest.png new file mode 100644 index 00000000000..071cba4a718 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-autotests-options-ctest.png differ diff --git a/doc/qtcreator/images/qtcreator-parse-build-output.png b/doc/qtcreator/images/qtcreator-parse-build-output.png index 56d9724ea66..abd84fa04f1 100644 Binary files a/doc/qtcreator/images/qtcreator-parse-build-output.png and b/doc/qtcreator/images/qtcreator-parse-build-output.png differ diff --git a/doc/qtcreator/images/qtcreator-python-wizard-app-window.png b/doc/qtcreator/images/qtcreator-python-wizard-app-window.png index 30e5230645b..b66da25628c 100644 Binary files a/doc/qtcreator/images/qtcreator-python-wizard-app-window.png and b/doc/qtcreator/images/qtcreator-python-wizard-app-window.png differ diff --git a/doc/qtcreator/images/qtcreator-python-wizard-qml.png b/doc/qtcreator/images/qtcreator-python-wizard-qml.png index d8d3aeb929f..8050ea055a7 100644 Binary files a/doc/qtcreator/images/qtcreator-python-wizard-qml.png and b/doc/qtcreator/images/qtcreator-python-wizard-qml.png differ diff --git a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc index 22d6082d95e..85a7a2256c0 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc @@ -38,13 +38,20 @@ build system and uses it or even the build system as such to execute the respective tests. - \QC integrates the \l{Qt Test} framework, - \l{https://github.com/google/googletest}{Google C++ Testing Framework}, - \l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html} - {Boost.Test}, and \l{https://github.com/catchorg/Catch2} - {Catch2 test framework} for unit testing applications and libraries. + \QC integrates the following testing frameworks for unit testing + applications and libraries: + + \list + \li \l{https://www.boost.org/doc/libs/1_70_0/libs/test/doc/html/index.html} + {Boost.Test} + \li \l{https://github.com/catchorg/Catch2}{Catch2 test framework} + \li \l{https://github.com/google/googletest}{Google C++ Testing Framework} + \li \l{Qt Test} framework + \endlist + Additional build system based support is provided for \l{https://cmake.org/cmake/help/latest/manual/ctest.1.html}{CTest}. + You can use \QC to create, build, and run code based tests for your projects. @@ -332,16 +339,23 @@ in the file currently open in the code editor. \endlist - \note By default, \QC builds a project before deploying and running - it. + \endlist + + By default, \QC builds a project before deploying and running it. + To run all tests without building and deploying them again, select + \uicontrol {Run All Tests Without Deployment} in the context menu. + To run the selected tests without deployment, select + \uicontrol {Run Selected Tests Without Deployment}. + + The functions to run tests are also available in the context menu in the + \uicontrol Tests view and in \uicontrol Tools > \uicontrol Tests. + \note If you have enabled build system based and code based tests, you may run tests twice when using \uicontrol {Run All Tests} or \uicontrol {Run Selected Tests}. This happens if the tests can be found by the code based test frameworks and are registered as test with the build system. - \endlist - If a test takes more than a minute to execute, the default timeout might stop the test execution. To increase the timeout, select \uicontrol Tools > \uicontrol Options > \uicontrol {Testing} > \uicontrol General. @@ -369,7 +383,8 @@ The test cases are listed in alphabetic, case insensitive order. To list them in the order in which they are defined in the source code, - select \inlineimage leafsort.png (\uicontrol {Sort Naturally}). + select \inlineimage leafsort.png + (\uicontrol {Sort Naturally}). \section2 Running and Debugging Tests from Code Editor @@ -511,7 +526,7 @@ \li To specify settings for running Catch2 tests, select \uicontrol Tools > \uicontrol Options > \uicontrol {Testing} > \uicontrol {Catch Test}. - \image qtcreator-autotests-options-catch2.png + \image qtcreator-autotests-options-catch2.png "Catch Test options" \li Select the \uicontrol {Show success} check box to show succeeding expressions as well. By default Catch2 will print only fails. \li Select the \uicontrol {Break on failure while debugging} check box @@ -543,7 +558,7 @@ \li To specify settings for running CTest-based tests, select \uicontrol Tools > \uicontrol Options > \uicontrol {Testing} > \uicontrol {CTest}. - //! insert image here + \image qtcreator-autotests-options-ctest.png "CTest options" \li Select the \uicontrol {Output on failure} check box to show test specific output if a test fails. Contrary to the CTest default this is enabled by default. diff --git a/doc/qtcreator/src/overview/creator-only/creator-configuring.qdoc b/doc/qtcreator/src/overview/creator-only/creator-configuring.qdoc index 780c5165bdc..041e8554053 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-configuring.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-configuring.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -158,7 +158,7 @@ However, some configuration options are available and you can set them in \uicontrol Tools > \uicontrol Options > \uicontrol {Version Control} > - \uicontrol Common. + \uicontrol General. For more information about the supported functions, see \l{Using Version Control Systems}. diff --git a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc index 6b4576e0772..46f384599d2 100644 --- a/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc +++ b/doc/qtcreator/src/overview/creator-only/creator-overview.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -65,7 +65,7 @@ \li \b {\l{Designing User Interfaces}} To create intuitive, modern-looking, fluid user interfaces, you - can use \l{Qt Quick} and \QDS. + can use \l{Qt Quick} and \l{Qt Design Studio Manual}{\QDS}. If you need a traditional user interface that is clearly structured and enforces a platform look and feel, you can use the integrated \QD. For more information, see @@ -114,9 +114,10 @@ execution. In addition, the QML Profiler enables you to profile Qt Quick applications. - \QC is integrated to the \l{Qt Test}, Google C++ Testing, and - Boost.Test frameworks for unit testing applications and - libraries. You can use \QC to create, build, and run autotests. + \QC is integrated to the \l{Qt Test}, Boost.Test, Catch 2 test, + and Google C++ Testing frameworks for unit testing applications + and libraries. You can use \QC to create, build, and run + autotests. For more information, see \l{Testing}. \li \b {Publishing} diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc index b56754bf3e7..4b58e67f9db 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-build-run-tutorial.qdoc @@ -51,7 +51,8 @@ \l{http://doc.qt.io/QtForDeviceCreation/index.html}{Qt for Device Creation} documentation. - If you have \QDS installed, you can open \QDS examples from \QC in \QDS. + If you have \l{Qt Design Studio Manual}{\QDS} installed, you can open + \QDS examples from \QC in \QDS. \list 1 diff --git a/doc/qtcreator/src/python/creator-python-project.qdocinc b/doc/qtcreator/src/python/creator-python-project.qdocinc index 7543434e065..075d6b80962 100644 --- a/doc/qtcreator/src/python/creator-python-project.qdocinc +++ b/doc/qtcreator/src/python/creator-python-project.qdocinc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Creator documentation. @@ -29,8 +29,8 @@ \section2 Creating Widget-Based Qt for Python Applications \l {https://doc.qt.io/qtforpython/index.html}{Qt for Python} enables you - to use Qt 5 API in Python applications. You can use the PySide2 module to - gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI}, + to use Qt 6 API in Python applications. You can use the PySide6 modules + to gain access to individual Qt modules, such as \l {Qt Core}, \l {Qt GUI}, and \l {Qt Widgets}. The Qt for Python Application wizards generate a \c {.pyproject} file that @@ -46,7 +46,8 @@ The \uicontrol {Qt for Python - Window (UI file)} wizard enables you to create a Python project that contains the source file for a class. Specify - the class name, base class, and and source file for the class. + the PySide version, class name, base class, and and source file for the + class. \image qtcreator-python-wizard-app-window.png "Qt for Python wizard for creating a widget-based UI" @@ -55,21 +56,22 @@ Widgets module, and Qt UI tools: \badcode - import sys import os + from pathlib import Path + import sys - from PySide2.QtWidgets import QApplication, QWidget - from PySide2.QtCore import QFile - from PySide2.QtUiTools import QUiLoader + from PySide6.QtWidgets import QApplication, QWidget + from PySide6.QtCore import QFile + from PySide6.QtUiTools import QUiLoader \endcode The wizard also adds a main class with the specified name that inherits from the specified base class: \badcode - class MyWidget(QWidget): + class Widget(QWidget): def __init__(self): - super(MyWidget, self).__init__() + super(Widget, self).__init__() self.load_ui() ... \endcode @@ -79,12 +81,12 @@ \badcode def load_ui(self): - loader = QUiLoader() - path = os.path.join(os.path.dirname(__file__), "form.ui") - ui_file = QFile(path) - ui_file.open(QFile.ReadOnly) - loader.load(ui_file, self) - ui_file.close() + loader = QUiLoader() + path = os.fspath(Path(__file__).resolve().parent / "form.ui") + ui_file = QFile(path) + ui_file.open(QFile.ReadOnly) + loader.load(ui_file, self) + ui_file.close() \endcode Next, the wizard adds a main function, where it creates a @@ -100,8 +102,8 @@ Next, the wizard instantiates the \c MainWindow class and shows it: \badcode - window = MyWidget() - window.show() + widget = Widget() + widget.show() ... \endcode @@ -153,12 +155,12 @@ to QGuiApplication and QQmlApplicationEngine: \badcode - import sys import os + from pathlib import Path + import sys - from PySide2.QtGui import QGuiApplication - from PySide2.QtQml import QQmlApplicationEngine - + from PySide6.QtGui import QGuiApplication + from PySide6.QtQml import QQmlApplicationEngine \endcode The wizard also adds a main function, where it creates a QGuiApplication @@ -175,7 +177,7 @@ \badcode engine = QQmlApplicationEngine() - engine.load(os.path.join(os.path.dirname(__file__), "main.qml")) + engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml")) \endcode Finally, the wizard adds code that checks whether the file was successfully @@ -190,7 +192,7 @@ \endcode Open the .qml file in the \uicontrol Edit mode to design a Qt Quick UI, or - use \QDS. + use \l{Qt Design Studio Manual}{\QDS}. //! [python qml project wizards] */ diff --git a/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc b/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc index 261c3406136..ff0fef58ddd 100644 --- a/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-open-documents-view.qdoc @@ -35,13 +35,8 @@ \image qtcreator-open-documents-view.png "Open Documents view" You can use the context menu to apply some of the functions also available - in the \uicontrol File menu - \if defined(qtcreator) - . - \else - and in the \l {File System Context Menu} {File System} view to the file - that is selected in the view. - \endif + in the \uicontrol File menu and in the \l {File System Context Menu} + {File System} view to the file that is selected in the view. In addition, you can: diff --git a/doc/qtcreator/src/user-interface/creator-ui.qdoc b/doc/qtcreator/src/user-interface/creator-ui.qdoc index e2f31b0c787..bd23b7e1d00 100644 --- a/doc/qtcreator/src/user-interface/creator-ui.qdoc +++ b/doc/qtcreator/src/user-interface/creator-ui.qdoc @@ -293,6 +293,7 @@ style. \endif + You can use \QC in the following modes: \list @@ -487,8 +488,8 @@ The pane filters out irrelevant output from the build tools and presents the issues in an organized way. To further filter the output by type, select - \uicontrol {Filter Tree} - and then select a filter. + \inlineimage filtericon.png + (\uicontrol {Filter Tree}) and then select a filter. \image qtcreator-issues.png "Issues output pane" @@ -550,9 +551,10 @@ To specify settings for displaying application output, select \uicontrol Tools > \uicontrol Options > \uicontrol {Build & Run} > - \uicontrol {Application Output}, or click the \uicontrol {Open Settings Page} - button. You can select whether to open the \uicontrol{Application Output} pane - on output when running or debugging applications, to clear old output on a new run, + \uicontrol {Application Output}, or click the \inlineimage settings.png + (\uicontrol {Open Settings Page}) button. You can select whether to open + the \uicontrol{Application Output} pane on output when running or debugging + applications, to clear old output on a new run, to word-wrap output, and to limit output to the specified number of lines. \section1 Compile Output @@ -575,8 +577,8 @@ In the \uicontrol {Limit output to} field, you can specify the maximum amount of build output lines to display in the pane. - You can also reach the options page by clicking the \uicontrol {Open Settings Page} - button. + You can also reach the options page by clicking \inlineimage settings.png + (\uicontrol {Open Settings Page}). To copy the output from the pane to the clipboard, select \uicontrol {Select All} in the context menu, and then select diff --git a/doc/qtcreator/src/user-interface/creator-views.qdoc b/doc/qtcreator/src/user-interface/creator-views.qdoc index 65d41d0bbf1..ec9466d7c4b 100644 --- a/doc/qtcreator/src/user-interface/creator-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-views.qdoc @@ -97,12 +97,14 @@ \list \li To see a complete list of all bindings, select - \uicontrol {Filter Tree} > \uicontrol {Show All Bindings}. + \inlineimage filtericon.png + (\uicontrol {Filter Tree}) > \uicontrol {Show All Bindings}. \li To sort types or symbols alphabetically, select \inlineimage sort_alphabetically.png (\uicontrol {Sort Alphabetically}). \li To stop the synchronization with the type or symbol selected in the - editor, deselect \uicontrol {Synchronize with Editor}. + editor, deselect \inlineimage linkicon.png + (\uicontrol {Synchronize with Editor}). \endlist \section1 Viewing the Class Hierarchy @@ -144,5 +146,6 @@ \image qtcreator-include-hierarchy-view.png "Include Hierarchy view" To keep the view synchronized with the file currently opened in the editor, - select \uicontrol {Synchronize with Editor}. + select \inlineimage linkicon.png + (\uicontrol {Synchronize with Editor}). */ diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qmlstatenodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qmlstatenodeinstance.cpp index 5b320814594..c07cc4bfcff 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qmlstatenodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qmlstatenodeinstance.cpp @@ -25,10 +25,11 @@ #include "qmlstatenodeinstance.h" -#include - #include "qmlpropertychangesnodeinstance.h" +#include +#include + namespace QmlDesigner { namespace Internal { @@ -53,12 +54,28 @@ QmlStateNodeInstance::Pointer return instance; } +void setAllNodesDirtyRecursive(QQuickItem *parentItem) +{ +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + Q_UNUSED(parentItem) +#else + if (!parentItem) + return; + const QList children = parentItem->childItems(); + for (QQuickItem *childItem : children) + setAllNodesDirtyRecursive(childItem); + DesignerSupport::addDirty(parentItem, QQuickDesignerSupport::Content); +#endif +} + void QmlStateNodeInstance::activateState() { if (!QmlPrivateGate::States::isStateActive(object(), context()) && nodeInstanceServer()->hasInstanceForObject(object())) { nodeInstanceServer()->setStateInstance(nodeInstanceServer()->instanceForObject(object())); QmlPrivateGate::States::activateState(object(), context()); + + setAllNodesDirtyRecursive(nodeInstanceServer()->rootItem()); } } diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 419e75cfa04..34d96265286 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -1858,7 +1858,11 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm #ifdef QUICK3D_MODULE if (qobject_cast(object) || qobject_cast(object) - || qobject_cast(object)) { + || qobject_cast(object) +#ifdef QUICK3D_PARTICLES_MODULE + || qobject_cast(object) +#endif + ) { return true; } // Node is a component if it has node children that have no instances diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png index 53d03e476b4..389a4eab873 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png new file mode 100644 index 00000000000..3636791da1e Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png index c3f05108f9e..6c50e4e1fa9 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png new file mode 100644 index 00000000000..09ea1ce94d5 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png index aeb03a574ed..01470cfbf5a 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-error.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-error@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-error@2x.png new file mode 100644 index 00000000000..63f54625549 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-error@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png index 882256b30d4..745828c1f7e 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png new file mode 100644 index 00000000000..c2232f3a754 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png index 47d66317b28..40c96993a0c 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png new file mode 100644 index 00000000000..c4ef9b7854d Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png new file mode 100644 index 00000000000..09ea1ce94d5 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png index 323f4d51b16..6c50e4e1fa9 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png index 53247a422fd..515f5e0b8e4 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png new file mode 100644 index 00000000000..1967a363dc0 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png index 63c6b7b79f0..d41b3c5ff88 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png new file mode 100644 index 00000000000..03c1ae66037 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png index fc21300336e..339342bd913 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png new file mode 100644 index 00000000000..2ec60f0453c Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png index 735219f0bb6..7b457bae8f4 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png new file mode 100644 index 00000000000..22e200c0d70 Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png index fc21300336e..65fbae504ff 100644 Binary files a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png new file mode 100644 index 00000000000..5d05168537d Binary files /dev/null and b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png differ diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml index c7ed3ec8d64..87a63dcefe8 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml @@ -202,8 +202,8 @@ Item { dialogBox.setScreenSizeIndex(index); var r = screenSizeModel.screenSizes(index); - widthTextField.text = r.width; - heightTextField.text = r.height; + widthField.realValue = r.width; + heightField.realValue = r.height; } Connections { @@ -252,19 +252,20 @@ Item { } // content items - SC.TextField { - id: widthTextField + SC.RealSpinBox { + id: widthField actionIndicatorVisible: false - translationIndicatorVisible: false - implicitWidth: 50 - color: DialogValues.textColor - selectByMouse: true - validator: IntValidator { bottom: 1; top: 100000; } + implicitWidth: 70 + labelColor: DialogValues.textColor + realFrom: 100 + realTo: 100000 + realValue: 100 + realStepSize: 10 font.pixelSize: DialogValues.defaultPixelSize - onTextChanged: { - var height = heightTextField.text ? parseInt(heightTextField.text) : 0 - var width = text ? parseInt(text) : 0 + onRealValueChanged: { + var height = heightField.realValue + var width = realValue if (width >= height) orientationButton.setHorizontal() @@ -276,22 +277,23 @@ Item { Binding { target: dialogBox property: "customWidth" - value: widthTextField.text + value: widthField.realValue } - SC.TextField { - id: heightTextField + SC.RealSpinBox { + id: heightField actionIndicatorVisible: false - translationIndicatorVisible: false - implicitWidth: 50 - color: DialogValues.textColor - selectByMouse: true - validator: IntValidator { bottom: 1; top: 100000; } + implicitWidth: 70 + labelColor: DialogValues.textColor + realFrom: 100 + realTo: 100000 + realValue: 100 + realStepSize: 10 font.pixelSize: DialogValues.defaultPixelSize - onTextChanged: { - var height = text ? parseInt(text) : 0 - var width = widthTextField.text ? parseInt(widthTextField.text) : 0 + onRealValueChanged: { + var height = realValue + var width = widthField.realValue if (width >= height) orientationButton.setHorizontal() @@ -303,7 +305,7 @@ Item { Binding { target: dialogBox property: "customHeight" - value: heightTextField.text + value: heightField.realValue } Item { Layout.fillWidth: true } @@ -348,9 +350,8 @@ Item { } onClicked: { - if (widthTextField.text && heightTextField.text) { - [widthTextField.text, heightTextField.text] = [heightTextField.text, widthTextField.text]; - + if (widthField.realValue && heightField.realValue) { + [widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue]; checked = !checked } } diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml index 05bc5fff042..75dfd684094 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/ProjectType/DefaultProject.qml @@ -29,7 +29,7 @@ import QtQuick.Controls import QtQuick import QtQuick.Layouts -import newprojectdialog +import NewProjectDialog Item { anchors.fill: parent diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 8b2e6698bd9..9adc5e5f2c9 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -158,16 +158,15 @@ QtObject { readonly property string transparent: "\u0099" readonly property string triState: "\u009A" readonly property string triangleArcA: "\u009B" - readonly property string triangleArcB: "\u009C" - readonly property string triangleCornerA: "\u009D" - readonly property string triangleCornerB: "\u009E" - readonly property string unLinked: "\u009F" - readonly property string undo: "\u00A0" - readonly property string unpin: "\u00A1" - readonly property string upDownIcon: "\u00A2" - readonly property string upDownSquare2: "\u00A3" - readonly property string visibilityOffBroken: "\u00A4" // visibilityOff - readonly property string visibilityOff: "\u00A5" // visibilityOff2 + readonly property string triangleArcB: "\u009D" + readonly property string triangleCornerA: "\u009E" + readonly property string triangleCornerB: "\u009F" + readonly property string unLinked: "\u00A0" + readonly property string undo: "\u00A1" + readonly property string unpin: "\u00A2" + readonly property string upDownIcon: "\u00A3" + readonly property string upDownSquare2: "\u00A4" + readonly property string visibilityOff: "\u00A5" readonly property string visibilityOn: "\u00A6" readonly property string wildcard: "\u00A7" readonly property string wizardsAutomotive: "\u00A8" @@ -175,12 +174,12 @@ QtObject { readonly property string wizardsGeneric: "\u00AA" readonly property string wizardsMcuEmpty: "\u00AB" readonly property string wizardsMcuGraph: "\u00AC" - readonly property string wizardsMobile: "\u00AD" - readonly property string wizardsUnknown: "\u00AE" - readonly property string zoomAll: "\u00AF" - readonly property string zoomIn: "\u00B0" - readonly property string zoomOut: "\u00B1" - readonly property string zoomSelection: "\u00B2" + readonly property string wizardsMobile: "\u00AE" + readonly property string wizardsUnknown: "\u00AF" + readonly property string zoomAll: "\u00B0" + readonly property string zoomIn: "\u00B1" + readonly property string zoomOut: "\u00B2" + readonly property string zoomSelection: "\u00B3" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index 24141fcc837..eb9426e8f45 100644 Binary files a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf and b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf differ diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index bd5d25834ed..1bfd9e9701d 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -794,8 +794,10 @@ bool Check::visit(UiObjectInitializer *) UiQualifiedId *qualifiedTypeId = qualifiedTypeNameId(parent()); if (qualifiedTypeId) { typeName = qualifiedTypeId->name.toString(); - if (typeName == "Component") + if (typeName == "Component") { m_idStack.push(StringSet()); + _componentChildCount = 0; + } } m_typeStack.push(typeName); @@ -806,10 +808,23 @@ bool Check::visit(UiObjectInitializer *) return true; } -void Check::endVisit(UiObjectInitializer *) +void Check::endVisit(UiObjectInitializer *uiObjectInitializer) { m_propertyStack.pop(); - m_typeStack.pop(); + + const QString type = m_typeStack.pop(); + + if (type == "Component" && _componentChildCount == 0) { + SourceLocation loc; + UiObjectDefinition *objectDefinition = cast(parent()); + if (objectDefinition) + loc = objectDefinition->qualifiedTypeNameId->identifierToken; + UiObjectBinding *objectBinding = cast(parent()); + if (objectBinding) + loc = objectBinding->qualifiedTypeNameId->identifierToken; + addMessage(WarnComponentRequiresChildren, loc); + } + UiObjectDefinition *objectDefinition = cast(parent()); if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == QLatin1String("Component")) m_idStack.pop(); @@ -962,6 +977,12 @@ void Check::visitQmlObject(Node *ast, UiQualifiedId *typeId, addMessage(ErrUnsupportedRootTypeInQmlUi, locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation()), typeName); + if (!m_typeStack.isEmpty() && m_typeStack.last() == "Component") { + _componentChildCount++; + if (_componentChildCount > 1) + addMessage(ErrToManyComponentChildren, typeErrorLocation); + } + bool typeError = false; if (_importsOk) { const ObjectValue *prototype = _context->lookupType(_doc.data(), typeId); diff --git a/src/libs/qmljs/qmljscheck.h b/src/libs/qmljs/qmljscheck.h index 362c0cc0ac6..10019a9794e 100644 --- a/src/libs/qmljs/qmljscheck.h +++ b/src/libs/qmljs/qmljscheck.h @@ -158,6 +158,7 @@ private: bool _importsOk; bool _inStatementBinding; + int _componentChildCount = 0; const Imports *_imports; TranslationFunction lastTransLationfunction = noTranslationfunction; }; diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.cpp b/src/libs/qmljs/qmljsstaticanalysismessage.cpp index 24bb70c1869..c65508bdfa5 100644 --- a/src/libs/qmljs/qmljsstaticanalysismessage.cpp +++ b/src/libs/qmljs/qmljsstaticanalysismessage.cpp @@ -251,6 +251,10 @@ StaticAnalysisMessages::StaticAnalysisMessages() tr("Type cannot be instantiated recursively (%1)."), 1); newMsg(WarnLogicalValueDoesNotDependOnValues, Warning, tr("Logical value does not depend on actual values")); + newMsg(ErrToManyComponentChildren, Error, + tr("Components are only allowed to have a single child element.")); + newMsg(WarnComponentRequiresChildren, Warning, + tr("Components require a child element.")); } } // anonymous namespace diff --git a/src/libs/qmljs/qmljsstaticanalysismessage.h b/src/libs/qmljs/qmljsstaticanalysismessage.h index e651533fd79..51a517d2352 100644 --- a/src/libs/qmljs/qmljsstaticanalysismessage.h +++ b/src/libs/qmljs/qmljsstaticanalysismessage.h @@ -132,6 +132,8 @@ enum Type { ErrInvalidArrayValueLength = 323, ErrHitMaximumRecursion = 324, WarnLogicalValueDoesNotDependOnValues = 325, + ErrToManyComponentChildren = 326, + WarnComponentRequiresChildren = 327, WarnDuplicateImport = 400 }; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 7638d0b402f..a062299aab9 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -37,7 +37,10 @@ #include #include +#include #include +#include +#include #include #include @@ -418,11 +421,19 @@ QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const void AndroidDeviceManager::updateDevicesList() { - connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() { - updateDevicesListOnce(); - }); + // If a non-Android Kit is currently active, skip the device list update + const Target *startupTarget = SessionManager::startupTarget(); + if (!startupTarget) + return; + + const Kit *kit = startupTarget->kit(); + if (!kit) + return; + + if (DeviceTypeKitAspect::deviceTypeId(kit) != Constants::ANDROID_DEVICE_TYPE) + return; + updateDevicesListOnce(); - m_devicesUpdaterTimer.start(deviceUpdaterMsInterval); } void AndroidDeviceManager::updateDevicesListOnce() @@ -537,11 +548,17 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent) void AndroidDeviceManager::setupDevicesWatcher() { - // The call to avdmanager is always slower than the call to adb devices, - // so connecting the slot to the slower call should be enough. - connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished, - this, &AndroidDeviceManager::devicesListUpdated); - updateDevicesList(); + if (!m_devicesUpdaterTimer.isActive()) { + // The call to avdmanager is always slower than the call to adb devices, + // so connecting the slot to the slower call should be enough. + connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished, + this, &AndroidDeviceManager::devicesListUpdated); + connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() { + updateDevicesList(); + }); + m_devicesUpdaterTimer.start(deviceUpdaterMsInterval); + } + updateDevicesListOnce(); } void AndroidDeviceManager::devicesListUpdated() diff --git a/src/plugins/autotest/testconfiguration.cpp b/src/plugins/autotest/testconfiguration.cpp index 09f17670c9c..4599fc7606b 100644 --- a/src/plugins/autotest/testconfiguration.cpp +++ b/src/plugins/autotest/testconfiguration.cpp @@ -83,21 +83,9 @@ FilePath ITestConfiguration::executableFilePath() const if (!hasExecutable()) return {}; - if (m_runnable.command.executable().isExecutableFile() && m_runnable.command.executable().path() != ".") { - return m_runnable.command.executable().absoluteFilePath(); - } else if (m_runnable.command.executable().path() == "."){ - QString fullCommandFileName = m_runnable.command.executable().toString(); - // TODO: check if we can use searchInPath() from Utils::Environment - const QStringList &pathList = m_runnable.environment.toProcessEnvironment().value("PATH") - .split(HostOsInfo::pathListSeparator()); - - for (const QString &path : pathList) { - QString filePath(path + QDir::separator() + fullCommandFileName); - if (QFileInfo(filePath).isExecutable()) - return m_runnable.command.executable().absoluteFilePath(); - } - } - return {}; + const Environment env = m_runnable.environment.size() == 0 ? Environment::systemEnvironment() + : m_runnable.environment; + return env.searchInPath(m_runnable.command.executable().path()); } Environment ITestConfiguration::filteredEnvironment(const Environment &original) const diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 1d924f8b2da..ac8f686910a 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -338,7 +338,9 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() return createProposal(); break; case ClangCompletionContextAnalyzer::CompleteIncludePath: - if (completeInclude(analyzer.positionEndOfExpression())) + m_completions = completeInclude(analyzer.positionEndOfExpression(), m_completionOperator, + m_interface.data(), m_interface->headerPaths()); + if (!m_completions.isEmpty()) return createProposal(); break; case ClangCompletionContextAnalyzer::CompletePreprocessorDirective: @@ -441,38 +443,46 @@ bool ClangCompletionAssistProcessor::accepts() const /** * @brief Creates completion proposals for #include and given cursor - * @param cursor - cursor placed after opening bracked or quote - * @return false if completions list is empty + * @param position - cursor placed after opening bracked or quote + * @param completionOperator - the type of token + * @param interface - relevant document data + * @param headerPaths - the include paths + * @return the list of completion items */ -bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor) +QList ClangCompletionAssistProcessor::completeInclude( + int position, unsigned completionOperator, const TextEditor::AssistInterface *interface, + const ProjectExplorer::HeaderPaths &headerPaths) { + QTextCursor cursor(interface->textDocument()); + cursor.setPosition(position); QString directoryPrefix; - if (m_completionOperator == T_SLASH) { + if (completionOperator == T_SLASH) { QTextCursor c = cursor; c.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); QString sel = c.selectedText(); int startCharPos = sel.indexOf(QLatin1Char('"')); if (startCharPos == -1) { startCharPos = sel.indexOf(QLatin1Char('<')); - m_completionOperator = T_ANGLE_STRING_LITERAL; + completionOperator = T_ANGLE_STRING_LITERAL; } else { - m_completionOperator = T_STRING_LITERAL; + completionOperator = T_STRING_LITERAL; } if (startCharPos != -1) directoryPrefix = sel.mid(startCharPos + 1, sel.length() - 1); } // Make completion for all relevant includes - ProjectExplorer::HeaderPaths headerPaths = m_interface->headerPaths(); + ProjectExplorer::HeaderPaths allHeaderPaths = headerPaths; const auto currentFilePath = ProjectExplorer::HeaderPath::makeUser( - m_interface->filePath().toFileInfo().path()); - if (!headerPaths.contains(currentFilePath)) - headerPaths.append(currentFilePath); + interface->filePath().toFileInfo().path()); + if (!allHeaderPaths.contains(currentFilePath)) + allHeaderPaths.append(currentFilePath); const ::Utils::MimeType mimeType = ::Utils::mimeTypeForName("text/x-c++hdr"); const QStringList suffixes = mimeType.suffixes(); - foreach (const ProjectExplorer::HeaderPath &headerPath, headerPaths) { + QList completions; + foreach (const ProjectExplorer::HeaderPath &headerPath, allHeaderPaths) { QString realPath = headerPath.path; if (!directoryPrefix.isEmpty()) { realPath += QLatin1Char('/'); @@ -480,11 +490,11 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor) if (headerPath.type == ProjectExplorer::HeaderPathType::Framework) realPath += QLatin1String(".framework/Headers"); } - completeIncludePath(realPath, suffixes); + completions << completeIncludePath(realPath, suffixes, completionOperator); } QList> completionsForSorting; - for (AssistProposalItemInterface * const item : qAsConst(m_completions)) { + for (AssistProposalItemInterface * const item : qAsConst(completions)) { QString s = item->text(); s.replace('/', QChar(0)); // The dir separator should compare less than anything else. completionsForSorting << qMakePair(item, s); @@ -493,26 +503,21 @@ bool ClangCompletionAssistProcessor::completeInclude(const QTextCursor &cursor) return left.second < right.second; }); for (int i = 0; i < completionsForSorting.count(); ++i) - m_completions[i] = completionsForSorting[i].first; + completions[i] = completionsForSorting[i].first; - return !m_completions.isEmpty(); -} - -bool ClangCompletionAssistProcessor::completeInclude(int position) -{ - QTextCursor textCursor(m_interface->textDocument()); // TODO: Simplify, move into function - textCursor.setPosition(position); - return completeInclude(textCursor); + return completions; } /** - * @brief Adds #include completion proposals using given include path + * @brief Finds #include completion proposals using given include path * @param realPath - one of directories where compiler searches includes * @param suffixes - file suffixes for C/C++ header files + * @return a list of matching completion items */ -void ClangCompletionAssistProcessor::completeIncludePath(const QString &realPath, - const QStringList &suffixes) +QList ClangCompletionAssistProcessor::completeIncludePath( + const QString &realPath, const QStringList &suffixes, unsigned completionOperator) { + QList completions; QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); //: Parent folder for proposed #include completion const QString hint = tr("Location: %1").arg(QDir::toNativeSeparators(QDir::cleanPath(realPath))); @@ -529,10 +534,11 @@ void ClangCompletionAssistProcessor::completeIncludePath(const QString &realPath item->setText(text); item->setDetail(hint); item->setIcon(CPlusPlus::Icons::keywordIcon()); - item->setCompletionOperator(m_completionOperator); - m_completions.append(item); + item->setCompletionOperator(completionOperator); + completions.append(item); } } + return completions; } bool ClangCompletionAssistProcessor::completePreprocessorDirectives() diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h index 78826f598a8..1d67344cc86 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h @@ -34,6 +34,11 @@ #include #include +namespace TextEditor { +class AssistInterface; +class AssistProposalItemInterface; +} + namespace ClangCodeModel { namespace Internal { @@ -48,6 +53,11 @@ public: ClangCompletionAssistProcessor(); ~ClangCompletionAssistProcessor() override; + static QList completeInclude( + int position, unsigned completionOperator, + const TextEditor::AssistInterface *interface, + const ProjectExplorer::HeaderPaths &headerPaths); + TextEditor::IAssistProposal *perform(const TextEditor::AssistInterface *interface) override; void handleAvailableCompletions(const CodeCompletions &completions); @@ -65,12 +75,10 @@ private: TextEditor::IAssistProposal *createProposal(); TextEditor::IAssistProposal *createFunctionHintProposal( const CodeCompletions &completions); - QList toAssistProposalItems( const CodeCompletions &completions) const; - bool completeInclude(const QTextCursor &cursor); - bool completeInclude(int position); - void completeIncludePath(const QString &realPath, const QStringList &suffixes); + static QList completeIncludePath( + const QString &realPath, const QStringList &suffixes, unsigned completionOperator); bool completePreprocessorDirectives(); bool completeDoxygenKeywords(); void addCompletionItem(const QString &text, diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 46c85f06cdf..7d034f7aac3 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -25,6 +25,7 @@ #include "clangdclient.h" +#include "clangcompletionassistprocessor.h" #include "clangcompletioncontextanalyzer.h" #include "clangdiagnosticmanager.h" #include "clangmodelmanagersupport.h" @@ -66,6 +67,7 @@ #include #include #include +#include #include #include @@ -810,14 +812,15 @@ public: }; -enum class CustomAssistMode { Doxygen, Preprocessor }; +enum class CustomAssistMode { Doxygen, Preprocessor, IncludePath }; class CustomAssistProcessor : public IAssistProcessor { public: - CustomAssistProcessor(ClangdClient *client, int position, unsigned completionOperator, - CustomAssistMode mode) + CustomAssistProcessor(ClangdClient *client, int position, int endPos, + unsigned completionOperator, CustomAssistMode mode) : m_client(client) , m_position(position) + , m_endPos(endPos) , m_completionOperator(completionOperator) , m_mode(mode) {} @@ -833,7 +836,7 @@ private: CPlusPlus::Icons::keywordIcon()); } break; - case CustomAssistMode::Preprocessor: + case CustomAssistMode::Preprocessor: { static QIcon macroIcon = Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Macro); for (const QString &completion : CppEditor::CppCompletionAssistProcessor::preprocessorCompletions()) { @@ -843,6 +846,17 @@ private: completions << createItem("import", macroIcon); break; } + case ClangCodeModel::Internal::CustomAssistMode::IncludePath: { + HeaderPaths headerPaths; + const CppEditor::ProjectPart::ConstPtr projectPart + = projectPartForFile(interface->filePath().toString()); + if (projectPart) + headerPaths = projectPart->headerPaths; + completions = ClangCompletionAssistProcessor::completeInclude( + m_endPos, m_completionOperator, interface, headerPaths); + break; + } + } GenericProposalModelPtr model(new GenericProposalModel); model->loadContent(completions); const auto proposal = new GenericProposal(m_position, model); @@ -864,6 +878,7 @@ private: ClangdClient * const m_client; const int m_position; + const int m_endPos; const unsigned m_completionOperator; const CustomAssistMode m_mode; }; @@ -1110,6 +1125,12 @@ public: using LanguageClientCompletionItem::LanguageClientCompletionItem; void apply(TextDocumentManipulatorInterface &manipulator, int basePosition) const override; + + enum class SpecialQtType { Signal, Slot, None }; + static SpecialQtType getQtType(const CompletionItem &item); + +private: + QIcon icon() const override; }; class ClangdClient::ClangdCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor @@ -1155,15 +1176,7 @@ ClangdClient::ClangdCompletionAssistProcessor::generateCompletionItems( // whether the cursor was on the second argument of a (dis)connect() call. // If so, we offer only signals, as nothing else makes sense in that context. static const auto criterion = [](const CompletionItem &ci) { - const Utils::optional doc = ci.documentation(); - if (!doc) - return false; - QString docText; - if (Utils::holds_alternative(*doc)) - docText = Utils::get(*doc); - else if (Utils::holds_alternative(*doc)) - docText = Utils::get(*doc).content(); - return docText.contains("Annotation: qt_signal"); + return ClangdCompletionItem::getQtType(ci) == ClangdCompletionItem::SpecialQtType::Signal; }; const QTextDocument *doc = document(); const int pos = basePos(); @@ -1526,6 +1539,30 @@ QString ClangdClient::displayNameFromDocumentSymbol(SymbolKind kind, const QStri } } +// Force re-parse of all open files that include the changed ui header. +// Otherwise, we potentially have stale diagnostics. +void ClangdClient::handleUiHeaderChange(const QString &fileName) +{ + const QRegularExpression includeRex("#include.*" + fileName + R"([>"])"); + const QVector &allClients = LanguageClientManager::clients(); + for (Client * const client : allClients) { + if (!client->reachable() || !qobject_cast(client)) + continue; + for (IDocument * const doc : DocumentModel::openedDocuments()) { + const auto textDoc = qobject_cast(doc); + if (!textDoc || !client->documentOpen(textDoc)) + continue; + const QTextCursor includePos = textDoc->document()->find(includeRex); + if (includePos.isNull()) + continue; + qCDebug(clangdLog) << "updating" << textDoc->filePath() << "due to change in UI header" + << fileName; + client->documentContentsChanged(textDoc, 0, 0, 0); + break; // No sane project includes the same UI header twice. + } + } +} + void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList &locations) { const auto refData = runningFindUsages.find(key); @@ -2817,14 +2854,26 @@ IAssistProcessor *ClangdClient::ClangdCompletionAssistProvider::createProcessor( qCDebug(clangdLogCompletion) << "creating doxygen processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), + contextAnalyzer.positionEndOfExpression(), contextAnalyzer.completionOperator(), CustomAssistMode::Doxygen); case ClangCompletionContextAnalyzer::CompletePreprocessorDirective: qCDebug(clangdLogCompletion) << "creating macro processor"; return new CustomAssistProcessor(m_client, contextAnalyzer.positionForProposal(), + contextAnalyzer.positionEndOfExpression(), contextAnalyzer.completionOperator(), CustomAssistMode::Preprocessor); + case ClangCompletionContextAnalyzer::CompleteIncludePath: + if (m_client->versionNumber() < QVersionNumber(14)) { // https://reviews.llvm.org/D112996 + qCDebug(clangdLogCompletion) << "creating include processor"; + return new CustomAssistProcessor(m_client, + contextAnalyzer.positionForProposal(), + contextAnalyzer.positionEndOfExpression(), + contextAnalyzer.completionOperator(), + CustomAssistMode::IncludePath); + } + [[fallthrough]]; default: break; } @@ -3009,6 +3058,38 @@ void ClangdCompletionItem::apply(TextDocumentManipulatorInterface &manipulator, } } +ClangdCompletionItem::SpecialQtType ClangdCompletionItem::getQtType(const CompletionItem &item) +{ + const Utils::optional doc = item.documentation(); + if (!doc) + return SpecialQtType::None; + QString docText; + if (Utils::holds_alternative(*doc)) + docText = Utils::get(*doc); + else if (Utils::holds_alternative(*doc)) + docText = Utils::get(*doc).content(); + if (docText.contains("Annotation: qt_signal")) + return SpecialQtType::Signal; + if (docText.contains("Annotation: qt_slot")) + return SpecialQtType::Slot; + return SpecialQtType::None; +} + +QIcon ClangdCompletionItem::icon() const +{ + const SpecialQtType qtType = getQtType(item()); + switch (qtType) { + case SpecialQtType::Signal: + return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::Signal); + case SpecialQtType::Slot: + // FIXME: Add visibility info to completion item tags in clangd? + return Utils::CodeModelIcon::iconForType(Utils::CodeModelIcon::SlotPublic); + case SpecialQtType::None: + break; + } + return LanguageClientCompletionItem::icon(); +} + MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc, const AstHandler &astHandler, AstCallbackMode callbackMode, const Range &range) diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 580168c3e33..de898696ec0 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -86,6 +86,8 @@ public: static QString displayNameFromDocumentSymbol(LanguageServerProtocol::SymbolKind kind, const QString &name, const QString &detail); + static void handleUiHeaderChange(const QString &fileName); + signals: void indexingFinished(); void foundReferences(const QList &items); diff --git a/src/plugins/clangcodemodel/clangfollowsymbol.cpp b/src/plugins/clangcodemodel/clangfollowsymbol.cpp index 87e336d5508..bb107285567 100644 --- a/src/plugins/clangcodemodel/clangfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangfollowsymbol.cpp @@ -155,9 +155,10 @@ static ::Utils::ProcessLinkCallback extendedCallback(::Utils::ProcessLinkCallbac // If globalFollowSymbol finds nothing follow to the declaration. return [original_callback = std::move(callback), result](const ::Utils::Link &link) { if (link.linkTextStart < 0 && result.isResultOnlyForFallBack) { - return original_callback(::Utils::Link(::Utils::FilePath::fromString(result.fileName), - result.startLine, - result.startColumn - 1)); + return original_callback(Utils::Link( + Utils::FilePath::fromString(result.fileName).cleanPath(), + result.startLine, + result.startColumn - 1)); } return original_callback(link); }; @@ -242,7 +243,7 @@ void ClangFollowSymbol::findLink(const CppEditor::CursorInEditor &data, symbolFinder, inNextSplit); } else { - callback(Link(Utils::FilePath::fromString(result.fileName), + callback(Link(Utils::FilePath::fromString(result.fileName).cleanPath(), result.startLine, result.startColumn - 1)); } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 3bd9d2640f6..371fb224524 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -608,6 +608,7 @@ void ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated(const QStr const QString mappedPath = m_uiHeaderOnDiskManager.write(filePath, content); m_communicator.unsavedFilesUpdated(mappedPath, content, 0); + ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName()); } void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &filePath) @@ -618,6 +619,7 @@ void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &fil const QString mappedPath = m_uiHeaderOnDiskManager.remove(filePath); const QString projectPartId = projectPartIdForFile(filePath); m_communicator.unsavedFilesRemoved({{mappedPath, projectPartId}}); + ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName()); } } diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 82a6eea7524..19fb1d7685b 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1488,9 +1488,15 @@ void ClangdTestCompletion::testCompleteIncludeDirective() getProposal("includeDirectiveCompletion.cpp", proposal); QVERIFY(proposal); - QVERIFY(hasItem(proposal, " file.h>")); - QVERIFY(hasItem(proposal, " otherFile.h>")); - QVERIFY(hasItem(proposal, " mylib/")); + if (client()->versionNumber() < QVersionNumber(14)) { + QVERIFY(hasItem(proposal, "file.h")); + QVERIFY(hasItem(proposal, "otherFile.h")); + QVERIFY(hasItem(proposal, "mylib/")); + } else { + QVERIFY(hasItem(proposal, " file.h>")); + QVERIFY(hasItem(proposal, " otherFile.h>")); + QVERIFY(hasItem(proposal, " mylib/")); + } QVERIFY(!hasSnippet(proposal, "class ")); } diff --git a/src/plugins/coreplugin/iwizardfactory.h b/src/plugins/coreplugin/iwizardfactory.h index 0cb1b96d43b..d5a435e0fc8 100644 --- a/src/plugins/coreplugin/iwizardfactory.h +++ b/src/plugins/coreplugin/iwizardfactory.h @@ -64,7 +64,7 @@ public: Utils::Id id() const { return m_id; } WizardKind kind() const { return m_supportedProjectTypes.isEmpty() ? FileWizard : ProjectWizard; } QIcon icon() const { return m_icon; } - QString fontIcondCode() const { return m_fontIconCode; } + QString fontIconName() const { return m_fontIconName; } QString description() const { return m_description; } QString displayName() const { return m_displayName; } QString category() const { return m_category; } @@ -79,7 +79,7 @@ public: void setId(const Utils::Id id) { m_id = id; } void setSupportedProjectTypes(const QSet &projectTypes) { m_supportedProjectTypes = projectTypes; } void setIcon(const QIcon &icon, const QString &iconText = {}); - void setFontIconCode(const QString &code) { m_fontIconCode = code; } + void setFontIconName(const QString &code) { m_fontIconName = code; } void setDescription(const QString &description) { m_description = description; } void setDisplayName(const QString &displayName) { m_displayName = displayName; } void setCategory(const QString &category) { m_category = category; } @@ -137,7 +137,7 @@ private: QAction *m_action = nullptr; QIcon m_icon; - QString m_fontIconCode; + QString m_fontIconName; QString m_description; QString m_displayName; QString m_category; diff --git a/src/plugins/cppeditor/projectpart.cpp b/src/plugins/cppeditor/projectpart.cpp index 1376186d804..930466e0fe4 100644 --- a/src/plugins/cppeditor/projectpart.cpp +++ b/src/plugins/cppeditor/projectpart.cpp @@ -57,7 +57,7 @@ QString ProjectPart::projectFileLocation() const bool ProjectPart::belongsToProject(const ProjectExplorer::Project *project) const { - return project && topLevelProject == project->projectFilePath(); + return project ? topLevelProject == project->projectFilePath() : !hasProject(); } QByteArray ProjectPart::readProjectConfigFile(const QString &projectConfigFile) diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 75f829b5308..858b0126eb7 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -258,7 +258,7 @@ void McuPackage::setRelativePathModifier(const QString &path) m_relativePathModifier = path; } -void McuPackage::setVersions(const QVector &versions) +void McuPackage::setVersions(const QStringList &versions) { m_versions = versions; } @@ -312,13 +312,14 @@ void McuPackage::updateStatusUi() QString McuPackage::statusText() const { const QString displayPackagePath = m_path.toUserOutput(); - const QString displayVersions = QStringList(m_versions.toList()).join(" or "); - const QString displayRequiredPath = QString("%1 %2").arg( - FilePath::fromString(m_detectionPath).toUserOutput(), - displayVersions); - const QString displayDetectedPath = QString("%1 %2").arg( - FilePath::fromString(m_detectionPath).toUserOutput(), - m_detectedVersion); + const QString displayVersions = m_versions.join(" or "); + const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); + const QString displayRequiredPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, displayVersions); + const QString displayDetectedPath = m_versions.empty() ? + outDetectionPath : + QString("%1 %2").arg(outDetectionPath, m_detectedVersion); QString response; switch (m_status) { diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 95130fb0aba..807683167f2 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -88,7 +88,7 @@ public: void writeGeneralSettings() const; bool writeToSettings() const; void setRelativePathModifier(const QString &path); - void setVersions(const QVector &versions); + void setVersions(const QStringList &versions); bool automaticKitCreationEnabled() const; void setAutomaticKitCreationEnabled(const bool enabled); @@ -118,7 +118,7 @@ private: Utils::FilePath m_path; QString m_relativePathModifier; // relative path to m_path to be returned by path() QString m_detectedVersion; - QVector m_versions; + QStringList m_versions; QString m_downloadUrl; QString m_environmentVariableName; bool m_addToPath = false; diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index a9cdf7a976f..1823d634513 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -341,13 +341,13 @@ struct McuTargetDescription } platform; struct { QString id; - QVector versions; + QStringList versions; } toolchain; struct { QString name; QString defaultPath; QString envVar; - QVector versions; + QStringList versions; } boardSdk; struct { QString envVar; @@ -658,10 +658,10 @@ static McuTargetDescription parseDescriptionJsonCommon(const QString &qulVersion const QJsonObject freeRTOS = target.value("freeRTOS").toObject(); const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList(); - const auto toolchainVersionsVector = Utils::transform >( + const auto toolchainVersionsList = Utils::transform( toolchainVersions, [&](const QVariant &version) { return version.toString(); }); const QVariantList boardSdkVersions = boardSdk.value("versions").toArray().toVariantList(); - const auto boardSdkVersionsVector = Utils::transform >( + const auto boardSdkVersionsList = Utils::transform( boardSdkVersions, [&](const QVariant &version) { return version.toString(); }); return { @@ -670,13 +670,13 @@ static McuTargetDescription parseDescriptionJsonCommon(const QString &qulVersion {}, { toolchain.value("id").toString(), - toolchainVersionsVector, + toolchainVersionsList, }, { boardSdk.value("name").toString(), boardSdk.value("defaultPath").toString(), boardSdk.value("envVar").toString(), - boardSdkVersionsVector, + boardSdkVersionsList, }, { freeRTOS.value("envVar").toString(), diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp index d460995aa81..425cfcd5526 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardfactory.cpp @@ -72,7 +72,7 @@ const char CATEGORY_NAME_KEY[] = "trDisplayCategory"; const char DISPLAY_NAME_KEY[] = "trDisplayName"; const char ICON_KEY[] = "icon"; const char ICON_TEXT_KEY[] = "iconText"; -const char FONT_ICON_CODE_KEY[] = "fontIconCode"; +const char FONT_ICON_NAME_KEY[] = "fontIconName"; const char IMAGE_KEY[] = "image"; const char ICON_KIND_KEY[] = "iconKind"; const char DESCRIPTION_KEY[] = "trDescription"; @@ -743,8 +743,8 @@ bool JsonWizardFactory::initialize(const QVariantMap &data, const FilePath &base : QIcon(iconPath.toString()), iconText); - const QString fontIconCode = data.value(QLatin1String(FONT_ICON_CODE_KEY)).toString(); - setFontIconCode(fontIconCode); + const QString fontIconName = data.value(QLatin1String(FONT_ICON_NAME_KEY)).toString(); + setFontIconName(fontIconName); strVal = data.value(QLatin1String(IMAGE_KEY)).toString(); if (!strVal.isEmpty()) { diff --git a/src/plugins/qmldesigner/boilerplate.qrc b/src/plugins/qmldesigner/boilerplate.qrc index 2680ec0da9c..3e2106beaa0 100644 --- a/src/plugins/qmldesigner/boilerplate.qrc +++ b/src/plugins/qmldesigner/boilerplate.qrc @@ -1,5 +1,10 @@ qmlprojectmaincpp.tpl + qmlprojectmaincppheader.tpl + qmlprojectmodules.tpl + qmlprojectmaincmakelists.tpl + qmlprojectmodulecmakelists.tpl + qmlprojectmainqml.tpl diff --git a/src/plugins/qmldesigner/components/componentcore/theme.cpp b/src/plugins/qmldesigner/components/componentcore/theme.cpp index 6fe7afe7603..df96fd61a36 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.cpp +++ b/src/plugins/qmldesigner/components/componentcore/theme.cpp @@ -186,6 +186,11 @@ QString Theme::getIconUnicode(Theme::Icon i) return instance()->m_constants->property(e.valueToKey(i)).toString(); } +QString Theme::getIconUnicode(const QString &name) +{ + return instance()->m_constants->property(name.toStdString().data()).toString(); +} + QColor Theme::qmlDesignerBackgroundColorDarker() const { return getColor(QmlDesigner_BackgroundColorDarker); diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h index 159824b1f77..1bcaea63307 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.h +++ b/src/plugins/qmldesigner/components/componentcore/theme.h @@ -174,8 +174,7 @@ public: unpin, upDownIcon, upDownSquare2, - visibilityOffBroken, // visibilityOff - visibilityOff, // visibilityOff2 + visibilityOff, visibilityOn, wildcard, wizardsAutomotive, @@ -198,6 +197,7 @@ public: static QColor getColor(Color role); static QPixmap getPixmap(const QString &id); static QString getIconUnicode(Theme::Icon i); + static QString getIconUnicode(const QString &name); Q_INVOKABLE QColor qmlDesignerBackgroundColorDarker() const; Q_INVOKABLE QColor qmlDesignerBackgroundColorDarkAlternate() const; diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index a5d904c495a..8b8b3b91253 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -279,6 +279,7 @@ bool DesignDocument::isDocumentLoaded() const void DesignDocument::resetToDocumentModel() { + plainTextEdit()->document()->clearUndoRedoStacks(); m_inFileComponentModel.reset(); } @@ -310,6 +311,8 @@ void DesignDocument::changeToDocumentModel() viewManager().detachRewriterView(); viewManager().detachViewsExceptRewriterAndComponetView(); + plainTextEdit()->document()->clearUndoRedoStacks(); + m_inFileComponentModel.reset(); m_inFileComponentTextModifier.reset(); @@ -345,6 +348,8 @@ void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textMod viewManager().detachRewriterView(); viewManager().detachViewsExceptRewriterAndComponetView(); + plainTextEdit()->document()->clearUndoRedoStacks(); + m_inFileComponentModel.reset(createInFileComponentModel()); m_inFileComponentModel->setTextModifier(m_inFileComponentTextModifier.data()); diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp index 6aca50c4334..aaccaee40db 100644 --- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp @@ -160,40 +160,65 @@ void ComponentTextModifier::handleOriginalTextChanged() const QString currentText = m_originalModifier->text(); - // Adjust for removal/addition of whitespace in the document - // Check that non-whitespace portion of the text is the same and count the whitespace diff const int oldLen = m_originalText.size(); const int newLen = currentText.size(); - int newSpace = 0; - int oldSpace = 0; - int newIdx = 0; - for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) { - const QChar oldChar = m_originalText[oldIdx]; - if (oldIdx == m_componentStartOffset) - m_componentStartOffset += newSpace - oldSpace; - if (oldIdx == m_componentEndOffset) { - m_componentEndOffset += newSpace - oldSpace; - break; + + if (oldLen != newLen) { + int newSpace = 0; + int oldSpace = 0; + int newIdx = 0; + int nonWhiteSpaceChangeIdx = -1; + int newStartOffset = m_componentStartOffset; + + // Adjust for removal/addition of whitespace in the document. + // Whitespace changes that happen when document is saved can be spread around throughout + // the entire document in multiple places. + // Check that non-whitespace portion of the text is the same and count the whitespace diff + for (int oldIdx = 0; oldIdx < oldLen; ++oldIdx) { + const QChar oldChar = m_originalText[oldIdx]; + if (oldIdx == m_componentStartOffset) + newStartOffset += newSpace - oldSpace; + if (oldIdx == m_componentEndOffset) { + m_componentEndOffset += newSpace - oldSpace; + m_componentStartOffset = newStartOffset; + m_originalText = currentText; + break; + } + + while (newIdx < newLen && currentText[newIdx].isSpace()) { + ++newSpace; + ++newIdx; + } + + if (oldChar.isSpace()) { + ++oldSpace; + continue; + } + + if (currentText[newIdx] != oldChar) { + nonWhiteSpaceChangeIdx = oldIdx; + // A non-whitespace change is a result of manual text edit or undo/redo operation. + // Assumption is that separate whitespace changes and a non-whitespace change can't + // both happen simultaneously, so break out of whitespace check loop. + break; + } else { + ++newIdx; + } } - while (newIdx < newLen && currentText[newIdx].isSpace()) { - ++newSpace; - ++newIdx; + if (nonWhiteSpaceChangeIdx >= 0) { + // For non-whitespace change, we assume the whole change is either before the component + // or inside the component. If the change spans both, it's likely the change is + // invalid anyway, and we don't care about trying to keep offsets up to date. + int diff = newLen - oldLen; + if (nonWhiteSpaceChangeIdx < m_componentEndOffset) + m_componentEndOffset += diff; + if (nonWhiteSpaceChangeIdx < m_componentStartOffset) + m_componentStartOffset += diff; + m_originalText = currentText; } - if (oldChar.isSpace()) { - ++oldSpace; - continue; - } - - if (currentText[newIdx] != oldChar) { - // Non-whitespace difference, we can't determine a valid offset in this case - // TODO: Needs proper handling to deal with undo/redo/arbitrary edits somehow (QDS-5392) - break; - } else { - ++newIdx; - } } - m_originalText = currentText; + emit textChanged(); } diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 9808c878a56..0afb86d6dd6 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -66,6 +66,7 @@ const char NAVIGATOR_REVERSE_ITEM_ORDER[] = "NavigatorReverseItemOrder"; const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These settings are not exposed in ui. */ const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ const char STANDALONE_MODE[] = "StandAloneMode"; +const char SHOW_DEBUG_SETTINGS[] = "ShowDebugSettings"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; const char COLOR_PALETTE_RECENT[] = "ColorPaletteRecent"; const char COLOR_PALETTE_FAVORITE[] = "ColorPaletteFavorite"; diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index feeaa2fe19e..24faa267397 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -78,7 +78,7 @@ void onGenerateCmakeLists() { queuedFiles.clear(); FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); - GenerateCmakeLists::generateMainCmake(rootDir); + GenerateCmakeLists::generateCmakes(rootDir); GenerateEntryPoints::generateMainCpp(rootDir); GenerateEntryPoints::generateMainQml(rootDir); if (showConfirmationDialog(rootDir)) @@ -139,138 +139,125 @@ bool writeFile(const GeneratableFile &file) return true; } +QString readTemplate(const QString &templatePath) +{ + QFile templatefile(templatePath); + templatefile.open(QIODevice::ReadOnly); + QTextStream stream(&templatefile); + QString content = stream.readAll(); + templatefile.close(); + + return content; +} + } namespace GenerateCmakeLists { +QStringList moduleNames; + const QDir::Filters FILES_ONLY = QDir::Files; const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot; const char CMAKEFILENAME[] = "CMakeLists.txt"; const char QMLDIRFILENAME[] = "qmldir"; +const char MODULEFILENAME[] = "qmlmodules"; -QStringList processDirectory(const FilePath &dir) +bool generateCmakes(const FilePath &rootDir) { - QStringList moduleNames; + moduleNames.clear(); - FilePaths files = dir.dirEntries(FILES_ONLY); - for (FilePath &file : files) { - if (!file.fileName().compare(CMAKEFILENAME)) - files.removeAll(file); - } + FilePath contentDir = rootDir.pathAppended("content"); + FilePath importDir = rootDir.pathAppended("imports"); - if (files.isEmpty()) { - generateSubdirCmake(dir); - FilePaths subDirs = dir.dirEntries(DIRS_ONLY); - for (FilePath &subDir : subDirs) { - QStringList subDirModules = processDirectory(subDir); - moduleNames.append(subDirModules); - } - } - else { - QString moduleName = generateModuleCmake(dir); - if (!moduleName.isEmpty()) { - moduleNames.append(moduleName); - } - } + generateModuleCmake(contentDir); + generateImportCmake(importDir); + generateMainCmake(rootDir); - return moduleNames; + return true; } -const char MAINFILE_REQUIRED_VERSION[] = "cmake_minimum_required(VERSION 3.18)\n\n"; -const char MAINFILE_PROJECT[] = "project(%1 LANGUAGES CXX)\n\n"; -const char MAINFILE_CMAKE_OPTIONS[] = "set(CMAKE_INCLUDE_CURRENT_DIR ON)\nset(CMAKE_AUTOMOC ON)\n\n"; -const char MAINFILE_PACKAGES[] = "find_package(Qt6 COMPONENTS Gui Qml Quick)\n"; -const char MAINFILE_LIBRARIES[] = "set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)\n\n"; -const char MAINFILE_CPP[] = "add_executable(%1 main.cpp)\n\n"; -const char MAINFILE_MAINMODULE[] = "qt6_add_qml_module(%1\n\tURI \"Main\"\n\tVERSION 1.0\n\tNO_PLUGIN\n\tQML_FILES main.qml\n)\n\n"; -const char MAINFILE_LINK_LIBRARIES[] = "target_link_libraries(%1 PRIVATE\n\tQt${QT_VERSION_MAJOR}::Core\n\tQt${QT_VERSION_MAJOR}::Gui\n\tQt${QT_VERSION_MAJOR}::Quick\n\tQt${QT_VERSION_MAJOR}::Qml\n)\n\n"; - -const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; +const char MAIN_CMAKEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincmakelists.tpl"; +const char QMLMODULES_FILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodules.tpl"; void generateMainCmake(const FilePath &rootDir) { //TODO startupProject() may be a terrible way to try to get "current project". It's not necessarily the same thing at all. QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); + QString appName = projectName + "App"; - FilePaths subDirs = rootDir.dirEntries(DIRS_ONLY); + QString cmakeFileContent = GenerateCmake::readTemplate(MAIN_CMAKEFILE_TEMPLATE_PATH).arg(appName); + queueCmakeFile(rootDir, cmakeFileContent); + QString modulesAsPlugins; + for (const QString &moduleName : moduleNames) + modulesAsPlugins.append(" " + moduleName + "plugin\n"); + + QString moduleFileContent = GenerateCmake::readTemplate(QMLMODULES_FILE_TEMPLATE_PATH).arg(appName).arg(modulesAsPlugins); + GenerateCmake::queueFile(rootDir.pathAppended(MODULEFILENAME), moduleFileContent); +} + +const char DO_NOT_EDIT_FILE_COMMENT[] = "### This file is automatically generated by Qt Design Studio.\n### Do not change\n\n"; +const char ADD_SUBDIR[] = "add_subdirectory(%1)\n"; + +void generateImportCmake(const FilePath &dir) +{ QString fileContent; - fileContent.append(MAINFILE_REQUIRED_VERSION); - fileContent.append(QString(MAINFILE_PROJECT).arg(projectName)); - fileContent.append(MAINFILE_CMAKE_OPTIONS); - fileContent.append(MAINFILE_PACKAGES); - fileContent.append(QString(MAINFILE_CPP).arg(projectName)); - fileContent.append(QString(MAINFILE_MAINMODULE).arg(projectName)); - fileContent.append(MAINFILE_LIBRARIES); + fileContent.append(DO_NOT_EDIT_FILE_COMMENT); + + FilePaths subDirs = dir.dirEntries(DIRS_ONLY); for (FilePath &subDir : subDirs) { - QStringList subDirModules = processDirectory(subDir); - if (!subDirModules.isEmpty()) - fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); + generateModuleCmake(subDir); } - fileContent.append("\n"); - fileContent.append(QString(MAINFILE_LINK_LIBRARIES).arg(projectName)); - - createCmakeFile(rootDir, fileContent); + queueCmakeFile(dir, fileContent); } const char MODULEFILE_PROPERTY_SINGLETON[] = "QT_QML_SINGLETON_TYPE"; -const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n\tPROPERTIES\n\t\t%2 %3\n)\n\n"; -const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\tVERSION 1.0\n%2)\n\n"; +const char MODULEFILE_PROPERTY_SET[] = "set_source_files_properties(%1\n PROPERTIES\n %2 %3\n)\n\n"; +const char MODULEFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmodulecmakelists.tpl"; - -QString generateModuleCmake(const FilePath &dir) +void generateModuleCmake(const FilePath &dir) { - QString fileContent; + QString fileTemplate = GenerateCmake::readTemplate(MODULEFILE_TEMPLATE_PATH); const QStringList qmldirFilesOnly(QMLDIRFILENAME); + QString singletonContent; FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); if (!qmldirFileList.isEmpty()) { QStringList singletons = getSingletonsFromQmldirFile(qmldirFileList.first()); for (QString &singleton : singletons) { - fileContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); + singletonContent.append(QString(MODULEFILE_PROPERTY_SET).arg(singleton).arg(MODULEFILE_PROPERTY_SINGLETON).arg("true")); } } QStringList qmlFileList = getDirectoryTreeQmls(dir); QString qmlFiles; for (QString &qmlFile : qmlFileList) - qmlFiles.append(QString("\t\t%1\n").arg(qmlFile)); + qmlFiles.append(QString(" %1\n").arg(qmlFile)); QStringList resourceFileList = getDirectoryTreeResources(dir); QString resourceFiles; for (QString &resourceFile : resourceFileList) - resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); + resourceFiles.append(QString(" %1\n").arg(resourceFile)); QString moduleContent; if (!qmlFiles.isEmpty()) { - moduleContent.append(QString("\tQML_FILES\n%1").arg(qmlFiles)); + moduleContent.append(QString(" QML_FILES\n%1").arg(qmlFiles)); } if (!resourceFiles.isEmpty()) { - moduleContent.append(QString("\tRESOURCES\n%1").arg(resourceFiles)); + moduleContent.append(QString(" RESOURCES\n%1").arg(resourceFiles)); } QString moduleName = dir.fileName(); - fileContent.append(QString(MODULEFILE_CREATE_MODULE).arg(moduleName).arg(moduleContent)); + moduleNames.append(moduleName); - createCmakeFile(dir, fileContent); - - return moduleName; -} - -void generateSubdirCmake(const FilePath &dir) -{ QString fileContent; - FilePaths subDirs = dir.dirEntries(DIRS_ONLY); - - for (FilePath &subDir : subDirs) { - fileContent.append(QString(ADD_SUBDIR).arg(subDir.fileName())); - } - - createCmakeFile(dir, fileContent); + fileContent.append(fileTemplate.arg(singletonContent).arg(moduleName).arg(moduleContent)); + queueCmakeFile(dir, fileContent); } QStringList getSingletonsFromQmldirFile(const FilePath &filePath) @@ -347,7 +334,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir) return resourceFileList; } -void createCmakeFile(const FilePath &dir, const QString &content) +void queueCmakeFile(const FilePath &dir, const QString &content) { FilePath filePath = dir.pathAppended(CMAKEFILENAME); GenerateCmake::queueFile(filePath, content); @@ -370,35 +357,42 @@ bool generateEntryPointFiles(const FilePath &dir) return cppOk && qmlOk; } -const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; +const char MAIN_CPPFILE_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; +const char MAIN_CPPFILE_DIR[] = "src"; const char MAIN_CPPFILE_NAME[] = "main.cpp"; +const char MAIN_CPPFILE_HEADER_TEMPLATE_PATH[] = ":/boilerplatetemplates/qmlprojectmaincppheader.tpl"; +const char MAIN_CPPFILE_HEADER_NAME[] = "import_qml_plugins.h"; +const char MAIN_CPPFILE_HEADER_PLUGIN_LINE[] = "Q_IMPORT_QML_PLUGIN(%1)\n"; bool generateMainCpp(const FilePath &dir) { - QFile templatefile(MAIN_CPPFILE_CONTENT); - templatefile.open(QIODevice::ReadOnly); - QTextStream stream(&templatefile); - QString content = stream.readAll(); - templatefile.close(); + FilePath srcDir = dir.pathAppended(MAIN_CPPFILE_DIR); - FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME); - return GenerateCmake::queueFile(filePath, content); + QString cppContent = GenerateCmake::readTemplate(MAIN_CPPFILE_TEMPLATE_PATH); + FilePath cppFilePath = srcDir.pathAppended(MAIN_CPPFILE_NAME); + bool cppOk = GenerateCmake::queueFile(cppFilePath, cppContent); + + QString modulesAsPlugins; + for (const QString &moduleName : GenerateCmakeLists::moduleNames) + modulesAsPlugins.append( + QString(MAIN_CPPFILE_HEADER_PLUGIN_LINE).arg(moduleName + "plugin")); + + QString headerContent = GenerateCmake::readTemplate(MAIN_CPPFILE_HEADER_TEMPLATE_PATH) + .arg(modulesAsPlugins); + FilePath headerFilePath = srcDir.pathAppended(MAIN_CPPFILE_HEADER_NAME); + bool headerOk = GenerateCmake::queueFile(headerFilePath, headerContent); + + return cppOk && headerOk; } -const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n"; +const char MAIN_QMLFILE_PATH[] = ":/boilerplatetemplates/qmlprojectmainqml.tpl"; const char MAIN_QMLFILE_NAME[] = "main.qml"; bool generateMainQml(const FilePath &dir) { + QString content = GenerateCmake::readTemplate(MAIN_QMLFILE_PATH); FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME); - QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName(); - ProjectExplorer::RunConfiguration *runConfiguration = ProjectExplorer::SessionManager::startupRunConfiguration(); - QString mainClass; - - if (const auto aspect = runConfiguration->aspect()) - mainClass = FilePath::fromString(aspect->mainScript()).baseName(); - - return GenerateCmake::queueFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass)); + return GenerateCmake::queueFile(filePath, content); } } diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h index d1603a1860b..b9f225e9465 100644 --- a/src/plugins/qmldesigner/generatecmakelists.h +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -45,16 +45,17 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir); bool queueFile(const Utils::FilePath &filePath, const QString &fileContent); bool writeFile(const GeneratableFile &file); bool writeQueuedFiles(); +QString readTemplate(const QString &templatePath); } namespace GenerateCmakeLists { +bool generateCmakes(const Utils::FilePath &rootDir); void generateMainCmake(const Utils::FilePath &rootDir); -void generateSubdirCmake(const Utils::FilePath &dir); -QString generateModuleCmake(const Utils::FilePath &dir); -QStringList processDirectory(const Utils::FilePath &dir); +void generateImportCmake(const Utils::FilePath &dir); +void generateModuleCmake(const Utils::FilePath &dir); QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); QStringList getDirectoryTreeQmls(const Utils::FilePath &dir); QStringList getDirectoryTreeResources(const Utils::FilePath &dir); -void createCmakeFile(const Utils::FilePath &filePath, const QString &content); +void queueCmakeFile(const Utils::FilePath &filePath, const QString &content); bool isFileBlacklisted(const QString &fileName); } namespace GenerateEntryPoints { diff --git a/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl b/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl new file mode 100644 index 00000000000..926f7b43be9 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmaincmakelists.tpl @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.18) + +project(%1 LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 COMPONENTS Gui Qml Quick) +add_executable(%1 src/main.cpp) + +target_link_libraries(%1 PRIVATE + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Quick + Qt${QT_VERSION_MAJOR}::Qml +) + +include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules) + diff --git a/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl b/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl new file mode 100644 index 00000000000..60cef09a82c --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmaincppheader.tpl @@ -0,0 +1,8 @@ +/* + * This file is automatically generated by Qt Design Studio. + * Do not change. +*/ + +#include + +%1 diff --git a/src/plugins/qmldesigner/qmlprojectmainqml.tpl b/src/plugins/qmldesigner/qmlprojectmainqml.tpl new file mode 100644 index 00000000000..fa8f6d1cc18 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmainqml.tpl @@ -0,0 +1,6 @@ +import QtQuick +import content + +App { +} + diff --git a/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl b/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl new file mode 100644 index 00000000000..46132d8c1a4 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmodulecmakelists.tpl @@ -0,0 +1,11 @@ +### This file is automatically generated by Qt Design Studio. +### Do not change + +%1 + +qt_add_library(%2 STATIC) +qt6_add_qml_module(%2 + URI "%2" + VERSION 1.0 +%3 +) diff --git a/src/plugins/qmldesigner/qmlprojectmodules.tpl b/src/plugins/qmldesigner/qmlprojectmodules.tpl new file mode 100644 index 00000000000..2cae6017cc3 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmodules.tpl @@ -0,0 +1,16 @@ +### This file is automatically generated by Qt Design Studio. +### Do not change + +qt6_add_qml_module(%1 + URI "Main" + VERSION 1.0 + NO_PLUGIN + QML_FILES main.qml +) + +add_subdirectory(content) +add_subdirectory(imports) + +target_link_libraries(%1 PRIVATE +%2 +) diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 2b6c3ba2d0f..30e06946d85 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -252,10 +252,14 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.askBeforeDeletingAssetCheckBox->setChecked(settings.value( DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool()); - if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { - m_ui.debugGroupBox->hide(); - m_ui.featureTimelineEditorCheckBox->hide(); - } + const auto standaloneMode = settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool(); +#ifdef QT_DEBUG + const auto showDebugSettings = true; +#else + const auto showDebugSettings = settings.value(DesignerSettingsKey::SHOW_DEBUG_SETTINGS).toBool(); +#endif + m_ui.debugGroupBox->setVisible(!standaloneMode || showDebugSettings); + m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode); } void SettingsPageWidget::apply() diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp index c2fd4b45763..1faf0ccbaab 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp @@ -199,7 +199,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) info(openInQDSAppSetting, description + tr(" Learn more about Qt Design Studio here: ") + "Qt Design Studio", - Utils::InfoBarEntry::GlobalSuppression::Enabled); + Utils::InfoBarEntry::GlobalSuppression::Disabled); Core::ICore::infoBar()->addInfo(info); } return; @@ -209,7 +209,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage) Utils::InfoBarEntry info(openInQDSAppSetting, description + "\n" + tr("Do you want to open this file in Qt Design Studio?"), - Utils::InfoBarEntry::GlobalSuppression::Enabled); + Utils::InfoBarEntry::GlobalSuppression::Disabled); info.setCustomButtonInfo(tr("Open in Qt Design Studio"), [filePath] { Core::ICore::infoBar()->removeInfo(openInQDSAppSetting); diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index 1a577a46ce8..9fb63765209 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -353,6 +353,10 @@ bool StudioWelcomePlugin::initialize(const QStringList &arguments, QString *erro void StudioWelcomePlugin::extensionsInitialized() { Core::ModeManager::activateMode(m_welcomeMode->id()); + + // Enable QDS new project dialog + Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); + if (Utils::CheckableMessageBox::shouldAskAgain(Core::ICore::settings(), DO_NOT_SHOW_SPLASHSCREEN_AGAIN_KEY)) { connect(Core::ICore::instance(), &Core::ICore::coreOpened, this, [this] { @@ -370,8 +374,6 @@ void StudioWelcomePlugin::extensionsInitialized() s_view->setSource(QUrl("qrc:/qml/splashscreen/main.qml")); #endif - // disabled by default - Core::ICore::setNewDialogFactory([](QWidget *parent) { return new QdsNewDialog(parent); }); QTC_ASSERT(s_view->rootObject(), qWarning() << "The StudioWelcomePlugin has a runtime depdendency on " diff --git a/src/plugins/studiowelcome/wizardfactories.cpp b/src/plugins/studiowelcome/wizardfactories.cpp index a7cb20b0c62..83a97d455d4 100644 --- a/src/plugins/studiowelcome/wizardfactories.cpp +++ b/src/plugins/studiowelcome/wizardfactories.cpp @@ -28,11 +28,7 @@ #include #include "wizardfactories.h" - -namespace { -// TODO: should be extern, check coreplugin/dialogs/newdialogwidget.cpp -const char BLACKLISTED_CATEGORIES_KEY[] = "Core/NewDialog/BlacklistedCategories"; -} +#include using namespace StudioWelcome; @@ -41,9 +37,6 @@ WizardFactories::WizardFactories(QList &factories, QWidg , m_platform{platform} , m_factories{factories} { - QVariant value = Core::ICore::settings()->value(BLACKLISTED_CATEGORIES_KEY); - m_blacklist = Utils::Id::fromStringList(value.toStringList()); - sortByCategoryAndId(); filter(); m_projectItems = makeProjectItemsGroupedByCategory(); @@ -65,10 +58,10 @@ void WizardFactories::filter() // TODO: perhaps I could use Utils::filtered here. std::copy_if(std::begin(m_factories), std::end(m_factories), std::back_inserter(acceptedFactories), [&](auto *wizard) { - return wizard->isAvailable(m_platform) - && wizard->kind() == Core::IWizardFactory::ProjectWizard - && !m_blacklist.contains(Utils::Id::fromString(wizard->category())); - }); + return wizard->isAvailable(m_platform) + && wizard->kind() == Core::IWizardFactory::ProjectWizard + && wizard->requiredFeatures().contains("QtStudio"); + }); m_factories = acceptedFactories; } @@ -83,7 +76,7 @@ ProjectItem WizardFactories::makeProjectItem(Core::IWizardFactory *f, QWidget *p /*.categoryId =*/f->category(), /*. description =*/f->description(), /*.qmlPath =*/f->detailsPageQmlPath(), - /*.fontIconCode =*/f->fontIcondCode(), + /*.fontIconCode =*/QmlDesigner::Theme::getIconUnicode(f->fontIconName()), /*.create =*/ std::bind(&Core::IWizardFactory::runWizard, f, _1, parent, platform, QVariantMap(), false), }; diff --git a/src/plugins/studiowelcome/wizardfactories.h b/src/plugins/studiowelcome/wizardfactories.h index c41300ff091..9353ecf59f7 100644 --- a/src/plugins/studiowelcome/wizardfactories.h +++ b/src/plugins/studiowelcome/wizardfactories.h @@ -55,7 +55,6 @@ private: std::map makeProjectItemsGroupedByCategory(); private: - QSet m_blacklist; QWidget *m_wizardParent; Utils::Id m_platform; diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index cee8e3cf314..9462b06b829 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -651,7 +651,7 @@ void TextDocument::setFilePath(const Utils::FilePath &newName) { if (newName == filePath()) return; - IDocument::setFilePath(newName.absoluteFilePath()); + IDocument::setFilePath(newName.absoluteFilePath().cleanPath()); } IDocument::ReloadBehavior TextDocument::reloadBehavior(ChangeTrigger state, ChangeType type) const diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 5b15f7c6c4d..d8498901d70 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -189,14 +189,14 @@ public: // Navigation QAction *m_goBack = nullptr; QAction *m_goNext = nullptr; - QLineEdit *m_searchFilter = nullptr; + QPointer m_searchFilter = nullptr; // Cost formatting QAction *m_filterProjectCosts = nullptr; QAction *m_costAbsolute = nullptr; QAction *m_costRelative = nullptr; QAction *m_costRelativeToParent = nullptr; - QComboBox *m_eventCombo = nullptr; + QPointer m_eventCombo; QTimer m_updateTimer; @@ -546,8 +546,10 @@ void CallgrindToolPrivate::setBusyCursor(bool busy) void CallgrindToolPrivate::selectFunction(const Function *func) { if (!func) { - m_flatView->clearSelection(); - m_visualization->setFunction(nullptr); + if (m_flatView) + m_flatView->clearSelection(); + if (m_visualization) + m_visualization->setFunction(nullptr); m_callersModel.clear(); m_calleesModel.clear(); return; @@ -555,15 +557,18 @@ void CallgrindToolPrivate::selectFunction(const Function *func) const QModelIndex index = m_dataModel.indexForObject(func); const QModelIndex proxyIndex = m_proxyModel.mapFromSource(index); - m_flatView->selectionModel()->clearSelection(); - m_flatView->selectionModel()->setCurrentIndex(proxyIndex, - QItemSelectionModel::ClearAndSelect | - QItemSelectionModel::Rows); - m_flatView->scrollTo(proxyIndex); + if (m_flatView) { + m_flatView->selectionModel()->clearSelection(); + m_flatView->selectionModel()->setCurrentIndex(proxyIndex, + QItemSelectionModel::ClearAndSelect | + QItemSelectionModel::Rows); + m_flatView->scrollTo(proxyIndex); + } m_callersModel.setCalls(func->incomingCalls(), func); m_calleesModel.setCalls(func->outgoingCalls(), func); - m_visualization->setFunction(func); + if (m_visualization) + m_visualization->setFunction(func); const Function *item = m_stackBrowser.current(); if (!item || item != func) @@ -689,7 +694,8 @@ void CallgrindToolPrivate::visualisationFunctionSelected(const Function *functio void CallgrindToolPrivate::setParseData(ParseData *data) { // we have new parse data, invalidate filters in the proxy model - m_visualization->setFunction(nullptr); + if (m_visualization) + m_visualization->setFunction(nullptr); // invalidate parse data in the data model delete m_dataModel.parseData(); @@ -705,7 +711,8 @@ void CallgrindToolPrivate::setParseData(ParseData *data) m_calleesModel.setParseData(data); m_callersModel.setParseData(data); - updateEventCombo(); + if (m_eventCombo) + updateEventCombo(); // clear history for new data m_stackBrowser.clear(); diff --git a/src/shared/qbs b/src/shared/qbs index c0f2da3065f..e08c3eedcdd 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit c0f2da3065fd00b4d4193786865f7603e07c4515 +Subproject commit e08c3eedcddbc18b251f56f7158353d8cbec2c81