McuSupport: Add dialog for Qt MCUs kit creation status and help

The status of automatically created kits or manually updated ones is
displayed in "General Messages" along with other messages making it
difficult to know if something went wrong with kit creation.

To avoid showing a dialog at QtC startup an InfoBar message was added
with a detail button that will open a dialog listing all the messages
with their platform, package and Os providing an easy button to go to
the MCU Option page to fix the package of a help button pointing to the
prerequisites documentation.

Fixes: QTCREATORBUG-28920
Change-Id: I20c30d968fbd2d4c6d10d16504a51e7201a2db3b
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Yasser Grimes
2023-03-24 17:49:27 +02:00
parent 2ad153f30e
commit 7aec8c0b14
15 changed files with 411 additions and 26 deletions

View File

@@ -24,6 +24,7 @@ add_qtc_plugin(McuSupport
settingshandler.cpp settingshandler.h
mcuqmlprojectnode.cpp mcuqmlprojectnode.h
mcubuildstep.cpp mcubuildstep.h
dialogs/mcukitcreationdialog.h dialogs/mcukitcreationdialog.cpp dialogs/mcukitcreationdialog.ui
)
add_subdirectory(test)

View File

@@ -0,0 +1,98 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "mcukitcreationdialog.h"
#include "ui_mcukitcreationdialog.h"
#include "mcuabstractpackage.h"
#include "mcusupportconstants.h"
#include "mcusupporttr.h"
#include <utils/filepath.h>
#include <utils/icon.h>
#include <coreplugin/icore.h>
#include <QCheckBox>
#include <QDesktopServices>
#include <QPushButton>
#include <QStyle>
#include <QPushButton>
namespace McuSupport::Internal {
McuKitCreationDialog::McuKitCreationDialog(const MessagesList &messages,
const SettingsHandler::Ptr &settingsHandler,
McuPackagePtr qtMCUPackage,
QWidget *parent)
: QDialog(parent)
, ui(new Ui::McuKitCreationDialog)
, m_messages(messages)
{
ui->setupUi(this);
ui->iconLabel->setPixmap(Utils::Icon(":/mcusupport/images/mcusupportdevice.png").pixmap());
m_previousButton = ui->buttonBox->addButton("<", QDialogButtonBox::ActionRole);
m_nextButton = ui->buttonBox->addButton(">", QDialogButtonBox::ActionRole);
m_fixButton = ui->buttonBox->addButton(Tr::tr("Fix"), QDialogButtonBox::ActionRole);
m_helpButton = ui->buttonBox->addButton(Tr::tr("Help"), QDialogButtonBox::HelpRole);
// prevent clicking the buttons from closing the message box
m_nextButton->disconnect();
m_previousButton->disconnect();
if (messages.size() == 1) {
m_nextButton->setVisible(false);
m_previousButton->setVisible(false);
}
//display first message
if (messages.size() > 1)
updateMessage(1);
if (qtMCUPackage->isValidStatus())
ui->qtMCUsPathLabel->setText(
Tr::tr("Qt for MCUs path %1").arg(qtMCUPackage->path().toUserOutput()));
connect(m_nextButton, &QPushButton::clicked, [=] { updateMessage(1); });
connect(m_previousButton, &QPushButton::clicked, [=] { updateMessage(-1); });
connect(m_fixButton, &QPushButton::clicked, [=] {
// Open the MCU Options widget on the current platform
settingsHandler->setInitialPlatformName(m_messages[m_currentIndex].platform);
Core::ICore::showOptionsDialog(Constants::SETTINGS_ID);
// reset the initial platform name
settingsHandler->setInitialPlatformName("");
});
connect(m_helpButton, &QPushButton::clicked, [] {
QDesktopServices::openUrl(QUrl("https://doc.qt.io/QtForMCUs/qtul-prerequisites.html"));
});
}
void McuKitCreationDialog::updateMessage(const int inc)
{
m_currentIndex += inc;
m_nextButton->setEnabled(m_currentIndex < (m_messages.size() - 1));
m_previousButton->setEnabled(m_currentIndex > 0);
ui->textLabel->setText(QString("<b>%1 %2</b> : %3")
.arg(Tr::tr("Target"),
(m_messages[m_currentIndex].status == McuSupportMessage::Warning
? Tr::tr("Warning")
: Tr::tr("Error")),
m_messages[m_currentIndex].platform));
ui->iconLabel->setPixmap(
QApplication::style()
->standardIcon(m_messages[m_currentIndex].status == McuSupportMessage::Warning
? QStyle::SP_MessageBoxWarning
: QStyle::SP_MessageBoxCritical)
.pixmap(64, 64));
ui->informationLabel->setText(QString("<b>%1</b>: %2<br><br><b>%3</b>: %4")
.arg(Tr::tr("Package"),
m_messages[m_currentIndex].packageName,
Tr::tr("Status"),
m_messages.at(m_currentIndex).message));
ui->messageCountLabel->setText(QString("%1 / %2").arg(QString::number(m_currentIndex + 1),
QString::number(m_messages.size())));
}
McuKitCreationDialog::~McuKitCreationDialog()
{
delete ui;
}
} // namespace McuSupport::Internal

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
#include "mcusupport_global.h"
#include "settingshandler.h"
#include <QDialog>
#include <QPushButton>
namespace Ui {
class McuKitCreationDialog;
}
namespace McuSupport::Internal {
class McuKitCreationDialog : public QDialog
{
Q_OBJECT
public:
explicit McuKitCreationDialog(const MessagesList &messages,
const SettingsHandler::Ptr &settingsHandler,
McuPackagePtr qtMCUPackage,
QWidget *parent = nullptr);
~McuKitCreationDialog();
private slots:
void updateMessage(const int inc);
private:
Ui::McuKitCreationDialog *ui;
int m_currentIndex = -1;
QPushButton *m_previousButton;
QPushButton *m_nextButton;
QPushButton *m_helpButton;
QPushButton *m_fixButton;
const MessagesList &m_messages;
};
} // namespace McuSupport::Internal

