From 5b7a3fba27fdcb385fc808a2e04339788996e937 Mon Sep 17 00:00:00 2001 From: Christiaan Janssen Date: Fri, 4 Dec 2020 16:32:34 +0100 Subject: [PATCH] McuSupport: Display errors when configuring Qt for MCUs SDK Fixes: QTCREATORBUG-25258 Change-Id: I6f445bddb51f3bc1850793966f049c4b7ce7889f Reviewed-by: Alessandro Portale Reviewed-by: Erik Verbruggen --- src/plugins/mcusupport/mcusupportoptions.cpp | 123 ++++++++++++++---- src/plugins/mcusupport/mcusupportoptions.h | 11 +- .../mcusupport/mcusupportoptionspage.cpp | 16 ++- src/plugins/mcusupport/mcusupportsdk.cpp | 28 +++- src/plugins/mcusupport/mcusupportsdk.h | 2 + 5 files changed, 151 insertions(+), 29 deletions(-) diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index da14c59f01c..375ed7ec4e6 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -105,10 +106,14 @@ McuPackage::McuPackage(const QString &label, const QString &defaultPath, m_automaticKitCreation = automaticKitCreationFromSettings(QSettings::UserScope); } +QString McuPackage::basePath() const +{ + return m_fileChooser != nullptr ? m_fileChooser->filePath().toString() : m_path; +} + 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 @@ -159,8 +164,12 @@ QWidget *McuPackage::widget() m_fileChooser->setPath(m_path); + QObject::connect(this, &McuPackage::statusChanged, this, [this] { + updateStatusUi(); + }); + QObject::connect(m_fileChooser, &PathChooser::pathChanged, this, [this] { - updateStatus(); + updatePath(); emit changed(); }); @@ -228,35 +237,58 @@ void McuPackage::setAutomaticKitCreationEnabled(const bool enabled) m_automaticKitCreation = enabled; } +void McuPackage::updatePath() +{ + m_path = m_fileChooser->rawPath(); + m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); + updateStatus(); +} + void McuPackage::updateStatus() { - m_path = m_fileChooser->rawPath(); - const bool validPath = m_fileChooser->isValid(); - const FilePath detectionPath = FilePath::fromString( - m_fileChooser->filePath().toString() + "/" + m_detectionPath); - const QString displayDetectionPath = FilePath::fromString(m_detectionPath).toUserOutput(); + 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(); - 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->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) { case ValidPackage: - statusText = m_detectionPath.isEmpty() - ? tr("Path exists.") - : tr("Path is valid, \"%1\" was found.").arg(displayDetectionPath); + response = m_detectionPath.isEmpty() + ? tr("Path %1 exists.").arg(displayPackagePath) + : tr("Path %1 is valid, %2 was found.") + .arg(displayPackagePath, displayDetectionPath); break; 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; 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; } - m_infoLabel->setText(statusText); - m_fileChooser->lineEdit()->button(FancyLineEdit::Right)->setEnabled(m_path != m_defaultPath); + return response; } McuToolChainPackage::McuToolChainPackage(const QString &label, @@ -453,6 +485,7 @@ McuTarget::Platform McuTarget::platform() const bool McuTarget::isValid() const { return !Utils::anyOf(packages(), [](McuPackage *package) { + package->updateStatus(); return package->status() != McuPackage::ValidPackage; }); } @@ -544,8 +577,9 @@ const QVersionNumber &McuSupportOptions::minimalQulVersion() void McuSupportOptions::setQulDir(const FilePath &dir) { deletePackagesAndTargets(); - Sdk::targetsAndPackages(dir, &packages, &mcuTargets); - //packages.append(qtForMCUsSdkPackage); + qtForMCUsSdkPackage->updateStatus(); + if (qtForMCUsSdkPackage->status() == McuPackage::Status::ValidPackage) + Sdk::targetsAndPackages(dir, &packages, &mcuTargets); for (auto package : packages) connect(package, &McuPackage::changed, this, &McuSupportOptions::changed); @@ -772,27 +806,70 @@ Kit *McuSupportOptions::newKit(const McuTarget *mcuTarget, const McuPackage *qtF 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() { - if (qulDirFromSettings().isEmpty()) - return; - auto qtForMCUsPackage = Sdk::createQtForMCUsPackage(); + const auto createKits = [qtForMCUsPackage]() { 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()); QVector packages; QVector mcuTargets; Sdk::targetsAndPackages(dir, &packages, &mcuTargets); for (auto target: qAsConst(mcuTargets)) - if (existingKits(target).isEmpty()) + if (target->isValid() && existingKits(target).isEmpty()) newKit(target, qtForMCUsPackage); qDeleteAll(packages); qDeleteAll(mcuTargets); } + }; + createKits(); delete qtForMCUsPackage; } diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 28671d0127e..382b0e7a803 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -47,12 +47,15 @@ class ToolChain; namespace McuSupport { namespace Internal { +void printMessage(const QString &message, bool important); + class McuPackage : public QObject { Q_OBJECT public: enum Status { + EmptyPath, InvalidPath, ValidPathInvalidPackage, ValidPackage @@ -62,10 +65,14 @@ public: const QString &settingsKey); virtual ~McuPackage() = default; + QString basePath() const; QString path() const; QString label() const; QString defaultPath() const; QString detectionPath() const; + QString statusText() const; + void updateStatus(); + Status status() const; void setDownloadUrl(const QString &url); void setEnvironmentVariableName(const QString &name); @@ -84,9 +91,11 @@ public: signals: void changed(); + void statusChanged(); private: - void updateStatus(); + void updatePath(); + void updateStatusUi(); QWidget *m_widget = nullptr; Utils::PathChooser *m_fileChooser = nullptr; diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index f64e7330f7e..11cc8330f60 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -26,6 +26,7 @@ #include "mcusupportconstants.h" #include "mcusupportoptionspage.h" #include "mcusupportoptions.h" +#include "mcusupportsdk.h" #include #include @@ -80,6 +81,7 @@ private: QCheckBox *m_kitAutomaticCreationCheckBox = nullptr; Utils::InfoLabel *m_kitCreationInfoLabel = nullptr; Utils::InfoLabel *m_statusInfoLabel = nullptr; + Utils::InfoLabel *m_mcuTargetsInfoLabel = nullptr; QPushButton *m_kitCreationPushButton = nullptr; QPushButton *m_kitRemovalPushButton = nullptr; }; @@ -128,6 +130,11 @@ McuSupportOptionsWidget::McuSupportOptionsWidget() 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")); connect(m_kitAutomaticCreationCheckBox, &QCheckBox::stateChanged, this, [this] (int state) { @@ -177,11 +184,18 @@ void McuSupportOptionsWidget::updateStatus() // Page elements { m_qtForMCUsSdkGroupBox->setVisible(cMakeAvailable); - const bool ready = cMakeAvailable && mcuTarget && + const bool valid = cMakeAvailable && m_options.qtForMCUsSdkPackage->status() == McuPackage::ValidPackage; + const bool ready = valid && mcuTarget; m_mcuTargetsGroupBox->setVisible(ready); m_packagesGroupBox->setVisible(ready && !mcuTarget->packages().isEmpty()); 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 diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index 580ee74f834..5ae3c81ee34 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -515,9 +515,14 @@ static QVector targetsFromDescriptions(const QList *packa { QList descriptions; - for (const QFileInfo &fileInfo : targetDescriptionFiles(dir)) { + auto descriptionFiles = targetDescriptionFiles(dir); + for (const QFileInfo &fileInfo : descriptionFiles) { QFile file(fileInfo.absoluteFilePath()); if (!file.open(QFile::ReadOnly)) continue; const McuTargetDescription desc = parseDescriptionJson(file.readAll()); - if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) - return; // Invalid version means invalid SDK installation. + if (QVersionNumber::fromString(desc.qulVersion) < McuSupportOptions::minimalQulVersion()) { + 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); } + // 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. // Desktop JSON file is shipped starting from Qul 1.5. // This whole section could be removed when minimalQulVersion will reach 1.5 or above diff --git a/src/plugins/mcusupport/mcusupportsdk.h b/src/plugins/mcusupport/mcusupportsdk.h index d9111fc5846..da471196122 100644 --- a/src/plugins/mcusupport/mcusupportsdk.h +++ b/src/plugins/mcusupport/mcusupportsdk.h @@ -43,6 +43,8 @@ McuPackage *createQtForMCUsPackage(); void targetsAndPackages(const Utils::FilePath &qulDir, QVector *packages, QVector *mcuTargets); +Utils::FilePath kitsPath(const Utils::FilePath &dir); + } // namespace Sdk } // namespace Internal } // namespace McuSupport