Merge remote-tracking branch 'origin/7.0'

Conflicts:
	src/libs/utils/qtcprocess.cpp
	src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp
	src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp

Change-Id: Id0c31719e46d1c44770ea89663eee321a0517ff4
This commit is contained in:
Eike Ziller
2022-02-24 11:42:13 +01:00
115 changed files with 1239 additions and 969 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -157,14 +157,6 @@
re-scanning is incremental, so nothing is lost by closing and re-starting
\QC.
Because clangd considers only the on-disk state of included header files
when parsing a source file, you need to save changes in header files to
have them considered elsewhere for completion, diagnostics, and so on.
Partly for this reason, files that are changed by refactoring actions are
saved automatically. To disable this feature, select \uicontrol Tools >
\uicontrol Options > \uicontrol Environment > \uicontrol System >
\uicontrol {Auto-save files after refactoring}.
The document outline in the \l{Viewing Defined Types and Symbols}
{Outline} view is backed by clangd's document symbol support, which
makes the results more reliable than before.

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -114,7 +114,7 @@
\c {share/qtcreator/templates/wizards/classes/mycpp}
\li Use the \uicontrol {Factory.Reset} action to make the wizard appear
in \uicontrol File > \uicontrol {New File or Project} without
in \uicontrol File > \uicontrol {New File} without
restarting \QC.
\li Open the wizard configuration file, \c {wizard.json} for editing:
@@ -122,7 +122,7 @@
\list
\li The following settings determine the type of the wizard and
its place in the \uicontrol {New File or Project} dialog:
its place in the \uicontrol {New File} dialog:
\code
"version": 1,
@@ -163,14 +163,14 @@
\li \c category is the category in which to place the wizard
in the list. You can use a leading letter to specify the
position of the category in the list in the
\uicontrol {New File or Project} dialog.
\uicontrol {New File} dialog.
This information is available in the wizard as
\c {%\{category\}}.
\endlist
\li The following settings specify the icon and text that appear in
the \uicontrol {New File or Project} dialog:
the \uicontrol {New File} dialog:
\code
"trDescription": "Creates a C++ header and a source file for a new class that you can add to a C++ project.",
@@ -194,9 +194,8 @@
This information is available in the wizard as
\c {%\{trDisplayName\}}.
\li \c trDisplayCategory appears in the
\uicontrol {New File or Project} dialog, under
\uicontrol Projects.
\li \c trDisplayCategory appears in the \uicontrol {New File}
dialog, under \uicontrol {Files and Classes}.
This information is available in the wizard as
\c {%\{trDisplayCategory\}}.
@@ -231,9 +230,9 @@
\c{false}.
\li \c enabled is evaluated to determine whether a wizard is
listed in \uicontrol Files >
\uicontrol {New File or Project}, after \c featuresRequired
has been checked.
listed in \uicontrol File > \uicontrol {New Project} or
\uicontrol {New File}, after \c featuresRequired has been
checked.
The default value is \c true.
@@ -373,7 +372,8 @@
instance of \QC.
\li \c Platform contains the platform selected in the \uicontrol File >
\uicontrol {New File or Project} dialog. This value may be empty.
\uicontrol {New Project} or \uicontrol {New File} dialog. This value
may be empty.
\endlist
The following information is only available when the wizard was triggered
@@ -487,7 +487,7 @@
\endcode
The page evaluates \c {%\{Platform\}} to set the platform selected in
\uicontrol File > \uicontrol {New File or Project}.
\uicontrol File > \uicontrol {New Project} or \uicontrol {New File}.

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -59,8 +59,8 @@
wizard directory and instruct the recipients to extract it into one of the
directories \QC searches wizards from.
\QC displays the wizards that it finds in the
\uicontrol {New File} and \uicontrol {New Project} dialogs. For each wizard, an icon (1), a
\QC displays the wizards that it finds in the \uicontrol {New Project}
and \uicontrol {New File} dialogs. For each wizard, an icon (1), a
display name (2), and a description (3) are displayed.
\image qtcreator-custom-wizard.png

View File

@@ -45,6 +45,8 @@
\uicontrol Environment > \uicontrol System, and then select
\uicontrol Change in the \uicontrol Environment field.
\image qtcreator-options-environment-system.png "Environment options System tab"
In addition, you can specify custom environment variables in the
\uicontrol {Project Settings} > \uicontrol Environment settings.
They are added to all build environments. The final build environment

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -30,7 +30,7 @@
\list 1
\li Select \uicontrol File > \uicontrol {New File or Project} >
\li Select \uicontrol File > \uicontrol {New Project} >
\uicontrol {Application (Qt)} > \uicontrol {Qt Quick Application}.
\li Select \uicontrol Choose to open the

View File

@@ -63,6 +63,8 @@
\li Select the \uicontrol {Auto-save modified files} check box to
automatically save changed files at the intervals specified in
the \uicontrol Interval field.
\li Select the \uicontrol {Auto-save files after refactoring} check
box to automatically save \l{Refactoring}{refactored files}.
\li Select the \uicontrol {Auto-suspend unmodified files} check
box to automatically free the resources of open files after
prolonged inactivity. The files are still listed in the

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Design Studio documentation.
@@ -61,7 +61,7 @@
To create stylable UI controls:
\list 1
\li Select \uicontrol File > \uicontrol {New File or Project} >
\li Select \uicontrol File > \uicontrol {New File} >
\uicontrol {Files and Classes} > \uicontrol {Qt Quick Controls}.
\li Select the control to create, and then select \uicontrol Choose.

View File

@@ -35,20 +35,18 @@
\image studio-examples-download.png "Examples for download in Welcome mode"
To run an example project:
\list 1
\li Select the example.
\li Select the \inlineimage icons/live_preview.png
(\uicontrol {Show Live Preview}) button to preview the example.
\li Select the example project to open it. \QDS makes all necessary
downloads.
\li Select \inlineimage icons/run_small.png
(\uicontrol {Run}) to run the example.
\endlist
Some of the example projects require that you download them before you can run them, to do this:
\list 1
\li Select an example.
\li Select \uicontrol {Start Download}.
\li Select the folder where the source files will be installed.
\li Select \uicontrol Continue to install the files.
\li Select \uicontrol Open to open the example in \QDS.
\endlist
If there is an update available for an example project that you have
installed, it is indicated by a yellow icon next to the example project name
on the \uicontrol Welcome page. Select the icon to download the latest
version of the example project.
\section1 Example Documentation

View File