View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>McuKitCreationDialog</class>
<widget class="QDialog" name="McuKitCreationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>349</width>
<height>200</height>
</rect>
</property>
<property name="windowTitle">
<string>QtMCUs Kit Creation</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="6" column="0" colspan="2">
<widget class="QLabel" name="qtMCUsPathLabel">
<property name="text">
<string>QtMCUs path: </string>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="7">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="6" column="3">
<widget class="QLabel" name="messageCountLabel">
<property name="text">
<string notr="true">1/3</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="3" rowspan="6">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ignore</set>
</property>
</widget>
</item>
<item row="2" column="1" rowspan="2">
<widget class="QLabel" name="informationLabel">
<property name="text">
<string>Dialog text</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0" rowspan="4">
<widget class="QLabel" name="iconLabel">
<property name="minimumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>1000</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="textLabel">
<property name="text">
<string>TextLabel</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../mcusupport.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>McuKitCreationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>339</x>
<y>23</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>199</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>McuKitCreationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>339</x>
<y>29</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>199</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -3,6 +3,7 @@
#include "mcukitmanager.h"
#include "mculegacyconstants.h"
#include "mcusupport_global.h"
#include "mcusupportoptions.h"
#include "mcukitinformation.h"
@@ -486,31 +487,37 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler)
{
McuPackagePtr qtForMCUsPackage{createQtForMCUsPackage(settingsHandler)};
const auto createKits = [qtForMCUsPackage, settingsHandler]() {
// add a list of package, board, errormessage,
MessagesList autoGenerationMessages;
const auto createKits = [&autoGenerationMessages, qtForMCUsPackage, settingsHandler] {
if (settingsHandler->isAutomaticKitCreationEnabled()) {
qtForMCUsPackage->updateStatus();
if (!qtForMCUsPackage->isValidStatus()) {
switch (qtForMCUsPackage->status()) {
case McuAbstractPackage::Status::ValidPathInvalidPackage: {
printMessage(Tr::tr("Path %1 exists, but does not contain %2.")
const QString message
= Tr::tr("Path %1 exists, but does not contain %2.")
.arg(qtForMCUsPackage->path().toUserOutput(),
qtForMCUsPackage->detectionPath().toUserOutput()),
true);
qtForMCUsPackage->detectionPath().toUserOutput());
autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message});
printMessage(message, true);
break;
}
case McuAbstractPackage::Status::InvalidPath: {
printMessage(Tr::tr(
"Path %1 does not exist. Add the path in Edit > Preferences > "
const QString message
= Tr::tr("Path %1 does not exist. Add the path in Edit > Preferences > "
"Devices > MCU.")
.arg(qtForMCUsPackage->path().toUserOutput()),
true);
.arg(qtForMCUsPackage->path().toUserOutput());
autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message});
printMessage(message, true);
break;
}
case McuAbstractPackage::Status::EmptyPath: {
printMessage(
Tr::tr("Missing %1. Add the path in Edit > Preferences > Devices > MCU.")
.arg(qtForMCUsPackage->detectionPath().toUserOutput()),
true);
const QString message = Tr::tr("Missing %1. Add the path in Edit > Preferences > Devices > MCU.")
.arg(qtForMCUsPackage->detectionPath().toUserOutput());
autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message});
printMessage(message, true);
return;
}
default:
@@ -520,10 +527,10 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler)
}
if (CMakeProjectManager::CMakeToolManager::cmakeTools().isEmpty()) {
printMessage(
Tr::tr("No CMake tool was detected. Add a CMake tool in Edit > Preferences > "
"Kits > CMake."),
true);
const QString message = Tr::tr("No CMake tool was detected. Add a CMake tool in Edit > Preferences > "
"Kits > CMake.");
autoGenerationMessages.push_back({qtForMCUsPackage->label(), "", message});
printMessage(message, true);
return;
}
@@ -543,7 +550,7 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler)
// if no kits for this target, create
if (target->isValid())
newKit(target.get(), qtForMCUsPackage);
target->printPackageProblems();
target->handlePackageProblems(autoGenerationMessages);
}
}
if (needsUpgrade)
@@ -552,6 +559,9 @@ void createAutomaticKits(const SettingsHandler::Ptr &settingsHandler)
};
createKits();
McuSupportOptions::displayKitCreationMessages(autoGenerationMessages,
settingsHandler,
qtForMCUsPackage);
}
// Maintenance
@@ -569,6 +579,7 @@ void upgradeKitsByCreatingNewPackage(const SettingsHandler::Ptr &settingsHandler
McuSdkRepository repo{targetsAndPackages(qtForMCUsPackage, settingsHandler)};
MessagesList messages;
for (const auto &target : std::as_const(repo.mcuTargets)) {
if (!matchingKits(target.get(), qtForMCUsPackage).empty())
// already up-to-date
@@ -583,9 +594,11 @@ void upgradeKitsByCreatingNewPackage(const SettingsHandler::Ptr &settingsHandler
if (target->isValid())
newKit(target.get(), qtForMCUsPackage);
target->printPackageProblems();
target->handlePackageProblems(messages);
}
}
// Open the dialog showing warnings and errors in packages
McuSupportOptions::displayKitCreationMessages(messages, settingsHandler, qtForMCUsPackage);
}
// Maintenance

