Merge remote-tracking branch 'origin/6.0'

Change-Id: I9b824b8bb7b0b5d76e9e8f28f909b542adf773f0
This commit is contained in:
Eike Ziller
2021-10-27 11:50:59 +02:00
98 changed files with 1529 additions and 1019 deletions

38
dist/changes-6.0.0.md vendored
View File

@@ -21,21 +21,30 @@ Editing
* Added support for multiple cursor editing (QTCREATORBUG-16013) * Added support for multiple cursor editing (QTCREATORBUG-16013)
* Added import and export for font settings (QTCREATORBUG-6833) * Added import and export for font settings (QTCREATORBUG-6833)
* Fixed missing permissions update when files change (QTCREATORBUG-22447)
### C++ ### C++
* Updated to LLVM 13 * Updated to LLVM 13
* Added completion and function hint to `clangd` support
* Added option for saving open files automatically after refactoring * Added option for saving open files automatically after refactoring
(QTCREATORBUG-25924) (QTCREATORBUG-25924)
* Added information about source to tooltip on diagnostics
* Fixed `Insert Definition` for templates with value parameters * Fixed `Insert Definition` for templates with value parameters
(QTCREATORBUG-26113) (QTCREATORBUG-26113)
* Fixed canceling of C++ parsing on configuration change (QTCREATORBUG-24890) * 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 ### QML
* Improved wizards for Qt 6.2 (QTCREATORBUG-26170) * Improved wizards for Qt 6.2 (QTCREATORBUG-26170)
* Simplified wizards * Simplified wizards
* Fixed wrong warning on JavaScript equality checks (QTCREATORBUG-25917)
### Language Server Protocol ### Language Server Protocol
@@ -53,11 +62,16 @@ Projects
* Fixed redundant output on process crash (QTCREATORBUG-26049) * Fixed redundant output on process crash (QTCREATORBUG-26049)
* Fixed duplicates in file rename dialog (QTCREATORBUG-26268) * Fixed duplicates in file rename dialog (QTCREATORBUG-26268)
* Fixed variable expansion for working directory (QTCREATORBUG-26274) * 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 ### CMake
* Removed separate `<Headers>` node from project tree (QTCREATORBUG-18206, * Removed separate `<Headers>` node from project tree (QTCREATORBUG-18206,
QTCREATORBUG-24609, QTCREATORBUG-25407) QTCREATORBUG-24609, QTCREATORBUG-25407)
* Improved performance while loading large projects
* Fixed that CMake warnings and project loading errors were not added to * Fixed that CMake warnings and project loading errors were not added to
`Issues` pane (QTCREATORBUG-26231) `Issues` pane (QTCREATORBUG-26231)
* Fixed header file handling when mentioned in target sources * Fixed header file handling when mentioned in target sources
@@ -70,6 +84,19 @@ Projects
* Fixed crash when canceling parsing (QTCREATORBUG-26333) * 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 Version Control Systems
----------------------- -----------------------
@@ -101,6 +128,10 @@ Platforms
* Added details to device settings (QTCREATORBUG-23991) * Added details to device settings (QTCREATORBUG-23991)
* Added filter field for Android SDK manager * Added filter field for Android SDK manager
### WebAssembly
* Fixed running applications (QTCREATORBUG-25905, QTCREATORBUG-26189)
### Docker ### Docker
* Various improvements * Various improvements
@@ -125,12 +156,14 @@ Eike Ziller
Fawzi Mohamed Fawzi Mohamed
Henning Gruendl Henning Gruendl
Ihor Dutchak Ihor Dutchak
Ivan Komissarov
Jaroslaw Kobus Jaroslaw Kobus
Johanna Vanhatapio Johanna Vanhatapio
Jonas Karlsson Jonas Karlsson
Kai Köhne Kai Köhne
Kama Wójcik Kama Wójcik
Knud Dollereder Knud Dollereder
Leena Miettinen
Li Xi Li Xi
Loren Burkholder Loren Burkholder
Mahmoud Badri Mahmoud Badri
@@ -143,10 +176,13 @@ Petar Perisin
Piotr Mikolajczyk Piotr Mikolajczyk
Samuel Ghinet Samuel Ghinet
Shantanu Tushar Shantanu Tushar
Tapani Mattila
Tasuku Suzuki Tasuku Suzuki
Thiago Macieira Thiago Macieira
Thomas Hartmann Thomas Hartmann
Tim Jenssen Tim Jenssen
Tony Leinonen Tony Leinonen
Tor Arne Vestbø Tor Arne Vestbø
Tuomo Pelkonen
Vikas Pachdha
Vladimir Serdyuk Vladimir Serdyuk

View File

@@ -0,0 +1,44 @@
<?xml version="1.0"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.qtproject.example"
android:installLocation="auto"
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
android:versionName="-- %%INSERT_VERSION_NAME%% --">
<!-- %%INSERT_PERMISSIONS -->
<!-- %%INSERT_FEATURES -->
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true" />
<application
android:name="org.qtproject.qt.android.bindings.QtApplication"
android:extractNativeLibs="true"
android:hardwareAccelerated="true"
android:label="-- %%INSERT_APP_NAME%% --"
android:requestLegacyExternalStorage="true">
<activity
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:label="-- %%INSERT_APP_NAME%% --"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="-- %%INSERT_APP_LIB_NAME%% --" />
<meta-data
android:name="android.app.arguments"
android:value="-- %%INSERT_APP_ARGUMENTS%% --" />
<meta-data
android:name="android.app.extract_android_style"
android:value="minimal" />
</activity>
</application>
</manifest>

View File

@@ -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
}

View File

@@ -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 $<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>)
target_link_libraries(accelbubbleexample
PRIVATE Qt6::Quick Qt6::Sensors Qt6::Svg Qt6::Xml)
qt_finalize_executable(accelbubbleexample)

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>accelbubble</string>
<key>CFBundleExecutable</key>
<string>accelbubble</string>
<key>CFBundleGetInfoString</key>
<string>Created by Qt</string>
<key>CFBundleIdentifier</key>
<string>io.qt.accelbubble</string>
<key>CFBundleName</key>
<string>accelbubble</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NOTE</key>
<string>This file was generated by Qt.</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
</dict>
</plist>

View File

@@ -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

View File

@@ -1,14 +1,13 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
QQmlApplicationEngine engine; QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml")); const QUrl url(u"qrc:/accelbubble/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) { &app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl) if (!obj && url == objUrl)

View File

@@ -1,49 +1,22 @@
import QtQuick 2.14 import QtQuick
import QtQuick.Window 2.14 import QtSensors
import QtSensors 5.12
Window { Window {
id: window
visible: true
property alias mainWindow: mainWindow
property alias bubble: bubble
Rectangle {
id: mainWindow id: mainWindow
color: "#ffffff" width: 320
anchors.fill: parent height: 480
visible: true
Bubble { title: qsTr("Accelerate Bubble")
id: bubble readonly property double radians_to_degrees: 180 / Math.PI
x: bubble.centerX - bubbleCenter
y: bubble.centerY - bubbleCenter
bubbleCenter: bubble.width /2
centerX: mainWindow.width /2
centerY: mainWindow.height /2
Behavior on y {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
Behavior on x {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
}
}
Accelerometer { Accelerometer {
id: accel id: accel
dataRate: 100 dataRate: 100
active: true active:true
readonly property double radians_to_degrees: 180 / Math.PI
onReadingChanged: { onReadingChanged: {
var newX = (bubble.x + calcRoll(accel.reading.x, accel.reading.y, accel.reading.z) * 0.1) 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) * 0.1) var newY = (bubble.y - calcPitch(accel.reading.x, accel.reading.y, accel.reading.z) * .1)
if (isNaN(newX) || isNaN(newY)) if (isNaN(newX) || isNaN(newY))
return; return;
@@ -66,9 +39,33 @@ Window {
} }
function calcPitch(x,y,z) { 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) { 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
}
}
} }
} }

View File

@@ -1,7 +0,0 @@
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>Bluebubble.svg</file>
<file>Bubble.qml</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -36,19 +36,21 @@
\title Creating a Mobile Application \title Creating a Mobile Application
This tutorial describes developing Qt Quick applications for Android and iOS This tutorial describes how to use \QC to develop Qt Quick applications for
devices using Qt Quick Controls. Android and iOS devices when using Qt 6 as the minimum Qt version and CMake
We use \QC to implement a Qt Quick application as the build system.
that accelerates an SVG (Scalable Vector Graphics) image based on the
changing accelerometer values. 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 \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 \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 set up the development environment for the device platform and configure a
connection between \QC and the mobile device. connection between \QC and the mobile device.
@@ -63,163 +65,58 @@
\include qtquick-tutorial-create-empty-project.qdocinc qtquick empty application \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 The main view of the application displays an SVG bubble image that moves
around the screen when you tilt the device. around the screen when you tilt the device.
We use \e {Bluebubble.svg} in this tutorial, but you can use any other 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 > We create the main view in the \e main.qml file by adding an \l Image
\uicontrol {Default Components} > \uicontrol Basic, select component with \e Bluebubble.svg as the source:
\uicontrol Rectangle and drag-and-drop it to \e Window
in \l Navigator.
\li Select the rectangle instance in \uicontrol Navigator to edit its \quotefromfile accelbubble/main.qml
properties in \l Properties: \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 \printuntil y:
\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
We now want to add code to move the bubble based on Accelerometer sensor 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 values. First, we add the following import statement:
it in \l {Text Editor}:
\list 1
\li Add the following import statement to \e main.qml:
\quotefromfile accelbubble/main.qml \quotefromfile accelbubble/main.qml
\skipto QtSensors \skipto QtSensors
\printline QtSensors \printline QtSensors
\li Add the \l{Accelerometer} component with the necessary properties: Next, we add the \l{Accelerometer} component with the necessary properties:
\skipto Accelerometer \skipto Accelerometer
\printuntil radians_to_degrees \printuntil active
\skipto }
\printuntil }
\li Add the following JavaScript functions that calculate the Then, we add the following JavaScript functions that calculate the
x and y position of the bubble based on the current Accelerometer x and y position of the bubble based on the current Accelerometer
values: values:
\quotefromfile accelbubble/main.qml \quotefromfile accelbubble/main.qml
\skipto function \skipto function
\printuntil Math.atan2(x \printuntil }
\printuntil } \printuntil }
\li Add the following JavaScript code for \c onReadingChanged signal of We add the following JavaScript code for \c onReadingChanged signal of
Accelerometer component to make the bubble move when the Accelerometer Accelerometer component to make the bubble move when the Accelerometer
values change: values change:
@@ -231,7 +128,8 @@
within the bounds of the screen. If the Accelerometer returns within the bounds of the screen. If the Accelerometer returns
\e {not a number} (NaN), the value is ignored and the bubble \e {not a number} (NaN), the value is ignored and the bubble
position is not updated. position is not updated.
\li Add \l SmoothedAnimation behavior on the \c x and \c y properties of
We add \l SmoothedAnimation behavior on the \c x and \c y properties of
the bubble to make its movement look smoother. the bubble to make its movement look smoother.
\quotefromfile accelbubble/main.qml \quotefromfile accelbubble/main.qml
@@ -239,7 +137,6 @@
\printuntil x \printuntil x
\printuntil } \printuntil }
\printuntil } \printuntil }
\endlist
\section1 Locking Device Orientation \section1 Locking Device Orientation
@@ -248,35 +145,69 @@
better for the screen orientation to be fixed. better for the screen orientation to be fixed.
To lock the orientation to portrait or landscape on Android, specify it in 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}. see \l{Editing Manifest Files}.
On iOS, you can lock the device orientation in an Info.plist file that you \image qtquick-mobile-tutorial-manifest.png "Accelbubble manifest file"
specify in the .pro file as the value of the QMAKE_INFO_PLIST variable.
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 \section1 Adding Dependencies
Update the accelbubble.pro file with the following library dependency You must tell the build system which Qt modules your application needs by
information: 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 The \e CMakeLists.txt file should contain the following entries that tell
QT += quick sensors svg xml CMake to look up the Qt installation and import the Qt Sensors, Qt SVG,
\endcode and Qt XML modules needed by the application:
On iOS, you must link to the above libraries statically, by adding the \quotefromfile accelbubble/CMakeLists.txt
plugin names explicitly as values of the QTPLUGIN variable. Specify a \skipto find_package
qmake scope for iOS builds (which can also contain the QMAKE_INFO_PLIST \printuntil REQUIRED
variable):
\code You also need to add the Qt modules to the list of target link libraries.
ios { \c target_link_libraries tells CMake that the accelbubble executable uses
QTPLUGIN += qsvg qsvgicon qtsensors_ios the Qt Sensors, Qt SVG, and Qt XML modules by referencing the targets
QMAKE_INFO_PLIST = Info.plist imported by the \c find_package() call above. This adds the necessary
} arguments to the linker and makes sure that the appropriate include
\endcode directories and compiler definitions are passed to the C++ compiler.
After adding the dependencies, select \uicontrol Build > \uicontrol {Run qmake} to apply \skipto target_link_libraries(accelbubble
the changes to the Makefile of the project. \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 \section1 Running the Application
@@ -292,7 +223,7 @@
If you are using a device running Android v4.2.2, it should prompt you to 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 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 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. \uicontrol OK.
\li To run the application on the device, press \key {Ctrl+R}. \li To run the application on the device, press \key {Ctrl+R}.

View File

@@ -184,18 +184,14 @@ void Qt5RenderNodeInstanceServer::completeComponent(const CompleteComponentComma
{ {
Qt5NodeInstanceServer::completeComponent(command); Qt5NodeInstanceServer::completeComponent(command);
QList<ServerNodeInstance> instanceList; const QVector<qint32> ids = command.instances();
foreach (qint32 instanceId, command.instances()) { for (qint32 instanceId : ids) {
if (hasInstanceForId(instanceId)) { if (hasInstanceForId(instanceId)) {
ServerNodeInstance instance = instanceForId(instanceId); ServerNodeInstance instance = instanceForId(instanceId);
if (instance.isValid()) { if (instance.isValid())
instanceList.append(instance);
m_dirtyInstanceSet.insert(instance); m_dirtyInstanceSet.insert(instance);
} }
} }
}
nodeInstanceClient()->pixmapChanged(createPixmapChangedCommand(instanceList));
} }
void QmlDesigner::Qt5RenderNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command) void QmlDesigner::Qt5RenderNodeInstanceServer::removeSharedMemory(const QmlDesigner::RemoveSharedMemoryCommand &command)

View File

@@ -33,7 +33,9 @@ import StudioTheme 1.0 as StudioTheme
PropertyEditorPane { PropertyEditorPane {
id: itemPane id: itemPane
ComponentSection {} ComponentSection {
showState: true
}
GeometrySection {} GeometrySection {}
@@ -82,22 +84,6 @@ PropertyEditorPane {
ExpandingSpacer {} 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 {}
}
} }
} }

View File

