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

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 <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
const QUrl url(u"qrc:/accelbubble/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)

View File

@@ -1,74 +1,71 @@
import QtQuick 2.14
import QtQuick.Window 2.14
import QtSensors 5.12
import QtQuick
import QtSensors
Window {
id: window
id: mainWindow
width: 320
height: 480
visible: true
property alias mainWindow: mainWindow
property alias bubble: bubble
Rectangle {
id: mainWindow
color: "#ffffff"
anchors.fill: parent
title: qsTr("Accelerate Bubble")
readonly property double radians_to_degrees: 180 / Math.PI
Bubble {
id: bubble
x: bubble.centerX - bubbleCenter
y: bubble.centerY - bubbleCenter
bubbleCenter: bubble.width /2
centerX: mainWindow.width /2
centerY: mainWindow.height /2
Accelerometer {
id: accel
dataRate: 100
active:true
Behavior on y {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
Behavior on x {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
onReadingChanged: {
var newX = (bubble.x + calcRoll(accel.reading.x, accel.reading.y, accel.reading.z) * .1)
var newY = (bubble.y - calcPitch(accel.reading.x, accel.reading.y, accel.reading.z) * .1)
if (isNaN(newX) || isNaN(newY))
return;
if (newX < 0)
newX = 0
if (newX > mainWindow.width - bubble.width)
newX = mainWindow.width - bubble.width
if (newY < 18)
newY = 18
if (newY > mainWindow.height - bubble.height)
newY = mainWindow.height - bubble.height
bubble.x = newX
bubble.y = newY
}
}
Accelerometer {
id: accel
dataRate: 100
active: true
readonly property double radians_to_degrees: 180 / Math.PI
onReadingChanged: {
var newX = (bubble.x + calcRoll(accel.reading.x, accel.reading.y, accel.reading.z) * 0.1)
var newY = (bubble.y - calcPitch(accel.reading.x, accel.reading.y, accel.reading.z) * 0.1)
if (isNaN(newX) || isNaN(newY))
return;
if (newX < 0)
newX = 0
if (newX > mainWindow.width - bubble.width)
newX = mainWindow.width - bubble.width
if (newY < 18)
newY = 18
if (newY > mainWindow.height - bubble.height)
newY = mainWindow.height - bubble.height
bubble.x = newX
bubble.y = newY
}
}
function calcPitch(x,y,z) {
return -Math.atan2(y, Math.hypot(x, z)) * accel.radians_to_degrees;
return -Math.atan2(y, Math.hypot(x, z)) * mainWindow.radians_to_degrees;
}
function calcRoll(x,y,z) {
return -Math.atan2(x, Math.hypot(y, z)) * accel.radians_to_degrees;
return -Math.atan2(x, Math.hypot(y, z)) * mainWindow.radians_to_degrees;
}
Image {
id: bubble
source: "Bluebubble.svg"
smooth: true
property real centerX: mainWindow.width / 2
property real centerY: mainWindow.height / 2
property real bubbleCenter: bubble.width / 2
x: centerX - bubbleCenter
y: centerY - bubbleCenter
Behavior on y {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
Behavior on x {
SmoothedAnimation {
easing.type: Easing.Linear
duration: 100
}
}
}
}

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
This tutorial describes developing Qt Quick applications for Android and iOS
devices using Qt Quick Controls.
We use \QC to implement a Qt Quick application
that accelerates an SVG (Scalable Vector Graphics) image based on the
changing accelerometer values.
This tutorial describes how to use \QC to develop Qt Quick applications for
Android and iOS devices when using Qt 6 as the minimum Qt version and CMake
as the build system.
We implement a Qt Quick application that accelerates an SVG (Scalable Vector
Graphics) image based on the changing accelerometer values.
\note You must have the \l{Qt Sensors} module from Qt 6.2 or later installed
to be able to follow this tutorial.
\image creator_android_tutorial_ex_app.png
For more information about the UI choices you have, see \l{User Interfaces}.
\section1 Setting up the Development Environment
To be able to build the application for and run it on a mobile device, you must
To build the application for and run it on a mobile device, you must
set up the development environment for the device platform and configure a
connection between \QC and the mobile device.
@@ -63,183 +65,78 @@
\include qtquick-tutorial-create-empty-project.qdocinc qtquick empty application
\section1 Creating the Accelbubble Main View
\section1 Adding Images as Resources
The main view of the application displays an SVG bubble image that moves
around the screen when you tilt the device.
We use \e {Bluebubble.svg} in this tutorial, but you can use any other
image or component, instead.
image or component instead.
To create the UI in \l{Form Editor}:
For the image to appear when you run the application, you must specify it
as a resource in the \c RESOURCES section of \e CMakeLists.txt file that
the wizard created for you:
\list 1
\quotefromfile accelbubble/CMakeLists.txt
\skipto qt_add_qml_module
\printuntil )
\li Open the \e main.qml in \uicontrol {Form Editor}.
\section1 Creating the Accelbubble Main View
\li In \l Library > \uicontrol Components >
\uicontrol {Default Components} > \uicontrol Basic, select
\uicontrol Rectangle and drag-and-drop it to \e Window
in \l Navigator.
We create the main view in the \e main.qml file by adding an \l Image
component with \e Bluebubble.svg as the source:
\li Select the rectangle instance in \uicontrol Navigator to edit its
properties in \l Properties:
\quotefromfile accelbubble/main.qml
\skipto Image
\printuntil smooth
\image qtquick-mobile-app-tutorial-main-view.png "Rectangle in different views"
Next, we add custom properties to position the image in respect to the width
and height of the main window:
\list a
\li In the \uicontrol ID field enter \e mainWindow, to be able
to reference the rectangle from other places.
\li Select the \uicontrol Layout tab, and then click
the \inlineimage icons/anchor-fill.png
(\uicontrol {Fill to Parent}) button to anchor the rectangle
to the window.
\endlist
\li Select \uicontrol Library > \uicontrol Assets >
\inlineimage plus.png
to locate Bluebubble.svg (or your own image) and add it to
the project folder.
\li Drag and drop the image from \uicontrol Assets to
\e mainWindow in \uicontrol Navigator. \QC creates an
instance of an \l{Images}{Image} component for you
with the path to the image file set as the value of
the \uicontrol Source field in \uicontrol Properties.
\li In the \uicontrol Properties view, \uicontrol ID field, enter
\e bubble to be able to reference the image from other places.
\image qtquick-mobile-app-tutorial-image.png "Image file in different views"
\li Select the \inlineimage icons/alias.png
(\uicontrol Export) button in \uicontrol Navigator to export
\e mainWindow and \e bubble as properties.
\endlist
We want to modify the properties of the bubble in ways that are not
supported in \uicontrol {Form Editor}, and therefore we turn it into
a custom component:
\list 1
\li Right-click the image and select
\uicontrol {Move Component into Separate File}.
\image qtquick-mobile-app-tutorial-bubble-component.png
\li In the \uicontrol {Component name} field, enter \e Bubble.
\li Deselect the \uicontrol x and \uicontrol y check boxes,
because we want to use the accelerometer to determine
the location of the bubble on the screen.
\li Select \uicontrol OK to create \e Bubble.qml.
\endlist
\QC creates an instance of the Bubble component in \e main.qml.
To check your code, you can compare your \e main.qml and
\e {Bubble.qml} with the corresponding example files.
The UI is now ready and you can add the necessary properties for
making the bubble move.
\section1 Moving the Bubble
We add custom properties to position the image in respect to the width
and height of the main window.
\list 1
\li Open \e Bubble.qml in \uicontrol {Form Editor}.
\li In \l {Connection View} > \uicontrol Properties,
select the \inlineimage plus.png
button to add a custom property for the Bubble component.
\image qtquick-mobile-app-tutorial-custom-properties.png "Connection View Properties tab"
\li Double-click the value in the \uicontrol Property column, and enter
\e centerY as the name of the property.
\li Double-click the value in the \uicontrol {Property Type} column,
and select \e real as the component of the property. You will specify
the property value later in \uicontrol Properties.
\li Add two more properties of the same type with the names \e centerY
and \e bubbleCenter.
\li Open \e main.qml in \uicontrol {Form Editor}.
\li Select \e bubble in \uicontrol Navigator to specify values for the
custom properties in \uicontrol Properties.
\li In the \uicontrol X field, select \inlineimage icons/action-icon.png
, and then select \uicontrol {Set Binding} to open
\uicontrol {Binding Editor}.
\image qtquick-mobile-app-tutorial-binding-editor1.png "Setting binding for X in Binding Editor"
\li Enter the following value to center the bubble horizontally in the
main window when the application starts:
\c{bubble.centerX - bubbleCenter}.
\li Select \uicontrol OK to close the binding editor and save the
binding.
\li In the \uicontrol X field, set the following binding to center the
bubble vertically: \c{bubble.centerY - bubbleCenter}.
\li In the \uicontrol centerY field, enter the following value to bind
the y coordinate of the bubble center to half the height of the main
window: \c {mainWindow.height /2}.
\image qtquick-mobile-app-tutorial-binding-editor.png "Setting binding for centerX"
\li In the \uicontrol centerX field, bind the x coordinate of
the bubble center to half the width of the main window:
\c {mainWindow.width /2}.
\li In the \uicontrol bubbleCenter field, bind the center of
the bubble to half of its width: \c {bubble.width /2}.
\endlist
\printuntil y:
We now want to add code to move the bubble based on Accelerometer sensor
values. This is not supported by \l {Form Editor}, so we will do
it in \l {Text Editor}:
values. First, we add the following import statement:
\list 1
\li Add the following import statement to \e main.qml:
\quotefromfile accelbubble/main.qml
\skipto QtSensors
\printline QtSensors
\quotefromfile accelbubble/main.qml
\skipto QtSensors
\printline QtSensors
Next, we add the \l{Accelerometer} component with the necessary properties:
\li Add the \l{Accelerometer} component with the necessary properties:
\skipto Accelerometer
\printuntil active
\skipto Accelerometer
\printuntil radians_to_degrees
\skipto }
\printuntil }
Then, we add the following JavaScript functions that calculate the
x and y position of the bubble based on the current Accelerometer
values:
\li Add the following JavaScript functions that calculate the
x and y position of the bubble based on the current Accelerometer
values:
\quotefromfile accelbubble/main.qml
\skipto function
\printuntil }
\printuntil }
\quotefromfile accelbubble/main.qml
\skipto function
\printuntil Math.atan2(x
\printuntil }
We add the following JavaScript code for \c onReadingChanged signal of
Accelerometer component to make the bubble move when the Accelerometer
values change:
\li Add the following JavaScript code for \c onReadingChanged signal of
Accelerometer component to make the bubble move when the Accelerometer
values change:
\quotefromfile accelbubble/main.qml
\skipto onReadingChanged
\printuntil }
\quotefromfile accelbubble/main.qml
\skipto onReadingChanged
\printuntil }
We want to ensure that the position of the bubble is always
within the bounds of the screen. If the Accelerometer returns
\e {not a number} (NaN), the value is ignored and the bubble
position is not updated.
We want to ensure that the position of the bubble is always
within the bounds of the screen. If the Accelerometer returns
\e {not a number} (NaN), the value is ignored and the bubble
position is not updated.
\li Add \l SmoothedAnimation behavior on the \c x and \c y properties of
the bubble to make its movement look smoother.
We add \l SmoothedAnimation behavior on the \c x and \c y properties of
the bubble to make its movement look smoother.
\quotefromfile accelbubble/main.qml
\skipto Behavior
\printuntil x
\printuntil }
\printuntil }
\endlist
\quotefromfile accelbubble/main.qml
\skipto Behavior
\printuntil x
\printuntil }
\printuntil }
\section1 Locking Device Orientation
@@ -248,35 +145,69 @@
better for the screen orientation to be fixed.
To lock the orientation to portrait or landscape on Android, specify it in
an AndroidManifest.xml that you can generate in \QC. For more information,
an \e AndroidManifest.xml that you can generate in \QC. For more information,
see \l{Editing Manifest Files}.
On iOS, you can lock the device orientation in an Info.plist file that you
specify in the .pro file as the value of the QMAKE_INFO_PLIST variable.
\image qtquick-mobile-tutorial-manifest.png "Accelbubble manifest file"
To generate and use a manifest file, you must specify the Android package
source directory, \c QT_ANDROID_PACKAGE_SOURCE_DIR in the \e CMakeLists.txt
file:
\quotefromfile accelbubble/CMakeLists.txt
\skipto set_property
\printuntil )
Because our CMake version is older than 3.19, we must add a manual
finalization step to the \c qt_add_executable function:
\quotefromfile accelbubble/CMakeLists.txt
\skipto qt_add_executable
\printuntil )
We also need to add the \c qt_finalize_executable function:
\skipto qt_finalize_executable
\printuntil )
On iOS, you can lock the device orientation in an \e Info.plist file
that you specify in the \e CMakeLists.txt file as the value of the
\c MACOSX_BUNDLE_INFO_PLIST variable:
\quotefromfile accelbubble/CMakeLists.txt
\skipto set_target_properties
\printuntil )
\section1 Adding Dependencies
Update the accelbubble.pro file with the following library dependency
information:
You must tell the build system which Qt modules your application needs by
specifying dependencies in the project file. Select \uicontrol Projects to
update the CMake configuration with the following Qt module information:
\c Sensors, \c Svg, \c Xml.
\code
QT += quick sensors svg xml
\endcode
The \e CMakeLists.txt file should contain the following entries that tell
CMake to look up the Qt installation and import the Qt Sensors, Qt SVG,
and Qt XML modules needed by the application:
On iOS, you must link to the above libraries statically, by adding the
plugin names explicitly as values of the QTPLUGIN variable. Specify a
qmake scope for iOS builds (which can also contain the QMAKE_INFO_PLIST
variable):
\quotefromfile accelbubble/CMakeLists.txt
\skipto find_package
\printuntil REQUIRED
\code
ios {
QTPLUGIN += qsvg qsvgicon qtsensors_ios
QMAKE_INFO_PLIST = Info.plist
}
\endcode
You also need to add the Qt modules to the list of target link libraries.
\c target_link_libraries tells CMake that the accelbubble executable uses
the Qt Sensors, Qt SVG, and Qt XML modules by referencing the targets
imported by the \c find_package() call above. This adds the necessary
arguments to the linker and makes sure that the appropriate include
directories and compiler definitions are passed to the C++ compiler.
After adding the dependencies, select \uicontrol Build > \uicontrol {Run qmake} to apply
the changes to the Makefile of the project.
\skipto target_link_libraries(accelbubble
\printuntil Qt6
After adding the dependencies, select \uicontrol Build >
\uicontrol {Run CMake} to apply configuration changes.
For more information about the CMakeLists.txt file, see
\l{Get started with CMake}.
\section1 Running the Application
@@ -292,7 +223,7 @@
If you are using a device running Android v4.2.2, it should prompt you to
verify the connection to allow USB debugging from the PC it is connected
to. To avoid such prompts every time you connect the device, select the
\uicontrol {Always allow from the computer} check box, and then select
\uicontrol {Always allow from this computer} check box, and then select
\uicontrol OK.
\li To run the application on the device, press \key {Ctrl+R}.

View File

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

View File

@@ -33,7 +33,9 @@ import StudioTheme 1.0 as StudioTheme
PropertyEditorPane {
id: itemPane
ComponentSection {}
ComponentSection {
showState: true
}
GeometrySection {}
@@ -82,22 +84,6 @@ PropertyEditorPane {
ExpandingSpacer {}
}
PropertyLabel { text: qsTr("State") }
SecondColumnLayout {
ComboBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
editable: true
backendValue: backendValues.state
model: allStateNames
valueType: ComboBox.String
}
ExpandingSpacer {}
}
}
}