View File

@@ -58,6 +58,9 @@ QtcPlugin {
"mcuhelpers.h",
"settingshandler.h",
"settingshandler.cpp",
"dialogs/mcukitcreationdialog.ui",
"dialogs/mcukitcreationdialog.h",
"dialogs/mcukitcreationdialog.cpp",
]
QtcTestFiles {

View File

@@ -30,4 +30,13 @@ static const QVersionNumber newVersion{2, 3};
using Targets = QList<McuTargetPtr>;
using Packages = QSet<McuPackagePtr>;
struct McuSupportMessage
{
QString packageName;
QString platform;
QString message;
enum Status { Warning, Error } status = Status::Error;
};
using MessagesList = QList<McuSupportMessage>;
} // namespace McuSupport::Internal

View File

@@ -22,5 +22,7 @@ const char SETTINGS_GROUP[]{"McuSupport"};
const char SETTINGS_KEY_PACKAGE_PREFIX[]{"Package_"};
const char SETTINGS_KEY_PACKAGE_QT_FOR_MCUS_SDK[]{"QtForMCUsSdk"}; // Key known by SDK installer
const char SETTINGS_KEY_AUTOMATIC_KIT_CREATION[]{"AutomaticKitCreation"};
// Used to decide which platform will be displayed first in the MCU Options page
const char SETTINGS_KEY_INITIAL_PLATFORM_KEY[]{"McuSupport.InitialPlatform"};
} // namespace McuSupport::Internal::Constants

View File