@@ -41,7 +41,7 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
Controls.Label { 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 font.pixelSize: StudioTheme.Values.myFontSize * 1.5
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View File

@@ -32,7 +32,9 @@ import StudioTheme 1.0 as StudioTheme
PropertyEditorPane { PropertyEditorPane {
id: itemPane id: itemPane
ComponentSection {} ComponentSection {
showState: majorVersion >= 6
}
Column { Column {
anchors.left: parent.left anchors.left: parent.left

View File

@@ -787,7 +787,9 @@ SecondColumnLayout {
ControlLabel { ControlLabel {
text: "Hex" text: "Hex"
width: StudioTheme.Values.colorEditorPopupHexLabelWidth width: 2 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
+ StudioTheme.Values.controlGap
horizontalAlignment: Text.AlignLeft
} }
} }

View File

@@ -32,11 +32,14 @@ import HelperWidgets 2.0
import StudioTheme 1.0 as StudioTheme import StudioTheme 1.0 as StudioTheme
Section { Section {
id: root
caption: qsTr("Component") caption: qsTr("Component")
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
property bool showState: false
SectionLayout { SectionLayout {
PropertyLabel { text: qsTr("Type") } PropertyLabel { text: qsTr("Type") }
@@ -262,5 +265,26 @@ Section {
onCanceled: hideWidget() 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 {}
}
} }
} }

View File

@@ -33,13 +33,13 @@ Item {
property string propertyName property string propertyName
property alias decimals: spinBox.decimals property alias decimals: spinBox.decimals
property alias value: spinBox.realValue property alias value: spinBox.realValue
property alias minimumValue: spinBox.realFrom property alias minimumValue: spinBox.realFrom
property alias maximumValue: spinBox.realTo property alias maximumValue: spinBox.realTo
property alias stepSize: spinBox.realStepSize property alias stepSize: spinBox.realStepSize
property alias pixelsPerUnit: spinBox.pixelsPerUnit
width: 90 width: 90
implicitHeight: spinBox.height implicitHeight: spinBox.height
@@ -52,6 +52,8 @@ Item {
StudioControls.RealSpinBox { StudioControls.RealSpinBox {
id: spinBox id: spinBox
__devicePixelRatio: devicePixelRatio()
width: wrapper.width width: wrapper.width
actionIndicatorVisible: false actionIndicatorVisible: false

View File

@@ -199,8 +199,6 @@ QtObject {
property real colorEditorPopupCmoboBoxWidth: 110 property real colorEditorPopupCmoboBoxWidth: 110
property real colorEditorPopupSpinBoxWidth: 54 property real colorEditorPopupSpinBoxWidth: 54
property real colorEditorPopupHexLabelWidth: 20
// Theme Colors // Theme Colors
property string themePanelBackground: Theme.color(Theme.DSpanelBackground) property string themePanelBackground: Theme.color(Theme.DSpanelBackground)

View File

@@ -133,8 +133,8 @@ ModelManagerInterface::ModelManagerInterface(QObject *parent)
qRegisterMetaType<QmlJS::PathAndLanguage>("QmlJS::PathAndLanguage"); qRegisterMetaType<QmlJS::PathAndLanguage>("QmlJS::PathAndLanguage");
qRegisterMetaType<QmlJS::PathsAndLanguages>("QmlJS::PathsAndLanguages"); qRegisterMetaType<QmlJS::PathsAndLanguages>("QmlJS::PathsAndLanguages");
m_defaultProjectInfo.qtQmlPath = QFileInfo( m_defaultProjectInfo.qtQmlPath =
QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)).canonicalFilePath(); FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
m_defaultProjectInfo.qtVersionString = QLibraryInfo::version().toString(); m_defaultProjectInfo.qtVersionString = QLibraryInfo::version().toString();
updateImportPaths(); updateImportPaths();
@@ -1217,16 +1217,14 @@ void ModelManagerInterface::updateImportPaths()
} }
for (const ProjectInfo &pInfo : qAsConst(m_projects)) { for (const ProjectInfo &pInfo : qAsConst(m_projects)) {
if (!pInfo.qtQmlPath.isEmpty()) { if (!pInfo.qtQmlPath.isEmpty())
allImportPaths.maybeInsert(Utils::FilePath::fromString(pInfo.qtQmlPath), allImportPaths.maybeInsert(pInfo.qtQmlPath, Dialect::QmlQtQuick2);
Dialect::QmlQtQuick2);
}
} }
{ {
const QString pathAtt = defaultProjectInfo().qtQmlPath; const FilePath pathAtt = defaultProjectInfo().qtQmlPath;
if (!pathAtt.isEmpty()) if (!pathAtt.isEmpty())
allImportPaths.maybeInsert(Utils::FilePath::fromString(pathAtt), Dialect::QmlQtQuick2); allImportPaths.maybeInsert(pathAtt, Dialect::QmlQtQuick2);
} }
for (const auto &importPath : defaultProjectInfo().importPaths) { for (const auto &importPath : defaultProjectInfo().importPaths) {
@@ -1435,7 +1433,7 @@ LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const
{ {
const ProjectInfo info = projectInfoForPath(doc->fileName()); const ProjectInfo info = projectInfoForPath(doc->fileName());
if (!info.qtQmlPath.isEmpty()) if (!info.qtQmlPath.isEmpty())
return m_validSnapshot.libraryInfo(info.qtQmlPath); return m_validSnapshot.libraryInfo(info.qtQmlPath.toString());
return LibraryInfo(); return LibraryInfo();
} }
@@ -1483,13 +1481,13 @@ ViewerContext ModelManagerInterface::getVContext(const ViewerContext &vCtx,
switch (res.language.dialect()) { switch (res.language.dialect()) {
case Dialect::AnyLanguage: case Dialect::AnyLanguage:
case Dialect::Qml: case Dialect::Qml:
maybeAddPath(res, info.qtQmlPath); maybeAddPath(res, info.qtQmlPath.toString());
Q_FALLTHROUGH(); Q_FALLTHROUGH();
case Dialect::QmlQtQuick2: case Dialect::QmlQtQuick2:
case Dialect::QmlQtQuick2Ui: case Dialect::QmlQtQuick2Ui:
{ {
if (res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) if (res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui)
maybeAddPath(res, info.qtQmlPath); maybeAddPath(res, info.qtQmlPath.toString());
QList<Dialect> languages = res.language.companionLanguages(); QList<Dialect> languages = res.language.companionLanguages();
auto addPathsOnLanguageMatch = [&](const PathsAndLanguages &importPaths) { auto addPathsOnLanguageMatch = [&](const PathsAndLanguages &importPaths) {
@@ -1534,7 +1532,7 @@ ViewerContext ModelManagerInterface::getVContext(const ViewerContext &vCtx,
for (const QString &path : qAsConst(defaultVCtx.paths)) for (const QString &path : qAsConst(defaultVCtx.paths))
maybeAddPath(res, path); maybeAddPath(res, path);
if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml) 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 if (res.language == Dialect::AnyLanguage || res.language == Dialect::Qml
|| res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) { || res.language == Dialect::QmlQtQuick2 || res.language == Dialect::QmlQtQuick2Ui) {
const auto environemntPaths = environmentImportPaths(); const auto environemntPaths = environmentImportPaths();

View File

@@ -78,10 +78,10 @@ public:
// whether trying to run qmldump makes sense // whether trying to run qmldump makes sense
bool tryQmlDump = false; bool tryQmlDump = false;
bool qmlDumpHasRelocatableFlag = true; bool qmlDumpHasRelocatableFlag = true;
QString qmlDumpPath; Utils::FilePath qmlDumpPath;
::Utils::Environment qmlDumpEnvironment; Utils::Environment qmlDumpEnvironment;
QString qtQmlPath; Utils::FilePath qtQmlPath;
QString qtVersionString; QString qtVersionString;
QmlJS::QmlLanguageBundles activeBundle; QmlJS::QmlLanguageBundles activeBundle;
QmlJS::QmlLanguageBundles extendedBundle; QmlJS::QmlLanguageBundles extendedBundle;

View File

@@ -34,6 +34,7 @@
#include <utils/filesystemwatcher.h> #include <utils/filesystemwatcher.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcprocess.h>
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <QDir> #include <QDir>
@@ -41,7 +42,9 @@
#include <QRegularExpression> #include <QRegularExpression>
using namespace LanguageUtils; using namespace LanguageUtils;
using namespace QmlJS; using namespace Utils;
namespace QmlJS {
PluginDumper::PluginDumper(ModelManagerInterface *modelManager) PluginDumper::PluginDumper(ModelManagerInterface *modelManager)
: QObject(modelManager) : QObject(modelManager)
@@ -86,29 +89,30 @@ void PluginDumper::onLoadBuiltinTypes(const QmlJS::ModelManagerInterface::Projec
if (info.qmlDumpPath.isEmpty() || info.qtQmlPath.isEmpty()) if (info.qmlDumpPath.isEmpty() || info.qtQmlPath.isEmpty())
return; 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)) if (m_runningQmldumps.values().contains(importsPath))
return; return;
LibraryInfo builtinInfo; LibraryInfo builtinInfo;
if (!force) { if (!force) {
const Snapshot snapshot = m_modelManager->snapshot(); const Snapshot snapshot = m_modelManager->snapshot();
builtinInfo = snapshot.libraryInfo(info.qtQmlPath); builtinInfo = snapshot.libraryInfo(info.qtQmlPath.toString());
if (builtinInfo.isValid()) if (builtinInfo.isValid())
return; return;
} }
builtinInfo = LibraryInfo(LibraryInfo::Found); builtinInfo = LibraryInfo(LibraryInfo::Found);
m_modelManager->updateLibraryInfo(info.qtQmlPath, builtinInfo); m_modelManager->updateLibraryInfo(info.qtQmlPath.toString(), builtinInfo);
// prefer QTDIR/qml/builtins.qmltypes if available // 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)) { if (QFile::exists(builtinQmltypesPath)) {
loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath, builtinInfo); loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath.toString(), builtinInfo);
return; return;
} }
runQmlDump(info, QStringList(QLatin1String("--builtins")), info.qtQmlPath); 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) 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)); "%2").arg(libraryPath, warning));
} }
static QString qmlPluginDumpErrorMessage(QProcess *process) static QString qmlPluginDumpErrorMessage(QtcProcess *process)
{ {
QString errorMessage; QString errorMessage;
const QString binary = QDir::toNativeSeparators(process->program()); const QString binary = process->commandLine().executable().toUserOutput();
switch (process->error()) { switch (process->error()) {
case QProcess::FailedToStart: case QProcess::FailedToStart:
errorMessage = PluginDumper::tr("\"%1\" failed to start: %2").arg(binary, process->errorString()); 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()); errorMessage = PluginDumper::tr("\"%1\" returned exit code %2.").arg(binary).arg(process->exitCode());
break; 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) { if (process->error() != QProcess::FailedToStart) {
const QString stdErr = QString::fromLocal8Bit(process->readAllStandardError()); const QString stdErr = QString::fromLocal8Bit(process->readAllStandardError());
if (!stdErr.isEmpty()) { if (!stdErr.isEmpty()) {
@@ -261,11 +265,8 @@ static QString qmlPluginDumpErrorMessage(QProcess *process)
return errorMessage; return errorMessage;
} }
void PluginDumper::qmlPluginTypeDumpDone(int exitCode) void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process)
{ {
QProcess *process = qobject_cast<QProcess *>(sender());
if (!process)
return;
process->deleteLater(); process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process); const QString libraryPath = m_runningQmldumps.take(process);
@@ -275,7 +276,7 @@ void PluginDumper::qmlPluginTypeDumpDone(int exitCode)
LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath);
bool privatePlugin = libraryPath.endsWith(QLatin1String("private")); bool privatePlugin = libraryPath.endsWith(QLatin1String("private"));
if (exitCode != 0) { if (process->exitCode() != 0) {
const QString errorMessages = qmlPluginDumpErrorMessage(process); const QString errorMessages = qmlPluginDumpErrorMessage(process);
if (!privatePlugin) if (!privatePlugin)
ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); 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<QProcess *>(sender());
if (!process)
return;
process->deleteLater(); process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process); 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, void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info,
const QStringList &arguments, const QString &importPath) const QStringList &arguments, const FilePath &importPath)
{ {
QDir wd = QDir(importPath); auto process = new QtcProcess(this);
wd.cdUp(); process->setEnvironment(info.qmlDumpEnvironment);
QProcess *process = new QProcess(this); process->setWorkingDirectory(importPath);
process->setEnvironment(info.qmlDumpEnvironment.toStringList()); process->setCommand({info.qmlDumpPath, arguments});
QString workingDir = wd.canonicalPath(); connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); });
process->setWorkingDirectory(workingDir); connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); });
connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), process->start();
this, &PluginDumper::qmlPluginTypeDumpDone); m_runningQmldumps.insert(process, importPath.toString());
connect(process, &QProcess::errorOccurred, this, &PluginDumper::qmlPluginTypeDumpError);
process->start(info.qmlDumpPath, arguments);
m_runningQmldumps.insert(process, importPath);
} }
void PluginDumper::dump(const Plugin &plugin) void PluginDumper::dump(const Plugin &plugin)
@@ -691,7 +686,7 @@ void PluginDumper::dump(const Plugin &plugin)
args << plugin.importUri; args << plugin.importUri;
args << plugin.importVersion; args << plugin.importVersion;
args << (plugin.importPath.isEmpty() ? QLatin1String(".") : plugin.importPath); 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); return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, prefix);
} }
} // QmlJS

View File

@@ -27,9 +27,10 @@
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/qtcprocess.h>
#include <QObject> #include <QObject>
#include <QHash> #include <QHash>
#include <QProcess>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QDir; class QDir;
@@ -57,8 +58,8 @@ private:
Q_INVOKABLE void onLoadPluginTypes(const QString &libraryPath, const QString &importPath, Q_INVOKABLE void onLoadPluginTypes(const QString &libraryPath, const QString &importPath,
const QString &importUri, const QString &importVersion); const QString &importUri, const QString &importVersion);
Q_INVOKABLE void dumpAllPlugins(); Q_INVOKABLE void dumpAllPlugins();
void qmlPluginTypeDumpDone(int exitCode); void qmlPluginTypeDumpDone(Utils::QtcProcess *process);
void qmlPluginTypeDumpError(QProcess::ProcessError error); void qmlPluginTypeDumpError(Utils::QtcProcess *process);
void pluginChanged(const QString &pluginLibrary); void pluginChanged(const QString &pluginLibrary);
private: private:
@@ -87,7 +88,8 @@ private:
QList<LanguageUtils::FakeMetaObject::ConstPtr> objects; QList<LanguageUtils::FakeMetaObject::ConstPtr> 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); void dump(const Plugin &plugin);
QFuture<QmlTypeDescription> loadQmlTypeDescription(const QStringList &path) const; QFuture<QmlTypeDescription> loadQmlTypeDescription(const QStringList &path) const;
QString buildQmltypesPath(const QString &name) const; QString buildQmltypesPath(const QString &name) const;
@@ -116,7 +118,7 @@ private:
ModelManagerInterface *m_modelManager; ModelManagerInterface *m_modelManager;
Utils::FileSystemWatcher *m_pluginWatcher; Utils::FileSystemWatcher *m_pluginWatcher;
QHash<QProcess *, QString> m_runningQmldumps; QHash<Utils::QtcProcess *, QString> m_runningQmldumps;
QList<Plugin> m_plugins; QList<Plugin> m_plugins;
QHash<QString, int> m_libraryToPluginIndex; QHash<QString, int> m_libraryToPluginIndex;
QHash<QString, QmlJS::ModelManagerInterface::ProjectInfo> m_qtToInfo; QHash<QString, QmlJS::ModelManagerInterface::ProjectInfo> m_qtToInfo;

View File

@@ -475,6 +475,12 @@ static ProcessInterface *newProcessInstance(QObject *parent, QtcProcess::Process
class QtcProcessPrivate : public QObject class QtcProcessPrivate : public QObject
{ {
public: public:
enum StartFailure {
NoFailure,
WrongFileNameFailure,
OtherFailure
};
explicit QtcProcessPrivate(QtcProcess *parent, explicit QtcProcessPrivate(QtcProcess *parent,
QtcProcess::ProcessImpl processImpl, QtcProcess::ProcessImpl processImpl,
ProcessMode processMode) ProcessMode processMode)
@@ -488,13 +494,11 @@ public:
connect(m_process, &ProcessInterface::finished, connect(m_process, &ProcessInterface::finished,
this, &QtcProcessPrivate::slotFinished); this, &QtcProcessPrivate::slotFinished);
connect(m_process, &ProcessInterface::errorOccurred, connect(m_process, &ProcessInterface::errorOccurred,
this, &QtcProcessPrivate::slotError); this, [this](QProcess::ProcessError error) { handleError(error, OtherFailure); });
connect(m_process, &ProcessInterface::readyReadStandardOutput, connect(m_process, &ProcessInterface::readyReadStandardOutput,
this, &QtcProcessPrivate::handleReadyReadStandardOutput); this, &QtcProcessPrivate::handleReadyReadStandardOutput);
connect(m_process, &ProcessInterface::readyReadStandardError, connect(m_process, &ProcessInterface::readyReadStandardError,
this, &QtcProcessPrivate::handleReadyReadStandardError); this, &QtcProcessPrivate::handleReadyReadStandardError);
connect(&m_timer, &QTimer::timeout, this, &QtcProcessPrivate::slotTimeout);
m_timer.setInterval(1000);
} }
void handleReadyReadStandardOutput() void handleReadyReadStandardOutput()
@@ -530,7 +534,7 @@ public:
} else { } else {
m_process->setErrorString(QLatin1String( m_process->setErrorString(QLatin1String(
"The program \"%1\" does not exist or is not executable.").arg(program)); "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 slotTimeout();
void slotFinished(int exitCode, QProcess::ExitStatus e); void slotFinished(int exitCode, QProcess::ExitStatus e);
void slotError(QProcess::ProcessError); void handleError(QProcess::ProcessError error, StartFailure startFailure);
void clearForRun(); void clearForRun();
QtcProcess::Result interpretExitCode(int exitCode); QtcProcess::Result interpretExitCode(int exitCode);
QTextCodec *m_codec = QTextCodec::codecForLocale(); QTextCodec *m_codec = QTextCodec::codecForLocale();
QTimer m_timer; QEventLoop *m_eventLoop = nullptr;
QEventLoop m_eventLoop;
QtcProcess::Result m_result = QtcProcess::StartFailed; QtcProcess::Result m_result = QtcProcess::StartFailed;
QProcess::ExitStatus m_exitStatus = QProcess::NormalExit; QProcess::ExitStatus m_exitStatus = QProcess::NormalExit;
ChannelBuffer m_stdOut; ChannelBuffer m_stdOut;
@@ -562,7 +565,7 @@ public:
int m_hangTimerCount = 0; int m_hangTimerCount = 0;
int m_maxHangTimerCount = defaultMaxHangTimerCount; int m_maxHangTimerCount = defaultMaxHangTimerCount;
bool m_startFailure = false; StartFailure m_startFailure = NoFailure;
bool m_timeOutMessageBoxEnabled = false; bool m_timeOutMessageBoxEnabled = false;
bool m_waitingForUser = false; bool m_waitingForUser = false;
bool m_processUserEvents = false; bool m_processUserEvents = false;
@@ -576,7 +579,7 @@ void QtcProcessPrivate::clearForRun()
m_stdErr.clearForRun(); m_stdErr.clearForRun();
m_stdErr.codec = m_codec; m_stdErr.codec = m_codec;
m_result = QtcProcess::StartFailed; m_result = QtcProcess::StartFailed;
m_startFailure = false; m_startFailure = NoFailure;
} }
QtcProcess::Result QtcProcessPrivate::interpretExitCode(int exitCode) QtcProcess::Result QtcProcessPrivate::interpretExitCode(int exitCode)
@@ -963,7 +966,7 @@ void QtcProcess::setResult(Result result)
int QtcProcess::exitCode() const 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 255; // This code is being returned by QProcess when FailedToStart error occurred
return d->m_process->exitCode(); return d->m_process->exitCode();
} }
@@ -1065,7 +1068,7 @@ void QtcProcess::setProcessChannelMode(QProcess::ProcessChannelMode mode)
QProcess::ProcessError QtcProcess::error() const QProcess::ProcessError QtcProcess::error() const
{ {
if (d->m_startFailure) if (d->m_startFailure == QtcProcessPrivate::WrongFileNameFailure)
return QProcess::FailedToStart; return QProcess::FailedToStart;
return d->m_process->error(); return d->m_process->error();
} }
@@ -1407,17 +1410,24 @@ void QtcProcess::runBlocking()
// On Windows, start failure is triggered immediately if the // On Windows, start failure is triggered immediately if the
// executable cannot be found in the path. Do not start the // executable cannot be found in the path. Do not start the
// event loop in that case. // event loop in that case.
if (!d->m_startFailure) { if (d->m_startFailure == QtcProcessPrivate::NoFailure) {
d->m_timer.start(); QTimer timer(this);
connect(&timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout);
timer.setInterval(1000);
timer.start();
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
if (isGuiThread()) if (isGuiThread())
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
#endif #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_stdOut.append(d->m_process->readAllStandardOutput());
d->m_stdErr.append(d->m_process->readAllStandardError()); d->m_stdErr.append(d->m_process->readAllStandardError());
d->m_timer.stop(); timer.stop();
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
if (isGuiThread()) if (isGuiThread())
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
@@ -1510,7 +1520,8 @@ void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus status)
m_result = QtcProcess::TerminatedAbnormally; m_result = QtcProcess::TerminatedAbnormally;
break; break;
} }
m_eventLoop.quit(); if (m_eventLoop)
m_eventLoop->quit();
m_stdOut.handleRest(); m_stdOut.handleRest();
m_stdErr.handleRest(); m_stdErr.handleRest();
@@ -1518,7 +1529,7 @@ void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus status)
emit q->finished(); emit q->finished();
} }
void QtcProcessPrivate::slotError(QProcess::ProcessError error) void QtcProcessPrivate::handleError(QProcess::ProcessError error, StartFailure startFailure)
{ {
m_hangTimerCount = 0; m_hangTimerCount = 0;
if (debug) if (debug)
@@ -1526,8 +1537,9 @@ void QtcProcessPrivate::slotError(QProcess::ProcessError error)
// Was hang detected before and killed? // Was hang detected before and killed?
if (m_result != QtcProcess::Hang) if (m_result != QtcProcess::Hang)
m_result = QtcProcess::StartFailed; m_result = QtcProcess::StartFailed;
m_startFailure = true; m_startFailure = startFailure;
m_eventLoop.quit(); if (m_eventLoop)
m_eventLoop->quit();
emit q->errorOccurred(error); emit q->errorOccurred(error);
} }

View File

