Let users disable environment entries

It's helpful to be able to temporarily disable environment variables, as
opposed to having to remove (and then re-add) them entirely.

Fixes: QTCREATORBUG-20984
Change-Id: Ib0d287035b9357507c4c19faaf3a1517382506b5
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-07-09 17:41:30 +02:00
parent b1dbd7e358
commit 4d71c0f13e
16 changed files with 179 additions and 95 deletions

View File

@@ -408,7 +408,7 @@ int main(int argc, char **argv)
{{"LD_LIBRARY_PATH", "", Utils::EnvironmentItem::Unset}}); {{"LD_LIBRARY_PATH", "", Utils::EnvironmentItem::Unset}});
} else { } else {
Utils::Environment::modifySystemEnvironment( Utils::Environment::modifySystemEnvironment(
{{"LD_LIBRARY_PATH", *options.userLibraryPath, Utils::EnvironmentItem::Set}}); {{"LD_LIBRARY_PATH", *options.userLibraryPath, Utils::EnvironmentItem::SetEnabled}});
} }
} }

View File

@@ -173,8 +173,10 @@ QProcessEnvironment ProcessCreator::processEnvironment() const
} }
const Utils::Environment &env = m_environment; const Utils::Environment &env = m_environment;
for (auto it = env.constBegin(); it != env.constEnd(); ++it) for (auto it = env.constBegin(); it != env.constEnd(); ++it) {
processEnvironment.insert(it.key(), it.value()); if (env.isEnabled(it))
processEnvironment.insert(it.key(), env.value(it));
}
return processEnvironment; return processEnvironment;
} }

View File

@@ -68,8 +68,10 @@ static NameValueMap::const_iterator findKey(const NameValueMap &input,
QProcessEnvironment Environment::toProcessEnvironment() const QProcessEnvironment Environment::toProcessEnvironment() const
{ {
QProcessEnvironment result; QProcessEnvironment result;
for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) {
result.insert(it.key(), it.value()); if (it.value().second)
result.insert(it.key(), it.value().first);
}
return result; return result;
} }
@@ -90,12 +92,12 @@ void Environment::appendOrSet(const QString &key, const QString &value, const QS
QTC_ASSERT(!key.contains('='), return ); QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key); auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) { if (it == m_values.end()) {
m_values.insert(key, value); m_values.insert(key, qMakePair(value, true));
} else { } else {
// Append unless it is already there // Append unless it is already there
const QString toAppend = sep + value; const QString toAppend = sep + value;
if (!it.value().endsWith(toAppend)) if (!it.value().first.endsWith(toAppend))
it.value().append(toAppend); it.value().first.append(toAppend);
} }
} }
@@ -104,12 +106,12 @@ void Environment::prependOrSet(const QString &key, const QString &value, const Q
QTC_ASSERT(!key.contains('='), return ); QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key); auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) { if (it == m_values.end()) {
m_values.insert(key, value); m_values.insert(key, qMakePair(value, true));
} else { } else {
// Prepend unless it is already there // Prepend unless it is already there
const QString toPrepend = value + sep; const QString toPrepend = value + sep;
if (!it.value().startsWith(toPrepend)) if (!it.value().first.startsWith(toPrepend))
it.value().prepend(toPrepend); it.value().first.prepend(toPrepend);
} }
} }
@@ -346,8 +348,8 @@ QString Environment::expandVariables(const QString &input) const
if (vStart > 0) { if (vStart > 0) {
const_iterator it = findKey(m_values, m_osType, result.mid(vStart, i - vStart - 1)); const_iterator it = findKey(m_values, m_osType, result.mid(vStart, i - vStart - 1));
if (it != m_values.constEnd()) { if (it != m_values.constEnd()) {
result.replace(vStart - 1, i - vStart + 1, *it); result.replace(vStart - 1, i - vStart + 1, it->first);
i = vStart - 1 + it->length(); i = vStart - 1 + it->first.length();
vStart = -1; vStart = -1;
} else { } else {
vStart = i; vStart = i;
@@ -380,8 +382,8 @@ QString Environment::expandVariables(const QString &input) const
if (c == '}') { if (c == '}') {
const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart)); const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart));
if (it != constEnd()) { if (it != constEnd()) {
result.replace(vStart - 2, i - vStart + 2, *it); result.replace(vStart - 2, i - vStart + 2, it->first);
i = vStart - 2 + it->length(); i = vStart - 2 + it->first.length();
} }
state = BASE; state = BASE;
} }
@@ -389,8 +391,8 @@ QString Environment::expandVariables(const QString &input) const
if (!c.isLetterOrNumber() && c != '_') { if (!c.isLetterOrNumber() && c != '_') {
const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1)); const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1));
if (it != constEnd()) { if (it != constEnd()) {
result.replace(vStart - 1, i - vStart, *it); result.replace(vStart - 1, i - vStart, it->first);
i = vStart - 1 + it->length(); i = vStart - 1 + it->first.length();
} }
state = BASE; state = BASE;
} }
@@ -399,7 +401,7 @@ QString Environment::expandVariables(const QString &input) const
if (state == VARIABLE) { if (state == VARIABLE) {
const_iterator it = m_values.constFind(result.mid(vStart)); const_iterator it = m_values.constFind(result.mid(vStart));
if (it != constEnd()) if (it != constEnd())
result.replace(vStart - 1, result.length() - vStart + 1, *it); result.replace(vStart - 1, result.length() - vStart + 1, it->first);
} }
} }
return result; return result;

