forked from qt-creator/qt-creator
Change-Id: I91391ad22b420926b0f512cac23cfe009048b218 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
405 lines
13 KiB
C++
405 lines
13 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of Qt Creator.
|
|
**
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qtkitinformation.h"
|
|
|
|
#include <QRegExp>
|
|
|
|
#include "qtsupportconstants.h"
|
|
#include "qtversionmanager.h"
|
|
#include "qtparser.h"
|
|
#include "qttestparser.h"
|
|
|
|
#include <coreplugin/icore.h>
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
#include <projectexplorer/task.h>
|
|
#include <utils/algorithm.h>
|
|
#include <utils/buildablehelperlibrary.h>
|
|
#include <utils/macroexpander.h>
|
|
#include <utils/qtcassert.h>
|
|
|
|
#include <QComboBox>
|
|
#include <QPushButton>
|
|
|
|
using namespace ProjectExplorer;
|
|
using namespace Utils;
|
|
|
|
namespace QtSupport {
|
|
namespace Internal {
|
|
|
|
class QtKitAspectWidget : public KitAspectWidget
|
|
{
|
|
Q_DECLARE_TR_FUNCTIONS(QtSupport::QtKitAspectWidget)
|
|
public:
|
|
QtKitAspectWidget(Kit *k, const KitAspect *ki) : KitAspectWidget(k, ki)
|
|
{
|
|
m_combo = new QComboBox;
|
|
m_combo->setSizePolicy(QSizePolicy::Ignored, m_combo->sizePolicy().verticalPolicy());
|
|
m_combo->addItem(tr("None"), -1);
|
|
|
|
QList<int> versionIds = Utils::transform(QtVersionManager::versions(), &BaseQtVersion::uniqueId);
|
|
versionsChanged(versionIds, QList<int>(), QList<int>());
|
|
|
|
m_manageButton = new QPushButton(KitAspectWidget::msgManage());
|
|
|
|
refresh();
|
|
m_combo->setToolTip(ki->description());
|
|
|
|
connect(m_combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
|
this, &QtKitAspectWidget::currentWasChanged);
|
|
|
|
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
|
|
this, &QtKitAspectWidget::versionsChanged);
|
|
|
|
connect(m_manageButton, &QAbstractButton::clicked, this, &QtKitAspectWidget::manageQtVersions);
|
|
}
|
|
|
|
~QtKitAspectWidget() override
|
|
{
|
|
delete m_combo;
|
|
delete m_manageButton;
|
|
}
|
|
|
|
private:
|
|
void makeReadOnly() override { m_combo->setEnabled(false); }
|
|
QWidget *mainWidget() const override { return m_combo; }
|
|
QWidget *buttonWidget() const override { return m_manageButton; }
|
|
|
|
void refresh() override
|
|
{
|
|
m_combo->setCurrentIndex(findQtVersion(QtKitAspect::qtVersionId(m_kit)));
|
|
}
|
|
|
|
private:
|
|
static QString itemNameFor(const BaseQtVersion *v)
|
|
{
|
|
QTC_ASSERT(v, return QString());
|
|
QString name = v->displayName();
|
|
if (!v->isValid())
|
|
name = QCoreApplication::translate("QtSupport::Internal::QtKitConfigWidget", "%1 (invalid)").arg(v->displayName());
|
|
return name;
|
|
}
|
|
|
|
void versionsChanged(const QList<int> &added, const QList<int> &removed, const QList<int> &changed)
|
|
{
|
|
foreach (const int id, added) {
|
|
BaseQtVersion *v = QtVersionManager::version(id);
|
|
QTC_CHECK(v);
|
|
QTC_CHECK(findQtVersion(id) < 0);
|
|
m_combo->addItem(itemNameFor(v), id);
|
|
}
|
|
foreach (const int id, removed) {
|
|
int pos = findQtVersion(id);
|
|
if (pos >= 0) // We do not include invalid Qt versions, so do not try to remove those.
|
|
m_combo->removeItem(pos);
|
|
}
|
|
foreach (const int id, changed) {
|
|
BaseQtVersion *v = QtVersionManager::version(id);
|
|
int pos = findQtVersion(id);
|
|
QTC_CHECK(pos >= 0);
|
|
m_combo->setItemText(pos, itemNameFor(v));
|
|
}
|
|
}
|
|
|
|
void manageQtVersions()
|
|
{
|
|
Core::ICore::showOptionsDialog(Constants::QTVERSION_SETTINGS_PAGE_ID, buttonWidget());
|
|
}
|
|
|
|
void currentWasChanged(int idx)
|
|
{
|
|
QtKitAspect::setQtVersionId(m_kit, m_combo->itemData(idx).toInt());
|
|
}
|
|
|
|
int findQtVersion(const int id) const
|
|
{
|
|
for (int i = 0; i < m_combo->count(); ++i) {
|
|
if (id == m_combo->itemData(i).toInt())
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
QComboBox *m_combo;
|
|
QPushButton *m_manageButton;
|
|
};
|
|
} // namespace Internal
|
|
|
|
QtKitAspect::QtKitAspect()
|
|
{
|
|
setObjectName(QLatin1String("QtKitAspect"));
|
|
setId(QtKitAspect::id());
|
|
setDisplayName(tr("Qt version"));
|
|
setDescription(tr("The Qt library to use for all projects using this kit.<br>"
|
|
"A Qt version is required for qmake-based projects "
|
|
"and optional when using other build systems."));
|
|
setPriority(26000);
|
|
|
|
connect(KitManager::instance(), &KitManager::kitsLoaded,
|
|
this, &QtKitAspect::kitsWereLoaded);
|
|
}
|
|
|
|
void QtKitAspect::setup(ProjectExplorer::Kit *k)
|
|
{
|
|
if (!k || k->hasValue(id()))
|
|
return;
|
|
const Abi tcAbi = ToolChainKitAspect::targetAbi(k);
|
|
const Core::Id deviceType = DeviceTypeKitAspect::deviceTypeId(k);
|
|
|
|
const QList<BaseQtVersion *> matches
|
|
= QtVersionManager::versions([&tcAbi, &deviceType](const BaseQtVersion *qt) {
|
|
return qt->targetDeviceTypes().contains(deviceType)
|
|
&& Utils::contains(qt->qtAbis(), [&tcAbi](const Abi &qtAbi) {
|
|
return qtAbi.isCompatibleWith(tcAbi); });
|
|
});
|
|
if (matches.empty())
|
|
return;
|
|
|
|
// An MSVC 2015 toolchain is compatible with an MSVC 2017 Qt, but we prefer an
|
|
// MSVC 2015 Qt if we find one.
|
|
const QList<BaseQtVersion *> exactMatches = Utils::filtered(matches,
|
|
[&tcAbi](const BaseQtVersion *qt) {
|
|
return qt->qtAbis().contains(tcAbi);
|
|
});
|
|
const QList<BaseQtVersion *> &candidates = !exactMatches.empty() ? exactMatches : matches;
|
|
|
|
BaseQtVersion * const qtFromPath = QtVersionManager::version(
|
|
equal(&BaseQtVersion::autodetectionSource, QString::fromLatin1("PATH")));
|
|
if (qtFromPath && candidates.contains(qtFromPath))
|
|
k->setValue(id(), qtFromPath->uniqueId());
|
|
else
|
|
k->setValue(id(), candidates.first()->uniqueId());
|
|
}
|
|
|
|
Tasks QtKitAspect::validate(const ProjectExplorer::Kit *k) const
|
|
{
|
|
QTC_ASSERT(QtVersionManager::isLoaded(), return { });
|
|
BaseQtVersion *version = qtVersion(k);
|
|
if (!version)
|
|
return { };
|
|
|
|
return version->validateKit(k);
|
|
}
|
|
|
|
void QtKitAspect::fix(ProjectExplorer::Kit *k)
|
|
{
|
|
QTC_ASSERT(QtVersionManager::isLoaded(), return);
|
|
BaseQtVersion *version = qtVersion(k);
|
|
if (!version && qtVersionId(k) >= 0) {
|
|
qWarning("Qt version is no longer known, removing from kit \"%s\".", qPrintable(k->displayName()));
|
|
setQtVersionId(k, -1);
|
|
}
|
|
}
|
|
|
|
ProjectExplorer::KitAspectWidget *QtKitAspect::createConfigWidget(ProjectExplorer::Kit *k) const
|
|
{
|
|
QTC_ASSERT(k, return nullptr);
|
|
return new Internal::QtKitAspectWidget(k, this);
|
|
}
|
|
|
|
QString QtKitAspect::displayNamePostfix(const ProjectExplorer::Kit *k) const
|
|
{
|
|
BaseQtVersion *version = qtVersion(k);
|
|
return version ? version->displayName() : QString();
|
|
}
|
|
|
|
ProjectExplorer::KitAspect::ItemList
|
|
QtKitAspect::toUserOutput(const ProjectExplorer::Kit *k) const
|
|
{
|
|
BaseQtVersion *version = qtVersion(k);
|
|
return ItemList() << qMakePair(tr("Qt version"), version ? version->displayName() : tr("None"));
|
|
}
|
|
|
|
void QtKitAspect::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const
|
|
{
|
|
BaseQtVersion *version = qtVersion(k);
|
|
if (version)
|
|
version->addToEnvironment(k, env);
|
|
}
|
|
|
|
ProjectExplorer::IOutputParser *QtKitAspect::createOutputParser(const ProjectExplorer::Kit *k) const
|
|
{
|
|
if (qtVersion(k)) {
|
|
const auto parser = new Internal::QtTestParser;
|
|
parser->appendOutputParser(new QtParser);
|
|
return parser;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
class QtMacroSubProvider
|
|
{
|
|
public:
|
|
QtMacroSubProvider(Kit *kit)
|
|
: expander(BaseQtVersion::createMacroExpander(
|
|
[kit] { return QtKitAspect::qtVersion(kit); }))
|
|
{}
|
|
|
|
MacroExpander *operator()() const
|
|
{
|
|
return expander.get();
|
|
}
|
|
|
|
std::shared_ptr<MacroExpander> expander;
|
|
};
|
|
|
|
void QtKitAspect::addToMacroExpander(Kit *kit, MacroExpander *expander) const
|
|
{
|
|
QTC_ASSERT(kit, return);
|
|
expander->registerSubProvider(QtMacroSubProvider(kit));
|
|
|
|
expander->registerVariable("Qt:Name", tr("Name of Qt Version"),
|
|
[kit]() -> QString {
|
|
BaseQtVersion *version = qtVersion(kit);
|
|
return version ? version->displayName() : tr("unknown");
|
|
});
|
|
expander->registerVariable("Qt:qmakeExecutable", tr("Path to the qmake executable"),
|
|
[kit]() -> QString {
|
|
BaseQtVersion *version = qtVersion(kit);
|
|
return version ? version->qmakeCommand().toString() : QString();
|
|
});
|
|
}
|
|
|
|
Core::Id QtKitAspect::id()
|
|
{
|
|
return "QtSupport.QtInformation";
|
|
}
|
|
|
|
int QtKitAspect::qtVersionId(const ProjectExplorer::Kit *k)
|
|
{
|
|
if (!k)
|
|
return -1;
|
|
|
|
int id = -1;
|
|
QVariant data = k->value(QtKitAspect::id(), -1);
|
|
if (data.type() == QVariant::Int) {
|
|
bool ok;
|
|
id = data.toInt(&ok);
|
|
if (!ok)
|
|
id = -1;
|
|
} else {
|
|
QString source = data.toString();
|
|
BaseQtVersion *v = QtVersionManager::version([source](const BaseQtVersion *v) { return v->autodetectionSource() == source; });
|
|
if (v)
|
|
id = v->uniqueId();
|
|
}
|
|
return id;
|
|
}
|
|
|
|
void QtKitAspect::setQtVersionId(ProjectExplorer::Kit *k, const int id)
|
|
{
|
|
QTC_ASSERT(k, return);
|
|
k->setValue(QtKitAspect::id(), id);
|
|
}
|
|
|
|
BaseQtVersion *QtKitAspect::qtVersion(const ProjectExplorer::Kit *k)
|
|
{
|
|
return QtVersionManager::version(qtVersionId(k));
|
|
}
|
|
|
|
void QtKitAspect::setQtVersion(ProjectExplorer::Kit *k, const BaseQtVersion *v)
|
|
{
|
|
if (!v)
|
|
setQtVersionId(k, -1);
|
|
else
|
|
setQtVersionId(k, v->uniqueId());
|
|
}
|
|
|
|
void QtKitAspect::qtVersionsChanged(const QList<int> &addedIds,
|
|
const QList<int> &removedIds,
|
|
const QList<int> &changedIds)
|
|
{
|
|
Q_UNUSED(addedIds);
|
|
Q_UNUSED(removedIds);
|
|
foreach (ProjectExplorer::Kit *k, ProjectExplorer::KitManager::kits()) {
|
|
if (changedIds.contains(qtVersionId(k))) {
|
|
k->validate(); // Qt version may have become (in)valid
|
|
notifyAboutUpdate(k);
|
|
}
|
|
}
|
|
}
|
|
|
|
void QtKitAspect::kitsWereLoaded()
|
|
{
|
|
foreach (ProjectExplorer::Kit *k, ProjectExplorer::KitManager::kits())
|
|
fix(k);
|
|
|
|
connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
|
|
this, &QtKitAspect::qtVersionsChanged);
|
|
}
|
|
|
|
Kit::Predicate QtKitAspect::platformPredicate(Core::Id platform)
|
|
{
|
|
return [platform](const Kit *kit) -> bool {
|
|
BaseQtVersion *version = QtKitAspect::qtVersion(kit);
|
|
return version && version->targetDeviceTypes().contains(platform);
|
|
};
|
|
}
|
|
|
|
Kit::Predicate QtKitAspect::qtVersionPredicate(const QSet<Core::Id> &required,
|
|
const QtVersionNumber &min,
|
|
const QtVersionNumber &max)
|
|
{
|
|
return [required, min, max](const Kit *kit) -> bool {
|
|
BaseQtVersion *version = QtKitAspect::qtVersion(kit);
|
|
if (!version)
|
|
return false;
|
|
QtVersionNumber current = version->qtVersion();
|
|
if (min.majorVersion > -1 && current < min)
|
|
return false;
|
|
if (max.majorVersion > -1 && current > max)
|
|
return false;
|
|
return version->features().contains(required);
|
|
};
|
|
}
|
|
|
|
QSet<Core::Id> QtKitAspect::supportedPlatforms(const Kit *k) const
|
|
{
|
|
BaseQtVersion *version = QtKitAspect::qtVersion(k);
|
|
return version ? version->targetDeviceTypes() : QSet<Core::Id>();
|
|
}
|
|
|
|
QSet<Core::Id> QtKitAspect::availableFeatures(const Kit *k) const
|
|
{
|
|
BaseQtVersion *version = QtKitAspect::qtVersion(k);
|
|
return version ? version->features() : QSet<Core::Id>();
|
|
}
|
|
|
|
int QtKitAspect::weight(const Kit *k) const
|
|
{
|
|
const BaseQtVersion * const qt = qtVersion(k);
|
|
if (!qt)
|
|
return 0;
|
|
if (!qt->targetDeviceTypes().contains(DeviceTypeKitAspect::deviceTypeId(k)))
|
|
return 0;
|
|
const Abi tcAbi = ToolChainKitAspect::targetAbi(k);
|
|
if (qt->qtAbis().contains(tcAbi))
|
|
return 2;
|
|
return Utils::contains(qt->qtAbis(), [&tcAbi](const Abi &qtAbi) {
|
|
return qtAbi.isCompatibleWith(tcAbi); }) ? 1 : 0;
|
|
}
|
|
|
|
} // namespace QtSupport
|