@@ -67,6 +67,28 @@ void setThemeApplicationPalette()
QApplication::setPalette(m_creatorTheme->palette()); 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) void setCreatorTheme(Theme *theme)
{ {
if (m_creatorTheme == theme) if (m_creatorTheme == theme)
@@ -74,13 +96,7 @@ void setCreatorTheme(Theme *theme)
delete m_creatorTheme; delete m_creatorTheme;
m_creatorTheme = theme; m_creatorTheme = theme;
#ifdef Q_OS_MACOS maybeForceMacOSLight(theme);
// 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
setThemeApplicationPalette(); setThemeApplicationPalette();
} }
@@ -251,6 +267,8 @@ bool Theme::systemUsesDarkMode()
bool ok; bool ok;
const auto setting = QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok); const auto setting = QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok);
return ok && setting == 0; return ok && setting == 0;
} else if (HostOsInfo::isMacHost()) {
return macOSSystemIsDark();
} }
return false; return false;
} }
@@ -270,6 +288,13 @@ static QPalette copyPalette(const QPalette &p)
return res; return res;
} }
void Theme::setInitialPalette(Theme *initTheme)
{
macOSSystemIsDark(); // initialize value for system mode
maybeForceMacOSLight(initTheme);
initialPalette();
}
QPalette Theme::initialPalette() QPalette Theme::initialPalette()
{ {
static QPalette palette = copyPalette(QApplication::palette()); static QPalette palette = copyPalette(QApplication::palette());

View File

@@ -485,6 +485,8 @@ public:
static bool systemUsesDarkMode(); static bool systemUsesDarkMode();
static QPalette initialPalette(); static QPalette initialPalette();
static void setInitialPalette(Theme *initTheme);
protected: protected:
Theme(Theme *originTheme, QObject *parent = nullptr); Theme(Theme *originTheme, QObject *parent = nullptr);
ThemePrivate *d; ThemePrivate *d;

View File

@@ -29,6 +29,7 @@ namespace Utils {
namespace Internal { namespace Internal {
void forceMacOSLightAquaApperance(); void forceMacOSLightAquaApperance();
bool currentAppearanceIsDark();
} // Internal } // Internal
} // Utils } // Utils

View File

@@ -49,5 +49,17 @@ void forceMacOSLightAquaApperance()
NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; 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 } // Internal
} // Utils } // Utils

View File

@@ -423,7 +423,7 @@ void AndroidBuildApkWidget::onOpenSslCheckBoxChanged()
Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath(); Utils::FilePath projectPath = m_step->buildConfiguration()->buildSystem()->projectFilePath();
QFile projectFile(projectPath.toString()); QFile projectFile(projectPath.toString());
if (!projectFile.open(QIODevice::ReadWrite | QIODevice::Text)) { 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; return;
} }
@@ -494,27 +494,31 @@ AndroidBuildApkStep::AndroidBuildApkStep(BuildStepList *parent, Utils::Id id)
bool AndroidBuildApkStep::init() bool AndroidBuildApkStep::init()
{ {
if (!AbstractProcessStep::init()) if (!AbstractProcessStep::init()) {
reportWarningOrError(tr("\"%1\" step failed initialization.").arg(displayName()),
Task::Error);
return false; return false;
}
if (m_signPackage) { if (m_signPackage) {
qCDebug(buildapkstepLog) << "Signing enabled"; qCDebug(buildapkstepLog) << "Signing enabled";
// check keystore and certificate passwords // check keystore and certificate passwords
if (!verifyKeystorePassword() || !verifyCertificatePassword()) { if (!verifyKeystorePassword() || !verifyCertificatePassword()) {
qCDebug(buildapkstepLog) << "Init failed. Keystore/Certificate password verification failed."; reportWarningOrError(tr("Keystore/Certificate password verification failed."),
Task::Error);
return false; return false;
} }
if (buildType() != BuildConfiguration::Release) { if (buildType() != BuildConfiguration::Release)
const QString error = tr("Warning: Signing a debug or profile package."); reportWarningOrError(tr("Warning: Signing a debug or profile package."), Task::Warning);
emit addOutput(error, OutputFormat::ErrorMessage);
TaskHub::addTask(BuildSystemTask(Task::Warning, error));
}
} }
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); 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; return false;
}
const QVersionNumber sdkToolsVersion = AndroidConfigurations::currentConfig().sdkToolsVersion(); const QVersionNumber sdkToolsVersion = AndroidConfigurations::currentConfig().sdkToolsVersion();
if (sdkToolsVersion >= QVersionNumber(25, 3, 0) if (sdkToolsVersion >= QVersionNumber(25, 3, 0)
@@ -526,16 +530,14 @@ bool AndroidBuildApkStep::init()
"is %2") "is %2")
.arg(sdkToolsVersion.toString()) .arg(sdkToolsVersion.toString())
.arg("5.9.0/5.6.3"); .arg("5.9.0/5.6.3");
emit addOutput(error, OutputFormat::Stderr); reportWarningOrError(error, Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} }
} else if (version->qtVersion() < QtSupport::QtVersionNumber(5, 4, 0)) { } 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. " 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.") "It is recommended to install the latest Qt version.")
.arg("5.4.0"); .arg("5.4.0");
emit addOutput(error, OutputFormat::Stderr); reportWarningOrError(error, Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; 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." = 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.") "\nThe minimum API level required by the kit is %1.")
.arg(minSDKForKit); .arg(minSDKForKit);
emit addOutput(error, OutputFormat::Stderr); reportWarningOrError(error, Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} }
@@ -568,16 +569,16 @@ bool AndroidBuildApkStep::init()
m_inputFile = AndroidQtVersion::androidDeploymentSettings(target()); m_inputFile = AndroidQtVersion::androidDeploymentSettings(target());
if (m_inputFile.isEmpty()) { if (m_inputFile.isEmpty()) {
qCDebug(buildapkstepLog) << "no input file" << target()->activeBuildKey();
m_skipBuilding = true; m_skipBuilding = true;
reportWarningOrError(tr("No valid input file for \"%1\".").arg(target()->activeBuildKey()),
Task::Warning);
return true; return true;
} }
m_skipBuilding = false; m_skipBuilding = false;
if (m_buildTargetSdk.isEmpty()) { if (m_buildTargetSdk.isEmpty()) {
const QString error = tr("Android build SDK not defined. Check Android settings."); reportWarningOrError(tr("Android build SDK version is not defined. Check Android settings.")
emit addOutput(error, OutputFormat::Stderr); , Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} }
@@ -665,10 +666,8 @@ void AndroidBuildApkStep::processFinished(int exitCode, QProcess::ExitStatus sta
bool AndroidBuildApkStep::verifyKeystorePassword() bool AndroidBuildApkStep::verifyKeystorePassword()
{ {
if (!m_keystorePath.exists()) { if (!m_keystorePath.exists()) {
const QString error = tr("Cannot sign the package. Invalid keystore path (%1).") reportWarningOrError(tr("Cannot sign the package. Invalid keystore path (%1).")
.arg(m_keystorePath.toString()); .arg(m_keystorePath.toString()), Task::Error);
emit addOutput(error, OutputFormat::ErrorMessage);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
@@ -687,10 +686,8 @@ bool AndroidBuildApkStep::verifyCertificatePassword()
{ {
if (!AndroidManager::checkCertificateExists(m_keystorePath.toString(), m_keystorePasswd, if (!AndroidManager::checkCertificateExists(m_keystorePath.toString(), m_keystorePasswd,
m_certificateAlias)) { m_certificateAlias)) {
const QString error = tr("Cannot sign the package. Certificate alias %1 does not exist.") reportWarningOrError(tr("Cannot sign the package. Certificate alias %1 does not exist.")
.arg(m_certificateAlias); .arg(m_certificateAlias), Task::Error);
emit addOutput(error, OutputFormat::ErrorMessage);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} }
@@ -731,9 +728,8 @@ static bool copyFileIfNewer(const FilePath &sourceFilePath,
void AndroidBuildApkStep::doRun() void AndroidBuildApkStep::doRun()
{ {
if (m_skipBuilding) { if (m_skipBuilding) {
const QString error = tr("Android deploy settings file not found, not building an APK."); reportWarningOrError(tr("Android deploy settings file not found, not building an APK."),
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
emit finished(true); emit finished(true);
return; return;
} }
@@ -743,8 +739,11 @@ void AndroidBuildApkStep::doRun()
const QString buildKey = target()->activeBuildKey(); const QString buildKey = target()->activeBuildKey();
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); 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; return false;
}
const FilePath buildDir = buildDirectory(); const FilePath buildDir = buildDirectory();
const FilePath androidBuildDir = AndroidManager::androidBuildDirectory(target()); const FilePath androidBuildDir = AndroidManager::androidBuildDirectory(target());
@@ -752,10 +751,9 @@ void AndroidBuildApkStep::doRun()
FilePath androidLibsDir = androidBuildDir / "libs" / abi; FilePath androidLibsDir = androidBuildDir / "libs" / abi;
if (!androidLibsDir.exists()) { if (!androidLibsDir.exists()) {
if (!androidLibsDir.ensureWritableDir()) { if (!androidLibsDir.ensureWritableDir()) {
const QString error = tr("The Android build folder %1 wasn't found and " reportWarningOrError(tr("The Android build folder %1 was not found and could "
"couldn't be created.").arg(androidLibsDir.toUserOutput()); "not be created.").arg(androidLibsDir.toUserOutput()),
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} else if (version->qtVersion() >= QtSupport::QtVersionNumber{6, 0, 0} } else if (version->qtVersion() >= QtSupport::QtVersionNumber{6, 0, 0}
&& version->qtVersion() <= QtSupport::QtVersionNumber{6, 1, 1}) { && version->qtVersion() <= QtSupport::QtVersionNumber{6, 1, 1}) {
@@ -769,11 +767,10 @@ void AndroidBuildApkStep::doRun()
continue; continue;
if (!from.copyFile(to)) { if (!from.copyFile(to)) {
const QString error = tr("Couldn't copy the target's lib file %1 to the " reportWarningOrError(tr("Cannot copy the target's lib file %1 to the "
"Android build folder %2.") "Android build folder %2.")
.arg(fileName, androidLibsDir.toUserOutput()); .arg(fileName, androidLibsDir.toUserOutput()),
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
return false; return false;
} }
} }
@@ -799,9 +796,14 @@ void AndroidBuildApkStep::doRun()
applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.toString(); applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.toString();
FilePath androidLibsDir = androidBuildDir / "libs" / androidAbis.first(); FilePath androidLibsDir = androidBuildDir / "libs" / androidAbis.first();
for (const FilePath &target : targets) { 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; return false;
} }
}
deploySettings["target-architecture"] = androidAbis.first(); deploySettings["target-architecture"] = androidAbis.first();
} else { } else {
applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.fileName(); applicationBinary = buildSystem()->buildTarget(buildKey).targetFilePath.fileName();
@@ -818,8 +820,14 @@ void AndroidBuildApkStep::doRun()
FilePath androidLibsDir = androidBuildDir / "libs" / abi; FilePath androidLibsDir = androidBuildDir / "libs" / abi;
for (const FilePath &target : targets) { for (const FilePath &target : targets) {
if (target.endsWith(targetSuffix)) { 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; return false;
}
architectures[abi] = AndroidManager::archTriplet(abi); architectures[abi] = AndroidManager::archTriplet(abi);
} }
} }
@@ -846,16 +854,18 @@ void AndroidBuildApkStep::doRun()
deploySettings["qml-root-path"] = qmlRootPath; deploySettings["qml-root-path"] = qmlRootPath;
QFile f{m_inputFile.toString()}; 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; return false;
}
f.write(QJsonDocument{deploySettings}.toJson()); f.write(QJsonDocument{deploySettings}.toJson());
return true; return true;
}; };
if (!setup()) { if (!setup()) {
const QString error = tr("Cannot set up Android, not building an APK."); reportWarningOrError(tr("Cannot set up \"%1\", not building an APK.").arg(displayName()),
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); Task::Error);
TaskHub::addTask(BuildSystemTask(Task::Error, error));
emit finished(false); emit finished(false);
return; return;
} }
@@ -863,6 +873,13 @@ void AndroidBuildApkStep::doRun()
AbstractProcessStep::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() void AndroidBuildApkStep::processStarted()
{ {
emit addOutput(tr("Starting: \"%1\" %2") emit addOutput(tr("Starting: \"%1\" %2")

View File

@@ -92,6 +92,8 @@ private:
void doRun() override; void doRun() override;
void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type);
bool m_buildAAB = false; bool m_buildAAB = false;
bool m_signPackage = false; bool m_signPackage = false;
bool m_verbose = false; bool m_verbose = false;

View File

@@ -1408,7 +1408,7 @@ Environment AndroidConfigurations::toolsEnvironment(const AndroidConfig &config)
return env; return env;
} }
const AndroidConfig &AndroidConfigurations::currentConfig() AndroidConfig &AndroidConfigurations::currentConfig()
{ {
return m_instance->m_config; // ensure that m_instance is initialized return m_instance->m_config; // ensure that m_instance is initialized
} }

View File

@@ -211,7 +211,7 @@ class ANDROID_EXPORT AndroidConfigurations : public QObject
Q_OBJECT Q_OBJECT
public: public:
static const AndroidConfig &currentConfig(); static AndroidConfig &currentConfig();
static Internal::AndroidSdkManager *sdkManager(); static Internal::AndroidSdkManager *sdkManager();
static void setConfig(const AndroidConfig &config); static void setConfig(const AndroidConfig &config);
static AndroidConfigurations *instance(); static AndroidConfigurations *instance();

View File

@@ -112,9 +112,8 @@ bool AndroidDeployQtStep::init()
{ {
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit()); QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit());
if (!version) { if (!version) {
qCDebug(deployStepLog, reportWarningOrError(tr("The Qt version for kit %1 is invalid.").arg(kit()->displayName()),
"The Qt version for kit %s is not valid.", Task::Error);
qPrintable(kit()->displayName()));
return false; return false;
} }
@@ -122,18 +121,21 @@ bool AndroidDeployQtStep::init()
m_androidABIs = AndroidManager::applicationAbis(target()); m_androidABIs = AndroidManager::applicationAbis(target());
if (m_androidABIs.isEmpty()) { if (m_androidABIs.isEmpty()) {
const QString error = tr("No Android arch set by the .pro file."); reportWarningOrError(tr("No Android architecture (ABI) is set by the project."),
emit addOutput(error, OutputFormat::Stderr); Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; 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(); 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(); 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<AndroidBuildApkStep>(); auto androidBuildApkStep = bc->buildSteps()->firstOfType<AndroidBuildApkStep>();
const int minTargetApi = AndroidManager::minimumSDK(target()); 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. // Try to re-use user-provided information from an earlier step of the same type.
BuildStepList *bsl = stepList(); 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<AndroidDeployQtStep>(); auto androidDeployQtStep = bsl->firstOfType<AndroidDeployQtStep>();
QTC_ASSERT(androidDeployQtStep, return false); QTC_ASSERT(androidDeployQtStep,
reportWarningOrError(tr("The kit's deploy configuration is invalid."), Task::Error);
return false);
AndroidDeviceInfo info; AndroidDeviceInfo info;
if (androidDeployQtStep != this) if (androidDeployQtStep != this)
info = androidDeployQtStep->m_deviceInfo; info = androidDeployQtStep->m_deviceInfo;
@@ -159,44 +164,44 @@ bool AndroidDeployQtStep::init()
if (selectedAbis.isEmpty()) if (selectedAbis.isEmpty())
selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString()); selectedAbis.append(bs->extraData(buildKey, Constants::AndroidAbi).toString());
// TODO: use AndroidDevice directly instead of AndroidDeviceInfo.
if (!info.isValid()) { if (!info.isValid()) {
const IDevice *dev = DeviceKitAspect::device(kit()).data(); 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); info = AndroidDevice::androidDeviceInfoFromIDevice(dev);
m_deviceInfo = info; // Keep around for later steps m_deviceInfo = info; // Keep around for later steps
if (!info.isValid()) { if (!info.isValid()) {
const QString error = tr("The deployment device \"%1\" is invalid.") reportWarningOrError(tr("The deployment device \"%1\" is invalid.")
.arg(dev->displayName()); .arg(dev->displayName()), Task::Error);
emit addOutput(error, OutputFormat::Stderr);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(dev); const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(dev);
if (androidDev && !androidDev->canSupportAbis(selectedAbis)) { 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" "architectures used by the kit.\n"
"The kit supports \"%2\", but the device uses \"%3\".") "The kit supports \"%2\", but the device uses \"%3\".")
.arg(dev->displayName()).arg(selectedAbis.join(", ")) .arg(dev->displayName()).arg(selectedAbis.join(", "))
.arg(androidDev->supportedAbis().join(", ")); .arg(androidDev->supportedAbis().join(", "));
emit addOutput(error, OutputFormat::Stderr); reportWarningOrError(error, Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
if (androidDev && !androidDev->canHandleDeployments()) { if (androidDev && !androidDev->canHandleDeployments()) {
const QString error = tr("The deployment device \"%1\" is disconnected.") reportWarningOrError(tr("The deployment device \"%1\" is disconnected.")
.arg(dev->displayName()); .arg(dev->displayName()), Task::Error);
emit addOutput(error, OutputFormat::Stderr);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
} }
const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit()); const QtSupport::BaseQtVersion * const qt = QtSupport::QtKitAspect::qtVersion(kit());
if (qt && qt->supportsMultipleQtAbis() && !selectedAbis.contains(info.cpuAbi.first())) { if (qt && qt->supportsMultipleQtAbis() && !selectedAbis.contains(info.cpuAbi.first())) {
TaskHub::addTask(DeploymentTask( TaskHub::addTask(DeploymentTask(Task::Warning,
Task::Warning,
tr("Android: The main ABI of the deployment device (%1) is not selected. The app " 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 > " "execution or debugging might not work properly. Add it from Projects > Build > "
"Build Steps > qmake > ABIs.") "Build Steps > qmake > ABIs.")
@@ -213,7 +218,7 @@ bool AndroidDeployQtStep::init()
AndroidManager::setDeviceApiLevel(target(), info.sdk); AndroidManager::setDeviceApiLevel(target(), info.sdk);
AndroidManager::setDeviceAbis(target(), info.cpuAbi); 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(); m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value();
if (m_uninstallPreviousPackageRun) if (m_uninstallPreviousPackageRun)
@@ -223,8 +228,10 @@ bool AndroidDeployQtStep::init()
if (m_useAndroiddeployqt) { if (m_useAndroiddeployqt) {
const QString buildKey = target()->activeBuildKey(); const QString buildKey = target()->activeBuildKey();
const ProjectNode *node = target()->project()->findNodeForBuildKey(buildKey); 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; return false;
}
m_apkPath = Utils::FilePath::fromString(node->data(Constants::AndroidApk).toString()); m_apkPath = Utils::FilePath::fromString(node->data(Constants::AndroidApk).toString());
if (!m_apkPath.isEmpty()) { if (!m_apkPath.isEmpty()) {
m_manifestName = Utils::FilePath::fromString(node->data(Constants::AndroidManifest).toString()); m_manifestName = Utils::FilePath::fromString(node->data(Constants::AndroidManifest).toString());
@@ -233,16 +240,13 @@ bool AndroidDeployQtStep::init()
} else { } else {
QString jsonFile = AndroidQtVersion::androidDeploymentSettings(target()).toString(); QString jsonFile = AndroidQtVersion::androidDeploymentSettings(target()).toString();
if (jsonFile.isEmpty()) { if (jsonFile.isEmpty()) {
const QString error = tr("Cannot find the androiddeploy Json file."); reportWarningOrError(tr("Cannot find the androiddeployqt input JSON file."),
emit addOutput(error, OutputFormat::Stderr); Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
m_command = version->hostBinPath(); m_command = version->hostBinPath();
if (m_command.isEmpty()) { if (m_command.isEmpty()) {
const QString error = tr("Cannot find the androiddeployqt tool."); reportWarningOrError(tr("Cannot find the androiddeployqt tool."), Task::Error);
emit addOutput(error, OutputFormat::Stderr);
TaskHub::addTask(DeploymentTask(Task::Error, error));
return false; return false;
} }
m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix(); m_command = m_command.pathAppended("androiddeployqt").withExecutableSuffix();
@@ -302,13 +306,14 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy()
if (m_uninstallPreviousPackageRun) { if (m_uninstallPreviousPackageRun) {
packageName = AndroidManager::packageName(m_manifestName); packageName = AndroidManager::packageName(m_manifestName);
if (packageName.isEmpty()) { if (packageName.isEmpty()) {
const QString error = tr("Cannot find the package name."); reportWarningOrError(tr("Cannot find the package name from the Android Manifest "
emit addOutput(error, OutputFormat::Stderr); "file \"%1\".").arg(m_manifestName.toUserOutput()),
TaskHub::addTask(DeploymentTask(Task::Error, error)); Task::Error);
return Failure; return Failure;
} }
qCDebug(deployStepLog) << "Uninstalling previous package"; const QString msg = tr("Uninstalling the previous package \"%1\".").arg(packageName);
emit addOutput(tr("Uninstall previous package %1.").arg(packageName), OutputFormat::NormalMessage); qCDebug(deployStepLog) << msg;
emit addOutput(msg, OutputFormat::NormalMessage);
runCommand({m_adbPath, runCommand({m_adbPath,
AndroidDeviceInfo::adbSelector(m_serialNumber) AndroidDeviceInfo::adbSelector(m_serialNumber)
<< "uninstall" << packageName}); << "uninstall" << packageName});
@@ -337,8 +342,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy()
m_process->start(); m_process->start();
emit addOutput(tr("Starting: \"%1\"").arg(cmd.toUserOutput()), emit addOutput(tr("Starting: \"%1\"").arg(cmd.toUserOutput()), OutputFormat::NormalMessage);
BuildStep::OutputFormat::NormalMessage);
while (!m_process->waitForFinished(200)) { while (!m_process->waitForFinished(200)) {
if (m_process->state() == QProcess::NotRunning) if (m_process->state() == QProcess::NotRunning)
@@ -369,24 +373,27 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy()
if (exitStatus == QProcess::NormalExit && exitCode == 0) { if (exitStatus == QProcess::NormalExit && exitCode == 0) {
emit addOutput(tr("The process \"%1\" exited normally.").arg(m_command.toUserOutput()), emit addOutput(tr("The process \"%1\" exited normally.").arg(m_command.toUserOutput()),
BuildStep::OutputFormat::NormalMessage); OutputFormat::NormalMessage);
} else if (exitStatus == QProcess::NormalExit) { } else if (exitStatus == QProcess::NormalExit) {
const QString error = tr("The process \"%1\" exited with code %2.") const QString error = tr("The process \"%1\" exited with code %2.")
.arg(m_command.toUserOutput(), QString::number(exitCode)); .arg(m_command.toUserOutput(), QString::number(exitCode));
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); reportWarningOrError(error, Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
} else { } else {
const QString error = tr("The process \"%1\" crashed.").arg(m_command.toUserOutput()); const QString error = tr("The process \"%1\" crashed.").arg(m_command.toUserOutput());
emit addOutput(error, BuildStep::OutputFormat::ErrorMessage); reportWarningOrError(error, Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
} }
if (deployError != NoError) { if (deployError != NoError) {
if (m_uninstallPreviousPackageRun) if (m_uninstallPreviousPackageRun) {
deployError = Failure; // Even re-install failed. Set to Failure. 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) { } else if (exitCode != 0 || exitStatus != QProcess::NormalExit) {
// Set the deployError to Failure when no deployError code was detected // Set the deployError to Failure when no deployError code was detected
// but the adb tool failed otherwise relay the detected deployError. // but the adb tool failed otherwise relay the detected deployError.
reportWarningOrError(tr("Installing the app failed with an unknown error."), Task::Error);
deployError = Failure; deployError = Failure;
} }
@@ -421,7 +428,8 @@ void AndroidDeployQtStep::slotAskForUninstall(DeployErrorCode errorCode)
mask <<= 1; 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, int button = QMessageBox::critical(nullptr, tr("Install failed"), uninstallMsg,
QMessageBox::Yes, QMessageBox::No); QMessageBox::Yes, QMessageBox::No);
m_askForUninstall = button == QMessageBox::Yes; m_askForUninstall = button == QMessageBox::Yes;
@@ -432,10 +440,13 @@ bool AndroidDeployQtStep::runImpl()
if (!m_avdName.isEmpty()) { if (!m_avdName.isEmpty()) {
QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, cancelChecker()); QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, cancelChecker());
qCDebug(deployStepLog) << "Deploying to AVD:" << m_avdName << serialNumber; 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; return false;
}
m_serialNumber = serialNumber; m_serialNumber = serialNumber;
qCDebug(deployStepLog) << "Target device serial number change:" << serialNumber; qCDebug(deployStepLog) << "Deployment device serial number changed:" << serialNumber;
AndroidManager::setDeviceSerialNumber(target(), serialNumber); AndroidManager::setDeviceSerialNumber(target(), serialNumber);
} }
@@ -451,7 +462,8 @@ bool AndroidDeployQtStep::runImpl()
if (!m_filesToPull.isEmpty()) if (!m_filesToPull.isEmpty())
emit addOutput(tr("Pulling files necessary for debugging."), OutputFormat::NormalMessage); 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) { for (auto itr = m_filesToPull.constBegin(); itr != m_filesToPull.constEnd(); ++itr) {
QFile::remove(itr.value()); QFile::remove(itr.value());
} }
@@ -464,8 +476,7 @@ bool AndroidDeployQtStep::runImpl()
const QString error = tr("Package deploy: Failed to pull \"%1\" to \"%2\".") const QString error = tr("Package deploy: Failed to pull \"%1\" to \"%2\".")
.arg(itr.key()) .arg(itr.key())
.arg(itr.value()); .arg(itr.value());
emit addOutput(error, OutputFormat::ErrorMessage); reportWarningOrError(error, Task::Error);
TaskHub::addTask(DeploymentTask(Task::Error, error));
} }
} }
@@ -518,11 +529,8 @@ void AndroidDeployQtStep::runCommand(const CommandLine &command)
buildProc.setCommand(command); buildProc.setCommand(command);
buildProc.setProcessUserEventWhileRunning(); buildProc.setProcessUserEventWhileRunning();
buildProc.runBlocking(); buildProc.runBlocking();
if (buildProc.result() != QtcProcess::FinishedWithSuccess) { if (buildProc.result() != QtcProcess::FinishedWithSuccess)
const QString error = buildProc.exitMessage(); reportWarningOrError(buildProc.exitMessage(), Task::Error);
emit addOutput(error, OutputFormat::ErrorMessage);
TaskHub::addTask(DeploymentTask(Task::Error, error));
}
} }
QWidget *AndroidDeployQtStep::createConfigWidget() QWidget *AndroidDeployQtStep::createConfigWidget()
@@ -590,6 +598,13 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::parseDeployErrors(
return errorCode; 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::AndroidDeployQtStepFactory() AndroidDeployQtStepFactory::AndroidDeployQtStepFactory()

View File

@@ -83,8 +83,15 @@ private:
void stdError(const QString &line); void stdError(const QString &line);
DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const; DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const;
friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { e1 = static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2); } friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) {
friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { return static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2); } e1 = static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2);
}
friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) {
return static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2);
}
void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type);
Utils::FilePath m_manifestName; Utils::FilePath m_manifestName;
QString m_serialNumber; QString m_serialNumber;

View File

@@ -627,8 +627,8 @@ AndroidDeviceManager *AndroidDeviceManager::instance()
AndroidDeviceManager::AndroidDeviceManager(QObject *parent) AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
: 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]() { connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
m_devicesUpdaterTimer.stop(); m_devicesUpdaterTimer.stop();

View File

@@ -90,7 +90,7 @@ public:
ProjectExplorer::IDevice::Ptr create() const override; ProjectExplorer::IDevice::Ptr create() const override;
private: private:
AndroidConfig m_androidConfig; const AndroidConfig &m_androidConfig;
}; };
class AndroidDeviceManager : public QObject class AndroidDeviceManager : public QObject
@@ -116,8 +116,8 @@ private:
QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher; QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher;
QFutureWatcher<QPair<ProjectExplorer::IDevice::ConstPtr, bool>> m_removeAvdFutureWatcher; QFutureWatcher<QPair<ProjectExplorer::IDevice::ConstPtr, bool>> m_removeAvdFutureWatcher;
QTimer m_devicesUpdaterTimer; QTimer m_devicesUpdaterTimer;
AndroidConfig &m_androidConfig;
AndroidAvdManager m_avdManager; AndroidAvdManager m_avdManager;
AndroidConfig m_androidConfig;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -72,6 +72,8 @@ private:
void setupOutputFormatter(OutputFormatter *formatter) final; void setupOutputFormatter(OutputFormatter *formatter) final;
void doRun() final; void doRun() final;
void reportWarningOrError(const QString &message, ProjectExplorer::Task::TaskType type);
QStringList m_androidDirsToClean; QStringList m_androidDirsToClean;
}; };
@@ -89,11 +91,16 @@ AndroidPackageInstallationStep::AndroidPackageInstallationStep(BuildStepList *bs
bool AndroidPackageInstallationStep::init() bool AndroidPackageInstallationStep::init()
{ {
if (!AbstractProcessStep::init()) if (!AbstractProcessStep::init()) {
reportWarningOrError(tr("\"%1\" step failed initialization.").arg(displayName()),
Task::TaskType::Error);
return false; return false;
}
ToolChain *tc = ToolChainKitAspect::cxxToolChain(kit()); 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(); QString dirPath = nativeAndroidBuildPath();
const QString innerQuoted = ProcessArgs::quoteArg(dirPath); const QString innerQuoted = ProcessArgs::quoteArg(dirPath);
@@ -140,8 +147,9 @@ void AndroidPackageInstallationStep::doRun()
if (!dir.isEmpty() && androidDir.exists()) { if (!dir.isEmpty() && androidDir.exists()) {
emit addOutput(tr("Removing directory %1").arg(dir), OutputFormat::NormalMessage); emit addOutput(tr("Removing directory %1").arg(dir), OutputFormat::NormalMessage);
if (!androidDir.removeRecursively(&error)) { if (!androidDir.removeRecursively(&error)) {
emit addOutput(error, OutputFormat::Stderr); reportWarningOrError(tr("Failed to clean \"%1\" from the previous build, with "
TaskHub::addTask(BuildSystemTask(Task::Error, error)); "error:\n%2").arg(androidDir.toUserOutput()).arg(error),
Task::TaskType::Error);
emit finished(false); emit finished(false);
return; return;
} }
@@ -167,13 +175,21 @@ void AndroidPackageInstallationStep::doRun()
qPrintable(file.fileName())); qPrintable(file.fileName()));
} else { } else {
qCDebug(packageInstallationStepLog, 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())); 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 // AndroidPackageInstallationStepFactory
// //

View File

@@ -78,7 +78,7 @@ private:
Utils::FilePath createQmlrcFile(const Utils::FilePath &workFolder, const QString &basename); Utils::FilePath createQmlrcFile(const Utils::FilePath &workFolder, const QString &basename);
ProjectExplorer::RunControl *m_rc = nullptr; ProjectExplorer::RunControl *m_rc = nullptr;
AndroidConfig m_androidConfig; const AndroidConfig &m_androidConfig;
QString m_serialNumber; QString m_serialNumber;
QStringList m_avdAbis; QStringList m_avdAbis;
int m_viewerPid = -1; int m_viewerPid = -1;

View File

@@ -48,8 +48,8 @@ namespace Internal {
* @brief Download Android SDK tools package from within Qt Creator. * @brief Download Android SDK tools package from within Qt Creator.
*/ */
AndroidSdkDownloader::AndroidSdkDownloader() AndroidSdkDownloader::AndroidSdkDownloader()
: m_androidConfig(AndroidConfigurations::currentConfig())
{ {
m_androidConfig = AndroidConfigurations::currentConfig();
connect(&m_manager, &QNetworkAccessManager::finished, this, &AndroidSdkDownloader::downloadFinished); connect(&m_manager, &QNetworkAccessManager::finished, this, &AndroidSdkDownloader::downloadFinished);
} }

View File

@@ -72,7 +72,7 @@ private:
QNetworkReply *m_reply = nullptr; QNetworkReply *m_reply = nullptr;
Utils::FilePath m_sdkFilename; Utils::FilePath m_sdkFilename;
QProgressDialog *m_progressDialog = nullptr; QProgressDialog *m_progressDialog = nullptr;
AndroidConfig m_androidConfig; const AndroidConfig &m_androidConfig;
}; };
} // Internal } // Internal

View File

@@ -108,7 +108,7 @@ private:
Ui_AndroidSettingsWidget m_ui; Ui_AndroidSettingsWidget m_ui;
AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr; AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr;
AndroidConfig m_androidConfig{AndroidConfigurations::currentConfig()}; AndroidConfig &m_androidConfig{AndroidConfigurations::currentConfig()};
AndroidSdkManager m_sdkManager{m_androidConfig}; AndroidSdkManager m_sdkManager{m_androidConfig};
AndroidSdkDownloader m_sdkDownloader; AndroidSdkDownloader m_sdkDownloader;

View File

@@ -116,7 +116,7 @@ bool AndroidToolChain::isValid() const
void AndroidToolChain::addToEnvironment(Environment &env) 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)); env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHostFromNdk(m_ndkLocation));
const Utils::FilePath javaHome = config.openJDKLocation(); const Utils::FilePath javaHome = config.openJDKLocation();
if (javaHome.exists()) { if (javaHome.exists()) {
@@ -178,7 +178,7 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath)
static QList<FilePath> uniqueNdksForCurrentQtVersions() static QList<FilePath> uniqueNdksForCurrentQtVersions()
{ {
AndroidConfig config = AndroidConfigurations::currentConfig(); const AndroidConfig &config = AndroidConfigurations::currentConfig();
auto androidQtVersions = QtSupport::QtVersionManager::versions( auto androidQtVersions = QtSupport::QtVersionManager::versions(
[](const QtSupport::BaseQtVersion *v) { [](const QtSupport::BaseQtVersion *v) {

View File

@@ -51,9 +51,9 @@ static Q_LOGGING_CATEGORY(avdDialogLog, "qtc.android.avdDialog", QtWarningMsg)
AvdDialog::AvdDialog(const AndroidConfig &config, QWidget *parent) AvdDialog::AvdDialog(const AndroidConfig &config, QWidget *parent)
: QDialog(parent), : QDialog(parent),
m_androidConfig(config),
m_sdkManager(m_androidConfig), m_sdkManager(m_androidConfig),
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")), m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*"))
m_androidConfig(config)
{ {
m_avdDialog.setupUi(this); m_avdDialog.setupUi(this);
m_hideTipTimer.setInterval(2000); m_hideTipTimer.setInterval(2000);

View File

@@ -71,12 +71,12 @@ private:
}; };
Ui::AddNewAVDDialog m_avdDialog; Ui::AddNewAVDDialog m_avdDialog;
AndroidSdkManager m_sdkManager;
CreateAvdInfo m_createdAvdInfo; CreateAvdInfo m_createdAvdInfo;
QTimer m_hideTipTimer; QTimer m_hideTipTimer;
QRegularExpression m_allowedNameChars; QRegularExpression m_allowedNameChars;
QList<DeviceDefinitionStruct> m_deviceDefinitionsList; QList<DeviceDefinitionStruct> m_deviceDefinitionsList;
AndroidConfig m_androidConfig; const AndroidConfig &m_androidConfig;
AndroidSdkManager m_sdkManager;
QMap<AvdDialog::DeviceType, QString> deviceTypeToStringMap; QMap<AvdDialog::DeviceType, QString> deviceTypeToStringMap;
}; };
} }

View File

@@ -1272,9 +1272,11 @@ void ClangdTestHighlighting::test()
}; };
const TextEditor::HighlightingResults results = findResults(); const TextEditor::HighlightingResults results = findResults();
if (client()->versionNumber() < QVersionNumber(14)) {
QEXPECT_FAIL("typedef as underlying type in enum declaration", QEXPECT_FAIL("typedef as underlying type in enum declaration",
"https://github.com/clangd/clangd/issues/878", "https://github.com/clangd/clangd/issues/878",
Abort); Abort);
}
QEXPECT_FAIL("Q_PROPERTY (property name)", "FIXME: How to do this?", 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 (getter)", "FIXME: How to do this?", Abort);
QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort); QEXPECT_FAIL("Q_PROPERTY (notifier)", "FIXME: How to do this?", Abort);

View File

@@ -35,6 +35,7 @@
#include <coreplugin/find/itemviewfind.h> #include <coreplugin/find/itemviewfind.h>
#include <projectexplorer/buildsteplist.h> #include <projectexplorer/buildsteplist.h>
#include <projectexplorer/gnumakeparser.h> #include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/processparameters.h> #include <projectexplorer/processparameters.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/projectexplorer.h> #include <projectexplorer/projectexplorer.h>
@@ -376,13 +377,15 @@ void CMakeBuildStep::setBuildTargets(const QStringList &buildTargets)
CommandLine CMakeBuildStep::cmakeCommand() const 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(), {}); FilePath buildDirectory = ".";
QString buildDirectory = ".";
if (buildConfiguration()) if (buildConfiguration())
buildDirectory = buildConfiguration()->buildDirectory().path(); buildDirectory = buildConfiguration()->buildDirectory();
cmd.addArgs({"--build", buildDirectory});
cmd.addArgs({"--build", buildDirectory.onDevice(cmd.executable()).path()});
cmd.addArg("--target"); cmd.addArg("--target");
cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) { cmd.addArgs(Utils::transform(m_buildTargets, [this](const QString &s) {

View File

@@ -72,7 +72,11 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
CMakeTool *cmake = parameters.cmakeTool(); CMakeTool *cmake = parameters.cmakeTool();
QTC_ASSERT(parameters.isValid() && cmake, return); 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()) { if (!buildDirectory.exists()) {
QString msg = tr("The build directory \"%1\" does not exist") QString msg = tr("The build directory \"%1\" does not exist")
.arg(buildDirectory.toUserOutput()); .arg(buildDirectory.toUserOutput());
@@ -119,12 +123,8 @@ void CMakeProcess::run(const BuildDirParameters &parameters, const QStringList &
connect(process.get(), &QtcProcess::finished, connect(process.get(), &QtcProcess::finished,
this, &CMakeProcess::handleProcessFinished); this, &CMakeProcess::handleProcessFinished);
const FilePath cmakeExecutable = cmake->cmakeExecutable();
const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable);
CommandLine commandLine(cmakeExecutable); CommandLine commandLine(cmakeExecutable);
commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(), commandLine.addArgs({"-S", sourceDirectory.path(), "-B", buildDirectory.path()});
"-B", buildDirectory.mapToDevicePath()});
commandLine.addArgs(arguments); commandLine.addArgs(arguments);
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM); TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);

View File

@@ -140,11 +140,12 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target,
config << "--config" << bc->cmakeBuildType(); config << "--config" << bc->cmakeBuildType();
} }
QString buildDirectory = "."; FilePath buildDirectory = ".";
if (bc) 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)); cmd.environment.set("DESTDIR", QDir::toNativeSeparators(installRoot));
return cmd; return cmd;

