forked from qt-creator/qt-creator
ProjectExplorer: Do not auto-remove customized run configurations
Until now, it could easily happen that a user's carefully fine-tuned run configurations disappeared just because of e.g. a temporarily broken build system file or simply a switch to a different build configuration. As this is clearly not acceptable, we now make sure customized run configurations are not thrown away even when there is currently no matching factory for them. Fixes: QTCREATORBUG-23163 Fixes: QTCREATORBUG-28273 Change-Id: Ic011a650d15a2897108df986c7e9fe410852e926 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -37,7 +37,7 @@ bool DisplayName::usesDefaultValue() const
|
||||
|
||||
void DisplayName::toMap(QVariantMap &map, const QString &key) const
|
||||
{
|
||||
if (!usesDefaultValue())
|
||||
if (m_forceSerialization || !usesDefaultValue())
|
||||
map.insert(key, m_value);
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,7 @@ public:
|
||||
QString value() const;
|
||||
QString defaultValue() const { return m_defaultValue; }
|
||||
bool usesDefaultValue() const;
|
||||
void forceSerialization() { m_forceSerialization = true; }
|
||||
|
||||
void toMap(QVariantMap &map, const QString &key) const;
|
||||
void fromMap(const QVariantMap &map, const QString &key);
|
||||
@@ -29,6 +30,7 @@ public:
|
||||
private:
|
||||
QString m_value;
|
||||
QString m_defaultValue;
|
||||
bool m_forceSerialization = false;
|
||||
};
|
||||
|
||||
bool QTCREATOR_UTILS_EXPORT operator==(const DisplayName &dn1, const DisplayName &dn2);
|
||||
|
@@ -38,6 +38,7 @@ public:
|
||||
bool usesDefaultDisplayName() const { return m_displayName.usesDefaultValue(); }
|
||||
void setDisplayName(const QString &name);
|
||||
void setDefaultDisplayName(const QString &name);
|
||||
void forceDisplayNameSerialization() { m_displayName.forceSerialization(); }
|
||||
|
||||
void setToolTip(const QString &text);
|
||||
QString toolTip() const;
|
||||
|
@@ -5,9 +5,10 @@
|
||||
|
||||
#include "buildconfiguration.h"
|
||||
#include "deployconfiguration.h"
|
||||
#include "projectconfiguration.h"
|
||||
#include "projectexplorertr.h"
|
||||
#include "runconfiguration.h"
|
||||
#include "target.h"
|
||||
#include "projectconfiguration.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/stringutils.h>
|
||||
@@ -30,6 +31,9 @@ static bool isOrderedBefore(const ProjectConfiguration *a, const ProjectConfigur
|
||||
ProjectConfigurationModel::ProjectConfigurationModel(Target *target) :
|
||||
m_target(target)
|
||||
{
|
||||
connect(target, &Target::runConfigurationsUpdated, this, [this] {
|
||||
emit dataChanged(index(0, 0), index(rowCount(), 0));
|
||||
});
|
||||
}
|
||||
|
||||
int ProjectConfigurationModel::rowCount(const QModelIndex &parent) const
|
||||
@@ -87,13 +91,17 @@ void ProjectConfigurationModel::displayNameChanged(ProjectConfiguration *pc)
|
||||
|
||||
QVariant ProjectConfigurationModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
const int row = index.row();
|
||||
if (row < m_projectConfigurations.size())
|
||||
return m_projectConfigurations.at(row)->expandedDisplayName();
|
||||
}
|
||||
if (index.row() >= m_projectConfigurations.size())
|
||||
return {};
|
||||
ProjectConfiguration * const config = m_projectConfigurations.at(index.row());
|
||||
|
||||
return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
QString displayName = config->expandedDisplayName();
|
||||
if (const auto rc = qobject_cast<RunConfiguration *>(config); rc && !rc->hasCreator())
|
||||
displayName += QString(" [%1]").arg(Tr::tr("unavailable"));
|
||||
return displayName;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ProjectConfiguration *ProjectConfigurationModel::projectConfigurationAt(int i) const
|
||||
|
@@ -45,6 +45,7 @@ using namespace ProjectExplorer::Internal;
|
||||
namespace ProjectExplorer {
|
||||
|
||||
const char BUILD_KEY[] = "ProjectExplorer.RunConfiguration.BuildKey";
|
||||
const char CUSTOMIZED_KEY[] = "ProjectExplorer.RunConfiguration.Customized";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -162,6 +163,7 @@ RunConfiguration::RunConfiguration(Target *target, Utils::Id id)
|
||||
: ProjectConfiguration(target, id)
|
||||
{
|
||||
QTC_CHECK(target && target == this->target());
|
||||
forceDisplayNameSerialization();
|
||||
connect(target, &Target::parsingFinished, this, &RunConfiguration::update);
|
||||
|
||||
m_expander.setDisplayName(Tr::tr("Run Settings"));
|
||||
@@ -239,6 +241,34 @@ bool RunConfiguration::isConfigured() const
|
||||
return !Utils::anyOf(checkForIssues(), [](const Task &t) { return t.type == Task::Error; });
|
||||
}
|
||||
|
||||
bool RunConfiguration::isCustomized() const
|
||||
{
|
||||
if (m_customized)
|
||||
return true;
|
||||
QVariantMap state = toMapSimple();
|
||||
|
||||
// TODO: Why do we save this at all? It's a computed value.
|
||||
state.remove("RunConfiguration.WorkingDirectory.default");
|
||||
|
||||
return state != m_pristineState;
|
||||
}
|
||||
|
||||
bool RunConfiguration::hasCreator() const
|
||||
{
|
||||
return Utils::contains(RunConfigurationFactory::creatorsForTarget(target()),
|
||||
[this](const RunConfigurationCreationInfo &info) {
|
||||
return info.factory->runConfigurationId() == id() && info.buildKey == buildKey();
|
||||
});
|
||||
}
|
||||
|
||||
void RunConfiguration::setPristineState()
|
||||
{
|
||||
if (!m_customized) {
|
||||
m_pristineState = toMapSimple();
|
||||
m_pristineState.remove("RunConfiguration.WorkingDirectory.default");
|
||||
}
|
||||
}
|
||||
|
||||
void RunConfiguration::addAspectFactory(const AspectFactory &aspectFactory)
|
||||
{
|
||||
theAspectFactories.push_back(aspectFactory);
|
||||
@@ -277,8 +307,14 @@ Task RunConfiguration::createConfigurationIssue(const QString &description) cons
|
||||
|
||||
QVariantMap RunConfiguration::toMap() const
|
||||
{
|
||||
QVariantMap map = ProjectConfiguration::toMap();
|
||||
QVariantMap map = toMapSimple();
|
||||
map.insert(CUSTOMIZED_KEY, isCustomized());
|
||||
return map;
|
||||
}
|
||||
|
||||
QVariantMap RunConfiguration::toMapSimple() const
|
||||
{
|
||||
QVariantMap map = ProjectConfiguration::toMap();
|
||||
map.insert(BUILD_KEY, m_buildKey);
|
||||
|
||||
// FIXME: Remove this id mangling, e.g. by using a separate entry for the build key.
|
||||
@@ -344,6 +380,7 @@ bool RunConfiguration::fromMap(const QVariantMap &map)
|
||||
if (!ProjectConfiguration::fromMap(map))
|
||||
return false;
|
||||
|
||||
m_customized = m_customized || map.value(CUSTOMIZED_KEY, false).toBool();
|
||||
m_buildKey = map.value(BUILD_KEY).toString();
|
||||
|
||||
if (m_buildKey.isEmpty()) {
|
||||
@@ -584,6 +621,7 @@ RunConfiguration *RunConfigurationCreationInfo::create(Target *target) const
|
||||
rc->m_buildKey = buildKey;
|
||||
rc->update();
|
||||
rc->setDisplayName(displayName);
|
||||
rc->setPristineState();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -597,6 +635,7 @@ RunConfiguration *RunConfigurationFactory::restore(Target *parent, const QVarian
|
||||
RunConfiguration *rc = factory->create(parent);
|
||||
if (rc->fromMap(map)) {
|
||||
rc->update();
|
||||
rc->setPristineState();
|
||||
return rc;
|
||||
}
|
||||
delete rc;
|
||||
|
@@ -111,7 +111,10 @@ public:
|
||||
QWidget *createConfigurationWidget();
|
||||
|
||||
bool isConfigured() const;
|
||||
bool isCustomized() const;
|
||||
bool hasCreator() const;
|
||||
virtual Tasks checkForIssues() const { return {}; }
|
||||
void setPristineState();
|
||||
|
||||
using CommandLineGetter = std::function<Utils::CommandLine()>;
|
||||
void setCommandLineGetter(const CommandLineGetter &cmdGetter);
|
||||
@@ -170,6 +173,7 @@ private:
|
||||
// Any additional data should be handled by aspects.
|
||||
bool fromMap(const QVariantMap &map) final;
|
||||
QVariantMap toMap() const final;
|
||||
QVariantMap toMapSimple() const;
|
||||
|
||||
static void addAspectFactory(const AspectFactory &aspectFactory);
|
||||
|
||||
@@ -182,6 +186,8 @@ private:
|
||||
RunnableModifier m_runnableModifier;
|
||||
Updater m_updater;
|
||||
Utils::MacroExpander m_expander;
|
||||
QVariantMap m_pristineState;
|
||||
bool m_customized = false;
|
||||
};
|
||||
|
||||
class RunConfigurationCreationInfo
|
||||
|
@@ -706,7 +706,7 @@ void Target::updateDefaultRunConfigurations()
|
||||
present = true;
|
||||
}
|
||||
}
|
||||
if (!present)
|
||||
if (!present && !rc->isCustomized())
|
||||
toRemove.append(rc);
|
||||
}
|
||||
configuredCount -= toRemove.count();
|
||||
@@ -797,6 +797,8 @@ void Target::updateDefaultRunConfigurations()
|
||||
// Remove the RCs that are no longer needed:
|
||||
for (RunConfiguration *rc : std::as_const(removalList))
|
||||
removeRunConfiguration(rc);
|
||||
|
||||
emit runConfigurationsUpdated();
|
||||
}
|
||||
|
||||
QVariant Target::namedSettings(const QString &name) const
|
||||
|
@@ -131,6 +131,7 @@ signals:
|
||||
void removedRunConfiguration(ProjectExplorer::RunConfiguration *rc);
|
||||
void addedRunConfiguration(ProjectExplorer::RunConfiguration *rc);
|
||||
void activeRunConfigurationChanged(ProjectExplorer::RunConfiguration *rc);
|
||||
void runConfigurationsUpdated();
|
||||
|
||||
void removedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
|
||||
void addedBuildConfiguration(ProjectExplorer::BuildConfiguration *bc);
|
||||
|
Reference in New Issue
Block a user