@@ -3,9 +3,11 @@
#include "mcusupportoptions.h"
#include "dialogs/mcukitcreationdialog.h"
#include "mcuhelpers.h"
#include "mcukitmanager.h"
#include "mcupackage.h"
#include "mcusupport_global.h"
#include "mcusupportconstants.h"
#include "mcusupportsdk.h"
#include "mcusupporttr.h"
@@ -19,6 +21,7 @@
#include <debugger/debuggerkitinformation.h>
#include <utils/algorithm.h>
#include <utils/filepath.h>
#include <utils/infobar.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
@@ -252,6 +255,30 @@ McuKitManager::UpgradeOption McuSupportOptions::askForKitUpgrades()
return McuKitManager::UpgradeOption::Ignore;
}
void McuSupportOptions::displayKitCreationMessages(const MessagesList &messages,
const SettingsHandler::Ptr &settingsHandler,
McuPackagePtr qtMCUsPackage)
{
if (messages.isEmpty() || !qtMCUsPackage->isValidStatus())
return;
static const char mcuKitCreationErrorInfoId[] = "ErrorWhileCreatingMCUKits";
if (!Core::ICore::infoBar()->canInfoBeAdded(mcuKitCreationErrorInfoId))
return;
Utils::InfoBarEntry info(mcuKitCreationErrorInfoId,
Tr::tr("Errors while creating Qt for MCUs kits"),
Utils::InfoBarEntry::GlobalSuppression::Enabled);
info.addCustomButton(Tr::tr("Details"), [=] {
auto popup = new McuKitCreationDialog(messages, settingsHandler, qtMCUsPackage);
popup->exec();
delete popup;
Core::ICore::infoBar()->removeInfo(mcuKitCreationErrorInfoId);
});
Core::ICore::infoBar()->addInfo(info);
}
void McuSupportOptions::checkUpgradeableKits()
{
if (!qtForMCUsSdkPackage->isValidStatus() || sdkRepository.mcuTargets.isEmpty())

View File

@@ -61,6 +61,9 @@ public:
[[nodiscard]] Utils::FilePath qulDirFromSettings() const;
[[nodiscard]] Utils::FilePath qulDocsDir() const;
static McuKitManager::UpgradeOption askForKitUpgrades();
static void displayKitCreationMessages(const MessagesList &messages,
const SettingsHandler::Ptr &settingsHandler,
McuPackagePtr qtMCUsPackage);
void registerQchFiles() const;
void registerExamples() const;

View File

@@ -350,10 +350,17 @@ void McuSupportOptionsWidget::populateMcuTargetsComboBox()
{
m_options.populatePackagesAndTargets();
m_mcuTargetsComboBox->clear();
int initialPlatformIndex = 0;
int targetsCounter = -1;
m_mcuTargetsComboBox->addItems(
Utils::transform<QStringList>(m_options.sdkRepository.mcuTargets, [](const McuTargetPtr &t) {
Utils::transform<QStringList>(m_options.sdkRepository.mcuTargets, [&](const McuTargetPtr &t) {
if (t->platform().name == m_settingsHandler->initialPlatformName())
initialPlatformIndex = m_options.sdkRepository.mcuTargets.indexOf(t);
targetsCounter++;
return McuKitManager::generateKitNameFromTarget(t.get());
}));
if (targetsCounter != -1)
m_mcuTargetsComboBox->setCurrentIndex(initialPlatformIndex);
updateStatus();
}

View File

@@ -1,11 +1,12 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "mcutarget.h"
#include "mcukitmanager.h"
#include "mcupackage.h"
#include "mcusupport_global.h"
#include "mcusupportplugin.h"
#include "mcusupporttr.h"
#include "mcutarget.h"
#include <utils/algorithm.h>
@@ -82,22 +83,33 @@ QString McuTarget::desktopCompilerId() const
return QLatin1String("invalid");
}
void McuTarget::printPackageProblems() const
void McuTarget::handlePackageProblems(MessagesList &messages) const
{
for (auto package : packages()) {
package->updateStatus();
if (!package->isValidStatus())
if (!package->isValidStatus()) {
printMessage(Tr::tr("Error creating kit for target %1, package %2: %3")
.arg(McuKitManager::generateKitNameFromTarget(this),
package->label(),
package->statusText()),
true);
if (package->status() == McuAbstractPackage::Status::ValidPackageMismatchedVersion)
messages.push_back({package->label(),
this->platform().name,
package->statusText(),
McuSupportMessage::Error});
}
if (package->status() == McuAbstractPackage::Status::ValidPackageMismatchedVersion) {
printMessage(Tr::tr("Warning creating kit for target %1, package %2: %3")
.arg(McuKitManager::generateKitNameFromTarget(this),
package->label(),
package->statusText()),
false);
messages.push_back({package->label(),
this->platform().name,
package->statusText(),
McuSupportMessage::Warning});
}
}
}

View File

@@ -54,7 +54,7 @@ public:
int colorDepth() const;
bool isValid() const;
QString desktopCompilerId() const;
void printPackageProblems() const;
void handlePackageProblems(MessagesList &messages) const;
private:
const QVersionNumber m_qulVersion;

View File

@@ -68,4 +68,17 @@ void SettingsHandler::setAutomaticKitCreation(bool isEnabled)
settings->setValue(automaticKitCreationSettingsKey, isEnabled);
}
void SettingsHandler::setInitialPlatformName(const QString &platform)
{
QSettings *settings = Core::ICore::settings(QSettings::UserScope);
settings->setValue(Constants::SETTINGS_KEY_INITIAL_PLATFORM_KEY, platform);
}
QString SettingsHandler::initialPlatformName() const
{
QSettings *settings = Core::ICore::settings(QSettings::UserScope);
const QString name
= settings->value(Constants::SETTINGS_KEY_INITIAL_PLATFORM_KEY, "").toString();
return name;
}
} // namespace McuSupport::Internal

View File

@@ -27,5 +27,8 @@ public:
virtual bool isAutomaticKitCreationEnabled() const;
void setAutomaticKitCreation(bool isEnabled);
void setInitialPlatformName(const QString &platform);
QString initialPlatformName() const;
}; //class SettingsHandler
} // namespace McuSupport::Internal