View File

@@ -162,10 +162,11 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
return false; return false;
} }
const CoreArguments args = parseArguments(arguments); const CoreArguments args = parseArguments(arguments);
Theme::initialPalette(); // Initialize palette before setting it
Theme *themeFromArg = ThemeEntry::createTheme(args.themeId); Theme *themeFromArg = ThemeEntry::createTheme(args.themeId);
setCreatorTheme(themeFromArg ? themeFromArg Theme *theme = themeFromArg ? themeFromArg
: ThemeEntry::createTheme(ThemeEntry::themeSetting())); : ThemeEntry::createTheme(ThemeEntry::themeSetting());
Theme::setInitialPalette(theme); // Initialize palette before setting it
setCreatorTheme(theme);
InfoBar::initialize(ICore::settings()); InfoBar::initialize(ICore::settings());
new ActionManager(this); new ActionManager(this);
ActionManager::setPresentationModeEnabled(args.presentationMode); ActionManager::setPresentationModeEnabled(args.presentationMode);

View File

@@ -455,8 +455,13 @@ void FolderNavigationWidget::insertRootDirectory(
m_rootSelector->setCurrentIndex(index); m_rootSelector->setCurrentIndex(index);
if (previousIndex < m_rootSelector->count()) if (previousIndex < m_rootSelector->count())
m_rootSelector->removeItem(previousIndex); m_rootSelector->removeItem(previousIndex);
if (Core::EditorManager::currentEditor()) {
if (m_autoSync) // we might find a better root for current selection now if (m_autoSync) // we might find a better root for current selection now
handleCurrentEditorChanged(Core::EditorManager::currentEditor()); 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) void FolderNavigationWidget::removeRootDirectory(const QString &id)

View File

@@ -62,6 +62,10 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/find/searchresultwindow.h> #include <coreplugin/find/searchresultwindow.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h>
#include <texteditor/basefilefind.h> #include <texteditor/basefilefind.h>
#include <texteditor/behaviorsettings.h> #include <texteditor/behaviorsettings.h>
#include <texteditor/codeassist/assistproposalitem.h> #include <texteditor/codeassist/assistproposalitem.h>
@@ -76,8 +80,6 @@
#include <texteditor/textdocumentlayout.h> #include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditorsettings.h> #include <texteditor/texteditorsettings.h>
#include <projectexplorer/projecttree.h>
#include <cplusplus/ASTPath.h> #include <cplusplus/ASTPath.h>
#include <cplusplus/FastPreprocessor.h> #include <cplusplus/FastPreprocessor.h>
#include <cplusplus/MatchingText.h> #include <cplusplus/MatchingText.h>
@@ -101,6 +103,7 @@ enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 };
using namespace Core; using namespace Core;
using namespace CPlusPlus; using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace TextEditor; using namespace TextEditor;
using namespace Utils; using namespace Utils;
@@ -1045,7 +1048,7 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
} }
void CppEditorWidget::findLinkAt(const QTextCursor &cursor, void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
Utils::ProcessLinkCallback &&processLinkCallback, ProcessLinkCallback &&processLinkCallback,
bool resolveTarget, bool resolveTarget,
bool inNextSplit) bool inNextSplit)
{ {
@@ -1054,9 +1057,36 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
const Utils::FilePath &filePath = textDocument()->filePath(); 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( followSymbolInterface().findLink(
CursorInEditor{cursor, filePath, this, textDocument()}, CursorInEditor{cursor, filePath, this, textDocument()},
std::move(processLinkCallback), std::move(callbackWrapper),
resolveTarget, resolveTarget,
d->m_modelManager->snapshot(), d->m_modelManager->snapshot(),
d->m_lastSemanticInfo.doc, d->m_lastSemanticInfo.doc,

View File

@@ -3116,8 +3116,10 @@ public:
defaultImplTargetComboBox->insertItems(0, implTargetStrings); defaultImplTargetComboBox->insertItems(0, implTargetStrings);
connect(defaultImplTargetComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, connect(defaultImplTargetComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
[this](int index) { [this](int index) {
for (QComboBox * const cb : qAsConst(m_implTargetBoxes)) for (int i = 0; i < m_implTargetBoxes.size(); ++i) {
cb->setCurrentIndex(index); if (!m_candidates.at(i)->type()->asFunctionType()->isPureVirtual())
static_cast<QComboBox *>(m_implTargetBoxes.at(i))->setCurrentIndex(index);
}
}); });
const auto defaultImplTargetLayout = new QHBoxLayout; const auto defaultImplTargetLayout = new QHBoxLayout;
defaultImplTargetLayout->addWidget(new QLabel(tr("Default implementation location:"))); defaultImplTargetLayout->addWidget(new QLabel(tr("Default implementation location:")));
@@ -3128,10 +3130,13 @@ public:
oo.showFunctionSignatures = true; oo.showFunctionSignatures = true;
oo.showReturnTypes = true; oo.showReturnTypes = true;
for (int i = 0; i < m_candidates.size(); ++i) { 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; const auto implTargetComboBox = new QComboBox;
m_implTargetBoxes.append(implTargetComboBox); m_implTargetBoxes.append(implTargetComboBox);
implTargetComboBox->insertItems(0, implTargetStrings); 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())), candidatesLayout->addWidget(new QLabel(oo.prettyType(func->type(), func->name())),
i, 0); i, 0);
candidatesLayout->addWidget(implTargetComboBox, i, 1); candidatesLayout->addWidget(implTargetComboBox, i, 1);

View File

@@ -1079,7 +1079,7 @@ void CdbEngine::activateFrame(int index)
if (debug || debugLocals) if (debug || debugLocals)
qDebug("activateFrame idx=%d '%s' %d", index, qDebug("activateFrame idx=%d '%s' %d", index,
qPrintable(frame.file), frame.line); qPrintable(frame.file.toUserOutput()), frame.line);
stackHandler()->setCurrentIndex(index); stackHandler()->setCurrentIndex(index);
gotoLocation(frame); gotoLocation(frame);
if (m_pythonVersion > 0x030000) if (m_pythonVersion > 0x030000)
@@ -2615,7 +2615,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = nullptr)
frame.level = QString::number(i); frame.level = QString::number(i);
const GdbMi fullName = frameMi["fullname"]; const GdbMi fullName = frameMi["fullname"];
if (fullName.isValid()) { 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.line = frameMi["line"].data().toInt();
frame.usable = false; // To be decided after source path mapping. frame.usable = false; // To be decided after source path mapping.
const GdbMi languageMi = frameMi["language"]; const GdbMi languageMi = frameMi["language"];
@@ -2661,12 +2661,12 @@ unsigned CdbEngine::parseStackTrace(const GdbMi &data, bool sourceStepInto)
return ParseStackStepOut; return ParseStackStepOut;
} }
if (hasFile) { 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) { if (!fileName.exists && i == 0 && sourceStepInto) {
showMessage("Step into: Hit frame with no source, step out...", LogMisc); showMessage("Step into: Hit frame with no source, step out...", LogMisc);
return ParseStackStepOut; return ParseStackStepOut;
} }
frames[i].file = fileName.fileName; frames[i].file = FilePath::fromString(fileName.fileName);
frames[i].usable = fileName.exists; frames[i].usable = fileName.exists;
if (current == -1 && frames[i].usable) if (current == -1 && frames[i].usable)
current = i; current = i;