View File

@@ -47,7 +47,8 @@ Utils::optional<EnvironmentItems> EnvironmentDialog::getEnvironmentItems(
tr("Enter one environment variable per line.\n" tr("Enter one environment variable per line.\n"
"To set or change a variable, use VARIABLE=VALUE.\n" "To set or change a variable, use VARIABLE=VALUE.\n"
"Existing variables can be referenced in a VALUE with ${OTHER}.\n" "Existing variables can be referenced in a VALUE with ${OTHER}.\n"
"To clear a variable, put its name on a line with nothing else on it.")); "To clear a variable, put its name on a line with nothing else on it.\n"
"To disable a variable, prefix the line with \"#\""));
} }
} // namespace Utils } // namespace Utils

View File

@@ -79,19 +79,22 @@ NameValueDictionary::NameValueDictionary(const NameValuePairs &nameValues)
QStringList NameValueDictionary::toStringList() const QStringList NameValueDictionary::toStringList() const
{ {
QStringList result; QStringList result;
for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it) {
result.append(it.key() + '=' + it.value()); if (it.value().second)
result.append(it.key() + '=' + it.value().first);
}
return result; return result;
} }
void NameValueDictionary::set(const QString &key, const QString &value) void NameValueDictionary::set(const QString &key, const QString &value, bool enabled)
{ {
QTC_ASSERT(!key.contains('='), return ); QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key); auto it = findKey(m_values, m_osType, key);
const auto valuePair = qMakePair(value, enabled);
if (it == m_values.end()) if (it == m_values.end())
m_values.insert(key, value); m_values.insert(key, valuePair);
else else
it.value() = value; it.value() = valuePair;
} }
void NameValueDictionary::unset(const QString &key) void NameValueDictionary::unset(const QString &key)
@@ -110,7 +113,7 @@ void NameValueDictionary::clear()
QString NameValueDictionary::value(const QString &key) const QString NameValueDictionary::value(const QString &key) const
{ {
const auto it = findKey(m_values, m_osType, key); const auto it = findKey(m_values, m_osType, key);
return it != m_values.end() ? it.value() : QString(); return it != m_values.end() && it.value().second ? it.value().first : QString();
} }
NameValueDictionary::const_iterator NameValueDictionary::constFind(const QString &name) const NameValueDictionary::const_iterator NameValueDictionary::constFind(const QString &name) const
@@ -146,8 +149,9 @@ NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool
NameValueItems result; NameValueItems result;
while (thisIt != constEnd() || otherIt != other.constEnd()) { while (thisIt != constEnd() || otherIt != other.constEnd()) {
if (thisIt == constEnd()) { if (thisIt == constEnd() || thisIt.key() > otherIt.key()) {
result.append(NameValueItem(otherIt.key(), otherIt.value())); result.append({otherIt.key(), otherIt.value().first,
otherIt.value().second ? NameValueItem::SetEnabled : NameValueItem::SetDisabled});
++otherIt; ++otherIt;
} else if (otherIt == other.constEnd()) { } else if (otherIt == other.constEnd()) {
result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset)); result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset));
@@ -155,25 +159,27 @@ NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool
} else if (thisIt.key() < otherIt.key()) { } else if (thisIt.key() < otherIt.key()) {
result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset)); result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset));
++thisIt; ++thisIt;
} else if (thisIt.key() > otherIt.key()) {
result.append(NameValueItem(otherIt.key(), otherIt.value()));
++otherIt;
} else { } else {
const QString &oldValue = thisIt.value(); const QString &oldValue = thisIt.value().first;
const QString &newValue = otherIt.value(); const QString &newValue = otherIt.value().first;
const bool oldEnabled = thisIt.value().second;
const bool newEnabled = otherIt.value().second;
if (oldValue != newValue) { if (oldValue != newValue) {
if (checkAppendPrepend && newValue.startsWith(oldValue)) { if (checkAppendPrepend && newValue.startsWith(oldValue)
&& oldEnabled == newEnabled) {
QString appended = newValue.right(newValue.size() - oldValue.size()); QString appended = newValue.right(newValue.size() - oldValue.size());
if (appended.startsWith(QLatin1Char(pathSepC))) if (appended.startsWith(QLatin1Char(pathSepC)))
appended.remove(0, 1); appended.remove(0, 1);
result.append(NameValueItem(otherIt.key(), appended, NameValueItem::Append)); result.append(NameValueItem(otherIt.key(), appended, NameValueItem::Append));
} else if (checkAppendPrepend && newValue.endsWith(oldValue)) { } else if (checkAppendPrepend && newValue.endsWith(oldValue)
&& oldEnabled == newEnabled) {
QString prepended = newValue.left(newValue.size() - oldValue.size()); QString prepended = newValue.left(newValue.size() - oldValue.size());
if (prepended.endsWith(QLatin1Char(pathSepC))) if (prepended.endsWith(QLatin1Char(pathSepC)))
prepended.chop(1); prepended.chop(1);
result.append(NameValueItem(otherIt.key(), prepended, NameValueItem::Prepend)); result.append(NameValueItem(otherIt.key(), prepended, NameValueItem::Prepend));
} else { } else {
result.append(NameValueItem(otherIt.key(), newValue)); result.append({otherIt.key(), newValue, newEnabled
? NameValueItem::SetEnabled : NameValueItem::SetDisabled});
} }
} }
++otherIt; ++otherIt;

View File

@@ -33,7 +33,7 @@ namespace Utils {
using NameValuePair = std::pair<QString, QString>; using NameValuePair = std::pair<QString, QString>;
using NameValuePairs = QVector<NameValuePair>; using NameValuePairs = QVector<NameValuePair>;
using NameValueMap = QMap<QString, QString>; using NameValueMap = QMap<QString, QPair<QString, bool>>;
class QTCREATOR_UTILS_EXPORT NameValueDictionary class QTCREATOR_UTILS_EXPORT NameValueDictionary
{ {
@@ -48,7 +48,7 @@ public:
QStringList toStringList() const; QStringList toStringList() const;
QString value(const QString &key) const; QString value(const QString &key) const;
void set(const QString &key, const QString &value); void set(const QString &key, const QString &value, bool enabled = true);
void unset(const QString &key); void unset(const QString &key);
void modify(const NameValueItems &items); void modify(const NameValueItems &items);
/// Return the KeyValueDictionary changes necessary to modify this into the other environment. /// Return the KeyValueDictionary changes necessary to modify this into the other environment.
@@ -61,15 +61,13 @@ public:
void clear(); void clear();
int size() const; int size() const;
QString key(NameValueDictionary::const_iterator it) const { return it.key(); } QString key(const_iterator it) const { return it.key(); }
QString value(const_iterator it) const { return it.value().first; }
bool isEnabled(const_iterator it) const { return it.value().second; }
QString value(NameValueDictionary::const_iterator it) const { return it.value(); } const_iterator constBegin() const { return m_values.constBegin(); }
const_iterator constEnd() const { return m_values.constEnd(); }
NameValueDictionary::const_iterator constBegin() const { return m_values.constBegin(); } const_iterator constFind(const QString &name) const;
NameValueDictionary::const_iterator constEnd() const { return m_values.constEnd(); }
NameValueDictionary::const_iterator constFind(const QString &name) const;
friend bool operator!=(const NameValueDictionary &first, const NameValueDictionary &second) friend bool operator!=(const NameValueDictionary &first, const NameValueDictionary &second)
{ {

View File

@@ -42,10 +42,17 @@ NameValueItems NameValueItem::fromStringList(const QStringList &list)
NameValueItems result; NameValueItems result;
for (const QString &string : list) { for (const QString &string : list) {
int pos = string.indexOf('=', 1); int pos = string.indexOf('=', 1);
if (pos == -1) if (pos == -1) {
result.append(NameValueItem(string, QString(), NameValueItem::Unset)); result.append(NameValueItem(string, QString(), NameValueItem::Unset));
else continue;
result.append(NameValueItem(string.left(pos), string.mid(pos + 1))); }
const int hashPos = string.indexOf('#');
if (hashPos != -1 && hashPos < pos) {
result.append({string.mid(hashPos + 1, pos - hashPos - 1), string.mid(pos + 1),
NameValueItem::SetDisabled});
} else {
result.append({string.left(pos), string.mid(pos + 1)});
}
} }
return result; return result;
} }
@@ -55,7 +62,8 @@ QStringList NameValueItem::toStringList(const NameValueItems &list)
return Utils::transform<QStringList>(list, [](const NameValueItem &item) { return Utils::transform<QStringList>(list, [](const NameValueItem &item) {
if (item.operation == NameValueItem::Unset) if (item.operation == NameValueItem::Unset)
return QString(item.name); return QString(item.name);
return QString(item.name + '=' + item.value); return QString((item.operation == NameValueItem::SetDisabled ? "#" : "")
+ item.name + '=' + item.value);
}); });
} }
@@ -103,7 +111,7 @@ static QString expand(const NameValueDictionary *dictionary, QString value)
const QString &key = value.mid(i + 2, end - i - 2); const QString &key = value.mid(i + 2, end - i - 2);
NameValueDictionary::const_iterator it = dictionary->constFind(key); NameValueDictionary::const_iterator it = dictionary->constFind(key);
if (it != dictionary->constEnd()) if (it != dictionary->constEnd())
value.replace(i, end - i + 1, it.value()); value.replace(i, end - i + 1, it.value().first);
++replaceCount; ++replaceCount;
QTC_ASSERT(replaceCount < 100, break); QTC_ASSERT(replaceCount < 100, break);
} }
@@ -124,16 +132,19 @@ enum : char {
void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const
{ {
switch (op) { switch (op) {
case Set: case SetEnabled:
dictionary->set(name, expand(dictionary, value)); dictionary->set(name, expand(dictionary, value));
break; break;
case SetDisabled:
dictionary->set(name, expand(dictionary, value), false);
break;
case Unset: case Unset:
dictionary->unset(name); dictionary->unset(name);
break; break;
case Prepend: { case Prepend: {
const NameValueDictionary::const_iterator it = dictionary->constFind(name); const NameValueDictionary::const_iterator it = dictionary->constFind(name);
if (it != dictionary->constEnd()) { if (it != dictionary->constEnd()) {
QString v = it.value(); QString v = dictionary->value(it);
const QChar pathSep{QLatin1Char(pathSepC)}; const QChar pathSep{QLatin1Char(pathSepC)};
int sepCount = 0; int sepCount = 0;
if (v.startsWith(pathSep)) if (v.startsWith(pathSep))
@@ -147,13 +158,13 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const
v.prepend(expand(dictionary, value)); v.prepend(expand(dictionary, value));
dictionary->set(name, v); dictionary->set(name, v);
} else { } else {
apply(dictionary, Set); apply(dictionary, SetEnabled);
} }
} break; } break;
case Append: { case Append: {
const NameValueDictionary::const_iterator it = dictionary->constFind(name); const NameValueDictionary::const_iterator it = dictionary->constFind(name);
if (it != dictionary->constEnd()) { if (it != dictionary->constEnd()) {
QString v = it.value(); QString v = dictionary->value(it);
const QChar pathSep{QLatin1Char(pathSepC)}; const QChar pathSep{QLatin1Char(pathSepC)};
int sepCount = 0; int sepCount = 0;
if (v.endsWith(pathSep)) if (v.endsWith(pathSep))
@@ -167,7 +178,7 @@ void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const
v.append(expand(dictionary, value)); v.append(expand(dictionary, value));
dictionary->set(name, v); dictionary->set(name, v);
} else { } else {
apply(dictionary, Set); apply(dictionary, SetEnabled);
} }
} break; } break;
} }
@@ -180,9 +191,12 @@ QDebug operator<<(QDebug debug, const NameValueItem &i)
debug.nospace(); debug.nospace();
debug << "KeyValueItem("; debug << "KeyValueItem(";
switch (i.operation) { switch (i.operation) {
case NameValueItem::Set: case NameValueItem::SetEnabled:
debug << "set \"" << i.name << "\" to \"" << i.value << '"'; debug << "set \"" << i.name << "\" to \"" << i.value << '"';
break; break;
case NameValueItem::SetDisabled:
debug << "set \"" << i.name << "\" to \"" << i.value << '"' << "[disabled]";
break;
case NameValueItem::Unset: case NameValueItem::Unset:
debug << "unset \"" << i.name << '"'; debug << "unset \"" << i.name << '"';
break; break;

View File

@@ -37,9 +37,9 @@ namespace Utils {
class QTCREATOR_UTILS_EXPORT NameValueItem class QTCREATOR_UTILS_EXPORT NameValueItem
{ {
public: public:
enum Operation : char { Set, Unset, Prepend, Append }; enum Operation : char { SetEnabled, Unset, Prepend, Append, SetDisabled };
NameValueItem() = default; NameValueItem() = default;
NameValueItem(const QString &key, const QString &value, Operation operation = Set) NameValueItem(const QString &key, const QString &value, Operation operation = SetEnabled)
: name(key) : name(key)
, value(value) , value(value)
, operation(operation) , operation(operation)

View File

@@ -28,11 +28,15 @@
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/namevaluedictionary.h> #include <utils/namevaluedictionary.h>
#include <utils/qtcassert.h>
#include <QBrush>
#include <QColor>
#include <QFont> #include <QFont>
#include <QString> #include <QString>
namespace Utils { namespace Utils {
namespace Internal { namespace Internal {
class NameValueModelPrivate class NameValueModelPrivate
@@ -142,19 +146,21 @@ QVariant NameValueModel::data(const QModelIndex &index, int role) const
if (!index.isValid()) if (!index.isValid())
return QVariant(); return QVariant();
if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) { const auto resultIterator = d->m_resultNameValueDictionary.constBegin() + index.row();
if (index.column() == 0) { switch (role) {
return d->m_resultNameValueDictionary.key(d->m_resultNameValueDictionary.constBegin() case Qt::DisplayRole:
+ index.row()); case Qt::EditRole:
} else if (index.column() == 1) { case Qt::ToolTipRole:
if (index.column() == 0)
return d->m_resultNameValueDictionary.key(resultIterator);
if (index.column() == 1) {
// Do not return "<UNSET>" when editing a previously unset variable: // Do not return "<UNSET>" when editing a previously unset variable:
if (role == Qt::EditRole) { if (role == Qt::EditRole) {
int pos = d->findInChanges(indexToVariable(index)); int pos = d->findInChanges(indexToVariable(index));
if (pos >= 0) if (pos != -1)
return d->m_items.at(pos).value; return d->m_items.at(pos).value;
} }
QString value = d->m_resultNameValueDictionary.value( QString value = d->m_resultNameValueDictionary.value(resultIterator);
d->m_resultNameValueDictionary.constBegin() + index.row());
if (role == Qt::ToolTipRole && value.length() > 80) { if (role == Qt::ToolTipRole && value.length() > 80) {
// Use html to enable text wrapping // Use html to enable text wrapping
value = value.toHtmlEscaped(); value = value.toHtmlEscaped();
@@ -163,16 +169,15 @@ QVariant NameValueModel::data(const QModelIndex &index, int role) const
} }
return value; return value;
} }
break;
case Qt::FontRole: {
QFont f;
f.setStrikeOut(!d->m_resultNameValueDictionary.isEnabled(resultIterator));
return f;
} }
if (role == Qt::FontRole) { case Qt::ForegroundRole:
// check whether this name value item variable exists in d->m_items return changes(d->m_resultNameValueDictionary.key(resultIterator))
if (changes(d->m_resultNameValueDictionary.key(d->m_resultNameValueDictionary.constBegin() ? QBrush(Qt::blue) : QBrush();
+ index.row()))) {
QFont f;
f.setBold(true);
return QVariant(f);
}
return QFont();
} }
return QVariant(); return QVariant();
} }
@@ -236,15 +241,20 @@ bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, in
// We are changing an existing value: // We are changing an existing value:
const QString stringValue = value.toString(); const QString stringValue = value.toString();
if (changesPos != -1) { if (changesPos != -1) {
const auto oldIt = d->m_baseNameValueDictionary.constFind(oldName);
const auto newIt = d->m_resultNameValueDictionary.constFind(oldName);
// We have already changed this value // We have already changed this value
if (d->m_baseNameValueDictionary.hasKey(oldName) if (oldIt != d->m_baseNameValueDictionary.constEnd()
&& stringValue == d->m_baseNameValueDictionary.value(oldName)) { && stringValue == d->m_baseNameValueDictionary.value(oldIt)
&& d->m_baseNameValueDictionary.isEnabled(oldIt)
== d->m_resultNameValueDictionary.isEnabled(newIt)) {
// ... and now went back to the base value // ... and now went back to the base value
d->m_items.removeAt(changesPos); d->m_items.removeAt(changesPos);
} else { } else {
// ... and changed it again // ... and changed it again
d->m_items[changesPos].value = stringValue; d->m_items[changesPos].value = stringValue;
d->m_items[changesPos].operation = NameValueItem::Set; if (d->m_items[changesPos].operation == NameValueItem::Unset)
d->m_items[changesPos].operation = NameValueItem::SetEnabled;
} }
} else { } else {
// Add a new change item: // Add a new change item:
@@ -346,13 +356,39 @@ void NameValueModel::unsetVariable(const QString &name)
emit userChangesChanged(); emit userChangesChanged();
} }
bool NameValueModel::canUnset(const QString &name) void NameValueModel::toggleVariable(const QModelIndex &idx)
{ {
int pos = d->findInChanges(name); const QString name = indexToVariable(idx);
if (pos != -1) const auto newIt = d->m_resultNameValueDictionary.constFind(name);
return d->m_items.at(pos).operation == NameValueItem::Unset; QTC_ASSERT(newIt != d->m_resultNameValueDictionary.constEnd(), return);
else const auto op = d->m_resultNameValueDictionary.isEnabled(newIt)
return false; ? NameValueItem::SetDisabled : NameValueItem::SetEnabled;
const int changesPos = d->findInChanges(name);
if (changesPos != -1) {
const auto oldIt = d->m_baseNameValueDictionary.constFind(name);
if (oldIt == d->m_baseNameValueDictionary.constEnd()
|| oldIt.value().first != newIt.value().first) {
d->m_items[changesPos].operation = op;
} else {
d->m_items.removeAt(changesPos);
}
} else {
d->m_items.append({name, d->m_resultNameValueDictionary.value(newIt), op});
}
d->updateResultNameValueDictionary();
emit dataChanged(index(idx.row(), 0), index(idx.row(), 1));
emit userChangesChanged();
}
bool NameValueModel::isUnset(const QString &name)
{
const int pos = d->findInChanges(name);
return pos == -1 ? false : d->m_items.at(pos).operation == NameValueItem::Unset;
}
bool NameValueModel::isEnabled(const QString &name) const
{
return d->m_resultNameValueDictionary.isEnabled(d->m_resultNameValueDictionary.constFind(name));
} }
bool NameValueModel::canReset(const QString &name) bool NameValueModel::canReset(const QString &name)

View File

@@ -59,7 +59,9 @@ public:
QModelIndex addVariable(const NameValueItem &item); QModelIndex addVariable(const NameValueItem &item);
void resetVariable(const QString &name); void resetVariable(const QString &name);
void unsetVariable(const QString &name); void unsetVariable(const QString &name);
bool canUnset(const QString &name); void toggleVariable(const QModelIndex &index);
bool isUnset(const QString &name);
bool isEnabled(const QString &name) const;
bool canReset(const QString &name); bool canReset(const QString &name);
QString indexToVariable(const QModelIndex &index) const; QString indexToVariable(const QModelIndex &index) const;
QModelIndex variableToIndex(const QString &name) const; QModelIndex variableToIndex(const QString &name) const;

View File

@@ -58,7 +58,7 @@ void ClangIndexingProjectSettings::saveMacros(const Utils::NameValueItems &items
for (const Utils::NameValueItem &item : items) { for (const Utils::NameValueItem &item : items) {
using Operation = Utils::NameValueItem::Operation; using Operation = Utils::NameValueItem::Operation;
switch (item.operation) { switch (item.operation) {
case Operation::Set: case Operation::SetEnabled:
sets[item.name] = item.value; sets[item.name] = item.value;
break; break;
case Operation::Unset: case Operation::Unset:
@@ -88,7 +88,7 @@ Utils::NameValueItems ClangIndexingProjectSettings::readMacros() const
QVariant sets = m_project->namedSettings("set_indexing_macro"); QVariant sets = m_project->namedSettings("set_indexing_macro");
items += fromQVariantMap(sets.toMap(), Utils::NameValueItem::Set); items += fromQVariantMap(sets.toMap(), Utils::NameValueItem::SetEnabled);
return items; return items;
} }

View File

@@ -237,7 +237,7 @@ void PreprocessorMacroWidget::currentIndexChanged(const QModelIndex &current)
m_editButton->setEnabled(true); m_editButton->setEnabled(true);
const QString &name = m_model->indexToVariable(current); const QString &name = m_model->indexToVariable(current);
bool modified = m_model->canReset(name) && m_model->changes(name); bool modified = m_model->canReset(name) && m_model->changes(name);
bool unset = m_model->canUnset(name); bool unset = m_model->isUnset(name);
m_resetButton->setEnabled(modified || unset); m_resetButton->setEnabled(modified || unset);
m_unsetButton->setEnabled(!unset); m_unsetButton->setEnabled(!unset);
} else { } else {

View File

@@ -189,7 +189,7 @@ void updateWithSettings(ClangBackEnd::CompilerMacros &macros,
}); });
auto point = std::partition_point(settingsItems.begin(), settingsItems.end(), [](const auto &entry) { auto point = std::partition_point(settingsItems.begin(), settingsItems.end(), [](const auto &entry) {
return entry.operation == Utils::NameValueItem::Set; return entry.operation == Utils::NameValueItem::SetEnabled;
}); });
std::transform( std::transform(

View File

@@ -94,6 +94,7 @@ public:
QPushButton *m_addButton; QPushButton *m_addButton;
QPushButton *m_resetButton; QPushButton *m_resetButton;
QPushButton *m_unsetButton; QPushButton *m_unsetButton;
QPushButton *m_toggleButton;
QPushButton *m_batchEditButton; QPushButton *m_batchEditButton;
QPushButton *m_appendPathButton = nullptr; QPushButton *m_appendPathButton = nullptr;
QPushButton *m_prependPathButton = nullptr; QPushButton *m_prependPathButton = nullptr;
@@ -166,6 +167,13 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additi
d->m_unsetButton->setText(tr("&Unset")); d->m_unsetButton->setText(tr("&Unset"));
buttonLayout->addWidget(d->m_unsetButton); buttonLayout->addWidget(d->m_unsetButton);
d->m_toggleButton = new QPushButton(tr("Disable"), this);
buttonLayout->addWidget(d->m_toggleButton);
connect(d->m_toggleButton, &QPushButton::clicked, this, [this] {
d->m_model->toggleVariable(d->m_environmentView->currentIndex());
updateButtons();
});
if (type == TypeLocal) { if (type == TypeLocal) {
d->m_appendPathButton = new QPushButton(this); d->m_appendPathButton = new QPushButton(this);
d->m_appendPathButton->setEnabled(false); d->m_appendPathButton->setEnabled(false);
@@ -287,10 +295,19 @@ void EnvironmentWidget::updateSummaryText()
foreach (const Utils::EnvironmentItem &item, list) { foreach (const Utils::EnvironmentItem &item, list) {
if (item.name != Utils::EnvironmentModel::tr("<VARIABLE>")) { if (item.name != Utils::EnvironmentModel::tr("<VARIABLE>")) {
text.append(QLatin1String("<br>")); text.append(QLatin1String("<br>"));
if (item.operation == Utils::EnvironmentItem::Unset) switch (item.operation) {
case Utils::EnvironmentItem::Unset:
text.append(tr("Unset <a href=\"%1\"><b>%1</b></a>").arg(item.name.toHtmlEscaped())); text.append(tr("Unset <a href=\"%1\"><b>%1</b></a>").arg(item.name.toHtmlEscaped()));
else break;
case Utils::EnvironmentItem::SetEnabled:
case Utils::EnvironmentItem::Append:
case Utils::EnvironmentItem::Prepend:
text.append(tr("Set <a href=\"%1\"><b>%1</b></a> to <b>%2</b>").arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped())); text.append(tr("Set <a href=\"%1\"><b>%1</b></a> to <b>%2</b>").arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped()));
break;
case Utils::EnvironmentItem::SetDisabled:
text.append(tr("Set <a href=\"%1\"><b>%1</b></a> to <b>%2</b> [disabled]").arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped()));
break;
}
} }
} }
@@ -429,13 +446,17 @@ void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &curren
d->m_editButton->setEnabled(true); d->m_editButton->setEnabled(true);
const QString &name = d->m_model->indexToVariable(current); const QString &name = d->m_model->indexToVariable(current);
bool modified = d->m_model->canReset(name) && d->m_model->changes(name); bool modified = d->m_model->canReset(name) && d->m_model->changes(name);
bool unset = d->m_model->canUnset(name); bool unset = d->m_model->isUnset(name);
d->m_resetButton->setEnabled(modified || unset); d->m_resetButton->setEnabled(modified || unset);
d->m_unsetButton->setEnabled(!unset); d->m_unsetButton->setEnabled(!unset);
d->m_toggleButton->setEnabled(!unset);
d->m_toggleButton->setText(d->m_model->isEnabled(name) ? tr("Disable") : tr("Enable"));
} else { } else {
d->m_editButton->setEnabled(false); d->m_editButton->setEnabled(false);
d->m_resetButton->setEnabled(false); d->m_resetButton->setEnabled(false);
d->m_unsetButton->setEnabled(false); d->m_unsetButton->setEnabled(false);
d->m_toggleButton->setEnabled(false);
d->m_toggleButton->setText(tr("Disable"));
} }
if (d->m_appendPathButton) { if (d->m_appendPathButton) {
d->m_appendPathButton->setEnabled(currentEntryIsPathList(current)); d->m_appendPathButton->setEnabled(currentEntryIsPathList(current));

View File

@@ -138,8 +138,10 @@ bool MakeInstallStep::init()
const MakeInstallCommand cmd = target()->makeInstallCommand(installRoot().toString()); const MakeInstallCommand cmd = target()->makeInstallCommand(installRoot().toString());
if (cmd.environment.size() > 0) { if (cmd.environment.size() > 0) {
Environment env = processParameters()->environment(); Environment env = processParameters()->environment();
for (auto it = cmd.environment.constBegin(); it != cmd.environment.constEnd(); ++it) for (auto it = cmd.environment.constBegin(); it != cmd.environment.constEnd(); ++it) {
env.set(it.key(), it.value()); if (cmd.environment.isEnabled(it))
env.set(it.key(), cmd.environment.value(it));
}
processParameters()->setEnvironment(env); processParameters()->setEnvironment(env);
} }
m_noInstallTarget = false; m_noInstallTarget = false;

View File

@@ -280,7 +280,7 @@ void tst_Environment::find()
QCOMPARE((end != it), contains); QCOMPARE((end != it), contains);
if (contains) if (contains)
QCOMPARE(it.value(), QString("bar")); QCOMPARE(env.value(it), QString("bar"));
} }