forked from qt-creator/qt-creator
ProjectExplorer: Report project-specific kit errors/warnings
Report project-specific warnings about the kit used in Project Mode. E.g. a python project should not complain about missing toolchains, while a qmake project should. Change-Id: I5ce6742683cdeffc7ff3f1a3e8f0b89aee9aa0b4 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -363,14 +363,16 @@ bool CMakeProject::knowsAllBuildExecutables() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMakeProject::supportsKit(const Kit *k, QString *errorMessage) const
|
||||
QList<Task> CMakeProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
if (!CMakeKitInformation::cmakeTool(k)) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("No cmake tool set.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
QList<Task> result = Project::projectIssues(k);
|
||||
|
||||
if (!CMakeKitInformation::cmakeTool(k))
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No cmake tool set.")));
|
||||
if (ToolChainKitInformation::toolChains(k).isEmpty())
|
||||
result.append(createProjectTask(Task::TaskType::Warning, tr("No compilers set in kit.")));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CMakeProject::runCMake()
|
||||
|
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
bool knowsAllBuildExecutables() const final;
|
||||
|
||||
bool supportsKit(const ProjectExplorer::Kit *k, QString *errorMessage = nullptr) const final;
|
||||
QList<ProjectExplorer::Task> projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
|
||||
void runCMake();
|
||||
void runCMakeAndScanProjectTree();
|
||||
|
@@ -154,20 +154,16 @@ void NimProject::updateProject()
|
||||
emitParsingFinished(true);
|
||||
}
|
||||
|
||||
bool NimProject::supportsKit(const Kit *k, QString *errorMessage) const
|
||||
QList<Task> NimProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
QList<Task> result = Project::projectIssues(k);
|
||||
auto tc = dynamic_cast<NimToolChain*>(ToolChainKitInformation::toolChain(k, Constants::C_NIMLANGUAGE_ID));
|
||||
if (!tc) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("No Nim compiler set.");
|
||||
return false;
|
||||
}
|
||||
if (!tc->compilerCommand().exists()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Nim compiler does not exist.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (!tc)
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No Nim compiler set.")));
|
||||
if (!tc->compilerCommand().exists())
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("Nim compiler does not exist.")));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FileNameList NimProject::nimFiles() const
|
||||
|
@@ -41,7 +41,7 @@ class NimProject : public ProjectExplorer::Project
|
||||
public:
|
||||
explicit NimProject(const Utils::FileName &fileName);
|
||||
|
||||
bool supportsKit(const ProjectExplorer::Kit *k, QString *errorMessage) const final;
|
||||
QList<ProjectExplorer::Task> projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
Utils::FileNameList nimFiles() const;
|
||||
QVariantMap toMap() const final;
|
||||
|
||||
|
@@ -407,7 +407,7 @@ bool IBuildConfigurationFactory::canHandle(const Target *target) const
|
||||
if (m_supportedProjectType.isValid() && m_supportedProjectType != target->project()->id())
|
||||
return false;
|
||||
|
||||
if (!target->project()->supportsKit(target->kit()))
|
||||
if (containsType(target->project()->projectIssues(target->kit()), Task::TaskType::Error))
|
||||
return false;
|
||||
|
||||
if (!supportsTargetDeviceType(DeviceTypeKitInformation::deviceTypeId(target->kit())))
|
||||
|
@@ -184,7 +184,7 @@ bool DeployConfigurationFactory::canHandle(Target *target) const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target->project()->supportsKit(target->kit()))
|
||||
if (containsType(target->project()->projectIssues(target->kit()), Task::TaskType::Error))
|
||||
return false;
|
||||
|
||||
if (!m_supportedTargetDeviceTypes.isEmpty()) {
|
||||
|
@@ -112,7 +112,7 @@ public:
|
||||
int m_nestedBlockingLevel = 0;
|
||||
bool m_autodetected = false;
|
||||
bool m_sdkProvided = false;
|
||||
bool m_isValid = true;
|
||||
bool m_hasError = false;
|
||||
bool m_hasWarning = false;
|
||||
bool m_hasValidityInfo = false;
|
||||
bool m_mustNotify = false;
|
||||
@@ -209,7 +209,7 @@ Kit *Kit::clone(bool keepName) const
|
||||
k->d->m_autodetected = false;
|
||||
k->d->m_data = d->m_data;
|
||||
// Do not clone m_fileSystemFriendlyName, needs to be unique
|
||||
k->d->m_isValid = d->m_isValid;
|
||||
k->d->m_hasError = d->m_hasError;
|
||||
k->d->m_cachedIcon = d->m_cachedIcon;
|
||||
k->d->m_iconPath = d->m_iconPath;
|
||||
k->d->m_sticky = d->m_sticky;
|
||||
@@ -240,7 +240,7 @@ bool Kit::isValid() const
|
||||
if (!d->m_hasValidityInfo)
|
||||
validate();
|
||||
|
||||
return d->m_isValid;
|
||||
return !d->m_hasError;
|
||||
}
|
||||
|
||||
bool Kit::hasWarning() const
|
||||
@@ -255,18 +255,13 @@ QList<Task> Kit::validate() const
|
||||
{
|
||||
QList<Task> result;
|
||||
QList<KitInformation *> infoList = KitManager::kitInformation();
|
||||
d->m_isValid = true;
|
||||
d->m_hasWarning = false;
|
||||
foreach (KitInformation *i, infoList) {
|
||||
for (KitInformation *i : infoList) {
|
||||
QList<Task> tmp = i->validate(this);
|
||||
foreach (const Task &t, tmp) {
|
||||
if (t.type == Task::Error)
|
||||
d->m_isValid = false;
|
||||
if (t.type == Task::Warning)
|
||||
d->m_hasWarning = true;
|
||||
}
|
||||
result.append(tmp);
|
||||
}
|
||||
d->m_hasError = containsType(result, Task::TaskType::Error);
|
||||
d->m_hasWarning = containsType(result, Task::TaskType::Warning);
|
||||
|
||||
Utils::sort(result);
|
||||
d->m_hasValidityInfo = true;
|
||||
return result;
|
||||
|
@@ -198,7 +198,9 @@ Project::Project(const QString &mimeType, const Utils::FileName &fileName,
|
||||
// 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 supportsKit(k); });
|
||||
setRequiredKitPredicate([this](const Kit *k) {
|
||||
return !containsType(projectIssues(k), Task::TaskType::Error);
|
||||
});
|
||||
}
|
||||
|
||||
Project::~Project()
|
||||
@@ -317,11 +319,12 @@ Target *Project::target(Kit *k) const
|
||||
return Utils::findOrDefault(d->m_targets, Utils::equal(&Target::kit, k));
|
||||
}
|
||||
|
||||
bool Project::supportsKit(const Kit *k, QString *errorMessage) const
|
||||
QList<Task> Project::projectIssues(const Kit *k) const
|
||||
{
|
||||
Q_UNUSED(k);
|
||||
Q_UNUSED(errorMessage);
|
||||
return true;
|
||||
QList<Task> result;
|
||||
if (!k->isValid())
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("Kit is not valid.")));
|
||||
return {};
|
||||
}
|
||||
|
||||
Target *Project::createTarget(Kit *k)
|
||||
@@ -762,6 +765,11 @@ void Project::projectLoaded()
|
||||
{
|
||||
}
|
||||
|
||||
Task Project::createProjectTask(Task::TaskType type, const QString &description)
|
||||
{
|
||||
return Task(type, description, Utils::FileName(), -1, Core::Id());
|
||||
}
|
||||
|
||||
Core::Context Project::projectContext() const
|
||||
{
|
||||
return Core::Context(d->m_id);
|
||||
|
@@ -122,7 +122,7 @@ public:
|
||||
Target *activeTarget() const;
|
||||
Target *target(Core::Id id) const;
|
||||
Target *target(Kit *k) const;
|
||||
virtual bool supportsKit(const Kit *k, QString *errorMessage = nullptr) const;
|
||||
virtual QList<Task> projectIssues(const Kit *k) const;
|
||||
|
||||
Target *createTarget(Kit *k);
|
||||
static bool copySteps(Target *sourceTarget, Target *newTarget);
|
||||
@@ -238,6 +238,9 @@ protected:
|
||||
void setProjectLanguage(Core::Id id, bool enabled);
|
||||
virtual void projectLoaded(); // Called when the project is fully loaded.
|
||||
|
||||
static ProjectExplorer::Task createProjectTask(ProjectExplorer::Task::TaskType type,
|
||||
const QString &description);
|
||||
|
||||
private:
|
||||
// The predicate used to select kits available in TargetSetupPage.
|
||||
void setRequiredKitPredicate(const Kit::Predicate &predicate);
|
||||
|
@@ -540,7 +540,7 @@ bool RunConfigurationFactory::canHandle(Target *target) const
|
||||
const Project *project = target->project();
|
||||
Kit *kit = target->kit();
|
||||
|
||||
if (!project->supportsKit(kit))
|
||||
if (containsType(target->project()->projectIssues(kit), Task::TaskType::Error))
|
||||
return false;
|
||||
|
||||
if (!m_supportedProjectTypes.isEmpty())
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include "session.h"
|
||||
#include "target.h"
|
||||
#include "targetsetuppage.h"
|
||||
#include "task.h"
|
||||
|
||||
#include <app/app_version.h>
|
||||
|
||||
@@ -282,9 +283,12 @@ class TargetItem : public TypedTreeItem<TreeItem, TargetGroupItem>
|
||||
public:
|
||||
enum { DefaultPage = 0 }; // Build page.
|
||||
|
||||
TargetItem(Project *project, Id kitId)
|
||||
: m_project(project), m_kitId(kitId)
|
||||
TargetItem(Project *project, Id kitId, const QList<Task> &issues)
|
||||
: m_project(project), m_kitId(kitId), m_kitIssues(issues)
|
||||
{
|
||||
m_kitWarningForProject = containsType(m_kitIssues, Task::TaskType::Warning);
|
||||
m_kitErrorsForProject = containsType(m_kitIssues, Task::TaskType::Error);
|
||||
|
||||
updateSubItems();
|
||||
}
|
||||
|
||||
@@ -298,7 +302,8 @@ public:
|
||||
Qt::ItemFlags flags(int column) const override
|
||||
{
|
||||
Q_UNUSED(column)
|
||||
return Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
return m_kitErrorsForProject ? Qt::ItemFlags(0)
|
||||
: Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
|
||||
}
|
||||
|
||||
QVariant data(int column, int role) const override
|
||||
@@ -313,11 +318,11 @@ public:
|
||||
case Qt::DecorationRole: {
|
||||
const Kit *k = KitManager::kit(m_kitId);
|
||||
QTC_ASSERT(k, return QVariant());
|
||||
if (m_kitErrorsForProject)
|
||||
return kitIconWithOverlay(*k, IconOverlay::Error);
|
||||
if (!isEnabled())
|
||||
return kitIconWithOverlay(*k, IconOverlay::Add);
|
||||
if (!k->isValid())
|
||||
return kitIconWithOverlay(*k, IconOverlay::Error);
|
||||
if (k->hasWarning())
|
||||
if (m_kitWarningForProject)
|
||||
return kitIconWithOverlay(*k, IconOverlay::Warning);
|
||||
return k->icon();
|
||||
}
|
||||
@@ -341,9 +346,12 @@ public:
|
||||
Kit *k = KitManager::kit(m_kitId);
|
||||
QTC_ASSERT(k, return QVariant());
|
||||
QString toolTip;
|
||||
if (!isEnabled())
|
||||
if (m_kitErrorsForProject)
|
||||
toolTip = "<h3>" + tr("Kit is unsuited for Project") + "</h3>";
|
||||
else if (!isEnabled())
|
||||
toolTip = "<h3>" + tr("Click to activate:") + "</h3>";
|
||||
toolTip += k->toHtml();
|
||||
if (!m_kitIssues.isEmpty())
|
||||
toolTip += toHtml(m_kitIssues);
|
||||
return toolTip;
|
||||
}
|
||||
|
||||
@@ -466,12 +474,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool isEnabled() const { return target() != 0; }
|
||||
bool isEnabled() const { return target() != nullptr; }
|
||||
|
||||
public:
|
||||
QPointer<Project> m_project; // Not owned.
|
||||
Id m_kitId;
|
||||
int m_currentChild = DefaultPage; // Use run page by default.
|
||||
int m_currentChild = DefaultPage;
|
||||
bool m_kitErrorsForProject = false;
|
||||
bool m_kitWarningForProject = false;
|
||||
QList<Task> m_kitIssues;
|
||||
|
||||
private:
|
||||
enum class IconOverlay {
|
||||
@@ -526,10 +537,9 @@ public:
|
||||
|
||||
BuildOrRunItem(Project *project, Id kitId, SubIndex subIndex)
|
||||
: m_project(project), m_kitId(kitId), m_subIndex(subIndex)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
~BuildOrRunItem()
|
||||
~BuildOrRunItem() override
|
||||
{
|
||||
delete m_panel;
|
||||
}
|
||||
@@ -769,7 +779,7 @@ TargetItem *TargetGroupItem::targetItem(Target *target) const
|
||||
Id needle = target->id(); // Unconfigured project have no active target.
|
||||
return findFirstLevelChild([needle](TargetItem *item) { return item->m_kitId == needle; });
|
||||
}
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TargetGroupItemPrivate::handleRemovedKit(Kit *kit)
|
||||
@@ -786,8 +796,7 @@ void TargetGroupItemPrivate::handleUpdatedKit(Kit *kit)
|
||||
|
||||
void TargetGroupItemPrivate::handleAddedKit(Kit *kit)
|
||||
{
|
||||
if (m_project->supportsKit(kit))
|
||||
q->appendChild(new TargetItem(m_project, kit->id()));
|
||||
q->appendChild(new TargetItem(m_project, kit->id(), m_project->projectIssues(kit)));
|
||||
}
|
||||
|
||||
void TargetItem::updateSubItems()
|
||||
@@ -805,11 +814,9 @@ void TargetGroupItemPrivate::rebuildContents()
|
||||
{
|
||||
q->removeChildren();
|
||||
|
||||
const QList<Kit *> kits = KitManager::sortKits(KitManager::kits([this](const Kit *kit) {
|
||||
return m_project->supportsKit(const_cast<Kit *>(kit));
|
||||
}));
|
||||
const QList<Kit *> kits = KitManager::sortKits(KitManager::kits());
|
||||
for (Kit *kit : kits)
|
||||
q->appendChild(new TargetItem(m_project, kit->id()));
|
||||
q->appendChild(new TargetItem(m_project, kit->id(), m_project->projectIssues(kit)));
|
||||
|
||||
if (q->parent())
|
||||
q->parent()->setData(0, QVariant::fromValue(static_cast<TreeItem *>(q)),
|
||||
|
@@ -25,13 +25,15 @@
|
||||
|
||||
#include "task.h"
|
||||
|
||||
#include "projectexplorerconstants.h"
|
||||
|
||||
#include <app/app_version.h>
|
||||
#include <texteditor/textmark.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/utilsicons.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include "projectexplorerconstants.h"
|
||||
|
||||
#include <QTextStream>
|
||||
|
||||
namespace ProjectExplorer
|
||||
@@ -174,4 +176,9 @@ QString toHtml(const QList<Task> &issues)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool containsType(const QList<Task> &issues, Task::TaskType type)
|
||||
{
|
||||
return Utils::contains(issues, [type](const Task &t) { return t.type == type; });
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -99,6 +99,7 @@ uint PROJECTEXPLORER_EXPORT qHash(const Task &task);
|
||||
bool PROJECTEXPLORER_EXPORT operator<(const Task &a, const Task &b);
|
||||
|
||||
QString PROJECTEXPLORER_EXPORT toHtml(const QList<Task> &issues);
|
||||
bool PROJECTEXPLORER_EXPORT containsType(const QList<Task> &issues, Task::TaskType);
|
||||
|
||||
} //namespace ProjectExplorer
|
||||
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include <projectexplorer/deploymentdata.h>
|
||||
#include <projectexplorer/headerpath.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
@@ -596,12 +597,14 @@ void QmakeProject::buildFinished(bool success)
|
||||
m_invalidateQmakeVfsContents = true;
|
||||
}
|
||||
|
||||
bool QmakeProject::supportsKit(const Kit *k, QString *errorMessage) const
|
||||
QList<Task> QmakeProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
||||
if (!version && errorMessage)
|
||||
*errorMessage = tr("No Qt version set in kit.");
|
||||
return version;
|
||||
QList<Task> result = Project::projectIssues(k);
|
||||
if (!QtSupport::QtKitInformation::qtVersion(k))
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No Qt version set in kit.")));
|
||||
if (!ToolChainKitInformation::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID))
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No C++ compiler set in kit.")));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Find the folder that contains a file with a certain name (recurse down)
|
||||
|
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
QmakeProFile *rootProFile() const;
|
||||
|
||||
bool supportsKit(const ProjectExplorer::Kit *k, QString *errorMesage) const final;
|
||||
QList<ProjectExplorer::Task> projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
|
||||
QmakeProFileNode *rootProjectNode() const final;
|
||||
|
||||
|
@@ -275,52 +275,42 @@ void QmlProject::refreshTargetDirectory()
|
||||
updateDeploymentData(target);
|
||||
}
|
||||
|
||||
bool QmlProject::supportsKit(const Kit *k, QString *errorMessage) const
|
||||
QList<Task> QmlProject::projectIssues(const Kit *k) const
|
||||
{
|
||||
if (!k->isValid()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Kit is not valid.");
|
||||
return false;
|
||||
}
|
||||
QList<Task> result = Project::projectIssues(k);
|
||||
|
||||
const QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
||||
if (!version)
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("No Qt version set in kit.")));
|
||||
|
||||
IDevice::ConstPtr dev = DeviceKitInformation::device(k);
|
||||
if (dev.isNull()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Kit has no device.");
|
||||
return false;
|
||||
}
|
||||
if (dev.isNull())
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("Kit has no device.")));
|
||||
|
||||
QtSupport::BaseQtVersion *version = QtSupport::QtKitInformation::qtVersion(k);
|
||||
if (!version) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("No Qt version set in kit.");
|
||||
return false;
|
||||
}
|
||||
if (version->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0)) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Qt version is too old.");
|
||||
return false;
|
||||
}
|
||||
if (version && version->qtVersion() < QtSupport::QtVersionNumber(5, 0, 0))
|
||||
result.append(createProjectTask(Task::TaskType::Error, tr("Qt version is too old.")));
|
||||
|
||||
if (dev.isNull() || !version)
|
||||
return result; // No need to check deeper than this
|
||||
|
||||
if (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
|
||||
if (version->type() == QtSupport::Constants::DESKTOPQT) {
|
||||
if (static_cast<QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand().isEmpty()) {
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Qt version has no qmlscene command.");
|
||||
return false;
|
||||
if (static_cast<const QtSupport::DesktopQtVersion *>(version)->qmlsceneCommand().isEmpty()) {
|
||||
result.append(createProjectTask(Task::TaskType::Error,
|
||||
tr("Qt version has no qmlscene command.")));
|
||||
}
|
||||
} else {
|
||||
// Non-desktop Qt on a desktop device? We don't support that.
|
||||
if (errorMessage)
|
||||
*errorMessage = tr("Non-desktop Qt is used with a Desktop device.");
|
||||
return false;
|
||||
result.append(createProjectTask(Task::TaskType::Error,
|
||||
tr("Non-desktop Qt is used with a Desktop device.")));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// If not a desktop device, don't check the Qt version for qmlscene.
|
||||
// The device is responsible for providing it and we assume qmlscene can be found
|
||||
// in $PATH if it's not explicitly given.
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage)
|
||||
@@ -334,7 +324,9 @@ Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *erro
|
||||
|
||||
if (!activeTarget()) {
|
||||
// find a kit that matches prerequisites (prefer default one)
|
||||
const QList<Kit*> kits = KitManager::kits([this](const Kit *k) { return supportsKit(k, nullptr); });
|
||||
const QList<Kit*> kits = KitManager::kits([this](const Kit *k) {
|
||||
return !containsType(projectIssues(k), Task::TaskType::Error);
|
||||
});
|
||||
|
||||
if (!kits.isEmpty()) {
|
||||
Kit *kit = kits.contains(KitManager::defaultKit()) ? KitManager::defaultKit() : kits.first();
|
||||
|
@@ -48,7 +48,7 @@ public:
|
||||
explicit QmlProject(const Utils::FileName &filename);
|
||||
~QmlProject() override;
|
||||
|
||||
bool supportsKit(const ProjectExplorer::Kit *k, QString *errorMessage = nullptr) const final;
|
||||
QList<ProjectExplorer::Task> projectIssues(const ProjectExplorer::Kit *k) const final;
|
||||
|
||||
bool validProjectFile() const;
|
||||
|
||||
|
Reference in New Issue
Block a user