View File

@@ -161,7 +161,7 @@ static bool debuggerActionsEnabledHelper(DebuggerState state)
Location::Location(const StackFrame &frame, bool marker) Location::Location(const StackFrame &frame, bool marker)
{ {
m_fileName = Utils::FilePath::fromString(frame.file); m_fileName = frame.file;
m_lineNumber = frame.line; m_lineNumber = frame.line;
m_needsMarker = marker; m_needsMarker = marker;
m_functionName = frame.function; m_functionName = frame.function;

View File

@@ -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'...) // 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); setUseTerminal(allowTerminal == DoAllowTerminal && m_runParameters.useTerminal);
const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH"); const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH");

View File

@@ -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()) return file1.canonicalPath() == file2.canonicalPath();
== FilePath::fromString(QFileInfo(file2).canonicalFilePath());
} }
bool DebuggerToolTipContext::matchesFrame(const StackFrame &frame) const bool DebuggerToolTipContext::matchesFrame(const StackFrame &frame) const
@@ -945,7 +944,7 @@ void DebuggerToolTipHolder::saveSessionData(QXmlStreamWriter &w) const
w.writeStartElement(toolTipElementC); w.writeStartElement(toolTipElementC);
QXmlStreamAttributes attributes; QXmlStreamAttributes attributes;
// attributes.append(toolTipClassAttributeC, QString::fromLatin1(metaObject()->className())); // attributes.append(toolTipClassAttributeC, QString::fromLatin1(metaObject()->className()));
attributes.append(fileNameAttributeC, context.fileName); attributes.append(fileNameAttributeC, context.fileName.toString());
if (!context.function.isEmpty()) if (!context.function.isEmpty())
attributes.append(functionAttributeC, context.function); attributes.append(functionAttributeC, context.function);
attributes.append(textPositionAttributeC, QString::number(context.position)); attributes.append(textPositionAttributeC, QString::number(context.position));
@@ -1019,15 +1018,15 @@ void DebuggerToolTipManagerPrivate::updateVisibleToolTips()
return; return;
} }
const QString fileName = toolTipEditor->textDocument()->filePath().toString(); const FilePath filePath = toolTipEditor->textDocument()->filePath();
if (fileName.isEmpty()) { if (filePath.isEmpty()) {
hideAllToolTips(); hideAllToolTips();
return; return;
} }
// Reposition and show all tooltips of that file. // Reposition and show all tooltips of that file.
for (DebuggerToolTipHolder *tooltip : qAsConst(m_tooltips)) { for (DebuggerToolTipHolder *tooltip : qAsConst(m_tooltips)) {
if (tooltip->context.fileName == fileName) if (tooltip->context.fileName == filePath)
tooltip->positionShow(toolTipEditor->editorWidget()); tooltip->positionShow(toolTipEditor->editorWidget());
else else
tooltip->widget->hide(); tooltip->widget->hide();
@@ -1085,7 +1084,8 @@ void DebuggerToolTipManagerPrivate::loadSessionData()
if (readStartElement(r, toolTipElementC)) { if (readStartElement(r, toolTipElementC)) {
const QXmlStreamAttributes attributes = r.attributes(); const QXmlStreamAttributes attributes = r.attributes();
DebuggerToolTipContext context; DebuggerToolTipContext context;
context.fileName = attributes.value(fileNameAttributeC).toString(); context.fileName = FilePath::fromString(
attributes.value(fileNameAttributeC).toString());
context.position = attributes.value(textPositionAttributeC).toString().toInt(); context.position = attributes.value(textPositionAttributeC).toString().toInt();
context.line = attributes.value(textLineAttributeC).toString().toInt(); context.line = attributes.value(textLineAttributeC).toString().toInt();
context.column = attributes.value(textColumnAttributeC).toString().toInt(); context.column = attributes.value(textColumnAttributeC).toString().toInt();
@@ -1197,7 +1197,7 @@ void DebuggerToolTipManagerPrivate::slotTooltipOverrideRequested
DebuggerToolTipContext context; DebuggerToolTipContext context;
context.engineType = m_engine->objectName(); context.engineType = m_engine->objectName();
context.fileName = document->filePath().toString(); context.fileName = document->filePath();
context.position = pos; context.position = pos;
editorWidget->convertPosition(pos, &context.line, &context.column); editorWidget->convertPosition(pos, &context.line, &context.column);
QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column, QString raw = cppExpressionAt(editorWidget, context.position, &context.line, &context.column,

View File

@@ -27,6 +27,8 @@
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include <utils/filepath.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDate> #include <QDate>
#include <QPoint> #include <QPoint>
@@ -46,7 +48,7 @@ public:
bool isSame(const DebuggerToolTipContext &other) const; bool isSame(const DebuggerToolTipContext &other) const;
QString toolTip() const; QString toolTip() const;
QString fileName; Utils::FilePath fileName;
int position; int position;
int line; int line;
int column; int column;

View File

@@ -346,11 +346,11 @@ void PdbEngine::refreshState(const GdbMi &reportedState)
void PdbEngine::refreshLocation(const GdbMi &reportedLocation) void PdbEngine::refreshLocation(const GdbMi &reportedLocation)
{ {
StackFrame frame; StackFrame frame;
frame.file = reportedLocation["file"].data(); frame.file = Utils::FilePath::fromString(reportedLocation["file"].data());
frame.line = reportedLocation["line"].toInt(); frame.line = reportedLocation["line"].toInt();
frame.usable = QFileInfo(frame.file).isReadable(); frame.usable = frame.file.isReadableFile();
if (state() == InferiorRunOk) { 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); gotoLocation(frame);
notifyInferiorSpontaneousStop(); notifyInferiorSpontaneousStop();
updateAll(); updateAll();
@@ -535,7 +535,7 @@ void PdbEngine::refreshStack(const GdbMi &stack)
for (const GdbMi &item : stack["frames"]) { for (const GdbMi &item : stack["frames"]) {
StackFrame frame; StackFrame frame;
frame.level = item["level"].data(); frame.level = item["level"].data();
frame.file = item["file"].data(); frame.file = Utils::FilePath::fromString(item["file"].data());
frame.function = item["function"].data(); frame.function = item["function"].data();
frame.module = item["function"].data(); frame.module = item["function"].data();
frame.line = item["line"].toInt(); frame.line = item["line"].toInt();
@@ -544,7 +544,7 @@ void PdbEngine::refreshStack(const GdbMi &stack)
if (usable.isValid()) if (usable.isValid())
frame.usable = usable.data().toInt(); frame.usable = usable.data().toInt();
else else
frame.usable = QFileInfo(frame.file).isReadable(); frame.usable = frame.file.isReadableFile();
frames.append(frame); frames.append(frame);
} }
bool canExpand = stack["hasmore"].toInt(); bool canExpand = stack["hasmore"].toInt();

View File

@@ -2036,8 +2036,9 @@ StackFrame QmlEnginePrivate::extractStackFrame(const QVariant &bodyVal)
stackFrame.function = extractString(body.value("func")); stackFrame.function = extractString(body.value("func"));
if (stackFrame.function.isEmpty()) if (stackFrame.function.isEmpty())
stackFrame.function = QCoreApplication::translate("QmlEngine", "Anonymous Function"); stackFrame.function = QCoreApplication::translate("QmlEngine", "Anonymous Function");
stackFrame.file = engine->toFileInProject(extractString(body.value("script"))); stackFrame.file = FilePath::fromString(
stackFrame.usable = QFileInfo(stackFrame.file).isReadable(); engine->toFileInProject(extractString(body.value("script"))));
stackFrame.usable = stackFrame.file.isReadableFile();
stackFrame.receiver = extractString(body.value("receiver")); stackFrame.receiver = extractString(body.value("receiver"));
stackFrame.line = body.value("line").toInt() + 1; stackFrame.line = body.value("line").toInt() + 1;

View File

@@ -134,7 +134,7 @@ void SourceAgent::updateLocationMarker()
d->editor->textDocument()->removeMark(d->locationMark); d->editor->textDocument()->removeMark(d->locationMark);
delete d->locationMark; delete d->locationMark;
d->locationMark = nullptr; 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; int lineNumber = d->engine->stackHandler()->currentFrame().line;
d->locationMark = new TextMark(Utils::FilePath(), lineNumber, d->locationMark = new TextMark(Utils::FilePath(), lineNumber,

View File

@@ -190,7 +190,7 @@ static void blockRecursion(const Overview &overview,
QStringList getUninitializedVariables(const Snapshot &snapshot, QStringList getUninitializedVariables(const Snapshot &snapshot,
const QString &functionName, const QString &functionName,
const QString &file, const FilePath &file,
int line) int line)
{ {
QStringList result; QStringList result;

View File

@@ -33,6 +33,7 @@ class TextDocument;
class TextEditorWidget; class TextEditorWidget;
} }
namespace Utils { class FilePath; }
namespace CPlusPlus { class Snapshot; } namespace CPlusPlus { class Snapshot; }
namespace Debugger { 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 // of a function from the code model. Shadowed variables will
// be reported using the debugger naming conventions '<shadowed n>' // be reported using the debugger naming conventions '<shadowed n>'
QStringList getUninitializedVariables(const CPlusPlus::Snapshot &snapshot, 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); ContextData getLocationContext(TextEditor::TextDocument *document, int lineNumber);

View File

@@ -35,6 +35,8 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
using namespace Utils;
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -93,7 +95,8 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet
frame.level = frameMi["level"].data(); frame.level = frameMi["level"].data();
frame.function = frameMi["function"].data(); frame.function = frameMi["function"].data();
frame.module = frameMi["module"].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.line = frameMi["line"].toInt();
frame.address = frameMi["address"].toAddress(); frame.address = frameMi["address"].toAddress();
frame.context = frameMi["context"].data(); frame.context = frameMi["context"].data();
@@ -107,13 +110,13 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet
if (usable.isValid()) if (usable.isValid())
frame.usable = usable.data().toInt(); frame.usable = usable.data().toInt();
else else
frame.usable = QFileInfo(frame.file).isReadable(); frame.usable = frame.file.isReadableFile();
return frame; return frame;
} }
QString StackFrame::toToolTip() const QString StackFrame::toToolTip() const
{ {
const QString filePath = QDir::toNativeSeparators(file); const QString filePath = file.toUserOutput();
QString res; QString res;
QTextStream str(&res); QTextStream str(&res);
str << "<html><body><table>"; str << "<html><body><table>";
@@ -150,7 +153,7 @@ QString StackFrame::toToolTip() const
"frame. However, matching sources have not been found."); "frame. However, matching sources have not been found.");
showDistributionNote = true; showDistributionNote = true;
} }
if (!Utils::HostOsInfo::isWindowsHost() && showDistributionNote) { if (file.osType() != OsTypeWindows && showDistributionNote) {
str << ' ' << tr("Note that most distributions ship debug information " str << ' ' << tr("Note that most distributions ship debug information "
"in separate packages."); "in separate packages.");
} }
@@ -159,19 +162,14 @@ QString StackFrame::toToolTip() const
return res; return res;
} }
static QString findFile(const QString &baseDir, const QString &relativeFile) static FilePath findFile(const FilePath &baseDir, const FilePath &relativeFile)
{ {
QDir dir(baseDir); for (FilePath dir(baseDir); !dir.isEmpty(); dir = dir.parentDir()) {
while (true) { const FilePath absolutePath = dir.resolvePath(relativeFile);
const QString path = dir.absoluteFilePath(relativeFile); if (absolutePath.isFile())
const QFileInfo fi(path); return absolutePath;
if (fi.isFile())
return path;
if (dir.isRoot())
break;
dir.cdUp();
} }
return QString(); return {};
} }
// Try to resolve files coming from resource files. // Try to resolve files coming from resource files.
@@ -179,21 +177,23 @@ void StackFrame::fixQrcFrame(const DebuggerRunParameters &rp)
{ {
if (language != QmlLanguage) if (language != QmlLanguage)
return; return;
QFileInfo aFi(file); if (file.isAbsolutePath()) {
if (aFi.isAbsolute()) { usable = file.isFile();
usable = aFi.isFile();
return; return;
} }
if (!file.startsWith("qrc:/")) if (!file.startsWith("qrc:/"))
return; return;
QString relativeFile = file.right(file.size() - 5); FilePath relativeFile = file;
while (relativeFile.startsWith('/')) QString relativePath = file.path();
relativeFile = relativeFile.mid(1); 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()) if (absFile.isEmpty())
absFile = findFile(QDir::currentPath(), relativeFile); absFile = findFile(FilePath::fromString(QDir::currentPath()), relativeFile);
if (absFile.isEmpty()) if (absFile.isEmpty())
return; return;

View File

@@ -27,6 +27,8 @@
#include "debuggerconstants.h" #include "debuggerconstants.h"
#include <utils/filepath.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QMetaType> #include <QMetaType>
@@ -56,7 +58,7 @@ public:
DebuggerLanguage language = CppLanguage; DebuggerLanguage language = CppLanguage;
QString level; QString level;
QString function; 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 module; // Sometimes something like "/usr/lib/libstdc++.so.6"
QString receiver; // Used in ScriptEngine only. QString receiver; // Used in ScriptEngine only.
qint32 line = -1; qint32 line = -1;

View File

@@ -101,7 +101,7 @@ QVariant StackFrameItem::data(int column, int role) const
case StackFunctionNameColumn: case StackFunctionNameColumn:
return simplifyType(frame.function); return simplifyType(frame.function);
case StackFileNameColumn: case StackFileNameColumn:
return frame.file.isEmpty() ? frame.module : FilePath::fromString(frame.file).fileName(); return frame.file.isEmpty() ? frame.module : frame.file.fileName();
case StackLineNumberColumn: case StackLineNumberColumn:
return frame.line > 0 ? QVariant(frame.line) : QVariant(); return frame.line > 0 ? QVariant(frame.line) : QVariant();
case StackAddressColumn: case StackAddressColumn:

View File

@@ -4,12 +4,7 @@ add_qtc_plugin(Docker
docker_global.h docker_global.h
dockerbuildstep.cpp dockerbuildstep.h dockerbuildstep.cpp dockerbuildstep.h
dockerconstants.h dockerconstants.h
dockerdevice.cpp dockerdevice.cpp dockerdevice.h
dockerdevice.h dockerplugin.cpp dockerplugin.h
dockerplugin.cpp dockersettings.cpp dockersettings.h
dockerplugin.h
dockerrunconfiguration.cpp
dockerrunconfiguration.h
dockersettings.cpp
dockersettings.h
) )

View File

@@ -6,7 +6,6 @@ SOURCES += \
dockerbuildstep.cpp \ dockerbuildstep.cpp \
dockerdevice.cpp \ dockerdevice.cpp \
dockerplugin.cpp \ dockerplugin.cpp \
dockerrunconfiguration.cpp \
dockersettings.cpp dockersettings.cpp
HEADERS += \ HEADERS += \
@@ -15,5 +14,4 @@ HEADERS += \
dockerconstants.h \ dockerconstants.h \
dockerdevice.h \ dockerdevice.h \
dockerplugin.h \ dockerplugin.h \
dockerrunconfiguration.h \
dockersettings.h dockersettings.h

View File

@@ -19,8 +19,6 @@ QtcPlugin {
"dockerdevice.cpp", "dockerdevice.cpp",
"dockerplugin.h", "dockerplugin.h",
"dockerplugin.cpp", "dockerplugin.cpp",
"dockerrunconfiguration.h",
"dockerrunconfiguration.cpp",
"dockersettings.h", "dockersettings.h",
"dockersettings.cpp" "dockersettings.cpp"
] ]

View File

@@ -29,11 +29,9 @@
#include "dockerbuildstep.h" #include "dockerbuildstep.h"
#include "dockerdevice.h" #include "dockerdevice.h"
#include "dockerrunconfiguration.h"
#include "dockersettings.h" #include "dockersettings.h"
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runcontrol.h>
using namespace Core; using namespace Core;
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -49,13 +47,6 @@ public:
// DockerOptionsPage optionsPage{&settings}; // DockerOptionsPage optionsPage{&settings};
DockerDeviceFactory deviceFactory; DockerDeviceFactory deviceFactory;
// DockerContainerRunConfigurationFactory containerRunConfigFactory;
// RunWorkerFactory containerRunWorkerFactory{
// RunWorkerFactory::make<SimpleTargetRunner>(),
// {ProjectExplorer::Constants::NORMAL_RUN_MODE},
// {containerRunConfigFactory.runConfigurationId()}
// };
// DockerBuildStepFactory buildStepFactory; // DockerBuildStepFactory buildStepFactory;
Utils::optional<bool> daemonRunning; Utils::optional<bool> daemonRunning;

View File

@@ -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 <projectexplorer/kitinformation.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/target.h>
#include <utils/stringutils.h>
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<BoolAspect>();
rmOption->setSettingsKey("Docker.RunConfiguration.RmOption");
rmOption->setDefaultValue(true);
rmOption->setLabelText(tr("Automatically remove the container when it exits"));
auto ttyOption = addAspect<BoolAspect>();
ttyOption->setSettingsKey("Docker.RunConfiguration.TtyOption");
ttyOption->setLabelText(tr("Allocate a pseudo-TTY"));
ttyOption->setVisible(false); // Not yet.
auto interactiveOption = addAspect<BoolAspect>();
interactiveOption->setSettingsKey("Docker.RunConfiguration.InteractiveOption");
interactiveOption->setLabelText(tr("Keep STDIN open even if not attached"));
interactiveOption->setVisible(false); // Not yet.
auto effectiveCommand = addAspect<StringAspect>();
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<const DockerDevice>(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<DockerContainerRunConfiguration>
("Docker.DockerContainerRunConfiguration");
addSupportedTargetDeviceType(Constants::DOCKER_DEVICE_TYPE);
}
} // Internal
} // Docker

View File

@@ -479,12 +479,18 @@ void IosConfigurations::loadProvisioningData(bool notify)
QList<QVariantMap> teams; QList<QVariantMap> teams;
for (auto accountiterator = teamMap.cbegin(), end = teamMap.cend(); for (auto accountiterator = teamMap.cbegin(), end = teamMap.cend();
accountiterator != end; ++accountiterator) { accountiterator != end; ++accountiterator) {
QVariantMap teamInfo = accountiterator.value().toMap(); // 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; int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0;
teamInfo[freeTeamTag] = provisioningTeamIsFree; teamInfo[freeTeamTag] = provisioningTeamIsFree;
teamInfo[emailTag] = accountiterator.key(); teamInfo[emailTag] = accountiterator.key();
teams.append(teamInfo); teams.append(teamInfo);
} }
}
// Sort team id's to move the free provisioning teams at last of the list. // Sort team id's to move the free provisioning teams at last of the list.
Utils::sort(teams, [](const QVariantMap &teamInfo1, const QVariantMap &teamInfo2) { Utils::sort(teams, [](const QVariantMap &teamInfo1, const QVariantMap &teamInfo2) {

View File

@@ -12,4 +12,5 @@ add_qtc_plugin(McuSupport
mcusupportsdk.cpp mcusupportsdk.h mcusupportsdk.cpp mcusupportsdk.h
mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h
mcusupportversiondetection.cpp mcusupportversiondetection.h mcusupportversiondetection.cpp mcusupportversiondetection.h
mcusupportcmakemapper.cpp mcusupportcmakemapper.h
) )

View File

@@ -13,7 +13,8 @@ HEADERS += \
mcusupportplugin.h \ mcusupportplugin.h \
mcusupportsdk.h \ mcusupportsdk.h \
mcusupportrunconfiguration.h \ mcusupportrunconfiguration.h \
mcusupportversiondetection.h mcusupportversiondetection.h \
mcusupportcmakemapper.h
SOURCES += \ SOURCES += \
mcusupportdevice.cpp \ mcusupportdevice.cpp \
@@ -22,7 +23,8 @@ SOURCES += \
mcusupportplugin.cpp \ mcusupportplugin.cpp \
mcusupportsdk.cpp \ mcusupportsdk.cpp \
mcusupportrunconfiguration.cpp \ mcusupportrunconfiguration.cpp \
mcusupportversiondetection.cpp mcusupportversiondetection.cpp \
mcusupportcmakemapper.cpp
RESOURCES += \ RESOURCES += \
mcusupport.qrc mcusupport.qrc

View File

@@ -32,5 +32,7 @@ QtcPlugin {
"mcusupportrunconfiguration.h", "mcusupportrunconfiguration.h",
"mcusupportversiondetection.cpp", "mcusupportversiondetection.cpp",
"mcusupportversiondetection.h", "mcusupportversiondetection.h",
"mcusupportcmakemapper.h",
"mcusupportcmakemapper.cpp"
] ]
} }

View File

@@ -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 <utils/algorithm.h>
namespace {
static const QHash<QString, QString> &envVarToCMakeVarMapping()
{
static const QHash<QString, QString> 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<CMakeProjectManager::CMakeConfigItem> 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();
});
}

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -22,20 +22,14 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
** **
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <projectexplorer/runconfiguration.h> #include "cmakeprojectmanager/cmakeconfigitem.h"
#include "utils/environmentfwd.h"
namespace Docker { namespace McuSupport {
namespace Internal { namespace Internal {
QList<CMakeProjectManager::CMakeConfigItem> mapEnvVarsToQul2xCmakeVars(
class DockerContainerRunConfigurationFactory const Utils::EnvironmentItems &envVars);
: public ProjectExplorer::FixedRunConfigurationFactory }
{ } // namespace McuSupport
public:
DockerContainerRunConfigurationFactory();
};
} // Internal
} // Docker

