forked from qt-creator/qt-creator
TargetSetupPage: Improve reporting on invalid kits
Give the reason for a kit being disabled in the tooltip. E.g. for a CMake project you will now get "Kit is invalid: No CMake tool set." instead of a generic error message about the kit being invalid. Change-Id: Ic776dc24149d65ebf27163b605ec2e52a3a504a7 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -58,12 +58,19 @@ void JsonKitsPage::initializePage()
|
||||
const Id platform = Id::fromString(wiz->stringValue(QLatin1String("Platform")));
|
||||
const QSet<Id> preferred
|
||||
= evaluate(m_preferredFeatures, wiz->value(QLatin1String("PreferredFeatures")), wiz);
|
||||
const QSet<Id> required
|
||||
= evaluate(m_requiredFeatures, wiz->value(QLatin1String("RequiredFeatures")), wiz);
|
||||
const QSet<Id> required = evaluate(m_requiredFeatures,
|
||||
wiz->value(QLatin1String("RequiredFeatures")),
|
||||
wiz);
|
||||
|
||||
setRequiredKitPredicate([required](const Kit *k) { return k->hasFeatures(required); });
|
||||
setPreferredKitPredicate([platform, preferred](const Kit *k) {
|
||||
return k->supportedPlatforms().contains(platform) && k->hasFeatures(preferred);
|
||||
setTasksGenerator([required, preferred, platform](const Kit *k) -> Tasks {
|
||||
if (!k->hasFeatures(required))
|
||||
return {CompileTask(Task::Error, tr("At least one required feature is not present."))};
|
||||
if (!k->supportedPlatforms().contains(platform))
|
||||
return {CompileTask(Task::Unknown, tr("Platform is not supported."))};
|
||||
if (!k->hasFeatures(preferred))
|
||||
return {
|
||||
CompileTask(Task::Unknown, tr("At least one preferred feature is not present."))};
|
||||
return {};
|
||||
});
|
||||
setProjectPath(wiz->expander()->expand(Utils::FilePath::fromString(unexpandedProjectPath())));
|
||||
|
||||
|
@@ -567,13 +567,16 @@ IOutputParser *Kit::createOutputParser() const
|
||||
return first;
|
||||
}
|
||||
|
||||
QString Kit::toHtml(const Tasks &additional) const
|
||||
QString Kit::toHtml(const Tasks &additional, const QString &extraText) const
|
||||
{
|
||||
QString result;
|
||||
QTextStream str(&result);
|
||||
str << "<html><body>";
|
||||
str << "<h3>" << displayName() << "</h3>";
|
||||
|
||||
if (!extraText.isEmpty())
|
||||
str << "<p>" << extraText << "</p>";
|
||||
|
||||
if (!isValid() || hasWarning() || !additional.isEmpty())
|
||||
str << "<p>" << ProjectExplorer::toHtml(additional + validate()) << "</p>";
|
||||
|
||||
|
@@ -118,7 +118,7 @@ public:
|
||||
void addToEnvironment(Utils::Environment &env) const;
|
||||
IOutputParser *createOutputParser() const;
|
||||
|
||||
QString toHtml(const Tasks &additional = Tasks()) const;
|
||||
QString toHtml(const Tasks &additional = Tasks(), const QString &extraText = QString()) const;
|
||||
Kit *clone(bool keepName = false) const;
|
||||
void copyFrom(const Kit *k);
|
||||
|
||||
@@ -173,6 +173,8 @@ private:
|
||||
Kit *m_kit;
|
||||
};
|
||||
|
||||
using TasksGenerator = std::function<Tasks(const Kit *)>;
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
Q_DECLARE_METATYPE(ProjectExplorer::Kit *)
|
||||
|
@@ -201,9 +201,6 @@ public:
|
||||
|
||||
QString m_displayName;
|
||||
|
||||
Kit::Predicate m_requiredKitPredicate;
|
||||
Kit::Predicate m_preferredKitPredicate;
|
||||
|
||||
Utils::MacroExpander m_macroExpander;
|
||||
Utils::FilePath m_rootProjectDirectory;
|
||||
mutable QVector<const Node *> m_sortedNodeList;
|
||||
@@ -229,10 +226,6 @@ Project::Project(const QString &mimeType,
|
||||
|
||||
// Only set up containernode after d is set so that it will find the project directory!
|
||||
d->m_containerNode = std::make_unique<ContainerNode>(this);
|
||||
|
||||
setRequiredKitPredicate([this](const Kit *k) {
|
||||
return !containsType(projectIssues(k), Task::TaskType::Error);
|
||||
});
|
||||
}
|
||||
|
||||
Project::~Project()
|
||||
@@ -974,31 +967,11 @@ ProjectImporter *Project::projectImporter() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Kit::Predicate Project::requiredKitPredicate() const
|
||||
{
|
||||
return d->m_requiredKitPredicate;
|
||||
}
|
||||
|
||||
void Project::setRequiredKitPredicate(const Kit::Predicate &predicate)
|
||||
{
|
||||
d->m_requiredKitPredicate = predicate;
|
||||
}
|
||||
|
||||
void Project::setCanBuildProducts()
|
||||
{
|
||||
d->m_canBuildProducts = true;
|
||||
}
|
||||
|
||||
Kit::Predicate Project::preferredKitPredicate() const
|
||||
{
|
||||
return d->m_preferredKitPredicate;
|
||||
}
|
||||
|
||||
void Project::setPreferredKitPredicate(const Kit::Predicate &predicate)
|
||||
{
|
||||
d->m_preferredKitPredicate = predicate;
|
||||
}
|
||||
|
||||
void Project::setExtraData(const QString &key, const QVariant &data)
|
||||
{
|
||||
d->m_extraData.insert(key, data);
|
||||
|
@@ -144,9 +144,6 @@ public:
|
||||
|
||||
virtual ProjectImporter *projectImporter() const;
|
||||
|
||||
Kit::Predicate requiredKitPredicate() const;
|
||||
Kit::Predicate preferredKitPredicate() const;
|
||||
|
||||
// The build system is able to report all executables that can be built, independent
|
||||
// of configuration.
|
||||
bool knowsAllBuildExecutables() const;
|
||||
@@ -208,12 +205,6 @@ protected:
|
||||
void createTargetFromMap(const QVariantMap &map, int index);
|
||||
virtual bool setupTarget(Target *t);
|
||||
|
||||
// Used to pre-check kits in the TargetSetupPage. RequiredKitPredicate
|
||||
// is used to select kits available in the TargetSetupPage
|
||||
void setPreferredKitPredicate(const Kit::Predicate &predicate);
|
||||
// The predicate used to select kits available in TargetSetupPage.
|
||||
void setRequiredKitPredicate(const Kit::Predicate &predicate);
|
||||
|
||||
void setCanBuildProducts();
|
||||
|
||||
void setId(Core::Id id);
|
||||
|
@@ -159,8 +159,8 @@ void TargetSetupPageWrapper::addTargetSetupPage()
|
||||
m_targetSetupPage = new TargetSetupPage(this);
|
||||
m_targetSetupPage->setUseScrollArea(false);
|
||||
m_targetSetupPage->setProjectPath(m_project->projectFilePath());
|
||||
m_targetSetupPage->setRequiredKitPredicate(m_project->requiredKitPredicate());
|
||||
m_targetSetupPage->setPreferredKitPredicate(m_project->preferredKitPredicate());
|
||||
m_targetSetupPage->setTasksGenerator(
|
||||
[this](const Kit *k) { return m_project->projectIssues(k); });
|
||||
m_targetSetupPage->setProjectImporter(m_project->projectImporter());
|
||||
m_targetSetupPage->initializePage();
|
||||
m_targetSetupPage->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
@@ -322,14 +322,14 @@ public:
|
||||
case Qt::ToolTipRole: {
|
||||
Kit *k = KitManager::kit(m_kitId);
|
||||
QTC_ASSERT(k, return QVariant());
|
||||
QString toolTip;
|
||||
if (m_kitErrorsForProject)
|
||||
toolTip = "<h3>" + tr("Kit is unsuited for project") + "</h3>";
|
||||
else if (!isEnabled())
|
||||
toolTip = "<h3>" + tr("Click to activate:") + "</h3>" + k->toHtml();
|
||||
if (!m_kitIssues.isEmpty())
|
||||
toolTip += toHtml(m_kitIssues);
|
||||
return toolTip;
|
||||
const QString extraText = [this]() {
|
||||
if (m_kitErrorsForProject)
|
||||
return QString("<h3>" + tr("Kit is unsuited for project") + "</h3>");
|
||||
if (!isEnabled())
|
||||
return QString("<h3>" + tr("Click to activate") + "</h3>");
|
||||
return QString();
|
||||
}();
|
||||
return k->toHtml(m_kitIssues, extraText);
|
||||
}
|
||||
|
||||
case PanelWidgetRole:
|
||||
|
@@ -26,14 +26,15 @@
|
||||
#include "targetsetuppage.h"
|
||||
#include "buildconfiguration.h"
|
||||
#include "buildinfo.h"
|
||||
#include "importwidget.h"
|
||||
#include "kit.h"
|
||||
#include "kitmanager.h"
|
||||
#include "importwidget.h"
|
||||
#include "project.h"
|
||||
#include "projectexplorerconstants.h"
|
||||
#include "session.h"
|
||||
#include "target.h"
|
||||
#include "targetsetupwidget.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
@@ -159,13 +160,27 @@ public:
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
static TasksGenerator defaultTasksGenerator(const TasksGenerator &childGenerator)
|
||||
{
|
||||
return [childGenerator](const Kit *k) -> Tasks {
|
||||
if (!k->isValid())
|
||||
return {
|
||||
CompileTask(Task::Error,
|
||||
QCoreApplication::translate("ProjectExplorer", "Kit is not valid."))};
|
||||
if (childGenerator)
|
||||
return childGenerator(k);
|
||||
return {};
|
||||
};
|
||||
}
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
TargetSetupPage::TargetSetupPage(QWidget *parent) :
|
||||
WizardPage(parent),
|
||||
m_ui(new TargetSetupPageUi),
|
||||
m_importWidget(new ImportWidget(this)),
|
||||
m_spacer(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding))
|
||||
TargetSetupPage::TargetSetupPage(QWidget *parent)
|
||||
: WizardPage(parent)
|
||||
, m_tasksGenerator(defaultTasksGenerator({}))
|
||||
, m_ui(new TargetSetupPageUi)
|
||||
, m_importWidget(new ImportWidget(this))
|
||||
, m_spacer(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding))
|
||||
{
|
||||
m_importWidget->setVisible(false);
|
||||
|
||||
@@ -217,9 +232,9 @@ void TargetSetupPage::initializePage()
|
||||
}
|
||||
}
|
||||
|
||||
void TargetSetupPage::setRequiredKitPredicate(const Kit::Predicate &predicate)
|
||||
void TargetSetupPage::setTasksGenerator(const TasksGenerator &tasksGenerator)
|
||||
{
|
||||
m_requiredPredicate = predicate;
|
||||
m_tasksGenerator = defaultTasksGenerator(tasksGenerator);
|
||||
}
|
||||
|
||||
QList<Core::Id> TargetSetupPage::selectedKits() const
|
||||
@@ -232,11 +247,6 @@ QList<Core::Id> TargetSetupPage::selectedKits() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void TargetSetupPage::setPreferredKitPredicate(const Kit::Predicate &predicate)
|
||||
{
|
||||
m_preferredPredicate = predicate;
|
||||
}
|
||||
|
||||
TargetSetupPage::~TargetSetupPage()
|
||||
{
|
||||
disconnect();
|
||||
@@ -396,8 +406,10 @@ void TargetSetupPage::selectAtLeastOneEnabledKit()
|
||||
TargetSetupWidget *toCheckWidget = nullptr;
|
||||
|
||||
const Kit *defaultKit = KitManager::defaultKit();
|
||||
|
||||
auto isPreferred = [this](const TargetSetupWidget *w) {
|
||||
return w->isEnabled() && (!m_preferredPredicate || m_preferredPredicate(w->kit()));
|
||||
const Tasks tasks = m_tasksGenerator(w->kit());
|
||||
return w->isEnabled() && tasks.isEmpty();
|
||||
};
|
||||
|
||||
// Use default kit if that is preferred:
|
||||
@@ -620,12 +632,12 @@ void TargetSetupPage::removeAdditionalWidgets(QLayout *layout)
|
||||
void TargetSetupPage::updateWidget(TargetSetupWidget *widget)
|
||||
{
|
||||
QTC_ASSERT(widget, return );
|
||||
widget->update(m_requiredPredicate);
|
||||
widget->update(m_tasksGenerator);
|
||||
}
|
||||
|
||||
bool TargetSetupPage::isUsable(const Kit *kit) const
|
||||
{
|
||||
return kit->isValid() && (!m_requiredPredicate || m_requiredPredicate(kit));
|
||||
return !containsType(m_tasksGenerator(kit), Task::Error);
|
||||
}
|
||||
|
||||
bool TargetSetupPage::setupProject(Project *project)
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "kitinformation.h"
|
||||
#include "kitmanager.h"
|
||||
#include "projectimporter.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <utils/wizardpage.h>
|
||||
|
||||
@@ -66,8 +67,7 @@ public:
|
||||
void initializePage() override;
|
||||
|
||||
// Call these before initializePage!
|
||||
void setRequiredKitPredicate(const Kit::Predicate &predicate);
|
||||
void setPreferredKitPredicate(const Kit::Predicate &predicate);
|
||||
void setTasksGenerator(const TasksGenerator &tasksGenerator);
|
||||
void setProjectPath(const Utils::FilePath &dir);
|
||||
void setProjectImporter(ProjectImporter *importer);
|
||||
bool importLineEditHasFocus() const;
|
||||
@@ -125,8 +125,7 @@ private:
|
||||
Internal::TargetSetupWidget *widget(const Core::Id kitId,
|
||||
Internal::TargetSetupWidget *fallback = nullptr) const;
|
||||
|
||||
Kit::Predicate m_requiredPredicate;
|
||||
Kit::Predicate m_preferredPredicate;
|
||||
TasksGenerator m_tasksGenerator;
|
||||
QPointer<ProjectImporter> m_importer;
|
||||
QLayout *m_baseLayout = nullptr;
|
||||
Utils::FilePath m_projectPath;
|
||||
|
@@ -224,24 +224,25 @@ void TargetSetupWidget::expandWidget()
|
||||
m_detailsWidget->setState(Utils::DetailsWidget::Expanded);
|
||||
}
|
||||
|
||||
void TargetSetupWidget::update(const Kit::Predicate &predicate)
|
||||
void TargetSetupWidget::update(const TasksGenerator &generator)
|
||||
{
|
||||
m_detailsWidget->setSummaryText(kit()->displayName());
|
||||
const Tasks tasks = generator(kit());
|
||||
|
||||
// Kits that we deem invalid get a warning icon, but users can still select them,
|
||||
// e.g. in case we misdetected an ABI mismatch.
|
||||
// Kits that don't fulfill the project predicate are not selectable, because we cannot
|
||||
m_detailsWidget->setSummaryText(kit()->displayName());
|
||||
m_detailsWidget->setIcon(kit()->isValid() ? kit()->icon() : Icons::CRITICAL.icon());
|
||||
|
||||
const Task errorTask = Utils::findOrDefault(tasks, Utils::equal(&Task::type, Task::Error));
|
||||
|
||||
// Kits that where the taskGenarator reports an error are not selectable, because we cannot
|
||||
// guarantee that we can handle the project sensibly (e.g. qmake project without Qt).
|
||||
if (predicate && !predicate(kit())) {
|
||||
if (!errorTask.isNull()) {
|
||||
toggleEnabled(false);
|
||||
m_detailsWidget->setToolTip(kit()->toHtml(tasks, ""));
|
||||
m_infoStore.clear();
|
||||
m_detailsWidget->setToolTip(tr("You cannot use this kit, because it does not fulfill "
|
||||
"the project's prerequisites."));
|
||||
return;
|
||||
}
|
||||
|
||||
toggleEnabled(true);
|
||||
m_detailsWidget->setIcon(kit()->isValid() ? kit()->icon() : Icons::CRITICAL.icon());
|
||||
m_detailsWidget->setToolTip(m_kit->toHtml());
|
||||
updateDefaultBuildDirectories();
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ public:
|
||||
const QList<BuildInfo> selectedBuildInfoList() const;
|
||||
void setProjectPath(const Utils::FilePath &projectPath);
|
||||
void expandWidget();
|
||||
void update(const Kit::Predicate &predicate);
|
||||
void update(const TasksGenerator &generator);
|
||||
|
||||
signals:
|
||||
void selectedToggled() const;
|
||||
|
@@ -117,16 +117,15 @@ private:
|
||||
/*!
|
||||
\class QmakeProject
|
||||
|
||||
QmakeProject manages information about an individual Qt 4 (.pro) project file.
|
||||
QmakeProject manages information about an individual qmake project file (.pro).
|
||||
*/
|
||||
|
||||
static bool matchesKit(const Project *p, const Kit *kit)
|
||||
static QtSupport::BaseQtVersion *projectIsPartOfQt(const Project *p)
|
||||
{
|
||||
FilePath filePath = p->projectFilePath();
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitAspect::qtVersion(kit);
|
||||
|
||||
return QtSupport::QtVersionManager::version([&filePath, version](const QtSupport::BaseQtVersion *v) {
|
||||
return v->isValid() && v->isSubProject(filePath) && v == version;
|
||||
return QtSupport::QtVersionManager::version([&filePath](const QtSupport::BaseQtVersion *v) {
|
||||
return v->isValid() && v->isSubProject(filePath);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -138,8 +137,6 @@ QmakeProject::QmakeProject(const FilePath &fileName) :
|
||||
setDisplayName(fileName.toFileInfo().completeBaseName());
|
||||
setCanBuildProducts();
|
||||
setHasMakeInstallEquivalent(true);
|
||||
|
||||
setPreferredKitPredicate([this](const Kit *kit) -> bool { return matchesKit(this, kit); });
|
||||
}
|
||||
|
||||
QmakeProject::~QmakeProject()
|
||||
@@ -603,12 +600,21 @@ void QmakeBuildSystem::buildFinished(bool success)
|
||||
Tasks QmakeProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
Tasks result = Project::projectIssues(k);
|
||||
if (!QtSupport::QtKitAspect::qtVersion(k))
|
||||
const QtSupport::BaseQtVersion *const qtFromKit = QtSupport::QtKitAspect::qtVersion(k);
|
||||
if (!qtFromKit)
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No Qt version set in kit.")));
|
||||
else if (!QtSupport::QtKitAspect::qtVersion(k)->isValid())
|
||||
else if (!qtFromKit->isValid())
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("Qt version is invalid.")));
|
||||
if (!ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No C++ compiler set in kit.")));
|
||||
|
||||
const QtSupport::BaseQtVersion *const qtThatContainsProject = projectIsPartOfQt(this);
|
||||
if (qtThatContainsProject && qtThatContainsProject != qtFromKit) {
|
||||
result.append(CompileTask(Task::Warning,
|
||||
tr("Project is part of Qt sources that do not match "
|
||||
"the Qt defined in the Kit")));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/targetsetuppage.h>
|
||||
#include <projectexplorer/task.h>
|
||||
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
#include <qtsupport/qtsupportconstants.h>
|
||||
@@ -178,14 +179,23 @@ BaseQmakeProjectWizardDialog::~BaseQmakeProjectWizardDialog()
|
||||
int BaseQmakeProjectWizardDialog::addTargetSetupPage(int id)
|
||||
{
|
||||
m_targetSetupPage = new ProjectExplorer::TargetSetupPage;
|
||||
const Core::Id platform = selectedPlatform();
|
||||
QSet<Core::Id> features = {QtSupport::Constants::FEATURE_DESKTOP};
|
||||
if (!platform.isValid())
|
||||
m_targetSetupPage->setPreferredKitPredicate(QtKitAspect::qtVersionPredicate(features));
|
||||
else
|
||||
m_targetSetupPage->setPreferredKitPredicate(QtKitAspect::platformPredicate(platform));
|
||||
|
||||
m_targetSetupPage->setRequiredKitPredicate(QtKitAspect::qtVersionPredicate(requiredFeatures()));
|
||||
m_targetSetupPage->setTasksGenerator([this](const Kit *k) -> Tasks {
|
||||
if (!QtKitAspect::qtVersionPredicate(requiredFeatures())(k))
|
||||
return {
|
||||
ProjectExplorer::CompileTask(Task::Error, tr("Required Qt features not present."))};
|
||||
|
||||
const Core::Id platform = selectedPlatform();
|
||||
if (platform.isValid() && !QtKitAspect::platformPredicate(platform)(k))
|
||||
return {ProjectExplorer::CompileTask(
|
||||
ProjectExplorer::Task::Warning,
|
||||
tr("Qt version does not target the expected platform."))};
|
||||
QSet<Core::Id> features = {QtSupport::Constants::FEATURE_DESKTOP};
|
||||
if (!QtKitAspect::qtVersionPredicate(features)(k))
|
||||
return {ProjectExplorer::CompileTask(ProjectExplorer::Task::Unknown,
|
||||
tr("Qt version does not provide all features."))};
|
||||
return {};
|
||||
});
|
||||
|
||||
resize(900, 450);
|
||||
if (id >= 0)
|
||||
|
Reference in New Issue
Block a user