@@ -28,6 +28,7 @@
#include "sharedmemory.h"
#include <QCache>
#include <QDebug>
#include <QLoggingCategory>
#include <cstring>
@@ -36,6 +37,8 @@
#define QTC_ASSERT_STRING(cond) qDebug("SOFT ASSERT: \"" cond"\" in file " __FILE__ ", line " QTC_ASSERT_STRINGIFY(__LINE__))
#define QTC_ASSERT(cond, action) if (cond) {} else { QTC_ASSERT_STRING(#cond); action; } do {} while (0)
static Q_LOGGING_CATEGORY(imageContainerDebug, "qtc.imagecontainer.debug", QtDebugMsg)
namespace QmlDesigner {
// using cache as a container which deletes sharedmemory pointers at process exit
@@ -202,7 +205,7 @@ static void readSharedMemory(qint32 key, ImageContainer &container)
image.setDevicePixelRatio(pixelRatio);
if (image.isNull())
qDebug() << Q_FUNC_INFO << "Not able to create image:" << imageWidth << imageHeight << imageFormat;
qCInfo(imageContainerDebug()) << Q_FUNC_INFO << "Not able to create image:" << imageWidth << imageHeight << imageFormat;
else
std::memcpy(image.bits(), reinterpret_cast<const qint32*>(sharedMemory.constData()) + 6, byteCount);

View File

@@ -125,6 +125,7 @@ bool startCrashpad()
// Optional arguments to pass to the handler
std::vector<std::string> arguments;
arguments.push_back("--no-rate-limit");
CrashpadClient *client = new CrashpadClient();
bool success = client->StartHandler(

View File

@@ -424,7 +424,7 @@ Item {
width: parent.width
height: parent.height - y
clip: true
interactive: assetsView.verticalScrollBarVisible
interactive: assetsView.verticalScrollBarVisible && !contextMenu.opened
Column {
Repeater {

View File

@@ -246,6 +246,7 @@ Item {
id: verticalScrollView
anchors.fill: parent
clip: true
interactive: !itemContextMenu.opened && !moduleContextMenu.opened
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - verticalScrollView.height, 0)
@@ -362,6 +363,7 @@ Item {
width: 270
height: parent.height
clip: true
interactive: !itemContextMenu.opened && !moduleContextMenu.opened
onContentHeightChanged: {
var maxPosition = Math.max(contentHeight - horizontalScrollView.height, 0)

View File

@@ -99,7 +99,7 @@ PropertyEditorPane {
anchors.right: parent.right
StudioControls.TabButton {
text: backendValues.className.value
text: backendValues.__classNamePrivateInternal.value
}
StudioControls.TabButton {
text: qsTr("Layout")

View File

@@ -56,13 +56,13 @@ Section {
anchors.fill: parent
anchors.leftMargin: StudioTheme.Values.inputHorizontalPadding
anchors.topMargin: StudioTheme.Values.typeLabelVerticalShift
text: backendValues.className.value
text: backendValues.__classNamePrivateInternal.value
}
ToolTipArea {
anchors.fill: parent
onDoubleClicked: {
typeLineEdit.text = backendValues.className.value
typeLineEdit.text = backendValues.__classNamePrivateInternal.value
typeLineEdit.visible = !typeLineEdit.visible
typeLineEdit.forceActiveFocus()
}

View File

@@ -86,7 +86,7 @@ QtObject {
property real contextMenuHorizontalPadding: Math.round(6 * values.scaleFactor)
property real inputHorizontalPadding: Math.round(6 * values.scaleFactor)
property real typeLabelVerticalShift: Math.round(5 * values.scaleFactor)
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
property real scrollBarThickness: 10

View File

@@ -1,5 +1,12 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.12
import QtQuick.Controls 2.15
Button {
id: control

View File

@@ -1,5 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
CheckBox {
id: control

View File

@@ -1,5 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
Dial {
id: control

View File

@@ -1,5 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
Slider {
id: control

View File

@@ -1,5 +1,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
SpinBox {
id: control

View File

@@ -1,5 +1,12 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import QtQuick.Controls 2.12
import QtQuick.Controls 2.15
Switch {
id: control

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
@if %{UseQtQuickControls2}
import QtQuick.Controls 2.15
@@ -8,6 +15,11 @@ import %{ApplicationImport}
import FlowView 1.0
FlowItem {
@if %{UseImport}
width: Constants.width
height: Constants.height
@else
width: 800
height: 600
@endif
}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
@if %{UseImport}
import %{ApplicationImport}
@@ -5,8 +12,13 @@ import %{ApplicationImport}
import FlowView 1.0
FlowView {
@if %{UseImport}
width: Constants.width
height: Constants.height
@else
width: 800
height: 600
@endif
defaultTransition: FlowTransition {
id: defaultTransition

View File

@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import %{ApplicationImport}
Pane {

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
GridView {

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
Item {

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
ListView {

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
@if %{UseQtQuickControls2}
import QtQuick.Controls 2.15

View File

@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import %{ApplicationImport}
Item {

View File

@@ -1,6 +1,6 @@
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
import %{ApplicationImport}
Item {

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import QtQuick3D %{QtQuick3DVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick 2.15
import Constants 1.0

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -1,3 +1,10 @@
/*
This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only.
It is supposed to be strictly declarative and only uses a subset of QML. If you edit
this file manually, you might introduce QML code that is not supported by Qt Design Studio.
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
import QtQuick %{QtQuickVersion}
import QtQuick.Controls %{QtQuickVersion}
import %{ImportModuleName} %{ImportModuleVersion}

View File

@@ -438,6 +438,7 @@ bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled)
// Optional arguments to pass to the handler
std::vector<std::string> arguments;
arguments.push_back("--no-rate-limit");
CrashpadClient *client = new CrashpadClient();
bool success = client->StartHandler(

View File

@@ -723,8 +723,10 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
}
value = pluginMetaData.value(QLatin1String(PLUGIN_METADATA));
if (!value.isObject())
return reportError(tr("Plugin meta data not found"));
if (!value.isObject()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Plugin meta data not found"));
}
metaData = value.toObject();
value = metaData.value(QLatin1String(PLUGIN_NAME));
@@ -806,9 +808,11 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
const QString platformSpec = value.toString().trimmed();
if (!platformSpec.isEmpty()) {
platformSpecification.setPattern(platformSpec);
if (!platformSpecification.isValid())
return reportError(tr("Invalid platform specification \"%1\": %2")
.arg(platformSpec, platformSpecification.errorString()));
if (!platformSpecification.isValid()) {
return reportError(::ExtensionSystem::Internal::PluginSpecPrivate::tr(
"Invalid platform specification \"%1\": %2")
.arg(platformSpec, platformSpecification.errorString()));
}
}
value = metaData.value(QLatin1String(DEPENDENCIES));
@@ -822,22 +826,36 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
QJsonObject dependencyObject = v.toObject();
PluginDependency dep;
value = dependencyObject.value(QLatin1String(DEPENDENCY_NAME));
if (value.isUndefined())
return reportError(tr("Dependency: %1").arg(msgValueMissing(DEPENDENCY_NAME)));
if (!value.isString())
return reportError(tr("Dependency: %1").arg(msgValueIsNotAString(DEPENDENCY_NAME)));
if (value.isUndefined()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Dependency: %1")
.arg(msgValueMissing(DEPENDENCY_NAME)));
}
if (!value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Dependency: %1")
.arg(msgValueIsNotAString(DEPENDENCY_NAME)));
}
dep.name = value.toString();
value = dependencyObject.value(QLatin1String(DEPENDENCY_VERSION));
if (!value.isUndefined() && !value.isString())
return reportError(tr("Dependency: %1").arg(msgValueIsNotAString(DEPENDENCY_VERSION)));
if (!value.isUndefined() && !value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Dependency: %1")
.arg(msgValueIsNotAString(DEPENDENCY_VERSION)));
}
dep.version = value.toString();
if (!isValidVersion(dep.version))
return reportError(tr("Dependency: %1").arg(msgInvalidFormat(DEPENDENCY_VERSION,
dep.version)));
if (!isValidVersion(dep.version)) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Dependency: %1")
.arg(msgInvalidFormat(DEPENDENCY_VERSION, dep.version)));
}
dep.type = PluginDependency::Required;
value = dependencyObject.value(QLatin1String(DEPENDENCY_TYPE));
if (!value.isUndefined() && !value.isString())
return reportError(tr("Dependency: %1").arg(msgValueIsNotAString(DEPENDENCY_TYPE)));
if (!value.isUndefined() && !value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Dependency: %1")
.arg(msgValueIsNotAString(DEPENDENCY_TYPE)));
}
if (!value.isUndefined()) {
const QString typeValue = value.toString();
if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_HARD)) {
@@ -847,11 +865,13 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
} else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_TEST)) {
dep.type = PluginDependency::Test;
} else {
return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\").")
.arg(QLatin1String(DEPENDENCY_TYPE),
QLatin1String(DEPENDENCY_TYPE_HARD),
QLatin1String(DEPENDENCY_TYPE_SOFT),
typeValue));
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr(
"Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\").")
.arg(QLatin1String(DEPENDENCY_TYPE),
QLatin1String(DEPENDENCY_TYPE_HARD),
QLatin1String(DEPENDENCY_TYPE_SOFT),
typeValue));
}
}
dependencies.append(dep);
@@ -869,20 +889,35 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
QJsonObject argumentObject = v.toObject();
PluginArgumentDescription arg;
value = argumentObject.value(QLatin1String(ARGUMENT_NAME));
if (value.isUndefined())
return reportError(tr("Argument: %1").arg(msgValueMissing(ARGUMENT_NAME)));
if (!value.isString())
return reportError(tr("Argument: %1").arg(msgValueIsNotAString(ARGUMENT_NAME)));
if (value.isUndefined()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Argument: %1")
.arg(msgValueMissing(ARGUMENT_NAME)));
}
if (!value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Argument: %1")
.arg(msgValueIsNotAString(ARGUMENT_NAME)));
}
arg.name = value.toString();
if (arg.name.isEmpty())
return reportError(tr("Argument: \"%1\" is empty").arg(QLatin1String(ARGUMENT_NAME)));
if (arg.name.isEmpty()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Argument: \"%1\" is empty")
.arg(QLatin1String(ARGUMENT_NAME)));
}
value = argumentObject.value(QLatin1String(ARGUMENT_DESCRIPTION));
if (!value.isUndefined() && !value.isString())
return reportError(tr("Argument: %1").arg(msgValueIsNotAString(ARGUMENT_DESCRIPTION)));
if (!value.isUndefined() && !value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Argument: %1")
.arg(msgValueIsNotAString(ARGUMENT_DESCRIPTION)));
}
arg.description = value.toString();
value = argumentObject.value(QLatin1String(ARGUMENT_PARAMETER));
if (!value.isUndefined() && !value.isString())
return reportError(tr("Argument: %1").arg(msgValueIsNotAString(ARGUMENT_PARAMETER)));
if (!value.isUndefined() && !value.isString()) {
return reportError(
::ExtensionSystem::Internal::PluginSpecPrivate::tr("Argument: %1")
.arg(msgValueIsNotAString(ARGUMENT_PARAMETER)));
}
arg.parameter = value.toString();
argumentDescriptions.append(arg);
qCDebug(pluginLog) << "Argument:" << arg.name << "Parameter:" << arg.parameter

View File

@@ -35,6 +35,7 @@
#include <utils/variant.h> // revert when macos minimum target is >= 10.14
#include <chrono>
#include <string>
#include <vector>

View File

@@ -34,7 +34,6 @@ add_qtc_library(Utils
differ.cpp differ.h
displayname.cpp displayname.h
dropsupport.cpp dropsupport.h
dynamiclicensecheck.h
elfreader.cpp elfreader.h
elidinglabel.cpp elidinglabel.h
environment.cpp environment.h

View File

@@ -1,5 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
@@ -752,48 +753,6 @@ QString AndroidConfig::getAvdName(const QString &serialnumber)
return QString::fromLatin1(name).trimmed();
}
static SdkToolResult emulatorNameAdbCommand(const QString &serialNumber)
{
QStringList args = AndroidDeviceInfo::adbSelector(serialNumber);
args.append({"emu", "avd", "name"});
return AndroidManager::runAdbCommand(args);
}
QString AndroidConfig::getRunningAvdsSerialNumber(const QString &name) const
{
for (const AndroidDeviceInfo &dev : connectedDevices()) {
if (!dev.serialNumber.startsWith("emulator"))
continue;
SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber);
const QString stdOut = result.stdOut();
if (stdOut.isEmpty())
continue; // Not an avd
const QStringList outputLines = stdOut.split('\n');
if (outputLines.size() > 1 && outputLines.first() == name)
return dev.serialNumber;
}
return {};
}
QStringList AndroidConfig::getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs)
{
QStringList runningDevs;
for (const AndroidDeviceInfo &dev : devs) {
if (!dev.serialNumber.startsWith("emulator"))
continue;
SdkToolResult result = emulatorNameAdbCommand(dev.serialNumber);
const QString stdOut = result.stdOut();
if (stdOut.isEmpty())
continue; // Not an avd
const QStringList outputLines = stdOut.split('\n');
if (outputLines.size() > 1)
runningDevs.append(outputLines.first());
}
return runningDevs;
}
AndroidConfig::OpenGl AndroidConfig::getOpenGLEnabled(const QString &emulator) const
{
QDir dir = QDir::home();

View File

@@ -1,5 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
@@ -176,15 +177,12 @@ public:
static Utils::FilePath getJdkPath();
static QStringList getAbis(const QString &device);
QString getRunningAvdsSerialNumber(const QString &name) const;
static QStringList getRunningAvdsFromDevices(const QVector<AndroidDeviceInfo> &devs);
static int getSDKVersion(const QString &device);
private:
static QString getDeviceProperty(const QString &device, const QString &property);
Utils::FilePath openJDKBinPath() const;
static int getSDKVersion(const QString &device);
static QString getAvdName(const QString &serialnumber);
void parseDependenciesJson();

View File

@@ -182,7 +182,7 @@ bool AndroidDeployQtStep::init()
return false;
}
if (!dev->canSupportAbis(selectedAbis)) {
if (!selectedAbis.isEmpty() && !dev->canSupportAbis(selectedAbis)) {
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\".")

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
@@ -52,6 +52,10 @@
#include <QLoggingCategory>
#include <QMessageBox>
#include <QPushButton>
#include <QTimer>
#include <QRegularExpression>
#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
@@ -59,9 +63,6 @@ namespace {
static Q_LOGGING_CATEGORY(androidDeviceLog, "qtc.android.androiddevice", QtWarningMsg)
}
// interval for updating the list of connected Android devices and emulators
constexpr int deviceUpdaterMsInterval = 30000;
namespace Android {
namespace Internal {
@@ -328,7 +329,7 @@ QString AndroidDevice::serialNumber() const
if (machineType() == Hardware)
return serialNumber;
return AndroidConfigurations::currentConfig().getRunningAvdsSerialNumber(avdName());
return AndroidDeviceManager::instance()->getRunningAvdsSerialNumber(avdName());
}
QString AndroidDevice::avdName() const
@@ -419,36 +420,28 @@ QUrl AndroidDevice::toolControlChannel(const ControlChannelHint &) const
return url;
}
void AndroidDeviceManager::updateDevicesList()
void AndroidDeviceManager::updateAvdsList()
{
// If a non-Android Kit is currently active, skip the device list update
const Target *startupTarget = SessionManager::startupTarget();
if (!startupTarget)
return;
const Kit *kit = startupTarget->kit();
if (!kit)
return;
if (DeviceTypeKitAspect::deviceTypeId(kit) != Constants::ANDROID_DEVICE_TYPE)
return;
updateDevicesListOnce();
}
void AndroidDeviceManager::updateDevicesListOnce()
{
if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists()) {
if (!m_avdsFutureWatcher.isRunning() && m_androidConfig.adbToolPath().exists())
m_avdsFutureWatcher.setFuture(m_avdManager.avdList());
m_devicesFutureWatcher.setFuture(Utils::runAsync([this]() {
return m_androidConfig.connectedDevices();
}));
}
}
void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::Ptr &device)
IDevice::DeviceState AndroidDeviceManager::getDeviceState(const QString &serial,
IDevice::MachineType type) const
{
const AndroidDevice *dev = static_cast<AndroidDevice *>(device.data());
const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo 1";
const SdkToolResult result = AndroidManager::runAdbCommand(args);
if (result.success())
return IDevice::DeviceReadyToUse;
else if (type == IDevice::Emulator || result.stdErr().contains("unauthorized"))
return IDevice::DeviceConnected;
return IDevice::DeviceDisconnected;
}
void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device)
{
const AndroidDevice *dev = static_cast<const AndroidDevice *>(device.data());
const QString serial = dev->serialNumber();
DeviceManager *const devMgr = DeviceManager::instance();
const Utils::Id id = dev->id();
@@ -457,15 +450,7 @@ void AndroidDeviceManager::updateDeviceState(const ProjectExplorer::IDevice::Ptr
return;
}
const QStringList args = AndroidDeviceInfo::adbSelector(serial) << "shell" << "echo" << "1";
const SdkToolResult result = AndroidManager::runAdbCommand(args);
const int success = result.success();
if (success)
devMgr->setDeviceState(id, IDevice::DeviceReadyToUse);
else if (dev->machineType() == IDevice::Emulator || result.stdErr().contains("unauthorized"))
devMgr->setDeviceState(id, IDevice::DeviceConnected);
else
devMgr->setDeviceState(id, IDevice::DeviceDisconnected);
devMgr->setDeviceState(id, getDeviceState(serial, dev->machineType()));
}
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent)
@@ -523,6 +508,13 @@ void AndroidDeviceManager::handleAvdRemoved()
}
}
QString AndroidDeviceManager::emulatorName(const QString &serialNumber) const
{
QStringList args = AndroidDeviceInfo::adbSelector(serialNumber);
args.append({"emu", "avd", "name"});
return AndroidManager::runAdbCommand(args).stdOut();
}
void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
{
const QString helpUrl =
@@ -546,73 +538,122 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
m_androidConfig.setEmulatorArgs(Utils::ProcessArgs::splitArgs(dialog.textValue()));
}
void AndroidDeviceManager::setupDevicesWatcher()
QString AndroidDeviceManager::getRunningAvdsSerialNumber(const QString &name) const
{
if (!m_devicesUpdaterTimer.isActive()) {
// The call to avdmanager is always slower than the call to adb devices,
// so connecting the slot to the slower call should be enough.
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
this, &AndroidDeviceManager::devicesListUpdated);
connect(&m_devicesUpdaterTimer, &QTimer::timeout, this, [this]() {
updateDevicesList();
});
m_devicesUpdaterTimer.start(deviceUpdaterMsInterval);
for (const AndroidDeviceInfo &dev : m_androidConfig.connectedDevices()) {
if (!dev.serialNumber.startsWith("emulator"))
continue;
const QString stdOut = emulatorName(dev.serialNumber);
if (stdOut.isEmpty())
continue; // Not an avd
const QStringList outputLines = stdOut.split('\n');
if (outputLines.size() > 1 && outputLines.first() == name)
return dev.serialNumber;
}
updateDevicesListOnce();
return {};
}
void AndroidDeviceManager::devicesListUpdated()
void AndroidDeviceManager::setupDevicesWatcher()
{
QVector<AndroidDeviceInfo> connectedDevicesInfos;
connectedDevicesInfos = m_devicesFutureWatcher.result();
// For checking the state of avds, since running avds are assigned a serial number of
// the form emulator-xxxx, thus we have to manually check for the names.
const QStringList runningAvds = m_androidConfig.getRunningAvdsFromDevices(connectedDevicesInfos);
AndroidDeviceInfoList devices = m_avdsFutureWatcher.result();
const QSet<QString> startedAvds = Utils::transform<QSet>(connectedDevicesInfos,
&AndroidDeviceInfo::avdname);
for (const AndroidDeviceInfo &dev : devices)
if (!startedAvds.contains(dev.avdname))
connectedDevicesInfos << dev;
DeviceManager *const devMgr = DeviceManager::instance();
QVector<IDevice::ConstPtr> existingDevs;
QVector<IDevice::ConstPtr> connectedDevs;
for (int i = 0; i < devMgr->deviceCount(); ++i) {
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
if (dev->id().toString().startsWith(Constants::ANDROID_DEVICE_ID)) {
existingDevs.append(dev);
}
if (!m_androidConfig.adbToolPath().exists()) {
qCDebug(androidDeviceLog) << "Cannot start ADB device watcher"
<< "because adb path does not exist.";
return;
}
for (auto item : connectedDevicesInfos) {
if (!m_adbDeviceWatcherProcess)
m_adbDeviceWatcherProcess.reset(new Utils::QtcProcess(this));
if (m_adbDeviceWatcherProcess->isRunning()) {
qCDebug(androidDeviceLog) << "ADB device watcher is already running.";
return;
}
connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::finished, this,
[]() { qCDebug(androidDeviceLog) << "ADB device watcher finished."; });
connect(m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::errorOccurred, this,
[this](QProcess::ProcessError) {
qCDebug(androidDeviceLog) << "ADB device watcher encountered an error:"
<< m_adbDeviceWatcherProcess->errorString();
if (!m_adbDeviceWatcherProcess->isRunning()) {
qCDebug(androidDeviceLog) << "Restarting the ADB device watcher now.";
QTimer::singleShot(0, m_adbDeviceWatcherProcess.get(), &Utils::QtcProcess::start);
}
});
m_adbDeviceWatcherProcess->setStdErrLineCallback([](const QString &error) {
qCDebug(androidDeviceLog) << "ADB device watcher error" << error; });
m_adbDeviceWatcherProcess->setStdOutLineCallback([this](const QString &output) {
HandleDevicesListChange(output);
});
const Utils::CommandLine command = Utils::CommandLine(m_androidConfig.adbToolPath(),
{"track-devices"});
m_adbDeviceWatcherProcess->setCommand(command);
m_adbDeviceWatcherProcess->setEnvironment(AndroidConfigurations::toolsEnvironment(m_androidConfig));
m_adbDeviceWatcherProcess->start();
// Setup AVD filesystem watcher to listen for changes when an avd is created/deleted,
// or started/stopped
QString avdEnvVar = qEnvironmentVariable("ANDROID_AVD_HOME");
if (avdEnvVar.isEmpty()) {
avdEnvVar = qEnvironmentVariable("ANDROID_SDK_HOME");
if (avdEnvVar.isEmpty())
avdEnvVar = qEnvironmentVariable("HOME");
avdEnvVar.append("/.android/avd");
}
const Utils::FilePath avdPath = Utils::FilePath::fromUserInput(avdEnvVar);
m_avdFileSystemWatcher.addPath(avdPath.toString());
connect(&m_avdsFutureWatcher, &QFutureWatcherBase::finished,
this, &AndroidDeviceManager::HandleAvdsListChange);
connect(&m_avdFileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, [this]() {
// If the avd list upate command is running no need to call it again.
if (!m_avdsFutureWatcher.isRunning())
updateAvdsList();
});
// Call initial update
updateAvdsList();
}
void AndroidDeviceManager::HandleAvdsListChange()
{
DeviceManager *const devMgr = DeviceManager::instance();
QVector<IDevice::ConstPtr> existingAvds;
for (int i = 0; i < devMgr->deviceCount(); ++i) {
const IDevice::ConstPtr dev = devMgr->deviceAt(i);
const bool isEmulator = dev->machineType() == IDevice::Emulator;
if (isEmulator && dev->type() == Constants::ANDROID_DEVICE_TYPE)
existingAvds.append(dev);
}
QVector<IDevice::ConstPtr> connectedDevs;
for (auto item : m_avdsFutureWatcher.result()) {
const Utils::Id deviceId = AndroidDevice::idFromDeviceInfo(item);
const QString displayName = AndroidDevice::displayNameFromInfo(item);
IDevice::ConstPtr dev = devMgr->find(deviceId);
if (!dev.isNull()) {
if (dev->displayName() == displayName) {
IDevice::DeviceState newState;
// If an AVD is not already running set its state to Connected instead of
// ReadyToUse.
if (dev->machineType() == IDevice::Emulator && !runningAvds.contains(displayName))
newState = IDevice::DeviceConnected;
else
newState = item.state;
if (dev->deviceState() != newState) {
const auto androidDev = static_cast<const AndroidDevice *>(dev.data());
// DeviceManager doens't seem to hav a way to directly update the name, if the name
// of the device has changed, remove it and register it again with the new name.
// Also account for the case of an AVD registered through old QC which might have
// invalid data by checking the sdcard size value.
if (dev->displayName() != displayName
|| androidDev->sdcardSize() == AndroidDevice::tr("Unknown")) {
devMgr->removeDevice(dev->id());
} else {
// Find the state of the AVD retrieved from the AVD watcher
const QString serial = getRunningAvdsSerialNumber(item.avdname);
const IDevice::DeviceState state = getDeviceState(serial, IDevice::Emulator);
if (dev->deviceState() != state) {
devMgr->setDeviceState(dev->id(), state);
qCDebug(androidDeviceLog, "Device id \"%s\" changed its state.",
dev->id().toString().toUtf8().data());
devMgr->setDeviceState(dev->id(), newState);
}
connectedDevs.append(dev);
continue;
} else {
// DeviceManager doens't seem to hav a way to directly update the name, if the name
// of the device has changed, remove it and register it again with the new name.
devMgr->removeDevice(dev->id());
}
}
@@ -625,17 +666,86 @@ void AndroidDeviceManager::devicesListUpdated()
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
newDev->id().toString().toUtf8().data());
const IDevice::ConstPtr constNewDev = IDevice::ConstPtr(newDev);
devMgr->addDevice(constNewDev);
devMgr->addDevice(IDevice::ConstPtr(constNewDev));
connectedDevs.append(constNewDev);
}
// Set devices no longer connected to disconnected state.
for (const IDevice::ConstPtr &dev : existingDevs) {
if (dev->id() != Constants::ANDROID_DEVICE_ID && !connectedDevs.contains(dev)
&& dev->deviceState() != IDevice::DeviceDisconnected) {
qCDebug(androidDeviceLog, "Device id \"%s\" is no longer connected.",
dev->id().toString().toUtf8().data());
devMgr->setDeviceState(dev->id(), IDevice::DeviceDisconnected);
// Set devices no longer connected to disconnected state.
for (const IDevice::ConstPtr &dev : existingAvds) {
if (!connectedDevs.contains(dev)) {
qCDebug(androidDeviceLog, "Removing AVD id \"%s\" because it no longer exists.",
dev->id().toString().toUtf8().data());
devMgr->removeDevice(dev->id());
}
}
}
}
void AndroidDeviceManager::HandleDevicesListChange(const QString &serialNumber)
{
DeviceManager *const devMgr = DeviceManager::instance();
const QStringList serialBits = serialNumber.split('\t');
if (serialBits.size() < 2)
return;
// Sample output of adb track-devices, the first 4 digits are for state type
// and sometimes 4 zeros are reported as part for the serial number.
// 00546db0e8d7 authorizing
// 00546db0e8d7 device
// 0000001711201JEC207789 offline
// emulator-5554 device
QString dirtySerial = serialBits.first().trimmed();
if (dirtySerial.startsWith("0000"))
dirtySerial = dirtySerial.mid(4);
if (dirtySerial.startsWith("00"))
dirtySerial = dirtySerial.mid(4);
const bool isEmulator = dirtySerial.startsWith("emulator");
const QString &serial = dirtySerial;
const QString stateStr = serialBits.at(1).trimmed();
IDevice::DeviceState state;
if (stateStr == "device")
state = IDevice::DeviceReadyToUse;
else if (stateStr == "offline")
state = IDevice::DeviceDisconnected;
else
state = IDevice::DeviceConnected;
if (isEmulator) {
const QString avdName = emulatorName(serial);
const Utils::Id avdId = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + avdName);
devMgr->setDeviceState(avdId, state);
} else {
const Utils::Id id = Utils::Id(Constants::ANDROID_DEVICE_ID).withSuffix(':' + serial);
QString displayName = AndroidConfigurations::currentConfig().getProductModel(serial);
// Check if the device is connected via WiFi. A sample serial of such devices can be
// like: "192.168.1.190:5555"
const QRegularExpression wifiSerialRegExp(
QLatin1String("(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d{1,5})"));
if (wifiSerialRegExp.match(serial).hasMatch())
displayName += QLatin1String(" (WiFi)");
if (IDevice::ConstPtr dev = devMgr->find(id)) {
// DeviceManager doens't seem to have a way to directly update the name, if the name
// of the device has changed, remove it and register it again with the new name.
if (dev->displayName() == displayName)
devMgr->setDeviceState(id, state);
else
devMgr->removeDevice(id);
} else {
AndroidDevice *newDev = new AndroidDevice();
newDev->setupId(IDevice::AutoDetected, id);
newDev->setDisplayName(displayName);
newDev->setMachineType(IDevice::Hardware);
newDev->setDeviceState(state);
newDev->setExtraData(Constants::AndroidSerialNumber, serial);
newDev->setExtraData(Constants::AndroidCpuAbi, m_androidConfig.getAbis(serial));
newDev->setExtraData(Constants::AndroidSdk, m_androidConfig.getSDKVersion(serial));
qCDebug(androidDeviceLog, "Registering new Android device id \"%s\".",
newDev->id().toString().toUtf8().data());
devMgr->addDevice(IDevice::ConstPtr(newDev));
}
}
}
@@ -652,9 +762,12 @@ AndroidDeviceManager::AndroidDeviceManager(QObject *parent)
m_avdManager(m_androidConfig)
{
connect(qApp, &QCoreApplication::aboutToQuit, this, [this]() {
m_devicesUpdaterTimer.stop();
if (m_adbDeviceWatcherProcess) {
m_adbDeviceWatcherProcess->terminate();
m_adbDeviceWatcherProcess->waitForFinished();
m_adbDeviceWatcherProcess.reset();
}
m_avdsFutureWatcher.waitForFinished();
m_devicesFutureWatcher.waitForFinished();
m_removeAvdFutureWatcher.waitForFinished();
});

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Copyright (C) 2022 The Qt Company Ltd.
** Copyright (C) 2016 BogDan Vatra <bog_dan_ro@yahoo.com>
** Contact: https://www.qt.io/licensing/
**
@@ -33,8 +33,10 @@
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/devicesupport/idevicefactory.h>
#include <utils/qtcprocess.h>
#include <QFutureWatcher>
#include <QTimer>
#include <QFileSystemWatcher>
namespace Android {
namespace Internal {
@@ -70,6 +72,7 @@ public:
QString androidTargetName() const;
QString sdcardSize() const;
QString openGlStatusString() const;
// TODO: remove not used
AndroidConfig::OpenGl openGlStatus() const;
protected:
@@ -98,24 +101,29 @@ class AndroidDeviceManager : public QObject
public:
static AndroidDeviceManager *instance();
void setupDevicesWatcher();
void updateDevicesList();
void updateDevicesListOnce();
void updateDeviceState(const ProjectExplorer::IDevice::Ptr &device);
void updateAvdsList();
IDevice::DeviceState getDeviceState(const QString &serial, IDevice::MachineType type) const;
void updateDeviceState(const ProjectExplorer::IDevice::ConstPtr &device);
void startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
void setEmulatorArguments(QWidget *parent = nullptr);
QString getRunningAvdsSerialNumber(const QString &name) const;
private:
AndroidDeviceManager(QObject *parent = nullptr);
void devicesListUpdated();
void HandleDevicesListChange(const QString &serialNumber);
void HandleAvdsListChange();
void handleAvdRemoved();
QString emulatorName(const QString &serialNumber) const;
QFutureWatcher<AndroidDeviceInfoList> m_avdsFutureWatcher;
QFutureWatcher<QVector<AndroidDeviceInfo>> m_devicesFutureWatcher;
QFutureWatcher<QPair<ProjectExplorer::IDevice::ConstPtr, bool>> m_removeAvdFutureWatcher;
QTimer m_devicesUpdaterTimer;
QFileSystemWatcher m_avdFileSystemWatcher;
std::unique_ptr<Utils::QtcProcess> m_adbDeviceWatcherProcess;
AndroidConfig &m_androidConfig;
AndroidAvdManager m_avdManager;
};

View File

@@ -2779,6 +2779,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
|| path.rbegin()->kind() == "CXXConstruct")) {
return false;
}
if (path.rbegin()->hasConstType())
return false;
for (auto it = path.rbegin() + 1; it != path.rend(); ++it) {
if (it->kind() == "Call" || it->kind() == "CXXConstruct"
|| it->kind() == "MemberInitializer") {
@@ -2810,8 +2812,9 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
const AstNode n = firstChildTree.takeFirst();
const QString detail = n.detail().value_or(QString());
if (detail.startsWith("operator")) {
return !detail.contains('=') && !detail.contains("++")
&& !detail.contains("--");
return !detail.contains('=')
&& !detail.contains("++") && !detail.contains("--")
&& !detail.contains("<<") && !detail.contains(">>");
}
firstChildTree << n.children().value_or(QList<AstNode>());
}
@@ -4122,7 +4125,7 @@ class MemoryTreeModel : public Utils::BaseTreeModel
public:
MemoryTreeModel(QObject *parent) : BaseTreeModel(parent)
{
setHeader({tr("Component"), tr("Total Memory")});
setHeader({MemoryUsageWidget::tr("Component"), MemoryUsageWidget::tr("Total Memory")});
}
void update(const MemoryTree &tree)

View File

@@ -1295,6 +1295,13 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("keywords: true") << 920 << 15 << 920 << 19 << QList<int>{C_KEYWORD} << 0;
QTest::newRow("keywords: false") << 921 << 15 << 921 << 20 << QList<int>{C_KEYWORD} << 0;
QTest::newRow("keywords: nullptr") << 922 << 15 << 922 << 22 << QList<int>{C_KEYWORD} << 0;
QTest::newRow("operator<<") << 934 << 10 << 934 << 14 << QList<int>{C_GLOBAL} << 0;
QTest::newRow("operator>>") << 936 << 10 << 936 << 13 << QList<int>{C_GLOBAL} << 0;
QTest::newRow("operator>>") << 936 << 17 << 936 << 18 << QList<int>{C_LOCAL} << 0;
QTest::newRow("input arg from passed object") << 945 << 17 << 945 << 18
<< QList<int>{C_FIELD} << 0;
QTest::newRow("output arg") << 945 << 20 << 945 << 23
<< QList<int>{C_LOCAL, C_OUTPUT_ARGUMENT} << 0;
}
void ClangdTestHighlighting::test()

View File

@@ -921,3 +921,26 @@ void keywords()
bool b2 = false;
void *p = nullptr;
}
namespace std {
struct Debug {};
Debug& operator<<(Debug &dbg, int) { return dbg; }
Debug& operator>>(Debug &dbg, int&) { return dbg; }
static Debug cout;
static Debug cin;
}
void outputOperator()
{
std::cout << 0;
int i;
std::cin >> i;
}
template <typename To, typename From, typename Op>
void transform(const From &from, To &&to, Op op) {}
struct WithVector { std::vector<int> v; };
void inputsAndOutputsFromObject(const WithVector &s)
{
std::vector<int> out;
transform(s.v, out, [] {});
}

View File

@@ -268,7 +268,7 @@ bool ConfigModel::hasChanges(bool initialParameters) const
return initialParameters ? i.isInitial : !i.isInitial;
});
return Utils::contains(filtered, [initialParameters](const InternalDataItem &i) {
return Utils::contains(filtered, [](const InternalDataItem &i) {
return i.isUserChanged || i.isUserNew || i.isUnset;
});
}

View File

@@ -40,7 +40,6 @@
#include <utils/qtcassert.h>
#include <utils/settingsutils.h>
static const char groupPostfix[] = "IndentSettings";
static const char indentBlockBracesKey[] = "IndentBlockBraces";
static const char indentBlockBodyKey[] = "IndentBlockBody";
static const char indentClassBracesKey[] = "IndentClassBraces";

View File

@@ -276,8 +276,6 @@ void ImageView::doScale(qreal factor)
void ImageView::wheelEvent(QWheelEvent *event)
{
qreal factor = qPow(Constants::DEFAULT_SCALE_FACTOR, event->angleDelta().y() / 240.0);
qreal currentScale = transform().m11();
qreal newScale = currentScale * factor;
// cap to 0.001 - 1000
qreal actualFactor = qBound(0.001, factor, 1000.0);
doScale(actualFactor);

View File

@@ -622,7 +622,7 @@ void Client::activateDocument(TextEditor::TextDocument *document)
void Client::deactivateDocument(TextEditor::TextDocument *document)
{
m_diagnosticManager.hideDiagnostics(document);
m_diagnosticManager.hideDiagnostics(document->filePath());
resetAssistProviders(document);
document->setFormatter(nullptr);
m_tokenSupport.clearHighlight(document);
@@ -1628,12 +1628,8 @@ void Client::shutDownCallback(const ShutdownRequest::Response &shutdownResponse)
m_shutdownTimer.stop();
QTC_ASSERT(m_state == ShutdownRequested, return);
QTC_ASSERT(m_clientInterface, return);
optional<ShutdownRequest::Response::Error> errorValue = shutdownResponse.error();
if (errorValue.has_value()) {
ShutdownRequest::Response::Error error = errorValue.value();
qDebug() << error;
return;
}
if (optional<ShutdownRequest::Response::Error> error = shutdownResponse.error())
log(*error);
// directly send message otherwise the state check of sendContent would fail
sendMessage(ExitNotification().toBaseMessage());
qCDebug(LOGLSPCLIENT) << "language server " << m_displayName << " shutdown";

View File

@@ -88,26 +88,19 @@ void DiagnosticManager::setDiagnostics(const LanguageServerProtocol::DocumentUri
const QList<LanguageServerProtocol::Diagnostic> &diagnostics,
const Utils::optional<int> &version)
{
removeDiagnostics(uri);
hideDiagnostics(uri.toFilePath());
m_diagnostics[uri] = {version, diagnostics};
}
void DiagnosticManager::hideDiagnostics(TextDocument *doc)
void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath)
{
if (!doc)
return;
if (m_hideHandler)
m_hideHandler();
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
editor->editorWidget()->setExtraSelections(TextEditorWidget::CodeWarningsSelection, {});
qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextMark::category, m_client->id())));
}
void DiagnosticManager::removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri)
{
hideDiagnostics(TextDocument::textDocumentForFilePath(uri.toFilePath()));
m_diagnostics.remove(uri);
if (auto doc = TextDocument::textDocumentForFilePath(filePath)) {
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
editor->editorWidget()->setExtraSelections(TextEditorWidget::CodeWarningsSelection, {});
}
qDeleteAll(m_marks.take(filePath));
}
static QTextEdit::ExtraSelection toDiagnosticsSelections(const Diagnostic &diagnostic,
@@ -130,11 +123,11 @@ void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version)
const FilePath &filePath = uri.toFilePath();
if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) {
QList<QTextEdit::ExtraSelection> extraSelections;
const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri);
const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri);
if (versionedDiagnostics.version.value_or(version) == version) {
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
extraSelections << toDiagnosticsSelections(diagnostic, doc->document());
doc->addMark(m_textMarkCreator(filePath, diagnostic));
m_marks[filePath].append(m_textMarkCreator(filePath, diagnostic));
}
}
@@ -164,7 +157,13 @@ TextEditor::TextMark *DiagnosticManager::createTextMark(const FilePath &filePath
void DiagnosticManager::clearDiagnostics()
{
for (const DocumentUri &uri : m_diagnostics.keys())
removeDiagnostics(uri);
hideDiagnostics(uri.toFilePath());
m_diagnostics.clear();
if (!QTC_GUARD(m_marks.isEmpty())) {
for (const QList<TextEditor::TextMark *> &marks : qAsConst(m_marks))
qDeleteAll(marks);
m_marks.clear();
}
}
QList<Diagnostic> DiagnosticManager::diagnosticsAt(const DocumentUri &uri,

View File

@@ -56,10 +56,9 @@ public:
void setDiagnostics(const LanguageServerProtocol::DocumentUri &uri,
const QList<LanguageServerProtocol::Diagnostic> &diagnostics,
const Utils::optional<int> &version);
void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri, int version);
void hideDiagnostics(TextEditor::TextDocument *doc);
void hideDiagnostics(const Utils::FilePath &filePath);
void clearDiagnostics();
@@ -81,6 +80,7 @@ private:
QList<LanguageServerProtocol::Diagnostic> diagnostics;
};
QMap<LanguageServerProtocol::DocumentUri, VersionedDiagnostics> m_diagnostics;
QMap<Utils::FilePath, QList<TextEditor::TextMark *>> m_marks;
TextMarkCreator m_textMarkCreator;
HideDiagnosticsHandler m_hideHandler;
Client *m_client;

View File

@@ -427,7 +427,7 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse(
items = Utils::get<QList<CompletionItem>>(*result);
}
auto proposalItems = generateCompletionItems(items);
if (!proposalItems.isEmpty() && !m_snippetsGroup.isEmpty()) {
if (!m_snippetsGroup.isEmpty()) {
proposalItems << TextEditor::SnippetAssistCollector(
m_snippetsGroup, QIcon(":/texteditor/images/snippet.png")).collect();
}

View File

@@ -45,22 +45,22 @@ public:
ValidPackage
};
virtual QString label() const = 0;
virtual const QString &environmentVariableName() const = 0;
virtual bool isAddToSystemPath() const = 0;
virtual void setVersions(const QStringList &) = 0;
virtual Utils::FilePath basePath() const = 0;
virtual Utils::FilePath path() const = 0;
virtual QString label() const = 0;
virtual Utils::FilePath defaultPath() const = 0;
virtual QString detectionPath() const = 0;
virtual QString statusText() const = 0;
virtual void updateStatus() = 0;
virtual Utils::FilePath detectionPath() const = 0;
virtual void updateStatus() = 0;
virtual Status status() const = 0;
virtual bool validStatus() const = 0;
virtual const QString &environmentVariableName() const = 0;
virtual void setAddToPath(bool) = 0;
virtual bool addToPath() const = 0;
virtual QString statusText() const = 0;
virtual bool isValidStatus() const = 0;
virtual bool writeToSettings() const = 0;
virtual void setRelativePathModifier(const QString &) = 0;
virtual void setVersions(const QStringList &) = 0;
virtual QWidget *widget() = 0;

View File

@@ -57,30 +57,21 @@ namespace McuKitManager {
static const int KIT_VERSION = 9; // Bumps up whenever details in Kit creation change
static FilePath qulDocsDir()
{
const FilePath qulDir = McuSupportOptions::qulDirFromSettings();
if (qulDir.isEmpty() || !qulDir.exists())
return {};
const FilePath docsDir = qulDir.pathAppended("docs");
return docsDir.exists() ? docsDir : FilePath();
}
static void setKitToolchains(Kit *k, const McuToolChainPackage *tcPackage)
{
switch (tcPackage->type()) {
case McuToolChainPackage::Type::Unsupported:
switch (tcPackage->toolchainType()) {
case McuToolChainPackage::ToolChainType::Unsupported:
return;
case McuToolChainPackage::Type::GHS:
case McuToolChainPackage::Type::GHSArm:
case McuToolChainPackage::ToolChainType::GHS:
case McuToolChainPackage::ToolChainType::GHSArm:
return; // No Green Hills toolchain, because support for it is missing.
case McuToolChainPackage::Type::IAR:
case McuToolChainPackage::Type::KEIL:
case McuToolChainPackage::Type::MSVC:
case McuToolChainPackage::Type::GCC:
case McuToolChainPackage::Type::ArmGcc:
case McuToolChainPackage::ToolChainType::IAR:
case McuToolChainPackage::ToolChainType::KEIL:
case McuToolChainPackage::ToolChainType::MSVC:
case McuToolChainPackage::ToolChainType::GCC:
case McuToolChainPackage::ToolChainType::ArmGcc:
ToolChainKitAspect::setToolChain(k,
tcPackage->toolChain(
ProjectExplorer::Constants::C_LANGUAGE_ID));
@@ -136,17 +127,17 @@ static void setKitDebugger(Kit *k, const McuToolChainPackage *tcPackage)
return;
}
switch (tcPackage->type()) {
case McuToolChainPackage::Type::Unsupported:
case McuToolChainPackage::Type::GHS:
case McuToolChainPackage::Type::GHSArm:
case McuToolChainPackage::Type::IAR:
switch (tcPackage->toolchainType()) {
case McuToolChainPackage::ToolChainType::Unsupported:
case McuToolChainPackage::ToolChainType::GHS:
case McuToolChainPackage::ToolChainType::GHSArm:
case McuToolChainPackage::ToolChainType::IAR:
return; // No Green Hills and IAR debugger, because support for it is missing.
case McuToolChainPackage::Type::KEIL:
case McuToolChainPackage::Type::MSVC:
case McuToolChainPackage::Type::GCC:
case McuToolChainPackage::Type::ArmGcc: {
case McuToolChainPackage::ToolChainType::KEIL:
case McuToolChainPackage::ToolChainType::MSVC:
case McuToolChainPackage::ToolChainType::GCC:
case McuToolChainPackage::ToolChainType::ArmGcc: {
const QVariant debuggerId = tcPackage->debuggerId();
if (debuggerId.isValid()) {
Debugger::DebuggerKitAspect::setDebugger(k, debuggerId);
@@ -168,11 +159,6 @@ 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 setKitDependencies(Kit *k,
const McuTarget *mcuTarget,
const McuAbstractPackage *qtForMCUsSdkPackage)
@@ -182,7 +168,7 @@ static void setKitDependencies(Kit *k,
auto processPackage = [&dependencies](const McuAbstractPackage *package) {
if (!package->environmentVariableName().isEmpty())
dependencies.append({package->environmentVariableName(),
QDir::toNativeSeparators(package->detectionPath())});
package->detectionPath().toUserOutput()});
};
for (auto package : mcuTarget->packages())
processPackage(package);
@@ -201,8 +187,8 @@ static void setKitCMakeOptions(Kit *k, const McuTarget *mcuTarget, const FilePat
CMakeConfig config = CMakeConfigurationKitAspect::configuration(k);
// CMake ToolChain file for ghs handles CMAKE_*_COMPILER autonomously
if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHS
&& mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHSArm) {
if (mcuTarget->toolChainPackage()->toolchainType() != McuToolChainPackage::ToolChainType::GHS
&& mcuTarget->toolChainPackage()->toolchainType() != McuToolChainPackage::ToolChainType::GHSArm) {
config.append(CMakeConfigItem("CMAKE_CXX_COMPILER", "%{Compiler:Executable:Cxx}"));
config.append(CMakeConfigItem("CMAKE_C_COMPILER", "%{Compiler:Executable:C}"));
}
@@ -240,8 +226,8 @@ static void setKitCMakeOptions(Kit *k, const McuTarget *mcuTarget, const FilePat
CMakeConfigurationKitAspect::setConfiguration(k, config);
if (HostOsInfo::isWindowsHost()) {
auto type = mcuTarget->toolChainPackage()->type();
if (type == McuToolChainPackage::Type::GHS || type == McuToolChainPackage::Type::GHSArm) {
auto type = mcuTarget->toolChainPackage()->toolchainType();
if (type == McuToolChainPackage::ToolChainType::GHS || type == McuToolChainPackage::ToolChainType::GHSArm) {
// See https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565802&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565802
// and https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565803&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565803
CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM");
@@ -389,13 +375,12 @@ void createAutomaticKits()
const auto createKits = [qtForMCUsPackage]() {
if (McuSupportOptions::automaticKitCreationFromSettings()) {
qtForMCUsPackage->updateStatus();
if (!qtForMCUsPackage->validStatus()) {
if (!qtForMCUsPackage->isValidStatus()) {
switch (qtForMCUsPackage->status()) {
case McuAbstractPackage::Status::ValidPathInvalidPackage: {
const QString displayPath
= FilePath::fromString(qtForMCUsPackage->detectionPath()).toUserOutput();
printMessage(McuPackage::tr("Path %1 exists, but does not contain %2.")
.arg(qtForMCUsPackage->path().toUserOutput(), displayPath),
.arg(qtForMCUsPackage->path().toUserOutput(),
qtForMCUsPackage->detectionPath().toUserOutput()),
true);
break;
}
@@ -408,7 +393,7 @@ void createAutomaticKits()
}
case McuAbstractPackage::Status::EmptyPath: {
printMessage(McuPackage::tr("Missing %1. Add the path in Tools > Options > Devices > MCU.")
.arg(qtForMCUsPackage->detectionPath()),
.arg(qtForMCUsPackage->detectionPath().toUserOutput()),
true);
return;
}
@@ -575,7 +560,7 @@ void fixExistingKits()
// Fix kit dependencies for known targets
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
qtForMCUsPackage->updateStatus();
if (qtForMCUsPackage->validStatus()) {
if (qtForMCUsPackage->isValidStatus()) {
FilePath dir = qtForMCUsPackage->path();
McuSdkRepository repo;
Sdk::targetsAndPackages(dir, &repo);

View File

@@ -28,37 +28,69 @@
#include "mcusupportversiondetection.h"
#include "mcusupportsdk.h"
#include <baremetal/baremetalconstants.h>
#include <coreplugin/icore.h>
#include <utils/algorithm.h>
#include <utils/infolabel.h>
#include <utils/pathchooser.h>
#include <utils/utilsicons.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <QDesktopServices>
#include <QGridLayout>
#include <QToolButton>
using namespace ProjectExplorer;
using namespace Utils;
namespace McuSupport::Internal {
McuPackage::McuPackage(const QString &label,
const FilePath &defaultPath,
const QString &detectionPath,
const FilePath &detectionPath,
const QString &settingsKey,
const QString &envVarName,
const QString &downloadUrl,
const McuPackageVersionDetector *versionDetector)
const McuPackageVersionDetector *versionDetector,
const bool addToSystemPath,
const FilePath &relativePathModifier)
: m_label(label)
, m_defaultPath(Sdk::packagePathFromSettings(settingsKey, QSettings::SystemScope, defaultPath))
, m_detectionPath(detectionPath)
, m_settingsKey(settingsKey)
, m_versionDetector(versionDetector)
, m_relativePathModifier(relativePathModifier)
, m_environmentVariableName(envVarName)
, m_downloadUrl(downloadUrl)
, m_addToSystemPath(addToSystemPath)
{
m_path = Sdk::packagePathFromSettings(settingsKey, QSettings::UserScope, m_defaultPath);
}
QString McuPackage::label() const
{
return m_label;
}
const QString &McuPackage::environmentVariableName() const
{
return m_environmentVariableName;
}
bool McuPackage::isAddToSystemPath() const
{
return m_addToSystemPath;
}
void McuPackage::setVersions(const QStringList &versions)
{
m_versions = versions;
}
FilePath McuPackage::basePath() const
{
return m_fileChooser != nullptr ? m_fileChooser->filePath() : m_path;
@@ -69,21 +101,131 @@ FilePath McuPackage::path() const
return basePath().resolvePath(m_relativePathModifier).absoluteFilePath();
}
QString McuPackage::label() const
{
return m_label;
}
FilePath McuPackage::defaultPath() const
{
return m_defaultPath;
}
QString McuPackage::detectionPath() const
FilePath McuPackage::detectionPath() const
{
return m_detectionPath;
}
void McuPackage::updatePath()
{
m_path = m_fileChooser->rawFilePath();
m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath);
updateStatus();
}
void McuPackage::updateStatus()
{
bool validPath = !m_path.isEmpty() && m_path.exists();
const FilePath detectionPath = basePath().resolvePath(m_detectionPath);
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
m_detectedVersion = validPath && validPackage && m_versionDetector
? m_versionDetector->parseVersion(basePath().toString())
: QString();
const bool validVersion = m_detectedVersion.isEmpty() || m_versions.isEmpty()
|| m_versions.contains(m_detectedVersion);
m_status = validPath ? (validPackage ? (validVersion ? Status::ValidPackage
: Status::ValidPackageMismatchedVersion)
: Status::ValidPathInvalidPackage)
: m_path.isEmpty() ? Status::EmptyPath
: Status::InvalidPath;
emit statusChanged();
}
McuPackage::Status McuPackage::status() const
{
return m_status;
}
bool McuPackage::isValidStatus() const
{
return m_status == Status::ValidPackage || m_status == Status::ValidPackageMismatchedVersion;
}
void McuPackage::updateStatusUi()
{
switch (m_status) {
case Status::ValidPackage:
m_infoLabel->setType(InfoLabel::Ok);
break;
case Status::ValidPackageMismatchedVersion:
m_infoLabel->setType(InfoLabel::Warning);
break;
default:
m_infoLabel->setType(InfoLabel::NotOk);
break;
}
m_infoLabel->setText(statusText());
}
QString McuPackage::statusText() const
{
const QString displayPackagePath = m_path.toUserOutput();
const QString displayVersions = m_versions.join(" or ");
const QString outDetectionPath = m_detectionPath.toUserOutput();
const QString displayRequiredPath = m_versions.empty() ? outDetectionPath
: QString("%1 %2").arg(outDetectionPath,
displayVersions);
const QString displayDetectedPath = m_versions.empty()
? outDetectionPath
: QString("%1 %2").arg(outDetectionPath,
m_detectedVersion);
QString response;
switch (m_status) {
case Status::ValidPackage:
response = m_detectionPath.isEmpty()
? (m_detectedVersion.isEmpty()
? tr("Path %1 exists.").arg(displayPackagePath)
: tr("Path %1 exists. Version %2 was found.")
.arg(displayPackagePath, m_detectedVersion))
: tr("Path %1 is valid, %2 was found.")
.arg(displayPackagePath, displayDetectedPath);
break;
case Status::ValidPackageMismatchedVersion: {
const QString versionWarning
= m_versions.size() == 1
? tr("but only version %1 is supported").arg(m_versions.first())
: tr("but only versions %1 are supported").arg(displayVersions);
response = tr("Path %1 is valid, %2 was found, %3.")
.arg(displayPackagePath, displayDetectedPath, versionWarning);
break;
}
case Status::ValidPathInvalidPackage:
response = tr("Path %1 exists, but does not contain %2.")
.arg(displayPackagePath, displayRequiredPath);
break;
case Status::InvalidPath:
response = tr("Path %1 does not exist.").arg(displayPackagePath);
break;
case Status::EmptyPath:
response = m_detectionPath.isEmpty()
? tr("Path is empty.")
: tr("Path is empty, %1 not found.").arg(displayRequiredPath);
break;
}
return response;
}
bool McuPackage::writeToSettings() const
{
const FilePath savedPath = Sdk::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.toString(), m_defaultPath.toString());
return savedPath != m_path;
}
QWidget *McuPackage::widget()
{
if (m_widget)
@@ -127,164 +269,201 @@ QWidget *McuPackage::widget()
return m_widget;
}
McuPackage::Status McuPackage::status() const
{
return m_status;
}
bool McuPackage::validStatus() const
{
return m_status == Status::ValidPackage || m_status == Status::ValidPackageMismatchedVersion;
}
const QString &McuPackage::environmentVariableName() const
{
return m_environmentVariableName;
}
void McuPackage::setAddToPath(bool addToPath)
{
m_addToPath = addToPath;
}
bool McuPackage::addToPath() const
{
return m_addToPath;
}
bool McuPackage::writeToSettings() const
{
const FilePath savedPath = Sdk::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.toString(), m_defaultPath.toString());
return savedPath != m_path;
}
void McuPackage::setRelativePathModifier(const QString &path)
{
m_relativePathModifier = path;
}
void McuPackage::setVersions(const QStringList &versions)
{
m_versions = versions;
}
void McuPackage::updatePath()
{
m_path = m_fileChooser->rawFilePath();
m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath);
updateStatus();
}
void McuPackage::updateStatus()
{
bool validPath = !m_path.isEmpty() && m_path.exists();
const FilePath detectionPath = basePath() / m_detectionPath;
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
m_detectedVersion = validPath && validPackage && m_versionDetector
? m_versionDetector->parseVersion(basePath().toString())
: QString();
const bool validVersion = m_detectedVersion.isEmpty() || m_versions.isEmpty()
|| m_versions.contains(m_detectedVersion);
m_status = validPath ? (validPackage ? (validVersion ? Status::ValidPackage
: Status::ValidPackageMismatchedVersion)
: Status::ValidPathInvalidPackage)
: m_path.isEmpty() ? Status::EmptyPath
: Status::InvalidPath;
emit statusChanged();
}
void McuPackage::updateStatusUi()
{
switch (m_status) {
case Status::ValidPackage:
m_infoLabel->setType(InfoLabel::Ok);
break;
case Status::ValidPackageMismatchedVersion:
m_infoLabel->setType(InfoLabel::Warning);
break;
default:
m_infoLabel->setType(InfoLabel::NotOk);
break;
}
m_infoLabel->setText(statusText());
}
QString McuPackage::statusText() const
{
const QString displayPackagePath = m_path.toUserOutput();
const QString displayVersions = m_versions.join(" or ");
const QString outDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput();
const QString displayRequiredPath = m_versions.empty() ? outDetectionPath
: QString("%1 %2").arg(outDetectionPath,
displayVersions);
const QString displayDetectedPath = m_versions.empty()
? outDetectionPath
: QString("%1 %2").arg(outDetectionPath,
m_detectedVersion);
QString response;
switch (m_status) {
case Status::ValidPackage:
response = m_detectionPath.isEmpty()
? (m_detectedVersion.isEmpty()
? tr("Path %1 exists.").arg(displayPackagePath)
: tr("Path %1 exists. Version %2 was found.")
.arg(displayPackagePath, m_detectedVersion))
: tr("Path %1 is valid, %2 was found.")
.arg(displayPackagePath, displayDetectedPath);
break;
case Status::ValidPackageMismatchedVersion: {
const QString versionWarning
= m_versions.size() == 1
? tr("but only version %1 is supported").arg(m_versions.first())
: tr("but only versions %1 are supported").arg(displayVersions);
response = tr("Path %1 is valid, %2 was found, %3.")
.arg(displayPackagePath, displayDetectedPath, versionWarning);
break;
}
case Status::ValidPathInvalidPackage:
response = tr("Path %1 exists, but does not contain %2.")
.arg(displayPackagePath, displayRequiredPath);
break;
case Status::InvalidPath:
response = tr("Path %1 does not exist.").arg(displayPackagePath);
break;
case Status::EmptyPath:
response = m_detectionPath.isEmpty()
? tr("Path is empty.")
: tr("Path is empty, %1 not found.").arg(displayRequiredPath);
break;
}
return response;
}
McuToolChainPackage::McuToolChainPackage(const QString &label,
const FilePath &defaultPath,
const QString &detectionPath,
const FilePath &detectionPath,
const QString &settingsKey,
McuToolChainPackage::Type type,
McuToolChainPackage::ToolChainType type,
const QString &envVarName,
const McuPackageVersionDetector *versionDetector)
: McuPackage(label, defaultPath, detectionPath, settingsKey, envVarName, {}, versionDetector)
, m_type(type)
{}
McuToolChainPackage::Type McuToolChainPackage::type() const
McuToolChainPackage::ToolChainType McuToolChainPackage::toolchainType() const
{
return m_type;
}
bool McuToolChainPackage::isDesktopToolchain() const
{
return m_type == Type::MSVC || m_type == Type::GCC;
return m_type == ToolChainType::MSVC || m_type == ToolChainType::GCC;
}
static ToolChain *msvcToolChain(Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
const Abi abi = t->targetAbi();
// TODO: Should Abi::WindowsMsvc2022Flavor be added too?
return (abi.osFlavor() == Abi::WindowsMsvc2017Flavor
|| abi.osFlavor() == Abi::WindowsMsvc2019Flavor)
&& abi.architecture() == Abi::X86Architecture && abi.wordWidth() == 64
&& t->language() == language;
});
return toolChain;
}
static ToolChain *gccToolChain(Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
const Abi abi = t->targetAbi();
return abi.os() != Abi::WindowsOS && abi.architecture() == Abi::X86Architecture
&& abi.wordWidth() == 64 && t->language() == language;
});
return toolChain;
}
static ToolChain *armGccToolChain(const FilePath &path, Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t) {
return t->compilerCommand() == path && t->language() == language;
});
if (!toolChain) {
ToolChainFactory *gccFactory
= Utils::findOrDefault(ToolChainFactory::allToolChainFactories(),
[](ToolChainFactory *f) {
return f->supportedToolChainType()
== ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID;
});
if (gccFactory) {
const QList<ToolChain *> detected = gccFactory->detectForImport({path, language});
if (!detected.isEmpty()) {
toolChain = detected.first();
toolChain->setDetection(ToolChain::ManualDetection);
toolChain->setDisplayName("Arm GCC");
ToolChainManager::registerToolChain(toolChain);
}
}
}
return toolChain;
}
static ToolChain *iarToolChain(const FilePath &path, Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
return t->typeId() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID
&& t->language() == language;
});
if (!toolChain) {
ToolChainFactory *iarFactory
= Utils::findOrDefault(ToolChainFactory::allToolChainFactories(),
[](ToolChainFactory *f) {
return f->supportedToolChainType()
== BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID;
});
if (iarFactory) {
Toolchains detected = iarFactory->autoDetect(ToolchainDetector({}, {}));
if (detected.isEmpty())
detected = iarFactory->detectForImport({path, language});
for (auto tc : detected) {
if (tc->language() == language) {
toolChain = tc;
toolChain->setDetection(ToolChain::ManualDetection);
toolChain->setDisplayName("IAREW");
ToolChainManager::registerToolChain(toolChain);
}
}
}
}
return toolChain;
}
ToolChain *McuToolChainPackage::toolChain(Id language) const
{
switch (m_type) {
case ToolChainType::MSVC:
return msvcToolChain(language);
case ToolChainType::GCC:
return gccToolChain(language);
case ToolChainType::IAR: {
const FilePath compiler = path().pathAppended("/bin/iccarm").withExecutableSuffix();
return iarToolChain(compiler, language);
}
case ToolChainType::ArmGcc:
case ToolChainType::KEIL:
case ToolChainType::GHS:
case ToolChainType::GHSArm:
case ToolChainType::Unsupported: {
const QLatin1String compilerName(
language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++");
const QString comp = QLatin1String(m_type == ToolChainType::ArmGcc ? "/bin/arm-none-eabi-%1"
: "/bar/foo-keil-%1")
.arg(compilerName);
const FilePath compiler = path().pathAppended(comp).withExecutableSuffix();
return armGccToolChain(compiler, language);
}
default:
Q_UNREACHABLE();
}
}
QString McuToolChainPackage::toolChainName() const
{
switch (m_type) {
case ToolChainType::ArmGcc:
return QLatin1String("armgcc");
case ToolChainType::IAR:
return QLatin1String("iar");
case ToolChainType::KEIL:
return QLatin1String("keil");
case ToolChainType::GHS:
return QLatin1String("ghs");
case ToolChainType::GHSArm:
return QLatin1String("ghs-arm");
default:
return QLatin1String("unsupported");
}
}
QString McuToolChainPackage::cmakeToolChainFileName() const
{
return toolChainName() + QLatin1String(".cmake");
}
QVariant McuToolChainPackage::debuggerId() const
{
using namespace Debugger;
QString sub, displayName;
DebuggerEngineType engineType;
switch (m_type) {
case ToolChainType::ArmGcc: {
sub = QString::fromLatin1("bin/arm-none-eabi-gdb-py");
displayName = McuPackage::tr("Arm GDB at %1");
engineType = Debugger::GdbEngineType;
break;
}
case ToolChainType::IAR: {
sub = QString::fromLatin1("../common/bin/CSpyBat");
displayName = QLatin1String("CSpy");
engineType = Debugger::NoEngineType; // support for IAR missing
break;
}
case ToolChainType::KEIL: {
sub = QString::fromLatin1("UV4/UV4");
displayName = QLatin1String("KEIL uVision Debugger");
engineType = Debugger::UvscEngineType;
break;
}
default:
return QVariant();
}
const FilePath command = path().pathAppended(sub).withExecutableSuffix();
if (const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command)) {
return debugger->id();
}
DebuggerItem newDebugger;
newDebugger.setCommand(command);
newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput()));
newDebugger.setEngineType(engineType);
return DebuggerItemManager::registerDebugger(newDebugger);
}

View File

@@ -55,33 +55,35 @@ class McuPackage : public McuAbstractPackage
public:
McuPackage(const QString &label,
const Utils::FilePath &defaultPath,
const QString &detectionPath,
const Utils::FilePath &detectionPath,
const QString &settingsKey,
const QString &envVarName = {},
const QString &downloadUrl = {},
const McuPackageVersionDetector *versionDetector = nullptr);
const McuPackageVersionDetector *versionDetector = nullptr,
const bool addToPath = false,
const Utils::FilePath &relativePathModifier = Utils::FilePath());
~McuPackage() override = default;
QString label() const override;
const QString &environmentVariableName() const override;
bool isAddToSystemPath() const override;
void setVersions(const QStringList &versions) override;
Utils::FilePath basePath() const override;
Utils::FilePath path() const override;
QString label() const override;
Utils::FilePath defaultPath() const override;
QString detectionPath() const override;
QString statusText() const override;
void updateStatus() override;
Utils::FilePath detectionPath() const override;
void updateStatus() override;
Status status() const override;
bool validStatus() const override;
void setAddToPath(bool addToPath) override;
bool addToPath() const override;
bool isValidStatus() const override;
QString statusText() const override;
bool writeToSettings() const override;
void setRelativePathModifier(const QString &path) override;
void setVersions(const QStringList &versions) override;
QWidget *widget() override;
const QString &environmentVariableName() const override;
private:
void updatePath();
void updateStatusUi();
@@ -92,17 +94,17 @@ private:
const QString m_label;
const Utils::FilePath m_defaultPath;
const QString m_detectionPath;
const Utils::FilePath m_detectionPath;
const QString m_settingsKey;
const McuPackageVersionDetector *m_versionDetector;
Utils::FilePath m_path;
QString m_relativePathModifier; // relative path to m_path to be returned by path()
Utils::FilePath m_relativePathModifier; // relative path to m_path to be returned by path()
QString m_detectedVersion;
QStringList m_versions;
const QString m_environmentVariableName;
const QString m_downloadUrl;
bool m_addToPath = false;
const bool m_addToSystemPath;
Status m_status = Status::InvalidPath;
};
@@ -110,17 +112,17 @@ private:
class McuToolChainPackage : public McuPackage
{
public:
enum class Type { IAR, KEIL, MSVC, GCC, ArmGcc, GHS, GHSArm, Unsupported };
enum class ToolChainType { IAR, KEIL, MSVC, GCC, ArmGcc, GHS, GHSArm, Unsupported };
McuToolChainPackage(const QString &label,
const Utils::FilePath &defaultPath,
const QString &detectionPath,
const Utils::FilePath &detectionPath,
const QString &settingsKey,
Type type,
ToolChainType toolchainType,
const QString &envVarName = {},
const McuPackageVersionDetector *versionDetector = nullptr);
Type type() const;
ToolChainType toolchainType() const;
bool isDesktopToolchain() const;
ProjectExplorer::ToolChain *toolChain(Utils::Id language) const;
QString toolChainName() const;
@@ -128,7 +130,7 @@ public:
QVariant debuggerId() const;
private:
const Type m_type;
const ToolChainType m_type;
};
} // namespace Internal

View File

@@ -134,7 +134,7 @@ void McuSupportOptions::setQulDir(const FilePath &dir)
{
deletePackagesAndTargets();
qtForMCUsSdkPackage->updateStatus();
if (qtForMCUsSdkPackage->validStatus())
if (qtForMCUsSdkPackage->isValidStatus())
Sdk::targetsAndPackages(dir, &sdkRepository);
for (const auto &package : qAsConst(sdkRepository.packages))
connect(package, &McuAbstractPackage::changed, this, &McuSupportOptions::packagesChanged);
@@ -164,73 +164,6 @@ void McuSupportOptions::remapQul2xCmakeVars(Kit *kit, const EnvironmentItems &en
CMakeConfigurationKitAspect::setConfiguration(kit, config);
}
static void setKitToolchains(Kit *k, const McuToolChainPackage *tcPackage)
{
switch (tcPackage->type()) {
case McuToolChainPackage::Type::Unsupported:
return;
case McuToolChainPackage::Type::GHS:
case McuToolChainPackage::Type::GHSArm:
return; // No Green Hills toolchain, because support for it is missing.
case McuToolChainPackage::Type::IAR:
case McuToolChainPackage::Type::KEIL:
case McuToolChainPackage::Type::MSVC:
case McuToolChainPackage::Type::GCC:
case McuToolChainPackage::Type::ArmGcc:
ToolChainKitAspect::setToolChain(k,
tcPackage->toolChain(
ProjectExplorer::Constants::C_LANGUAGE_ID));
ToolChainKitAspect::setToolChain(k,
tcPackage->toolChain(
ProjectExplorer::Constants::CXX_LANGUAGE_ID));
return;
default:
Q_UNREACHABLE();
}
}
static void setKitDebugger(Kit *k, const McuToolChainPackage *tcPackage)
{
if (tcPackage->isDesktopToolchain()) {
// Qt Creator seems to be smart enough to deduce the right Kit debugger from the ToolChain
return;
}
switch (tcPackage->type()) {
case McuToolChainPackage::Type::Unsupported:
case McuToolChainPackage::Type::GHS:
case McuToolChainPackage::Type::GHSArm:
case McuToolChainPackage::Type::IAR:
return; // No Green Hills and IAR debugger, because support for it is missing.
case McuToolChainPackage::Type::KEIL:
case McuToolChainPackage::Type::MSVC:
case McuToolChainPackage::Type::GCC:
case McuToolChainPackage::Type::ArmGcc: {
const QVariant debuggerId = tcPackage->debuggerId();
if (debuggerId.isValid()) {
Debugger::DebuggerKitAspect::setDebugger(k, debuggerId);
}
return;
}
default:
Q_UNREACHABLE();
}
}
static void setKitDevice(Kit *k, const McuTarget *mcuTarget)
{
// "Device Type" Desktop is the default. We use that for the Qt for MCUs Desktop Kit
if (mcuTarget->toolChainPackage()->isDesktopToolchain())
return;
DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE);
}
static bool expectsCmakeVars(const McuTarget *mcuTarget)
{
return mcuTarget->qulVersion() >= QVersionNumber{2, 0};
@@ -251,7 +184,7 @@ void McuSupportOptions::setKitEnvironment(Kit *k,
pathAdditions.append(qtForMCUsSdkPackage->path().pathAppended("bin").toUserOutput());
auto processPackage = [&pathAdditions, &changes](const McuAbstractPackage *package) {
if (package->addToPath())
if (package->isAddToSystemPath())
pathAdditions.append(package->path().toUserOutput());
if (!package->environmentVariableName().isEmpty())
changes.append({package->environmentVariableName(), package->path().toUserOutput()});
@@ -271,34 +204,12 @@ void McuSupportOptions::setKitEnvironment(Kit *k,
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
}
static void setKitDependencies(Kit *k,
const McuTarget *mcuTarget,
const McuAbstractPackage *qtForMCUsSdkPackage)
{
NameValueItems dependencies;
auto processPackage = [&dependencies](const McuAbstractPackage *package) {
if (!package->environmentVariableName().isEmpty())
dependencies.append({package->environmentVariableName(),
QDir::toNativeSeparators(package->detectionPath())});
};
for (auto package : mcuTarget->packages())
processPackage(package);
processPackage(qtForMCUsSdkPackage);
McuDependenciesKitAspect::setDependencies(k, dependencies);
auto irrelevant = k->irrelevantAspects();
irrelevant.insert(McuDependenciesKitAspect::id());
k->setIrrelevantAspects(irrelevant);
}
void McuSupportOptions::updateKitEnvironment(Kit *k, const McuTarget *mcuTarget)
{
EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(k);
for (auto package : mcuTarget->packages()) {
const QString varName = package->environmentVariableName();
if (!varName.isEmpty() && package->validStatus()) {
if (!varName.isEmpty() && package->isValidStatus()) {
const int index = Utils::indexOf(changes, [varName](const EnvironmentItem &item) {
return item.name == varName;
});
@@ -319,76 +230,6 @@ void McuSupportOptions::updateKitEnvironment(Kit *k, const McuTarget *mcuTarget)
EnvironmentKitAspect::setEnvironmentChanges(k, changes);
}
static void setKitCMakeOptions(Kit *k, const McuTarget *mcuTarget, const FilePath &qulDir)
{
using namespace CMakeProjectManager;
CMakeConfig config = CMakeConfigurationKitAspect::configuration(k);
// CMake ToolChain file for ghs handles CMAKE_*_COMPILER autonomously
if (mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHS
&& mcuTarget->toolChainPackage()->type() != McuToolChainPackage::Type::GHSArm) {
config.append(CMakeConfigItem("CMAKE_CXX_COMPILER", "%{Compiler:Executable:Cxx}"));
config.append(CMakeConfigItem("CMAKE_C_COMPILER", "%{Compiler:Executable:C}"));
}
if (!mcuTarget->toolChainPackage()->isDesktopToolchain()) {
const FilePath cMakeToolchainFile = qulDir.pathAppended(
"lib/cmake/Qul/toolchain/" + mcuTarget->toolChainPackage()->cmakeToolChainFileName());
config.append(
CMakeConfigItem("CMAKE_TOOLCHAIN_FILE", cMakeToolchainFile.toString().toUtf8()));
if (!cMakeToolchainFile.exists()) {
printMessage(McuTarget::tr(
"Warning for target %1: missing CMake toolchain file expected at %2.")
.arg(McuKitManager::kitName(mcuTarget),
cMakeToolchainFile.toUserOutput()),
false);
}
}
const FilePath generatorsPath = qulDir.pathAppended("/lib/cmake/Qul/QulGenerators.cmake");
config.append(CMakeConfigItem("QUL_GENERATORS", generatorsPath.toString().toUtf8()));
if (!generatorsPath.exists()) {
printMessage(McuTarget::tr("Warning for target %1: missing QulGenerators expected at %2.")
.arg(McuKitManager::kitName(mcuTarget), generatorsPath.toUserOutput()),
false);
}
config.append(CMakeConfigItem("QUL_PLATFORM", mcuTarget->platform().name.toUtf8()));
if (mcuTarget->colorDepth() != McuTarget::UnspecifiedColorDepth)
config.append(CMakeConfigItem("QUL_COLOR_DEPTH",
QString::number(mcuTarget->colorDepth()).toLatin1()));
if (McuSupportOptions::kitsNeedQtVersion())
config.append(CMakeConfigItem("CMAKE_PREFIX_PATH", "%{Qt:QT_INSTALL_PREFIX}"));
CMakeConfigurationKitAspect::setConfiguration(k, config);
if (HostOsInfo::isWindowsHost()) {
auto type = mcuTarget->toolChainPackage()->type();
if (type == McuToolChainPackage::Type::GHS || type == McuToolChainPackage::Type::GHSArm) {
// See https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565802&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565802
// and https://bugreports.qt.io/browse/UL-4247?focusedCommentId=565803&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-565803
CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM");
}
}
}
static void setKitQtVersionOptions(Kit *k)
{
if (!McuSupportOptions::kitsNeedQtVersion())
QtSupport::QtKitAspect::setQtVersion(k, nullptr);
// else: auto-select a Qt version
}
static FilePath kitDependencyPath(const Kit *kit, const QString &variableName)
{
for (const NameValueItem &nameValueItem : EnvironmentKitAspect::environmentChanges(kit)) {
if (nameValueItem.name == variableName)
return FilePath::fromUserInput(nameValueItem.value);
}
return FilePath();
}
McuKitManager::UpgradeOption McuSupportOptions::askForKitUpgrades()
{
QMessageBox upgradePopup(Core::ICore::dialogParent());
@@ -417,7 +258,7 @@ void McuSupportOptions::deletePackagesAndTargets()
void McuSupportOptions::checkUpgradeableKits()
{
if (!qtForMCUsSdkPackage->validStatus() || sdkRepository.mcuTargets.length() == 0)
if (!qtForMCUsSdkPackage->isValidStatus() || sdkRepository.mcuTargets.length() == 0)
return;
if (Utils::anyOf(sdkRepository.mcuTargets, [this](const McuTarget *target) {

View File

@@ -197,7 +197,7 @@ void McuSupportOptionsWidget::updateStatus()
// Page elements
{
m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable);
const bool valid = cMakeAvailable && m_options.qtForMCUsSdkPackage->validStatus();
const bool valid = cMakeAvailable && m_options.qtForMCUsSdkPackage->isValidStatus();
const bool ready = valid && mcuTarget;
m_mcuTargetsGroupBox->setVisible(ready);
m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty());

View File

@@ -71,24 +71,24 @@ McuPackage *createQtForMCUsPackage()
{
return new McuPackage(McuPackage::tr("Qt for MCUs SDK"),
FileUtils::homePath(), // defaultPath
FilePath("bin/qmltocpp").withExecutableSuffix().toString(), // detectionPath
FilePath("bin/qmltocpp").withExecutableSuffix(), // detectionPath
Constants::SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK, // settingsKey
QStringLiteral("Qul_DIR")); // envVarName
}
static McuToolChainPackage *createMsvcToolChainPackage()
{
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::MSVC);
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::ToolChainType::MSVC);
}
static McuToolChainPackage *createGccToolChainPackage()
{
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::GCC);
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::ToolChainType::GCC);
}
static McuToolChainPackage *createUnsupportedToolChainPackage()
{
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::Type::Unsupported);
return new McuToolChainPackage({}, {}, {}, {}, McuToolChainPackage::ToolChainType::Unsupported);
}
static McuToolChainPackage *createArmGccPackage()
@@ -109,7 +109,7 @@ static McuToolChainPackage *createArmGccPackage()
}
}
const QString detectionPath = Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++");
const Utils::FilePath detectionPath = FilePath("bin/arm-none-eabi-g++").withExecutableSuffix();
const auto versionDetector
= new McuPackageExecutableVersionDetector(detectionPath,
{"--version"},
@@ -119,7 +119,7 @@ static McuToolChainPackage *createArmGccPackage()
defaultPath,
detectionPath,
"GNUArmEmbeddedToolchain", // settingsKey
McuToolChainPackage::Type::ArmGcc,
McuToolChainPackage::ToolChainType::ArmGcc,
envVar,
versionDetector);
}
@@ -131,16 +131,15 @@ static McuToolChainPackage *createGhsToolchainPackage()
const FilePath defaultPath = FilePath::fromUserInput(qEnvironmentVariable(envVar));
const auto versionDetector
= new McuPackageExecutableVersionDetector(Utils::HostOsInfo::withExecutableSuffix("as850"),
= new McuPackageExecutableVersionDetector(FilePath("as850").withExecutableSuffix(),
{"-V"},
"\\bv(\\d+\\.\\d+\\.\\d+)\\b");
return new McuToolChainPackage("Green Hills Compiler",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix(
"ccv850"), // detectionPath
FilePath("ccv850").withExecutableSuffix(), // detectionPath
"GHSToolchain", // settingsKey
McuToolChainPackage::Type::GHS,
McuToolChainPackage::ToolChainType::GHS,
envVar,
versionDetector);
}
@@ -152,15 +151,15 @@ static McuToolChainPackage *createGhsArmToolchainPackage()
const FilePath defaultPath = FilePath::fromUserInput(qEnvironmentVariable(envVar));
const auto versionDetector
= new McuPackageExecutableVersionDetector(Utils::HostOsInfo::withExecutableSuffix("asarm"),
= new McuPackageExecutableVersionDetector(FilePath("asarm").withExecutableSuffix(),
{"-V"},
"\\bv(\\d+\\.\\d+\\.\\d+)\\b");
return new McuToolChainPackage("Green Hills Compiler for ARM",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix("cxarm"), // detectionPath
FilePath("cxarm").withExecutableSuffix(), // detectionPath
"GHSArmToolchain", // settingsKey
McuToolChainPackage::Type::GHSArm,
McuToolChainPackage::ToolChainType::GHSArm,
envVar,
versionDetector);
}
@@ -183,7 +182,7 @@ static McuToolChainPackage *createIarToolChainPackage()
}
}
const QString detectionPath = Utils::HostOsInfo::withExecutableSuffix("bin/iccarm");
const FilePath detectionPath = FilePath("bin/iccarm").withExecutableSuffix();
const auto versionDetector
= new McuPackageExecutableVersionDetector(detectionPath,
{"--version"},
@@ -193,7 +192,7 @@ static McuToolChainPackage *createIarToolChainPackage()
defaultPath,
detectionPath,
"IARToolchain", // settings key
McuToolChainPackage::Type::IAR,
McuToolChainPackage::ToolChainType::IAR,
envVar,
versionDetector);
}
@@ -237,17 +236,24 @@ static McuPackage *createStm32CubeProgrammerPackage()
if (programPath.exists())
defaultPath = programPath;
}
const FilePath detectionPath = FilePath::fromString(
QLatin1String(Utils::HostOsInfo::isWindowsHost()
? "/bin/STM32_Programmer_CLI.exe"
: "/bin/STM32_Programmer.sh")
);
auto result
= new McuPackage(McuPackage::tr("STM32CubeProgrammer"),
defaultPath,
QLatin1String(Utils::HostOsInfo::isWindowsHost()
? "/bin/STM32_Programmer_CLI.exe"
: "/bin/STM32_Programmer.sh"), // detection path
detectionPath,
"Stm32CubeProgrammer",
{}, // env var
"https://www.st.com/en/development-tools/stm32cubeprog.html"); // download url
result->setRelativePathModifier("/bin");
result->setAddToPath(true);
"https://www.st.com/en/development-tools/stm32cubeprog.html", // download url
nullptr, // version detector
true, // add to path
"/bin" // relative path modifier
);
return result;
}
@@ -276,8 +282,7 @@ static McuPackage *createMcuXpressoIdePackage()
return new McuPackage("MCUXpresso IDE",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix(
"ide/binaries/crt_emu_cm_redlink"), // detection path
FilePath("ide/binaries/crt_emu_cm_redlink").withExecutableSuffix(), // detection path
"MCUXpressoIDE", // settings key
envVar,
"https://www.nxp.com/mcuxpresso/ide"); // download url
@@ -303,7 +308,7 @@ static McuPackage *createCypressProgrammerPackage()
auto result = new McuPackage("Cypress Auto Flash Utility",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix("/bin/openocd"),
FilePath("/bin/openocd").withExecutableSuffix(),
"CypressAutoFlashUtil",
envVar);
return result;
@@ -329,7 +334,7 @@ static McuPackage *createRenesasProgrammerPackage()
auto result = new McuPackage("Renesas Flash Programmer",
defaultPath,
Utils::HostOsInfo::withExecutableSuffix("rfp-cli"),
FilePath("rfp-cli").withExecutableSuffix(),
"RenesasFlashProgrammer",
envVar);
return result;
@@ -538,7 +543,7 @@ protected:
QVector<McuAbstractPackage *> required3rdPartyPkgs;
// Desktop toolchains don't need any additional settings
if (tcPkg && !tcPkg->isDesktopToolchain()
&& tcPkg->type() != McuToolChainPackage::Type::Unsupported)
&& tcPkg->toolchainType() != McuToolChainPackage::ToolChainType::Unsupported)
required3rdPartyPkgs.append(tcPkg);
// Add setting specific to platform IDE

View File

@@ -46,7 +46,7 @@ QString matchRegExp(const QString &text, const QString &regExp)
McuPackageVersionDetector::McuPackageVersionDetector() {}
McuPackageExecutableVersionDetector::McuPackageExecutableVersionDetector(
const QString &detectionPath, const QStringList &detectionArgs, const QString &detectionRegExp)
const Utils::FilePath &detectionPath, const QStringList &detectionArgs, const QString &detectionRegExp)
: McuPackageVersionDetector()
, m_detectionPath(detectionPath)
, m_detectionArgs(detectionArgs)
@@ -58,7 +58,7 @@ QString McuPackageExecutableVersionDetector::parseVersion(const QString &package
if (m_detectionPath.isEmpty() || m_detectionRegExp.isEmpty())
return QString();
const Utils::FilePath binaryPath = Utils::FilePath::fromString(packagePath) / m_detectionPath;
const Utils::FilePath binaryPath = Utils::FilePath::fromString(packagePath).resolvePath(m_detectionPath);
if (!binaryPath.exists())
return QString();

View File

@@ -26,6 +26,7 @@
#pragma once
#include <QObject>
#include <utils/filepath.h>
namespace McuSupport {
namespace Internal {
@@ -43,13 +44,13 @@ public:
class McuPackageExecutableVersionDetector : public McuPackageVersionDetector
{
public:
McuPackageExecutableVersionDetector(const QString &detectionPath,
McuPackageExecutableVersionDetector(const Utils::FilePath &detectionPath,
const QStringList &detectionArgs,
const QString &detectionRegExp);
QString parseVersion(const QString &packagePath) const final;
private:
const QString m_detectionPath;
const Utils::FilePath m_detectionPath;
const QStringList m_detectionArgs;
const QString m_detectionRegExp;
};

View File

@@ -26,196 +26,14 @@
#include "mcutarget.h"
#include "mcupackage.h"
#include "mcukitmanager.h"
#include "mcusupportplugin.h"
#include <baremetal/baremetalconstants.h>
#include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h>
#include <utils/algorithm.h>
using namespace ProjectExplorer;
using namespace Utils;
namespace McuSupport::Internal {
static ToolChain *msvcToolChain(Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
const Abi abi = t->targetAbi();
// TODO: Should Abi::WindowsMsvc2022Flavor be added too?
return (abi.osFlavor() == Abi::WindowsMsvc2017Flavor
|| abi.osFlavor() == Abi::WindowsMsvc2019Flavor)
&& abi.architecture() == Abi::X86Architecture && abi.wordWidth() == 64
&& t->language() == language;
});
return toolChain;
}
static ToolChain *gccToolChain(Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
const Abi abi = t->targetAbi();
return abi.os() != Abi::WindowsOS && abi.architecture() == Abi::X86Architecture
&& abi.wordWidth() == 64 && t->language() == language;
});
return toolChain;
}
static ToolChain *armGccToolChain(const FilePath &path, Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t) {
return t->compilerCommand() == path && t->language() == language;
});
if (!toolChain) {
ToolChainFactory *gccFactory
= Utils::findOrDefault(ToolChainFactory::allToolChainFactories(),
[](ToolChainFactory *f) {
return f->supportedToolChainType()
== ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID;
});
if (gccFactory) {
const QList<ToolChain *> detected = gccFactory->detectForImport({path, language});
if (!detected.isEmpty()) {
toolChain = detected.first();
toolChain->setDetection(ToolChain::ManualDetection);
toolChain->setDisplayName("Arm GCC");
ToolChainManager::registerToolChain(toolChain);
}
}
}
return toolChain;
}
static ToolChain *iarToolChain(const FilePath &path, Id language)
{
ToolChain *toolChain = ToolChainManager::toolChain([language](const ToolChain *t) {
return t->typeId() == BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID
&& t->language() == language;
});
if (!toolChain) {
ToolChainFactory *iarFactory
= Utils::findOrDefault(ToolChainFactory::allToolChainFactories(),
[](ToolChainFactory *f) {
return f->supportedToolChainType()
== BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID;
});
if (iarFactory) {
Toolchains detected = iarFactory->autoDetect(ToolchainDetector({}, {}));
if (detected.isEmpty())
detected = iarFactory->detectForImport({path, language});
for (auto tc : detected) {
if (tc->language() == language) {
toolChain = tc;
toolChain->setDetection(ToolChain::ManualDetection);
toolChain->setDisplayName("IAREW");
ToolChainManager::registerToolChain(toolChain);
}
}
}
}
return toolChain;
}
ToolChain *McuToolChainPackage::toolChain(Id language) const
{
switch (m_type) {
case Type::MSVC:
return msvcToolChain(language);
case Type::GCC:
return gccToolChain(language);
case Type::IAR: {
const FilePath compiler = path().pathAppended("/bin/iccarm").withExecutableSuffix();
return iarToolChain(compiler, language);
}
case Type::ArmGcc:
case Type::KEIL:
case Type::GHS:
case Type::GHSArm:
case Type::Unsupported: {
const QLatin1String compilerName(
language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++");
const QString comp = QLatin1String(m_type == Type::ArmGcc ? "/bin/arm-none-eabi-%1"
: "/bar/foo-keil-%1")
.arg(compilerName);
const FilePath compiler = path().pathAppended(comp).withExecutableSuffix();
return armGccToolChain(compiler, language);
}
default:
Q_UNREACHABLE();
}
}
QString McuToolChainPackage::toolChainName() const
{
switch (m_type) {
case Type::ArmGcc:
return QLatin1String("armgcc");
case Type::IAR:
return QLatin1String("iar");
case Type::KEIL:
return QLatin1String("keil");
case Type::GHS:
return QLatin1String("ghs");
case Type::GHSArm:
return QLatin1String("ghs-arm");
default:
return QLatin1String("unsupported");
}
}
QString McuToolChainPackage::cmakeToolChainFileName() const
{
return toolChainName() + QLatin1String(".cmake");
}
QVariant McuToolChainPackage::debuggerId() const
{
using namespace Debugger;
QString sub, displayName;
DebuggerEngineType engineType;
switch (m_type) {
case Type::ArmGcc: {
sub = QString::fromLatin1("bin/arm-none-eabi-gdb-py");
displayName = McuPackage::tr("Arm GDB at %1");
engineType = Debugger::GdbEngineType;
break;
}
case Type::IAR: {
sub = QString::fromLatin1("../common/bin/CSpyBat");
displayName = QLatin1String("CSpy");
engineType = Debugger::NoEngineType; // support for IAR missing
break;
}
case Type::KEIL: {
sub = QString::fromLatin1("UV4/UV4");
displayName = QLatin1String("KEIL uVision Debugger");
engineType = Debugger::UvscEngineType;
break;
}
default:
return QVariant();
}
const FilePath command = path().pathAppended(sub).withExecutableSuffix();
if (const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command)) {
return debugger->id();
}
DebuggerItem newDebugger;
newDebugger.setCommand(command);
newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput()));
newDebugger.setEngineType(engineType);
return DebuggerItemManager::registerDebugger(newDebugger);
}
McuTarget::McuTarget(const QVersionNumber &qulVersion,
const Platform &platform,
OS os,
@@ -254,7 +72,7 @@ bool McuTarget::isValid() const
{
return Utils::allOf(packages(), [](McuAbstractPackage *package) {
package->updateStatus();
return package->validStatus();
return package->isValidStatus();
});
}
@@ -262,7 +80,7 @@ void McuTarget::printPackageProblems() const
{
for (auto package : packages()) {
package->updateStatus();
if (!package->validStatus())
if (!package->isValidStatus())
printMessage(tr("Error creating kit for target %1, package %2: %3")
.arg(McuKitManager::kitName(this),
package->label(),

View File

@@ -39,17 +39,15 @@ public:
MOCK_METHOD(Utils::FilePath, path, (), (const));
MOCK_METHOD(QString, label, (), (const));
MOCK_METHOD(Utils::FilePath, defaultPath, (), (const));
MOCK_METHOD(QString, detectionPath, (), (const));
MOCK_METHOD(Utils::FilePath, detectionPath, (), (const));
MOCK_METHOD(QString, statusText, (), (const));
MOCK_METHOD(void, updateStatus, ());
MOCK_METHOD(Status, status, (), (const));
MOCK_METHOD(bool, validStatus, (), (const));
MOCK_METHOD(bool, isValidStatus, (), (const));
MOCK_METHOD(const QString &, environmentVariableName, (), (const));
MOCK_METHOD(void, setAddToPath, (bool) );
MOCK_METHOD(bool, addToPath, (), (const));
MOCK_METHOD(bool, isAddToSystemPath, (), (const));
MOCK_METHOD(bool, writeToSettings, (), (const));
MOCK_METHOD(void, setRelativePathModifier, (const QString &) );
MOCK_METHOD(void, setVersions, (const QStringList &) );
MOCK_METHOD(QWidget *, widget, ());

View File

@@ -47,7 +47,7 @@ using Utils::FilePath;
void McuSupportTest::initTestCase()
{
EXPECT_CALL(freeRtosPackage, environmentVariableName()).WillRepeatedly(ReturnRef(freeRtosEnvVar));
EXPECT_CALL(freeRtosPackage, validStatus()).WillRepeatedly(Return(true));
EXPECT_CALL(freeRtosPackage, isValidStatus()).WillRepeatedly(Return(true));
EXPECT_CALL(freeRtosPackage, path())
.WillRepeatedly(Return(FilePath::fromString(defaultfreeRtosPath)));
}

View File

@@ -32,6 +32,7 @@ add_qtc_plugin(QmlDesigner
cmakegeneratordialogtreemodel.cpp cmakegeneratordialogtreemodel.h
cmakeprojectconverter.cpp cmakeprojectconverter.h
cmakeprojectconverterdialog.cpp cmakeprojectconverterdialog.h
dynamiclicensecheck.h
generateresource.cpp generateresource.h
generatecmakelists.cpp generatecmakelists.h
generatecmakelistsconstants.h

View File

@@ -29,7 +29,9 @@
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/icore.h>
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
@@ -63,13 +65,46 @@ void CmakeProjectConverter::generateMenuEntry()
Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.ConvertToCmakeProject");
menu->addAction(cmd, Core::Constants::G_FILE_EXPORT);
action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr);
action->setEnabled(isProjectConvertable(ProjectExplorer::SessionManager::startupProject()));
QObject::connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged, [action]() {
action->setEnabled(ProjectExplorer::SessionManager::startupProject() != nullptr);
action->setEnabled(isProjectConvertable(ProjectExplorer::SessionManager::startupProject()));
});
}
bool CmakeProjectConverter::isProjectConvertable(const ProjectExplorer::Project *project)
{
if (!project)
return false;
return !isProjectCurrentFormat(project);
}
const QStringList sanityCheckFiles({FILENAME_CMAKELISTS,
FILENAME_MODULES,
FILENAME_MAINQML,
QString(DIRNAME_CONTENT)+'/'+FILENAME_CMAKELISTS,
QString(DIRNAME_IMPORT)+'/'+FILENAME_CMAKELISTS,
QString(DIRNAME_CPP)+'/'+FILENAME_MAINCPP,
QString(DIRNAME_CPP)+'/'+FILENAME_ENV_HEADER,
QString(DIRNAME_CPP)+'/'+FILENAME_MAINCPP_HEADER
});
bool CmakeProjectConverter::isProjectCurrentFormat(const ProjectExplorer::Project *project)
{
const QmlProjectManager::QmlProject *qmlprj = qobject_cast<const QmlProjectManager::QmlProject*>(project);
if (!qmlprj)
return false;
FilePath rootDir = qmlprj->rootProjectDirectory();
for (const QString &file : sanityCheckFiles)
if (!rootDir.pathAppended(file).exists())
return false;
return true;
}
void CmakeProjectConverter::onConvertProject()
{
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject();
@@ -100,10 +135,16 @@ bool CmakeProjectConverter::convertProject(const QmlProjectManager::QmlProject *
bool retVal = prepareAndExecute();
if (retVal)
QMessageBox::information(nullptr, SUCCESS_TITLE, SUCCESS_TEXT);
else
QMessageBox::critical(nullptr, ERROR_TITLE, ERROR_TEXT.arg(m_errorText));
if (retVal) {
QMessageBox::information(Core::ICore::dialogParent(), SUCCESS_TITLE, SUCCESS_TEXT);
ProjectExplorer::ProjectExplorerPlugin::OpenProjectResult result
= ProjectExplorer::ProjectExplorerPlugin::openProject(newProjectFile());
if (!result)
ProjectExplorer::ProjectExplorerPlugin::showOpenProjectError(result);
}
else {
QMessageBox::critical(Core::ICore::dialogParent(), ERROR_TITLE, ERROR_TEXT.arg(m_errorText));
}
return retVal;
}
@@ -298,31 +339,36 @@ bool CmakeProjectConverter::createPreparedProject()
return true;
}
const FilePath CmakeProjectConverter::contentDir()
const FilePath CmakeProjectConverter::contentDir() const
{
return m_newProjectDir.pathAppended(DIRNAME_CONTENT);
}
const FilePath CmakeProjectConverter::sourceDir()
const FilePath CmakeProjectConverter::sourceDir() const
{
return m_newProjectDir.pathAppended(DIRNAME_CPP);
}
const FilePath CmakeProjectConverter::importDir()
const FilePath CmakeProjectConverter::importDir() const
{
return m_newProjectDir.pathAppended(DIRNAME_IMPORT);
}
const FilePath CmakeProjectConverter::assetDir()
const FilePath CmakeProjectConverter::assetDir() const
{
return contentDir().pathAppended(DIRNAME_ASSET);
}
const FilePath CmakeProjectConverter::assetImportDir()
const FilePath CmakeProjectConverter::assetImportDir() const
{
return m_newProjectDir.pathAppended(DIRNAME_ASSETIMPORT);
}
const FilePath CmakeProjectConverter::newProjectFile() const
{
return m_newProjectDir.pathAppended(m_project->projectFilePath().fileName());
}
const FilePath CmakeProjectConverter::projectMainFile() const
{
auto *target = m_project->activeTarget();
@@ -370,17 +416,20 @@ bool CmakeProjectConverter::modifyProjectFile()
QString projectFileName = m_project->projectFilePath().fileName();
FilePath projectFilePath = m_newProjectDir.pathAppended(projectFileName);
QFile projectFile(projectFilePath.toString());
projectFile.open(QIODevice::ReadWrite);
projectFile.open(QIODevice::ReadOnly);
if (!projectFile.isOpen())
return false;
QString projectFileContent = QString::fromUtf8(projectFile.readAll());
projectFile.close();
const QRegularExpression mainFilePattern("^\\s*mainFile:\\s*\".*\"", QRegularExpression::MultilineOption);
const QString mainFileString(" mainFile: \"content/App.qml\"");
projectFileContent.replace(mainFilePattern, mainFileString);
projectFile.reset();
projectFile.open(QIODevice::WriteOnly|QIODevice::Truncate);
if (!projectFile.isOpen())
return false;
projectFile.write(projectFileContent.toUtf8());
projectFile.close();

View File

@@ -51,6 +51,8 @@ public:
const Utils::FilePath &targetDir);
static void generateMenuEntry();
static void onConvertProject();
static bool isProjectConvertable(const ProjectExplorer::Project *project);
static bool isProjectCurrentFormat(const ProjectExplorer::Project *project);
private:
bool prepareAndExecute();
@@ -68,11 +70,12 @@ private:
const Utils::FilePath &original, const Utils::FilePath &target);
bool createPreparedProject();
const Utils::FilePath contentDir();
const Utils::FilePath sourceDir();
const Utils::FilePath importDir();
const Utils::FilePath assetDir();
const Utils::FilePath assetImportDir();
const Utils::FilePath contentDir() const;
const Utils::FilePath sourceDir() const;
const Utils::FilePath importDir() const;
const Utils::FilePath assetDir() const;
const Utils::FilePath assetImportDir() const;
const Utils::FilePath newProjectFile() const;
const QString environmentVariable(const QString &key) const;
const Utils::FilePath projectMainFile() const;

View File

@@ -121,6 +121,12 @@ void AssetsLibraryView::modelAboutToBeDetached(Model *model)
void AssetsLibraryView::setResourcePath(const QString &resourcePath)
{
if (resourcePath == m_lastResourcePath)
return;
m_lastResourcePath = resourcePath;
if (m_widget.isNull()) {
m_widget = new AssetsLibraryWidget{m_imageCacheData->cache,
m_imageCacheData->asynchronousFontImageCache,

View File

@@ -62,6 +62,7 @@ private:
std::once_flag imageCacheFlag;
std::unique_ptr<ImageCacheData> m_imageCacheData;
QPointer<AssetsLibraryWidget> m_widget;
QString m_lastResourcePath;
};
}

View File

@@ -321,6 +321,8 @@ static QHash<QByteArray, QStringList> allImageFormats()
void AssetsLibraryWidget::addResources(const QStringList &files)
{
clearSearchFilter();
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
QTC_ASSERT(document, return);

View File

@@ -141,12 +141,6 @@ void DesignerActionManagerView::bindingPropertiesChanged(const QList<BindingProp
setupContext(SelectionContext::UpdateMode::Properties);
}
void DesignerActionManagerView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &)
{
if (hasSingleSelectedModelNode())
setupContext(SelectionContext::UpdateMode::Properties);
}
void DesignerActionManagerView::customNotification(const AbstractView * /*view*/,
const QString &identifier,
const QList<ModelNode> & /* nodeList */,

View File

@@ -64,8 +64,6 @@ public:
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChangeFlag) override;
void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChangeFlag) override;
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
DesignerActionManager &designerActionManager();
const DesignerActionManager &designerActionManager() const;
void emitSelectionChanged();

View File

@@ -69,8 +69,7 @@ bool CurveEditorView::hasWidget() const
WidgetInfo CurveEditorView::widgetInfo()
{
return createWidgetInfo(
m_editor, "CurveEditorId", WidgetInfo::BottomPane, 0, tr("CurveEditor"));
return createWidgetInfo(m_editor, "CurveEditorId", WidgetInfo::BottomPane, 0, tr("Curve Editor"));
}
void CurveEditorView::modelAttached(Model *model)

View File

@@ -2246,6 +2246,9 @@ void FormEditor3dPreview::paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
if (!painter->isActive())
return;

View File

@@ -357,6 +357,8 @@ void FormEditorWidget::initialize()
defaultZoom = m_formEditorView->rootModelNode().auxiliaryData("formeditorZoom").toDouble();
}
m_graphicsView->setZoomFactor(defaultZoom);
if (m_formEditorView->scene() && m_formEditorView->scene()->rootFormEditorItem())
m_graphicsView->centerOn(m_formEditorView->scene()->rootFormEditorItem());
m_zoomAction->setZoomFactor(defaultZoom);
updateActions();
}

View File

@@ -128,11 +128,9 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(
importPaths = model->importPaths();
}
QString targetDir = defaulTargetDirectory;
ProjectExplorer::Project *currentProject = ProjectExplorer::SessionManager::projectForFile(doc->fileName());
if (currentProject)
targetDir = currentProject->projectDirectory().toString();
QString targetDir = QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
if (targetDir.isEmpty())
targetDir = defaulTargetDirectory;
// Import is always done under known folder. The order of preference for folder is:
// 1) An existing QUICK_3D_ASSETS_FOLDER under DEFAULT_ASSET_IMPORT_FOLDER project import path

View File

@@ -234,11 +234,6 @@ void ItemLibraryModel::showAllHiddenCategories()
void ItemLibraryModel::setFlowMode(bool b)
{
m_flowMode = b;
bool changed = false;
if (updateVisibility(&changed); changed) {
beginResetModel();
endResetModel();
}
}
ItemLibraryModel::ItemLibraryModel(QObject *parent)

View File

@@ -254,6 +254,20 @@ void ItemLibraryWidget::handleSearchfilterChanged(const QString &filterText)
}
}
QString ItemLibraryWidget::getDependencyImport(const Import &import)
{
static QStringList prefixDependencies = {"QtQuick3D"};
const QStringList splitImport = import.url().split('.');
if (splitImport.count() > 1) {
if (prefixDependencies.contains(splitImport.first()))
return splitImport.first();
}
return {};
}
void ItemLibraryWidget::handleAddImport(int index)
{
Import import = m_addModuleModel->getImportAt(index);
@@ -263,8 +277,19 @@ void ItemLibraryWidget::handleAddImport(int index)
+ import.toImportString());
}
QList<Import> imports;
const QString dependency = getDependencyImport(import);
auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
document->documentModel()->changeImports({import}, {});
Model *model = document->documentModel();
if (!dependency.isEmpty()) {
Import dependencyImport = m_addModuleModel->getImport(dependency);
if (!dependencyImport.isEmpty())
imports.append(dependencyImport);
}
imports.append(import);
model->changeImports(imports, {});
QMetaObject::invokeMethod(m_itemsWidget->rootObject(), "switchToComponentsView");
updateSearch();

View File

@@ -110,6 +110,7 @@ private:
void updateSearch();
void handlePriorityImportsChanged();
static QString getDependencyImport(const Import &import);
QTimer m_compressionTimer;
QSize m_itemIconSize;

View File

@@ -421,14 +421,19 @@ void PropertyEditorQmlBackend::setup(const QmlObjectNode &qmlObjectNode, const Q
context()->setContextProperty(QLatin1String("modelNodeBackend"), &m_backendModelNode);
// className
auto valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_backendValuesPropertyMap.value(QLatin1String("className"))));
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
if (!valueObject)
valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap);
valueObject->setName("className");
valueObject->setName(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY);
valueObject->setModelNode(qmlObjectNode.modelNode());
valueObject->setValue(m_backendModelNode.simplifiedTypeName());
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(QLatin1String("className"), QVariant::fromValue(valueObject));
QObject::connect(valueObject,
&PropertyEditorValue::valueChanged,
&backendValuesPropertyMap(),
&DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY,
QVariant::fromValue(valueObject));
// id
valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_backendValuesPropertyMap.value(QLatin1String("id"))));
@@ -506,14 +511,19 @@ void PropertyEditorQmlBackend::initialSetup(const TypeName &typeName, const QUrl
foreach (const PropertyName &propertyName, metaInfo.propertyNames())
setupPropertyEditorValue(propertyName, propertyEditor, QString::fromUtf8(metaInfo.propertyTypeName(propertyName)));
auto valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_backendValuesPropertyMap.value(QLatin1String("className"))));
auto valueObject = qobject_cast<PropertyEditorValue *>(variantToQObject(
m_backendValuesPropertyMap.value(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)));
if (!valueObject)
valueObject = new PropertyEditorValue(&m_backendValuesPropertyMap);
valueObject->setName("className");
valueObject->setName(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY);
valueObject->setValue(typeName);
QObject::connect(valueObject, &PropertyEditorValue::valueChanged, &backendValuesPropertyMap(), &DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(QLatin1String("className"), QVariant::fromValue(valueObject));
QObject::connect(valueObject,
&PropertyEditorValue::valueChanged,
&backendValuesPropertyMap(),
&DesignerPropertyMap::valueChanged);
m_backendValuesPropertyMap.insert(Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY,
QVariant::fromValue(valueObject));
// id
valueObject = qobject_cast<PropertyEditorValue*>(variantToQObject(m_backendValuesPropertyMap.value(QLatin1String("id"))));

View File

@@ -144,7 +144,7 @@ void PropertyEditorView::changeValue(const QString &name)
if (locked())
return;
if (propertyName == "className")
if (propertyName == Constants::PROPERTY_EDITOR_CLASSNAME_PROPERTY)
return;
if (noValidSelection())

View File

@@ -1576,9 +1576,9 @@ QUrl Model::fileUrl() const
QUrl Model::projectUrl() const
{
#ifndef QMLDESIGNER_TEST
DesignDocument *document = QmlDesignerPlugin::instance()->viewManager().currentDesignDocument();
if (document)
return QUrl::fromLocalFile(document->projectFolder().toString());
DesignDocument *document = QmlDesignerPlugin::instance()->viewManager().currentDesignDocument();
if (document)
return QUrl::fromLocalFile(document->projectFolder().toString());
#endif
return {};
}

View File

@@ -464,7 +464,8 @@ void RewriterView::auxiliaryDataChanged(const ModelNode &node, const PropertyNam
return;
if (node.isRootNode()) {
if (name == "width" || name == "height" || name == "autoSize" || name == "formeditorColor")
if (name == "width" || name == "height" || name == "autoSize" || name == "formeditorColor"
|| name == "formeditorZoom")
return;
}

View File

@@ -43,7 +43,7 @@ class ProjectStorage;
using PathCache = SourcePathCache<ProjectStorage<Sqlite::Database>, NonLockingMutex>;
class FileSystem final : public FileSystemInterface
class FileSystem : public FileSystemInterface
{
public:
FileSystem(PathCache &sourcePathCache)

View File

@@ -1924,6 +1924,8 @@ private:
void createTypesAndePropertyDeclarationsTables(Database &database,
const Sqlite::Column &foreignModuleIdColumn)
{
Q_UNUSED(foreignModuleIdColumn)
Sqlite::Table typesTable;
typesTable.setUseIfNotExists(true);
typesTable.setName("types");

View File

@@ -214,11 +214,7 @@ void DesignModeWidget::setup()
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
// Setup icons
const QColor iconColor(Theme::getColor(Theme::DStitleBarIcon));
const QString closeUnicode = Theme::getIconUnicode(Theme::Icon::adsClose);
const QString menuUnicode = Theme::getIconUnicode(Theme::Icon::adsDropDown);
const QString undockUnicode = Theme::getIconUnicode(Theme::Icon::adsDetach);
const QString fontName = "qtds_propertyIconFont.ttf";
const QSize size = QSize(28, 28);

View File

@@ -34,7 +34,7 @@
#include <QMetaObject>
namespace Utils {
namespace QmlDesigner {
enum FoundLicense {
community,

View File

@@ -107,6 +107,8 @@ const char EVENT_TIMELINE_TIME[] = "Timeline";
const char EVENT_TRANSITIONEDITOR_TIME[] = "Transition Editor";
const char EVENT_CURVEDITOR_TIME[] = "Curve Editor";
const char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal";
namespace Internal {
enum { debug = 0 };
}

View File

@@ -312,8 +312,11 @@ bool QmlDesignerPlugin::delayedInitialize()
d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::PathTool>());
d->viewManager.registerFormEditorTool(std::make_unique<QmlDesigner::TransitionTool>());
if (QmlProjectManager::QmlProject::isQtDesignStudio())
if (QmlProjectManager::QmlProject::isQtDesignStudio()) {
emitUsageStatistics("StandaloneMode");
if (QmlProjectManager::QmlProject::isQtDesignStudioStartedFromQtC())
emitUsageStatistics("QDSlaunchedFromQtC");
}
return true;
}

Some files were not shown because too many files have changed in this diff Show More