View File

@@ -27,6 +27,7 @@
#include "mcusupportoptions.h" #include "mcusupportoptions.h"
#include "mcusupportsdk.h" #include "mcusupportsdk.h"
#include "mcusupportplugin.h" #include "mcusupportplugin.h"
#include "mcusupportcmakemapper.h"
#include <baremetal/baremetalconstants.h> #include <baremetal/baremetalconstants.h>
#include <cmakeprojectmanager/cmaketoolmanager.h> #include <cmakeprojectmanager/cmaketoolmanager.h>
@@ -70,7 +71,7 @@ using namespace Utils;
namespace McuSupport { namespace McuSupport {
namespace Internal { 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, static FilePath packagePathFromSettings(const QString &settingsKey,
QSettings::Scope scope = QSettings::UserScope, QSettings::Scope scope = QSettings::UserScope,
@@ -99,6 +100,22 @@ static bool kitNeedsQtVersion()
return !HostOsInfo::isWindowsHost(); 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, McuPackage::McuPackage(const QString &label, const FilePath &defaultPath,
const QString &detectionPath, const QString &settingsKey, const QString &detectionPath, const QString &settingsKey,
const McuPackageVersionDetector *versionDetector) const McuPackageVersionDetector *versionDetector)
@@ -231,7 +248,7 @@ bool McuPackage::writeToSettings() const
const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath); const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath);
const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' + const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' +
QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey; 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; return savedPath != m_path;
} }
@@ -573,6 +590,14 @@ void McuTarget::setColorDepth(int colorDepth)
m_colorDepth = colorDepth; m_colorDepth = colorDepth;
} }
void McuSdkRepository::deletePackagesAndTargets()
{
qDeleteAll(packages);
packages.clear();
qDeleteAll(mcuTargets);
mcuTargets.clear();
}
McuSupportOptions::McuSupportOptions(QObject *parent) McuSupportOptions::McuSupportOptions(QObject *parent)
: QObject(parent) : QObject(parent)
, qtForMCUsSdkPackage(Sdk::createQtForMCUsPackage()) , 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() const QVersionNumber &McuSupportOptions::minimalQulVersion()
{ {
static const QVersionNumber v({1, 3}); static const QVersionNumber v({1, 3});
@@ -654,8 +671,8 @@ void McuSupportOptions::setQulDir(const FilePath &dir)
deletePackagesAndTargets(); deletePackagesAndTargets();
qtForMCUsSdkPackage->updateStatus(); qtForMCUsSdkPackage->updateStatus();
if (qtForMCUsSdkPackage->validStatus()) if (qtForMCUsSdkPackage->validStatus())
Sdk::targetsAndPackages(dir, &packages, &mcuTargets); Sdk::targetsAndPackages(dir, &sdkRepository);
for (auto package : qAsConst(packages)) for (const auto &package : qAsConst(sdkRepository.packages))
connect(package, &McuPackage::changed, this, &McuSupportOptions::changed); connect(package, &McuPackage::changed, this, &McuSupportOptions::changed);
emit changed(); emit changed();
@@ -736,6 +753,11 @@ static void setKitDevice(Kit *k, const McuTarget* mcuTarget)
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); 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, static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
const McuPackage *qtForMCUsSdkPackage) const McuPackage *qtForMCUsSdkPackage)
{ {
@@ -770,6 +792,11 @@ static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
if (kitNeedsQtVersion()) if (kitNeedsQtVersion())
changes.append({QLatin1String("LD_LIBRARY_PATH"), "%{Qt:QT_INSTALL_LIBS}"}); 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); 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); EnvironmentKitAspect::setEnvironmentChanges(k, changes);
} }
@@ -1015,6 +1047,11 @@ bool McuSupportOptions::kitUpToDate(const Kit *kit, const McuTarget *mcuTarget,
kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path(); kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path();
} }
void McuSupportOptions::deletePackagesAndTargets()
{
sdkRepository.deletePackagesAndTargets();
}
McuSupportOptions::UpgradeOption McuSupportOptions::askForKitUpgrades() McuSupportOptions::UpgradeOption McuSupportOptions::askForKitUpgrades()
{ {
QMessageBox upgradePopup(Core::ICore::dialogParent()); QMessageBox upgradePopup(Core::ICore::dialogParent());
@@ -1076,12 +1113,11 @@ void McuSupportOptions::createAutomaticKits()
} }
FilePath dir = qtForMCUsPackage->path(); FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages; McuSdkRepository repo;
QVector<McuTarget*> mcuTargets; Sdk::targetsAndPackages(dir, &repo);
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
bool needsUpgrade = false; bool needsUpgrade = false;
for (auto target: qAsConst(mcuTargets)) { for (const auto &target: qAsConst(repo.mcuTargets)) {
// if kit already exists, skip // if kit already exists, skip
if (!matchingKits(target, qtForMCUsPackage).empty()) if (!matchingKits(target, qtForMCUsPackage).empty())
continue; continue;
@@ -1096,8 +1132,7 @@ void McuSupportOptions::createAutomaticKits()
} }
} }
qDeleteAll(packages); repo.deletePackagesAndTargets();
qDeleteAll(mcuTargets);
if (needsUpgrade) if (needsUpgrade)
McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade(); McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade();
@@ -1110,10 +1145,10 @@ void McuSupportOptions::createAutomaticKits()
void McuSupportOptions::checkUpgradeableKits() void McuSupportOptions::checkUpgradeableKits()
{ {
if (!qtForMCUsSdkPackage->validStatus() || mcuTargets.length() == 0) if (!qtForMCUsSdkPackage->validStatus() || sdkRepository.mcuTargets.length() == 0)
return; return;
if (Utils::anyOf(mcuTargets, [this](const McuTarget *target) { if (Utils::anyOf(sdkRepository.mcuTargets, [this](const McuTarget *target) {
return !upgradeableKits(target, this->qtForMCUsSdkPackage).empty() && return !upgradeableKits(target, this->qtForMCUsSdkPackage).empty() &&
matchingKits(target, this->qtForMCUsSdkPackage).empty(); matchingKits(target, this->qtForMCUsSdkPackage).empty();
})) }))
@@ -1128,11 +1163,10 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption)
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
auto dir = qtForMCUsPackage->path(); auto dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages; McuSdkRepository repo;
QVector<McuTarget*> mcuTargets; Sdk::targetsAndPackages(dir, &repo);
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto target: qAsConst(mcuTargets)) { for (const auto &target: qAsConst(repo.mcuTargets)) {
if (!matchingKits(target, qtForMCUsPackage).empty()) if (!matchingKits(target, qtForMCUsPackage).empty())
// already up-to-date // already up-to-date
continue; continue;
@@ -1149,8 +1183,7 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption)
} }
} }
qDeleteAll(packages); repo.deletePackagesAndTargets();
qDeleteAll(mcuTargets);
delete qtForMCUsPackage; delete qtForMCUsPackage;
} }
@@ -1166,10 +1199,9 @@ void McuSupportOptions::fixKitsDependencies()
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
FilePath dir = qtForMCUsPackage->path(); FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages; McuSdkRepository repo;
QVector<McuTarget*> mcuTargets; Sdk::targetsAndPackages(dir, &repo);
Sdk::targetsAndPackages(dir, &packages, &mcuTargets); for (const auto &target: qAsConst(repo.mcuTargets)) {
for (auto target: qAsConst(mcuTargets)) {
if (target->isValid()) { if (target->isValid()) {
for (auto kit : kitsWithMismatchedDependencies(target)) { for (auto kit : kitsWithMismatchedDependencies(target)) {
updateKitEnvironment(kit, target); updateKitEnvironment(kit, target);
@@ -1177,8 +1209,7 @@ void McuSupportOptions::fixKitsDependencies()
} }
} }
qDeleteAll(packages); repo.deletePackagesAndTargets();
qDeleteAll(mcuTargets);
delete qtForMCUsPackage; delete qtForMCUsPackage;
} }
@@ -1242,18 +1273,16 @@ void McuSupportOptions::fixExistingKits()
qtForMCUsPackage->updateStatus(); qtForMCUsPackage->updateStatus();
if (qtForMCUsPackage->validStatus()) { if (qtForMCUsPackage->validStatus()) {
FilePath dir = qtForMCUsPackage->path(); FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages; McuSdkRepository repo;
QVector<McuTarget*> mcuTargets; Sdk::targetsAndPackages(dir, &repo);
Sdk::targetsAndPackages(dir, &packages, &mcuTargets); for (const auto &target: qAsConst(repo.mcuTargets))
for (auto target: qAsConst(mcuTargets))
for (auto kit: existingKits(target)) { for (auto kit: existingKits(target)) {
if (McuDependenciesKitAspect::dependencies(kit).isEmpty()) { if (McuDependenciesKitAspect::dependencies(kit).isEmpty()) {
setKitDependencies(kit, target, qtForMCUsPackage); setKitDependencies(kit, target, qtForMCUsPackage);
} }
} }
qDeleteAll(packages); repo.deletePackagesAndTargets();
qDeleteAll(mcuTargets);
} }
delete qtForMCUsPackage; delete qtForMCUsPackage;
} }

View File

@@ -200,6 +200,15 @@ private:
int m_colorDepth = -1; int m_colorDepth = -1;
}; };
class McuSdkRepository
{
public:
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
void deletePackagesAndTargets();
};
class McuSupportOptions : public QObject class McuSupportOptions : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -214,9 +223,8 @@ public:
McuSupportOptions(QObject *parent = nullptr); McuSupportOptions(QObject *parent = nullptr);
~McuSupportOptions() override; ~McuSupportOptions() override;
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
McuPackage *qtForMCUsSdkPackage = nullptr; McuPackage *qtForMCUsSdkPackage = nullptr;
McuSdkRepository sdkRepository;
void setQulDir(const Utils::FilePath &dir); void setQulDir(const Utils::FilePath &dir);
static Utils::FilePath qulDirFromSettings(); static Utils::FilePath qulDirFromSettings();

View File