View File

@@ -41,7 +41,7 @@ Rectangle {
anchors.fill: parent
Controls.Label {
text: qsTr("Select an Item in the Form Editor, Navigator or Text Edit View to see its properties.")
text: qsTr("Select a component in Form Editor, Navigator, or Text Editor to see its properties.")
font.pixelSize: StudioTheme.Values.myFontSize * 1.5
color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap

View File

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

View File

@@ -787,7 +787,9 @@ SecondColumnLayout {
ControlLabel {
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
Section {
id: root
caption: qsTr("Component")
anchors.left: parent.left
anchors.right: parent.right
property bool showState: false
SectionLayout {
PropertyLabel { text: qsTr("Type") }
@@ -262,5 +265,26 @@ Section {
onCanceled: hideWidget()
}
}
PropertyLabel {
visible: root.showState
text: qsTr("State")
}
SecondColumnLayout {
visible: root.showState
ComboBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
editable: true
backendValue: backendValues.state
model: allStateNames
valueType: ComboBox.String
}
ExpandingSpacer {}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -67,6 +67,28 @@ void setThemeApplicationPalette()
QApplication::setPalette(m_creatorTheme->palette());
}
static void maybeForceMacOSLight(Theme *theme)
{
#ifdef Q_OS_MACOS
// Match the native UI theme and palette with the creator
// theme by forcing light aqua for light creator themes.
if (theme && !theme->flag(Theme::DarkUserInterface))
Internal::forceMacOSLightAquaApperance();
#else
Q_UNUSED(theme)
#endif
}
static bool macOSSystemIsDark()
{
#ifdef Q_OS_MACOS
static bool systemIsDark = Internal::currentAppearanceIsDark();
return systemIsDark;
#else
return false;
#endif
}
void setCreatorTheme(Theme *theme)
{
if (m_creatorTheme == theme)
@@ -74,13 +96,7 @@ void setCreatorTheme(Theme *theme)
delete m_creatorTheme;
m_creatorTheme = theme;
#ifdef Q_OS_MACOS
// Match the native UI theme and palette with the creator
// theme by forcing light aqua for light creator themes.
if (theme && !theme->flag(Theme::DarkUserInterface))
Internal::forceMacOSLightAquaApperance();
#endif
maybeForceMacOSLight(theme);
setThemeApplicationPalette();
}
@@ -251,6 +267,8 @@ bool Theme::systemUsesDarkMode()
bool ok;
const auto setting = QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok);
return ok && setting == 0;
} else if (HostOsInfo::isMacHost()) {
return macOSSystemIsDark();
}
return false;
}
@@ -270,6 +288,13 @@ static QPalette copyPalette(const QPalette &p)
return res;
}
void Theme::setInitialPalette(Theme *initTheme)
{
macOSSystemIsDark(); // initialize value for system mode
maybeForceMacOSLight(initTheme);
initialPalette();
}
QPalette Theme::initialPalette()
{
static QPalette palette = copyPalette(QApplication::palette());

View File

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

View File

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

View File

@@ -49,5 +49,17 @@ void forceMacOSLightAquaApperance()
NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
}
bool currentAppearanceIsDark()
{
#if __has_builtin(__builtin_available)
if (__builtin_available(macOS 10.14, *)) {
auto appearance = [NSApp.effectiveAppearance
bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
return [appearance isEqualToString:NSAppearanceNameDarkAqua];
}
#endif
return false;
}
} // Internal
} // Utils

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -83,8 +83,15 @@ private:
void stdError(const QString &line);
DeployErrorCode parseDeployErrors(const QString &deployOutputLine) const;
friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &e2) { e1 = static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2); }
friend DeployErrorCode operator|(const DeployErrorCode &e1, const DeployErrorCode &e2) { return static_cast<AndroidDeployQtStep::DeployErrorCode>((int)e1 | (int)e2); }
friend void operator|=(DeployErrorCode &e1, const DeployErrorCode &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;
QString m_serialNumber;

View File

@@ -627,8 +627,8 @@ AndroidDeviceManager *AndroidDeviceManager::instance()
AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
: QObject(parent),
m_avdManager(m_androidConfig),
m_androidConfig(AndroidConfigurations::currentConfig())
m_androidConfig(AndroidConfigurations::currentConfig()),
m_avdManager(m_androidConfig)
{
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
m_devicesUpdaterTimer.stop();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -116,7 +116,7 @@ bool AndroidToolChain::isValid() const
void AndroidToolChain::addToEnvironment(Environment &env) const
{
AndroidConfig config = AndroidConfigurations::currentConfig();
const AndroidConfig &config = AndroidConfigurations::currentConfig();
env.set(QLatin1String("ANDROID_NDK_HOST"), config.toolchainHostFromNdk(m_ndkLocation));
const Utils::FilePath javaHome = config.openJDKLocation();
if (javaHome.exists()) {
@@ -178,7 +178,7 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath)
static QList<FilePath> uniqueNdksForCurrentQtVersions()
{
AndroidConfig config = AndroidConfigurations::currentConfig();
const AndroidConfig &config = AndroidConfigurations::currentConfig();
auto androidQtVersions = QtSupport::QtVersionManager::versions(
[](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)
: QDialog(parent),
m_androidConfig(config),
m_sdkManager(m_androidConfig),
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*")),
m_androidConfig(config)
m_allowedNameChars(QLatin1String("[a-z|A-Z|0-9|._-]*"))
{
m_avdDialog.setupUi(this);
m_hideTipTimer.setInterval(2000);

View File

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

View File

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

View File

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

View File

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

View File

@@ -140,11 +140,12 @@ MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target,
config << "--config" << bc->cmakeBuildType();
}
QString buildDirectory = ".";
FilePath buildDirectory = ".";
if (bc)
buildDirectory = bc->buildDirectory().toString();
buildDirectory = bc->buildDirectory();
cmd.arguments << "--build" << buildDirectory << "--target" << installTarget << config;
cmd.arguments << "--build" << buildDirectory.onDevice(cmd.command).mapToDevicePath()
<< "--target" << installTarget << config;
cmd.environment.set("DESTDIR", QDir::toNativeSeparators(installRoot));
return cmd;

View File

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

View File

@@ -455,8 +455,13 @@ void FolderNavigationWidget::insertRootDirectory(
m_rootSelector->setCurrentIndex(index);
if (previousIndex < m_rootSelector->count())
m_rootSelector->removeItem(previousIndex);
if (m_autoSync) // we might find a better root for current selection now
handleCurrentEditorChanged(Core::EditorManager::currentEditor());
if (Core::EditorManager::currentEditor()) {
if (m_autoSync) // we might find a better root for current selection now
handleCurrentEditorChanged(Core::EditorManager::currentEditor());
} else if (m_rootAutoSync) {
// assume the new root is better (e.g. because a project was opened)
m_rootSelector->setCurrentIndex(index);
}
}
void FolderNavigationWidget::removeRootDirectory(const QString &id)

View File

@@ -62,6 +62,10 @@
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/find/searchresultwindow.h>
#include <projectexplorer/projectnodes.h>
#include <projectexplorer/projecttree.h>
#include <projectexplorer/session.h>
#include <texteditor/basefilefind.h>
#include <texteditor/behaviorsettings.h>
#include <texteditor/codeassist/assistproposalitem.h>
@@ -76,8 +80,6 @@
#include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditorsettings.h>
#include <projectexplorer/projecttree.h>
#include <cplusplus/ASTPath.h>
#include <cplusplus/FastPreprocessor.h>
#include <cplusplus/MatchingText.h>
@@ -101,6 +103,7 @@ enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 };
using namespace Core;
using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace TextEditor;
using namespace Utils;
@@ -1045,7 +1048,7 @@ void CppEditorWidget::switchDeclarationDefinition(bool inNextSplit)
}
void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
Utils::ProcessLinkCallback &&processLinkCallback,
ProcessLinkCallback &&processLinkCallback,
bool resolveTarget,
bool inNextSplit)
{
@@ -1054,9 +1057,36 @@ void CppEditorWidget::findLinkAt(const QTextCursor &cursor,
const Utils::FilePath &filePath = textDocument()->filePath();
// Let following a "leaf" C++ symbol take us to the designer, if we are in a generated
// UI header.
QTextCursor c(cursor);
c.select(QTextCursor::WordUnderCursor);
ProcessLinkCallback callbackWrapper = [start = c.selectionStart(), end = c.selectionEnd(),
doc = QPointer(cursor.document()), callback = std::move(processLinkCallback),
filePath](const Link &link) {
const int linkPos = doc ? Text::positionInText(doc, link.targetLine, link.targetColumn + 1)
: -1;
if (link.targetFilePath == filePath && linkPos >= start && linkPos < end) {
const QString fileName = filePath.fileName();
if (fileName.startsWith("ui_") && fileName.endsWith(".h")) {
const QString uiFileName = fileName.mid(3, fileName.length() - 4) + "ui";
for (const Project * const project : SessionManager::projects()) {
const auto nodeMatcher = [uiFileName](Node *n) {
return n->filePath().fileName() == uiFileName;
};
if (const Node * const uiNode = project->rootProjectNode()
->findNode(nodeMatcher)) {
EditorManager::openEditor(uiNode->filePath());
return;
}
}
}
}
callback(link);
};
followSymbolInterface().findLink(
CursorInEditor{cursor, filePath, this, textDocument()},
std::move(processLinkCallback),
std::move(callbackWrapper),
resolveTarget,
d->m_modelManager->snapshot(),
d->m_lastSemanticInfo.doc,

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

@@ -134,7 +134,7 @@ void SourceAgent::updateLocationMarker()
d->editor->textDocument()->removeMark(d->locationMark);
delete d->locationMark;
d->locationMark = nullptr;
if (d->engine->stackHandler()->currentFrame().file == d->path) {
if (d->engine->stackHandler()->currentFrame().file == Utils::FilePath::fromString(d->path)) {
int lineNumber = d->engine->stackHandler()->currentFrame().line;
d->locationMark = new TextMark(Utils::FilePath(), lineNumber,

View File

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

View File

@@ -33,6 +33,7 @@ class TextDocument;
class TextEditorWidget;
}
namespace Utils { class FilePath; }
namespace CPlusPlus { class Snapshot; }
namespace Debugger {
@@ -52,7 +53,7 @@ QString cppFunctionAt(const QString &fileName, int line, int column = 0);
// of a function from the code model. Shadowed variables will
// be reported using the debugger naming conventions '<shadowed n>'
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);

View File

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

View File

@@ -27,6 +27,8 @@
#include "debuggerconstants.h"
#include <utils/filepath.h>
#include <QCoreApplication>
#include <QMetaType>
@@ -56,7 +58,7 @@ public:
DebuggerLanguage language = CppLanguage;
QString level;
QString function;
QString file; // We try to put an absolute file name in there.
Utils::FilePath file;// We try to put an absolute file name in there.
QString module; // Sometimes something like "/usr/lib/libstdc++.so.6"
QString receiver; // Used in ScriptEngine only.
qint32 line = -1;

View File

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

View File

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

View File

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

View File

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

View File

@@ -29,11 +29,9 @@
#include "dockerbuildstep.h"
#include "dockerdevice.h"
#include "dockerrunconfiguration.h"
#include "dockersettings.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/runcontrol.h>
using namespace Core;
using namespace ProjectExplorer;
@@ -49,13 +47,6 @@ public:
// DockerOptionsPage optionsPage{&settings};
DockerDeviceFactory deviceFactory;
// DockerContainerRunConfigurationFactory containerRunConfigFactory;
// RunWorkerFactory containerRunWorkerFactory{
// RunWorkerFactory::make<SimpleTargetRunner>(),
// {ProjectExplorer::Constants::NORMAL_RUN_MODE},
// {containerRunConfigFactory.runConfigurationId()}
// };
// DockerBuildStepFactory buildStepFactory;
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,11 +479,17 @@ void IosConfigurations::loadProvisioningData(bool notify)
QList<QVariantMap> teams;
for (auto accountiterator = teamMap.cbegin(), end = teamMap.cend();
accountiterator != end; ++accountiterator) {
QVariantMap teamInfo = accountiterator.value().toMap();
int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0;
teamInfo[freeTeamTag] = provisioningTeamIsFree;
teamInfo[emailTag] = accountiterator.key();
teams.append(teamInfo);
// difference between Qt 5 (map) and Qt 6 (list of maps)
const bool isList = accountiterator->userType() == QMetaType::QVariantList;
const QVariantList teamsList = isList ? accountiterator.value().toList()
: QVariantList({accountiterator.value()});
for (const QVariant &teamInfoIt : teamsList) {
QVariantMap teamInfo = teamInfoIt.toMap();
int provisioningTeamIsFree = teamInfo.value(freeTeamTag).toBool() ? 1 : 0;
teamInfo[freeTeamTag] = provisioningTeamIsFree;
teamInfo[emailTag] = accountiterator.key();
teams.append(teamInfo);
}
}
// Sort team id's to move the free provisioning teams at last of the list.

View File

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

View File

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

View File

@@ -32,5 +32,7 @@ QtcPlugin {
"mcusupportrunconfiguration.h",
"mcusupportversiondetection.cpp",
"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/
**
** This file is part of Qt Creator.
@@ -22,20 +22,14 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <projectexplorer/runconfiguration.h>
#include "cmakeprojectmanager/cmakeconfigitem.h"
#include "utils/environmentfwd.h"
namespace Docker {
namespace McuSupport {
namespace Internal {
class DockerContainerRunConfigurationFactory
: public ProjectExplorer::FixedRunConfigurationFactory
{
public:
DockerContainerRunConfigurationFactory();
};
} // Internal
} // Docker
QList<CMakeProjectManager::CMakeConfigItem> mapEnvVarsToQul2xCmakeVars(
const Utils::EnvironmentItems &envVars);
}
} // namespace McuSupport

View File

@@ -27,6 +27,7 @@
#include "mcusupportoptions.h"
#include "mcusupportsdk.h"
#include "mcusupportplugin.h"
#include "mcusupportcmakemapper.h"
#include <baremetal/baremetalconstants.h>
#include <cmakeprojectmanager/cmaketoolmanager.h>
@@ -70,7 +71,7 @@ using namespace Utils;
namespace McuSupport {
namespace Internal {
static const int KIT_VERSION = 8; // Bumps up whenever details in Kit creation change
static const int KIT_VERSION = 9; // Bumps up whenever details in Kit creation change
static FilePath packagePathFromSettings(const QString &settingsKey,
QSettings::Scope scope = QSettings::UserScope,
@@ -99,6 +100,22 @@ static bool kitNeedsQtVersion()
return !HostOsInfo::isWindowsHost();
}
static void remapQul2xCmakeVars(Kit *kit, const EnvironmentItems &envItems)
{
using namespace CMakeProjectManager;
const auto cmakeVars = mapEnvVarsToQul2xCmakeVars(envItems);
const auto cmakeVarNames = Utils::transform(cmakeVars, &CMakeConfigItem::key);
// First filter out all Qul2.x CMake vars
auto config = Utils::filtered(CMakeConfigurationKitAspect::configuration(kit),
[&](const auto &configItem) {
return !cmakeVarNames.contains(configItem.key);
});
// Then append them with new values
config.append(cmakeVars);
CMakeConfigurationKitAspect::setConfiguration(kit, config);
}
McuPackage::McuPackage(const QString &label, const FilePath &defaultPath,
const QString &detectionPath, const QString &settingsKey,
const McuPackageVersionDetector *versionDetector)
@@ -231,7 +248,7 @@ bool McuPackage::writeToSettings() const
const FilePath savedPath = packagePathFromSettings(m_settingsKey, QSettings::UserScope, m_defaultPath);
const QString key = QLatin1String(Constants::SETTINGS_GROUP) + '/' +
QLatin1String(Constants::SETTINGS_KEY_PACKAGE_PREFIX) + m_settingsKey;
Core::ICore::settings()->setValueWithDefault(key, m_path, m_defaultPath);
Core::ICore::settings()->setValueWithDefault(key, m_path.toString(), m_defaultPath.toString());
return savedPath != m_path;
}
@@ -573,6 +590,14 @@ void McuTarget::setColorDepth(int colorDepth)
m_colorDepth = colorDepth;
}
void McuSdkRepository::deletePackagesAndTargets()
{
qDeleteAll(packages);
packages.clear();
qDeleteAll(mcuTargets);
mcuTargets.clear();
}
McuSupportOptions::McuSupportOptions(QObject *parent)
: QObject(parent)
, qtForMCUsSdkPackage(Sdk::createQtForMCUsPackage())
@@ -635,14 +660,6 @@ void McuSupportOptions::registerExamples()
}
}
void McuSupportOptions::deletePackagesAndTargets()
{
qDeleteAll(packages);
packages.clear();
qDeleteAll(mcuTargets);
mcuTargets.clear();
}
const QVersionNumber &McuSupportOptions::minimalQulVersion()
{
static const QVersionNumber v({1, 3});
@@ -654,8 +671,8 @@ void McuSupportOptions::setQulDir(const FilePath &dir)
deletePackagesAndTargets();
qtForMCUsSdkPackage->updateStatus();
if (qtForMCUsSdkPackage->validStatus())
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto package : qAsConst(packages))
Sdk::targetsAndPackages(dir, &sdkRepository);
for (const auto &package : qAsConst(sdkRepository.packages))
connect(package, &McuPackage::changed, this, &McuSupportOptions::changed);
emit changed();
@@ -736,6 +753,11 @@ static void setKitDevice(Kit *k, const McuTarget* mcuTarget)
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE);
}
static bool expectsCmakeVars(const McuTarget *mcuTarget)
{
return mcuTarget->qulVersion() >= QVersionNumber{2,0};
}
static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
const McuPackage *qtForMCUsSdkPackage)
{
@@ -770,6 +792,11 @@ static void setKitEnvironment(Kit *k, const McuTarget *mcuTarget,
if (kitNeedsQtVersion())
changes.append({QLatin1String("LD_LIBRARY_PATH"), "%{Qt:QT_INSTALL_LIBS}"});
// Hack, this problem should be solved in lower layer
if (expectsCmakeVars(mcuTarget)) {
remapQul2xCmakeVars(k, changes);
}
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
}
@@ -812,6 +839,11 @@ static void updateKitEnvironment(Kit *k, const McuTarget *mcuTarget)
}
}
// Hack, this problem should be solved in lower layer
if (expectsCmakeVars(mcuTarget)) {
remapQul2xCmakeVars(k, changes);
}
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
}
@@ -1015,6 +1047,11 @@ bool McuSupportOptions::kitUpToDate(const Kit *kit, const McuTarget *mcuTarget,
kitDependencyPath(kit, qtForMCUsSdkPackage->environmentVariableName()) == qtForMCUsSdkPackage->path();
}
void McuSupportOptions::deletePackagesAndTargets()
{
sdkRepository.deletePackagesAndTargets();
}
McuSupportOptions::UpgradeOption McuSupportOptions::askForKitUpgrades()
{
QMessageBox upgradePopup(Core::ICore::dialogParent());
@@ -1076,12 +1113,11 @@ void McuSupportOptions::createAutomaticKits()
}
FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
McuSdkRepository repo;
Sdk::targetsAndPackages(dir, &repo);
bool needsUpgrade = false;
for (auto target: qAsConst(mcuTargets)) {
for (const auto &target: qAsConst(repo.mcuTargets)) {
// if kit already exists, skip
if (!matchingKits(target, qtForMCUsPackage).empty())
continue;
@@ -1096,8 +1132,7 @@ void McuSupportOptions::createAutomaticKits()
}
}
qDeleteAll(packages);
qDeleteAll(mcuTargets);
repo.deletePackagesAndTargets();
if (needsUpgrade)
McuSupportPlugin::askUserAboutMcuSupportKitsUpgrade();
@@ -1110,10 +1145,10 @@ void McuSupportOptions::createAutomaticKits()
void McuSupportOptions::checkUpgradeableKits()
{
if (!qtForMCUsSdkPackage->validStatus() || mcuTargets.length() == 0)
if (!qtForMCUsSdkPackage->validStatus() || sdkRepository.mcuTargets.length() == 0)
return;
if (Utils::anyOf(mcuTargets, [this](const McuTarget *target) {
if (Utils::anyOf(sdkRepository.mcuTargets, [this](const McuTarget *target) {
return !upgradeableKits(target, this->qtForMCUsSdkPackage).empty() &&
matchingKits(target, this->qtForMCUsSdkPackage).empty();
}))
@@ -1128,11 +1163,10 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption)
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
auto dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
McuSdkRepository repo;
Sdk::targetsAndPackages(dir, &repo);
for (auto target: qAsConst(mcuTargets)) {
for (const auto &target: qAsConst(repo.mcuTargets)) {
if (!matchingKits(target, qtForMCUsPackage).empty())
// already up-to-date
continue;
@@ -1149,8 +1183,7 @@ void McuSupportOptions::upgradeKits(UpgradeOption upgradeOption)
}
}
qDeleteAll(packages);
qDeleteAll(mcuTargets);
repo.deletePackagesAndTargets();
delete qtForMCUsPackage;
}
@@ -1166,10 +1199,9 @@ void McuSupportOptions::fixKitsDependencies()
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto target: qAsConst(mcuTargets)) {
McuSdkRepository repo;
Sdk::targetsAndPackages(dir, &repo);
for (const auto &target: qAsConst(repo.mcuTargets)) {
if (target->isValid()) {
for (auto kit : kitsWithMismatchedDependencies(target)) {
updateKitEnvironment(kit, target);
@@ -1177,8 +1209,7 @@ void McuSupportOptions::fixKitsDependencies()
}
}
qDeleteAll(packages);
qDeleteAll(mcuTargets);
repo.deletePackagesAndTargets();
delete qtForMCUsPackage;
}
@@ -1242,18 +1273,16 @@ void McuSupportOptions::fixExistingKits()
qtForMCUsPackage->updateStatus();
if (qtForMCUsPackage->validStatus()) {
FilePath dir = qtForMCUsPackage->path();
QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto target: qAsConst(mcuTargets))
McuSdkRepository repo;
Sdk::targetsAndPackages(dir, &repo);
for (const auto &target: qAsConst(repo.mcuTargets))
for (auto kit: existingKits(target)) {
if (McuDependenciesKitAspect::dependencies(kit).isEmpty()) {
setKitDependencies(kit, target, qtForMCUsPackage);
}
}
qDeleteAll(packages);
qDeleteAll(mcuTargets);
repo.deletePackagesAndTargets();
}
delete qtForMCUsPackage;
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,6 +14,10 @@ else()
endif()
qul_target_qml_sources(%{ProjectName} %{MainQmlFile})
app_target_setup_os(%{ProjectName})
app_target_default_main(%{ProjectName} %{RootItemName})
if(Qul_VERSION VERSION_GREATER_EQUAL "2.0")
app_target_default_entrypoint(%{ProjectName} %{RootItemName})
else()
app_target_default_main(%{ProjectName} %{RootItemName})
endif()

View File

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

View File

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

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();
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);
for (const QString &imgPath : addedImages) {
QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {},
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode());
}
// Create Text components for added font assets
const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString);
for (const QString &fontPath : addedFonts) {
QString fontFamily = QFileInfo(fontPath).baseName();
QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(),
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode());
}
}
} // namespace QmlDesigner

