diff --git a/dist/changes-6.0.0.md b/dist/changes-6.0.0.md index 90db19cc57e..fdf1c71ca57 100644 --- a/dist/changes-6.0.0.md +++ b/dist/changes-6.0.0.md @@ -21,21 +21,30 @@ Editing * Added support for multiple cursor editing (QTCREATORBUG-16013) * Added import and export for font settings (QTCREATORBUG-6833) +* Fixed missing permissions update when files change (QTCREATORBUG-22447) ### C++ * Updated to LLVM 13 -* Added completion and function hint to `clangd` support * Added option for saving open files automatically after refactoring (QTCREATORBUG-25924) +* Added information about source to tooltip on diagnostics * Fixed `Insert Definition` for templates with value parameters (QTCREATORBUG-26113) * Fixed canceling of C++ parsing on configuration change (QTCREATORBUG-24890) +* Fixed crash when checking for refactoring actions (QTCREATORBUG-26316) +* Fixed wrong target compiler option (QTCREATORBUG-25615) +* Fixed parentheses matching (QTCREATORBUG-26400) +* Clangd + * Added warning for older `clangd` versions + * Added support for completion and function hint + * Improved location of generated `compile_commands.json` (QTCREATORBUG-26431) ### QML * Improved wizards for Qt 6.2 (QTCREATORBUG-26170) * Simplified wizards +* Fixed wrong warning on JavaScript equality checks (QTCREATORBUG-25917) ### Language Server Protocol @@ -53,11 +62,16 @@ Projects * Fixed redundant output on process crash (QTCREATORBUG-26049) * Fixed duplicates in file rename dialog (QTCREATORBUG-26268) * Fixed variable expansion for working directory (QTCREATORBUG-26274) +* Fixed possible warning when opening files from compile output + (QTCREATORBUG-26422) +* Fixed that re-detecting compilers removed compilers from kits + (QTCREATORBUG-25697) ### CMake * Removed separate `` node from project tree (QTCREATORBUG-18206, QTCREATORBUG-24609, QTCREATORBUG-25407) +* Improved performance while loading large projects * Fixed that CMake warnings and project loading errors were not added to `Issues` pane (QTCREATORBUG-26231) * Fixed header file handling when mentioned in target sources @@ -70,6 +84,19 @@ Projects * Fixed crash when canceling parsing (QTCREATORBUG-26333) +### Compilation Database + +* Fixed that headers were not shown as part of the project (QTCREATORBUG-26356) + +Debugging +--------- + +### GDB + +* Fixed issue with non-English locale (QTCREATORBUG-26384) +* Fixed variable expansion for `Additional Startup Commands` + (QTCREATORBUG-26382) + Version Control Systems ----------------------- @@ -101,6 +128,10 @@ Platforms * Added details to device settings (QTCREATORBUG-23991) * Added filter field for Android SDK manager +### WebAssembly + +* Fixed running applications (QTCREATORBUG-25905, QTCREATORBUG-26189) + ### Docker * Various improvements @@ -125,12 +156,14 @@ Eike Ziller Fawzi Mohamed Henning Gruendl Ihor Dutchak +Ivan Komissarov Jaroslaw Kobus Johanna Vanhatapio Jonas Karlsson Kai Köhne Kama Wójcik Knud Dollereder +Leena Miettinen Li Xi Loren Burkholder Mahmoud Badri @@ -143,10 +176,13 @@ Petar Perisin Piotr Mikolajczyk Samuel Ghinet Shantanu Tushar +Tapani Mattila Tasuku Suzuki Thiago Macieira Thomas Hartmann Tim Jenssen Tony Leinonen Tor Arne Vestbø +Tuomo Pelkonen +Vikas Pachdha Vladimir Serdyuk diff --git a/doc/qtcreator/examples/accelbubble/AndroidManifest.xml b/doc/qtcreator/examples/accelbubble/AndroidManifest.xml new file mode 100644 index 00000000000..cf737f72d16 --- /dev/null +++ b/doc/qtcreator/examples/accelbubble/AndroidManifest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/doc/qtcreator/examples/accelbubble/Bubble.qml b/doc/qtcreator/examples/accelbubble/Bubble.qml deleted file mode 100644 index 043086fcdc9..00000000000 --- a/doc/qtcreator/examples/accelbubble/Bubble.qml +++ /dev/null @@ -1,12 +0,0 @@ -import QtQuick 2.14 -import QtQuick.Window 2.14 - -Image { - id: bubble - source: "Bluebubble.svg" - smooth: true - property real centerX - property real bubbleCenter - property real centerY - fillMode: Image.PreserveAspectFit -} diff --git a/doc/qtcreator/examples/accelbubble/CMakeLists.txt b/doc/qtcreator/examples/accelbubble/CMakeLists.txt new file mode 100644 index 00000000000..5c15a2b97de --- /dev/null +++ b/doc/qtcreator/examples/accelbubble/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.16) + +project(accelbubble VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.2 COMPONENTS Quick Sensors Svg Xml REQUIRED) + +qt_add_executable(accelbubbleexample + main.cpp + MANUAL_FINALIZATION +) +set_target_properties(accelbubbleexample PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist" +) +set_property(TARGET accelbubbleexample APPEND PROPERTY + QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android +) +qt_add_qml_module(accelbubbleexample + URI accelbubble + VERSION 1.0 + QML_FILES main.qml + RESOURCES Bluebubble.svg +) + +target_compile_definitions(accelbubbleexample + PRIVATE $<$,$>:QT_QML_DEBUG>) +target_link_libraries(accelbubbleexample + PRIVATE Qt6::Quick Qt6::Sensors Qt6::Svg Qt6::Xml) + +qt_finalize_executable(accelbubbleexample) diff --git a/doc/qtcreator/examples/accelbubble/Info.plist b/doc/qtcreator/examples/accelbubble/Info.plist new file mode 100644 index 00000000000..49a90b2c32a --- /dev/null +++ b/doc/qtcreator/examples/accelbubble/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDisplayName + accelbubble + CFBundleExecutable + accelbubble + CFBundleGetInfoString + Created by Qt + CFBundleIdentifier + io.qt.accelbubble + CFBundleName + accelbubble + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NOTE + This file was generated by Qt. + UILaunchStoryboardName + LaunchScreen + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/doc/qtcreator/examples/accelbubble/accelbubble.pro b/doc/qtcreator/examples/accelbubble/accelbubble.pro deleted file mode 100644 index a0caf1e9b2f..00000000000 --- a/doc/qtcreator/examples/accelbubble/accelbubble.pro +++ /dev/null @@ -1,25 +0,0 @@ -QT += quick sensors svg xml - -CONFIG += c++11 - -# You can make your code fail to compile if it uses deprecated APIs. -# In order to do so, uncomment the following line. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -SOURCES += \ - main.cpp - -RESOURCES += qml.qrc - -# Additional import path used to resolve QML modules in Qt Creator's code model -QML_IMPORT_PATH = - -# Additional import path used to resolve QML modules just for Qt Quick Designer -QML_DESIGNER_IMPORT_PATH = - -# Default rules for deployment. -qnx: target.path = /tmp/$${TARGET}/bin -else: unix:!android: target.path = /opt/$${TARGET}/bin -!isEmpty(target.path): INSTALLS += target - -ANDROID_ABIS = armeabi-v7a diff --git a/doc/qtcreator/examples/accelbubble/main.cpp b/doc/qtcreator/examples/accelbubble/main.cpp index fa832817aa3..611f865c2b6 100644 --- a/doc/qtcreator/examples/accelbubble/main.cpp +++ b/doc/qtcreator/examples/accelbubble/main.cpp @@ -1,14 +1,13 @@ #include #include + int main(int argc, char *argv[]) { - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - const QUrl url(QStringLiteral("qrc:/main.qml")); + const QUrl url(u"qrc:/accelbubble/main.qml"_qs); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) diff --git a/doc/qtcreator/examples/accelbubble/main.qml b/doc/qtcreator/examples/accelbubble/main.qml index 6e567e819e9..d25942ea11c 100644 --- a/doc/qtcreator/examples/accelbubble/main.qml +++ b/doc/qtcreator/examples/accelbubble/main.qml @@ -1,74 +1,71 @@ -import QtQuick 2.14 -import QtQuick.Window 2.14 -import QtSensors 5.12 +import QtQuick +import QtSensors Window { - id: window + id: mainWindow + width: 320 + height: 480 visible: true - property alias mainWindow: mainWindow - property alias bubble: bubble - Rectangle { - id: mainWindow - color: "#ffffff" - anchors.fill: parent + title: qsTr("Accelerate Bubble") + readonly property double radians_to_degrees: 180 / Math.PI - Bubble { - id: bubble - x: bubble.centerX - bubbleCenter - y: bubble.centerY - bubbleCenter - bubbleCenter: bubble.width /2 - centerX: mainWindow.width /2 - centerY: mainWindow.height /2 + Accelerometer { + id: accel + dataRate: 100 + active:true - Behavior on y { - SmoothedAnimation { - easing.type: Easing.Linear - duration: 100 - } - } - Behavior on x { - SmoothedAnimation { - easing.type: Easing.Linear - duration: 100 - } - } + onReadingChanged: { + var newX = (bubble.x + calcRoll(accel.reading.x, accel.reading.y, accel.reading.z) * .1) + var newY = (bubble.y - calcPitch(accel.reading.x, accel.reading.y, accel.reading.z) * .1) + + if (isNaN(newX) || isNaN(newY)) + return; + + if (newX < 0) + newX = 0 + + if (newX > mainWindow.width - bubble.width) + newX = mainWindow.width - bubble.width + + if (newY < 18) + newY = 18 + + if (newY > mainWindow.height - bubble.height) + newY = mainWindow.height - bubble.height + + bubble.x = newX + bubble.y = newY } } - Accelerometer { - id: accel - dataRate: 100 - active: true - readonly property double radians_to_degrees: 180 / Math.PI - - onReadingChanged: { - var newX = (bubble.x + calcRoll(accel.reading.x, accel.reading.y, accel.reading.z) * 0.1) - var newY = (bubble.y - calcPitch(accel.reading.x, accel.reading.y, accel.reading.z) * 0.1) - - if (isNaN(newX) || isNaN(newY)) - return; - - if (newX < 0) - newX = 0 - - if (newX > mainWindow.width - bubble.width) - newX = mainWindow.width - bubble.width - - if (newY < 18) - newY = 18 - - if (newY > mainWindow.height - bubble.height) - newY = mainWindow.height - bubble.height - - bubble.x = newX - bubble.y = newY - } - } - function calcPitch(x,y,z) { - return -Math.atan2(y, Math.hypot(x, z)) * accel.radians_to_degrees; + return -Math.atan2(y, Math.hypot(x, z)) * mainWindow.radians_to_degrees; } function calcRoll(x,y,z) { - return -Math.atan2(x, Math.hypot(y, z)) * accel.radians_to_degrees; + return -Math.atan2(x, Math.hypot(y, z)) * mainWindow.radians_to_degrees; + } + + Image { + id: bubble + source: "Bluebubble.svg" + smooth: true + property real centerX: mainWindow.width / 2 + property real centerY: mainWindow.height / 2 + property real bubbleCenter: bubble.width / 2 + x: centerX - bubbleCenter + y: centerY - bubbleCenter + + Behavior on y { + SmoothedAnimation { + easing.type: Easing.Linear + duration: 100 + } + } + Behavior on x { + SmoothedAnimation { + easing.type: Easing.Linear + duration: 100 + } + } } } diff --git a/doc/qtcreator/examples/accelbubble/qml.qrc b/doc/qtcreator/examples/accelbubble/qml.qrc deleted file mode 100644 index 3e6f33859ad..00000000000 --- a/doc/qtcreator/examples/accelbubble/qml.qrc +++ /dev/null @@ -1,7 +0,0 @@ - - - main.qml - Bluebubble.svg - Bubble.qml - - diff --git a/doc/qtcreator/images/qtquick-mobile-tutorial-manifest.png b/doc/qtcreator/images/qtquick-mobile-tutorial-manifest.png new file mode 100644 index 00000000000..297b90637bb Binary files /dev/null and b/doc/qtcreator/images/qtquick-mobile-tutorial-manifest.png differ diff --git a/doc/qtcreator/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc b/doc/qtcreator/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc index c2b6ddc96f5..64426b366fe 100644 --- a/doc/qtcreator/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc +++ b/doc/qtcreator/src/qtquick/creator-only/creator-mobile-app-tutorial.qdoc @@ -36,19 +36,21 @@ \title Creating a Mobile Application - This tutorial describes developing Qt Quick applications for Android and iOS - devices using Qt Quick Controls. - We use \QC to implement a Qt Quick application - that accelerates an SVG (Scalable Vector Graphics) image based on the - changing accelerometer values. + This tutorial describes how to use \QC to develop Qt Quick applications for + Android and iOS devices when using Qt 6 as the minimum Qt version and CMake + as the build system. + + We implement a Qt Quick application that accelerates an SVG (Scalable Vector + Graphics) image based on the changing accelerometer values. + + \note You must have the \l{Qt Sensors} module from Qt 6.2 or later installed + to be able to follow this tutorial. \image creator_android_tutorial_ex_app.png - For more information about the UI choices you have, see \l{User Interfaces}. - \section1 Setting up the Development Environment - To be able to build the application for and run it on a mobile device, you must + To build the application for and run it on a mobile device, you must set up the development environment for the device platform and configure a connection between \QC and the mobile device. @@ -63,183 +65,78 @@ \include qtquick-tutorial-create-empty-project.qdocinc qtquick empty application - \section1 Creating the Accelbubble Main View + \section1 Adding Images as Resources The main view of the application displays an SVG bubble image that moves around the screen when you tilt the device. We use \e {Bluebubble.svg} in this tutorial, but you can use any other - image or component, instead. + image or component instead. - To create the UI in \l{Form Editor}: + For the image to appear when you run the application, you must specify it + as a resource in the \c RESOURCES section of \e CMakeLists.txt file that + the wizard created for you: - \list 1 + \quotefromfile accelbubble/CMakeLists.txt + \skipto qt_add_qml_module + \printuntil ) - \li Open the \e main.qml in \uicontrol {Form Editor}. + \section1 Creating the Accelbubble Main View - \li In \l Library > \uicontrol Components > - \uicontrol {Default Components} > \uicontrol Basic, select - \uicontrol Rectangle and drag-and-drop it to \e Window - in \l Navigator. + We create the main view in the \e main.qml file by adding an \l Image + component with \e Bluebubble.svg as the source: - \li Select the rectangle instance in \uicontrol Navigator to edit its - properties in \l Properties: + \quotefromfile accelbubble/main.qml + \skipto Image + \printuntil smooth - \image qtquick-mobile-app-tutorial-main-view.png "Rectangle in different views" + Next, we add custom properties to position the image in respect to the width + and height of the main window: - \list a - - \li In the \uicontrol ID field enter \e mainWindow, to be able - to reference the rectangle from other places. - - \li Select the \uicontrol Layout tab, and then click - the \inlineimage icons/anchor-fill.png - (\uicontrol {Fill to Parent}) button to anchor the rectangle - to the window. - - \endlist - - \li Select \uicontrol Library > \uicontrol Assets > - \inlineimage plus.png - to locate Bluebubble.svg (or your own image) and add it to - the project folder. - \li Drag and drop the image from \uicontrol Assets to - \e mainWindow in \uicontrol Navigator. \QC creates an - instance of an \l{Images}{Image} component for you - with the path to the image file set as the value of - the \uicontrol Source field in \uicontrol Properties. - - \li In the \uicontrol Properties view, \uicontrol ID field, enter - \e bubble to be able to reference the image from other places. - - \image qtquick-mobile-app-tutorial-image.png "Image file in different views" - - \li Select the \inlineimage icons/alias.png - (\uicontrol Export) button in \uicontrol Navigator to export - \e mainWindow and \e bubble as properties. - - \endlist - - We want to modify the properties of the bubble in ways that are not - supported in \uicontrol {Form Editor}, and therefore we turn it into - a custom component: - - \list 1 - - \li Right-click the image and select - \uicontrol {Move Component into Separate File}. - - \image qtquick-mobile-app-tutorial-bubble-component.png - - \li In the \uicontrol {Component name} field, enter \e Bubble. - - \li Deselect the \uicontrol x and \uicontrol y check boxes, - because we want to use the accelerometer to determine - the location of the bubble on the screen. - - \li Select \uicontrol OK to create \e Bubble.qml. - - \endlist - - \QC creates an instance of the Bubble component in \e main.qml. - - To check your code, you can compare your \e main.qml and - \e {Bubble.qml} with the corresponding example files. - - The UI is now ready and you can add the necessary properties for - making the bubble move. - - \section1 Moving the Bubble - - We add custom properties to position the image in respect to the width - and height of the main window. - - \list 1 - \li Open \e Bubble.qml in \uicontrol {Form Editor}. - \li In \l {Connection View} > \uicontrol Properties, - select the \inlineimage plus.png - button to add a custom property for the Bubble component. - \image qtquick-mobile-app-tutorial-custom-properties.png "Connection View Properties tab" - \li Double-click the value in the \uicontrol Property column, and enter - \e centerY as the name of the property. - \li Double-click the value in the \uicontrol {Property Type} column, - and select \e real as the component of the property. You will specify - the property value later in \uicontrol Properties. - \li Add two more properties of the same type with the names \e centerY - and \e bubbleCenter. - \li Open \e main.qml in \uicontrol {Form Editor}. - \li Select \e bubble in \uicontrol Navigator to specify values for the - custom properties in \uicontrol Properties. - \li In the \uicontrol X field, select \inlineimage icons/action-icon.png - , and then select \uicontrol {Set Binding} to open - \uicontrol {Binding Editor}. - \image qtquick-mobile-app-tutorial-binding-editor1.png "Setting binding for X in Binding Editor" - \li Enter the following value to center the bubble horizontally in the - main window when the application starts: - \c{bubble.centerX - bubbleCenter}. - \li Select \uicontrol OK to close the binding editor and save the - binding. - \li In the \uicontrol X field, set the following binding to center the - bubble vertically: \c{bubble.centerY - bubbleCenter}. - \li In the \uicontrol centerY field, enter the following value to bind - the y coordinate of the bubble center to half the height of the main - window: \c {mainWindow.height /2}. - \image qtquick-mobile-app-tutorial-binding-editor.png "Setting binding for centerX" - \li In the \uicontrol centerX field, bind the x coordinate of - the bubble center to half the width of the main window: - \c {mainWindow.width /2}. - \li In the \uicontrol bubbleCenter field, bind the center of - the bubble to half of its width: \c {bubble.width /2}. - \endlist + \printuntil y: We now want to add code to move the bubble based on Accelerometer sensor - values. This is not supported by \l {Form Editor}, so we will do - it in \l {Text Editor}: + values. First, we add the following import statement: - \list 1 - \li Add the following import statement to \e main.qml: + \quotefromfile accelbubble/main.qml + \skipto QtSensors + \printline QtSensors - \quotefromfile accelbubble/main.qml - \skipto QtSensors - \printline QtSensors + Next, we add the \l{Accelerometer} component with the necessary properties: - \li Add the \l{Accelerometer} component with the necessary properties: + \skipto Accelerometer + \printuntil active - \skipto Accelerometer - \printuntil radians_to_degrees - \skipto } - \printuntil } + Then, we add the following JavaScript functions that calculate the + x and y position of the bubble based on the current Accelerometer + values: - \li Add the following JavaScript functions that calculate the - x and y position of the bubble based on the current Accelerometer - values: + \quotefromfile accelbubble/main.qml + \skipto function + \printuntil } + \printuntil } - \quotefromfile accelbubble/main.qml - \skipto function - \printuntil Math.atan2(x - \printuntil } + We add the following JavaScript code for \c onReadingChanged signal of + Accelerometer component to make the bubble move when the Accelerometer + values change: - \li Add the following JavaScript code for \c onReadingChanged signal of - Accelerometer component to make the bubble move when the Accelerometer - values change: + \quotefromfile accelbubble/main.qml + \skipto onReadingChanged + \printuntil } - \quotefromfile accelbubble/main.qml - \skipto onReadingChanged - \printuntil } + We want to ensure that the position of the bubble is always + within the bounds of the screen. If the Accelerometer returns + \e {not a number} (NaN), the value is ignored and the bubble + position is not updated. - We want to ensure that the position of the bubble is always - within the bounds of the screen. If the Accelerometer returns - \e {not a number} (NaN), the value is ignored and the bubble - position is not updated. - \li Add \l SmoothedAnimation behavior on the \c x and \c y properties of - the bubble to make its movement look smoother. + We add \l SmoothedAnimation behavior on the \c x and \c y properties of + the bubble to make its movement look smoother. - \quotefromfile accelbubble/main.qml - \skipto Behavior - \printuntil x - \printuntil } - \printuntil } - \endlist + \quotefromfile accelbubble/main.qml + \skipto Behavior + \printuntil x + \printuntil } + \printuntil } \section1 Locking Device Orientation @@ -248,35 +145,69 @@ better for the screen orientation to be fixed. To lock the orientation to portrait or landscape on Android, specify it in - an AndroidManifest.xml that you can generate in \QC. For more information, + an \e AndroidManifest.xml that you can generate in \QC. For more information, see \l{Editing Manifest Files}. - On iOS, you can lock the device orientation in an Info.plist file that you - specify in the .pro file as the value of the QMAKE_INFO_PLIST variable. + \image qtquick-mobile-tutorial-manifest.png "Accelbubble manifest file" + + To generate and use a manifest file, you must specify the Android package + source directory, \c QT_ANDROID_PACKAGE_SOURCE_DIR in the \e CMakeLists.txt + file: + + \quotefromfile accelbubble/CMakeLists.txt + \skipto set_property + \printuntil ) + + Because our CMake version is older than 3.19, we must add a manual + finalization step to the \c qt_add_executable function: + + \quotefromfile accelbubble/CMakeLists.txt + \skipto qt_add_executable + \printuntil ) + + We also need to add the \c qt_finalize_executable function: + + \skipto qt_finalize_executable + \printuntil ) + + On iOS, you can lock the device orientation in an \e Info.plist file + that you specify in the \e CMakeLists.txt file as the value of the + \c MACOSX_BUNDLE_INFO_PLIST variable: + + \quotefromfile accelbubble/CMakeLists.txt + \skipto set_target_properties + \printuntil ) \section1 Adding Dependencies - Update the accelbubble.pro file with the following library dependency - information: + You must tell the build system which Qt modules your application needs by + specifying dependencies in the project file. Select \uicontrol Projects to + update the CMake configuration with the following Qt module information: + \c Sensors, \c Svg, \c Xml. - \code - QT += quick sensors svg xml - \endcode + The \e CMakeLists.txt file should contain the following entries that tell + CMake to look up the Qt installation and import the Qt Sensors, Qt SVG, + and Qt XML modules needed by the application: - On iOS, you must link to the above libraries statically, by adding the - plugin names explicitly as values of the QTPLUGIN variable. Specify a - qmake scope for iOS builds (which can also contain the QMAKE_INFO_PLIST - variable): + \quotefromfile accelbubble/CMakeLists.txt + \skipto find_package + \printuntil REQUIRED - \code - ios { - QTPLUGIN += qsvg qsvgicon qtsensors_ios - QMAKE_INFO_PLIST = Info.plist - } - \endcode + You also need to add the Qt modules to the list of target link libraries. + \c target_link_libraries tells CMake that the accelbubble executable uses + the Qt Sensors, Qt SVG, and Qt XML modules by referencing the targets + imported by the \c find_package() call above. This adds the necessary + arguments to the linker and makes sure that the appropriate include + directories and compiler definitions are passed to the C++ compiler. - After adding the dependencies, select \uicontrol Build > \uicontrol {Run qmake} to apply - the changes to the Makefile of the project. + \skipto target_link_libraries(accelbubble + \printuntil Qt6 + + After adding the dependencies, select \uicontrol Build > + \uicontrol {Run CMake} to apply configuration changes. + + For more information about the CMakeLists.txt file, see + \l{Get started with CMake}. \section1 Running the Application @@ -292,7 +223,7 @@ If you are using a device running Android v4.2.2, it should prompt you to verify the connection to allow USB debugging from the PC it is connected to. To avoid such prompts every time you connect the device, select the - \uicontrol {Always allow from the computer} check box, and then select + \uicontrol {Always allow from this computer} check box, and then select \uicontrol OK. \li To run the application on the device, press \key {Ctrl+R}. diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp index 1d110098ff1..6fe0807d01a 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5rendernodeinstanceserver.cpp @@ -184,18 +184,14 @@ void Qt5RenderNodeInstanceServer::completeComponent(const CompleteComponentComma { Qt5NodeInstanceServer::completeComponent(command); - QList instanceList; - foreach (qint32 instanceId, command.instances()) { + const QVector ids = command.instances(); + for (qint32 instanceId : ids) { if (hasInstanceForId(instanceId)) { ServerNodeInstance instance = instanceForId(instanceId); - if (instance.isValid()) { - instanceList.append(instance); + if (instance.isValid()) m_dirtyInstanceSet.insert(instance); - } } } - - nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList)); } void QmlDesigner::Qt5RenderNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml index 98b41da3051..a55280a0401 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/ItemPane.qml @@ -33,7 +33,9 @@ import StudioTheme 1.0 as StudioTheme PropertyEditorPane { id: itemPane - ComponentSection {} + ComponentSection { + showState: true + } GeometrySection {} @@ -82,22 +84,6 @@ PropertyEditorPane { ExpandingSpacer {} } - - PropertyLabel { text: qsTr("State") } - - SecondColumnLayout { - ComboBox { - implicitWidth: StudioTheme.Values.singleControlColumnWidth - + StudioTheme.Values.actionIndicatorWidth - width: implicitWidth - editable: true - backendValue: backendValues.state - model: allStateNames - valueType: ComboBox.String - } - - ExpandingSpacer {} - } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml index 2f45e6b5ebe..ccc77a0e9d9 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/emptyPane.qml @@ -41,7 +41,7 @@ Rectangle { anchors.fill: parent Controls.Label { - text: qsTr("Select an Item in the Form Editor, Navigator or Text Edit View to see its properties.") + text: qsTr("Select a component in Form Editor, Navigator, or Text Editor to see its properties.") font.pixelSize: StudioTheme.Values.myFontSize * 1.5 color: StudioTheme.Values.themeTextColor wrapMode: Text.WordWrap diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml index c6cd287b997..7cded878a1d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Object3DPane.qml @@ -32,7 +32,9 @@ import StudioTheme 1.0 as StudioTheme PropertyEditorPane { id: itemPane - ComponentSection {} + ComponentSection { + showState: majorVersion >= 6 + } Column { anchors.left: parent.left diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml index 8006be8ffa1..30dbeccea9e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml @@ -787,7 +787,9 @@ SecondColumnLayout { ControlLabel { text: "Hex" - width: StudioTheme.Values.colorEditorPopupHexLabelWidth + width: 2 * StudioTheme.Values.colorEditorPopupSpinBoxWidth + + StudioTheme.Values.controlGap + horizontalAlignment: Text.AlignLeft } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml index f285c6a620d..7a2225bee7d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml @@ -32,11 +32,14 @@ import HelperWidgets 2.0 import StudioTheme 1.0 as StudioTheme Section { + id: root caption: qsTr("Component") anchors.left: parent.left anchors.right: parent.right + property bool showState: false + SectionLayout { PropertyLabel { text: qsTr("Type") } @@ -262,5 +265,26 @@ Section { onCanceled: hideWidget() } } + + PropertyLabel { + visible: root.showState + text: qsTr("State") + } + + SecondColumnLayout { + visible: root.showState + + ComboBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + editable: true + backendValue: backendValues.state + model: allStateNames + valueType: ComboBox.String + } + + ExpandingSpacer {} + } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPropertySpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPropertySpinBox.qml index 65b6c14c73d..07cf70265b1 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPropertySpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPropertySpinBox.qml @@ -33,13 +33,13 @@ Item { property string propertyName property alias decimals: spinBox.decimals - property alias value: spinBox.realValue - property alias minimumValue: spinBox.realFrom property alias maximumValue: spinBox.realTo property alias stepSize: spinBox.realStepSize + property alias pixelsPerUnit: spinBox.pixelsPerUnit + width: 90 implicitHeight: spinBox.height @@ -52,6 +52,8 @@ Item { StudioControls.RealSpinBox { id: spinBox + __devicePixelRatio: devicePixelRatio() + width: wrapper.width actionIndicatorVisible: false diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index eb4e1dca8f3..031921c8ba0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -199,8 +199,6 @@ QtObject { property real colorEditorPopupCmoboBoxWidth: 110 property real colorEditorPopupSpinBoxWidth: 54 - property real colorEditorPopupHexLabelWidth: 20 - // Theme Colors property string themePanelBackground: Theme.color(Theme.DSpanelBackground) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index db08418ca78..b7ed718a98d 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -133,8 +133,8 @@ ModelManagerInterface::ModelManagerInterface(QObject *parent) qRegisterMetaType("QmlJS::PathAndLanguage"); qRegisterMetaType("QmlJS::PathsAndLanguages"); - m_defaultProjectInfo.qtQmlPath = QFileInfo( - QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)).canonicalFilePath(); + m_defaultProjectInfo.qtQmlPath = + FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); m_defaultProjectInfo.qtVersionString = QLibraryInfo::version().toString(); updateImportPaths(); @@ -1217,16 +1217,14 @@ void ModelManagerInterface::updateImportPaths() } for (const ProjectInfo &pInfo : qAsConst(m_projects)) { - if (!pInfo.qtQmlPath.isEmpty()) { - allImportPaths.maybeInsert(Utils::FilePath::fromString(pInfo.qtQmlPath), - Dialect::QmlQtQuick2); - } + if (!pInfo.qtQmlPath.isEmpty()) + allImportPaths.maybeInsert(pInfo.qtQmlPath, Dialect::QmlQtQuick2); } { - const QString pathAtt = defaultProjectInfo().qtQmlPath; + const FilePath pathAtt = defaultProjectInfo().qtQmlPath; if (!pathAtt.isEmpty()) - allImportPaths.maybeInsert(Utils::FilePath::fromString(pathAtt), Dialect::QmlQtQuick2); + allImportPaths.maybeInsert(pathAtt, Dialect::QmlQtQuick2); } for (const auto &importPath : defaultProjectInfo().importPaths) { @@ -1435,7 +1433,7 @@ LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const { const ProjectInfo info = projectInfoForPath(doc->fileName()); if (!info.qtQmlPath.isEmpty()) - return m_validSnapshot.libraryInfo(info.qtQmlPath); + return m_validSnapshot.libraryInfo(info.qtQmlPath.toString()); return LibraryInfo(); } @@ -1483,13 +1481,13 @@ ViewerContext ModelManagerInterface::getVContext(const ViewerContext &vCtx, switch (res.language.dialect()) { case Dialect::AnyLanguage: case Dialect::Qml: - maybeAddPath(res, info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath.toString()); Q_FALLTHROUGH(); case Dialect::QmlQtQuick2: case Dialect::QmlQtQuick2Ui: { if (res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) - maybeAddPath(res, info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath.toString()); QList languages = res.language.companionLanguages(); auto addPathsOnLanguageMatch = [&](const PathsAndLanguages &importPaths) { @@ -1534,7 +1532,7 @@ ViewerContext ModelManagerInterface::getVContext(const ViewerContext &vCtx, for (const QString &path : qAsConst(defaultVCtx.paths)) maybeAddPath(res, path); if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml) - maybeAddPath(res, info.qtQmlPath); + maybeAddPath(res, info.qtQmlPath.toString()); if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml || res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) { const auto environemntPaths = environmentImportPaths(); diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 899f9d71245..1fc9260ae94 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -78,10 +78,10 @@ public: // whether trying to run qmldump makes sense bool tryQmlDump = false; bool qmlDumpHasRelocatableFlag = true; - QString qmlDumpPath; - ::Utils::Environment qmlDumpEnvironment; + Utils::FilePath qmlDumpPath; + Utils::Environment qmlDumpEnvironment; - QString qtQmlPath; + Utils::FilePath qtQmlPath; QString qtVersionString; QmlJS::QmlLanguageBundles activeBundle; QmlJS::QmlLanguageBundles extendedBundle; diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index a131b4763a3..c8b80fafa56 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -41,7 +42,9 @@ #include using namespace LanguageUtils; -using namespace QmlJS; +using namespace Utils; + +namespace QmlJS { PluginDumper::PluginDumper(ModelManagerInterface *modelManager) : QObject(modelManager) @@ -86,29 +89,30 @@ void PluginDumper::onLoadBuiltinTypes(const QmlJS::ModelManagerInterface::Projec if (info.qmlDumpPath.isEmpty() || info.qtQmlPath.isEmpty()) return; - const QString importsPath = QDir::cleanPath(info.qtQmlPath); + // FIXME: This doesn't work for non-local paths. + const QString importsPath = QDir::cleanPath(info.qtQmlPath.toString()); if (m_runningQmldumps.values().contains(importsPath)) return; LibraryInfo builtinInfo; if (!force) { const Snapshot snapshot = m_modelManager->snapshot(); - builtinInfo = snapshot.libraryInfo(info.qtQmlPath); + builtinInfo = snapshot.libraryInfo(info.qtQmlPath.toString()); if (builtinInfo.isValid()) return; } builtinInfo = LibraryInfo(LibraryInfo::Found); - m_modelManager->updateLibraryInfo(info.qtQmlPath, builtinInfo); + m_modelManager->updateLibraryInfo(info.qtQmlPath.toString(), builtinInfo); // prefer QTDIR/qml/builtins.qmltypes if available - const QString builtinQmltypesPath = info.qtQmlPath + QLatin1String("/builtins.qmltypes"); + const QString builtinQmltypesPath = info.qtQmlPath.toString() + QLatin1String("/builtins.qmltypes"); if (QFile::exists(builtinQmltypesPath)) { - loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath, builtinInfo); + loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath.toString(), builtinInfo); return; } runQmlDump(info, QStringList(QLatin1String("--builtins")), info.qtQmlPath); - m_qtToInfo.insert(info.qtQmlPath, info); + m_qtToInfo.insert(info.qtQmlPath.toString(), info); } static QString makeAbsolute(const QString &path, const QString &base) @@ -227,10 +231,10 @@ static void printParseWarnings(const QString &libraryPath, const QString &warnin "%2").arg(libraryPath, warning)); } -static QString qmlPluginDumpErrorMessage(QProcess *process) +static QString qmlPluginDumpErrorMessage(QtcProcess *process) { QString errorMessage; - const QString binary = QDir::toNativeSeparators(process->program()); + const QString binary = process->commandLine().executable().toUserOutput(); switch (process->error()) { case QProcess::FailedToStart: errorMessage = PluginDumper::tr("\"%1\" failed to start: %2").arg(binary, process->errorString()); @@ -250,7 +254,7 @@ static QString qmlPluginDumpErrorMessage(QProcess *process) errorMessage = PluginDumper::tr("\"%1\" returned exit code %2.").arg(binary).arg(process->exitCode()); break; } - errorMessage += QLatin1Char('\n') + PluginDumper::tr("Arguments: %1").arg(process->arguments().join(QLatin1Char(' '))); + errorMessage += '\n' + PluginDumper::tr("Arguments: %1").arg(process->commandLine().arguments()); if (process->error() != QProcess::FailedToStart) { const QString stdErr = QString::fromLocal8Bit(process->readAllStandardError()); if (!stdErr.isEmpty()) { @@ -261,11 +265,8 @@ static QString qmlPluginDumpErrorMessage(QProcess *process) return errorMessage; } -void PluginDumper::qmlPluginTypeDumpDone(int exitCode) +void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) { - QProcess *process = qobject_cast(sender()); - if (!process) - return; process->deleteLater(); const QString libraryPath = m_runningQmldumps.take(process); @@ -275,7 +276,7 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode) LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); bool privatePlugin = libraryPath.endsWith(QLatin1String("private")); - if (exitCode != 0) { + if (process->exitCode() != 0) { const QString errorMessages = qmlPluginDumpErrorMessage(process); if (!privatePlugin) ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); @@ -333,11 +334,8 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode) } } -void PluginDumper::qmlPluginTypeDumpError(QProcess::ProcessError) +void PluginDumper::qmlPluginTypeDumpError(QtcProcess *process) { - QProcess *process = qobject_cast(sender()); - if (!process) - return; process->deleteLater(); const QString libraryPath = m_runningQmldumps.take(process); @@ -632,20 +630,17 @@ void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths, }); } -void PluginDumper::runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, - const QStringList &arguments, const QString &importPath) +void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info, + const QStringList &arguments, const FilePath &importPath) { - QDir wd = QDir(importPath); - wd.cdUp(); - QProcess *process = new QProcess(this); - process->setEnvironment(info.qmlDumpEnvironment.toStringList()); - QString workingDir = wd.canonicalPath(); - process->setWorkingDirectory(workingDir); - connect(process, QOverload::of(&QProcess::finished), - this, &PluginDumper::qmlPluginTypeDumpDone); - connect(process, &QProcess::errorOccurred, this, &PluginDumper::qmlPluginTypeDumpError); - process->start(info.qmlDumpPath, arguments); - m_runningQmldumps.insert(process, importPath); + auto process = new QtcProcess(this); + process->setEnvironment(info.qmlDumpEnvironment); + process->setWorkingDirectory(importPath); + process->setCommand({info.qmlDumpPath, arguments}); + connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); }); + connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); }); + process->start(); + m_runningQmldumps.insert(process, importPath.toString()); } void PluginDumper::dump(const Plugin &plugin) @@ -691,7 +686,7 @@ void PluginDumper::dump(const Plugin &plugin) args << plugin.importUri; args << plugin.importVersion; args << (plugin.importPath.isEmpty() ? QLatin1String(".") : plugin.importPath); - runQmlDump(info, args, plugin.qmldirPath); + runQmlDump(info, args, FilePath::fromString(plugin.qmldirPath)); } /*! @@ -792,3 +787,5 @@ QString PluginDumper::resolvePlugin(const QDir &qmldirPath, const QString &qmldi } return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, prefix); } + +} // QmlJS diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index 3b664d507bb..98aadfbce40 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -27,9 +27,10 @@ #include +#include + #include #include -#include QT_BEGIN_NAMESPACE class QDir; @@ -57,8 +58,8 @@ private: Q_INVOKABLE void onLoadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri, const QString &importVersion); Q_INVOKABLE void dumpAllPlugins(); - void qmlPluginTypeDumpDone(int exitCode); - void qmlPluginTypeDumpError(QProcess::ProcessError error); + void qmlPluginTypeDumpDone(Utils::QtcProcess *process); + void qmlPluginTypeDumpError(Utils::QtcProcess *process); void pluginChanged(const QString &pluginLibrary); private: @@ -87,7 +88,8 @@ private: QList objects; }; - void runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, const QStringList &arguments, const QString &importPath); + void runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, const QStringList &arguments, + const Utils::FilePath &importPath); void dump(const Plugin &plugin); QFuture loadQmlTypeDescription(const QStringList &path) const; QString buildQmltypesPath(const QString &name) const; @@ -116,7 +118,7 @@ private: ModelManagerInterface *m_modelManager; Utils::FileSystemWatcher *m_pluginWatcher; - QHash m_runningQmldumps; + QHash m_runningQmldumps; QList m_plugins; QHash m_libraryToPluginIndex; QHash m_qtToInfo; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index f4b715eece6..810f770e0e3 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -475,6 +475,12 @@ static ProcessInterface *newProcessInstance(QObject *parent, QtcProcess::Process class QtcProcessPrivate : public QObject { public: + enum StartFailure { + NoFailure, + WrongFileNameFailure, + OtherFailure + }; + explicit QtcProcessPrivate(QtcProcess *parent, QtcProcess::ProcessImpl processImpl, ProcessMode processMode) @@ -488,13 +494,11 @@ public: connect(m_process, &ProcessInterface::finished, this, &QtcProcessPrivate::slotFinished); connect(m_process, &ProcessInterface::errorOccurred, - this, &QtcProcessPrivate::slotError); + this, [this](QProcess::ProcessError error) { handleError(error, OtherFailure); }); connect(m_process, &ProcessInterface::readyReadStandardOutput, this, &QtcProcessPrivate::handleReadyReadStandardOutput); connect(m_process, &ProcessInterface::readyReadStandardError, this, &QtcProcessPrivate::handleReadyReadStandardError); - connect(&m_timer, &QTimer::timeout, this, &QtcProcessPrivate::slotTimeout); - m_timer.setInterval(1000); } void handleReadyReadStandardOutput() @@ -530,7 +534,7 @@ public: } else { m_process->setErrorString(QLatin1String( "The program \"%1\" does not exist or is not executable.").arg(program)); - slotError(QProcess::FailedToStart); + handleError(QProcess::FailedToStart, WrongFileNameFailure); } } @@ -546,14 +550,13 @@ public: void slotTimeout(); void slotFinished(int exitCode, QProcess::ExitStatus e); - void slotError(QProcess::ProcessError); + void handleError(QProcess::ProcessError error, StartFailure startFailure); void clearForRun(); QtcProcess::Result interpretExitCode(int exitCode); QTextCodec *m_codec = QTextCodec::codecForLocale(); - QTimer m_timer; - QEventLoop m_eventLoop; + QEventLoop *m_eventLoop = nullptr; QtcProcess::Result m_result = QtcProcess::StartFailed; QProcess::ExitStatus m_exitStatus = QProcess::NormalExit; ChannelBuffer m_stdOut; @@ -562,7 +565,7 @@ public: int m_hangTimerCount = 0; int m_maxHangTimerCount = defaultMaxHangTimerCount; - bool m_startFailure = false; + StartFailure m_startFailure = NoFailure; bool m_timeOutMessageBoxEnabled = false; bool m_waitingForUser = false; bool m_processUserEvents = false; @@ -576,7 +579,7 @@ void QtcProcessPrivate::clearForRun() m_stdErr.clearForRun(); m_stdErr.codec = m_codec; m_result = QtcProcess::StartFailed; - m_startFailure = false; + m_startFailure = NoFailure; } QtcProcess::Result QtcProcessPrivate::interpretExitCode(int exitCode) @@ -963,7 +966,7 @@ void QtcProcess::setResult(Result result) int QtcProcess::exitCode() const { - if (d->m_startFailure) + if (d->m_startFailure == QtcProcessPrivate::WrongFileNameFailure) return 255; // This code is being returned by QProcess when FailedToStart error occurred return d->m_process->exitCode(); } @@ -1065,7 +1068,7 @@ void QtcProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode) QProcess::ProcessError QtcProcess::error() const { - if (d->m_startFailure) + if (d->m_startFailure == QtcProcessPrivate::WrongFileNameFailure) return QProcess::FailedToStart; return d->m_process->error(); } @@ -1407,17 +1410,24 @@ void QtcProcess::runBlocking() // On Windows, start failure is triggered immediately if the // executable cannot be found in the path. Do not start the // event loop in that case. - if (!d->m_startFailure) { - d->m_timer.start(); + if (d->m_startFailure == QtcProcessPrivate::NoFailure) { + QTimer timer(this); + connect(&timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout); + timer.setInterval(1000); + timer.start(); #ifdef QT_GUI_LIB if (isGuiThread()) QApplication::setOverrideCursor(Qt::WaitCursor); #endif - d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + QEventLoop eventLoop(this); + QTC_ASSERT(!d->m_eventLoop, return); + d->m_eventLoop = &eventLoop; + eventLoop.exec(QEventLoop::ExcludeUserInputEvents); + d->m_eventLoop = nullptr; d->m_stdOut.append(d->m_process->readAllStandardOutput()); d->m_stdErr.append(d->m_process->readAllStandardError()); - d->m_timer.stop(); + timer.stop(); #ifdef QT_GUI_LIB if (isGuiThread()) QApplication::restoreOverrideCursor(); @@ -1510,7 +1520,8 @@ void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus status) m_result = QtcProcess::TerminatedAbnormally; break; } - m_eventLoop.quit(); + if (m_eventLoop) + m_eventLoop->quit(); m_stdOut.handleRest(); m_stdErr.handleRest(); @@ -1518,7 +1529,7 @@ void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus status) emit q->finished(); } -void QtcProcessPrivate::slotError(QProcess::ProcessError error) +void QtcProcessPrivate::handleError(QProcess::ProcessError error, StartFailure startFailure) { m_hangTimerCount = 0; if (debug) @@ -1526,8 +1537,9 @@ void QtcProcessPrivate::slotError(QProcess::ProcessError error) // Was hang detected before and killed? if (m_result != QtcProcess::Hang) m_result = QtcProcess::StartFailed; - m_startFailure = true; - m_eventLoop.quit(); + m_startFailure = startFailure; + if (m_eventLoop) + m_eventLoop->quit(); emit q->errorOccurred(error); } diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp index e45662012e5..463f01e43de 100644 --- a/src/libs/utils/theme/theme.cpp +++ b/src/libs/utils/theme/theme.cpp @@ -67,6 +67,28 @@ void setThemeApplicationPalette() QApplication::setPalette(m_creatorTheme->palette()); } +static void maybeForceMacOSLight(Theme *theme) +{ +#ifdef Q_OS_MACOS + // Match the native UI theme and palette with the creator + // theme by forcing light aqua for light creator themes. + if (theme && !theme->flag(Theme::DarkUserInterface)) + Internal::forceMacOSLightAquaApperance(); +#else + Q_UNUSED(theme) +#endif +} + +static bool macOSSystemIsDark() +{ +#ifdef Q_OS_MACOS + static bool systemIsDark = Internal::currentAppearanceIsDark(); + return systemIsDark; +#else + return false; +#endif +} + void setCreatorTheme(Theme *theme) { if (m_creatorTheme == theme) @@ -74,13 +96,7 @@ void setCreatorTheme(Theme *theme) delete m_creatorTheme; m_creatorTheme = theme; -#ifdef Q_OS_MACOS - // Match the native UI theme and palette with the creator - // theme by forcing light aqua for light creator themes. - if (theme && !theme->flag(Theme::DarkUserInterface)) - Internal::forceMacOSLightAquaApperance(); -#endif - + maybeForceMacOSLight(theme); setThemeApplicationPalette(); } @@ -251,6 +267,8 @@ bool Theme::systemUsesDarkMode() bool ok; const auto setting = QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok); return ok && setting == 0; + } else if (HostOsInfo::isMacHost()) { + return macOSSystemIsDark(); } return false; } @@ -270,6 +288,13 @@ static QPalette copyPalette(const QPalette &p) return res; } +void Theme::setInitialPalette(Theme *initTheme) +{ + macOSSystemIsDark(); // initialize value for system mode + maybeForceMacOSLight(initTheme); + initialPalette(); +} + QPalette Theme::initialPalette() { static QPalette palette = copyPalette(QApplication::palette()); diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index c2b34d07978..3f3249d71ea 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -485,6 +485,8 @@ public: static bool systemUsesDarkMode(); static QPalette initialPalette(); + static void setInitialPalette(Theme *initTheme); + protected: Theme(Theme *originTheme, QObject *parent = nullptr); ThemePrivate *d; diff --git a/src/libs/utils/theme/theme_mac.h b/src/libs/utils/theme/theme_mac.h index 55e6d12bc02..8c48e52734c 100644 --- a/src/libs/utils/theme/theme_mac.h +++ b/src/libs/utils/theme/theme_mac.h @@ -29,6 +29,7 @@ namespace Utils { namespace Internal { void forceMacOSLightAquaApperance(); +bool currentAppearanceIsDark(); } // Internal } // Utils diff --git a/src/libs/utils/theme/theme_mac.mm b/src/libs/utils/theme/theme_mac.mm index 8d95c88630b..d1d623e3a80 100644 --- a/src/libs/utils/theme/theme_mac.mm +++ b/src/libs/utils/theme/theme_mac.mm @@ -49,5 +49,17 @@ void forceMacOSLightAquaApperance() NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; } +bool currentAppearanceIsDark() +{ +#if __has_builtin(__builtin_available) + if (__builtin_available(macOS 10.14, *)) { + auto appearance = [NSApp.effectiveAppearance + bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]]; + return [appearance isEqualToString:NSAppearanceNameDarkAqua]; + } +#endif + return false; +} + } // Internal } // Utils diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index dc6b42754c1..f42c5524acf 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -423,7 +423,7 @@ void AndroidBuildApkWidget::onOpenSslCheckBoxChanged() Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath(); QFile projectFile(projectPath.toString()); if (!projectFile.open(QIODevice::ReadWrite | QIODevice::Text)) { - qWarning() << "Cound't open project file to add OpenSSL extra libs: " << projectPath; + qWarning() << "Cannot open project file to add OpenSSL extra libs: " << projectPath; return; } @@ -494,27 +494,31 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id) bool AndroidBuildApkStep::init() { - if (!AbstractProcessStep::init()) + if (!AbstractProcessStep::init()) { + reportWarningOrError(tr("\"%1\" step failed initialization.").arg(displayName()), + Task::Error); return false; + } if (m_signPackage) { qCDebug(buildapkstepLog) << "Signing enabled"; // check keystore and certificate passwords if (!verifyKeystorePassword() || !verifyCertificatePassword()) { - qCDebug(buildapkstepLog) << "Init failed. Keystore/Certificate password verification failed."; + reportWarningOrError(tr("Keystore/Certificate password verification failed."), + Task::Error); return false; } - if (buildType() != BuildConfiguration::Release) { - const QString error = tr("Warning: Signing a debug or profile package."); - emit addOutput(error, OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Warning, error)); - } + if (buildType() != BuildConfiguration::Release) + reportWarningOrError(tr("Warning: Signing a debug or profile package."), Task::Warning); } QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); - if (!version) + if (!version) { + reportWarningOrError(tr("The Qt version for kit %1 is invalid.").arg(kit()->displayName()), + Task::Error); return false; + } const QVersionNumber sdkToolsVersion = AndroidConfigurations::currentConfig().sdkToolsVersion(); if (sdkToolsVersion >= QVersionNumber(25, 3, 0) @@ -526,16 +530,14 @@ bool AndroidBuildApkStep::init() "is %2") .arg(sdkToolsVersion.toString()) .arg("5.9.0/5.6.3"); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); return false; } } else if (version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { const QString error = tr("The minimum Qt version required for Gradle build to work is %1. " "It is recommended to install the latest Qt version.") .arg("5.4.0"); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); return false; } @@ -545,8 +547,7 @@ bool AndroidBuildApkStep::init() = tr("The API level set for the APK is less than the minimum required by the kit." "\nThe minimum API level required by the kit is %1.") .arg(minSDKForKit); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); return false; } @@ -568,16 +569,16 @@ bool AndroidBuildApkStep::init() m_inputFile = AndroidQtVersion::androidDeploymentSettings(target()); if (m_inputFile.isEmpty()) { - qCDebug(buildapkstepLog) << "no input file" << target()->activeBuildKey(); m_skipBuilding = true; + reportWarningOrError(tr("No valid input file for \"%1\".").arg(target()->activeBuildKey()), + Task::Warning); return true; } m_skipBuilding = false; if (m_buildTargetSdk.isEmpty()) { - const QString error = tr("Android build SDK not defined. Check Android settings."); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Android build SDK version is not defined. Check Android settings.") + , Task::Error); return false; } @@ -665,10 +666,8 @@ void AndroidBuildApkStep::processFinished(int exitCode, QProcess::ExitStatus sta bool AndroidBuildApkStep::verifyKeystorePassword() { if (!m_keystorePath.exists()) { - const QString error = tr("Cannot sign the package. Invalid keystore path (%1).") - .arg(m_keystorePath.toString()); - emit addOutput(error, OutputFormat::ErrorMessage); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("Cannot sign the package. Invalid keystore path (%1).") + .arg(m_keystorePath.toString()), Task::Error); return false; } @@ -687,10 +686,8 @@ bool AndroidBuildApkStep::verifyCertificatePassword() { if (!AndroidManager::checkCertificateExists(m_keystorePath.toString(), m_keystorePasswd, m_certificateAlias)) { - const QString error = tr("Cannot sign the package. Certificate alias %1 does not exist.") - .arg(m_certificateAlias); - emit addOutput(error, OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Cannot sign the package. Certificate alias %1 does not exist.") + .arg(m_certificateAlias), Task::Error); return false; } @@ -731,9 +728,8 @@ static bool copyFileIfNewer(const FilePath &sourceFilePath, void AndroidBuildApkStep::doRun() { if (m_skipBuilding) { - const QString error = tr("Android deploy settings file not found, not building an APK."); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Android deploy settings file not found, not building an APK."), + Task::Error); emit finished(true); return; } @@ -743,8 +739,11 @@ void AndroidBuildApkStep::doRun() const QString buildKey = target()->activeBuildKey(); QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); - if (!version) + if (!version) { + reportWarningOrError(tr("The Qt version for kit %1 is invalid.") + .arg(kit()->displayName()), Task::Error); return false; + } const FilePath buildDir = buildDirectory(); const FilePath androidBuildDir = AndroidManager::androidBuildDirectory(target()); @@ -752,10 +751,9 @@ void AndroidBuildApkStep::doRun() FilePath androidLibsDir = androidBuildDir / "libs" / abi; if (!androidLibsDir.exists()) { if (!androidLibsDir.ensureWritableDir()) { - const QString error = tr("The Android build folder %1 wasn't found and " - "couldn't be created.").arg(androidLibsDir.toUserOutput()); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("The Android build folder %1 was not found and could " + "not be created.").arg(androidLibsDir.toUserOutput()), + Task::Error); return false; } else if (version->qtVersion() >= QtSupport::QtVersionNumber{6, 0, 0} && version->qtVersion() <= QtSupport::QtVersionNumber{6, 1, 1}) { @@ -769,11 +767,10 @@ void AndroidBuildApkStep::doRun() continue; if (!from.copyFile(to)) { - const QString error = tr("Couldn't copy the target's lib file %1 to the " - "Android build folder %2.") - .arg(fileName, androidLibsDir.toUserOutput()); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Cannot copy the target's lib file %1 to the " + "Android build folder %2.") + .arg(fileName, androidLibsDir.toUserOutput()), + Task::Error); return false; } } @@ -799,8 +796,13 @@ void AndroidBuildApkStep::doRun() applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.toString(); FilePath androidLibsDir = androidBuildDir / "libs" / androidAbis.first(); for (const FilePath &target : targets) { - if (!copyFileIfNewer(target, androidLibsDir.pathAppended(target.fileName()))) + if (!copyFileIfNewer(target, androidLibsDir.pathAppended(target.fileName()))) { + reportWarningOrError( + tr("Cannot copy file \"%1\" to Android build libs folder \"%2\".") + .arg(target.toUserOutput()).arg(androidLibsDir.toUserOutput()), + Task::Error); return false; + } } deploySettings["target-architecture"] = androidAbis.first(); } else { @@ -818,8 +820,14 @@ void AndroidBuildApkStep::doRun() FilePath androidLibsDir = androidBuildDir / "libs" / abi; for (const FilePath &target : targets) { if (target.endsWith(targetSuffix)) { - if (!copyFileIfNewer(target, androidLibsDir.pathAppended(target.fileName()))) + const FilePath destination = androidLibsDir.pathAppended(target.fileName()); + if (!copyFileIfNewer(target, destination)) { + reportWarningOrError( + tr("Cannot copy file \"%1\" to Android build libs folder \"%2\".") + .arg(target.toUserOutput()).arg(androidLibsDir.toUserOutput()), + Task::Error); return false; + } architectures[abi] = AndroidManager::archTriplet(abi); } } @@ -846,16 +854,18 @@ void AndroidBuildApkStep::doRun() deploySettings["qml-root-path"] = qmlRootPath; QFile f{m_inputFile.toString()}; - if (!f.open(QIODevice::WriteOnly)) + if (!f.open(QIODevice::WriteOnly)) { + reportWarningOrError(tr("Cannot open androiddeployqt input file \"%1\" for writing.") + .arg(m_inputFile.toUserOutput()), Task::Error); return false; + } f.write(QJsonDocument{deploySettings}.toJson()); return true; }; if (!setup()) { - const QString error = tr("Cannot set up Android, not building an APK."); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Cannot set up \"%1\", not building an APK.").arg(displayName()), + Task::Error); emit finished(false); return; } @@ -863,6 +873,13 @@ void AndroidBuildApkStep::doRun() AbstractProcessStep::doRun(); } +void AndroidBuildApkStep::reportWarningOrError(const QString &message, Task::TaskType type) +{ + qCDebug(buildapkstepLog) << message; + emit addOutput(message, OutputFormat::ErrorMessage); + TaskHub::addTask(BuildSystemTask(type, message)); +} + void AndroidBuildApkStep::processStarted() { emit addOutput(tr("Starting: \"%1\" %2") diff --git a/src/plugins/android/androidbuildapkstep.h b/src/plugins/android/androidbuildapkstep.h index 5bbe2cf3be8..2b439faf8af 100644 --- a/src/plugins/android/androidbuildapkstep.h +++ b/src/plugins/android/androidbuildapkstep.h @@ -92,6 +92,8 @@ private: void doRun() override; + void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type); + bool m_buildAAB = false; bool m_signPackage = false; bool m_verbose = false; diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 65f55080630..6377ee73ee1 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1408,7 +1408,7 @@ Environment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config) return env; } -const AndroidConfig &AndroidConfigurations::currentConfig() +AndroidConfig &AndroidConfigurations::currentConfig() { return m_instance->m_config; // ensure that m_instance is initialized } diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 2fc22ddbc2e..2110125ad70 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -211,7 +211,7 @@ class ANDROID_EXPORT AndroidConfigurations : public QObject Q_OBJECT public: - static const AndroidConfig ¤tConfig(); + static AndroidConfig ¤tConfig(); static Internal::AndroidSdkManager *sdkManager(); static void setConfig(const AndroidConfig &config); static AndroidConfigurations *instance(); diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 0910f483d69..1915955d242 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -112,9 +112,8 @@ bool AndroidDeployQtStep::init() { QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); if (!version) { - qCDebug(deployStepLog, - "The Qt version for kit %s is not valid.", - qPrintable(kit()->displayName())); + reportWarningOrError(tr("The Qt version for kit %1 is invalid.").arg(kit()->displayName()), + Task::Error); return false; } @@ -122,18 +121,21 @@ bool AndroidDeployQtStep::init() m_androidABIs = AndroidManager::applicationAbis(target()); if (m_androidABIs.isEmpty()) { - const QString error = tr("No Android arch set by the .pro file."); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("No Android architecture (ABI) is set by the project."), + Task::Error); return false; } - emit addOutput(tr("Initializing deployment to Android device/simulator"), OutputFormat::Stdout); + emit addOutput(tr("Initializing deployment to Android device/simulator"), + OutputFormat::NormalMessage); RunConfiguration *rc = target()->activeRunConfiguration(); - QTC_ASSERT(rc, return false); + QTC_ASSERT(rc, reportWarningOrError(tr("The kit's run configuration is invalid."), Task::Error); + return false); BuildConfiguration *bc = target()->activeBuildConfiguration(); - QTC_ASSERT(bc, return false); + QTC_ASSERT(bc, reportWarningOrError(tr("The kit's build configuration is invalid."), + Task::Error); + return false); auto androidBuildApkStep = bc->buildSteps()->firstOfType(); const int minTargetApi = AndroidManager::minimumSDK(target()); @@ -142,9 +144,12 @@ bool AndroidDeployQtStep::init() // Try to re-use user-provided information from an earlier step of the same type. BuildStepList *bsl = stepList(); - QTC_ASSERT(bsl, return false); + QTC_ASSERT(bsl, reportWarningOrError(tr("The kit's build steps list is invalid."), Task::Error); + return false); auto androidDeployQtStep = bsl->firstOfType(); - QTC_ASSERT(androidDeployQtStep, return false); + QTC_ASSERT(androidDeployQtStep, + reportWarningOrError(tr("The kit's deploy configuration is invalid."), Task::Error); + return false); AndroidDeviceInfo info; if (androidDeployQtStep != this) info = androidDeployQtStep->m_deviceInfo; @@ -159,44 +164,44 @@ bool AndroidDeployQtStep::init() if (selectedAbis.isEmpty()) selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); + // TODO: use AndroidDevice directly instead of AndroidDeviceInfo. if (!info.isValid()) { const IDevice *dev = DeviceKitAspect::device(kit()).data(); + if (!dev) { + reportWarningOrError(tr("The deployment device \"%1\" is invalid."), Task::Error); + return false; + } + info = AndroidDevice::androidDeviceInfoFromIDevice(dev); m_deviceInfo = info; // Keep around for later steps if (!info.isValid()) { - const QString error = tr("The deployment device \"%1\" is invalid.") - .arg(dev->displayName()); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("The deployment device \"%1\" is invalid.") + .arg(dev->displayName()), Task::Error); return false; } const AndroidDevice *androidDev = static_cast(dev); if (androidDev && !androidDev->canSupportAbis(selectedAbis)) { - const QString error = tr("The deployment device \"%1\" doesn't support the " + const QString error = tr("The deployment device \"%1\" does not support the " "architectures used by the kit.\n" "The kit supports \"%2\", but the device uses \"%3\".") .arg(dev->displayName()).arg(selectedAbis.join(", ")) .arg(androidDev->supportedAbis().join(", ")); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); return false; } if (androidDev && !androidDev->canHandleDeployments()) { - const QString error = tr("The deployment device \"%1\" is disconnected.") - .arg(dev->displayName()); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("The deployment device \"%1\" is disconnected.") + .arg(dev->displayName()), Task::Error); return false; } } const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); if (qt && qt->supportsMultipleQtAbis() && !selectedAbis.contains(info.cpuAbi.first())) { - TaskHub::addTask(DeploymentTask( - Task::Warning, + TaskHub::addTask(DeploymentTask(Task::Warning, tr("Android: The main ABI of the deployment device (%1) is not selected. The app " "execution or debugging might not work properly. Add it from Projects > Build > " "Build Steps > qmake > ABIs.") @@ -213,7 +218,7 @@ bool AndroidDeployQtStep::init() AndroidManager::setDeviceApiLevel(target(), info.sdk); AndroidManager::setDeviceAbis(target(), info.cpuAbi); - emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::Stdout); + emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value(); if (m_uninstallPreviousPackageRun) @@ -223,8 +228,10 @@ bool AndroidDeployQtStep::init() if (m_useAndroiddeployqt) { const QString buildKey = target()->activeBuildKey(); const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey); - if (!node) + if (!node) { + reportWarningOrError(tr("The deployment step's project node is invalid."), Task::Error); return false; + } m_apkPath = Utils::FilePath::fromString(node->data(Constants::AndroidApk).toString()); if (!m_apkPath.isEmpty()) { m_manifestName = Utils::FilePath::fromString(node->data(Constants::AndroidManifest).toString()); @@ -233,16 +240,13 @@ bool AndroidDeployQtStep::init() } else { QString jsonFile = AndroidQtVersion::androidDeploymentSettings(target()).toString(); if (jsonFile.isEmpty()) { - const QString error = tr("Cannot find the androiddeploy Json file."); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("Cannot find the androiddeployqt input JSON file."), + Task::Error); return false; } m_command = version->hostBinPath(); if (m_command.isEmpty()) { - const QString error = tr("Cannot find the androiddeployqt tool."); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("Cannot find the androiddeployqt tool."), Task::Error); return false; } m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix(); @@ -302,13 +306,14 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy() if (m_uninstallPreviousPackageRun) { packageName = AndroidManager::packageName(m_manifestName); if (packageName.isEmpty()) { - const QString error = tr("Cannot find the package name."); - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(tr("Cannot find the package name from the Android Manifest " + "file \"%1\".").arg(m_manifestName.toUserOutput()), + Task::Error); return Failure; } - qCDebug(deployStepLog) << "Uninstalling previous package"; - emit addOutput(tr("Uninstall previous package %1.").arg(packageName), OutputFormat::NormalMessage); + const QString msg = tr("Uninstalling the previous package \"%1\".").arg(packageName); + qCDebug(deployStepLog) << msg; + emit addOutput(msg, OutputFormat::NormalMessage); runCommand({m_adbPath, AndroidDeviceInfo::adbSelector(m_serialNumber) << "uninstall" << packageName}); @@ -337,8 +342,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy() m_process->start(); - emit addOutput(tr("Starting: \"%1\"").arg(cmd.toUserOutput()), - BuildStep::OutputFormat::NormalMessage); + emit addOutput(tr("Starting: \"%1\"").arg(cmd.toUserOutput()), OutputFormat::NormalMessage); while (!m_process->waitForFinished(200)) { if (m_process->state() == QProcess::NotRunning) @@ -369,24 +373,27 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy() if (exitStatus == QProcess::NormalExit && exitCode == 0) { emit addOutput(tr("The process \"%1\" exited normally.").arg(m_command.toUserOutput()), - BuildStep::OutputFormat::NormalMessage); + OutputFormat::NormalMessage); } else if (exitStatus == QProcess::NormalExit) { const QString error = tr("The process \"%1\" exited with code %2.") .arg(m_command.toUserOutput(), QString::number(exitCode)); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); } else { const QString error = tr("The process \"%1\" crashed.").arg(m_command.toUserOutput()); - emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); } if (deployError != NoError) { - if (m_uninstallPreviousPackageRun) + if (m_uninstallPreviousPackageRun) { deployError = Failure; // Even re-install failed. Set to Failure. + reportWarningOrError( + tr("Installing the app failed even after uninstalling the previous one."), + Task::Error); + } } else if (exitCode != 0 || exitStatus != QProcess::NormalExit) { // Set the deployError to Failure when no deployError code was detected // but the adb tool failed otherwise relay the detected deployError. + reportWarningOrError(tr("Installing the app failed with an unknown error."), Task::Error); deployError = Failure; } @@ -421,7 +428,8 @@ void AndroidDeployQtStep::slotAskForUninstall(DeployErrorCode errorCode) mask <<= 1; } - uninstallMsg.append(tr("\nUninstalling the installed package may solve the issue.\nDo you want to uninstall the existing package?")); + uninstallMsg.append(tr("\nUninstalling the installed package may solve the issue.\n" + "Do you want to uninstall the existing package?")); int button = QMessageBox::critical(nullptr, tr("Install failed"), uninstallMsg, QMessageBox::Yes, QMessageBox::No); m_askForUninstall = button == QMessageBox::Yes; @@ -432,10 +440,13 @@ bool AndroidDeployQtStep::runImpl() if (!m_avdName.isEmpty()) { QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, cancelChecker()); qCDebug(deployStepLog) << "Deploying to AVD:" << m_avdName << serialNumber; - if (serialNumber.isEmpty()) + if (serialNumber.isEmpty()) { + reportWarningOrError(tr("The deployment AVD \"%1\" cannot be started.") + .arg(m_avdName), Task::Error); return false; + } m_serialNumber = serialNumber; - qCDebug(deployStepLog) << "Target device serial number change:" << serialNumber; + qCDebug(deployStepLog) << "Deployment device serial number changed:" << serialNumber; AndroidManager::setDeviceSerialNumber(target(), serialNumber); } @@ -451,7 +462,8 @@ bool AndroidDeployQtStep::runImpl() if (!m_filesToPull.isEmpty()) emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage); - // Note that values are not necessarily unique, e.g. app_process is looked up in several directories + // Note that values are not necessarily unique, e.g. app_process is looked up in several + // directories for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) { QFile::remove(itr.value()); } @@ -464,8 +476,7 @@ bool AndroidDeployQtStep::runImpl() const QString error = tr("Package deploy: Failed to pull \"%1\" to \"%2\".") .arg(itr.key()) .arg(itr.value()); - emit addOutput(error, OutputFormat::ErrorMessage); - TaskHub::addTask(DeploymentTask(Task::Error, error)); + reportWarningOrError(error, Task::Error); } } @@ -518,11 +529,8 @@ void AndroidDeployQtStep::runCommand(const CommandLine &command) buildProc.setCommand(command); buildProc.setProcessUserEventWhileRunning(); buildProc.runBlocking(); - if (buildProc.result() != QtcProcess::FinishedWithSuccess) { - const QString error = buildProc.exitMessage(); - emit addOutput(error, OutputFormat::ErrorMessage); - TaskHub::addTask(DeploymentTask(Task::Error, error)); - } + if (buildProc.result() != QtcProcess::FinishedWithSuccess) + reportWarningOrError(buildProc.exitMessage(), Task::Error); } QWidget *AndroidDeployQtStep::createConfigWidget() @@ -590,6 +598,13 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::parseDeployErrors( return errorCode; } +void AndroidDeployQtStep::reportWarningOrError(const QString &message, Task::TaskType type) +{ + qCDebug(deployStepLog) << message; + emit addOutput(message, OutputFormat::ErrorMessage); + TaskHub::addTask(DeploymentTask(type, message)); +} + // AndroidDeployQtStepFactory AndroidDeployQtStepFactory::AndroidDeployQtStepFactory() diff --git a/src/plugins/android/androiddeployqtstep.h b/src/plugins/android/androiddeployqtstep.h index 1a5acc84b89..0e0f1c3054e 100644 --- a/src/plugins/android/androiddeployqtstep.h +++ b/src/plugins/android/androiddeployqtstep.h @@ -83,8 +83,15 @@ private: void stdError(const QString &line); DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const; - friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { e1 = static_cast((int)e1 | (int)e2); } - friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { return static_cast((int)e1 | (int)e2); } + friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { + e1 = static_cast((int)e1 | (int)e2); + } + + friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { + return static_cast((int)e1 | (int)e2); + } + + void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type); Utils::FilePath m_manifestName; QString m_serialNumber; diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index de8a89e7f76..3d4376a98fd 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -627,8 +627,8 @@ AndroidDeviceManager *AndroidDeviceManager::instance() AndroidDeviceManager::AndroidDeviceManager(QObject *parent) : QObject(parent), - m_avdManager(m_androidConfig), - m_androidConfig(AndroidConfigurations::currentConfig()) + m_androidConfig(AndroidConfigurations::currentConfig()), + m_avdManager(m_androidConfig) { connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() { m_devicesUpdaterTimer.stop(); diff --git a/src/plugins/android/androiddevice.h b/src/plugins/android/androiddevice.h index e99d8bd4cec..a9133de3f32 100644 --- a/src/plugins/android/androiddevice.h +++ b/src/plugins/android/androiddevice.h @@ -90,7 +90,7 @@ public: ProjectExplorer::IDevice::Ptr create() const override; private: - AndroidConfig m_androidConfig; + const AndroidConfig &m_androidConfig; }; class AndroidDeviceManager : public QObject @@ -116,8 +116,8 @@ private: QFutureWatcher> m_devicesFutureWatcher; QFutureWatcher> m_removeAvdFutureWatcher; QTimer m_devicesUpdaterTimer; + AndroidConfig &m_androidConfig; AndroidAvdManager m_avdManager; - AndroidConfig m_androidConfig; }; } // namespace Internal diff --git a/src/plugins/android/androidpackageinstallationstep.cpp b/src/plugins/android/androidpackageinstallationstep.cpp index 17e641443ae..ba7f0700aba 100644 --- a/src/plugins/android/androidpackageinstallationstep.cpp +++ b/src/plugins/android/androidpackageinstallationstep.cpp @@ -72,6 +72,8 @@ private: void setupOutputFormatter(OutputFormatter *formatter) final; void doRun() final; + void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type); + QStringList m_androidDirsToClean; }; @@ -89,11 +91,16 @@ AndroidPackageInstallationStep::AndroidPackageInstallationStep(BuildStepList *bs bool AndroidPackageInstallationStep::init() { - if (!AbstractProcessStep::init()) + if (!AbstractProcessStep::init()) { + reportWarningOrError(tr("\"%1\" step failed initialization.").arg(displayName()), + Task::TaskType::Error); return false; + } ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit()); - QTC_ASSERT(tc, return false); + QTC_ASSERT(tc, reportWarningOrError(tr("\"%1\" step has an invalid C++ toolchain.") + .arg(displayName()), Task::TaskType::Error); + return false); QString dirPath = nativeAndroidBuildPath(); const QString innerQuoted = ProcessArgs::quoteArg(dirPath); @@ -140,8 +147,9 @@ void AndroidPackageInstallationStep::doRun() if (!dir.isEmpty() && androidDir.exists()) { emit addOutput(tr("Removing directory %1").arg(dir), OutputFormat::NormalMessage); if (!androidDir.removeRecursively(&error)) { - emit addOutput(error, OutputFormat::Stderr); - TaskHub::addTask(BuildSystemTask(Task::Error, error)); + reportWarningOrError(tr("Failed to clean \"%1\" from the previous build, with " + "error:\n%2").arg(androidDir.toUserOutput()).arg(error), + Task::TaskType::Error); emit finished(false); return; } @@ -167,13 +175,21 @@ void AndroidPackageInstallationStep::doRun() qPrintable(file.fileName())); } else { qCDebug(packageInstallationStepLog, - "Cound't add %s to the package. The QML debugger might not work properly.", + "Cannot add %s to the package. The QML debugger might not work properly.", qPrintable(file.fileName())); } } } } +void AndroidPackageInstallationStep::reportWarningOrError(const QString &message, + Task::TaskType type) +{ + qCDebug(packageInstallationStepLog) << message; + emit addOutput(message, OutputFormat::ErrorMessage); + TaskHub::addTask(BuildSystemTask(type, message)); +} + // // AndroidPackageInstallationStepFactory // diff --git a/src/plugins/android/androidqmlpreviewworker.h b/src/plugins/android/androidqmlpreviewworker.h index c837570e01f..68e541a8ec8 100644 --- a/src/plugins/android/androidqmlpreviewworker.h +++ b/src/plugins/android/androidqmlpreviewworker.h @@ -78,7 +78,7 @@ private: Utils::FilePath createQmlrcFile(const Utils::FilePath &workFolder, const QString &basename); ProjectExplorer::RunControl *m_rc = nullptr; - AndroidConfig m_androidConfig; + const AndroidConfig &m_androidConfig; QString m_serialNumber; QStringList m_avdAbis; int m_viewerPid = -1; diff --git a/src/plugins/android/androidsdkdownloader.cpp b/src/plugins/android/androidsdkdownloader.cpp index 16be29fa25f..1ed8e045810 100644 --- a/src/plugins/android/androidsdkdownloader.cpp +++ b/src/plugins/android/androidsdkdownloader.cpp @@ -48,8 +48,8 @@ namespace Internal { * @brief Download Android SDK tools package from within Qt Creator. */ AndroidSdkDownloader::AndroidSdkDownloader() + : m_androidConfig(AndroidConfigurations::currentConfig()) { - m_androidConfig = AndroidConfigurations::currentConfig(); connect(&m_manager, &QNetworkAccessManager::finished, this, &AndroidSdkDownloader::downloadFinished); } diff --git a/src/plugins/android/androidsdkdownloader.h b/src/plugins/android/androidsdkdownloader.h index b462c4b510c..a018d3d10cd 100644 --- a/src/plugins/android/androidsdkdownloader.h +++ b/src/plugins/android/androidsdkdownloader.h @@ -72,7 +72,7 @@ private: QNetworkReply *m_reply = nullptr; Utils::FilePath m_sdkFilename; QProgressDialog *m_progressDialog = nullptr; - AndroidConfig m_androidConfig; + const AndroidConfig &m_androidConfig; }; } // Internal diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 44fc69e92b9..dfa22056370 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -108,7 +108,7 @@ private: Ui_AndroidSettingsWidget m_ui; AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr; - AndroidConfig m_androidConfig{AndroidConfigurations::currentConfig()}; + AndroidConfig &m_androidConfig{AndroidConfigurations::currentConfig()}; AndroidSdkManager m_sdkManager{m_androidConfig}; AndroidSdkDownloader m_sdkDownloader; diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index ff92e8c74a3..8406ea0e678 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -116,7 +116,7 @@ bool AndroidToolChain::isValid() const void AndroidToolChain::addToEnvironment(Environment &env) const { - AndroidConfig config = AndroidConfigurations::currentConfig(); + const AndroidConfig &config = AndroidConfigurations::currentConfig(); env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHostFromNdk(m_ndkLocation)); const Utils::FilePath javaHome = config.openJDKLocation(); if (javaHome.exists()) { @@ -178,7 +178,7 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath) static QList uniqueNdksForCurrentQtVersions() { - AndroidConfig config = AndroidConfigurations::currentConfig(); + const AndroidConfig &config = AndroidConfigurations::currentConfig(); auto androidQtVersions = QtSupport::QtVersionManager::versions( [](const QtSupport::BaseQtVersion *v) { diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp index d3418f39ca8..795537e1db7 100644 --- a/src/plugins/android/avddialog.cpp +++ b/src/plugins/android/avddialog.cpp @@ -51,9 +51,9 @@ static Q_LOGGING_CATEGORY(avdDialogLog, "qtc.android.avdDialog", QtWarningMsg) AvdDialog::AvdDialog(const AndroidConfig &config, QWidget *parent) : QDialog(parent), + m_androidConfig(config), m_sdkManager(m_androidConfig), - m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")), - m_androidConfig(config) + m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")) { m_avdDialog.setupUi(this); m_hideTipTimer.setInterval(2000); diff --git a/src/plugins/android/avddialog.h b/src/plugins/android/avddialog.h index 3f95bed2130..45169bd79f4 100644 --- a/src/plugins/android/avddialog.h +++ b/src/plugins/android/avddialog.h @@ -71,12 +71,12 @@ private: }; Ui::AddNewAVDDialog m_avdDialog; - AndroidSdkManager m_sdkManager; CreateAvdInfo m_createdAvdInfo; QTimer m_hideTipTimer; QRegularExpression m_allowedNameChars; QList m_deviceDefinitionsList; - AndroidConfig m_androidConfig; + const AndroidConfig &m_androidConfig; + AndroidSdkManager m_sdkManager; QMap deviceTypeToStringMap; }; } diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index ac7ec7e2b4f..e31cc4d6f55 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1272,9 +1272,11 @@ void ClangdTestHighlighting::test() }; const TextEditor::HighlightingResults results = findResults(); - QEXPECT_FAIL("typedef as underlying type in enum declaration", - "https://github.com/clangd/clangd/issues/878", - Abort); + if (client()->versionNumber() < QVersionNumber(14)) { + QEXPECT_FAIL("typedef as underlying type in enum declaration", + "https://github.com/clangd/clangd/issues/878", + Abort); + } QEXPECT_FAIL("Q_PROPERTY (property name)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (getter)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp index 2dfb70076a2..0973bbc519a 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildstep.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -376,13 +377,15 @@ void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets) CommandLine CMakeBuildStep::cmakeCommand() const { - CMakeTool *tool = CMakeKitAspect::cmakeTool(kit()); + CommandLine cmd; + if (CMakeTool *tool = CMakeKitAspect::cmakeTool(kit())) + cmd.setExecutable(tool->cmakeExecutable()); - CommandLine cmd(tool ? tool->cmakeExecutable() : FilePath(), {}); - QString buildDirectory = "."; + FilePath buildDirectory = "."; if (buildConfiguration()) - buildDirectory = buildConfiguration()->buildDirectory().path(); - cmd.addArgs({"--build", buildDirectory}); + buildDirectory = buildConfiguration()->buildDirectory(); + + cmd.addArgs({"--build", buildDirectory.onDevice(cmd.executable()).path()}); cmd.addArg("--target"); cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index d8f24b43623..e43db3176f9 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -72,7 +72,11 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & CMakeTool *cmake = parameters.cmakeTool(); QTC_ASSERT(parameters.isValid() && cmake, return); - const FilePath buildDirectory = parameters.buildDirectory; + const FilePath cmakeExecutable = cmake->cmakeExecutable(); + + const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable); + const FilePath buildDirectory = parameters.buildDirectory.onDevice(cmakeExecutable); + if (!buildDirectory.exists()) { QString msg = tr("The build directory \"%1\" does not exist") .arg(buildDirectory.toUserOutput()); @@ -119,12 +123,8 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & connect(process.get(), &QtcProcess::finished, this, &CMakeProcess::handleProcessFinished); - const FilePath cmakeExecutable = cmake->cmakeExecutable(); - const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable); - CommandLine commandLine(cmakeExecutable); - commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(), - "-B", buildDirectory.mapToDevicePath()}); + commandLine.addArgs({"-S", sourceDirectory.path(), "-B", buildDirectory.path()}); commandLine.addArgs(arguments); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 9f881802c5d..f201ab523be 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -140,11 +140,12 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target, config << "--config" << bc->cmakeBuildType(); } - QString buildDirectory = "."; + FilePath buildDirectory = "."; if (bc) - buildDirectory = bc->buildDirectory().toString(); + buildDirectory = bc->buildDirectory(); - cmd.arguments << "--build" << buildDirectory << "--target" << installTarget << config; + cmd.arguments << "--build" << buildDirectory.onDevice(cmd.command).mapToDevicePath() + << "--target" << installTarget << config; cmd.environment.set("DESTDIR", QDir::toNativeSeparators(installRoot)); return cmd; diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp index f4019500157..26f03a5f48c 100644 --- a/src/plugins/coreplugin/coreplugin.cpp +++ b/src/plugins/coreplugin/coreplugin.cpp @@ -162,10 +162,11 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage) return false; } const CoreArguments args = parseArguments(arguments); - Theme::initialPalette(); // Initialize palette before setting it Theme *themeFromArg = ThemeEntry::createTheme(args.themeId); - setCreatorTheme(themeFromArg ? themeFromArg - : ThemeEntry::createTheme(ThemeEntry::themeSetting())); + Theme *theme = themeFromArg ? themeFromArg + : ThemeEntry::createTheme(ThemeEntry::themeSetting()); + Theme::setInitialPalette(theme); // Initialize palette before setting it + setCreatorTheme(theme); InfoBar::initialize(ICore::settings()); new ActionManager(this); ActionManager::setPresentationModeEnabled(args.presentationMode); diff --git a/src/plugins/coreplugin/foldernavigationwidget.cpp b/src/plugins/coreplugin/foldernavigationwidget.cpp index 931505d137d..55ab5701262 100644 --- a/src/plugins/coreplugin/foldernavigationwidget.cpp +++ b/src/plugins/coreplugin/foldernavigationwidget.cpp @@ -455,8 +455,13 @@ void FolderNavigationWidget::insertRootDirectory( m_rootSelector->setCurrentIndex(index); if (previousIndex < m_rootSelector->count()) m_rootSelector->removeItem(previousIndex); - if (m_autoSync) // we might find a better root for current selection now - handleCurrentEditorChanged(Core::EditorManager::currentEditor()); + if (Core::EditorManager::currentEditor()) { + if (m_autoSync) // we might find a better root for current selection now + handleCurrentEditorChanged(Core::EditorManager::currentEditor()); + } else if (m_rootAutoSync) { + // assume the new root is better (e.g. because a project was opened) + m_rootSelector->setCurrentIndex(index); + } } void FolderNavigationWidget::removeRootDirectory(const QString &id) diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index 182691c2a45..6ef037d36be 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -62,6 +62,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -76,8 +80,6 @@ #include #include -#include - #include #include #include @@ -101,6 +103,7 @@ enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 }; using namespace Core; using namespace CPlusPlus; +using namespace ProjectExplorer; using namespace TextEditor; using namespace Utils; @@ -1045,7 +1048,7 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit) } void CppEditorWidget::findLinkAt(const QTextCursor &cursor, - Utils::ProcessLinkCallback &&processLinkCallback, + ProcessLinkCallback &&processLinkCallback, bool resolveTarget, bool inNextSplit) { @@ -1054,9 +1057,36 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor, const Utils::FilePath &filePath = textDocument()->filePath(); + // Let following a "leaf" C++ symbol take us to the designer, if we are in a generated + // UI header. + QTextCursor c(cursor); + c.select(QTextCursor::WordUnderCursor); + ProcessLinkCallback callbackWrapper = [start = c.selectionStart(), end = c.selectionEnd(), + doc = QPointer(cursor.document()), callback = std::move(processLinkCallback), + filePath](const Link &link) { + const int linkPos = doc ? Text::positionInText(doc, link.targetLine, link.targetColumn + 1) + : -1; + if (link.targetFilePath == filePath && linkPos >= start && linkPos < end) { + const QString fileName = filePath.fileName(); + if (fileName.startsWith("ui_") && fileName.endsWith(".h")) { + const QString uiFileName = fileName.mid(3, fileName.length() - 4) + "ui"; + for (const Project * const project : SessionManager::projects()) { + const auto nodeMatcher = [uiFileName](Node *n) { + return n->filePath().fileName() == uiFileName; + }; + if (const Node * const uiNode = project->rootProjectNode() + ->findNode(nodeMatcher)) { + EditorManager::openEditor(uiNode->filePath()); + return; + } + } + } + } + callback(link); + }; followSymbolInterface().findLink( CursorInEditor{cursor, filePath, this, textDocument()}, - std::move(processLinkCallback), + std::move(callbackWrapper), resolveTarget, d->m_modelManager->snapshot(), d->m_lastSemanticInfo.doc, diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 6f5d9d07d17..f1f01935115 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -3116,8 +3116,10 @@ public: defaultImplTargetComboBox->insertItems(0, implTargetStrings); connect(defaultImplTargetComboBox, qOverload(&QComboBox::currentIndexChanged), this, [this](int index) { - for (QComboBox * const cb : qAsConst(m_implTargetBoxes)) - cb->setCurrentIndex(index); + for (int i = 0; i < m_implTargetBoxes.size(); ++i) { + if (!m_candidates.at(i)->type()->asFunctionType()->isPureVirtual()) + static_cast(m_implTargetBoxes.at(i))->setCurrentIndex(index); + } }); const auto defaultImplTargetLayout = new QHBoxLayout; defaultImplTargetLayout->addWidget(new QLabel(tr("Default implementation location:"))); @@ -3128,10 +3130,13 @@ public: oo.showFunctionSignatures = true; oo.showReturnTypes = true; for (int i = 0; i < m_candidates.size(); ++i) { + const Function * const func = m_candidates.at(i)->type()->asFunctionType(); + QTC_ASSERT(func, continue); const auto implTargetComboBox = new QComboBox; m_implTargetBoxes.append(implTargetComboBox); implTargetComboBox->insertItems(0, implTargetStrings); - const Symbol * const func = m_candidates.at(i); + if (func->isPureVirtual()) + implTargetComboBox->setCurrentIndex(0); candidatesLayout->addWidget(new QLabel(oo.prettyType(func->type(), func->name())), i, 0); candidatesLayout->addWidget(implTargetComboBox, i, 1); diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 58d0ef0b050..e1c8be48c31 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -1079,7 +1079,7 @@ void CdbEngine::activateFrame(int index) if (debug || debugLocals) qDebug("activateFrame idx=%d '%s' %d", index, - qPrintable(frame.file), frame.line); + qPrintable(frame.file.toUserOutput()), frame.line); stackHandler()->setCurrentIndex(index); gotoLocation(frame); if (m_pythonVersion > 0x030000) @@ -2615,7 +2615,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = nullptr) frame.level = QString::number(i); const GdbMi fullName = frameMi["fullname"]; if (fullName.isValid()) { - frame.file = Utils::FileUtils::normalizedPathName(fullName.data()); + frame.file = Utils::FilePath::fromString(fullName.data()).normalizedPathName(); frame.line = frameMi["line"].data().toInt(); frame.usable = false; // To be decided after source path mapping. const GdbMi languageMi = frameMi["language"]; @@ -2661,12 +2661,12 @@ unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto) return ParseStackStepOut; } if (hasFile) { - const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file); + const NormalizedSourceFileName fileName = sourceMapNormalizeFileNameFromDebugger(frames.at(i).file.toString()); if (!fileName.exists && i == 0 && sourceStepInto) { showMessage("Step into: Hit frame with no source, step out...", LogMisc); return ParseStackStepOut; } - frames[i].file = fileName.fileName; + frames[i].file = FilePath::fromString(fileName.fileName); frames[i].usable = fileName.exists; if (current == -1 && frames[i].usable) current = i; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index f2dd9f09a00..f2441aff33a 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -161,7 +161,7 @@ static bool debuggerActionsEnabledHelper(DebuggerState state) Location::Location(const StackFrame &frame, bool marker) { - m_fileName = Utils::FilePath::fromString(frame.file); + m_fileName = frame.file; m_lineNumber = frame.line; m_needsMarker = marker; m_functionName = frame.function; diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index daa8749e021..80e9cecba7c 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -912,9 +912,14 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm } } - m_runParameters.inferior = runnable(); + Runnable inferior = runnable(); + const FilePath &debuggerExecutable = m_runParameters.debugger.command.executable(); + inferior.command.setExecutable(inferior.command.executable().onDevice(debuggerExecutable)); + inferior.workingDirectory = inferior.workingDirectory.onDevice(debuggerExecutable); // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) - m_runParameters.inferior.workingDirectory = m_runParameters.inferior.workingDirectory.normalizedPathName(); + inferior.workingDirectory = inferior.workingDirectory.normalizedPathName(); + m_runParameters.inferior = inferior; + setUseTerminal(allowTerminal == DoAllowTerminal && m_runParameters.useTerminal); const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH"); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index efda99b07fa..814b71ecfb3 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -718,10 +718,9 @@ DebuggerToolTipContext::DebuggerToolTipContext() { } -static bool filesMatch(const QString &file1, const QString &file2) +static bool filesMatch(const FilePath &file1, const FilePath &file2) { - return FilePath::fromString(QFileInfo(file1).canonicalFilePath()) - == FilePath::fromString(QFileInfo(file2).canonicalFilePath()); + return file1.canonicalPath() == file2.canonicalPath(); } bool DebuggerToolTipContext::matchesFrame(const StackFrame &frame) const @@ -945,7 +944,7 @@ void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const w.writeStartElement(toolTipElementC); QXmlStreamAttributes attributes; // attributes.append(toolTipClassAttributeC, QString::fromLatin1(metaObject()->className())); - attributes.append(fileNameAttributeC, context.fileName); + attributes.append(fileNameAttributeC, context.fileName.toString()); if (!context.function.isEmpty()) attributes.append(functionAttributeC, context.function); attributes.append(textPositionAttributeC, QString::number(context.position)); @@ -1019,15 +1018,15 @@ void DebuggerToolTipManagerPrivate::updateVisibleToolTips() return; } - const QString fileName = toolTipEditor->textDocument()->filePath().toString(); - if (fileName.isEmpty()) { + const FilePath filePath = toolTipEditor->textDocument()->filePath(); + if (filePath.isEmpty()) { hideAllToolTips(); return; } // Reposition and show all tooltips of that file. for (DebuggerToolTipHolder *tooltip : qAsConst(m_tooltips)) { - if (tooltip->context.fileName == fileName) + if (tooltip->context.fileName == filePath) tooltip->positionShow(toolTipEditor->editorWidget()); else tooltip->widget->hide(); @@ -1085,7 +1084,8 @@ void DebuggerToolTipManagerPrivate::loadSessionData() if (readStartElement(r, toolTipElementC)) { const QXmlStreamAttributes attributes = r.attributes(); DebuggerToolTipContext context; - context.fileName = attributes.value(fileNameAttributeC).toString(); + context.fileName = FilePath::fromString( + attributes.value(fileNameAttributeC).toString()); context.position = attributes.value(textPositionAttributeC).toString().toInt(); context.line = attributes.value(textLineAttributeC).toString().toInt(); context.column = attributes.value(textColumnAttributeC).toString().toInt(); @@ -1197,7 +1197,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested DebuggerToolTipContext context; context.engineType = m_engine->objectName(); - context.fileName = document->filePath().toString(); + context.fileName = document->filePath(); context.position = pos; editorWidget->convertPosition(pos, &context.line, &context.column); QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, diff --git a/src/plugins/debugger/debuggertooltipmanager.h b/src/plugins/debugger/debuggertooltipmanager.h index 251addefbef..2c6853fcb60 100644 --- a/src/plugins/debugger/debuggertooltipmanager.h +++ b/src/plugins/debugger/debuggertooltipmanager.h @@ -27,6 +27,8 @@ #include "debuggerconstants.h" +#include + #include #include #include @@ -46,7 +48,7 @@ public: bool isSame(const DebuggerToolTipContext &other) const; QString toolTip() const; - QString fileName; + Utils::FilePath fileName; int position; int line; int column; diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index 620c37fb313..57f3383942d 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -346,11 +346,11 @@ void PdbEngine::refreshState(const GdbMi &reportedState) void PdbEngine::refreshLocation(const GdbMi &reportedLocation) { StackFrame frame; - frame.file = reportedLocation["file"].data(); + frame.file = Utils::FilePath::fromString(reportedLocation["file"].data()); frame.line = reportedLocation["line"].toInt(); - frame.usable = QFileInfo(frame.file).isReadable(); + frame.usable = frame.file.isReadableFile(); if (state() == InferiorRunOk) { - showMessage(QString("STOPPED AT: %1:%2").arg(frame.file).arg(frame.line)); + showMessage(QString("STOPPED AT: %1:%2").arg(frame.file.toUserOutput()).arg(frame.line)); gotoLocation(frame); notifyInferiorSpontaneousStop(); updateAll(); @@ -535,7 +535,7 @@ void PdbEngine::refreshStack(const GdbMi &stack) for (const GdbMi &item : stack["frames"]) { StackFrame frame; frame.level = item["level"].data(); - frame.file = item["file"].data(); + frame.file = Utils::FilePath::fromString(item["file"].data()); frame.function = item["function"].data(); frame.module = item["function"].data(); frame.line = item["line"].toInt(); @@ -544,7 +544,7 @@ void PdbEngine::refreshStack(const GdbMi &stack) if (usable.isValid()) frame.usable = usable.data().toInt(); else - frame.usable = QFileInfo(frame.file).isReadable(); + frame.usable = frame.file.isReadableFile(); frames.append(frame); } bool canExpand = stack["hasmore"].toInt(); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 416e1693bd1..b071ca6eb1b 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -2036,8 +2036,9 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal) stackFrame.function = extractString(body.value("func")); if (stackFrame.function.isEmpty()) stackFrame.function = QCoreApplication::translate("QmlEngine", "Anonymous Function"); - stackFrame.file = engine->toFileInProject(extractString(body.value("script"))); - stackFrame.usable = QFileInfo(stackFrame.file).isReadable(); + stackFrame.file = FilePath::fromString( + engine->toFileInProject(extractString(body.value("script")))); + stackFrame.usable = stackFrame.file.isReadableFile(); stackFrame.receiver = extractString(body.value("receiver")); stackFrame.line = body.value("line").toInt() + 1; diff --git a/src/plugins/debugger/sourceagent.cpp b/src/plugins/debugger/sourceagent.cpp index 7c1946e8121..02bddf6bfa3 100644 --- a/src/plugins/debugger/sourceagent.cpp +++ b/src/plugins/debugger/sourceagent.cpp @@ -134,7 +134,7 @@ void SourceAgent::updateLocationMarker() d->editor->textDocument()->removeMark(d->locationMark); delete d->locationMark; d->locationMark = nullptr; - if (d->engine->stackHandler()->currentFrame().file == d->path) { + if (d->engine->stackHandler()->currentFrame().file == Utils::FilePath::fromString(d->path)) { int lineNumber = d->engine->stackHandler()->currentFrame().line; d->locationMark = new TextMark(Utils::FilePath(), lineNumber, diff --git a/src/plugins/debugger/sourceutils.cpp b/src/plugins/debugger/sourceutils.cpp index 5b0b63cbff7..79850bdc420 100644 --- a/src/plugins/debugger/sourceutils.cpp +++ b/src/plugins/debugger/sourceutils.cpp @@ -190,7 +190,7 @@ static void blockRecursion(const Overview &overview, QStringList getUninitializedVariables(const Snapshot &snapshot, const QString &functionName, - const QString &file, + const FilePath &file, int line) { QStringList result; diff --git a/src/plugins/debugger/sourceutils.h b/src/plugins/debugger/sourceutils.h index 634fa662037..0487c354352 100644 --- a/src/plugins/debugger/sourceutils.h +++ b/src/plugins/debugger/sourceutils.h @@ -33,6 +33,7 @@ class TextDocument; class TextEditorWidget; } +namespace Utils { class FilePath; } namespace CPlusPlus { class Snapshot; } namespace Debugger { @@ -52,7 +53,7 @@ QString cppFunctionAt(const QString &fileName, int line, int column = 0); // of a function from the code model. Shadowed variables will // be reported using the debugger naming conventions '' QStringList getUninitializedVariables(const CPlusPlus::Snapshot &snapshot, - const QString &function, const QString &file, int line); + const QString &function, const Utils::FilePath &file, int line); ContextData getLocationContext(TextEditor::TextDocument *document, int lineNumber); diff --git a/src/plugins/debugger/stackframe.cpp b/src/plugins/debugger/stackframe.cpp index d5a52bc4c38..d223d686da3 100644 --- a/src/plugins/debugger/stackframe.cpp +++ b/src/plugins/debugger/stackframe.cpp @@ -35,6 +35,8 @@ #include +using namespace Utils; + namespace Debugger { namespace Internal { @@ -93,7 +95,8 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet frame.level = frameMi["level"].data(); frame.function = frameMi["function"].data(); frame.module = frameMi["module"].data(); - frame.file = frameMi["file"].data(); + const FilePath debugger = rp.debugger.command.executable(); + frame.file = FilePath::fromString(frameMi["file"].data()).onDevice(debugger); frame.line = frameMi["line"].toInt(); frame.address = frameMi["address"].toAddress(); frame.context = frameMi["context"].data(); @@ -107,13 +110,13 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet if (usable.isValid()) frame.usable = usable.data().toInt(); else - frame.usable = QFileInfo(frame.file).isReadable(); + frame.usable = frame.file.isReadableFile(); return frame; } QString StackFrame::toToolTip() const { - const QString filePath = QDir::toNativeSeparators(file); + const QString filePath = file.toUserOutput(); QString res; QTextStream str(&res); str << ""; @@ -150,7 +153,7 @@ QString StackFrame::toToolTip() const "frame. However, matching sources have not been found."); showDistributionNote = true; } - if (!Utils::HostOsInfo::isWindowsHost() && showDistributionNote) { + if (file.osType() != OsTypeWindows && showDistributionNote) { str << ' ' << tr("Note that most distributions ship debug information " "in separate packages."); } @@ -159,19 +162,14 @@ QString StackFrame::toToolTip() const return res; } -static QString findFile(const QString &baseDir, const QString &relativeFile) +static FilePath findFile(const FilePath &baseDir, const FilePath &relativeFile) { - QDir dir(baseDir); - while (true) { - const QString path = dir.absoluteFilePath(relativeFile); - const QFileInfo fi(path); - if (fi.isFile()) - return path; - if (dir.isRoot()) - break; - dir.cdUp(); + for (FilePath dir(baseDir); !dir.isEmpty(); dir = dir.parentDir()) { + const FilePath absolutePath = dir.resolvePath(relativeFile); + if (absolutePath.isFile()) + return absolutePath; } - return QString(); + return {}; } // Try to resolve files coming from resource files. @@ -179,21 +177,23 @@ void StackFrame::fixQrcFrame(const DebuggerRunParameters &rp) { if (language != QmlLanguage) return; - QFileInfo aFi(file); - if (aFi.isAbsolute()) { - usable = aFi.isFile(); + if (file.isAbsolutePath()) { + usable = file.isFile(); return; } if (!file.startsWith("qrc:/")) return; - QString relativeFile = file.right(file.size() - 5); - while (relativeFile.startsWith('/')) - relativeFile = relativeFile.mid(1); + FilePath relativeFile = file; + QString relativePath = file.path(); + relativePath = relativePath.right(relativePath.size() - 5); + while (relativePath.startsWith('/')) + relativePath = relativePath.mid(1); + relativeFile.setPath(relativePath); - QString absFile = findFile(rp.projectSourceDirectory.toString(), relativeFile); + FilePath absFile = findFile(rp.projectSourceDirectory, relativeFile); if (absFile.isEmpty()) - absFile = findFile(QDir::currentPath(), relativeFile); + absFile = findFile(FilePath::fromString(QDir::currentPath()), relativeFile); if (absFile.isEmpty()) return; diff --git a/src/plugins/debugger/stackframe.h b/src/plugins/debugger/stackframe.h index e51736b5184..9fd83a15e78 100644 --- a/src/plugins/debugger/stackframe.h +++ b/src/plugins/debugger/stackframe.h @@ -27,6 +27,8 @@ #include "debuggerconstants.h" +#include + #include #include @@ -56,7 +58,7 @@ public: DebuggerLanguage language = CppLanguage; QString level; QString function; - QString file; // We try to put an absolute file name in there. + Utils::FilePath file;// We try to put an absolute file name in there. QString module; // Sometimes something like "/usr/lib/libstdc++.so.6" QString receiver; // Used in ScriptEngine only. qint32 line = -1; diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index a81433b99ee..488c6649b10 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -101,7 +101,7 @@ QVariant StackFrameItem::data(int column, int role) const case StackFunctionNameColumn: return simplifyType(frame.function); case StackFileNameColumn: - return frame.file.isEmpty() ? frame.module : FilePath::fromString(frame.file).fileName(); + return frame.file.isEmpty() ? frame.module : frame.file.fileName(); case StackLineNumberColumn: return frame.line > 0 ? QVariant(frame.line) : QVariant(); case StackAddressColumn: diff --git a/src/plugins/docker/CMakeLists.txt b/src/plugins/docker/CMakeLists.txt index 095d7b41c77..e89c5b5ee23 100644 --- a/src/plugins/docker/CMakeLists.txt +++ b/src/plugins/docker/CMakeLists.txt @@ -4,12 +4,7 @@ add_qtc_plugin(Docker docker_global.h dockerbuildstep.cpp dockerbuildstep.h dockerconstants.h - dockerdevice.cpp - dockerdevice.h - dockerplugin.cpp - dockerplugin.h - dockerrunconfiguration.cpp - dockerrunconfiguration.h - dockersettings.cpp - dockersettings.h + dockerdevice.cpp dockerdevice.h + dockerplugin.cpp dockerplugin.h + dockersettings.cpp dockersettings.h ) diff --git a/src/plugins/docker/docker.pro b/src/plugins/docker/docker.pro index ac012006b73..49ddfcd9a02 100644 --- a/src/plugins/docker/docker.pro +++ b/src/plugins/docker/docker.pro @@ -6,7 +6,6 @@ SOURCES += \ dockerbuildstep.cpp \ dockerdevice.cpp \ dockerplugin.cpp \ - dockerrunconfiguration.cpp \ dockersettings.cpp HEADERS += \ @@ -15,5 +14,4 @@ HEADERS += \ dockerconstants.h \ dockerdevice.h \ dockerplugin.h \ - dockerrunconfiguration.h \ dockersettings.h diff --git a/src/plugins/docker/docker.qbs b/src/plugins/docker/docker.qbs index 93ea8a84bae..60c31290630 100644 --- a/src/plugins/docker/docker.qbs +++ b/src/plugins/docker/docker.qbs @@ -19,8 +19,6 @@ QtcPlugin { "dockerdevice.cpp", "dockerplugin.h", "dockerplugin.cpp", - "dockerrunconfiguration.h", - "dockerrunconfiguration.cpp", "dockersettings.h", "dockersettings.cpp" ] diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp index b1fea6e45e7..d195c81d6b3 100644 --- a/src/plugins/docker/dockerplugin.cpp +++ b/src/plugins/docker/dockerplugin.cpp @@ -29,11 +29,9 @@ #include "dockerbuildstep.h" #include "dockerdevice.h" -#include "dockerrunconfiguration.h" #include "dockersettings.h" #include -#include using namespace Core; using namespace ProjectExplorer; @@ -49,13 +47,6 @@ public: // DockerOptionsPage optionsPage{&settings}; DockerDeviceFactory deviceFactory; -// DockerContainerRunConfigurationFactory containerRunConfigFactory; - -// RunWorkerFactory containerRunWorkerFactory{ -// RunWorkerFactory::make(), -// {ProjectExplorer::Constants::NORMAL_RUN_MODE}, -// {containerRunConfigFactory.runConfigurationId()} -// }; // DockerBuildStepFactory buildStepFactory; Utils::optional daemonRunning; diff --git a/src/plugins/docker/dockerrunconfiguration.cpp b/src/plugins/docker/dockerrunconfiguration.cpp deleted file mode 100644 index c9018ae84b1..00000000000 --- a/src/plugins/docker/dockerrunconfiguration.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "dockerrunconfiguration.h" - -#include "dockerconstants.h" -#include "dockerdevice.h" - -#include -#include -#include -#include -#include - -#include - -using namespace ProjectExplorer; -using namespace Utils; - -namespace Docker { -namespace Internal { - -class DockerContainerRunConfiguration : public RunConfiguration -{ - Q_DECLARE_TR_FUNCTIONS(Docker::Internal::DockerRunConfiguration) - -public: - DockerContainerRunConfiguration(Target *target, Id id) - : RunConfiguration(target, id) - { - auto rmOption = addAspect(); - rmOption->setSettingsKey("Docker.RunConfiguration.RmOption"); - rmOption->setDefaultValue(true); - rmOption->setLabelText(tr("Automatically remove the container when it exits")); - - auto ttyOption = addAspect(); - ttyOption->setSettingsKey("Docker.RunConfiguration.TtyOption"); - ttyOption->setLabelText(tr("Allocate a pseudo-TTY")); - ttyOption->setVisible(false); // Not yet. - - auto interactiveOption = addAspect(); - interactiveOption->setSettingsKey("Docker.RunConfiguration.InteractiveOption"); - interactiveOption->setLabelText(tr("Keep STDIN open even if not attached")); - interactiveOption->setVisible(false); // Not yet. - - auto effectiveCommand = addAspect(); - effectiveCommand->setLabelText(tr("Effective command call:")); - effectiveCommand->setDisplayStyle(StringAspect::TextEditDisplay); - effectiveCommand->setReadOnly(true); - - setUpdater([this, effectiveCommand] { - IDevice::ConstPtr device = DeviceKitAspect::device(kit()); - QTC_ASSERT(device, return); - DockerDevice::ConstPtr dockerDevice = qSharedPointerCast(device); - QTC_ASSERT(dockerDevice, return); - const DockerDeviceData &data = dockerDevice->data(); - - const Runnable r = runnable(); - const QStringList dockerRunFlags = r.extraData[Constants::DOCKER_RUN_FLAGS].toStringList(); - - CommandLine cmd("docker"); - cmd.addArg("run"); - cmd.addArgs(dockerRunFlags); - cmd.addArg(data.imageId); - - // FIXME: the global one above is apparently not sufficient. - effectiveCommand->setReadOnly(true); - effectiveCommand->setValue(cmd.toUserOutput()); - }); - - setRunnableModifier([rmOption, interactiveOption, ttyOption](Runnable &runnable) { - QStringList runArgs; - if (!rmOption->value()) - runArgs.append("--rm=false"); - if (interactiveOption->value()) - runArgs.append("--interactive"); - if (ttyOption->value()) - runArgs.append("--tty"); - runnable.extraData[Constants::DOCKER_RUN_FLAGS].toStringList(); - }); - - setCommandLineGetter([] { - return CommandLine(); - }); - - update(); - connect(rmOption, &BaseAspect::changed, this, &RunConfiguration::update); - } - -private: - bool isEnabled() const override { return true; } -}; - - -DockerContainerRunConfigurationFactory::DockerContainerRunConfigurationFactory() : - FixedRunConfigurationFactory(DockerContainerRunConfiguration::tr("Docker Container")) -{ - registerRunConfiguration - ("Docker.DockerContainerRunConfiguration"); - addSupportedTargetDeviceType(Constants::DOCKER_DEVICE_TYPE); -} - -} // Internal -} // Docker diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index 1b7be13f81f..cf137c68bc6 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -479,11 +479,17 @@ void IosConfigurations::loadProvisioningData(bool notify) QList teams; for (auto accountiterator = teamMap.cbegin(), end = teamMap.cend(); accountiterator != end; ++accountiterator) { - QVariantMap teamInfo = accountiterator.value().toMap(); - int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0; - teamInfo[freeTeamTag] = provisioningTeamIsFree; - teamInfo[emailTag] = accountiterator.key(); - teams.append(teamInfo); + // difference between Qt 5 (map) and Qt 6 (list of maps) + const bool isList = accountiterator->userType() == QMetaType::QVariantList; + const QVariantList teamsList = isList ? accountiterator.value().toList() + : QVariantList({accountiterator.value()}); + for (const QVariant &teamInfoIt : teamsList) { + QVariantMap teamInfo = teamInfoIt.toMap(); + int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0; + teamInfo[freeTeamTag] = provisioningTeamIsFree; + teamInfo[emailTag] = accountiterator.key(); + teams.append(teamInfo); + } } // Sort team id's to move the free provisioning teams at last of the list. diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt index 3729ac7256c..a85b35b5f9b 100644 --- a/src/plugins/mcusupport/CMakeLists.txt +++ b/src/plugins/mcusupport/CMakeLists.txt @@ -12,4 +12,5 @@ add_qtc_plugin(McuSupport mcusupportsdk.cpp mcusupportsdk.h mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h mcusupportversiondetection.cpp mcusupportversiondetection.h + mcusupportcmakemapper.cpp mcusupportcmakemapper.h ) diff --git a/src/plugins/mcusupport/mcusupport.pro b/src/plugins/mcusupport/mcusupport.pro index f2d7a1c501c..e03db38925d 100644 --- a/src/plugins/mcusupport/mcusupport.pro +++ b/src/plugins/mcusupport/mcusupport.pro @@ -13,7 +13,8 @@ HEADERS += \ mcusupportplugin.h \ mcusupportsdk.h \ mcusupportrunconfiguration.h \ - mcusupportversiondetection.h + mcusupportversiondetection.h \ + mcusupportcmakemapper.h SOURCES += \ mcusupportdevice.cpp \ @@ -22,7 +23,8 @@ SOURCES += \ mcusupportplugin.cpp \ mcusupportsdk.cpp \ mcusupportrunconfiguration.cpp \ - mcusupportversiondetection.cpp + mcusupportversiondetection.cpp \ + mcusupportcmakemapper.cpp RESOURCES += \ mcusupport.qrc diff --git a/src/plugins/mcusupport/mcusupport.qbs b/src/plugins/mcusupport/mcusupport.qbs index 8818514b2b5..2f775a01549 100644 --- a/src/plugins/mcusupport/mcusupport.qbs +++ b/src/plugins/mcusupport/mcusupport.qbs @@ -32,5 +32,7 @@ QtcPlugin { "mcusupportrunconfiguration.h", "mcusupportversiondetection.cpp", "mcusupportversiondetection.h", + "mcusupportcmakemapper.h", + "mcusupportcmakemapper.cpp" ] } diff --git a/src/plugins/mcusupport/mcusupportcmakemapper.cpp b/src/plugins/mcusupport/mcusupportcmakemapper.cpp new file mode 100644 index 00000000000..326489e365c --- /dev/null +++ b/src/plugins/mcusupport/mcusupportcmakemapper.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "mcusupportcmakemapper.h" +#include "utils/namevalueitem.h" + +#include + +namespace { +static const QHash &envVarToCMakeVarMapping() +{ + static const QHash mapping = { + {"EVK_MIMXRT1060_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"EVK_MIMXRT1064_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"EVK_MIMXRT595_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"EVK_MIMXRT1170_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"EVKB_IMXRT1050_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"STM32Cube_FW_F7_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"STM32Cube_FW_F4_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"STM32Cube_FW_L4_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"STM32Cube_FW_H7_SDK_PATH","QUL_BOARD_SDK_DIR"}, + {"ARMGCC_DIR", "QUL_TARGET_TOOLCHAIN_DIR"}, + {"IAR_ARM_COMPILER_DIR", "QUL_TARGET_TOOLCHAIN_DIR"}, + {"GHS_COMPILER_DIR", "QUL_TARGET_TOOLCHAIN_DIR"}, + {"GHS_ARM_COMPILER_DIR", "QUL_TARGET_TOOLCHAIN_DIR"}, + {"EVK_MIMXRT1170_FREERTOS_PATH","FREERTOS_DIR"}, + {"EVK_MIMXRT1170_FREERTOS_PATH","FREERTOS_DIR"}, + {"IMXRT1064_FREERTOS_DIR","FREERTOS_DIR"}, + {"IMXRT595_FREERTOS_DIR","FREERTOS_DIR"}, + {"STM32F7_FREERTOS_DIR", "FREERTOS_DIR"}, + {"eFlashLoad_PATH","eFlashLoad_PATH"}, + {"RenesasFlashProgrammer_PATH", "RenesasFlashProgrammer_PATH"}, + {"MCUXpressoIDE_PATH", "MCUXpressoIDE_PATH"}, + {"JLINK_PATH", "JLINK_PATH"}, + {"TVII_GRAPHICS_DRIVER_DIR", "TVII_GRAPHICS_DRIVER_DIR"}, + {"CYPRESS_AUTO_FLASH_UTILITY_DIR", "CYPRESS_AUTO_FLASH_UTILITY_DIR"}, + {"EK_RA6M3G_E2_PROJECT_PATH", "EK_RA6M3G_E2_PROJECT_PATH"}, + {"EK_RA6M3G_FSP_PATH", "EK_RA6M3G_FSP_PATH"}, + }; + return mapping; +} +} // namespace + +QList McuSupport::Internal::mapEnvVarsToQul2xCmakeVars( + const Utils::EnvironmentItems &envVars) +{ + const auto &mapping = envVarToCMakeVarMapping(); + auto cmakeVars = Utils::transform(envVars, [mapping](const Utils::EnvironmentItem &envVar) { + return CMakeProjectManager::CMakeConfigItem(mapping.value(envVar.name, "").toUtf8(), envVar.value.toUtf8()); + }).toList(); + + return Utils::filtered(cmakeVars, [](const CMakeProjectManager::CMakeConfigItem &item) { + return !item.key.isEmpty(); + }); +} diff --git a/src/plugins/docker/dockerrunconfiguration.h b/src/plugins/mcusupport/mcusupportcmakemapper.h similarity index 79% rename from src/plugins/docker/dockerrunconfiguration.h rename to src/plugins/mcusupport/mcusupportcmakemapper.h index 37eef9ba6c9..f5da2092def 100644 --- a/src/plugins/docker/dockerrunconfiguration.h +++ b/src/plugins/mcusupport/mcusupportcmakemapper.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -22,20 +22,14 @@ ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ - #pragma once -#include +#include "cmakeprojectmanager/cmakeconfigitem.h" +#include "utils/environmentfwd.h" -namespace Docker { +namespace McuSupport { namespace Internal { - -class DockerContainerRunConfigurationFactory - : public ProjectExplorer::FixedRunConfigurationFactory -{ -public: - DockerContainerRunConfigurationFactory(); -}; - -} // Internal -} // Docker +QList mapEnvVarsToQul2xCmakeVars( + const Utils::EnvironmentItems &envVars); +} +} // namespace McuSupport diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index ba6107d6fc6..6ac2e30fd13 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -27,6 +27,7 @@ #include "mcusupportoptions.h" #include "mcusupportsdk.h" #include "mcusupportplugin.h" +#include "mcusupportcmakemapper.h" #include #include @@ -70,7 +71,7 @@ using namespace Utils; namespace McuSupport { namespace Internal { -static const int KIT_VERSION = 8; // Bumps up whenever details in Kit creation change +static const int KIT_VERSION = 9; // Bumps up whenever details in Kit creation change static FilePath packagePathFromSettings(const QString &settingsKey, QSettings::Scope scope = QSettings::UserScope, @@ -99,6 +100,22 @@ static bool kitNeedsQtVersion() return !HostOsInfo::isWindowsHost(); } +static void remapQul2xCmakeVars(Kit *kit, const EnvironmentItems &envItems) +{ + using namespace CMakeProjectManager; + const auto cmakeVars = mapEnvVarsToQul2xCmakeVars(envItems); + const auto cmakeVarNames = Utils::transform(cmakeVars, &CMakeConfigItem::key); + + // First filter out all Qul2.x CMake vars + auto config = Utils::filtered(CMakeConfigurationKitAspect::configuration(kit), + [&](const auto &configItem) { + return !cmakeVarNames.contains(configItem.key); + }); + // Then append them with new values + config.append(cmakeVars); + CMakeConfigurationKitAspect::setConfiguration(kit, config); +} + McuPackage::McuPackage(const QString &label, const FilePath &defaultPath, const QString &detectionPath, const QString &settingsKey, const McuPackageVersionDetector *versionDetector) @@ -231,7 +248,7 @@ bool McuPackage::writeToSettings() const const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; - Core::ICore::settings()->setValueWithDefault(key, m_path, m_defaultPath); + Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString()); return savedPath != m_path; } @@ -573,6 +590,14 @@ void McuTarget::setColorDepth(int colorDepth) m_colorDepth = colorDepth; } +void McuSdkRepository::deletePackagesAndTargets() +{ + qDeleteAll(packages); + packages.clear(); + qDeleteAll(mcuTargets); + mcuTargets.clear(); +} + McuSupportOptions::McuSupportOptions(QObject *parent) : QObject(parent) , qtForMCUsSdkPackage(Sdk::createQtForMCUsPackage()) @@ -635,14 +660,6 @@ void McuSupportOptions::registerExamples() } } -void McuSupportOptions::deletePackagesAndTargets() -{ - qDeleteAll(packages); - packages.clear(); - qDeleteAll(mcuTargets); - mcuTargets.clear(); -} - const QVersionNumber &McuSupportOptions::minimalQulVersion() { static const QVersionNumber v({1, 3}); @@ -654,8 +671,8 @@ void McuSupportOptions::setQulDir(const FilePath &dir) deletePackagesAndTargets(); qtForMCUsSdkPackage->updateStatus(); if (qtForMCUsSdkPackage->validStatus()) - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); - for (auto package : qAsConst(packages)) + Sdk::targetsAndPackages(dir, &sdkRepository); + for (const auto &package : qAsConst(sdkRepository.packages)) connect(package, &McuPackage::changed, this, &McuSupportOptions::changed); emit changed(); @@ -736,6 +753,11 @@ static void setKitDevice(Kit *k, const McuTarget* mcuTarget) DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); } +static bool expectsCmakeVars(const McuTarget *mcuTarget) +{ + return mcuTarget->qulVersion() >= QVersionNumber{2,0}; +} + static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget, const McuPackage *qtForMCUsSdkPackage) { @@ -770,6 +792,11 @@ static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget, if (kitNeedsQtVersion()) changes.append({QLatin1String("LD_LIBRARY_PATH"), "%{Qt:QT_INSTALL_LIBS}"}); + // Hack, this problem should be solved in lower layer + if (expectsCmakeVars(mcuTarget)) { + remapQul2xCmakeVars(k, changes); + } + EnvironmentKitAspect::setEnvironmentChanges(k, changes); } @@ -812,6 +839,11 @@ static void updateKitEnvironment(Kit *k, const McuTarget *mcuTarget) } } + // Hack, this problem should be solved in lower layer + if (expectsCmakeVars(mcuTarget)) { + remapQul2xCmakeVars(k, changes); + } + EnvironmentKitAspect::setEnvironmentChanges(k, changes); } @@ -1015,6 +1047,11 @@ bool McuSupportOptions::kitUpToDate(const Kit *kit, const McuTarget *mcuTarget, kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path(); } +void McuSupportOptions::deletePackagesAndTargets() +{ + sdkRepository.deletePackagesAndTargets(); +} + McuSupportOptions::UpgradeOption McuSupportOptions::askForKitUpgrades() { QMessageBox upgradePopup(Core::ICore::dialogParent()); @@ -1076,12 +1113,11 @@ void McuSupportOptions::createAutomaticKits() } FilePath dir = qtForMCUsPackage->path(); - QVector packages; - QVector mcuTargets; - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); + McuSdkRepository repo; + Sdk::targetsAndPackages(dir, &repo); bool needsUpgrade = false; - for (auto target: qAsConst(mcuTargets)) { + for (const auto &target: qAsConst(repo.mcuTargets)) { // if kit already exists, skip if (!matchingKits(target, qtForMCUsPackage).empty()) continue; @@ -1096,8 +1132,7 @@ void McuSupportOptions::createAutomaticKits() } } - qDeleteAll(packages); - qDeleteAll(mcuTargets); + repo.deletePackagesAndTargets(); if (needsUpgrade) McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade(); @@ -1110,10 +1145,10 @@ void McuSupportOptions::createAutomaticKits() void McuSupportOptions::checkUpgradeableKits() { - if (!qtForMCUsSdkPackage->validStatus() || mcuTargets.length() == 0) + if (!qtForMCUsSdkPackage->validStatus() || sdkRepository.mcuTargets.length() == 0) return; - if (Utils::anyOf(mcuTargets, [this](const McuTarget *target) { + if (Utils::anyOf(sdkRepository.mcuTargets, [this](const McuTarget *target) { return !upgradeableKits(target, this->qtForMCUsSdkPackage).empty() && matchingKits(target, this->qtForMCUsSdkPackage).empty(); })) @@ -1128,11 +1163,10 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption) auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); auto dir = qtForMCUsPackage->path(); - QVector packages; - QVector mcuTargets; - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); + McuSdkRepository repo; + Sdk::targetsAndPackages(dir, &repo); - for (auto target: qAsConst(mcuTargets)) { + for (const auto &target: qAsConst(repo.mcuTargets)) { if (!matchingKits(target, qtForMCUsPackage).empty()) // already up-to-date continue; @@ -1149,8 +1183,7 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption) } } - qDeleteAll(packages); - qDeleteAll(mcuTargets); + repo.deletePackagesAndTargets(); delete qtForMCUsPackage; } @@ -1166,10 +1199,9 @@ void McuSupportOptions::fixKitsDependencies() auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); FilePath dir = qtForMCUsPackage->path(); - QVector packages; - QVector mcuTargets; - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); - for (auto target: qAsConst(mcuTargets)) { + McuSdkRepository repo; + Sdk::targetsAndPackages(dir, &repo); + for (const auto &target: qAsConst(repo.mcuTargets)) { if (target->isValid()) { for (auto kit : kitsWithMismatchedDependencies(target)) { updateKitEnvironment(kit, target); @@ -1177,8 +1209,7 @@ void McuSupportOptions::fixKitsDependencies() } } - qDeleteAll(packages); - qDeleteAll(mcuTargets); + repo.deletePackagesAndTargets(); delete qtForMCUsPackage; } @@ -1242,18 +1273,16 @@ void McuSupportOptions::fixExistingKits() qtForMCUsPackage->updateStatus(); if (qtForMCUsPackage->validStatus()) { FilePath dir = qtForMCUsPackage->path(); - QVector packages; - QVector mcuTargets; - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); - for (auto target: qAsConst(mcuTargets)) + McuSdkRepository repo; + Sdk::targetsAndPackages(dir, &repo); + for (const auto &target: qAsConst(repo.mcuTargets)) for (auto kit: existingKits(target)) { if (McuDependenciesKitAspect::dependencies(kit).isEmpty()) { setKitDependencies(kit, target, qtForMCUsPackage); } } - qDeleteAll(packages); - qDeleteAll(mcuTargets); + repo.deletePackagesAndTargets(); } delete qtForMCUsPackage; } diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 346c2b9de50..95130fb0aba 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -200,6 +200,15 @@ private: int m_colorDepth = -1; }; +class McuSdkRepository +{ +public: + QVector packages; + QVector mcuTargets; + + void deletePackagesAndTargets(); +}; + class McuSupportOptions : public QObject { Q_OBJECT @@ -214,9 +223,8 @@ public: McuSupportOptions(QObject *parent = nullptr); ~McuSupportOptions() override; - QVector packages; - QVector mcuTargets; McuPackage *qtForMCUsSdkPackage = nullptr; + McuSdkRepository sdkRepository; void setQulDir(const Utils::FilePath &dir); static Utils::FilePath qulDirFromSettings(); diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 71eff41c246..f4b79ec0f2e 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -190,7 +190,7 @@ void McuSupportOptionsWidget::updateStatus() m_mcuTargetsGroupBox->setVisible(ready); m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty()); m_kitCreationGroupBox->setVisible(ready); - m_mcuTargetsInfoLabel->setVisible(valid && m_options.mcuTargets.isEmpty()); + m_mcuTargetsInfoLabel->setVisible(valid && m_options.sdkRepository.mcuTargets.isEmpty()); if (m_mcuTargetsInfoLabel->isVisible()) { m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk); const Utils::FilePath sdkPath = m_options.qtForMCUsSdkPackage->basePath(); @@ -261,7 +261,7 @@ void McuSupportOptionsWidget::showMcuTargetPackages() row.fieldItem->widget()->hide(); } - for (auto package : qAsConst(m_options.packages)) { + for (auto package : qAsConst(m_options.sdkRepository.packages)) { QWidget *packageWidget = package->widget(); if (!mcuTarget->packages().contains(package)) continue; @@ -275,9 +275,9 @@ void McuSupportOptionsWidget::showMcuTargetPackages() McuTarget *McuSupportOptionsWidget::currentMcuTarget() const { const int mcuTargetIndex = m_mcuTargetsComboBox->currentIndex(); - return (mcuTargetIndex == -1 || m_options.mcuTargets.isEmpty()) + return (mcuTargetIndex == -1 || m_options.sdkRepository.mcuTargets.isEmpty()) ? nullptr - : m_options.mcuTargets.at(mcuTargetIndex); + : m_options.sdkRepository.mcuTargets.at(mcuTargetIndex); } void McuSupportOptionsWidget::showEvent(QShowEvent *event) @@ -292,7 +292,7 @@ void McuSupportOptionsWidget::apply() m_options.qtForMCUsSdkPackage->writeGeneralSettings(); pathsChanged |= m_options.qtForMCUsSdkPackage->writeToSettings(); - for (auto package : qAsConst(m_options.packages)) + for (auto package : qAsConst(m_options.sdkRepository.packages)) pathsChanged |= package->writeToSettings(); if (pathsChanged) { @@ -306,7 +306,7 @@ void McuSupportOptionsWidget::populateMcuTargetsComboBox() m_options.populatePackagesAndTargets(); m_mcuTargetsComboBox->clear(); m_mcuTargetsComboBox->addItems( - Utils::transform(m_options.mcuTargets, [](McuTarget *t) { + Utils::transform(m_options.sdkRepository.mcuTargets, [](McuTarget *t) { return McuSupportOptions::kitName(t); })); updateStatus(); diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 291f0647b29..a9cdf7a976f 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -331,19 +331,28 @@ struct McuTargetDescription }; QString qulVersion; - QString platform; - QString platformName; - QString platformVendor; - QVector colorDepths; - QString toolchainId; - QVector toolchainVersions; - QString boardSdkEnvVar; - QString boardSdkName; - QString boardSdkDefaultPath; - QVector boardSdkVersions; - QString freeRTOSEnvVar; - QString freeRTOSBoardSdkSubDir; - TargetType type; + QString compatVersion; + struct { + QString id; + QString name; + QString vendor; + QVector colorDepths; + TargetType type; + } platform; + struct { + QString id; + QVector versions; + } toolchain; + struct { + QString name; + QString defaultPath; + QString envVar; + QVector versions; + } boardSdk; + struct { + QString envVar; + QString boardSdkSubDir; + } freeRTOS; }; static McuPackageVersionDetector* generatePackageVersionDetector(QString envVar) @@ -373,29 +382,29 @@ static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc) auto sdkName = postfixPos > 0 ? envVar.left(postfixPos) : envVar; return QString::fromLatin1("MCU SDK (%1)").arg(sdkName); }; - const QString sdkName = desc.boardSdkName.isEmpty() ? generateSdkName(desc.boardSdkEnvVar) : desc.boardSdkName; + const QString sdkName = desc.boardSdk.name.isEmpty() ? generateSdkName(desc.boardSdk.envVar) : desc.boardSdk.name; const FilePath defaultPath = [&] { - const auto envVar = desc.boardSdkEnvVar.toLatin1(); + const auto envVar = desc.boardSdk.envVar.toLatin1(); if (qEnvironmentVariableIsSet(envVar)) return FilePath::fromUserInput(qEnvironmentVariable(envVar)); - if (!desc.boardSdkDefaultPath.isEmpty()) { - FilePath defaultPath = FilePath::fromUserInput(QDir::rootPath() + desc.boardSdkDefaultPath); + if (!desc.boardSdk.defaultPath.isEmpty()) { + FilePath defaultPath = FilePath::fromUserInput(QDir::rootPath() + desc.boardSdk.defaultPath); if (defaultPath.exists()) return defaultPath; } return FileUtils::homePath(); }(); - const auto versionDetector = generatePackageVersionDetector(desc.boardSdkEnvVar); + const auto versionDetector = generatePackageVersionDetector(desc.boardSdk.envVar); auto result = new McuPackage( sdkName, defaultPath, {}, - desc.boardSdkEnvVar, + desc.boardSdk.envVar, versionDetector); - result->setEnvironmentVariableName(desc.boardSdkEnvVar); + result->setEnvironmentVariableName(desc.boardSdk.envVar); return result; } @@ -434,7 +443,7 @@ struct McuTargetFactory { auto qulVersion = QVersionNumber::fromString(description.qulVersion); if (qulVersion <= QVersionNumber({1,3})) { - if (description.type == McuTargetDescription::TargetType::Desktop) + if (description.platform.type == McuTargetDescription::TargetType::Desktop) return createDesktopTargetsLegacy(description); // There was a platform backends related refactoring in Qul 1.4 @@ -459,44 +468,44 @@ protected: QVector createMcuTargetsLegacy(const McuTargetDescription &desc) { QVector mcuTargets; - McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); + McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id); if (!tcPkg) tcPkg = createUnsupportedToolChainPackage(); for (auto os : {McuTarget::OS::BareMetal, McuTarget::OS::FreeRTOS}) { - for (int colorDepth : desc.colorDepths) { + for (int colorDepth : desc.platform.colorDepths) { QVector required3rdPartyPkgs = { tcPkg }; - if (vendorPkgs.contains(desc.platformVendor)) - required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platformVendor)); + if (vendorPkgs.contains(desc.platform.vendor)) + required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platform.vendor)); FilePath boardSdkDefaultPath; - if (!desc.boardSdkEnvVar.isEmpty()) { - if (!boardSdkPkgs.contains(desc.boardSdkEnvVar)) { - auto boardSdkPkg = desc.boardSdkEnvVar != "RGL_DIR" + if (!desc.boardSdk.envVar.isEmpty()) { + if (!boardSdkPkgs.contains(desc.boardSdk.envVar)) { + auto boardSdkPkg = desc.boardSdk.envVar != "RGL_DIR" ? createBoardSdkPackage(desc) : createRGLPackage(); - boardSdkPkgs.insert(desc.boardSdkEnvVar, boardSdkPkg); + boardSdkPkgs.insert(desc.boardSdk.envVar, boardSdkPkg); } - auto boardSdkPkg = boardSdkPkgs.value(desc.boardSdkEnvVar); + auto boardSdkPkg = boardSdkPkgs.value(desc.boardSdk.envVar); boardSdkDefaultPath = boardSdkPkg->defaultPath(); required3rdPartyPkgs.append(boardSdkPkg); } if (os == McuTarget::OS::FreeRTOS) { - if (desc.freeRTOSEnvVar.isEmpty()) { + if (desc.freeRTOS.envVar.isEmpty()) { continue; } else { - if (!freeRTOSPkgs.contains(desc.freeRTOSEnvVar)) { - freeRTOSPkgs.insert(desc.freeRTOSEnvVar, createFreeRTOSSourcesPackage( - desc.freeRTOSEnvVar, boardSdkDefaultPath, - desc.freeRTOSBoardSdkSubDir)); + if (!freeRTOSPkgs.contains(desc.freeRTOS.envVar)) { + freeRTOSPkgs.insert(desc.freeRTOS.envVar, createFreeRTOSSourcesPackage( + desc.freeRTOS.envVar, boardSdkDefaultPath, + desc.freeRTOS.boardSdkSubDir)); } - required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOSEnvVar)); + required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOS.envVar)); } } - const auto platform = McuTarget::Platform{ desc.platform, desc.platformName, desc.platformVendor }; + const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), platform, os, required3rdPartyPkgs, tcPkg); - if (desc.colorDepths.count() > 1) + if (desc.platform.colorDepths.count() > 1) mcuTarget->setColorDepth(colorDepth); mcuTargets.append(mcuTarget); } @@ -506,10 +515,10 @@ protected: QVector createDesktopTargetsLegacy(const McuTargetDescription& desc) { - McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); + McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id); if (!tcPkg) tcPkg = createUnsupportedToolChainPackage(); - const auto platform = McuTarget::Platform{ desc.platform, desc.platformName, desc.platformVendor }; + const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; auto desktopTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), platform, McuTarget::OS::Desktop, {}, tcPkg); return { desktopTarget }; @@ -519,21 +528,21 @@ protected: { // OS deduction const auto os = [&] { - if (desc.type == McuTargetDescription::TargetType::Desktop) + if (desc.platform.type == McuTargetDescription::TargetType::Desktop) return McuTarget::OS::Desktop; - else if (!desc.freeRTOSEnvVar.isEmpty()) + else if (!desc.freeRTOS.envVar.isEmpty()) return McuTarget::OS::FreeRTOS; return McuTarget::OS::BareMetal; }(); QVector mcuTargets; - McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); + McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id); if (tcPkg) { if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8})) - tcPkg->setVersions(desc.toolchainVersions); + tcPkg->setVersions(desc.toolchain.versions); } else tcPkg = createUnsupportedToolChainPackage(); - for (int colorDepth : desc.colorDepths) { + for (int colorDepth : desc.platform.colorDepths) { QVector required3rdPartyPkgs; // Desktop toolchains don't need any additional settings if (tcPkg @@ -542,34 +551,34 @@ protected: required3rdPartyPkgs.append(tcPkg); // Add setting specific to platform IDE - if (vendorPkgs.contains(desc.platformVendor)) - required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platformVendor)); + if (vendorPkgs.contains(desc.platform.vendor)) + required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platform.vendor)); // Board SDK specific settings FilePath boardSdkDefaultPath; - if (!desc.boardSdkEnvVar.isEmpty()) { - if (!boardSdkPkgs.contains(desc.boardSdkEnvVar)) { + if (!desc.boardSdk.envVar.isEmpty()) { + if (!boardSdkPkgs.contains(desc.boardSdk.envVar)) { auto boardSdkPkg = createBoardSdkPackage(desc); - boardSdkPkgs.insert(desc.boardSdkEnvVar, boardSdkPkg); + boardSdkPkgs.insert(desc.boardSdk.envVar, boardSdkPkg); } - auto boardSdkPkg = boardSdkPkgs.value(desc.boardSdkEnvVar); + auto boardSdkPkg = boardSdkPkgs.value(desc.boardSdk.envVar); if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8})) - boardSdkPkg->setVersions(desc.boardSdkVersions); + boardSdkPkg->setVersions(desc.boardSdk.versions); boardSdkDefaultPath = boardSdkPkg->defaultPath(); required3rdPartyPkgs.append(boardSdkPkg); } // Free RTOS specific settings - if (!desc.freeRTOSEnvVar.isEmpty()) { - if (!freeRTOSPkgs.contains(desc.freeRTOSEnvVar)) { - freeRTOSPkgs.insert(desc.freeRTOSEnvVar, createFreeRTOSSourcesPackage( - desc.freeRTOSEnvVar, boardSdkDefaultPath, - desc.freeRTOSBoardSdkSubDir)); + if (!desc.freeRTOS.envVar.isEmpty()) { + if (!freeRTOSPkgs.contains(desc.freeRTOS.envVar)) { + freeRTOSPkgs.insert(desc.freeRTOS.envVar, createFreeRTOSSourcesPackage( + desc.freeRTOS.envVar, boardSdkDefaultPath, + desc.freeRTOS.boardSdkSubDir)); } - required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOSEnvVar)); + required3rdPartyPkgs.append(freeRTOSPkgs.value(desc.freeRTOS.envVar)); } - const auto platform = McuTarget::Platform{ desc.platform, desc.platformName, desc.platformVendor }; + const auto platform = McuTarget::Platform{ desc.platform.id, desc.platform.name, desc.platform.vendor }; auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion), platform, os, required3rdPartyPkgs, tcPkg); mcuTarget->setColorDepth(colorDepth); @@ -634,17 +643,20 @@ static QFileInfoList targetDescriptionFiles(const Utils::FilePath &dir) return kitsDir.entryInfoList(); } -static McuTargetDescription parseDescriptionJson(const QByteArray &data) +static QString extractQulVersion(const QByteArray &data) { const QJsonDocument document = QJsonDocument::fromJson(data); const QJsonObject target = document.object(); + return target.value("qulVersion").toString(); +} + +static McuTargetDescription parseDescriptionJsonCommon(const QString &qulVersion, const QJsonObject &target) +{ + const QString compatVersion = target.value("compatVersion").toString(); const QJsonObject toolchain = target.value("toolchain").toObject(); const QJsonObject boardSdk = target.value("boardSdk").toObject(); const QJsonObject freeRTOS = target.value("freeRTOS").toObject(); - const QVariantList colorDepths = target.value("colorDepths").toArray().toVariantList(); - const auto colorDepthsVector = Utils::transform >( - colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); }); const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList(); const auto toolchainVersionsVector = Utils::transform >( toolchainVersions, [&](const QVariant &version) { return version.toString(); }); @@ -653,23 +665,78 @@ static McuTargetDescription parseDescriptionJson(const QByteArray &data) boardSdkVersions, [&](const QVariant &version) { return version.toString(); }); return { - target.value("qulVersion").toString(), - target.value("platform").toString(), - target.value("platformName").toString(), - target.value("platformVendor").toString(), - colorDepthsVector, - toolchain.value("id").toString(), - toolchainVersionsVector, - boardSdk.value("envVar").toString(), - boardSdk.value("name").toString(), - boardSdk.value("defaultPath").toString(), - boardSdkVersionsVector, - freeRTOS.value("envVar").toString(), - freeRTOS.value("boardSdkSubDir").toString(), - boardSdk.empty() ? McuTargetDescription::TargetType::Desktop : McuTargetDescription::TargetType::MCU + qulVersion, + compatVersion, + {}, + { + toolchain.value("id").toString(), + toolchainVersionsVector, + }, + { + boardSdk.value("name").toString(), + boardSdk.value("defaultPath").toString(), + boardSdk.value("envVar").toString(), + boardSdkVersionsVector, + }, + { + freeRTOS.value("envVar").toString(), + freeRTOS.value("boardSdkSubDir").toString(), + } }; } +static McuTargetDescription parseDescriptionJsonV1x(const QString &qulVersion, const QJsonObject &target) +{ + auto description = parseDescriptionJsonCommon(qulVersion, target); + + const QVariantList colorDepths = target.value("colorDepths").toArray().toVariantList(); + const auto colorDepthsVector = Utils::transform >( + colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); }); + + description.platform = { + target.value("platform").toString(), + target.value("platformName").toString(), + target.value("platformVendor").toString(), + colorDepthsVector, + description.boardSdk.envVar.isEmpty() ? McuTargetDescription::TargetType::Desktop : McuTargetDescription::TargetType::MCU + }; + return description; +} + +static McuTargetDescription parseDescriptionJsonV2x(const QString &qulVersion, const QJsonObject &target) +{ + const QJsonObject platform = target.value("platform").toObject(); + + const QVariantList colorDepths = platform.value("colorDepths").toArray().toVariantList(); + const auto colorDepthsVector = Utils::transform >( + colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); }); + const QString platformName = platform.value("platformName").toString(); + McuTargetDescription description = parseDescriptionJsonCommon(qulVersion, target); + description.platform = { + platform.value("id").toString(), + platformName, + platform.value("vendor").toString(), + colorDepthsVector, + platformName == "Desktop" ? McuTargetDescription::TargetType::Desktop : McuTargetDescription::TargetType::MCU, + }; + + return description; +} + +static McuTargetDescription parseDescriptionJson(const QByteArray &data) +{ + const QJsonDocument document = QJsonDocument::fromJson(data); + const QJsonObject target = document.object(); + + const QString qulVersion = target.value("qulVersion").toString(); + + switch (QVersionNumber::fromString(qulVersion).majorVersion()) { + case 1: return parseDescriptionJsonV1x(qulVersion, target); + case 2: return parseDescriptionJsonV2x(qulVersion, target); + default: return { qulVersion }; + } +} + // https://doc.qt.io/qtcreator/creator-developing-mcu.html#supported-qt-for-mcus-sdks const QHash oldSdkQtcRequiredVersion = { {{"1.0"}, {"4.11.x"}}, @@ -695,8 +762,7 @@ bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message) return false; } -void targetsAndPackages(const Utils::FilePath &dir, QVector *packages, - QVector *mcuTargets) +void targetsAndPackages(const Utils::FilePath &dir, McuSdkRepository *repo) { QList descriptions; @@ -706,8 +772,17 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector *packa if (!file.open(QFile::ReadOnly)) continue; const McuTargetDescription desc = parseDescriptionJson(file.readAll()); + const auto pth = Utils::FilePath::fromString(fileInfo.filePath()); + bool ok = false; + const int compatVersion = desc.compatVersion.toInt(&ok); + if (!desc.compatVersion.isEmpty() && ok && compatVersion > MAX_COMPATIBILITY_VERSION) { + printMessage(McuTarget::tr("Skipped %1. Unsupported version \"%2\".").arg( + QDir::toNativeSeparators(pth.fileNameWithPathComponents(1)), + desc.qulVersion), + false); + continue; + } if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) { - const auto pth = Utils::FilePath::fromString(fileInfo.filePath()); const QString qtcSupportText = oldSdkQtcRequiredVersion.contains(desc.qulVersion) ? McuTarget::tr("Detected version \"%1\", only supported by Qt Creator %2.") .arg(desc.qulVersion, oldSdkQtcRequiredVersion.value(desc.qulVersion)) @@ -744,7 +819,7 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector *packa // This whole section could be removed when minimalQulVersion will reach 1.5 or above { const bool hasDesktopDescription = Utils::contains(descriptions, [](const McuTargetDescription &desc) { - return desc.type == McuTargetDescription::TargetType::Desktop; + return desc.platform.type == McuTargetDescription::TargetType::Desktop; }); if (!hasDesktopDescription) { @@ -764,12 +839,12 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector *packa desktopDescription.qulVersion = descriptions.empty() ? McuSupportOptions::minimalQulVersion().toString() : descriptions.first().qulVersion; - desktopDescription.platform = "Qt"; - desktopDescription.platformName = "Desktop"; - desktopDescription.platformVendor = "Qt"; - desktopDescription.colorDepths = {32}; - desktopDescription.toolchainId = Utils::HostOsInfo::isWindowsHost() ? QString("msvc") : QString("gcc"); - desktopDescription.type = McuTargetDescription::TargetType::Desktop; + desktopDescription.platform.id = "Qt"; + desktopDescription.platform.name = "Desktop"; + desktopDescription.platform.vendor = "Qt"; + desktopDescription.platform.colorDepths = {32}; + desktopDescription.toolchain.id = Utils::HostOsInfo::isWindowsHost() ? QString("msvc") : QString("gcc"); + desktopDescription.platform.type = McuTargetDescription::TargetType::Desktop; descriptions.prepend(desktopDescription); } else { if (dir.exists()) @@ -782,10 +857,10 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector *packa } } - mcuTargets->append(targetsFromDescriptions(descriptions, packages)); + repo->mcuTargets.append(targetsFromDescriptions(descriptions, &(repo->packages))); // Keep targets sorted lexicographically - std::sort(mcuTargets->begin(), mcuTargets->end(), [] (const McuTarget* lhs, const McuTarget* rhs) { + std::sort(repo->mcuTargets.begin(), repo->mcuTargets.end(), [] (const McuTarget* lhs, const McuTarget* rhs) { return McuSupportOptions::kitName(lhs) < McuSupportOptions::kitName(rhs); }); } diff --git a/src/plugins/mcusupport/mcusupportsdk.h b/src/plugins/mcusupport/mcusupportsdk.h index f7519919e5f..2f687555d68 100644 --- a/src/plugins/mcusupport/mcusupportsdk.h +++ b/src/plugins/mcusupport/mcusupportsdk.h @@ -33,17 +33,18 @@ class FilePath; namespace McuSupport { namespace Internal { + +#define MAX_COMPATIBILITY_VERSION 1 + +class McuSdkRepository; class McuPackage; -class McuToolChainPackage; -class McuTarget; namespace Sdk { McuPackage *createQtForMCUsPackage(); bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message); -void targetsAndPackages(const Utils::FilePath &qulDir, - QVector *packages, QVector *mcuTargets); +void targetsAndPackages(const Utils::FilePath &qulDir, McuSdkRepository *repo); Utils::FilePath kitsPath(const Utils::FilePath &dir); diff --git a/src/plugins/mcusupport/wizards/application/CMakeLists.txt b/src/plugins/mcusupport/wizards/application/CMakeLists.txt index e86a8fb6ac9..71c4e023432 100644 --- a/src/plugins/mcusupport/wizards/application/CMakeLists.txt +++ b/src/plugins/mcusupport/wizards/application/CMakeLists.txt @@ -14,6 +14,10 @@ else() endif() qul_target_qml_sources(%{ProjectName} %{MainQmlFile}) - app_target_setup_os(%{ProjectName}) -app_target_default_main(%{ProjectName} %{RootItemName}) + +if(Qul_VERSION VERSION_GREATER_EQUAL "2.0") + app_target_default_entrypoint(%{ProjectName} %{RootItemName}) +else() + app_target_default_main(%{ProjectName} %{RootItemName}) +endif() diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 9ca0e228c3c..e30aeb70647 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1219,17 +1219,14 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP connect(&m_launcher, &ApplicationLauncher::processExited, this, [this, runnable](int exitCode, QProcess::ExitStatus status) { - QString msg; - if (status == QProcess::CrashExit) - msg = tr("%1 crashed."); - else - msg = tr("%2 exited with code %1").arg(exitCode); + if (m_stopReported) + return; + const QString msg = (status == QProcess::CrashExit) + ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode); const QString displayName = runnable.command.executable().toUserOutput(); appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); - if (!m_stopReported) { - m_stopReported = true; - reportStopped(); - } + m_stopReported = true; + reportStopped(); }); connect(&m_launcher, &ApplicationLauncher::error, diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 0fe3867a7ef..467a33b40a3 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -38,6 +38,7 @@ add_qtc_plugin(QmlDesigner designermcumanager.cpp designermcumanager.h richtexteditordialog.cpp richtexteditordialog.h editorproxy.cpp editorproxy.h + boilerplate.qrc EXPLICIT_MOC components/propertyeditor/propertyeditorvalue.h components/connectioneditor/connectionviewwidget.h diff --git a/src/plugins/qmldesigner/boilerplate.qrc b/src/plugins/qmldesigner/boilerplate.qrc new file mode 100644 index 00000000000..2680ec0da9c --- /dev/null +++ b/src/plugins/qmldesigner/boilerplate.qrc @@ -0,0 +1,5 @@ + + + qmlprojectmaincpp.tpl + + diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index 6b81d1f92e2..e7e3d69d6a3 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -599,12 +599,20 @@ void FormEditorWidget::dropEvent(QDropEvent *dropEvent) ->viewManager().designerActionManager(); QHash addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); - // add image assets to Form Editor + // Create Image components for added image assets const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString); for (const QString &imgPath : addedImages) { QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {}, m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode()); } + + // Create Text components for added font assets + const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString); + for (const QString &fontPath : addedFonts) { + QString fontFamily = QFileInfo(fontPath).baseName(); + QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(), + m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode()); + } } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/integration/componentview.cpp b/src/plugins/qmldesigner/components/integration/componentview.cpp index 06aa47c7a50..a30423b4c0b 100644 --- a/src/plugins/qmldesigner/components/integration/componentview.cpp +++ b/src/plugins/qmldesigner/components/integration/componentview.cpp @@ -46,8 +46,7 @@ ComponentView::ComponentView(QObject *parent) void ComponentView::nodeAboutToBeRemoved(const ModelNode &removedNode) { - removeSingleNodeFromList(removedNode); - searchForComponentAndRemoveFromList(removedNode); + removeFromListRecursive(removedNode); } QStandardItemModel *ComponentView::standardItemModel() const @@ -75,7 +74,7 @@ void ComponentView::setComponentToMaster() m_componentAction->setCurrentIndex(indexOfMaster()); } -void ComponentView::removeSingleNodeFromList(const ModelNode &node) +void ComponentView::removeNodeFromList(const ModelNode &node) { for (int row = 0; row < m_standardItemModel->rowCount(); row++) { if (m_standardItemModel->item(row)->data(ModelNodeRole).toInt() == node.internalId()) @@ -83,6 +82,18 @@ void ComponentView::removeSingleNodeFromList(const ModelNode &node) } } +void ComponentView::addNodeToList(const ModelNode &node) +{ + if (hasEntryForNode(node)) + return; + + QString description = descriptionForNode(node); + auto item = new QStandardItem(description); + item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole); + item->setEditable(false); + m_standardItemModel->appendRow(item); +} + int ComponentView::indexForNode(const ModelNode &node) const { for (int row = 0; row < m_standardItemModel->rowCount(); row++) { @@ -112,7 +123,7 @@ bool ComponentView::hasEntryForNode(const ModelNode &node) const return indexForNode(node) >= 0; } -void ComponentView::addMasterDocument() +void ComponentView::ensureMasterDocument() { if (!hasMasterEntry()) { QStandardItem *item = new QStandardItem(QLatin1String("master")); @@ -122,9 +133,11 @@ void ComponentView::addMasterDocument() } } -void ComponentView::removeMasterDocument() +void ComponentView::maybeRemoveMasterDocument() { - m_standardItemModel->removeRow(indexOfMaster()); + int idx = indexOfMaster(); + if (idx >= 0 && m_standardItemModel->rowCount() == 1) + m_standardItemModel->removeRow(idx); } QString ComponentView::descriptionForNode(const ModelNode &node) const @@ -155,6 +168,15 @@ void ComponentView::updateDescription(const ModelNode &node) m_standardItemModel->item(nodeIndex)->setText(descriptionForNode(node)); } +bool ComponentView::isSubComponentNode(const ModelNode &node) const +{ + return node.nodeSourceType() == ModelNode::NodeWithComponentSource + || (node.hasParentProperty() + && !node.parentProperty().isDefaultProperty() + && node.metaInfo().isValid() + && node.metaInfo().isGraphicalItem()); +} + void ComponentView::modelAttached(Model *model) { if (AbstractView::model() == model) @@ -187,46 +209,25 @@ void ComponentView::nodeCreated(const ModelNode &createdNode) void ComponentView::searchForComponentAndAddToList(const ModelNode &node) { - bool masterNotAdded = true; - - foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) { - if (node.nodeSourceType() == ModelNode::NodeWithComponentSource - || (node.hasParentProperty() - && !node.parentProperty().isDefaultProperty() - && node.metaInfo().isValid() - && node.metaInfo().isGraphicalItem())) { - if (masterNotAdded) { - masterNotAdded = true; - addMasterDocument(); - } - - if (!hasEntryForNode(node)) { - QString description = descriptionForNode(node); - - auto item = new QStandardItem(description); - item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole); - item->setEditable(false); - removeSingleNodeFromList(node); //remove node if already present - m_standardItemModel->appendRow(item); + const auto nodeList = node.allSubModelNodesAndThisNode(); + bool hasMaster = false; + for (const ModelNode &childNode : nodeList) { + if (isSubComponentNode(childNode)) { + if (!hasMaster) { + hasMaster = true; + ensureMasterDocument(); } + addNodeToList(childNode); } } } -void ComponentView::searchForComponentAndRemoveFromList(const ModelNode &node) +void ComponentView::removeFromListRecursive(const ModelNode &node) { - QList nodeList; - nodeList.append(node); - nodeList.append(node.allSubModelNodes()); - - - foreach (const ModelNode &childNode, nodeList) { - if (childNode.nodeSourceType() == ModelNode::NodeWithComponentSource) - removeSingleNodeFromList(childNode); - } - - if (m_standardItemModel->rowCount() == 1) - removeMasterDocument(); + const auto nodeList = node.allSubModelNodesAndThisNode(); + for (const ModelNode &childNode : std::as_const(nodeList)) + removeNodeFromList(childNode); + maybeRemoveMasterDocument(); } void ComponentView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) @@ -240,4 +241,17 @@ void ComponentView::nodeIdChanged(const ModelNode& node, const QString& /*newId* { updateDescription(node); } + +void ComponentView::nodeSourceChanged(const ModelNode &node, const QString &/*newNodeSource*/) +{ + if (isSubComponentNode(node)) { + if (!hasEntryForNode(node)) { + ensureMasterDocument(); + addNodeToList(node); + } + } else { + removeNodeFromList(node); + maybeRemoveMasterDocument(); + } +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/integration/componentview.h b/src/plugins/qmldesigner/components/integration/componentview.h index d9b92085c48..28060a51883 100644 --- a/src/plugins/qmldesigner/components/integration/componentview.h +++ b/src/plugins/qmldesigner/components/integration/componentview.h @@ -62,6 +62,7 @@ public: const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override; void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override; + void nodeSourceChanged(const ModelNode &node, const QString &newNodeSource) override; QStandardItemModel *standardItemModel() const; @@ -76,16 +77,18 @@ signals: private: //functions void updateModel(); void searchForComponentAndAddToList(const ModelNode &node); - void searchForComponentAndRemoveFromList(const ModelNode &node); - void removeSingleNodeFromList(const ModelNode &node); + void removeFromListRecursive(const ModelNode &node); + void removeNodeFromList(const ModelNode &node); + void addNodeToList(const ModelNode &node); int indexForNode(const ModelNode &node) const; int indexOfMaster() const; bool hasMasterEntry() const; bool hasEntryForNode(const ModelNode &node) const; - void addMasterDocument(); - void removeMasterDocument(); + void ensureMasterDocument(); + void maybeRemoveMasterDocument(); QString descriptionForNode(const ModelNode &node) const; void updateDescription(const ModelNode &node); + bool isSubComponentNode(const ModelNode &node) const; private: QStandardItemModel *m_standardItemModel; diff --git a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h index f1b694c6880..66e93abda3a 100644 --- a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h +++ b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h @@ -36,6 +36,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -69,6 +70,7 @@ private: // functions void parseQuick3DAssetsDir(const QString &quick3DAssetsPath); void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {}); QStringList quick3DAssetPaths() const; + TypeName resolveDirQualifier(const QString &dirPath) const; private: // variables QFileSystemWatcher m_watcher; @@ -76,6 +78,7 @@ private: // variables // key: canonical directory path QMultiHash m_dirToQualifier; QUrl m_filePath; + QDir m_filePathDir; QPointer m_model; }; diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp index 7466604d054..4e1fd500664 100644 --- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp +++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp @@ -134,8 +134,11 @@ void SubComponentManager::parseDirectories() if (dirInfo.exists() && dirInfo.isDir()) parseDirectory(canonicalPath); - foreach (const QString &subDir, QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { - parseDirectory(canonicalPath + QLatin1Char('/') + subDir, true, subDir.toUtf8()); + const QStringList subDirs = QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot + | QDir::NoDotDot); + for (const QString &subDir : subDirs) { + const QString canSubPath = canonicalPath + QLatin1Char('/') + subDir; + parseDirectory(canSubPath, true, resolveDirQualifier(canSubPath)); } } @@ -146,8 +149,10 @@ void SubComponentManager::parseDirectories() foreach (const Import &import, m_imports) { if (import.isFileImport()) { QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); - if (dirInfo.exists() && dirInfo.isDir()) - parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); + if (dirInfo.exists() && dirInfo.isDir()) { + const QString canPath = dirInfo.canonicalFilePath(); + parseDirectory(canPath, true, resolveDirQualifier(canPath)); + } } else { QString url = import.url(); url.replace(QLatin1Char('.'), QLatin1Char('/')); @@ -445,6 +450,11 @@ QStringList SubComponentManager::quick3DAssetPaths() const return retPaths; } +TypeName SubComponentManager::resolveDirQualifier(const QString &dirPath) const +{ + return m_filePathDir.relativeFilePath(dirPath).toUtf8(); +} + /*! \class SubComponentManager @@ -472,10 +482,12 @@ void SubComponentManager::update(const QUrl &filePath, const QList &impo if (!m_filePath.isEmpty()) { const QString file = m_filePath.toLocalFile(); oldDir = QFileInfo(QFileInfo(file).path()); + m_filePathDir = QDir(); } if (!filePath.isEmpty()) { const QString file = filePath.toLocalFile(); newDir = QFileInfo(QFileInfo(file).path()); + m_filePathDir = {newDir.absoluteFilePath()}; } m_filePath = filePath; @@ -538,8 +550,10 @@ void SubComponentManager::updateImport(const Import &import) if (import.isFileImport()) { QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); - if (dirInfo.exists() && dirInfo.isDir()) - parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); + if (dirInfo.exists() && dirInfo.isDir()) { + const QString canPath = dirInfo.canonicalFilePath(); + parseDirectory(canPath, true, resolveDirQualifier(canPath)); + } } else { QString url = import.url(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index c678f3b06d7..3f6a04fde47 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -914,16 +914,30 @@ static QList generatePossibleFileImports(const QString &pat usedImportsSet.insert(i.info.path()); QList possibleImports; + const QStringList qmlList("*.qml"); + const QStringList qmldirList("qmldir"); - foreach (const QString &subDir, QDir(path).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { - QDir dir(path + "/" + subDir); - if (!dir.entryInfoList(QStringList("*.qml"), QDir::Files).isEmpty() - && dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty() - && !usedImportsSet.contains(dir.path())) { - QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir); - possibleImports.append(import); + QStringList fileImportPaths; + const QChar delimeter('/'); + + std::function checkDir; + checkDir = [&](const QString &checkPath) { + const QStringList entries = QDir(checkPath).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot); + const QString checkPathDelim = checkPath + delimeter; + for (const QString &entry : entries) { + QDir dir(checkPathDelim + entry); + const QString dirPath = dir.path(); + if (!dir.entryInfoList(qmlList, QDir::Files).isEmpty() + && dir.entryInfoList(qmldirList, QDir::Files).isEmpty() + && !usedImportsSet.contains(dirPath)) { + const QString importName = dir.path().mid(path.size() + 1); + QmlDesigner::Import import = QmlDesigner::Import::createFileImport(importName); + possibleImports.append(import); + } + checkDir(dirPath); } - } + }; + checkDir(path); return possibleImports; } @@ -931,17 +945,44 @@ static QList generatePossibleFileImports(const QString &pat static QList generatePossibleLibraryImports(const QHash &filteredPossibleImportKeys) { QList possibleImports; + QSet controlsImplVersions; + bool hasVersionedControls = false; + bool hasVersionlessControls = false; + const QString controlsName = "QtQuick.Controls"; + const QString controlsImplName = "QtQuick.Controls.impl"; - foreach (const ImportKey &importKey, filteredPossibleImportKeys) { + for (const ImportKey &importKey : filteredPossibleImportKeys) { QString libraryName = importKey.splitPath.join(QLatin1Char('.')); int majorVersion = importKey.majorVersion; if (majorVersion >= 0) { int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion; QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion); possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version)); + + // In Qt6, QtQuick.Controls itself doesn't have any version as it has no types, + // so it never gets added normally to possible imports. + // We work around this by injecting corresponding QtQuick.Controls version for each + // found impl version, if no valid QtQuick.Controls versions are found. + if (!hasVersionedControls) { + if (libraryName == controlsImplName) + controlsImplVersions.insert(version); + else if (libraryName == controlsName) + hasVersionedControls = true; + } + } else if (!hasVersionlessControls && libraryName == controlsName) { + // If QtQuick.Controls module is not included even in non-versioned, it means + // QtQuick.Controls is either in use or not available at all, + // so we shouldn't inject it. + hasVersionlessControls = true; } } + if (hasVersionlessControls && !hasVersionedControls && !controlsImplVersions.isEmpty()) { + for (const auto &version : std::as_const(controlsImplVersions)) + possibleImports.append(QmlDesigner::Import::createLibraryImport(controlsName, version)); + } + + return possibleImports; } @@ -2111,7 +2152,7 @@ void TextToModelMerger::collectLinkErrors(QList *errors, const void TextToModelMerger::collectImportErrors(QList *errors) { if (m_rewriterView->model()->imports().isEmpty()) { - const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found")); + const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found.")); errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); } @@ -2137,7 +2178,7 @@ void TextToModelMerger::collectImportErrors(QList *errors) SourceLocation(0, 0, 0, 0), QCoreApplication::translate( "QmlDesigner::TextToModelMerger", - "QtQuick 6 is not supported with a Qt 5 kit.")); + "Qt Quick 6 is not supported with a Qt 5 kit.")); errors->prepend( DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); @@ -2161,7 +2202,7 @@ void TextToModelMerger::collectImportErrors(QList *errors) diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", - "Unsupported QtQuick version")); + "Unsupported Qt Quick version.")); errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); } diff --git a/src/plugins/qmldesigner/generatecmakelists.cpp b/src/plugins/qmldesigner/generatecmakelists.cpp index 8e96c0ec95e..fdadd059277 100644 --- a/src/plugins/qmldesigner/generatecmakelists.cpp +++ b/src/plugins/qmldesigner/generatecmakelists.cpp @@ -30,9 +30,11 @@ #include #include +#include #include #include +#include #include @@ -44,21 +46,15 @@ using namespace Utils; namespace QmlDesigner { -namespace GenerateCmakeLists { -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"; +namespace GenerateCmake { void generateMenuEntry() { Core::ActionContainer *buildMenu = Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); - const Core::Context projectCntext(QmlProjectManager::Constants::QML_PROJECT_ID); auto action = new QAction("Generate CMakeLists.txt files"); - QObject::connect(action, &QAction::triggered, GenerateCmakeLists::onGenerateCmakeLists); + QObject::connect(action, &QAction::triggered, GenerateCmake::onGenerateCmakeLists); Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists"); buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN); @@ -71,9 +67,33 @@ void generateMenuEntry() void onGenerateCmakeLists() { - generateMainCmake(ProjectExplorer::SessionManager::startupProject()->projectDirectory()); + FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory(); + GenerateCmakeLists::generateMainCmake(rootDir); + GenerateEntryPoints::generateMainCpp(rootDir); + GenerateEntryPoints::generateMainQml(rootDir); } +bool writeFile(const FilePath &filePath, const QString &fileContent) +{ + QFile file(filePath.toString()); + file.open(QIODevice::WriteOnly); + QTextStream stream(&file); + stream << fileContent; + file.close(); + + return true; +} + +} + +namespace GenerateCmakeLists { + +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"; + QStringList processDirectory(const FilePath &dir) { QStringList moduleNames; @@ -149,9 +169,7 @@ const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\t QString generateModuleCmake(const FilePath &dir) { QString fileContent; - const QStringList qmlFilesOnly("*.qml"); const QStringList qmldirFilesOnly(QMLDIRFILENAME); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); if (!qmldirFileList.isEmpty()) { @@ -161,18 +179,15 @@ QString generateModuleCmake(const FilePath &dir) } } - FilePaths qmlFileList = dir.dirEntries(qmlFilesOnly, FILES_ONLY); + QStringList qmlFileList = getDirectoryTreeQmls(dir); QString qmlFiles; - for (FilePath &qmlFile : qmlFileList) { - if (project->isKnownFile(qmlFile)) - qmlFiles.append(QString("\t\t%1\n").arg(qmlFile.fileName())); - } + for (QString &qmlFile : qmlFileList) + qmlFiles.append(QString("\t\t%1\n").arg(qmlFile)); QStringList resourceFileList = getDirectoryTreeResources(dir); QString resourceFiles; - for (QString &resourceFile : resourceFileList) { + for (QString &resourceFile : resourceFileList) resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); - } QString moduleContent; if (!qmlFiles.isEmpty()) { @@ -226,6 +241,31 @@ QStringList getSingletonsFromQmldirFile(const FilePath &filePath) return singletons; } +QStringList getDirectoryTreeQmls(const FilePath &dir) +{ + const QStringList qmlFilesOnly("*.qml"); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + QStringList qmlFileList; + + FilePaths thisDirFiles = dir.dirEntries(qmlFilesOnly, FILES_ONLY); + for (FilePath &file : thisDirFiles) { + if (!isFileBlacklisted(file.fileName()) && + project->isKnownFile(file)) { + qmlFileList.append(file.fileName()); + } + } + + FilePaths subDirsList = dir.dirEntries(DIRS_ONLY); + for (FilePath &subDir : subDirsList) { + QStringList subDirQmlFiles = getDirectoryTreeQmls(subDir); + for (QString &qmlFile : subDirQmlFiles) { + qmlFileList.append(subDir.fileName().append('/').append(qmlFile)); + } + } + + return qmlFileList; +} + QStringList getDirectoryTreeResources(const FilePath &dir) { ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); @@ -255,11 +295,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir) void createCmakeFile(const FilePath &dir, const QString &content) { FilePath filePath = dir.pathAppended(CMAKEFILENAME); - QFile cmakeFile(filePath.toString()); - cmakeFile.open(QIODevice::WriteOnly); - QTextStream stream(&cmakeFile); - stream << content; - cmakeFile.close(); + GenerateCmake::writeFile(filePath, content); } bool isFileBlacklisted(const QString &fileName) @@ -269,4 +305,48 @@ bool isFileBlacklisted(const QString &fileName) } } + +namespace GenerateEntryPoints { +bool generateEntryPointFiles(const FilePath &dir) +{ + bool cppOk = generateMainCpp(dir); + bool qmlOk = generateMainQml(dir); + + return cppOk && qmlOk; } + +const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl"; +const char MAIN_CPPFILE_NAME[] = "main.cpp"; + +bool generateMainCpp(const FilePath &dir) +{ + QFile templatefile(MAIN_CPPFILE_CONTENT); + templatefile.open(QIODevice::ReadOnly); + QTextStream stream(&templatefile); + QString content = stream.readAll(); + templatefile.close(); + + FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME); + return GenerateCmake::writeFile(filePath, content); +} + +const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n"; +const char MAIN_QMLFILE_NAME[] = "main.qml"; + +bool generateMainQml(const FilePath &dir) +{ + 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::writeFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass)); +} + +} + +} + diff --git a/src/plugins/qmldesigner/generatecmakelists.h b/src/plugins/qmldesigner/generatecmakelists.h index 55b0f6958d1..18b28f88d58 100644 --- a/src/plugins/qmldesigner/generatecmakelists.h +++ b/src/plugins/qmldesigner/generatecmakelists.h @@ -30,16 +30,25 @@ #include namespace QmlDesigner { -namespace GenerateCmakeLists { +namespace GenerateCmake { void generateMenuEntry(); void onGenerateCmakeLists(); +bool writeFile(const Utils::FilePath &filePath, const QString &fileContent); +} +namespace GenerateCmakeLists { void generateMainCmake(const Utils::FilePath &rootDir); void generateSubdirCmake(const Utils::FilePath &dir); QString generateModuleCmake(const Utils::FilePath &dir); QStringList processDirectory(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); bool isFileBlacklisted(const QString &fileName); } +namespace GenerateEntryPoints { +bool generateEntryPointFiles(const Utils::FilePath &dir); +bool generateMainCpp(const Utils::FilePath &dir); +bool generateMainQml(const Utils::FilePath &dir); +} } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 014c79b59d3..b8affa11ff7 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -223,7 +223,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) GenerateResource::generateMenuEntry(); - GenerateCmakeLists::generateMenuEntry(); + GenerateCmake::generateMenuEntry(); const QString fontPath = Core::ICore::resourcePath( diff --git a/src/plugins/qmldesigner/qmlprojectmaincpp.tpl b/src/plugins/qmldesigner/qmlprojectmaincpp.tpl new file mode 100644 index 00000000000..7b68c637d05 --- /dev/null +++ b/src/plugins/qmldesigner/qmlprojectmaincpp.tpl @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Quick Studio Components. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +int main(int argc, char *argv[]) +{ + qputenv("QT_LOGGING_RULES", "qt.qml.connections=false"); + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl url(u"qrc:Main/main.qml"_qs); + QObject::connect( + &engine, &QQmlApplicationEngine::objectCreated, &app, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, + Qt::QueuedConnection); + + engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml"); + engine.addImportPath(":/"); + + engine.load(url); + + if (engine.rootObjects().isEmpty()) { + return -1; + } + + return app.exec(); +} diff --git a/src/plugins/qmljstools/qmljsmodelmanager.cpp b/src/plugins/qmljstools/qmljsmodelmanager.cpp index 004f844f1cf..1f6d7e6a5ca 100644 --- a/src/plugins/qmljstools/qmljsmodelmanager.cpp +++ b/src/plugins/qmljstools/qmljsmodelmanager.cpp @@ -83,7 +83,7 @@ static void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &proje if (projectInfo.project) activeTarget = projectInfo.project->activeTarget(); Kit *activeKit = activeTarget ? activeTarget->kit() : KitManager::defaultKit(); - const QHash replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath}}; + const QHash replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath.toString()}}; for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements); @@ -146,17 +146,17 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject( } if (qtVersion && qtVersion->isValid()) { projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT); - projectInfo.qtQmlPath = qtVersion->qmlPath().toFileInfo().canonicalFilePath(); + projectInfo.qtQmlPath = qtVersion->qmlPath(); projectInfo.qtVersionString = qtVersion->qtVersionString(); } else if (!activeKit || !activeKit->value(QtSupport::SuppliesQtQuickImportPath::id(), false).toBool()) { - projectInfo.qtQmlPath = QFileInfo(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)).canonicalFilePath(); + projectInfo.qtQmlPath = FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)); projectInfo.qtVersionString = QLatin1String(qVersion()); } projectInfo.qmlDumpPath.clear(); const QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(activeKit); if (version && projectInfo.tryQmlDump) { - projectInfo.qmlDumpPath = version->qmlplugindumpFilePath().toString(); + projectInfo.qmlDumpPath = version->qmlplugindumpFilePath(); projectInfo.qmlDumpHasRelocatableFlag = version->hasQmlDumpWithRelocatableFlag(); } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 90d141808a5..a0ca47c5413 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -502,6 +502,7 @@ public: void duplicateSelection(bool comment); void updateCannotDecodeInfo(); void collectToCircularClipboard(); + void setClipboardSelection(); void ctor(const QSharedPointer &doc); void handleHomeKey(bool anchor, bool block); @@ -5217,7 +5218,8 @@ void TextEditorWidget::mousePressEvent(QMouseEvent *e) void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e) { - if (d->m_linkPressed && d->isMouseNavigationEvent(e) && e->button() == Qt::LeftButton) { + const Qt::MouseButton button = e->button(); + if (d->m_linkPressed && d->isMouseNavigationEvent(e) && button == Qt::LeftButton) { EditorManager::addCurrentPositionToNavigationHistory(); bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit()) || (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier)); @@ -5227,12 +5229,22 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e) if (self && self->openLink(symbolLink, inNextSplit)) self->d->clearLink(); }, true, inNextSplit); + } else if (button == Qt::MiddleButton + && !isReadOnly() + && QGuiApplication::clipboard()->supportsSelection()) { + if (!(e->modifiers() & Qt::AltModifier)) + doSetTextCursor(cursorForPosition(e->pos())); + if (const QMimeData *md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection)) + insertFromMimeData(md); + e->accept(); + return; } if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e)) return; QPlainTextEdit::mouseReleaseEvent(e); + d->setClipboardSelection(); } void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e) @@ -5247,6 +5259,14 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e) } QPlainTextEdit::mouseDoubleClickEvent(e); + d->setClipboardSelection(); +} + +void TextEditorWidgetPrivate::setClipboardSelection() +{ + QClipboard *clipboard = QGuiApplication::clipboard(); + if (m_cursors.hasSelection() && clipboard->supportsSelection()) + clipboard->setMimeData(q->createMimeDataFromSelection(), QClipboard::Selection); } void TextEditorWidget::leaveEvent(QEvent *e) diff --git a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp index 0dc78ecd759..04660c7a9c7 100644 --- a/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp +++ b/tests/auto/qml/codemodel/importscheck/tst_importscheck.cpp @@ -267,7 +267,7 @@ void tst_ImportCheck::importTypes() // the default qtQmlPath is based on the Qt version in use otherwise ModelManagerInterface::ProjectInfo defaultProject; - defaultProject.qtQmlPath = importPath; + defaultProject.qtQmlPath = Utils::FilePath::fromString(importPath); modelManager->setDefaultProject(defaultProject, nullptr); modelManager->activateScan();