@@ -190,7 +190,7 @@ void McuSupportOptionsWidget::updateStatus()
m_mcuTargetsGroupBox->setVisible(ready); m_mcuTargetsGroupBox->setVisible(ready);
m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty()); m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty());
m_kitCreationGroupBox->setVisible(ready); 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()) { if (m_mcuTargetsInfoLabel->isVisible()) {
m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk); m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk);
const Utils::FilePath sdkPath = m_options.qtForMCUsSdkPackage->basePath(); const Utils::FilePath sdkPath = m_options.qtForMCUsSdkPackage->basePath();
@@ -261,7 +261,7 @@ void McuSupportOptionsWidget::showMcuTargetPackages()
row.fieldItem->widget()->hide(); row.fieldItem->widget()->hide();
} }
for (auto package : qAsConst(m_options.packages)) { for (auto package : qAsConst(m_options.sdkRepository.packages)) {
QWidget *packageWidget = package->widget(); QWidget *packageWidget = package->widget();
if (!mcuTarget->packages().contains(package)) if (!mcuTarget->packages().contains(package))
continue; continue;
@@ -275,9 +275,9 @@ void McuSupportOptionsWidget::showMcuTargetPackages()
McuTarget *McuSupportOptionsWidget::currentMcuTarget() const McuTarget *McuSupportOptionsWidget::currentMcuTarget() const
{ {
const int mcuTargetIndex = m_mcuTargetsComboBox->currentIndex(); const int mcuTargetIndex = m_mcuTargetsComboBox->currentIndex();
return (mcuTargetIndex == -1 || m_options.mcuTargets.isEmpty()) return (mcuTargetIndex == -1 || m_options.sdkRepository.mcuTargets.isEmpty())
? nullptr ? nullptr
: m_options.mcuTargets.at(mcuTargetIndex); : m_options.sdkRepository.mcuTargets.at(mcuTargetIndex);
} }
void McuSupportOptionsWidget::showEvent(QShowEvent *event) void McuSupportOptionsWidget::showEvent(QShowEvent *event)
@@ -292,7 +292,7 @@ void McuSupportOptionsWidget::apply()
m_options.qtForMCUsSdkPackage->writeGeneralSettings(); m_options.qtForMCUsSdkPackage->writeGeneralSettings();
pathsChanged |= m_options.qtForMCUsSdkPackage->writeToSettings(); pathsChanged |= m_options.qtForMCUsSdkPackage->writeToSettings();
for (auto package : qAsConst(m_options.packages)) for (auto package : qAsConst(m_options.sdkRepository.packages))
pathsChanged |= package->writeToSettings(); pathsChanged |= package->writeToSettings();
if (pathsChanged) { if (pathsChanged) {
@@ -306,7 +306,7 @@ void McuSupportOptionsWidget::populateMcuTargetsComboBox()
m_options.populatePackagesAndTargets(); m_options.populatePackagesAndTargets();
m_mcuTargetsComboBox->clear(); m_mcuTargetsComboBox->clear();
m_mcuTargetsComboBox->addItems( m_mcuTargetsComboBox->addItems(
Utils::transform<QStringList>(m_options.mcuTargets, [](McuTarget *t) { Utils::transform<QStringList>(m_options.sdkRepository.mcuTargets, [](McuTarget *t) {
return McuSupportOptions::kitName(t); return McuSupportOptions::kitName(t);
})); }));
updateStatus(); updateStatus();

View File

@@ -331,19 +331,28 @@ struct McuTargetDescription
}; };
QString qulVersion; QString qulVersion;
QString platform; QString compatVersion;
QString platformName; struct {
QString platformVendor; QString id;
QString name;
QString vendor;
QVector<int> colorDepths; QVector<int> colorDepths;
QString toolchainId;
QVector<QString> toolchainVersions;
QString boardSdkEnvVar;
QString boardSdkName;
QString boardSdkDefaultPath;
QVector<QString> boardSdkVersions;
QString freeRTOSEnvVar;
QString freeRTOSBoardSdkSubDir;
TargetType type; TargetType type;
} platform;
struct {
QString id;
QVector<QString> versions;
} toolchain;
struct {
QString name;
QString defaultPath;
QString envVar;
QVector<QString> versions;
} boardSdk;
struct {
QString envVar;
QString boardSdkSubDir;
} freeRTOS;
}; };
static McuPackageVersionDetector* generatePackageVersionDetector(QString envVar) static McuPackageVersionDetector* generatePackageVersionDetector(QString envVar)
@@ -373,29 +382,29 @@ static McuPackage *createBoardSdkPackage(const McuTargetDescription& desc)
auto sdkName = postfixPos > 0 ? envVar.left(postfixPos) : envVar; auto sdkName = postfixPos > 0 ? envVar.left(postfixPos) : envVar;
return QString::fromLatin1("MCU SDK (%1)").arg(sdkName); 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 FilePath defaultPath = [&] {
const auto envVar = desc.boardSdkEnvVar.toLatin1(); const auto envVar = desc.boardSdk.envVar.toLatin1();
if (qEnvironmentVariableIsSet(envVar)) if (qEnvironmentVariableIsSet(envVar))
return FilePath::fromUserInput(qEnvironmentVariable(envVar)); return FilePath::fromUserInput(qEnvironmentVariable(envVar));
if (!desc.boardSdkDefaultPath.isEmpty()) { if (!desc.boardSdk.defaultPath.isEmpty()) {
FilePath defaultPath = FilePath::fromUserInput(QDir::rootPath() + desc.boardSdkDefaultPath); FilePath defaultPath = FilePath::fromUserInput(QDir::rootPath() + desc.boardSdk.defaultPath);
if (defaultPath.exists()) if (defaultPath.exists())
return defaultPath; return defaultPath;
} }
return FileUtils::homePath(); return FileUtils::homePath();
}(); }();
const auto versionDetector = generatePackageVersionDetector(desc.boardSdkEnvVar); const auto versionDetector = generatePackageVersionDetector(desc.boardSdk.envVar);
auto result = new McuPackage( auto result = new McuPackage(
sdkName, sdkName,
defaultPath, defaultPath,
{}, {},
desc.boardSdkEnvVar, desc.boardSdk.envVar,
versionDetector); versionDetector);
result->setEnvironmentVariableName(desc.boardSdkEnvVar); result->setEnvironmentVariableName(desc.boardSdk.envVar);
return result; return result;
} }
@@ -434,7 +443,7 @@ struct McuTargetFactory
{ {
auto qulVersion = QVersionNumber::fromString(description.qulVersion); auto qulVersion = QVersionNumber::fromString(description.qulVersion);
if (qulVersion <= QVersionNumber({1,3})) { if (qulVersion <= QVersionNumber({1,3})) {
if (description.type == McuTargetDescription::TargetType::Desktop) if (description.platform.type == McuTargetDescription::TargetType::Desktop)
return createDesktopTargetsLegacy(description); return createDesktopTargetsLegacy(description);
// There was a platform backends related refactoring in Qul 1.4 // There was a platform backends related refactoring in Qul 1.4
@@ -459,44 +468,44 @@ protected:
QVector<McuTarget *> createMcuTargetsLegacy(const McuTargetDescription &desc) QVector<McuTarget *> createMcuTargetsLegacy(const McuTargetDescription &desc)
{ {
QVector<McuTarget *> mcuTargets; QVector<McuTarget *> mcuTargets;
McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id);
if (!tcPkg) if (!tcPkg)
tcPkg = createUnsupportedToolChainPackage(); tcPkg = createUnsupportedToolChainPackage();
for (auto os : {McuTarget::OS::BareMetal, McuTarget::OS::FreeRTOS}) { for (auto os : {McuTarget::OS::BareMetal, McuTarget::OS::FreeRTOS}) {
for (int colorDepth : desc.colorDepths) { for (int colorDepth : desc.platform.colorDepths) {
QVector<McuPackage*> required3rdPartyPkgs = { tcPkg }; QVector<McuPackage*> required3rdPartyPkgs = { tcPkg };
if (vendorPkgs.contains(desc.platformVendor)) if (vendorPkgs.contains(desc.platform.vendor))
required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platformVendor)); required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platform.vendor));
FilePath boardSdkDefaultPath; FilePath boardSdkDefaultPath;
if (!desc.boardSdkEnvVar.isEmpty()) { if (!desc.boardSdk.envVar.isEmpty()) {
if (!boardSdkPkgs.contains(desc.boardSdkEnvVar)) { if (!boardSdkPkgs.contains(desc.boardSdk.envVar)) {
auto boardSdkPkg = desc.boardSdkEnvVar != "RGL_DIR" auto boardSdkPkg = desc.boardSdk.envVar != "RGL_DIR"
? createBoardSdkPackage(desc) ? createBoardSdkPackage(desc)
: createRGLPackage(); : 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(); boardSdkDefaultPath = boardSdkPkg->defaultPath();
required3rdPartyPkgs.append(boardSdkPkg); required3rdPartyPkgs.append(boardSdkPkg);
} }
if (os == McuTarget::OS::FreeRTOS) { if (os == McuTarget::OS::FreeRTOS) {
if (desc.freeRTOSEnvVar.isEmpty()) { if (desc.freeRTOS.envVar.isEmpty()) {
continue; continue;
} else { } else {
if (!freeRTOSPkgs.contains(desc.freeRTOSEnvVar)) { if (!freeRTOSPkgs.contains(desc.freeRTOS.envVar)) {
freeRTOSPkgs.insert(desc.freeRTOSEnvVar, createFreeRTOSSourcesPackage( freeRTOSPkgs.insert(desc.freeRTOS.envVar, createFreeRTOSSourcesPackage(
desc.freeRTOSEnvVar, boardSdkDefaultPath, desc.freeRTOS.envVar, boardSdkDefaultPath,
desc.freeRTOSBoardSdkSubDir)); 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), auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion),
platform, os, required3rdPartyPkgs, tcPkg); platform, os, required3rdPartyPkgs, tcPkg);
if (desc.colorDepths.count() > 1) if (desc.platform.colorDepths.count() > 1)
mcuTarget->setColorDepth(colorDepth); mcuTarget->setColorDepth(colorDepth);
mcuTargets.append(mcuTarget); mcuTargets.append(mcuTarget);
} }
@@ -506,10 +515,10 @@ protected:
QVector<McuTarget *> createDesktopTargetsLegacy(const McuTargetDescription& desc) QVector<McuTarget *> createDesktopTargetsLegacy(const McuTargetDescription& desc)
{ {
McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id);
if (!tcPkg) if (!tcPkg)
tcPkg = createUnsupportedToolChainPackage(); 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), auto desktopTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion),
platform, McuTarget::OS::Desktop, {}, tcPkg); platform, McuTarget::OS::Desktop, {}, tcPkg);
return { desktopTarget }; return { desktopTarget };
@@ -519,21 +528,21 @@ protected:
{ {
// OS deduction // OS deduction
const auto os = [&] { const auto os = [&] {
if (desc.type == McuTargetDescription::TargetType::Desktop) if (desc.platform.type == McuTargetDescription::TargetType::Desktop)
return McuTarget::OS::Desktop; return McuTarget::OS::Desktop;
else if (!desc.freeRTOSEnvVar.isEmpty()) else if (!desc.freeRTOS.envVar.isEmpty())
return McuTarget::OS::FreeRTOS; return McuTarget::OS::FreeRTOS;
return McuTarget::OS::BareMetal; return McuTarget::OS::BareMetal;
}(); }();
QVector<McuTarget *> mcuTargets; QVector<McuTarget *> mcuTargets;
McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchainId); McuToolChainPackage *tcPkg = tcPkgs.value(desc.toolchain.id);
if (tcPkg) { if (tcPkg) {
if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8})) if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8}))
tcPkg->setVersions(desc.toolchainVersions); tcPkg->setVersions(desc.toolchain.versions);
} else } else
tcPkg = createUnsupportedToolChainPackage(); tcPkg = createUnsupportedToolChainPackage();
for (int colorDepth : desc.colorDepths) { for (int colorDepth : desc.platform.colorDepths) {
QVector<McuPackage*> required3rdPartyPkgs; QVector<McuPackage*> required3rdPartyPkgs;
// Desktop toolchains don't need any additional settings // Desktop toolchains don't need any additional settings
if (tcPkg if (tcPkg
@@ -542,34 +551,34 @@ protected:
required3rdPartyPkgs.append(tcPkg); required3rdPartyPkgs.append(tcPkg);
// Add setting specific to platform IDE // Add setting specific to platform IDE
if (vendorPkgs.contains(desc.platformVendor)) if (vendorPkgs.contains(desc.platform.vendor))
required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platformVendor)); required3rdPartyPkgs.push_back(vendorPkgs.value(desc.platform.vendor));
// Board SDK specific settings // Board SDK specific settings
FilePath boardSdkDefaultPath; FilePath boardSdkDefaultPath;
if (!desc.boardSdkEnvVar.isEmpty()) { if (!desc.boardSdk.envVar.isEmpty()) {
if (!boardSdkPkgs.contains(desc.boardSdkEnvVar)) { if (!boardSdkPkgs.contains(desc.boardSdk.envVar)) {
auto boardSdkPkg = createBoardSdkPackage(desc); 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})) if (QVersionNumber::fromString(desc.qulVersion) >= QVersionNumber({1,8}))
boardSdkPkg->setVersions(desc.boardSdkVersions); boardSdkPkg->setVersions(desc.boardSdk.versions);
boardSdkDefaultPath = boardSdkPkg->defaultPath(); boardSdkDefaultPath = boardSdkPkg->defaultPath();
required3rdPartyPkgs.append(boardSdkPkg); required3rdPartyPkgs.append(boardSdkPkg);
} }
// Free RTOS specific settings // Free RTOS specific settings
if (!desc.freeRTOSEnvVar.isEmpty()) { if (!desc.freeRTOS.envVar.isEmpty()) {
if (!freeRTOSPkgs.contains(desc.freeRTOSEnvVar)) { if (!freeRTOSPkgs.contains(desc.freeRTOS.envVar)) {
freeRTOSPkgs.insert(desc.freeRTOSEnvVar, createFreeRTOSSourcesPackage( freeRTOSPkgs.insert(desc.freeRTOS.envVar, createFreeRTOSSourcesPackage(
desc.freeRTOSEnvVar, boardSdkDefaultPath, desc.freeRTOS.envVar, boardSdkDefaultPath,
desc.freeRTOSBoardSdkSubDir)); 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), auto mcuTarget = new McuTarget(QVersionNumber::fromString(desc.qulVersion),
platform, os, required3rdPartyPkgs, tcPkg); platform, os, required3rdPartyPkgs, tcPkg);
mcuTarget->setColorDepth(colorDepth); mcuTarget->setColorDepth(colorDepth);
@@ -634,17 +643,20 @@ static QFileInfoList targetDescriptionFiles(const Utils::FilePath &dir)
return kitsDir.entryInfoList(); return kitsDir.entryInfoList();
} }
static McuTargetDescription parseDescriptionJson(const QByteArray &data) static QString extractQulVersion(const QByteArray &data)
{ {
const QJsonDocument document = QJsonDocument::fromJson(data); const QJsonDocument document = QJsonDocument::fromJson(data);
const QJsonObject target = document.object(); 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 toolchain = target.value("toolchain").toObject();
const QJsonObject boardSdk = target.value("boardSdk").toObject(); const QJsonObject boardSdk = target.value("boardSdk").toObject();
const QJsonObject freeRTOS = target.value("freeRTOS").toObject(); const QJsonObject freeRTOS = target.value("freeRTOS").toObject();
const QVariantList colorDepths = target.value("colorDepths").toArray().toVariantList();
const auto colorDepthsVector = Utils::transform<QVector<int> >(
colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); });
const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList(); const QVariantList toolchainVersions = toolchain.value("versions").toArray().toVariantList();
const auto toolchainVersionsVector = Utils::transform<QVector<QString> >( const auto toolchainVersionsVector = Utils::transform<QVector<QString> >(
toolchainVersions, [&](const QVariant &version) { return version.toString(); }); toolchainVersions, [&](const QVariant &version) { return version.toString(); });
@@ -653,21 +665,76 @@ static McuTargetDescription parseDescriptionJson(const QByteArray &data)
boardSdkVersions, [&](const QVariant &version) { return version.toString(); }); boardSdkVersions, [&](const QVariant &version) { return version.toString(); });
return { return {
target.value("qulVersion").toString(), 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<QVector<int> >(
colorDepths, [&](const QVariant &colorDepth) { return colorDepth.toInt(); });
description.platform = {
target.value("platform").toString(), target.value("platform").toString(),
target.value("platformName").toString(), target.value("platformName").toString(),
target.value("platformVendor").toString(), target.value("platformVendor").toString(),
colorDepthsVector, colorDepthsVector,
toolchain.value("id").toString(), description.boardSdk.envVar.isEmpty() ? McuTargetDescription::TargetType::Desktop : McuTargetDescription::TargetType::MCU
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
}; };
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<QVector<int> >(
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 // https://doc.qt.io/qtcreator/creator-developing-mcu.html#supported-qt-for-mcus-sdks
@@ -695,8 +762,7 @@ bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message)
return false; return false;
} }
void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packages, void targetsAndPackages(const Utils::FilePath &dir, McuSdkRepository *repo)
QVector<McuTarget *> *mcuTargets)
{ {
QList<McuTargetDescription> descriptions; QList<McuTargetDescription> descriptions;
@@ -706,8 +772,17 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
if (!file.open(QFile::ReadOnly)) if (!file.open(QFile::ReadOnly))
continue; continue;
const McuTargetDescription desc = parseDescriptionJson(file.readAll()); const McuTargetDescription desc = parseDescriptionJson(file.readAll());
if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) {
const auto pth = Utils::FilePath::fromString(fileInfo.filePath()); 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 QString qtcSupportText = oldSdkQtcRequiredVersion.contains(desc.qulVersion) ? const QString qtcSupportText = oldSdkQtcRequiredVersion.contains(desc.qulVersion) ?
McuTarget::tr("Detected version \"%1\", only supported by Qt Creator %2.") McuTarget::tr("Detected version \"%1\", only supported by Qt Creator %2.")
.arg(desc.qulVersion, oldSdkQtcRequiredVersion.value(desc.qulVersion)) .arg(desc.qulVersion, oldSdkQtcRequiredVersion.value(desc.qulVersion))
@@ -744,7 +819,7 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
// This whole section could be removed when minimalQulVersion will reach 1.5 or above // This whole section could be removed when minimalQulVersion will reach 1.5 or above
{ {
const bool hasDesktopDescription = Utils::contains(descriptions, [](const McuTargetDescription &desc) { const bool hasDesktopDescription = Utils::contains(descriptions, [](const McuTargetDescription &desc) {
return desc.type == McuTargetDescription::TargetType::Desktop; return desc.platform.type == McuTargetDescription::TargetType::Desktop;
}); });
if (!hasDesktopDescription) { if (!hasDesktopDescription) {
@@ -764,12 +839,12 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
desktopDescription.qulVersion = descriptions.empty() ? desktopDescription.qulVersion = descriptions.empty() ?
McuSupportOptions::minimalQulVersion().toString() McuSupportOptions::minimalQulVersion().toString()
: descriptions.first().qulVersion; : descriptions.first().qulVersion;
desktopDescription.platform = "Qt"; desktopDescription.platform.id = "Qt";
desktopDescription.platformName = "Desktop"; desktopDescription.platform.name = "Desktop";
desktopDescription.platformVendor = "Qt"; desktopDescription.platform.vendor = "Qt";
desktopDescription.colorDepths = {32}; desktopDescription.platform.colorDepths = {32};
desktopDescription.toolchainId = Utils::HostOsInfo::isWindowsHost() ? QString("msvc") : QString("gcc"); desktopDescription.toolchain.id = Utils::HostOsInfo::isWindowsHost() ? QString("msvc") : QString("gcc");
desktopDescription.type = McuTargetDescription::TargetType::Desktop; desktopDescription.platform.type = McuTargetDescription::TargetType::Desktop;
descriptions.prepend(desktopDescription); descriptions.prepend(desktopDescription);
} else { } else {
if (dir.exists()) if (dir.exists())
@@ -782,10 +857,10 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
} }
} }
mcuTargets->append(targetsFromDescriptions(descriptions, packages)); repo->mcuTargets.append(targetsFromDescriptions(descriptions, &(repo->packages)));
// Keep targets sorted lexicographically // 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); return McuSupportOptions::kitName(lhs) < McuSupportOptions::kitName(rhs);
}); });
} }

View File