View File

@@ -46,8 +46,7 @@ ComponentView::ComponentView(QObject *parent)
void ComponentView::nodeAboutToBeRemoved(const ModelNode &removedNode)
{
removeSingleNodeFromList(removedNode);
searchForComponentAndRemoveFromList(removedNode);
removeFromListRecursive(removedNode);
}
QStandardItemModel *ComponentView::standardItemModel() const
@@ -75,7 +74,7 @@ void ComponentView::setComponentToMaster()
m_componentAction->setCurrentIndex(indexOfMaster());
}
void ComponentView::removeSingleNodeFromList(const ModelNode &node)
void ComponentView::removeNodeFromList(const ModelNode &node)
{
for (int row = 0; row < m_standardItemModel->rowCount(); row++) {
if (m_standardItemModel->item(row)->data(ModelNodeRole).toInt() == node.internalId())
@@ -83,6 +82,18 @@ void ComponentView::removeSingleNodeFromList(const ModelNode &node)
}
}
void ComponentView::addNodeToList(const ModelNode &node)
{
if (hasEntryForNode(node))
return;
QString description = descriptionForNode(node);
auto item = new QStandardItem(description);
item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole);
item->setEditable(false);
m_standardItemModel->appendRow(item);
}
int ComponentView::indexForNode(const ModelNode &node) const
{
for (int row = 0; row < m_standardItemModel->rowCount(); row++) {
@@ -112,7 +123,7 @@ bool ComponentView::hasEntryForNode(const ModelNode &node) const
return indexForNode(node) >= 0;
}
void ComponentView::addMasterDocument()
void ComponentView::ensureMasterDocument()
{
if (!hasMasterEntry()) {
QStandardItem *item = new QStandardItem(QLatin1String("master"));
@@ -122,9 +133,11 @@ void ComponentView::addMasterDocument()
}
}
void ComponentView::removeMasterDocument()
void ComponentView::maybeRemoveMasterDocument()
{
m_standardItemModel->removeRow(indexOfMaster());
int idx = indexOfMaster();
if (idx >= 0 && m_standardItemModel->rowCount() == 1)
m_standardItemModel->removeRow(idx);
}
QString ComponentView::descriptionForNode(const ModelNode &node) const
@@ -155,6 +168,15 @@ void ComponentView::updateDescription(const ModelNode &node)
m_standardItemModel->item(nodeIndex)->setText(descriptionForNode(node));
}
bool ComponentView::isSubComponentNode(const ModelNode &node) const
{
return node.nodeSourceType() == ModelNode::NodeWithComponentSource
|| (node.hasParentProperty()
&& !node.parentProperty().isDefaultProperty()
&& node.metaInfo().isValid()
&& node.metaInfo().isGraphicalItem());
}
void ComponentView::modelAttached(Model *model)
{
if (AbstractView::model() == model)
@@ -187,46 +209,25 @@ void ComponentView::nodeCreated(const ModelNode &createdNode)
void ComponentView::searchForComponentAndAddToList(const ModelNode &node)
{
bool masterNotAdded = true;
foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) {
if (node.nodeSourceType() == ModelNode::NodeWithComponentSource
|| (node.hasParentProperty()
&& !node.parentProperty().isDefaultProperty()
&& node.metaInfo().isValid()
&& node.metaInfo().isGraphicalItem())) {
if (masterNotAdded) {
masterNotAdded = true;
addMasterDocument();
}
if (!hasEntryForNode(node)) {
QString description = descriptionForNode(node);
auto item = new QStandardItem(description);
item->setData(QVariant::fromValue(node.internalId()), ModelNodeRole);
item->setEditable(false);
removeSingleNodeFromList(node); //remove node if already present
m_standardItemModel->appendRow(item);
const auto nodeList = node.allSubModelNodesAndThisNode();
bool hasMaster = false;
for (const ModelNode &childNode : nodeList) {
if (isSubComponentNode(childNode)) {
if (!hasMaster) {
hasMaster = true;
ensureMasterDocument();
}
addNodeToList(childNode);
}
}
}
void ComponentView::searchForComponentAndRemoveFromList(const ModelNode &node)
void ComponentView::removeFromListRecursive(const ModelNode &node)
{
QList<ModelNode> nodeList;
nodeList.append(node);
nodeList.append(node.allSubModelNodes());
foreach (const ModelNode &childNode, nodeList) {
if (childNode.nodeSourceType() == ModelNode::NodeWithComponentSource)
removeSingleNodeFromList(childNode);
}
if (m_standardItemModel->rowCount() == 1)
removeMasterDocument();
const auto nodeList = node.allSubModelNodesAndThisNode();
for (const ModelNode &childNode : std::as_const(nodeList))
removeNodeFromList(childNode);
maybeRemoveMasterDocument();
}
void ComponentView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/)
@@ -240,4 +241,17 @@ void ComponentView::nodeIdChanged(const ModelNode& node, const QString& /*newId*
{
updateDescription(node);
}
void ComponentView::nodeSourceChanged(const ModelNode &node, const QString &/*newNodeSource*/)
{
if (isSubComponentNode(node)) {
if (!hasEntryForNode(node)) {
ensureMasterDocument();
addNodeToList(node);
}
} else {
removeNodeFromList(node);
maybeRemoveMasterDocument();
}
}
} // namespace QmlDesigner

View File

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

View File

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

View File

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

View File

@@ -914,16 +914,30 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
usedImportsSet.insert(i.info.path());
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)) {
QDir dir(path + "/" + subDir);
if (!dir.entryInfoList(QStringList("*.qml"), QDir::Files).isEmpty()
&& dir.entryInfoList(QStringList("qmldir"), QDir::Files).isEmpty()
&& !usedImportsSet.contains(dir.path())) {
QmlDesigner::Import import = QmlDesigner::Import::createFileImport(subDir);
possibleImports.append(import);
QStringList fileImportPaths;
const QChar delimeter('/');
std::function<void(const QString &)> checkDir;
checkDir = [&](const QString &checkPath) {
const QStringList entries = QDir(checkPath).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
const QString checkPathDelim = checkPath + delimeter;
for (const QString &entry : entries) {
QDir dir(checkPathDelim + entry);
const QString dirPath = dir.path();
if (!dir.entryInfoList(qmlList, QDir::Files).isEmpty()
&& dir.entryInfoList(qmldirList, QDir::Files).isEmpty()
&& !usedImportsSet.contains(dirPath)) {
const QString importName = dir.path().mid(path.size() + 1);
QmlDesigner::Import import = QmlDesigner::Import::createFileImport(importName);
possibleImports.append(import);
}
checkDir(dirPath);
}
}
};
checkDir(path);
return possibleImports;
}
@@ -931,17 +945,44 @@ static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &pat
static QList<QmlDesigner::Import> generatePossibleLibraryImports(const QHash<QString, ImportKey> &filteredPossibleImportKeys)
{
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('.'));
int majorVersion = importKey.majorVersion;
if (majorVersion >= 0) {
int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion;
QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion);
possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version));
// In Qt6, QtQuick.Controls itself doesn't have any version as it has no types,
// so it never gets added normally to possible imports.
// We work around this by injecting corresponding QtQuick.Controls version for each
// found impl version, if no valid QtQuick.Controls versions are found.
if (!hasVersionedControls) {
if (libraryName == controlsImplName)
controlsImplVersions.insert(version);
else if (libraryName == controlsName)
hasVersionedControls = true;
}
} else if (!hasVersionlessControls && libraryName == controlsName) {
// If QtQuick.Controls module is not included even in non-versioned, it means
// QtQuick.Controls is either in use or not available at all,
// so we shouldn't inject it.
hasVersionlessControls = true;
}
}
if (hasVersionlessControls && !hasVersionedControls && !controlsImplVersions.isEmpty()) {
for (const auto &version : std::as_const(controlsImplVersions))
possibleImports.append(QmlDesigner::Import::createLibraryImport(controlsName, version));
}
return possibleImports;
}
@@ -2111,7 +2152,7 @@ void TextToModelMerger::collectLinkErrors(QList<DocumentMessage> *errors, const
void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
{
if (m_rewriterView->model()->imports().isEmpty()) {
const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found"));
const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found."));
errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName())));
}
@@ -2137,7 +2178,7 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
SourceLocation(0, 0, 0, 0),
QCoreApplication::translate(
"QmlDesigner::TextToModelMerger",
"QtQuick 6 is not supported with a Qt 5 kit."));
"Qt Quick 6 is not supported with a Qt 5 kit."));
errors->prepend(
DocumentMessage(diagnosticMessage,
QUrl::fromLocalFile(m_document->fileName())));
@@ -2161,7 +2202,7 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
diagnosticMessage(QmlJS::Severity::Error,
SourceLocation(0, 0, 0, 0),
QCoreApplication::translate("QmlDesigner::TextToModelMerger",
"Unsupported QtQuick version"));
"Unsupported Qt Quick version."));
errors->append(DocumentMessage(diagnosticMessage,
QUrl::fromLocalFile(m_document->fileName())));
}

