McuSupport: Display errors when configuring Qt for MCUs SDK

Fixes: QTCREATORBUG-25258
Change-Id: I6f445bddb51f3bc1850793966f049c4b7ce7889f
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Reviewed-by: Erik Verbruggen <erik.verbruggen@me.com>
This commit is contained in:
Christiaan Janssen
2020-12-04 16:32:34 +01:00
committed by christiaan.janssen
parent ef5b4b8db5
commit 5b7a3fba27
5 changed files with 151 additions and 29 deletions

View File

@@ -31,6 +31,7 @@
#include <cmakeprojectmanager/cmaketoolmanager.h> #include <cmakeprojectmanager/cmaketoolmanager.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/helpmanager.h> #include <coreplugin/helpmanager.h>
#include <coreplugin/messagemanager.h>
#include <cmakeprojectmanager/cmakekitinformation.h> #include <cmakeprojectmanager/cmakekitinformation.h>
#include <debugger/debuggeritem.h> #include <debugger/debuggeritem.h>
#include <debugger/debuggeritemmanager.h> #include <debugger/debuggeritemmanager.h>
@@ -105,10 +106,14 @@ McuPackage::McuPackage(const QString &label, const QString &defaultPath,
m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope);
} }
QString McuPackage::basePath() const
{
return m_fileChooser != nullptr ? m_fileChooser->filePath().toString() : m_path;
}
QString McuPackage::path() const QString McuPackage::path() const
{ {
QString basePath = m_fileChooser != nullptr ? m_fileChooser->filePath().toString() : m_path; return QFileInfo(basePath() + m_relativePathModifier).absoluteFilePath();
return QFileInfo(basePath + m_relativePathModifier).absoluteFilePath();
} }
QString McuPackage::label() const QString McuPackage::label() const
@@ -159,8 +164,12 @@ QWidget *McuPackage::widget()
m_fileChooser->setPath(m_path); m_fileChooser->setPath(m_path);
QObject::connect(this, &McuPackage::statusChanged, this, [this] {
updateStatusUi();
});
QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] {
updateStatus(); updatePath();
emit changed(); emit changed();
}); });
@@ -228,35 +237,58 @@ void McuPackage::setAutomaticKitCreationEnabled(const bool enabled)
m_automaticKitCreation = enabled; m_automaticKitCreation = enabled;
} }
void McuPackage::updateStatus() void McuPackage::updatePath()
{ {
m_path = m_fileChooser->rawPath(); m_path = m_fileChooser->rawPath();
const bool validPath = m_fileChooser->isValid(); m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath);
const FilePath detectionPath = FilePath::fromString( updateStatus();
m_fileChooser->filePath().toString() + "/" + m_detectionPath); }
const QString displayDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput();
void McuPackage::updateStatus()
{
bool validPath = !m_path.isEmpty() && FilePath::fromString(m_path).exists();
const FilePath detectionPath = FilePath::fromString(basePath() + "/" + m_detectionPath);
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists(); const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
m_status = validPath ? (validPackage ? ValidPackage : ValidPathInvalidPackage) : InvalidPath; m_status = validPath ? (validPackage ? ValidPackage : ValidPathInvalidPackage) :
m_path.isEmpty() ? EmptyPath : InvalidPath;
emit statusChanged();
}
void McuPackage::updateStatusUi()
{
m_infoLabel->setType(m_status == ValidPackage ? InfoLabel::Ok : InfoLabel::NotOk); m_infoLabel->setType(m_status == ValidPackage ? InfoLabel::Ok : InfoLabel::NotOk);
m_infoLabel->setText(statusText());
}
QString statusText; QString McuPackage::statusText() const
{
const QString displayPackagePath = FilePath::fromString(m_path).toUserOutput();
const QString displayDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput();
QString response;
switch (m_status) { switch (m_status) {
case ValidPackage: case ValidPackage:
statusText = m_detectionPath.isEmpty() response = m_detectionPath.isEmpty()
? tr("Path exists.") ? tr("Path %1 exists.").arg(displayPackagePath)
: tr("Path is valid, \"%1\" was found.").arg(displayDetectionPath); : tr("Path %1 is valid, %2 was found.")
.arg(displayPackagePath, displayDetectionPath);
break; break;
case ValidPathInvalidPackage: case ValidPathInvalidPackage:
statusText = tr("Path exists, but does not contain \"%1\".").arg(displayDetectionPath); response = tr("Path %1 exists, but does not contain %2.")
.arg(displayPackagePath, displayDetectionPath);
break; break;
case InvalidPath: case InvalidPath:
statusText = tr("Path does not exist."); response = tr("Path %1 does not exist.").arg(displayPackagePath);
break;
case EmptyPath:
response = m_detectionPath.isEmpty()
? tr("Path is empty.")
: tr("Path is empty, %1 not found.")
.arg(displayDetectionPath);
break; break;
} }
m_infoLabel->setText(statusText); return response;
m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath);
} }
McuToolChainPackage::McuToolChainPackage(const QString &label, McuToolChainPackage::McuToolChainPackage(const QString &label,
@@ -453,6 +485,7 @@ McuTarget::Platform McuTarget::platform() const
bool McuTarget::isValid() const bool McuTarget::isValid() const
{ {
return !Utils::anyOf(packages(), [](McuPackage *package) { return !Utils::anyOf(packages(), [](McuPackage *package) {
package->updateStatus();
return package->status() != McuPackage::ValidPackage; return package->status() != McuPackage::ValidPackage;
}); });
} }
@@ -544,8 +577,9 @@ const QVersionNumber &McuSupportOptions::minimalQulVersion()
void McuSupportOptions::setQulDir(const FilePath &dir) void McuSupportOptions::setQulDir(const FilePath &dir)
{ {
deletePackagesAndTargets(); deletePackagesAndTargets();
qtForMCUsSdkPackage->updateStatus();
if (qtForMCUsSdkPackage->status() == McuPackage::Status::ValidPackage)
Sdk::targetsAndPackages(dir, &packages, &mcuTargets); Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
//packages.append(qtForMCUsSdkPackage);
for (auto package : packages) for (auto package : packages)
connect(package, &McuPackage::changed, this, &McuSupportOptions::changed); connect(package, &McuPackage::changed, this, &McuSupportOptions::changed);
@@ -772,27 +806,70 @@ Kit *McuSupportOptions::newKit(const McuTarget *mcuTarget, const McuPackage *qtF
return KitManager::registerKit(init); return KitManager::registerKit(init);
} }
void printMessage(const QString &message, bool important)
{
const QString displayMessage = QCoreApplication::translate("QtForMCUs", "Qt for MCUs: %1").arg(message);
if (important)
Core::MessageManager::writeFlashing(displayMessage);
else
Core::MessageManager::writeSilently(displayMessage);
}
void McuSupportOptions::createAutomaticKits() void McuSupportOptions::createAutomaticKits()
{ {
if (qulDirFromSettings().isEmpty())
return;
auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); auto qtForMCUsPackage = Sdk::createQtForMCUsPackage();
const auto createKits = [qtForMCUsPackage]() {
if (qtForMCUsPackage->automaticKitCreationEnabled()) { if (qtForMCUsPackage->automaticKitCreationEnabled()) {
qtForMCUsPackage->updateStatus();
if (qtForMCUsPackage->status() != McuPackage::ValidPackage) {
switch (qtForMCUsPackage->status()) {
case McuPackage::ValidPathInvalidPackage: {
const QString displayPath = FilePath::fromString(qtForMCUsPackage->detectionPath())
.toUserOutput();
printMessage(tr("Path %1 exists, but does not contain %2.")
.arg(qtForMCUsPackage->path(), displayPath),
true);
break;
}
case McuPackage::InvalidPath: {
printMessage(tr("Path %1 does not exist. Add the path in Tools > Options > Devices > MCU.")
.arg(qtForMCUsPackage->path()),
true);
break;
}
case McuPackage::EmptyPath: {
printMessage(tr("Missing %1. Add the path in Tools > Options > Devices > MCU.")
.arg(qtForMCUsPackage->detectionPath()),
true);
return;
}
default: break;
}
return;
}
if (CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty()) {
printMessage(tr("No CMake tool was detected. Add a CMake tool in Tools > Options > Kits > CMake."),
true);
return;
}
auto dir = FilePath::fromUserInput(qtForMCUsPackage->path()); auto dir = FilePath::fromUserInput(qtForMCUsPackage->path());
QVector<McuPackage*> packages; QVector<McuPackage*> packages;
QVector<McuTarget*> mcuTargets; QVector<McuTarget*> mcuTargets;
Sdk::targetsAndPackages(dir, &packages, &mcuTargets); Sdk::targetsAndPackages(dir, &packages, &mcuTargets);
for (auto target: qAsConst(mcuTargets)) for (auto target: qAsConst(mcuTargets))
if (existingKits(target).isEmpty()) if (target->isValid() && existingKits(target).isEmpty())
newKit(target, qtForMCUsPackage); newKit(target, qtForMCUsPackage);
qDeleteAll(packages); qDeleteAll(packages);
qDeleteAll(mcuTargets); qDeleteAll(mcuTargets);
} }
};
createKits();
delete qtForMCUsPackage; delete qtForMCUsPackage;
} }

View File

@@ -47,12 +47,15 @@ class ToolChain;
namespace McuSupport { namespace McuSupport {
namespace Internal { namespace Internal {
void printMessage(const QString &message, bool important);
class McuPackage : public QObject class McuPackage : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum Status { enum Status {
EmptyPath,
InvalidPath, InvalidPath,
ValidPathInvalidPackage, ValidPathInvalidPackage,
ValidPackage ValidPackage
@@ -62,10 +65,14 @@ public:
const QString &settingsKey); const QString &settingsKey);
virtual ~McuPackage() = default; virtual ~McuPackage() = default;
QString basePath() const;
QString path() const; QString path() const;
QString label() const; QString label() const;
QString defaultPath() const; QString defaultPath() const;
QString detectionPath() const; QString detectionPath() const;
QString statusText() const;
void updateStatus();
Status status() const; Status status() const;
void setDownloadUrl(const QString &url); void setDownloadUrl(const QString &url);
void setEnvironmentVariableName(const QString &name); void setEnvironmentVariableName(const QString &name);
@@ -84,9 +91,11 @@ public:
signals: signals:
void changed(); void changed();
void statusChanged();
private: private:
void updateStatus(); void updatePath();
void updateStatusUi();
QWidget *m_widget = nullptr; QWidget *m_widget = nullptr;
Utils::PathChooser *m_fileChooser = nullptr; Utils::PathChooser *m_fileChooser = nullptr;

View File

@@ -26,6 +26,7 @@
#include "mcusupportconstants.h" #include "mcusupportconstants.h"
#include "mcusupportoptionspage.h" #include "mcusupportoptionspage.h"
#include "mcusupportoptions.h" #include "mcusupportoptions.h"
#include "mcusupportsdk.h"
#include <cmakeprojectmanager/cmakeprojectconstants.h> #include <cmakeprojectmanager/cmakeprojectconstants.h>
#include <cmakeprojectmanager/cmaketoolmanager.h> #include <cmakeprojectmanager/cmaketoolmanager.h>
@@ -80,6 +81,7 @@ private:
QCheckBox *m_kitAutomaticCreationCheckBox = nullptr; QCheckBox *m_kitAutomaticCreationCheckBox = nullptr;
Utils::InfoLabel *m_kitCreationInfoLabel = nullptr; Utils::InfoLabel *m_kitCreationInfoLabel = nullptr;
Utils::InfoLabel *m_statusInfoLabel = nullptr; Utils::InfoLabel *m_statusInfoLabel = nullptr;
Utils::InfoLabel *m_mcuTargetsInfoLabel = nullptr;
QPushButton *m_kitCreationPushButton = nullptr; QPushButton *m_kitCreationPushButton = nullptr;
QPushButton *m_kitRemovalPushButton = nullptr; QPushButton *m_kitRemovalPushButton = nullptr;
}; };
@@ -128,6 +130,11 @@ McuSupportOptionsWidget::McuSupportOptionsWidget()
m_packagesGroupBox->setLayout(m_packagesLayout); m_packagesGroupBox->setLayout(m_packagesLayout);
} }
{
m_mcuTargetsInfoLabel = new Utils::InfoLabel;
mainLayout->addWidget(m_mcuTargetsInfoLabel);
}
{ {
m_kitAutomaticCreationCheckBox = new QCheckBox(tr("Automatically create kits for all available targets on start")); m_kitAutomaticCreationCheckBox = new QCheckBox(tr("Automatically create kits for all available targets on start"));
connect(m_kitAutomaticCreationCheckBox, &QCheckBox::stateChanged, this, [this] (int state) { connect(m_kitAutomaticCreationCheckBox, &QCheckBox::stateChanged, this, [this] (int state) {
@@ -177,11 +184,18 @@ void McuSupportOptionsWidget::updateStatus()
// Page elements // Page elements
{ {
m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable); m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable);
const bool ready = cMakeAvailable && mcuTarget && const bool valid = cMakeAvailable &&
m_options.qtForMCUsSdkPackage->status() == McuPackage::ValidPackage; m_options.qtForMCUsSdkPackage->status() == McuPackage::ValidPackage;
const bool ready = valid && mcuTarget;
m_mcuTargetsGroupBox->setVisible(ready); m_mcuTargetsGroupBox->setVisible(ready);
m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty()); m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty());
m_kitCreationGroupBox->setVisible(ready); m_kitCreationGroupBox->setVisible(ready);
m_mcuTargetsInfoLabel->setVisible(valid && m_options.mcuTargets.isEmpty());
if (m_mcuTargetsInfoLabel->isVisible()) {
m_mcuTargetsInfoLabel->setType(Utils::InfoLabel::NotOk);
auto displayKitsPath = Sdk::kitsPath(Utils::FilePath::fromString(m_options.qtForMCUsSdkPackage->basePath())).toUserOutput();
m_mcuTargetsInfoLabel->setText(tr("No valid kit descriptions found at %1.").arg(displayKitsPath));
}
} }
// Kit creation status // Kit creation status

View File

@@ -515,9 +515,14 @@ static QVector<McuTarget *> targetsFromDescriptions(const QList<McuTargetDescrip
return mcuTargets; return mcuTargets;
} }
Utils::FilePath kitsPath(const Utils::FilePath &dir)
{
return dir + "/kits/";
}
static QFileInfoList targetDescriptionFiles(const Utils::FilePath &dir) static QFileInfoList targetDescriptionFiles(const Utils::FilePath &dir)
{ {
const QDir kitsDir(dir.toString() + "/kits/", "*.json"); const QDir kitsDir(kitsPath(dir).toString(), "*.json");
return kitsDir.entryInfoList(); return kitsDir.entryInfoList();
} }
@@ -554,16 +559,31 @@ void targetsAndPackages(const Utils::FilePath &dir, QVector<McuPackage *> *packa
{ {
QList<McuTargetDescription> descriptions; QList<McuTargetDescription> descriptions;
for (const QFileInfo &fileInfo : targetDescriptionFiles(dir)) { auto descriptionFiles = targetDescriptionFiles(dir);
for (const QFileInfo &fileInfo : descriptionFiles) {
QFile file(fileInfo.absoluteFilePath()); QFile file(fileInfo.absoluteFilePath());
if (!file.open(QFile::ReadOnly)) if (!file.open(QFile::ReadOnly))
continue; continue;
const McuTargetDescription desc = parseDescriptionJson(file.readAll()); const McuTargetDescription desc = parseDescriptionJson(file.readAll());
if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) {
return; // Invalid version means invalid SDK installation. auto pth = Utils::FilePath::fromString(fileInfo.filePath());
printMessage(QObject::tr("Skipped %1 - Unsupported version \"%2\" (should be >= %3)")
.arg(
QDir::toNativeSeparators(pth.fileNameWithPathComponents(1)),
desc.qulVersion,
McuSupportOptions::minimalQulVersion().toString()),
false);
continue;
}
descriptions.append(desc); descriptions.append(desc);
} }
// No valid description means invalid SDK installation.
if (descriptions.empty() && kitsPath(dir).exists()) {
printMessage(QObject::tr("No valid kit descriptions found at %1.").arg(kitsPath(dir).toUserOutput()), true);
return;
}
// Workaround for missing JSON file for Desktop target. // Workaround for missing JSON file for Desktop target.
// Desktop JSON file is shipped starting from Qul 1.5. // Desktop JSON file is shipped starting from Qul 1.5.
// This whole section could be removed when minimalQulVersion will reach 1.5 or above // This whole section could be removed when minimalQulVersion will reach 1.5 or above

View File

@@ -43,6 +43,8 @@ McuPackage *createQtForMCUsPackage();
void targetsAndPackages(const Utils::FilePath &qulDir, void targetsAndPackages(const Utils::FilePath &qulDir,
QVector<McuPackage*> *packages, QVector<McuTarget*> *mcuTargets); QVector<McuPackage*> *packages, QVector<McuTarget*> *mcuTargets);
Utils::FilePath kitsPath(const Utils::FilePath &dir);
} // namespace Sdk } // namespace Sdk
} // namespace Internal } // namespace Internal
} // namespace McuSupport } // namespace McuSupport