From e1eea7c9dbf177cf47bd381dfb10d27da85f3ca6 Mon Sep 17 00:00:00 2001
From: Rainer Keller <Rainer.Keller@qt.io>
Date: Tue, 18 Oct 2022 07:37:44 +0200
Subject: [PATCH] Show error in UI

Change-Id: Iacd5b4a0a3dffb9f75a5e7144907e400c503b55c

# Conflicts:
#	src/plugins/mcusupport/mcutargetfactory.cpp

# Conflicts:
#	src/plugins/mcusupport/mcutargetfactory.cpp
---
 src/plugins/mcusupport/mcuabstractpackage.h   |  1 +
 src/plugins/mcusupport/mcupackage.cpp         | 60 ++++++++++++++-----
 src/plugins/mcusupport/mcupackage.h           |  8 +++
 .../mcusupport/mcusupportoptionspage.cpp      |  2 +-
 src/plugins/mcusupport/mcutargetfactory.cpp   | 38 ++++++------
 5 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/src/plugins/mcusupport/mcuabstractpackage.h b/src/plugins/mcusupport/mcuabstractpackage.h
index e4240a41c5..ae04531651 100644
--- a/src/plugins/mcusupport/mcuabstractpackage.h
+++ b/src/plugins/mcusupport/mcuabstractpackage.h
@@ -20,6 +20,7 @@ public:
     enum class Status {
         EmptyPath,
         InvalidPath,
+        InvalidJson,
         ValidPathInvalidPackage,
         ValidPackageMismatchedVersion,
         ValidPackage
diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp
index 93310399ef..4ff5842041 100644
--- a/src/plugins/mcusupport/mcupackage.cpp
+++ b/src/plugins/mcusupport/mcupackage.cpp
@@ -126,20 +126,25 @@ void McuPackage::updatePath()
 
 void McuPackage::updateStatus()
 {
-    bool validPath = !m_path.isEmpty() && m_path.exists();
-    const FilePath detectionPath = basePath() / m_detectionPath.path();
-    const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
-    m_detectedVersion = validPath && validPackage && m_versionDetector
-                            ? m_versionDetector->parseVersion(basePath())
-                            : 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;
+    if (!m_jsonErrorMessage.isEmpty()) {
+        // The JSON file content has an error
+        m_status = Status::InvalidJson;
+    } else {
+        bool validPath = !m_path.isEmpty() && m_path.exists();
+        const FilePath detectionPath = basePath() / m_detectionPath.path();
+        const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
+        m_detectedVersion = validPath && validPackage && m_versionDetector
+                                ? m_versionDetector->parseVersion(basePath())
+                                : 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();
 }
@@ -215,6 +220,11 @@ QString McuPackage::statusText() const
                        ? tr("Path is empty.")
                        : tr("Path is empty, %1 not found.").arg(displayRequiredPath);
         break;
+    case Status::InvalidJson:
+        response = m_jsonErrorMessage;
+        if (!m_informationSourceFile.isEmpty())
+            response += " " + tr("File:") + " " + m_informationSourceFile;
+        break;
     }
     return response;
 }
@@ -224,6 +234,22 @@ bool McuPackage::writeToSettings() const
     return settingsHandler->write(m_settingsKey, m_path, m_defaultPath);
 }
 
+void McuPackage::setInformationSourceFile(const QString &fileName)
+{
+    m_informationSourceFile = fileName;
+}
+
+const QString &McuPackage::informationSourceFile() const
+{
+    return m_informationSourceFile;
+}
+
+void McuPackage::setJsonErrorMessage(const QString &message)
+{
+     m_jsonErrorMessage = message;
+     updateStatus();
+}
+
 QWidget *McuPackage::widget()
 {
     auto *widget = new QWidget;
@@ -261,6 +287,12 @@ QWidget *McuPackage::widget()
     });
 
     updateStatus();
+
+    if (m_status == Status::InvalidJson) {
+        // The invalid JSON is considered a permanent error and it does not make
+        // sense to allow the user to do any changes in the line edit.
+        m_fileChooser->hide();
+    }
     return widget;
 }
 
diff --git a/src/plugins/mcusupport/mcupackage.h b/src/plugins/mcusupport/mcupackage.h
index 631b514998..0cf7495354 100644
--- a/src/plugins/mcusupport/mcupackage.h
+++ b/src/plugins/mcusupport/mcupackage.h
@@ -63,6 +63,11 @@ public:
 
     bool writeToSettings() const override;
 