View File

@@ -30,9 +30,11 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/project.h>
#include <projectexplorer/runcontrol.h>
#include <projectexplorer/session.h>
#include <qmlprojectmanager/qmlprojectmanagerconstants.h>
#include <qmlprojectmanager/qmlmainfileaspect.h>
#include <utils/fileutils.h>
@@ -44,21 +46,15 @@
using namespace Utils;
namespace QmlDesigner {
namespace GenerateCmakeLists {
const QDir::Filters FILES_ONLY = QDir::Files;
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const char CMAKEFILENAME[] = "CMakeLists.txt";
const char QMLDIRFILENAME[] = "qmldir";
namespace GenerateCmake {
void generateMenuEntry()
{
Core::ActionContainer *buildMenu =
Core::ActionManager::actionContainer(ProjectExplorer::Constants::M_BUILDPROJECT);
const Core::Context projectCntext(QmlProjectManager::Constants::QML_PROJECT_ID);
auto action = new QAction("Generate CMakeLists.txt files");
QObject::connect(action, &QAction::triggered, GenerateCmakeLists::onGenerateCmakeLists);
QObject::connect(action, &QAction::triggered, GenerateCmake::onGenerateCmakeLists);
Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateCMakeLists");
buildMenu->addAction(cmd, ProjectExplorer::Constants::G_BUILD_RUN);
@@ -71,9 +67,33 @@ void generateMenuEntry()
void onGenerateCmakeLists()
{
generateMainCmake(ProjectExplorer::SessionManager::startupProject()->projectDirectory());
FilePath rootDir = ProjectExplorer::SessionManager::startupProject()->projectDirectory();
GenerateCmakeLists::generateMainCmake(rootDir);
GenerateEntryPoints::generateMainCpp(rootDir);
GenerateEntryPoints::generateMainQml(rootDir);
}
bool writeFile(const FilePath &filePath, const QString &fileContent)
{
QFile file(filePath.toString());
file.open(QIODevice::WriteOnly);
QTextStream stream(&file);
stream << fileContent;
file.close();
return true;
}
}
namespace GenerateCmakeLists {
const QDir::Filters FILES_ONLY = QDir::Files;
const QDir::Filters DIRS_ONLY = QDir::Dirs|QDir::Readable|QDir::NoDotAndDotDot;
const char CMAKEFILENAME[] = "CMakeLists.txt";
const char QMLDIRFILENAME[] = "qmldir";
QStringList processDirectory(const FilePath &dir)
{
QStringList moduleNames;
@@ -149,9 +169,7 @@ const char MODULEFILE_CREATE_MODULE[] = "qt6_add_qml_module(%1\n\tURI \"%1\"\n\t
QString generateModuleCmake(const FilePath &dir)
{
QString fileContent;
const QStringList qmlFilesOnly("*.qml");
const QStringList qmldirFilesOnly(QMLDIRFILENAME);
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
FilePaths qmldirFileList = dir.dirEntries(qmldirFilesOnly, FILES_ONLY);
if (!qmldirFileList.isEmpty()) {
@@ -161,18 +179,15 @@ QString generateModuleCmake(const FilePath &dir)
}
}
FilePaths qmlFileList = dir.dirEntries(qmlFilesOnly, FILES_ONLY);
QStringList qmlFileList = getDirectoryTreeQmls(dir);
QString qmlFiles;
for (FilePath &qmlFile : qmlFileList) {
if (project->isKnownFile(qmlFile))
qmlFiles.append(QString("\t\t%1\n").arg(qmlFile.fileName()));
}
for (QString &qmlFile : qmlFileList)
qmlFiles.append(QString("\t\t%1\n").arg(qmlFile));
QStringList resourceFileList = getDirectoryTreeResources(dir);
QString resourceFiles;
for (QString &resourceFile : resourceFileList) {
for (QString &resourceFile : resourceFileList)
resourceFiles.append(QString("\t\t%1\n").arg(resourceFile));
}
QString moduleContent;
if (!qmlFiles.isEmpty()) {
@@ -226,6 +241,31 @@ QStringList getSingletonsFromQmldirFile(const FilePath &filePath)
return singletons;
}
QStringList getDirectoryTreeQmls(const FilePath &dir)
{
const QStringList qmlFilesOnly("*.qml");
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
QStringList qmlFileList;
FilePaths thisDirFiles = dir.dirEntries(qmlFilesOnly, FILES_ONLY);
for (FilePath &file : thisDirFiles) {
if (!isFileBlacklisted(file.fileName()) &&
project->isKnownFile(file)) {
qmlFileList.append(file.fileName());
}
}
FilePaths subDirsList = dir.dirEntries(DIRS_ONLY);
for (FilePath &subDir : subDirsList) {
QStringList subDirQmlFiles = getDirectoryTreeQmls(subDir);
for (QString &qmlFile : subDirQmlFiles) {
qmlFileList.append(subDir.fileName().append('/').append(qmlFile));
}
}
return qmlFileList;
}
QStringList getDirectoryTreeResources(const FilePath &dir)
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
@@ -255,11 +295,7 @@ QStringList getDirectoryTreeResources(const FilePath &dir)
void createCmakeFile(const FilePath &dir, const QString &content)
{
FilePath filePath = dir.pathAppended(CMAKEFILENAME);
QFile cmakeFile(filePath.toString());
cmakeFile.open(QIODevice::WriteOnly);
QTextStream stream(&cmakeFile);
stream << content;
cmakeFile.close();
GenerateCmake::writeFile(filePath, content);
}
bool isFileBlacklisted(const QString &fileName)
@@ -269,4 +305,48 @@ bool isFileBlacklisted(const QString &fileName)
}
}
namespace GenerateEntryPoints {
bool generateEntryPointFiles(const FilePath &dir)
{
bool cppOk = generateMainCpp(dir);
bool qmlOk = generateMainQml(dir);
return cppOk && qmlOk;
}
const char MAIN_CPPFILE_CONTENT[] = ":/boilerplatetemplates/qmlprojectmaincpp.tpl";
const char MAIN_CPPFILE_NAME[] = "main.cpp";
bool generateMainCpp(const FilePath &dir)
{
QFile templatefile(MAIN_CPPFILE_CONTENT);
templatefile.open(QIODevice::ReadOnly);
QTextStream stream(&templatefile);
QString content = stream.readAll();
templatefile.close();
FilePath filePath = dir.pathAppended(MAIN_CPPFILE_NAME);
return GenerateCmake::writeFile(filePath, content);
}
const char MAIN_QMLFILE_CONTENT[] = "import %1Qml\n\n%2 {\n}\n";
const char MAIN_QMLFILE_NAME[] = "main.qml";
bool generateMainQml(const FilePath &dir)
{
FilePath filePath = dir.pathAppended(MAIN_QMLFILE_NAME);
QString projectName = ProjectExplorer::SessionManager::startupProject()->displayName();
ProjectExplorer::RunConfiguration *runConfiguration = ProjectExplorer::SessionManager::startupRunConfiguration();
QString mainClass;
if (const auto aspect = runConfiguration->aspect<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>
namespace QmlDesigner {
namespace GenerateCmakeLists {
namespace GenerateCmake {
void generateMenuEntry();
void onGenerateCmakeLists();
bool writeFile(const Utils::FilePath &filePath, const QString &fileContent);
}
namespace GenerateCmakeLists {
void generateMainCmake(const Utils::FilePath &rootDir);
void generateSubdirCmake(const Utils::FilePath &dir);
QString generateModuleCmake(const Utils::FilePath &dir);
QStringList processDirectory(const Utils::FilePath &dir);
QStringList getSingletonsFromQmldirFile(const Utils::FilePath &filePath);
QStringList getDirectoryTreeQmls(const Utils::FilePath &dir);
QStringList getDirectoryTreeResources(const Utils::FilePath &dir);
void createCmakeFile(const Utils::FilePath &filePath, const QString &content);
bool isFileBlacklisted(const QString &fileName);
}
namespace GenerateEntryPoints {
bool generateEntryPointFiles(const Utils::FilePath &dir);
bool generateMainCpp(const Utils::FilePath &dir);
bool generateMainQml(const Utils::FilePath &dir);
}
}

View File

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

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)
activeTarget = projectInfo.project->activeTarget();
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())
bp->mergeBundlesForKit(activeKit, projectInfo.activeBundle, replacements);
@@ -146,17 +146,17 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
}
if (qtVersion && qtVersion->isValid()) {
projectInfo.tryQmlDump = project && qtVersion->type() == QLatin1String(QtSupport::Constants::DESKTOPQT);
projectInfo.qtQmlPath = qtVersion->qmlPath().toFileInfo().canonicalFilePath();
projectInfo.qtQmlPath = qtVersion->qmlPath();
projectInfo.qtVersionString = qtVersion->qtVersionString();
} else if (!activeKit || !activeKit->value(QtSupport::SuppliesQtQuickImportPath::id(), false).toBool()) {
projectInfo.qtQmlPath = QFileInfo(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath)).canonicalFilePath();
projectInfo.qtQmlPath = FilePath::fromUserInput(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
projectInfo.qtVersionString = QLatin1String(qVersion());
}
projectInfo.qmlDumpPath.clear();
const QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(activeKit);
if (version && projectInfo.tryQmlDump) {
projectInfo.qmlDumpPath = version->qmlplugindumpFilePath().toString();
projectInfo.qmlDumpPath = version->qmlplugindumpFilePath();
projectInfo.qmlDumpHasRelocatableFlag = version->hasQmlDumpWithRelocatableFlag();
}

View File

@@ -502,6 +502,7 @@ public:
void duplicateSelection(bool comment);
void updateCannotDecodeInfo();
void collectToCircularClipboard();
void setClipboardSelection();
void ctor(const QSharedPointer<TextDocument> &doc);
void handleHomeKey(bool anchor, bool block);
@@ -5217,7 +5218,8 @@ void TextEditorWidget::mousePressEvent(QMouseEvent *e)
void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
{
if (d->m_linkPressed && d->isMouseNavigationEvent(e) && e->button() == Qt::LeftButton) {
const Qt::MouseButton button = e->button();
if (d->m_linkPressed && d->isMouseNavigationEvent(e) && button == Qt::LeftButton) {
EditorManager::addCurrentPositionToNavigationHistory();
bool inNextSplit = ((e->modifiers() & Qt::AltModifier) && !alwaysOpenLinksInNextSplit())
|| (alwaysOpenLinksInNextSplit() && !(e->modifiers() & Qt::AltModifier));
@@ -5227,12 +5229,22 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
if (self && self->openLink(symbolLink, inNextSplit))
self->d->clearLink();
}, true, inNextSplit);
} else if (button == Qt::MiddleButton
&& !isReadOnly()
&& QGuiApplication::clipboard()->supportsSelection()) {
if (!(e->modifiers() & Qt::AltModifier))
doSetTextCursor(cursorForPosition(e->pos()));
if (const QMimeData *md = QGuiApplication::clipboard()->mimeData(QClipboard::Selection))
insertFromMimeData(md);
e->accept();
return;
}
if (!HostOsInfo::isLinuxHost() && handleForwardBackwardMouseButtons(e))
return;
QPlainTextEdit::mouseReleaseEvent(e);
d->setClipboardSelection();
}
void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
@@ -5247,6 +5259,14 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
}
QPlainTextEdit::mouseDoubleClickEvent(e);
d->setClipboardSelection();
}
void TextEditorWidgetPrivate::setClipboardSelection()
{
QClipboard *clipboard = QGuiApplication::clipboard();
if (m_cursors.hasSelection() && clipboard->supportsSelection())
clipboard->setMimeData(q->createMimeDataFromSelection(), QClipboard::Selection);
}
void TextEditorWidget::leaveEvent(QEvent *e)

View File

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