@@ -33,17 +33,18 @@ class FilePath;
namespace McuSupport { namespace McuSupport {
namespace Internal { namespace Internal {
#define MAX_COMPATIBILITY_VERSION 1
class McuSdkRepository;
class McuPackage; class McuPackage;
class McuToolChainPackage;
class McuTarget;
namespace Sdk { namespace Sdk {
McuPackage *createQtForMCUsPackage(); McuPackage *createQtForMCUsPackage();
bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message); bool checkDeprecatedSdkError(const Utils::FilePath &qulDir, QString &message);
void targetsAndPackages(const Utils::FilePath &qulDir, void targetsAndPackages(const Utils::FilePath &qulDir, McuSdkRepository *repo);
QVector<McuPackage*> *packages, QVector<McuTarget*> *mcuTargets);
Utils::FilePath kitsPath(const Utils::FilePath &dir); Utils::FilePath kitsPath(const Utils::FilePath &dir);

View File

@@ -14,6 +14,10 @@ else()
endif() endif()
qul_target_qml_sources(%{ProjectName} %{MainQmlFile}) qul_target_qml_sources(%{ProjectName} %{MainQmlFile})
app_target_setup_os(%{ProjectName}) 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()

View File

@@ -1219,17 +1219,14 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP
connect(&m_launcher, &ApplicationLauncher::processExited, connect(&m_launcher, &ApplicationLauncher::processExited,
this, [this, runnable](int exitCode, QProcess::ExitStatus status) { this, [this, runnable](int exitCode, QProcess::ExitStatus status) {
QString msg; if (m_stopReported)
if (status == QProcess::CrashExit) return;
msg = tr("%1 crashed."); const QString msg = (status == QProcess::CrashExit)
else ? tr("%1 crashed.") : tr("%2 exited with code %1").arg(exitCode);
msg = tr("%2 exited with code %1").arg(exitCode);
const QString displayName = runnable.command.executable().toUserOutput(); const QString displayName = runnable.command.executable().toUserOutput();
appendMessage(msg.arg(displayName), Utils::NormalMessageFormat); appendMessage(msg.arg(displayName), Utils::NormalMessageFormat);
if (!m_stopReported) {
m_stopReported = true; m_stopReported = true;
reportStopped(); reportStopped();
}
}); });
connect(&m_launcher, &ApplicationLauncher::error, connect(&m_launcher, &ApplicationLauncher::error,

View File

@@ -38,6 +38,7 @@ add_qtc_plugin(QmlDesigner
designermcumanager.cpp designermcumanager.h designermcumanager.cpp designermcumanager.h
richtexteditordialog.cpp richtexteditordialog.h richtexteditordialog.cpp richtexteditordialog.h
editorproxy.cpp editorproxy.h editorproxy.cpp editorproxy.h
boilerplate.qrc
EXPLICIT_MOC EXPLICIT_MOC
components/propertyeditor/propertyeditorvalue.h components/propertyeditor/propertyeditorvalue.h
components/connectioneditor/connectionviewwidget.h components/connectioneditor/connectionviewwidget.h

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/boilerplatetemplates">
<file>qmlprojectmaincpp.tpl</file>
</qresource>
</RCC>

View File

@@ -599,12 +599,20 @@ void FormEditorWidget::dropEvent(QDropEvent *dropEvent)
->viewManager().designerActionManager(); ->viewManager().designerActionManager();
QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); QHash<QString, QStringList> 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); const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString);
for (const QString &imgPath : addedImages) { for (const QString &imgPath : addedImages) {
QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {}, QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {},
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode()); 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 } // namespace QmlDesigner

View File

@@ -46,8 +46,7 @@ ComponentView::ComponentView(QObject *parent)
void ComponentView::nodeAboutToBeRemoved(const ModelNode &removedNode) void ComponentView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{ {
removeSingleNodeFromList(removedNode); removeFromListRecursive(removedNode);
searchForComponentAndRemoveFromList(removedNode);
} }
QStandardItemModel *ComponentView::standardItemModel() const QStandardItemModel *ComponentView::standardItemModel() const
@@ -75,7 +74,7 @@ void ComponentView::setComponentToMaster()
m_componentAction->setCurrentIndex(indexOfMaster()); 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++) { for (int row = 0; row < m_standardItemModel->rowCount(); row++) {
if (m_standardItemModel->item(row)->data(ModelNodeRole).toInt() == node.internalId()) 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 int ComponentView::indexForNode(const ModelNode &node) const
{ {
for (int row = 0; row < m_standardItemModel->rowCount(); row++) { for (int row = 0; row < m_standardItemModel->rowCount(); row++) {
@@ -112,7 +123,7 @@ bool ComponentView::hasEntryForNode(const ModelNode &node) const
return indexForNode(node) >= 0; return indexForNode(node) >= 0;
} }
void ComponentView::addMasterDocument() void ComponentView::ensureMasterDocument()
{ {
if (!hasMasterEntry()) { if (!hasMasterEntry()) {
QStandardItem *item = new QStandardItem(QLatin1String("master")); 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 QString ComponentView::descriptionForNode(const ModelNode &node) const
@@ -155,6 +168,15 @@ void ComponentView::updateDescription(const ModelNode &node)
m_standardItemModel->item(nodeIndex)->setText(descriptionForNode(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) void ComponentView::modelAttached(Model *model)
{ {
if (AbstractView::model() == model) if (AbstractView::model() == model)
@@ -187,46 +209,25 @@ void ComponentView::nodeCreated(const ModelNode &createdNode)
void ComponentView::searchForComponentAndAddToList(const ModelNode &node) void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
{ {
bool masterNotAdded = true; const auto nodeList = node.allSubModelNodesAndThisNode();
bool hasMaster = false;
foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) { for (const ModelNode &childNode : nodeList) {
if (node.nodeSourceType() == ModelNode::NodeWithComponentSource if (isSubComponentNode(childNode)) {
|| (node.hasParentProperty() if (!hasMaster) {
&& !node.parentProperty().isDefaultProperty() hasMaster = true;
&& node.metaInfo().isValid() ensureMasterDocument();
&& 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);
} }
addNodeToList(childNode);
} }
} }
} }
void ComponentView::searchForComponentAndRemoveFromList(const ModelNode &node) void ComponentView::removeFromListRecursive(const ModelNode &node)
{ {
QList<ModelNode> nodeList; const auto nodeList = node.allSubModelNodesAndThisNode();
nodeList.append(node); for (const ModelNode &childNode : std::as_const(nodeList))
nodeList.append(node.allSubModelNodes()); removeNodeFromList(childNode);
maybeRemoveMasterDocument();
foreach (const ModelNode &childNode, nodeList) {
if (childNode.nodeSourceType() == ModelNode::NodeWithComponentSource)
removeSingleNodeFromList(childNode);
}
if (m_standardItemModel->rowCount() == 1)
removeMasterDocument();
} }
void ComponentView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) 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); 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 } // namespace QmlDesigner

View File

@@ -62,6 +62,7 @@ public:
const NodeAbstractProperty &oldPropertyParent, const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override; AbstractView::PropertyChangeFlags propertyChange) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) 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; QStandardItemModel *standardItemModel() const;
@@ -76,16 +77,18 @@ signals:
private: //functions private: //functions
void updateModel(); void updateModel();
void searchForComponentAndAddToList(const ModelNode &node); void searchForComponentAndAddToList(const ModelNode &node);
void searchForComponentAndRemoveFromList(const ModelNode &node); void removeFromListRecursive(const ModelNode &node);
void removeSingleNodeFromList(const ModelNode &node); void removeNodeFromList(const ModelNode &node);
void addNodeToList(const ModelNode &node);
int indexForNode(const ModelNode &node) const; int indexForNode(const ModelNode &node) const;
int indexOfMaster() const; int indexOfMaster() const;
bool hasMasterEntry() const; bool hasMasterEntry() const;
bool hasEntryForNode(const ModelNode &node) const; bool hasEntryForNode(const ModelNode &node) const;
void addMasterDocument(); void ensureMasterDocument();
void removeMasterDocument(); void maybeRemoveMasterDocument();
QString descriptionForNode(const ModelNode &node) const; QString descriptionForNode(const ModelNode &node) const;
void updateDescription(const ModelNode &node); void updateDescription(const ModelNode &node);
bool isSubComponentNode(const ModelNode &node) const;
private: private:
QStandardItemModel *m_standardItemModel; QStandardItemModel *m_standardItemModel;

View File

@@ -36,6 +36,7 @@
#include <QMultiHash> #include <QMultiHash>
#include <QPointer> #include <QPointer>
#include <QFileInfo> #include <QFileInfo>
#include <QDir>
namespace QmlDesigner { namespace QmlDesigner {
@@ -69,6 +70,7 @@ private: // functions
void parseQuick3DAssetsDir(const QString &quick3DAssetsPath); void parseQuick3DAssetsDir(const QString &quick3DAssetsPath);
void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {}); void parseQuick3DAssetsItem(const QString &importUrl, const QString &quick3DAssetsPath = {});
QStringList quick3DAssetPaths() const; QStringList quick3DAssetPaths() const;
TypeName resolveDirQualifier(const QString &dirPath) const;
private: // variables private: // variables
QFileSystemWatcher m_watcher; QFileSystemWatcher m_watcher;
@@ -76,6 +78,7 @@ private: // variables
// key: canonical directory path // key: canonical directory path
QMultiHash<QString,QString> m_dirToQualifier; QMultiHash<QString,QString> m_dirToQualifier;
QUrl m_filePath; QUrl m_filePath;
QDir m_filePathDir;
QPointer<Model> m_model; QPointer<Model> m_model;
}; };

View File

@@ -134,8 +134,11 @@ void SubComponentManager::parseDirectories()
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir())
parseDirectory(canonicalPath); parseDirectory(canonicalPath);
foreach (const QString &subDir, QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { const QStringList subDirs = QDir(QFileInfo(file).path()).entryList(QDir::Dirs | QDir::NoDot
parseDirectory(canonicalPath + QLatin1Char('/') + subDir, true, subDir.toUtf8()); | 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) { foreach (const Import &import, m_imports) {
if (import.isFileImport()) { if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir()) {
parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); const QString canPath = dirInfo.canonicalFilePath();
parseDirectory(canPath, true, resolveDirQualifier(canPath));
}
} else { } else {
QString url = import.url(); QString url = import.url();
url.replace(QLatin1Char('.'), QLatin1Char('/')); url.replace(QLatin1Char('.'), QLatin1Char('/'));
@@ -445,6 +450,11 @@ QStringList SubComponentManager::quick3DAssetPaths() const
return retPaths; return retPaths;
} }
TypeName SubComponentManager::resolveDirQualifier(const QString &dirPath) const
{
return m_filePathDir.relativeFilePath(dirPath).toUtf8();
}
/*! /*!
\class SubComponentManager \class SubComponentManager
@@ -472,10 +482,12 @@ void SubComponentManager::update(const QUrl &filePath, const QList<Import> &impo
if (!m_filePath.isEmpty()) { if (!m_filePath.isEmpty()) {
const QString file = m_filePath.toLocalFile(); const QString file = m_filePath.toLocalFile();
oldDir = QFileInfo(QFileInfo(file).path()); oldDir = QFileInfo(QFileInfo(file).path());
m_filePathDir = QDir();
} }
if (!filePath.isEmpty()) { if (!filePath.isEmpty()) {
const QString file = filePath.toLocalFile(); const QString file = filePath.toLocalFile();
newDir = QFileInfo(QFileInfo(file).path()); newDir = QFileInfo(QFileInfo(file).path());
m_filePathDir = {newDir.absoluteFilePath()};
} }
m_filePath = filePath; m_filePath = filePath;
@@ -538,8 +550,10 @@ void SubComponentManager::updateImport(const Import &import)
if (import.isFileImport()) { if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile()); QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
if (dirInfo.exists() && dirInfo.isDir()) if (dirInfo.exists() && dirInfo.isDir()) {
parseDirectory(dirInfo.canonicalFilePath(), true, dirInfo.baseName().toUtf8()); const QString canPath = dirInfo.canonicalFilePath();
parseDirectory(canPath, true, resolveDirQualifier(canPath));
}
} else { } else {
QString url = import.url(); QString url = import.url();

View File

@@ -914,16 +914,30 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
usedImportsSet.insert(i.info.path()); usedImportsSet.insert(i.info.path());
QList<QmlDesigner::Import> possibleImports; QList<QmlDesigner::Import> possibleImports;
const QStringList qmlList("*.qml");
const QStringList qmldirList("qmldir");
foreach (const QString &subDir, QDir(path).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot)) { QStringList fileImportPaths;
QDir dir(path + "/" + subDir); const QChar delimeter('/');
if (!dir.entryInfoList(QStringList("*.qml"), QDir::Files).isEmpty()
&& dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty() std::function<void(const QString &)> checkDir;
&& !usedImportsSet.contains(dir.path())) { checkDir = [&](const QString &checkPath) {
QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir); 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); possibleImports.append(import);
} }
checkDir(dirPath);
} }
};
checkDir(path);
return possibleImports; return possibleImports;
} }
@@ -931,17 +945,44 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
static QList<QmlDesigner::Import> generatePossibleLibraryImports(const QHash<QString, ImportKey> &filteredPossibleImportKeys) static QList<QmlDesigner::Import> generatePossibleLibraryImports(const QHash<QString, ImportKey> &filteredPossibleImportKeys)
{ {
QList<QmlDesigner::Import> possibleImports; QList<QmlDesigner::Import> possibleImports;
QSet<QString> 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('.')); QString libraryName = importKey.splitPath.join(QLatin1Char('.'));
int majorVersion = importKey.majorVersion; int majorVersion = importKey.majorVersion;
if (majorVersion >= 0) { if (majorVersion >= 0) {
int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion; int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion;
QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion); QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion);
possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version)); 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; return possibleImports;
} }
@@ -2111,7 +2152,7 @@ void TextToModelMerger::collectLinkErrors(QList<DocumentMessage> *errors, const
void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors) void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
{ {
if (m_rewriterView->model()->imports().isEmpty()) { 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()))); errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName())));
} }
@@ -2137,7 +2178,7 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
SourceLocation(0, 0, 0, 0), SourceLocation(0, 0, 0, 0),
QCoreApplication::translate( QCoreApplication::translate(
"QmlDesigner::TextToModelMerger", "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( errors->prepend(
DocumentMessage(diagnosticMessage, DocumentMessage(diagnosticMessage,
QUrl::fromLocalFile(m_document->fileName()))); QUrl::fromLocalFile(m_document->fileName())));
@@ -2161,7 +2202,7 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
diagnosticMessage(QmlJS::Severity::Error, diagnosticMessage(QmlJS::Severity::Error,
SourceLocation(0, 0, 0, 0), SourceLocation(0, 0, 0, 0),
QCoreApplication::translate("QmlDesigner::TextToModelMerger", QCoreApplication::translate("QmlDesigner::TextToModelMerger",
"Unsupported QtQuick version")); "Unsupported Qt Quick version."));
errors->append(DocumentMessage(diagnosticMessage, errors->append(DocumentMessage(diagnosticMessage,
QUrl::fromLocalFile(m_document->fileName()))); QUrl::fromLocalFile(m_document->fileName())));
} }

View File

@@ -30,9 +30,11 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h> #include <projectexplorer/project.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <qmlprojectmanager/qmlprojectmanagerconstants.h> #include <qmlprojectmanager/qmlprojectmanagerconstants.h>
#include <qmlprojectmanager/qmlmainfileaspect.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
@@ -44,21 +46,15 @@
using namespace Utils; using namespace Utils;
namespace QmlDesigner { namespace QmlDesigner {
namespace GenerateCmakeLists {
const QDir::Filters FILES_ONLY = QDir::Files; namespace GenerateCmake {
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const char CMAKEFILENAME[] = "CMakeLists.txt";
const char QMLDIRFILENAME[] = "qmldir";
void generateMenuEntry() void generateMenuEntry()
{ {
Core::ActionContainer *buildMenu = Core::ActionContainer *buildMenu =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT); Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
const Core::Context projectCntext(QmlProjectManager::Constants::QML_PROJECT_ID);
auto action = new QAction("Generate CMakeLists.txt files"); 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"); Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists");
buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN); buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN);
@@ -71,9 +67,33 @@ void generateMenuEntry()
void onGenerateCmakeLists() 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 processDirectory(const FilePath &dir)
{ {
QStringList moduleNames; 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 generateModuleCmake(const FilePath &dir)
{ {
QString fileContent; QString fileContent;
const QStringList qmlFilesOnly("*.qml");
const QStringList qmldirFilesOnly(QMLDIRFILENAME); const QStringList qmldirFilesOnly(QMLDIRFILENAME);
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY); FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY);
if (!qmldirFileList.isEmpty()) { 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; QString qmlFiles;
for (FilePath &qmlFile : qmlFileList) { for (QString &qmlFile : qmlFileList)
if (project->isKnownFile(qmlFile)) qmlFiles.append(QString("\t\t%1\n").arg(qmlFile));
qmlFiles.append(QString("\t\t%1\n").arg(qmlFile.fileName()));
}
QStringList resourceFileList = getDirectoryTreeResources(dir); QStringList resourceFileList = getDirectoryTreeResources(dir);
QString resourceFiles; QString resourceFiles;
for (QString &resourceFile : resourceFileList) { for (QString &resourceFile : resourceFileList)
resourceFiles.append(QString("\t\t%1\n").arg(resourceFile)); resourceFiles.append(QString("\t\t%1\n").arg(resourceFile));
}
QString moduleContent; QString moduleContent;
if (!qmlFiles.isEmpty()) { if (!qmlFiles.isEmpty()) {
@@ -226,6 +241,31 @@ QStringList getSingletonsFromQmldirFile(const FilePath &filePath)
return singletons; 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) QStringList getDirectoryTreeResources(const FilePath &dir)
{ {
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
@@ -255,11 +295,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
void createCmakeFile(const FilePath &dir, const QString &content) void createCmakeFile(const FilePath &dir, const QString &content)
{ {
FilePath filePath = dir.pathAppended(CMAKEFILENAME); FilePath filePath = dir.pathAppended(CMAKEFILENAME);
QFile cmakeFile(filePath.toString()); GenerateCmake::writeFile(filePath, content);
cmakeFile.open(QIODevice::WriteOnly);
QTextStream stream(&cmakeFile);
stream << content;
cmakeFile.close();
} }
bool isFileBlacklisted(const QString &fileName) 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<QmlProjectManager::QmlMainFileAspect>())
mainClass = FilePath::fromString(aspect->mainScript()).baseName();
return GenerateCmake::writeFile(filePath, QString(MAIN_QMLFILE_CONTENT).arg(projectName).arg(mainClass));
}
}
}

View File

@@ -30,16 +30,25 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
namespace QmlDesigner { namespace QmlDesigner {
namespace GenerateCmakeLists { namespace GenerateCmake {
void generateMenuEntry(); void generateMenuEntry();
void onGenerateCmakeLists(); void onGenerateCmakeLists();
bool writeFile(const Utils::FilePath &filePath, const QString &fileContent);
}
namespace GenerateCmakeLists {
void generateMainCmake(const Utils::FilePath &rootDir); void generateMainCmake(const Utils::FilePath &rootDir);
void generateSubdirCmake(const Utils::FilePath &dir); void generateSubdirCmake(const Utils::FilePath &dir);
QString generateModuleCmake(const Utils::FilePath &dir); QString generateModuleCmake(const Utils::FilePath &dir);
QStringList processDirectory(const Utils::FilePath &dir); QStringList processDirectory(const Utils::FilePath &dir);
QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath); QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath);
QStringList getDirectoryTreeQmls(const Utils::FilePath &dir);
QStringList getDirectoryTreeResources(const Utils::FilePath &dir); QStringList getDirectoryTreeResources(const Utils::FilePath &dir);
void createCmakeFile(const Utils::FilePath &filePath, const QString &content); void createCmakeFile(const Utils::FilePath &filePath, const QString &content);
bool isFileBlacklisted(const QString &fileName); 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);
}
} }

View File

@@ -223,7 +223,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool()) if (DesignerSettings::getValue(DesignerSettingsKey::STANDALONE_MODE).toBool())
GenerateResource::generateMenuEntry(); GenerateResource::generateMenuEntry();
GenerateCmakeLists::generateMenuEntry(); GenerateCmake::generateMenuEntry();
const QString fontPath const QString fontPath
= Core::ICore::resourcePath( = Core::ICore::resourcePath(

View File

@@ -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 <QGuiApplication>
#include <QQmlApplicationEngine>
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();
}

View File

@@ -83,7 +83,7 @@ static void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &proje
if (projectInfo.project) if (projectInfo.project)
activeTarget = projectInfo.project->activeTarget(); activeTarget = projectInfo.project->activeTarget();
Kit *activeKit = activeTarget ? activeTarget->kit() : KitManager::defaultKit(); Kit *activeKit = activeTarget ? activeTarget->kit() : KitManager::defaultKit();
const QHash<QString, QString> replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath}}; const QHash<QString, QString> replacements = {{QLatin1String("$(QT_INSTALL_QML)"), projectInfo.qtQmlPath.toString()}};
for (IBundleProvider *bp : IBundleProvider::allBundleProviders()) for (IBundleProvider *bp : IBundleProvider::allBundleProviders())
bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements); bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements);
@@ -146,17 +146,17 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
} }
if (qtVersion && qtVersion->isValid()) { if (qtVersion && qtVersion->isValid()) {
projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT); projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT);
projectInfo.qtQmlPath = qtVersion->qmlPath().toFileInfo().canonicalFilePath(); projectInfo.qtQmlPath = qtVersion->qmlPath();
projectInfo.qtVersionString = qtVersion->qtVersionString(); projectInfo.qtVersionString = qtVersion->qtVersionString();
} else if (!activeKit || !activeKit->value(QtSupport::SuppliesQtQuickImportPath::id(), false).toBool()) { } 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.qtVersionString = QLatin1String(qVersion());
} }
projectInfo.qmlDumpPath.clear(); projectInfo.qmlDumpPath.clear();
const QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(activeKit); const QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(activeKit);
if (version && projectInfo.tryQmlDump) { if (version && projectInfo.tryQmlDump) {
projectInfo.qmlDumpPath = version->qmlplugindumpFilePath().toString(); projectInfo.qmlDumpPath = version->qmlplugindumpFilePath();
projectInfo.qmlDumpHasRelocatableFlag = version->hasQmlDumpWithRelocatableFlag(); projectInfo.qmlDumpHasRelocatableFlag = version->hasQmlDumpWithRelocatableFlag();
} }

View File

@@ -502,6 +502,7 @@ public:
void duplicateSelection(bool comment); void duplicateSelection(bool comment);
void updateCannotDecodeInfo(); void updateCannotDecodeInfo();
void collectToCircularClipboard(); void collectToCircularClipboard();
void setClipboardSelection();
void ctor(const QSharedPointer<TextDocument> &doc); void ctor(const QSharedPointer<TextDocument> &doc);
void handleHomeKey(bool anchor, bool block); void handleHomeKey(bool anchor, bool block);
@@ -5217,7 +5218,8 @@ void TextEditorWidget::mousePressEvent(QMouseEvent *e)
void TextEditorWidget::mouseReleaseEvent(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(); EditorManager::addCurrentPositionToNavigationHistory();
bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit()) bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit())
|| (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier)); || (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier));
@@ -5227,12 +5229,22 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
if (self && self->openLink(symbolLink, inNextSplit)) if (self && self->openLink(symbolLink, inNextSplit))
self->d->clearLink(); self->d->clearLink();
}, true, inNextSplit); }, 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)) if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
return; return;
QPlainTextEdit::mouseReleaseEvent(e); QPlainTextEdit::mouseReleaseEvent(e);
d->setClipboardSelection();
} }
void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e) void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
@@ -5247,6 +5259,14 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
} }
QPlainTextEdit::mouseDoubleClickEvent(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) void TextEditorWidget::leaveEvent(QEvent *e)

View File

@@ -267,7 +267,7 @@ void tst_ImportCheck::importTypes()
// the default qtQmlPath is based on the Qt version in use otherwise // the default qtQmlPath is based on the Qt version in use otherwise
ModelManagerInterface::ProjectInfo defaultProject; ModelManagerInterface::ProjectInfo defaultProject;
defaultProject.qtQmlPath = importPath; defaultProject.qtQmlPath = Utils::FilePath::fromString(importPath);
modelManager->setDefaultProject(defaultProject, nullptr); modelManager->setDefaultProject(defaultProject, nullptr);
modelManager->activateScan(); modelManager->activateScan();