forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/6.0'
Change-Id: I9b824b8bb7b0b5d76e9e8f28f909b542adf773f0
This commit is contained in:
38
dist/changes-6.0.0.md
vendored
38
dist/changes-6.0.0.md
vendored
@@ -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
|
||||
|
44
doc/qtcreator/examples/accelbubble/AndroidManifest.xml
Normal file
44
doc/qtcreator/examples/accelbubble/AndroidManifest.xml
Normal 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>
|
@@ -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
|
||||
}
|
32
doc/qtcreator/examples/accelbubble/CMakeLists.txt
Normal file
32
doc/qtcreator/examples/accelbubble/CMakeLists.txt
Normal 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)
|
34
doc/qtcreator/examples/accelbubble/Info.plist
Normal file
34
doc/qtcreator/examples/accelbubble/Info.plist
Normal 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>
|
@@ -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
|
@@ -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)
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>main.qml</file>
|
||||
<file>Bluebubble.svg</file>
|
||||
<file>Bubble.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
BIN
doc/qtcreator/images/qtquick-mobile-tutorial-manifest.png
Normal file
BIN
doc/qtcreator/images/qtquick-mobile-tutorial-manifest.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
@@ -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}.
|
||||
|
@@ -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)
|
||||
|
@@ -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 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -32,7 +32,9 @@ import StudioTheme 1.0 as StudioTheme
|
||||
PropertyEditorPane {
|
||||
id: itemPane
|
||||
|
||||
ComponentSection {}
|
||||
ComponentSection {
|
||||
showState: majorVersion >= 6
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: parent.left
|
||||
|
@@ -787,7 +787,9 @@ SecondColumnLayout {
|
||||
|
||||
ControlLabel {
|
||||
text: "Hex"
|
||||
width: StudioTheme.Values.colorEditorPopupHexLabelWidth
|
||||
width: 2 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||
+ StudioTheme.Values.controlGap
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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());
|
||||
|
@@ -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;
|
||||
|
@@ -29,6 +29,7 @@ namespace Utils {
|
||||
namespace Internal {
|
||||
|
||||
void forceMacOSLightAquaApperance();
|
||||
bool currentAppearanceIsDark();
|
||||
|
||||
} // Internal
|
||||
} // Utils
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -211,7 +211,7 @@ class ANDROID_EXPORT AndroidConfigurations : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static const AndroidConfig ¤tConfig();
|
||||
static AndroidConfig ¤tConfig();
|
||||
static Internal::AndroidSdkManager *sdkManager();
|
||||
static void setConfig(const AndroidConfig &config);
|
||||
static AndroidConfigurations *instance();
|
||||
|
@@ -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()
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
//
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
};
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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) {
|
||||
|
@@ -72,7 +72,11 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &
|
||||
CMakeTool *cmake = parameters.cmakeTool();
|
||||
QTC_ASSERT(parameters.isValid() && cmake, return);
|
||||
|
||||
const FilePath buildDirectory = parameters.buildDirectory;
|
||||
const FilePath cmakeExecutable = cmake->cmakeExecutable();
|
||||
|
||||
const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable);
|
||||
const FilePath buildDirectory = parameters.buildDirectory.onDevice(cmakeExecutable);
|
||||
|
||||
if (!buildDirectory.exists()) {
|
||||
QString msg = tr("The build directory \"%1\" does not exist")
|
||||
.arg(buildDirectory.toUserOutput());
|
||||
@@ -119,12 +123,8 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList &
|
||||
connect(process.get(), &QtcProcess::finished,
|
||||
this, &CMakeProcess::handleProcessFinished);
|
||||
|
||||
const FilePath cmakeExecutable = cmake->cmakeExecutable();
|
||||
const FilePath sourceDirectory = parameters.sourceDirectory.onDevice(cmakeExecutable);
|
||||
|
||||
CommandLine commandLine(cmakeExecutable);
|
||||
commandLine.addArgs({"-S", sourceDirectory.mapToDevicePath(),
|
||||
"-B", buildDirectory.mapToDevicePath()});
|
||||
commandLine.addArgs({"-S", sourceDirectory.path(), "-B", buildDirectory.path()});
|
||||
commandLine.addArgs(arguments);
|
||||
|
||||
TaskHub::clearTasks(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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");
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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:
|
||||
|
@@ -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
|
||||
)
|
||||
|
@@ -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
|
||||
|
@@ -19,8 +19,6 @@ QtcPlugin {
|
||||
"dockerdevice.cpp",
|
||||
"dockerplugin.h",
|
||||
"dockerplugin.cpp",
|
||||
"dockerrunconfiguration.h",
|
||||
"dockerrunconfiguration.cpp",
|
||||
"dockersettings.h",
|
||||
"dockersettings.cpp"
|
||||
]
|
||||
|
@@ -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;
|
||||
|
@@ -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
|
@@ -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.
|
||||
|
@@ -12,4 +12,5 @@ add_qtc_plugin(McuSupport
|
||||
mcusupportsdk.cpp mcusupportsdk.h
|
||||
mcusupportrunconfiguration.cpp mcusupportrunconfiguration.h
|
||||
mcusupportversiondetection.cpp mcusupportversiondetection.h
|
||||
mcusupportcmakemapper.cpp mcusupportcmakemapper.h
|
||||
)
|
||||
|
@@ -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
|
||||
|
@@ -32,5 +32,7 @@ QtcPlugin {
|
||||
"mcusupportrunconfiguration.h",
|
||||
"mcusupportversiondetection.cpp",
|
||||
"mcusupportversiondetection.h",
|
||||
"mcusupportcmakemapper.h",
|
||||
"mcusupportcmakemapper.cpp"
|
||||
]
|
||||
}
|
||||
|
76
src/plugins/mcusupport/mcusupportcmakemapper.cpp
Normal file
76
src/plugins/mcusupport/mcusupportcmakemapper.cpp
Normal 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();
|
||||
});
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
|
@@ -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();
|
||||
|
@@ -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();
|
||||
|
@@ -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);
|
||||
});
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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()
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
5
src/plugins/qmldesigner/boilerplate.qrc
Normal file
5
src/plugins/qmldesigner/boilerplate.qrc
Normal file
@@ -0,0 +1,5 @@
|
||||
<RCC>
|
||||
<qresource prefix="/boilerplatetemplates">
|
||||
<file>qmlprojectmaincpp.tpl</file>
|
||||
</qresource>
|
||||
</RCC>
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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())));
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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(
|
||||
|
58
src/plugins/qmldesigner/qmlprojectmaincpp.tpl
Normal file
58
src/plugins/qmldesigner/qmlprojectmaincpp.tpl
Normal 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();
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
|
||||
|
Reference in New Issue
Block a user