+    void setInformationSourceFile(const QString &fileName);
+    const QString &informationSourceFile() const;
+
+    void setJsonErrorMessage(const QString &message);
+
     QWidget *widget() override;
     const McuPackageVersionDetector *getVersionDetector() const override;
 
@@ -91,6 +96,9 @@ private:
     const QString m_downloadUrl;
     const bool m_addToSystemPath;
 
+    QString m_informationSourceFile; // This is usually the JSON file there the information was taken from
+    QString m_jsonErrorMessage;
+
     Status m_status = Status::InvalidPath;
 }; // class McuPackage
 
diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp
index fd166245a7..6ac293b811 100644
--- a/src/plugins/mcusupport/mcusupportoptionspage.cpp
+++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp
@@ -255,7 +255,7 @@ void McuSupportOptionsWidget::showMcuTargetPackages()
     }
 
     for (const auto &package : mcuTarget->packages()) {
-        if (package->label().isEmpty())
+        if (package->label().isEmpty() && package->status() != McuPackage::Status::InvalidJson)
             continue;
         QWidget *packageWidget = package->widget();
         m_packagesLayout->addRow(package->label(), packageWidget);
diff --git a/src/plugins/mcusupport/mcutargetfactory.cpp b/src/plugins/mcusupport/mcutargetfactory.cpp
index 20bf691fc6..ff497e4331 100644
--- a/src/plugins/mcusupport/mcutargetfactory.cpp
+++ b/src/plugins/mcusupport/mcutargetfactory.cpp
@@ -4,7 +4,6 @@
 #include "mcutargetfactory.h"
 #include "mcuhelpers.h"
 #include "mcupackage.h"
-#include "mcusupportplugin.h"
 #include "mcusupportversiondetection.h"
 #include "mcutarget.h"
 #include "mcutargetdescription.h"
@@ -44,7 +43,7 @@ McuPackageVersionDetector *createVersionDetection(const VersionDetection &versio
 static void removeEmptyPackages(Packages &packages)
 {
     for (const McuPackagePtr &pkg : packages) {
-        if (pkg->cmakeVariableName().isEmpty() && pkg->path().isEmpty())
+        if (pkg->cmakeVariableName().isEmpty() && pkg->path().isEmpty() && pkg->status() != McuPackage::Status::InvalidJson)
             packages.remove(pkg);
     }
 }
@@ -87,7 +86,6 @@ QPair<Targets, Packages> McuTargetFactory::createTargets(const McuTargetDescript
         targetPackages.insert({qtForMCUsPackage});
         targetPackages.unite({toolchainFile});
 
-        removeEmptyPackages(targetPackages);
         expandVariables(targetPackages);
 
         packages.unite(targetPackages);
@@ -187,24 +185,30 @@ McuToolChainPackage *McuTargetFactory::createToolchain(
         errorMessage = McuPackage::tr("the toolchain file cmakeVar in the JSON config file is empty");
     }
 
-    if (!errorMessage.isEmpty()) {
+    if (!errorMessage.isEmpty())
         toolchainType = McuToolChainPackage::ToolChainType::Unsupported;
 
-        printMessage(McuPackage::tr("Toolchain description for \"%1\" is invalid because %2. File: %3")
-                     .arg(toolchain.id).arg(errorMessage).arg(sourceFile),
-                     true);
+    auto ptr = new McuToolChainPackage{settingsHandler,
+                                       compilerDescription.label,
+                                       compilerDescription.defaultPath,
+                                       compilerDescription.validationPath,
+                                       compilerDescription.setting,
+                                       toolchainType,
+                                       toolchain.versions,
+                                       compilerDescription.cmakeVar,
+                                       compilerDescription.envVar,
+                                       createVersionDetection(compilerDescription.versionDetection)};
+
+    ptr->setInformationSourceFile(sourceFile);
+
+    if (!errorMessage.isEmpty()) {
+        ptr->setJsonErrorMessage(
+        McuPackage::tr("Toolchain description for \"%1\" is invalid because %2.")
+                     .arg(toolchain.id).arg(errorMessage)
+                     );
     }
 
-    return new McuToolChainPackage{settingsHandler,
-                                   compilerDescription.label,
-                                   compilerDescription.defaultPath,
-                                   compilerDescription.validationPath,
-                                   compilerDescription.setting,
-                                   toolchainType,
-                                   toolchain.versions,
-                                   compilerDescription.cmakeVar,
-                                   compilerDescription.envVar,
-                                   createVersionDetection(compilerDescription.versionDetection)};
+    return ptr;
 }
 
 } // namespace McuSupport::Internal
-- 
2.37.3

