aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2019-05-07 16:51:22 +0200
committerMarco Bubke <marco.bubke@qt.io>2019-06-13 16:51:48 +0000
commit4bae5de36b530bbef06ec7cb1fbfb7453fd59dc7 (patch)
treee8631b82915aef669fd63e6b0a72a1088185fa7e
parentf636f06b458782289340a61e42e6bbc1e523f937 (diff)
Enable macro editing for the Clang indexer
Refactor much of the code from Environment* classes to NameValue* classes to share it with the preprocessor macro settings. Change-Id: Ica4ee817aa338230c422b30d91240d266248d226 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r--src/libs/utils/CMakeLists.txt5
-rw-r--r--src/libs/utils/environment.cpp369
-rw-r--r--src/libs/utils/environment.h77
-rw-r--r--src/libs/utils/environmentdialog.cpp149
-rw-r--r--src/libs/utils/environmentdialog.h30
-rw-r--r--src/libs/utils/environmentfwd.h51
-rw-r--r--src/libs/utils/environmentmodel.cpp354
-rw-r--r--src/libs/utils/environmentmodel.h44
-rw-r--r--src/libs/utils/namevaluedictionary.cpp282
-rw-r--r--src/libs/utils/namevaluedictionary.h92
-rw-r--r--src/libs/utils/namevalueitem.cpp199
-rw-r--r--src/libs/utils/namevalueitem.h80
-rw-r--r--src/libs/utils/namevaluemodel.cpp397
-rw-r--r--src/libs/utils/namevaluemodel.h83
-rw-r--r--src/libs/utils/namevaluesdialog.cpp147
-rw-r--r--src/libs/utils/namevaluesdialog.h86
-rw-r--r--src/libs/utils/namevaluevalidator.cpp72
-rw-r--r--src/libs/utils/namevaluevalidator.h58
-rw-r--r--src/libs/utils/utils-lib.pri16
-rw-r--r--src/plugins/autotest/testrunner.cpp18
-rw-r--r--src/plugins/clangcodemodel/clangcodemodelplugin.cpp5
-rw-r--r--src/plugins/clangformat/clangformatplugin.cpp4
-rw-r--r--src/plugins/clangpchmanager/CMakeLists.txt5
-rw-r--r--src/plugins/clangpchmanager/clangindexingprojectsettings.cpp96
-rw-r--r--src/plugins/clangpchmanager/clangindexingprojectsettings.h50
-rw-r--r--src/plugins/clangpchmanager/clangindexingprojectsettingswidget.cpp61
-rw-r--r--src/plugins/clangpchmanager/clangindexingprojectsettingswidget.h56
-rw-r--r--src/plugins/clangpchmanager/clangindexingprojectsettingswidget.ui32
-rw-r--r--src/plugins/clangpchmanager/clangindexingsettingsmanager.cpp55
-rw-r--r--src/plugins/clangpchmanager/clangindexingsettingsmanager.h56
-rw-r--r--src/plugins/clangpchmanager/clangpchmanager-source.pri6
-rw-r--r--src/plugins/clangpchmanager/clangpchmanager.pro7
-rw-r--r--src/plugins/clangpchmanager/clangpchmanagerplugin.cpp37
-rw-r--r--src/plugins/clangpchmanager/clangpchmanagerplugin.h2
-rw-r--r--src/plugins/clangpchmanager/pchmanagerprojectupdater.h5
-rw-r--r--src/plugins/clangpchmanager/preprocessormacrocollector.cpp68
-rw-r--r--src/plugins/clangpchmanager/preprocessormacrocollector.h51
-rw-r--r--src/plugins/clangpchmanager/preprocessormacrowidget.cpp282
-rw-r--r--src/plugins/clangpchmanager/preprocessormacrowidget.h79
-rw-r--r--src/plugins/clangpchmanager/projectupdater.cpp65
-rw-r--r--src/plugins/clangpchmanager/projectupdater.h13
-rw-r--r--src/plugins/clangpchmanager/qtcreatorprojectupdater.h6
-rw-r--r--src/plugins/clangrefactoring/clangrefactoringplugin.cpp17
-rw-r--r--src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.cpp6
-rw-r--r--src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.h10
-rw-r--r--src/plugins/clangrefactoring/refactoringprojectupdater.h5
-rw-r--r--src/plugins/coreplugin/dialogs/externaltoolconfig.cpp17
-rw-r--r--src/plugins/coreplugin/dialogs/externaltoolconfig.h8
-rw-r--r--src/plugins/coreplugin/externaltool.cpp12
-rw-r--r--src/plugins/coreplugin/externaltool.h6
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp4
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.h6
-rw-r--r--src/plugins/projectexplorer/environmentaspect.cpp2
-rw-r--r--src/plugins/projectexplorer/environmentaspect.h8
-rw-r--r--src/plugins/projectexplorer/environmentaspectwidget.cpp2
-rw-r--r--src/plugins/projectexplorer/environmentaspectwidget.h2
-rw-r--r--src/plugins/projectexplorer/environmentwidget.cpp66
-rw-r--r--src/plugins/projectexplorer/environmentwidget.h11
-rw-r--r--src/plugins/projectexplorer/extracompiler.cpp2
-rw-r--r--src/plugins/projectexplorer/kitinformation.cpp36
-rw-r--r--src/plugins/projectexplorer/kitinformation.h4
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.cpp4
-rw-r--r--src/plugins/projectexplorer/msvctoolchain.h7
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp2
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h4
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp2
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.h2
-rw-r--r--src/plugins/qnx/qnxconfiguration.cpp2
-rw-r--r--src/plugins/qnx/qnxconfiguration.h4
-rw-r--r--src/plugins/qnx/qnxqtversion.cpp2
-rw-r--r--src/plugins/qnx/qnxqtversion.h4
-rw-r--r--src/plugins/qnx/qnxtoolchain.cpp7
-rw-r--r--src/plugins/qnx/qnxutils.cpp6
-rw-r--r--src/plugins/qnx/qnxutils.h4
-rw-r--r--src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp2
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolscollector.cpp1
-rw-r--r--src/tools/sdktool/sdktool.pro4
-rw-r--r--tests/unit/mockup/projectexplorer/project.h4
-rw-r--r--tests/unit/unittest/clangindexingsettingsmanager-test.cpp83
-rw-r--r--tests/unit/unittest/pchmanagerclient-test.cpp7
-rw-r--r--tests/unit/unittest/preprocessormacrocollector-test.cpp71
-rw-r--r--tests/unit/unittest/projectupdater-test.cpp44
-rw-r--r--tests/unit/unittest/refactoringprojectupdater-test.cpp7
-rw-r--r--tests/unit/unittest/unittest.pro2
84 files changed, 2971 insertions, 1178 deletions
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index 0cbbeadfc1..127a41960f 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -87,6 +87,11 @@ add_qtc_library(Utils
mimetypes/mimeprovider.cpp mimetypes/mimeprovider_p.h
mimetypes/mimetype.cpp mimetypes/mimetype.h mimetypes/mimetype_p.h
mimetypes/mimetypeparser.cpp mimetypes/mimetypeparser_p.h
+ namevaluedictionary.cpp namevaluedictionary.h
+ namevalueitem.cpp namevalueitem.h
+ namevaluemodel.cpp namevaluemodel.h
+ namevaluesdialog.cpp namevaluesdialog.h
+ namevaluevalidator.cpp namevaluevalidator.h
navigationtreeview.cpp navigationtreeview.h
networkaccessmanager.cpp networkaccessmanager.h
newclasswidget.cpp newclasswidget.h newclasswidget.ui
diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp
index d61a75ebf7..476df9c0f9 100644
--- a/src/libs/utils/environment.cpp
+++ b/src/libs/utils/environment.cpp
@@ -39,11 +39,12 @@ Q_GLOBAL_STATIC_WITH_ARGS(Utils::Environment, staticSystemEnvironment,
Q_GLOBAL_STATIC(QVector<Utils::EnvironmentProvider>, environmentProviders)
-static QMap<QString, QString>::iterator findKey(QMap<QString, QString> &input, Utils::OsType osType,
- const QString &key)
+namespace Utils {
+
+static NameValueMap::iterator findKey(NameValueMap &input, Utils::OsType osType, const QString &key)
{
- const Qt::CaseSensitivity casing
- = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
+ : Qt::CaseSensitive;
for (auto it = input.begin(); it != input.end(); ++it) {
if (key.compare(it.key(), casing) == 0)
return it;
@@ -51,12 +52,12 @@ static QMap<QString, QString>::iterator findKey(QMap<QString, QString> &input, U
return input.end();
}
-static QMap<QString, QString>::const_iterator findKey(const QMap<QString, QString> &input,
- Utils::OsType osType,
- const QString &key)
+static NameValueMap::const_iterator findKey(const NameValueMap &input,
+ Utils::OsType osType,
+ const QString &key)
{
- const Qt::CaseSensitivity casing
- = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
+ : Qt::CaseSensitive;
for (auto it = input.constBegin(); it != input.constEnd(); ++it) {
if (key.compare(it.key(), casing) == 0)
return it;
@@ -64,198 +65,6 @@ static QMap<QString, QString>::const_iterator findKey(const QMap<QString, QStrin
return input.constEnd();
}
-namespace Utils {
-
-enum : char
-{
-#ifdef Q_OS_WIN
- pathSepC = ';'
-#else
- pathSepC = ':'
-#endif
-};
-
-void EnvironmentItem::sort(QList<EnvironmentItem> *list)
-{
- Utils::sort(*list, &EnvironmentItem::name);
-}
-
-QList<EnvironmentItem> EnvironmentItem::fromStringList(const QStringList &list)
-{
- QList<EnvironmentItem> result;
- for (const QString &string : list) {
- int pos = string.indexOf('=', 1);
- if (pos == -1)
- result.append(EnvironmentItem(string, QString(), EnvironmentItem::Unset));
- else
- result.append(EnvironmentItem(string.left(pos), string.mid(pos + 1)));
- }
- return result;
-}
-
-QStringList EnvironmentItem::toStringList(const QList<EnvironmentItem> &list)
-{
- return Utils::transform(list, [](const EnvironmentItem &item) {
- if (item.operation == EnvironmentItem::Unset)
- return QString(item.name);
- return QString(item.name + '=' + item.value);
- });
-}
-
-QList<EnvironmentItem> EnvironmentItem::itemsFromVariantList(const QVariantList &list)
-{
- return Utils::transform(list, [](const QVariant &item) {
- return itemFromVariantList(item.toList());
- });
-}
-
-QVariantList EnvironmentItem::toVariantList(const QList<EnvironmentItem> &list)
-{
- return Utils::transform(list, [](const EnvironmentItem &item) {
- return QVariant(toVariantList(item));
- });
-}
-
-EnvironmentItem EnvironmentItem::itemFromVariantList(const QVariantList &list)
-{
- QTC_ASSERT(list.size() == 3, return EnvironmentItem("", ""));
- QString name = list.value(0).toString();
- Operation operation = Operation(list.value(1).toInt());
- QString value = list.value(2).toString();
- return EnvironmentItem(name, value, operation);
-}
-
-QVariantList EnvironmentItem::toVariantList(const EnvironmentItem &item)
-{
- return QVariantList() << item.name << item.operation << item.value;
-}
-
-static QString expand(const Environment *e, QString value)
-{
- int replaceCount = 0;
- for (int i = 0; i < value.size(); ++i) {
- if (value.at(i) == '$') {
- if ((i + 1) < value.size()) {
- const QChar &c = value.at(i+1);
- int end = -1;
- if (c == '(')
- end = value.indexOf(')', i);
- else if (c == '{')
- end = value.indexOf('}', i);
- if (end != -1) {
- const QString &name = value.mid(i + 2, end - i - 2);
- Environment::const_iterator it = e->constFind(name);
- if (it != e->constEnd())
- value.replace(i, end - i + 1, it.value());
- ++replaceCount;
- QTC_ASSERT(replaceCount < 100, break);
- }
- }
- }
- }
- return value;
-}
-
-QDebug operator<<(QDebug debug, const EnvironmentItem &i)
-{
- QDebugStateSaver saver(debug);
- debug.noquote();
- debug.nospace();
- debug << "EnvironmentItem(";
- switch (i.operation) {
- case EnvironmentItem::Set:
- debug << "set \"" << i.name << "\" to \"" << i.value << '"';
- break;
- case EnvironmentItem::Unset:
- debug << "unset \"" << i.name << '"';
- break;
- case EnvironmentItem::Prepend:
- debug << "prepend to \"" << i.name << "\":\"" << i.value << '"';
- break;
- case EnvironmentItem::Append:
- debug << "append to \"" << i.name << "\":\"" << i.value << '"';
- break;
- }
- debug << ')';
- return debug;
-}
-
-void EnvironmentItem::apply(Environment *e, Operation op) const
-{
- switch (op) {
- case Set:
- e->set(name, expand(e, value));
- break;
- case Unset:
- e->unset(name);
- break;
- case Prepend: {
- const Environment::const_iterator it = e->constFind(name);
- if (it != e->constEnd()) {
- QString v = it.value();
- const QChar pathSep{QLatin1Char(pathSepC)};
- int sepCount = 0;
- if (v.startsWith(pathSep))
- ++sepCount;
- if (value.endsWith(pathSep))
- ++sepCount;
- if (sepCount == 2)
- v.remove(0, 1);
- else if (sepCount == 0)
- v.prepend(pathSep);
- v.prepend(expand(e, value));
- e->set(name, v);
- } else {
- apply(e, Set);
- }
- }
- break;
- case Append: {
- const Environment::const_iterator it = e->constFind(name);
- if (it != e->constEnd()) {
- QString v = it.value();
- const QChar pathSep{QLatin1Char(pathSepC)};
- int sepCount = 0;
- if (v.endsWith(pathSep))
- ++sepCount;
- if (value.startsWith(pathSep))
- ++sepCount;
- if (sepCount == 2)
- v.chop(1);
- else if (sepCount == 0)
- v.append(pathSep);
- v.append(expand(e, value));
- e->set(name, v);
- } else {
- apply(e, Set);
- }
- }
- break;
- }
-}
-
-Environment::Environment(const QStringList &env, OsType osType) : m_osType(osType)
-{
- for (const QString &s : env) {
- int i = s.indexOf('=', 1);
- if (i >= 0) {
- const QString key = s.left(i);
- if (!key.contains('=')) {
- const QString value = s.mid(i + 1);
- set(key, value);
- }
- }
- }
-}
-
-QStringList Environment::toStringList() const
-{
- QStringList result;
- for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it)
- result.append(it.key() + '=' + it.value());
- return result;
-}
-
QProcessEnvironment Environment::toProcessEnvironment() const
{
QProcessEnvironment result;
@@ -264,27 +73,21 @@ QProcessEnvironment Environment::toProcessEnvironment() const
return result;
}
-void Environment::set(const QString &key, const QString &value)
+void Environment::appendOrSetPath(const QString &value)
{
- QTC_ASSERT(!key.contains('='), return);
- auto it = findKey(m_values, m_osType, key);
- if (it == m_values.end())
- m_values.insert(key, value);
- else
- it.value() = value;
+ appendOrSet("PATH", QDir::toNativeSeparators(value),
+ QString(OsSpecificAspects::pathListSeparator(m_osType)));
}
-void Environment::unset(const QString &key)
+void Environment::prependOrSetPath(const QString &value)
{
- QTC_ASSERT(!key.contains('='), return);
- auto it = findKey(m_values, m_osType, key);
- if (it != m_values.end())
- m_values.erase(it);
+ prependOrSet("PATH", QDir::toNativeSeparators(value),
+ QString(OsSpecificAspects::pathListSeparator(m_osType)));
}
void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
{
- QTC_ASSERT(!key.contains('='), return);
+ QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
@@ -296,9 +99,9 @@ void Environment::appendOrSet(const QString &key, const QString &value, const QS
}
}
-void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
+void Environment::prependOrSet(const QString &key, const QString &value, const QString &sep)
{
- QTC_ASSERT(!key.contains('='), return);
+ QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
@@ -310,18 +113,6 @@ void Environment::prependOrSet(const QString&key, const QString &value, const QS
}
}
-void Environment::appendOrSetPath(const QString &value)
-{
- appendOrSet("PATH", QDir::toNativeSeparators(value),
- QString(OsSpecificAspects::pathListSeparator(m_osType)));
-}
-
-void Environment::prependOrSetPath(const QString &value)
-{
- prependOrSet("PATH", QDir::toNativeSeparators(value),
- QString(OsSpecificAspects::pathListSeparator(m_osType)));
-}
-
void Environment::prependOrSetLibrarySearchPath(const QString &value)
{
switch (m_osType) {
@@ -387,11 +178,6 @@ void Environment::setupEnglishOutput(QStringList *environment)
*environment = env.toStringList();
}
-void Environment::clear()
-{
- m_values.clear();
-}
-
FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory,
QSet<FilePath> &alreadyChecked) const
{
@@ -494,122 +280,7 @@ FilePathList Environment::path() const
return Utils::transform(pathComponents, &FilePath::fromUserInput);
}
-QString Environment::value(const QString &key) const
-{
- const auto it = findKey(m_values, m_osType, key);
- return it != m_values.end() ? it.value() : QString();
-}
-
-QString Environment::key(Environment::const_iterator it) const
-{
- return it.key();
-}
-
-QString Environment::value(Environment::const_iterator it) const
-{
- return it.value();
-}
-
-Environment::const_iterator Environment::constBegin() const
-{
- return m_values.constBegin();
-}
-
-Environment::const_iterator Environment::constEnd() const
-{
- return m_values.constEnd();
-}
-
-Environment::const_iterator Environment::constFind(const QString &name) const
-{
- return findKey(m_values, m_osType, name);
-}
-
-int Environment::size() const
-{
- return m_values.size();
-}
-
-void Environment::modify(const QList<EnvironmentItem> & list)
-{
- Environment resultEnvironment = *this;
- for (const EnvironmentItem &item : list)
- item.apply(&resultEnvironment);
- *this = resultEnvironment;
-}
-
-QList<EnvironmentItem> Environment::diff(const Environment &other, bool checkAppendPrepend) const
-{
- QMap<QString, QString>::const_iterator thisIt = constBegin();
- QMap<QString, QString>::const_iterator otherIt = other.constBegin();
-
- QList<EnvironmentItem> result;
- while (thisIt != constEnd() || otherIt != other.constEnd()) {
- if (thisIt == constEnd()) {
- result.append(EnvironmentItem(otherIt.key(), otherIt.value()));
- ++otherIt;
- } else if (otherIt == other.constEnd()) {
- result.append(EnvironmentItem(thisIt.key(), QString(), EnvironmentItem::Unset));
- ++thisIt;
- } else if (thisIt.key() < otherIt.key()) {
- result.append(EnvironmentItem(thisIt.key(), QString(), EnvironmentItem::Unset));
- ++thisIt;
- } else if (thisIt.key() > otherIt.key()) {
- result.append(EnvironmentItem(otherIt.key(), otherIt.value()));
- ++otherIt;
- } else {
- const QString &oldValue = thisIt.value();
- const QString &newValue = otherIt.value();
- if (oldValue != newValue) {
- if (checkAppendPrepend && newValue.startsWith(oldValue)) {
- QString appended = newValue.right(newValue.size() - oldValue.size());
- if (appended.startsWith(QLatin1Char(pathSepC)))
- appended.remove(0, 1);
- result.append(EnvironmentItem(otherIt.key(), appended,
- EnvironmentItem::Append));
- } else if (checkAppendPrepend && newValue.endsWith(oldValue)) {
- QString prepended = newValue.left(newValue.size() - oldValue.size());
- if (prepended.endsWith(QLatin1Char(pathSepC)))
- prepended.chop(1);
- result.append(EnvironmentItem(otherIt.key(), prepended,
- EnvironmentItem::Prepend));
- } else {
- result.append(EnvironmentItem(otherIt.key(), newValue));
- }
- }
- ++otherIt;
- ++thisIt;
- }
- }
- return result;
-}
-
-bool Environment::hasKey(const QString &key) const
-{
- return m_values.contains(key);
-}
-
-OsType Environment::osType() const
-{
- return m_osType;
-}
-
-QString Environment::userName() const
-{
- return value(QString::fromLatin1(m_osType == OsTypeWindows ? "USERNAME" : "USER"));
-}
-
-bool Environment::operator!=(const Environment &other) const
-{
- return !(*this == other);
-}
-
-bool Environment::operator==(const Environment &other) const
-{
- return m_osType == other.m_osType && m_values == other.m_values;
-}
-
-void Environment::modifySystemEnvironment(const QList<EnvironmentItem> &list)
+void Environment::modifySystemEnvironment(const EnvironmentItems &list)
{
staticSystemEnvironment->modify(list);
}
diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h
index f1e957ab6d..10ad75165e 100644
--- a/src/libs/utils/environment.h
+++ b/src/libs/utils/environment.h
@@ -27,8 +27,9 @@
#include "fileutils.h"
#include "hostosinfo.h"
+#include "namevaluedictionary.h"
+#include "namevalueitem.h"
#include "optional.h"
-#include "utils_global.h"
#include <QMap>
#include <QStringList>
@@ -39,71 +40,18 @@ QT_FORWARD_DECLARE_CLASS(QDebug)
QT_FORWARD_DECLARE_CLASS(QProcessEnvironment)
namespace Utils {
-class Environment;
-class QTCREATOR_UTILS_EXPORT EnvironmentItem
+class QTCREATOR_UTILS_EXPORT Environment final : public NameValueDictionary
{
public:
- enum Operation { Set, Unset, Prepend, Append };
+ using NameValueDictionary::NameValueDictionary;
- EnvironmentItem(const QString &n, const QString &v, Operation op = Set)
- : name(n), value(v), operation(op)
- {}
-
- void apply(Environment *e) const { apply(e, operation); }
-
- QString name;
- QString value;
- Operation operation;
-
- bool operator==(const EnvironmentItem &other) const
- {
- return operation == other.operation && name == other.name && value == other.value;
- }
-
- bool operator!=(const EnvironmentItem &other) const
- {
- return !(*this == other);
- }
-
- static void sort(QList<EnvironmentItem> *list);
- static QList<EnvironmentItem> fromStringList(const QStringList &list);
- static QStringList toStringList(const QList<EnvironmentItem> &list);
- static QList<EnvironmentItem> itemsFromVariantList(const QVariantList &list);
- static QVariantList toVariantList(const QList<EnvironmentItem> &list);
- static EnvironmentItem itemFromVariantList(const QVariantList &list);
- static QVariantList toVariantList(const EnvironmentItem &item);
-
-private:
- void apply(Environment *e, Operation op) const;
-};
-
-QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const EnvironmentItem &i);
-
-class QTCREATOR_UTILS_EXPORT Environment
-{
-public:
- using const_iterator = QMap<QString, QString>::const_iterator;
-
- explicit Environment(OsType osType = HostOsInfo::hostOs()) : m_osType(osType) {}
- explicit Environment(const QStringList &env, OsType osType = HostOsInfo::hostOs());
static Environment systemEnvironment();
static void setupEnglishOutput(Environment *environment);
static void setupEnglishOutput(QProcessEnvironment *environment);
static void setupEnglishOutput(QStringList *environment);
- QStringList toStringList() const;
QProcessEnvironment toProcessEnvironment() const;
- QString value(const QString &key) const;
- void set(const QString &key, const QString &value);
- void unset(const QString &key);
- void modify(const QList<EnvironmentItem> &list);
- /// Return the Environment changes necessary to modify this into the other environment.
- QList<EnvironmentItem> diff(const Environment &other, bool checkAppendPrepend = false) const;
- bool hasKey(const QString &key) const;
- OsType osType() const;
-
- QString userName() const;
void appendOrSet(const QString &key, const QString &value, const QString &sep = QString());
void prependOrSet(const QString &key, const QString &value, const QString &sep = QString());
@@ -114,16 +62,6 @@ public:
void prependOrSetLibrarySearchPath(const QString &value);
void prependOrSetLibrarySearchPaths(const QStringList &values);
- void clear();
- int size() const;
-
- QString key(Environment::const_iterator it) const;
- QString value(Environment::const_iterator it) const;
-
- Environment::const_iterator constBegin() const;
- Environment::const_iterator constEnd() const;
- Environment::const_iterator constFind(const QString &name) const;
-
using PathFilter = std::function<bool(const FilePath &)>;
FilePath searchInPath(const QString &executable,
const FilePathList &additionalDirs = FilePathList(),
@@ -138,16 +76,11 @@ public:
FilePath expandVariables(const FilePath &input) const;
QStringList expandVariables(const QStringList &input) const;
- bool operator!=(const Environment &other) const;
- bool operator==(const Environment &other) const;
-
- static void modifySystemEnvironment(const QList<EnvironmentItem> &list); // use with care!!!
+ static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!!
private:
FilePath searchInDirectory(const QStringList &execs, const FilePath &directory,
QSet<FilePath> &alreadyChecked) const;
- QMap<QString, QString> m_values;
- OsType m_osType;
};
class QTCREATOR_UTILS_EXPORT EnvironmentProvider
diff --git a/src/libs/utils/environmentdialog.cpp b/src/libs/utils/environmentdialog.cpp
index 07e6155c7d..e9c9fd620f 100644
--- a/src/libs/utils/environmentdialog.cpp
+++ b/src/libs/utils/environmentdialog.cpp
@@ -35,144 +35,19 @@
namespace Utils {
-namespace Internal {
-
-static QList<EnvironmentItem> cleanUp(
- const QList<EnvironmentItem> &items)
-{
- QList<EnvironmentItem> uniqueItems;
- QSet<QString> uniqueSet;
- for (int i = items.count() - 1; i >= 0; i--) {
- EnvironmentItem item = items.at(i);
- if (HostOsInfo::isWindowsHost())
- item.name = item.name.toUpper();
- const QString &itemName = item.name;
- QString emptyName = itemName;
- emptyName.remove(QLatin1Char(' '));
- if (!emptyName.isEmpty() && !uniqueSet.contains(itemName)) {
- uniqueItems.prepend(item);
- uniqueSet.insert(itemName);
- }
- }
- return uniqueItems;
-}
-
-class EnvironmentItemsWidget : public QWidget
-{
- Q_OBJECT
-public:
- explicit EnvironmentItemsWidget(QWidget *parent = nullptr);
-
- void setEnvironmentItems(const QList<EnvironmentItem> &items);
- QList<EnvironmentItem> environmentItems() const;
-
- void setPlaceholderText(const QString &text);
-
-private:
- QPlainTextEdit *m_editor;
-};
-
-EnvironmentItemsWidget::EnvironmentItemsWidget(QWidget *parent) :
- QWidget(parent)
-{
- m_editor = new QPlainTextEdit(this);
- auto layout = new QVBoxLayout(this);
- layout->setMargin(0);
- layout->addWidget(m_editor);
-}
-
-void EnvironmentItemsWidget::setEnvironmentItems(const QList<EnvironmentItem> &items)
-{
- QList<EnvironmentItem> sortedItems = items;
- EnvironmentItem::sort(&sortedItems);
- const QStringList list = EnvironmentItem::toStringList(sortedItems);
- m_editor->document()->setPlainText(list.join(QLatin1Char('\n')));
-}
-
-QList<EnvironmentItem> EnvironmentItemsWidget::environmentItems() const
-{
- const QStringList list = m_editor->document()->toPlainText().split(QLatin1String("\n"));
- QList<EnvironmentItem> items = EnvironmentItem::fromStringList(list);
- return cleanUp(items);
-}
-
-void EnvironmentItemsWidget::setPlaceholderText(const QString &text)
-{
- m_editor->setPlaceholderText(text);
-}
-
-class EnvironmentDialogPrivate
-{
-public:
- EnvironmentItemsWidget *m_editor;
-};
-
-} // namespace Internal
-
-EnvironmentDialog::EnvironmentDialog(QWidget *parent) :
- QDialog(parent), d(new Internal::EnvironmentDialogPrivate)
-{
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- resize(640, 480);
- d->m_editor = new Internal::EnvironmentItemsWidget(this);
- auto box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
- connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
-
- auto helpLabel = new QLabel(this);
- helpLabel->setText(tr("Enter one environment variable per line.\n"
- "To set or change a variable, use VARIABLE=VALUE.\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."));
-
- auto layout = new QVBoxLayout(this);
- layout->addWidget(d->m_editor);
- layout->addWidget(helpLabel);
-
- layout->addWidget(box);
-
- setWindowTitle(tr("Edit Environment"));
-}
-
-EnvironmentDialog::~EnvironmentDialog()
-{
- delete d;
-}
-
-void EnvironmentDialog::setEnvironmentItems(const QList<EnvironmentItem> &items)
-{
- d->m_editor->setEnvironmentItems(items);
-}
-
-QList<EnvironmentItem> EnvironmentDialog::environmentItems() const
+Utils::optional<EnvironmentItems> EnvironmentDialog::getEnvironmentItems(
+ QWidget *parent, const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher)
{
- return d->m_editor->environmentItems();
-}
-
-void EnvironmentDialog::setPlaceholderText(const QString &text)
-{
- d->m_editor->setPlaceholderText(text);
-}
-
-QList<EnvironmentItem> EnvironmentDialog::getEnvironmentItems(bool *ok,
- QWidget *parent,
- const QList<EnvironmentItem> &initial,
- const QString &placeholderText,
- Polisher polisher)
-{
- EnvironmentDialog dlg(parent);
- if (polisher)
- polisher(&dlg);
- dlg.setEnvironmentItems(initial);
- dlg.setPlaceholderText(placeholderText);
- bool result = dlg.exec() == QDialog::Accepted;
- if (ok)
- *ok = result;
- if (result)
- return dlg.environmentItems();
- return QList<EnvironmentItem>();
+ return getNameValueItems(
+ parent,
+ initial,
+ placeholderText,
+ polisher,
+ tr("Edit Environment"),
+ tr("Enter one environment variable per line.\n"
+ "To set or change a variable, use VARIABLE=VALUE.\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."));
}
} // namespace Utils
-
-#include "environmentdialog.moc"
diff --git a/src/libs/utils/environmentdialog.h b/src/libs/utils/environmentdialog.h
index be8218508b..6dbb38e191 100644
--- a/src/libs/utils/environmentdialog.h
+++ b/src/libs/utils/environmentdialog.h
@@ -25,36 +25,20 @@
#pragma once
-#include "utils_global.h"
#include "environment.h"
-
-#include <QDialog>
+#include "namevaluesdialog.h"
+#include <thread>
namespace Utils {
-namespace Internal { class EnvironmentDialogPrivate; }
-
-class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public QDialog
+class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public NameValuesDialog
{
Q_OBJECT
public:
- explicit EnvironmentDialog(QWidget *parent = nullptr);
- ~EnvironmentDialog() override;
-
- void setEnvironmentItems(const QList<EnvironmentItem> &items);
- QList<EnvironmentItem> environmentItems() const;
-
- void setPlaceholderText(const QString &text);
-
- using Polisher = std::function<void(QWidget*)>;
- static QList<EnvironmentItem> getEnvironmentItems(bool *ok,
- QWidget *parent = nullptr,
- const QList<EnvironmentItem> &initial = QList<EnvironmentItem>(),
- const QString &placeholderText = QString(),
- Polisher polish = Polisher());
-
-private:
- Internal::EnvironmentDialogPrivate *d;
+ static Utils::optional<EnvironmentItems> getEnvironmentItems(QWidget *parent = nullptr,
+ const EnvironmentItems &initial = {},
+ const QString &placeholderText = {},
+ Polisher polish = {});
};
} // namespace Utils
diff --git a/src/libs/utils/environmentfwd.h b/src/libs/utils/environmentfwd.h
new file mode 100644
index 0000000000..04a57418b5
--- /dev/null
+++ b/src/libs/utils/environmentfwd.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGlobal>
+
+QT_BEGIN_NAMESPACE
+template<typename Type>
+class QList;
+class QTreeView;
+QT_END_NAMESPACE
+
+namespace Utils {
+class NameValueDictionary;
+class NameValueItem;
+using NameValueItems = QVector<NameValueItem>;
+
+class Environment;
+using EnvironmentItem = NameValueItem;
+using EnvironmentItems = NameValueItems;
+
+class PreprocessorMacroDictionary;
+using PreprocessorMacroItem = NameValueItem;
+using PreprocessorMacroItems = NameValueItems;
+
+class NameValueModel;
+class EnvironmentModel;
+} // namespace Utils
diff --git a/src/libs/utils/environmentmodel.cpp b/src/libs/utils/environmentmodel.cpp
index 045a6d2b65..c7efcce930 100644
--- a/src/libs/utils/environmentmodel.cpp
+++ b/src/libs/utils/environmentmodel.cpp
@@ -33,360 +33,12 @@
#include <QFont>
namespace Utils {
-namespace Internal {
-
-class EnvironmentModelPrivate
-{
-public:
- void updateResultEnvironment()
- {
- m_resultEnvironment = m_baseEnvironment;
- m_resultEnvironment.modify(m_items);
- // Add removed variables again and mark them as "<UNSET>" so
- // that the user can actually see those removals:
- foreach (const EnvironmentItem &item, m_items) {
- if (item.operation == EnvironmentItem::Unset)
- m_resultEnvironment.set(item.name, EnvironmentModel::tr("<UNSET>"));
- }
- }
-
- int findInChanges(const QString &name) const
- {
- for (int i=0; i<m_items.size(); ++i)
- if (m_items.at(i).name == name)
- return i;
- return -1;
- }
-
- int findInResultInsertPosition(const QString &name) const
- {
- Environment::const_iterator it;
- int i = 0;
- for (it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
- if (m_resultEnvironment.key(it) > name)
- return i;
- return m_resultEnvironment.size();
- }
-
- int findInResult(const QString &name) const
- {
- Environment::const_iterator it;
- int i = 0;
- for (it = m_resultEnvironment.constBegin(); it != m_resultEnvironment.constEnd(); ++it, ++i)
- if (m_resultEnvironment.key(it) == name)
- return i;
- return -1;
- }
-
- Environment m_baseEnvironment;
- Environment m_resultEnvironment;
- QList<EnvironmentItem> m_items;
-};
-
-} // namespace Internal
-
-EnvironmentModel::EnvironmentModel(QObject *parent) :
- QAbstractTableModel(parent),
- d(new Internal::EnvironmentModelPrivate)
-{ }
-
-EnvironmentModel::~EnvironmentModel()
-{
- delete d;
-}
-
-QString EnvironmentModel::indexToVariable(const QModelIndex &index) const
+const Environment &EnvironmentModel::baseEnvironment() const
{
- return d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row());
+ return static_cast<const Environment &>(baseNameValueDictionary());
}
-
void EnvironmentModel::setBaseEnvironment(const Environment &env)
{
- if (d->m_baseEnvironment == env)
- return;
- beginResetModel();
- d->m_baseEnvironment = env;
- d->updateResultEnvironment();
- endResetModel();
-}
-
-int EnvironmentModel::rowCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return d->m_resultEnvironment.size();
-}
-int EnvironmentModel::columnCount(const QModelIndex &parent) const
-{
- if (parent.isValid())
- return 0;
-
- return 2;
-}
-
-bool EnvironmentModel::changes(const QString &name) const
-{
- return d->findInChanges(name) >= 0;
-}
-
-Environment EnvironmentModel::baseEnvironment() const
-{
- return d->m_baseEnvironment;
-}
-
-QVariant EnvironmentModel::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
- if (index.column() == 0) {
- return d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row());
- } else if (index.column() == 1) {
- // Do not return "<UNSET>" when editing a previously unset variable:
- if (role == Qt::EditRole) {
- int pos = d->findInChanges(indexToVariable(index));
- if (pos >= 0)
- return d->m_items.at(pos).value;
- }
- QString value = d->m_resultEnvironment.value(d->m_resultEnvironment.constBegin() + index.row());
- if (role == Qt::ToolTipRole && value.length() > 80) {
- // Use html to enable text wrapping
- value = value.toHtmlEscaped();
- value.prepend(QLatin1String("<html><body>"));
- value.append(QLatin1String("</body></html>"));
- }
- return value;
- }
- }
- if (role == Qt::FontRole) {
- // check whether this environment variable exists in d->m_items
- if (changes(d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row()))) {
- QFont f;
- f.setBold(true);
- return QVariant(f);
- }
- return QFont();
- }
- return QVariant();
-}
-
-Qt::ItemFlags EnvironmentModel::flags(const QModelIndex &index) const
-{
- Q_UNUSED(index)
- return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
-}
-
-QVariant EnvironmentModel::headerData(int section, Qt::Orientation orientation, int role) const
-{
- if (orientation == Qt::Vertical || role != Qt::DisplayRole)
- return QVariant();
- return section == 0 ? tr("Variable") : tr("Value");
+ setBaseNameValueDictionary(env);
}
-
-/// *****************
-/// Utility functions
-/// *****************
-QModelIndex EnvironmentModel::variableToIndex(const QString &name) const
-{
- int row = d->findInResult(name);
- if (row == -1)
- return QModelIndex();
- return index(row, 0);
-}
-
-bool EnvironmentModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (!index.isValid() || role != Qt::EditRole)
- return false;
-
- // ignore changes to already set values:
- if (data(index, role) == value)
- return true;
-
- const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString();
- const QString oldValue = data(this->index(index.row(), 1, QModelIndex()), Qt::EditRole).toString();
- int changesPos = d->findInChanges(oldName);
-
- if (index.column() == 0) {
- //fail if a variable with the same name already exists
- const QString &newName = HostOsInfo::isWindowsHost()
- ? value.toString().toUpper() : value.toString();
- if (newName.isEmpty() || newName.contains('='))
- return false;
- // Does the new name exist already?
- if (d->m_resultEnvironment.hasKey(newName) || newName.isEmpty())
- return false;
-
- EnvironmentItem newVariable(newName, oldValue);
-
- if (changesPos != -1)
- resetVariable(oldName); // restore the original base variable again
-
- QModelIndex newIndex = addVariable(newVariable); // add the new variable
- emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value
- return true;
- } else if (index.column() == 1) {
- // We are changing an existing value:
- const QString stringValue = value.toString();
- if (changesPos != -1) {
- // We have already changed this value
- if (d->m_baseEnvironment.hasKey(oldName) && stringValue == d->m_baseEnvironment.value(oldName)) {
- // ... and now went back to the base value
- d->m_items.removeAt(changesPos);
- } else {
- // ... and changed it again
- d->m_items[changesPos].value = stringValue;
- d->m_items[changesPos].operation = EnvironmentItem::Set;
- }
- } else {
- // Add a new change item:
- d->m_items.append(EnvironmentItem(oldName, stringValue));
- }
- d->updateResultEnvironment();
- emit dataChanged(index, index);
- emit userChangesChanged();
- return true;
- }
- return false;
-}
-
-QModelIndex EnvironmentModel::addVariable()
-{
- //: Name when inserting a new variable
- return addVariable(EnvironmentItem(tr("<VARIABLE>"),
- //: Value when inserting a new variable
- tr("<VALUE>")));
-}
-
-QModelIndex EnvironmentModel::addVariable(const EnvironmentItem &item)
-{
-
- // Return existing index if the name is already in the result set:
- int pos = d->findInResult(item.name);
- if (pos >= 0 && pos < d->m_resultEnvironment.size())
- return index(pos, 0, QModelIndex());
-
- int insertPos = d->findInResultInsertPosition(item.name);
- int changePos = d->findInChanges(item.name);
- if (d->m_baseEnvironment.hasKey(item.name)) {
- // We previously unset this!
- Q_ASSERT(changePos >= 0);
- // Do not insert a line here as we listed the variable as <UNSET> before!
- Q_ASSERT(d->m_items.at(changePos).name == item.name);
- Q_ASSERT(d->m_items.at(changePos).operation == EnvironmentItem::Unset);
- Q_ASSERT(d->m_items.at(changePos).value.isEmpty());
- d->m_items[changePos] = item;
- emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex()));
- } else {
- // We add something that is not in the base environment
- // Insert a new line!
- beginInsertRows(QModelIndex(), insertPos, insertPos);
- Q_ASSERT(changePos < 0);
- d->m_items.append(item);
- d->updateResultEnvironment();
- endInsertRows();
- }
- emit userChangesChanged();
- return index(insertPos, 0, QModelIndex());
-}
-
-void EnvironmentModel::resetVariable(const QString &name)
-{
- int rowInChanges = d->findInChanges(name);
- if (rowInChanges < 0)
- return;
-
- int rowInResult = d->findInResult(name);
- if (rowInResult < 0)
- return;
-
- if (d->m_baseEnvironment.hasKey(name)) {
- d->m_items.removeAt(rowInChanges);
- d->updateResultEnvironment();
- emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex()));
- emit userChangesChanged();
- } else {
- // Remove the line completely!
- beginRemoveRows(QModelIndex(), rowInResult, rowInResult);
- d->m_items.removeAt(rowInChanges);
- d->updateResultEnvironment();
- endRemoveRows();
- emit userChangesChanged();
- }
-}
-
-void EnvironmentModel::unsetVariable(const QString &name)
-{
- // This does not change the number of rows as we will display a <UNSET>
- // in place of the original variable!
- int row = d->findInResult(name);
- if (row < 0)
- return;
-
- // look in d->m_items for the variable
- int pos = d->findInChanges(name);
- if (pos != -1) {
- d->m_items[pos].operation = EnvironmentItem::Unset;
- d->m_items[pos].value.clear();
- d->updateResultEnvironment();
- emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
- emit userChangesChanged();
- return;
- }
- d->m_items.append(EnvironmentItem(name, QString(), EnvironmentItem::Unset));
- d->updateResultEnvironment();
- emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
- emit userChangesChanged();
-}
-
-bool EnvironmentModel::canUnset(const QString &name)
-{
- int pos = d->findInChanges(name);
- if (pos != -1)
- return d->m_items.at(pos).operation == EnvironmentItem::Unset;
- else
- return false;
-}
-
-bool EnvironmentModel::canReset(const QString &name)
-{
- return d->m_baseEnvironment.hasKey(name);
-}
-
-QList<EnvironmentItem> EnvironmentModel::userChanges() const
-{
- return d->m_items;
-}
-
-void EnvironmentModel::setUserChanges(const QList<EnvironmentItem> &list)
-{
- QList<EnvironmentItem> filtered = Utils::filtered(list, [](const EnvironmentItem &i) {
- return i.name != "export " && !i.name.contains('=');
- });
- // We assume nobody is reordering the items here.
- if (filtered == d->m_items)
- return;
- beginResetModel();
- d->m_items = filtered;
- for (EnvironmentItem &item : d->m_items) {
- QString &name = item.name;
- name = name.trimmed();
- if (name.startsWith("export "))
- name = name.mid(7).trimmed();
- if (d->m_baseEnvironment.osType() == OsTypeWindows) {
- // Environment variable names are case-insensitive under windows, but we still
- // want to preserve the case of pre-existing variables.
- auto it = d->m_baseEnvironment.constFind(name);
- if (it != d->m_baseEnvironment.constEnd())
- name = d->m_baseEnvironment.key(it);
- }
- }
-
- d->updateResultEnvironment();
- endResetModel();
- emit userChangesChanged();
-}
-
} // namespace Utils
diff --git a/src/libs/utils/environmentmodel.h b/src/libs/utils/environmentmodel.h
index db20224651..ac5f017448 100644
--- a/src/libs/utils/environmentmodel.h
+++ b/src/libs/utils/environmentmodel.h
@@ -25,55 +25,17 @@
#pragma once
-#include "utils_global.h"
-
-#include <QAbstractTableModel>
+#include "namevaluemodel.h"
namespace Utils {
-class Environment;
-class EnvironmentItem;
-
-namespace Internal { class EnvironmentModelPrivate; }
-class QTCREATOR_UTILS_EXPORT EnvironmentModel : public QAbstractTableModel
+class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel
{
Q_OBJECT
public:
- explicit EnvironmentModel(QObject *parent = nullptr);
- ~EnvironmentModel() override;
-
- int rowCount(const QModelIndex &parent) const override;
- int columnCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
- Qt::ItemFlags flags(const QModelIndex &index) const override;
- QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole) const override;
-
- QModelIndex addVariable();
- QModelIndex addVariable(const EnvironmentItem &item);
- void resetVariable(const QString &name);
- void unsetVariable(const QString &name);
- bool canUnset(const QString &name);
- bool canReset(const QString &name);
- QString indexToVariable(const QModelIndex &index) const;
- QModelIndex variableToIndex(const QString &name) const;
- bool changes(const QString &key) const;
- Environment baseEnvironment() const;
+ const Environment &baseEnvironment() const;
void setBaseEnvironment(const Environment &env);
- QList<EnvironmentItem> userChanges() const;
- void setUserChanges(const QList<EnvironmentItem> &list);
-
-signals:
- void userChangesChanged();
- /// Hint to the view where it should make sense to focus on next
- // This is a hack since there is no way for a model to suggest
- // the next interesting place to focus on to the view.
- void focusIndex(const QModelIndex &index);
-
-private:
- Internal::EnvironmentModelPrivate *d;
};
} // namespace Utils
diff --git a/src/libs/utils/namevaluedictionary.cpp b/src/libs/utils/namevaluedictionary.cpp
new file mode 100644
index 0000000000..30e3c18448
--- /dev/null
+++ b/src/libs/utils/namevaluedictionary.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "algorithm.h"
+#include "namevaluedictionary.h"
+#include "qtcassert.h"
+
+#include <QDir>
+
+namespace Utils {
+
+namespace {
+NameValueMap::iterator findKey(NameValueMap &input, Utils::OsType osType, const QString &key)
+{
+ const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
+ : Qt::CaseSensitive;
+ for (auto it = input.begin(); it != input.end(); ++it) {
+ if (key.compare(it.key(), casing) == 0)
+ return it;
+ }
+ return input.end();
+}
+
+NameValueMap::const_iterator findKey(const NameValueMap &input, Utils::OsType osType, const QString &key)
+{
+ const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
+ : Qt::CaseSensitive;
+ for (auto it = input.constBegin(); it != input.constEnd(); ++it) {
+ if (key.compare(it.key(), casing) == 0)
+ return it;
+ }
+ return input.constEnd();
+}
+} // namespace
+
+NameValueDictionary::NameValueDictionary(const QStringList &env, OsType osType)
+ : m_osType(osType)
+{
+ for (const QString &s : env) {
+ int i = s.indexOf('=', 1);
+ if (i >= 0) {
+ const QString key = s.left(i);
+ if (!key.contains('=')) {
+ const QString value = s.mid(i + 1);
+ set(key, value);
+ }
+ }
+ }
+}
+
+NameValueDictionary::NameValueDictionary(const NameValuePairs &nameValues)
+{
+ for (const auto &nameValue : nameValues)
+ set(nameValue.first, nameValue.second);
+}
+
+QStringList NameValueDictionary::toStringList() const
+{
+ QStringList result;
+ for (auto it = m_values.constBegin(); it != m_values.constEnd(); ++it)
+ result.append(it.key() + '=' + it.value());
+ return result;
+}
+
+void NameValueDictionary::set(const QString &key, const QString &value)
+{
+ QTC_ASSERT(!key.contains('='), return );
+ auto it = findKey(m_values, m_osType, key);
+ if (it == m_values.end())
+ m_values.insert(key, value);
+ else
+ it.value() = value;
+}
+
+void NameValueDictionary::unset(const QString &key)
+{
+ QTC_ASSERT(!key.contains('='), return );
+ auto it = findKey(m_values, m_osType, key);
+ if (it != m_values.end())
+ m_values.erase(it);
+}
+
+void NameValueDictionary::clear()
+{
+ m_values.clear();
+}
+
+QString NameValueDictionary::value(const QString &key) const
+{
+ const auto it = findKey(m_values, m_osType, key);
+ return it != m_values.end() ? it.value() : QString();
+}
+
+NameValueDictionary::const_iterator NameValueDictionary::constFind(const QString &name) const
+{
+ return findKey(m_values, m_osType, name);
+}
+
+int NameValueDictionary::size() const
+{
+ return m_values.size();
+}
+
+void NameValueDictionary::modify(const NameValueItems &items)
+{
+ NameValueDictionary resultKeyValueDictionary = *this;
+ for (const NameValueItem &item : items)
+ item.apply(&resultKeyValueDictionary);
+ *this = resultKeyValueDictionary;
+}
+
+enum : char {
+#ifdef Q_OS_WIN
+ pathSepC = ';'
+#else
+ pathSepC = ':'
+#endif
+};
+
+NameValueItems NameValueDictionary::diff(const NameValueDictionary &other, bool checkAppendPrepend) const
+{
+ NameValueMap::const_iterator thisIt = constBegin();
+ NameValueMap::const_iterator otherIt = other.constBegin();
+
+ NameValueItems result;
+ while (thisIt != constEnd() || otherIt != other.constEnd()) {
+ if (thisIt == constEnd()) {
+ result.append(NameValueItem(otherIt.key(), otherIt.value()));
+ ++otherIt;
+ } else if (otherIt == other.constEnd()) {
+ result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset));
+ ++thisIt;
+ } else if (thisIt.key() < otherIt.key()) {
+ result.append(NameValueItem(thisIt.key(), QString(), NameValueItem::Unset));
+ ++thisIt;
+ } else if (thisIt.key() > otherIt.key()) {
+ result.append(NameValueItem(otherIt.key(), otherIt.value()));
+ ++otherIt;
+ } else {
+ const QString &oldValue = thisIt.value();
+ const QString &newValue = otherIt.value();
+ if (oldValue != newValue) {
+ if (checkAppendPrepend && newValue.startsWith(oldValue)) {
+ QString appended = newValue.right(newValue.size() - oldValue.size());
+ if (appended.startsWith(QLatin1Char(pathSepC)))
+ appended.remove(0, 1);
+ result.append(NameValueItem(otherIt.key(), appended, NameValueItem::Append));
+ } else if (checkAppendPrepend && newValue.endsWith(oldValue)) {
+ QString prepended = newValue.left(newValue.size() - oldValue.size());
+ if (prepended.endsWith(QLatin1Char(pathSepC)))
+ prepended.chop(1);
+ result.append(NameValueItem(otherIt.key(), prepended, NameValueItem::Prepend));
+ } else {
+ result.append(NameValueItem(otherIt.key(), newValue));
+ }
+ }
+ ++otherIt;
+ ++thisIt;
+ }
+ }
+ return result;
+}
+
+bool NameValueDictionary::hasKey(const QString &key) const
+{
+ return m_values.contains(key);
+}
+
+OsType NameValueDictionary::osType() const
+{
+ return m_osType;
+}
+
+QString NameValueDictionary::userName() const
+{
+ return value(QString::fromLatin1(m_osType == OsTypeWindows ? "USERNAME" : "USER"));
+}
+
+/** Expand environment variables in a string.
+ *
+ * KeyValueDictionary variables are accepted in the following forms:
+ * $SOMEVAR, ${SOMEVAR} on Unix and %SOMEVAR% on Windows.
+ * No escapes and quoting are supported.
+ * If a variable is not found, it is not substituted.
+ */
+QString NameValueDictionary::expandVariables(const QString &input) const
+{
+ QString result = input;
+
+ if (m_osType == OsTypeWindows) {
+ for (int vStart = -1, i = 0; i < result.length();) {
+ if (result.at(i++) == '%') {
+ if (vStart > 0) {
+ const_iterator it = findKey(m_values, m_osType, result.mid(vStart, i - vStart - 1));
+ if (it != m_values.constEnd()) {
+ result.replace(vStart - 1, i - vStart + 1, *it);
+ i = vStart - 1 + it->length();
+ vStart = -1;
+ } else {
+ vStart = i;
+ }
+ } else {
+ vStart = i;
+ }
+ }
+ }
+ } else {
+ enum { BASE, OPTIONALVARIABLEBRACE, VARIABLE, BRACEDVARIABLE } state = BASE;
+ int vStart = -1;
+
+ for (int i = 0; i < result.length();) {
+ QChar c = result.at(i++);
+ if (state == BASE) {
+ if (c == '$')
+ state = OPTIONALVARIABLEBRACE;
+ } else if (state == OPTIONALVARIABLEBRACE) {
+ if (c == '{') {
+ state = BRACEDVARIABLE;
+ vStart = i;
+ } else if (c.isLetterOrNumber() || c == '_') {
+ state = VARIABLE;
+ vStart = i - 1;
+ } else {
+ state = BASE;
+ }
+ } else if (state == BRACEDVARIABLE) {
+ if (c == '}') {
+ const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart));
+ if (it != constEnd()) {
+ result.replace(vStart - 2, i - vStart + 2, *it);
+ i = vStart - 2 + it->length();
+ }
+ state = BASE;
+ }
+ } else if (state == VARIABLE) {
+ if (!c.isLetterOrNumber() && c != '_') {
+ const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1));
+ if (it != constEnd()) {
+ result.replace(vStart - 1, i - vStart, *it);
+ i = vStart - 1 + it->length();
+ }
+ state = BASE;
+ }
+ }
+ }
+ if (state == VARIABLE) {
+ const_iterator it = m_values.constFind(result.mid(vStart));
+ if (it != constEnd())
+ result.replace(vStart - 1, result.length() - vStart + 1, *it);
+ }
+ }
+ return result;
+}
+
+QStringList NameValueDictionary::expandVariables(const QStringList &variables) const
+{
+ return Utils::transform(variables, [this](const QString &i) { return expandVariables(i); });
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluedictionary.h b/src/libs/utils/namevaluedictionary.h
new file mode 100644
index 0000000000..112d6b094c
--- /dev/null
+++ b/src/libs/utils/namevaluedictionary.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "fileutils.h"
+#include "hostosinfo.h"
+#include "namevalueitem.h"
+
+namespace Utils {
+
+using NameValuePair = std::pair<QString, QString>;
+using NameValuePairs = QVector<NameValuePair>;
+using NameValueMap = QMap<QString, QString>;
+
+class QTCREATOR_UTILS_EXPORT NameValueDictionary
+{
+public:
+ using const_iterator = NameValueMap::const_iterator;
+
+ explicit NameValueDictionary(OsType osType = HostOsInfo::hostOs())
+ : m_osType(osType)
+ {}
+ explicit NameValueDictionary(const QStringList &env, OsType osType = HostOsInfo::hostOs());
+ explicit NameValueDictionary(const NameValuePairs &nameValues);
+
+ QStringList toStringList() const;
+ QString value(const QString &key) const;
+ void set(const QString &key, const QString &value);
+ void unset(const QString &key);
+ void modify(const NameValueItems &items);
+ /// Return the KeyValueDictionary changes necessary to modify this into the other environment.
+ NameValueItems diff(const NameValueDictionary &other, bool checkAppendPrepend = false) const;
+ bool hasKey(const QString &key) const;
+ OsType osType() const;
+
+ QString userName() const;
+
+ void clear();
+ int size() const;
+
+ QString key(NameValueDictionary::const_iterator it) const { return it.key(); }
+
+ QString value(NameValueDictionary::const_iterator it) const { return it.value(); }
+
+ NameValueDictionary::const_iterator constBegin() const { return m_values.constBegin(); }
+
+ NameValueDictionary::const_iterator constEnd() const { return m_values.constEnd(); }
+
+ NameValueDictionary::const_iterator constFind(const QString &name) const;
+
+ QString expandVariables(const QString &input) const;
+ QStringList expandVariables(const QStringList &input) const;
+
+ friend bool operator!=(const NameValueDictionary &first, const NameValueDictionary &second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator==(const NameValueDictionary &first, const NameValueDictionary &second)
+ {
+ return first.m_osType == second.m_osType && first.m_values == second.m_values;
+ }
+
+protected:
+ NameValueMap m_values;
+ OsType m_osType;
+};
+
+} // namespace Utils
diff --git a/src/libs/utils/namevalueitem.cpp b/src/libs/utils/namevalueitem.cpp
new file mode 100644
index 0000000000..6be972201c
--- /dev/null
+++ b/src/libs/utils/namevalueitem.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "namevalueitem.h"
+#include "algorithm.h"
+#include "namevaluedictionary.h"
+#include "qtcassert.h"
+
+#include <QDebug>
+
+namespace Utils {
+
+void NameValueItem::sort(NameValueItems *list)
+{
+ Utils::sort(*list, &NameValueItem::name);
+}
+
+NameValueItems NameValueItem::fromStringList(const QStringList &list)
+{
+ NameValueItems result;
+ for (const QString &string : list) {
+ int pos = string.indexOf('=', 1);
+ if (pos == -1)
+ result.append(NameValueItem(string, QString(), NameValueItem::Unset));
+ else
+ result.append(NameValueItem(string.left(pos), string.mid(pos + 1)));
+ }
+ return result;
+}
+
+QStringList NameValueItem::toStringList(const NameValueItems &list)
+{
+ return Utils::transform<QStringList>(list, [](const NameValueItem &item) {
+ if (item.operation == NameValueItem::Unset)
+ return QString(item.name);
+ return QString(item.name + '=' + item.value);
+ });
+}
+
+NameValueItems NameValueItem::itemsFromVariantList(const QVariantList &list)
+{
+ return Utils::transform<NameValueItems>(list, [](const QVariant &item) {
+ return itemFromVariantList(item.toList());
+ });
+}
+
+QVariantList NameValueItem::toVariantList(const NameValueItems &list)
+{
+ return Utils::transform<QVariantList>(list, [](const NameValueItem &item) {
+ return QVariant(toVariantList(item));
+ });
+}
+
+NameValueItem NameValueItem::itemFromVariantList(const QVariantList &list)
+{
+ QTC_ASSERT(list.size() == 3, return NameValueItem("", ""));
+ QString key = list.value(0).toString();
+ Operation operation = Operation(list.value(1).toInt());
+ QString value = list.value(2).toString();
+ return NameValueItem(key, value, operation);
+}
+
+QVariantList NameValueItem::toVariantList(const NameValueItem &item)
+{
+ return QVariantList() << item.name << item.operation << item.value;
+}
+
+static QString expand(const NameValueDictionary *dictionary, QString value)
+{
+ int replaceCount = 0;
+ for (int i = 0; i < value.size(); ++i) {
+ if (value.at(i) == '$') {
+ if ((i + 1) < value.size()) {
+ const QChar &c = value.at(i + 1);
+ int end = -1;
+ if (c == '(')
+ end = value.indexOf(')', i);
+ else if (c == '{')
+ end = value.indexOf('}', i);
+ if (end != -1) {
+ const QString &key = value.mid(i + 2, end - i - 2);
+ NameValueDictionary::const_iterator it = dictionary->constFind(key);
+ if (it != dictionary->constEnd())
+ value.replace(i, end - i + 1, it.value());
+ ++replaceCount;
+ QTC_ASSERT(replaceCount < 100, break);
+ }
+ }
+ }
+ }
+ return value;
+}
+
+enum : char {
+#ifdef Q_OS_WIN
+ pathSepC = ';'
+#else
+ pathSepC = ':'
+#endif
+};
+
+void NameValueItem::apply(NameValueDictionary *dictionary, Operation op) const
+{
+ switch (op) {
+ case Set:
+ dictionary->set(name, expand(dictionary, value));
+ break;
+ case Unset:
+ dictionary->unset(name);
+ break;
+ case Prepend: {
+ const NameValueDictionary::const_iterator it = dictionary->constFind(name);
+ if (it != dictionary->constEnd()) {
+ QString v = it.value();
+ const QChar pathSep{QLatin1Char(pathSepC)};
+ int sepCount = 0;
+ if (v.startsWith(pathSep))
+ ++sepCount;
+ if (value.endsWith(pathSep))
+ ++sepCount;
+ if (sepCount == 2)
+ v.remove(0, 1);
+ else if (sepCount == 0)
+ v.prepend(pathSep);
+ v.prepend(expand(dictionary, value));
+ dictionary->set(name, v);
+ } else {
+ apply(dictionary, Set);
+ }
+ } break;
+ case Append: {
+ const NameValueDictionary::const_iterator it = dictionary->constFind(name);
+ if (it != dictionary->constEnd()) {
+ QString v = it.value();
+ const QChar pathSep{QLatin1Char(pathSepC)};
+ int sepCount = 0;
+ if (v.endsWith(pathSep))
+ ++sepCount;
+ if (value.startsWith(pathSep))
+ ++sepCount;
+ if (sepCount == 2)
+ v.chop(1);
+ else if (sepCount == 0)
+ v.append(pathSep);
+ v.append(expand(dictionary, value));
+ dictionary->set(name, v);
+ } else {
+ apply(dictionary, Set);
+ }
+ } break;
+ }
+}
+
+QDebug operator<<(QDebug debug, const NameValueItem &i)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote();
+ debug.nospace();
+ debug << "KeyValueItem(";
+ switch (i.operation) {
+ case NameValueItem::Set:
+ debug << "set \"" << i.name << "\" to \"" << i.value << '"';
+ break;
+ case NameValueItem::Unset:
+ debug << "unset \"" << i.name << '"';
+ break;
+ case NameValueItem::Prepend:
+ debug << "prepend to \"" << i.name << "\":\"" << i.value << '"';
+ break;
+ case NameValueItem::Append:
+ debug << "append to \"" << i.name << "\":\"" << i.value << '"';
+ break;
+ }
+ debug << ')';
+ return debug;
+}
+} // namespace Utils
diff --git a/src/libs/utils/namevalueitem.h b/src/libs/utils/namevalueitem.h
new file mode 100644
index 0000000000..3ed4cc3cb3
--- /dev/null
+++ b/src/libs/utils/namevalueitem.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "environmentfwd.h"
+#include "utils_global.h"
+
+#include <QStringList>
+#include <QVariantList>
+#include <QVector>
+
+namespace Utils {
+
+class QTCREATOR_UTILS_EXPORT NameValueItem
+{
+public:
+ enum Operation : char { Set, Unset, Prepend, Append };
+ NameValueItem() = default;
+ NameValueItem(const QString &key, const QString &value, Operation operation = Set)
+ : name(key)
+ , value(value)
+ , operation(operation)
+ {}
+
+ void apply(NameValueDictionary *dictionary) const { apply(dictionary, operation); }
+
+ static void sort(NameValueItems *list);
+ static NameValueItems fromStringList(const QStringList &list);
+ static QStringList toStringList(const NameValueItems &list);
+ static NameValueItems itemsFromVariantList(const QVariantList &list);
+ static QVariantList toVariantList(const NameValueItems &list);
+ static NameValueItem itemFromVariantList(const QVariantList &list);
+ static QVariantList toVariantList(const NameValueItem &item);
+
+ friend bool operator==(const NameValueItem &first, const NameValueItem &second)
+ {
+ return first.operation == second.operation && first.name == second.name
+ && first.value == second.value;
+ }
+
+ friend bool operator!=(const NameValueItem &first, const NameValueItem &second)
+ {
+ return !(first == second);
+ }
+
+public:
+ QString name;
+ QString value;
+ Operation operation = Unset;
+
+private:
+ void apply(NameValueDictionary *dictionary, Operation op) const;
+};
+
+QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug debug, const NameValueItem &i);
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluemodel.cpp b/src/libs/utils/namevaluemodel.cpp
new file mode 100644
index 0000000000..2a310d6b61
--- /dev/null
+++ b/src/libs/utils/namevaluemodel.cpp
@@ -0,0 +1,397 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "namevaluemodel.h"
+
+#include <utils/algorithm.h>
+#include <utils/hostosinfo.h>
+#include <utils/namevaluedictionary.h>
+
+#include <QFont>
+#include <QString>
+
+namespace Utils {
+namespace Internal {
+
+class NameValueModelPrivate
+{
+public:
+ void updateResultNameValueDictionary()
+ {
+ m_resultNameValueDictionary = m_baseNameValueDictionary;
+ m_resultNameValueDictionary.modify(m_items);
+ // Add removed variables again and mark them as "<UNSET>" so
+ // that the user can actually see those removals:
+ foreach (const NameValueItem &item, m_items) {
+ if (item.operation == NameValueItem::Unset)
+ m_resultNameValueDictionary.set(item.name, NameValueModel::tr("<UNSET>"));
+ }
+ }
+
+ int findInChanges(const QString &name) const
+ {
+ for (int i = 0; i < m_items.size(); ++i)
+ if (m_items.at(i).name == name)
+ return i;
+ return -1;
+ }
+
+ int findInResultInsertPosition(const QString &name) const
+ {
+ NameValueDictionary::const_iterator it;
+ int i = 0;
+ for (it = m_resultNameValueDictionary.constBegin();
+ it != m_resultNameValueDictionary.constEnd();
+ ++it, ++i)
+ if (m_resultNameValueDictionary.key(it) > name)
+ return i;
+ return m_resultNameValueDictionary.size();
+ }
+
+ int findInResult(const QString &name) const
+ {
+ NameValueDictionary::const_iterator it;
+ int i = 0;
+ for (it = m_resultNameValueDictionary.constBegin();
+ it != m_resultNameValueDictionary.constEnd();
+ ++it, ++i)
+ if (m_resultNameValueDictionary.key(it) == name)
+ return i;
+ return -1;
+ }
+
+ NameValueDictionary m_baseNameValueDictionary;
+ NameValueDictionary m_resultNameValueDictionary;
+ NameValueItems m_items;
+};
+
+} // namespace Internal
+
+NameValueModel::NameValueModel(QObject *parent)
+ : QAbstractTableModel(parent)
+ , d(std::make_unique<Internal::NameValueModelPrivate>())
+{}
+
+NameValueModel::~NameValueModel() = default;
+
+QString NameValueModel::indexToVariable(const QModelIndex &index) const
+{
+ return d->m_resultNameValueDictionary.key(d->m_resultNameValueDictionary.constBegin()
+ + index.row());
+}
+
+void NameValueModel::setBaseNameValueDictionary(const NameValueDictionary &dictionary)
+{
+ if (d->m_baseNameValueDictionary == dictionary)
+ return;
+ beginResetModel();
+ d->m_baseNameValueDictionary = dictionary;
+ d->updateResultNameValueDictionary();
+ endResetModel();
+}
+
+int NameValueModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return d->m_resultNameValueDictionary.size();
+}
+int NameValueModel::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return 2;
+}
+
+bool NameValueModel::changes(const QString &name) const
+{
+ return d->findInChanges(name) >= 0;
+}
+
+const NameValueDictionary &NameValueModel::baseNameValueDictionary() const
+{
+ return d->m_baseNameValueDictionary;
+}
+
+QVariant NameValueModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole) {
+ if (index.column() == 0) {
+ return d->m_resultNameValueDictionary.key(d->m_resultNameValueDictionary.constBegin()
+ + index.row());
+ } else if (index.column() == 1) {
+ // Do not return "<UNSET>" when editing a previously unset variable:
+ if (role == Qt::EditRole) {
+ int pos = d->findInChanges(indexToVariable(index));
+ if (pos >= 0)
+ return d->m_items.at(pos).value;
+ }
+ QString value = d->m_resultNameValueDictionary.value(
+ d->m_resultNameValueDictionary.constBegin() + index.row());
+ if (role == Qt::ToolTipRole && value.length() > 80) {
+ // Use html to enable text wrapping
+ value = value.toHtmlEscaped();
+ value.prepend(QLatin1String("<html><body>"));
+ value.append(QLatin1String("</body></html>"));
+ }
+ return value;
+ }
+ }
+ if (role == Qt::FontRole) {
+ // check whether this name value item variable exists in d->m_items
+ if (changes(d->m_resultNameValueDictionary.key(d->m_resultNameValueDictionary.constBegin()
+ + index.row()))) {
+ QFont f;
+ f.setBold(true);
+ return QVariant(f);
+ }
+ return QFont();
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags NameValueModel::flags(const QModelIndex &index) const
+{
+ Q_UNUSED(index)
+ return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
+}
+
+QVariant NameValueModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Vertical || role != Qt::DisplayRole)
+ return QVariant();
+ return section == 0 ? tr("Variable") : tr("Value");
+}
+
+/// *****************
+/// Utility functions
+/// *****************
+QModelIndex NameValueModel::variableToIndex(const QString &name) const
+{
+ int row = d->findInResult(name);
+ if (row == -1)
+ return QModelIndex();
+ return index(row, 0);
+}
+
+bool NameValueModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || role != Qt::EditRole)
+ return false;
+
+ // ignore changes to already set values:
+ if (data(index, role) == value)
+ return true;
+
+ const QString oldName = data(this->index(index.row(), 0, QModelIndex())).toString();
+ const QString oldValue = data(this->index(index.row(), 1, QModelIndex()), Qt::EditRole).toString();
+ int changesPos = d->findInChanges(oldName);
+
+ if (index.column() == 0) {
+ //fail if a variable with the same name already exists
+ const QString &newName = HostOsInfo::isWindowsHost() ? value.toString().toUpper()
+ : value.toString();
+ if (newName.isEmpty() || newName.contains('='))
+ return false;
+ // Does the new name exist already?
+ if (d->m_resultNameValueDictionary.hasKey(newName) || newName.isEmpty())
+ return false;
+
+ NameValueItem newVariable(newName, oldValue);
+
+ if (changesPos != -1)
+ resetVariable(oldName); // restore the original base variable again
+
+ QModelIndex newIndex = addVariable(newVariable); // add the new variable
+ emit focusIndex(newIndex.sibling(newIndex.row(), 1)); // hint to focus on the value
+ return true;
+ } else if (index.column() == 1) {
+ // We are changing an existing value:
+ const QString stringValue = value.toString();
+ if (changesPos != -1) {
+ // We have already changed this value
+ if (d->m_baseNameValueDictionary.hasKey(oldName)
+ && stringValue == d->m_baseNameValueDictionary.value(oldName)) {
+ // ... and now went back to the base value
+ d->m_items.removeAt(changesPos);
+ } else {
+ // ... and changed it again
+ d->m_items[changesPos].value = stringValue;
+ d->m_items[changesPos].operation = NameValueItem::Set;
+ }
+ } else {
+ // Add a new change item:
+ d->m_items.append(NameValueItem(oldName, stringValue));
+ }
+ d->updateResultNameValueDictionary();
+ emit dataChanged(index, index);
+ emit userChangesChanged();
+ return true;
+ }
+ return false;
+}
+
+QModelIndex NameValueModel::addVariable()
+{
+ //: Name when inserting a new variable
+ return addVariable(NameValueItem(tr("<VARIABLE>"),
+ //: Value when inserting a new variable
+ tr("<VALUE>")));
+}
+
+QModelIndex NameValueModel::addVariable(const NameValueItem &item)
+{
+ // Return existing index if the name is already in the result set:
+ int pos = d->findInResult(item.name);
+ if (pos >= 0 && pos < d->m_resultNameValueDictionary.size())
+ return index(pos, 0, QModelIndex());
+
+ int insertPos = d->findInResultInsertPosition(item.name);
+ int changePos = d->findInChanges(item.name);
+ if (d->m_baseNameValueDictionary.hasKey(item.name)) {
+ // We previously unset this!
+ Q_ASSERT(changePos >= 0);
+ // Do not insert a line here as we listed the variable as <UNSET> before!
+ Q_ASSERT(d->m_items.at(changePos).name == item.name);
+ Q_ASSERT(d->m_items.at(changePos).operation == NameValueItem::Unset);
+ Q_ASSERT(d->m_items.at(changePos).value.isEmpty());
+ d->m_items[changePos] = item;
+ emit dataChanged(index(insertPos, 0, QModelIndex()), index(insertPos, 1, QModelIndex()));
+ } else {
+ // We add something that is not in the base dictionary
+ // Insert a new line!
+ beginInsertRows(QModelIndex(), insertPos, insertPos);
+ Q_ASSERT(changePos < 0);
+ d->m_items.append(item);
+ d->updateResultNameValueDictionary();
+ endInsertRows();
+ }
+ emit userChangesChanged();
+ return index(insertPos, 0, QModelIndex());
+}
+
+void NameValueModel::resetVariable(const QString &name)
+{
+ int rowInChanges = d->findInChanges(name);
+ if (rowInChanges < 0)
+ return;
+
+ int rowInResult = d->findInResult(name);
+ if (rowInResult < 0)
+ return;
+
+ if (d->m_baseNameValueDictionary.hasKey(name)) {
+ d->m_items.removeAt(rowInChanges);
+ d->updateResultNameValueDictionary();
+ emit dataChanged(index(rowInResult, 0, QModelIndex()), index(rowInResult, 1, QModelIndex()));
+ emit userChangesChanged();
+ } else {
+ // Remove the line completely!
+ beginRemoveRows(QModelIndex(), rowInResult, rowInResult);
+ d->m_items.removeAt(rowInChanges);
+ d->updateResultNameValueDictionary();
+ endRemoveRows();
+ emit userChangesChanged();
+ }
+}
+
+void NameValueModel::unsetVariable(const QString &name)
+{
+ // This does not change the number of rows as we will display a <UNSET>
+ // in place of the original variable!
+ int row = d->findInResult(name);
+ if (row < 0)
+ return;
+
+ // look in d->m_items for the variable
+ int pos = d->findInChanges(name);
+ if (pos != -1) {
+ d->m_items[pos].operation = NameValueItem::Unset;
+ d->m_items[pos].value.clear();
+ d->updateResultNameValueDictionary();
+ emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
+ emit userChangesChanged();
+ return;
+ }
+ d->m_items.append(NameValueItem(name, QString(), NameValueItem::Unset));
+ d->updateResultNameValueDictionary();
+ emit dataChanged(index(row, 0, QModelIndex()), index(row, 1, QModelIndex()));
+ emit userChangesChanged();
+}
+
+bool NameValueModel::canUnset(const QString &name)
+{
+ int pos = d->findInChanges(name);
+ if (pos != -1)
+ return d->m_items.at(pos).operation == NameValueItem::Unset;
+ else
+ return false;
+}
+
+bool NameValueModel::canReset(const QString &name)
+{
+ return d->m_baseNameValueDictionary.hasKey(name);
+}
+
+NameValueItems NameValueModel::userChanges() const
+{
+ return d->m_items;
+}
+
+void NameValueModel::setUserChanges(const NameValueItems &items)
+{
+ NameValueItems filtered = Utils::filtered(items, [](const NameValueItem &i) {
+ return i.name != "export " && !i.name.contains('=');
+ });
+ // We assume nobody is reordering the items here.
+ if (filtered == d->m_items)
+ return;
+ beginResetModel();
+ d->m_items = filtered;
+ for (NameValueItem &item : d->m_items) {
+ QString &name = item.name;
+ name = name.trimmed();
+ if (name.startsWith("export "))
+ name = name.mid(7).trimmed();
+ if (d->m_baseNameValueDictionary.osType() == OsTypeWindows) {
+ // NameValueDictionary variable names are case-insensitive under windows, but we still
+ // want to preserve the case of pre-existing variables.
+ auto it = d->m_baseNameValueDictionary.constFind(name);
+ if (it != d->m_baseNameValueDictionary.constEnd())
+ name = d->m_baseNameValueDictionary.key(it);
+ }
+ }
+
+ d->updateResultNameValueDictionary();
+ endResetModel();
+ emit userChangesChanged();
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluemodel.h b/src/libs/utils/namevaluemodel.h
new file mode 100644
index 0000000000..96811fec68
--- /dev/null
+++ b/src/libs/utils/namevaluemodel.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "environmentfwd.h"
+#include "utils_global.h"
+
+#include <QAbstractTableModel>
+
+#include <memory>
+
+namespace Utils {
+
+namespace Internal {
+class NameValueModelPrivate;
+}
+
+class QTCREATOR_UTILS_EXPORT NameValueModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit NameValueModel(QObject *parent = nullptr);
+ ~NameValueModel() override;
+
+ int rowCount(const QModelIndex &parent) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QVariant headerData(int section,
+ Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const override;
+
+ QModelIndex addVariable();
+ QModelIndex addVariable(const NameValueItem &item);
+ void resetVariable(const QString &name);
+ void unsetVariable(const QString &name);
+ bool canUnset(const QString &name);
+ bool canReset(const QString &name);
+ QString indexToVariable(const QModelIndex &index) const;
+ QModelIndex variableToIndex(const QString &name) const;
+ bool changes(const QString &key) const;
+ const NameValueDictionary &baseNameValueDictionary() const;
+ void setBaseNameValueDictionary(const NameValueDictionary &dictionary);
+ NameValueItems userChanges() const;
+ void setUserChanges(const NameValueItems &items);
+
+signals:
+ void userChangesChanged();
+ /// Hint to the view where it should make sense to focus on next
+ // This is a hack since there is no way for a model to suggest
+ // the next interesting place to focus on to the view.
+ void focusIndex(const QModelIndex &index);
+
+private:
+ std::unique_ptr<Internal::NameValueModelPrivate> d;
+};
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluesdialog.cpp b/src/libs/utils/namevaluesdialog.cpp
new file mode 100644
index 0000000000..ed71d8db7f
--- /dev/null
+++ b/src/libs/utils/namevaluesdialog.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "namevaluesdialog.h"
+
+#include <utils/environment.h>
+#include <utils/hostosinfo.h>
+
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QPlainTextEdit>
+#include <QVBoxLayout>
+
+namespace Utils {
+
+namespace Internal {
+
+static EnvironmentItems cleanUp(const EnvironmentItems &items)
+{
+ EnvironmentItems uniqueItems;
+ QSet<QString> uniqueSet;
+ for (int i = items.count() - 1; i >= 0; i--) {
+ EnvironmentItem item = items.at(i);
+ if (HostOsInfo::isWindowsHost())
+ item.name = item.name.toUpper();
+ const QString &itemName = item.name;
+ QString emptyName = itemName;
+ emptyName.remove(QLatin1Char(' '));
+ if (!emptyName.isEmpty() && !uniqueSet.contains(itemName)) {
+ uniqueItems.prepend(item);
+ uniqueSet.insert(itemName);
+ }
+ }
+ return uniqueItems;
+}
+
+NameValueItemsWidget::NameValueItemsWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ m_editor = new QPlainTextEdit(this);
+ auto layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->addWidget(m_editor);
+}
+
+void NameValueItemsWidget::setEnvironmentItems(const EnvironmentItems &items)
+{
+ EnvironmentItems sortedItems = items;
+ EnvironmentItem::sort(&sortedItems);
+ const QStringList list = EnvironmentItem::toStringList(sortedItems);
+ m_editor->document()->setPlainText(list.join(QLatin1Char('\n')));
+}
+
+EnvironmentItems NameValueItemsWidget::environmentItems() const
+{
+ const QStringList list = m_editor->document()->toPlainText().split(QLatin1String("\n"));
+ EnvironmentItems items = EnvironmentItem::fromStringList(list);
+ return cleanUp(items);
+}
+
+void NameValueItemsWidget::setPlaceholderText(const QString &text)
+{
+ m_editor->setPlaceholderText(text);
+}
+} // namespace Internal
+
+NameValuesDialog::NameValuesDialog(const QString &windowTitle, const QString &helpText, QWidget *parent)
+ : QDialog(parent)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ resize(640, 480);
+ m_editor = new Internal::NameValueItemsWidget(this);
+ auto box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal,
+ this);
+ connect(box, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
+
+ auto helpLabel = new QLabel(this);
+ helpLabel->setText(helpText);
+
+ auto layout = new QVBoxLayout(this);
+ layout->addWidget(m_editor);
+ layout->addWidget(helpLabel);
+
+ layout->addWidget(box);
+
+ setWindowTitle(windowTitle);
+}
+
+void NameValuesDialog::setNameValueItems(const EnvironmentItems &items)
+{
+ m_editor->setEnvironmentItems(items);
+}
+
+EnvironmentItems NameValuesDialog::nameValueItems() const
+{
+ return m_editor->environmentItems();
+}
+
+void NameValuesDialog::setPlaceholderText(const QString &text)
+{
+ m_editor->setPlaceholderText(text);
+}
+
+Utils::optional<NameValueItems> NameValuesDialog::getNameValueItems(QWidget *parent,
+ const NameValueItems &initial,
+ const QString &placeholderText,
+ Polisher polisher,
+ const QString &windowTitle,
+ const QString &helpText)
+{
+ NameValuesDialog dialog(windowTitle, helpText, parent);
+ if (polisher)
+ polisher(&dialog);
+ dialog.setNameValueItems(initial);
+ dialog.setPlaceholderText(placeholderText);
+ bool result = dialog.exec() == QDialog::Accepted;
+ if (result)
+ return dialog.nameValueItems();
+
+ return {};
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluesdialog.h b/src/libs/utils/namevaluesdialog.h
new file mode 100644
index 0000000000..8170a99a1d
--- /dev/null
+++ b/src/libs/utils/namevaluesdialog.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "environmentfwd.h"
+#include "optional.h"
+#include "utils_global.h"
+
+#include <QDialog>
+
+#include <functional>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+QT_END_NAMESPACE
+
+namespace Utils {
+
+namespace Internal {
+class NameValueItemsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit NameValueItemsWidget(QWidget *parent = nullptr);
+
+ void setEnvironmentItems(const EnvironmentItems &items);
+ EnvironmentItems environmentItems() const;
+
+ void setPlaceholderText(const QString &text);
+
+private:
+ QPlainTextEdit *m_editor;
+};
+} // namespace Internal
+
+class QTCREATOR_UTILS_EXPORT NameValuesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ void setNameValueItems(const NameValueItems &items);
+ NameValueItems nameValueItems() const;
+
+ void setPlaceholderText(const QString &text);
+
+ using Polisher = std::function<void(QWidget *)>;
+ static Utils::optional<NameValueItems> getNameValueItems(QWidget *parent = nullptr,
+ const NameValueItems &initial = {},
+ const QString &placeholderText = {},
+ Polisher polish = {},
+ const QString &windowTitle = {},
+ const QString &helpText = {});
+
+protected:
+ explicit NameValuesDialog(const QString &windowTitle,
+ const QString &helpText,
+ QWidget *parent = {});
+
+private:
+ Internal::NameValueItemsWidget *m_editor;
+};
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluevalidator.cpp b/src/libs/utils/namevaluevalidator.cpp
new file mode 100644
index 0000000000..580a476e01
--- /dev/null
+++ b/src/libs/utils/namevaluevalidator.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "namevaluevalidator.h"
+#include "namevaluemodel.h"
+#include "tooltip/tooltip.h"
+
+#include <QTreeView>
+
+namespace Utils {
+
+NameValueValidator::NameValueValidator(QWidget *parent,
+ Utils::NameValueModel *model,
+ QTreeView *view,
+ const QModelIndex &index,
+ const QString &toolTipText)
+ : QValidator(parent)
+ , m_toolTipText(toolTipText)
+ , m_model(model)
+ , m_view(view)
+ , m_index(index)
+{
+ m_hideTipTimer.setInterval(2000);
+ m_hideTipTimer.setSingleShot(true);
+ connect(&m_hideTipTimer, &QTimer::timeout, this, []() { Utils::ToolTip::hide(); });
+}
+
+QValidator::State NameValueValidator::validate(QString &in, int &pos) const
+{
+ Q_UNUSED(pos)
+ QModelIndex idx = m_model->variableToIndex(in);
+ if (idx.isValid() && idx != m_index)
+ return QValidator::Intermediate;
+ Utils::ToolTip::hide();
+ m_hideTipTimer.stop();
+ return QValidator::Acceptable;
+}
+
+void NameValueValidator::fixup(QString &input) const
+{
+ Q_UNUSED(input)
+
+ QPoint pos = m_view->mapToGlobal(m_view->visualRect(m_index).topLeft());
+ pos -= Utils::ToolTip::offsetFromPosition();
+ Utils::ToolTip::show(pos, m_toolTipText);
+ m_hideTipTimer.start();
+ // do nothing
+}
+
+} // namespace Utils
diff --git a/src/libs/utils/namevaluevalidator.h b/src/libs/utils/namevaluevalidator.h
new file mode 100644
index 0000000000..e1a8ae13a0
--- /dev/null
+++ b/src/libs/utils/namevaluevalidator.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "environmentfwd.h"
+#include "utils_global.h"
+
+#include <QModelIndex>
+#include <QTimer>
+#include <QValidator>
+
+namespace Utils {
+
+class QTCREATOR_UTILS_EXPORT NameValueValidator : public QValidator
+{
+ Q_OBJECT
+public:
+ NameValueValidator(QWidget *parent,
+ Utils::NameValueModel *model,
+ QTreeView *view,
+ const QModelIndex &index,
+ const QString &toolTipText);
+
+ QValidator::State validate(QString &in, int &pos) const override;
+
+ void fixup(QString &input) const override;
+
+private:
+ const QString &m_toolTipText;
+ Utils::NameValueModel *m_model;
+ QTreeView *m_view;
+ QModelIndex m_index;
+ mutable QTimer m_hideTipTimer;
+};
+} // namespace Utils
diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri
index c7fef47c97..5789bc4995 100644
--- a/src/libs/utils/utils-lib.pri
+++ b/src/libs/utils/utils-lib.pri
@@ -27,6 +27,10 @@ SOURCES += \
$$PWD/environment.cpp \
$$PWD/environmentmodel.cpp \
$$PWD/environmentdialog.cpp \
+ $$PWD/namevaluedictionary.cpp \
+ $$PWD/namevalueitem.cpp \
+ $$PWD/namevaluemodel.cpp \
+ $$PWD/namevaluesdialog.cpp \
$$PWD/qrcparser.cpp \
$$PWD/qtcprocess.cpp \
$$PWD/reloadpromptutils.cpp \
@@ -125,19 +129,24 @@ SOURCES += \
$$PWD/fixedsizeclicklabel.cpp \
$$PWD/removefiledialog.cpp \
$$PWD/differ.cpp \
- $$PWD/jsontreeitem.cpp
-
+ $$PWD/jsontreeitem.cpp \
+ $$PWD/namevaluevalidator.cpp
win32:SOURCES += $$PWD/consoleprocess_win.cpp
else:SOURCES += $$PWD/consoleprocess_unix.cpp
HEADERS += \
+ $$PWD/environmentfwd.h \
$$PWD/genericconstants.h \
$$PWD/globalfilechangeblocker.h \
$$PWD/benchmarker.h \
$$PWD/environment.h \
$$PWD/environmentmodel.h \
$$PWD/environmentdialog.h \
+ $$PWD/namevaluedictionary.h \
+ $$PWD/namevalueitem.h \
+ $$PWD/namevaluemodel.h \
+ $$PWD/namevaluesdialog.h \
$$PWD/pointeralgorithm.h \
$$PWD/qrcparser.h \
$$PWD/qtcprocess.h \
@@ -270,7 +279,8 @@ HEADERS += \
$$PWD/differ.h \
$$PWD/cpplanguage_details.h \
$$PWD/jsontreeitem.h \
- $$PWD/listmodel.h
+ $$PWD/listmodel.h \
+ $$PWD/namevaluevalidator.h
FORMS += $$PWD/filewizardpage.ui \
$$PWD/newclasswidget.ui \
diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp
index cf432870e3..cee23ef1ae 100644
--- a/src/plugins/autotest/testrunner.cpp
+++ b/src/plugins/autotest/testrunner.cpp
@@ -150,7 +150,7 @@ static QString constructOmittedDetailsString(const QStringList &omitted)
"configuration page for \"%1\":") + '\n' + omitted.join('\n');
}
-static QString constructOmittedVariablesDetailsString(const QList<Utils::EnvironmentItem> &diff)
+static QString constructOmittedVariablesDetailsString(const Utils::EnvironmentItems &diff)
{
auto removedVars = Utils::transform<QStringList>(diff, [](const Utils::EnvironmentItem &it) {
return it.name;
@@ -204,10 +204,10 @@ void TestRunner::scheduleNext()
m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
const Utils::Environment &original = m_currentConfig->environment();
Utils::Environment environment = m_currentConfig->filteredEnvironment(original);
- const QList<Utils::EnvironmentItem> removedVariables
- = Utils::filtered(original.diff(environment), [](const Utils::EnvironmentItem &it) {
- return it.operation == Utils::EnvironmentItem::Unset;
- });
+ const Utils::EnvironmentItems removedVariables = Utils::filtered(
+ original.diff(environment), [](const Utils::EnvironmentItem &it) {
+ return it.operation == Utils::EnvironmentItem::Unset;
+ });
if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(m_currentConfig->displayName());
@@ -560,10 +560,10 @@ void TestRunner::debugTests()
}
Utils::Environment original(inferior.environment);
inferior.environment = config->filteredEnvironment(original);
- const QList<Utils::EnvironmentItem> removedVariables
- = Utils::filtered(original.diff(inferior.environment), [](const Utils::EnvironmentItem &it) {
- return it.operation == Utils::EnvironmentItem::Unset;
- });
+ const Utils::EnvironmentItems removedVariables = Utils::filtered(
+ original.diff(inferior.environment), [](const Utils::EnvironmentItem &it) {
+ return it.operation == Utils::EnvironmentItem::Unset;
+ });
if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(config->displayName());
diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
index 12efff6c6e..c8f7d9f7d1 100644
--- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
+++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp
@@ -60,9 +60,8 @@ static void addProjectPanelWidget()
auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
panelFactory->setPriority(60);
panelFactory->setDisplayName(ClangProjectSettingsWidget::tr("Clang Code Model"));
- panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project) {
- return new ClangProjectSettingsWidget(project);
- });
+ panelFactory->setCreateWidgetFunction(
+ [&](ProjectExplorer::Project *project) { return new ClangProjectSettingsWidget(project); });
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
}
diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp
index 49f4fe049f..493f19c3e2 100644
--- a/src/plugins/clangformat/clangformatplugin.cpp
+++ b/src/plugins/clangformat/clangformatplugin.cpp
@@ -106,8 +106,8 @@ static void replaceCppCodeStyle()
bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorString)
{
- Q_UNUSED(arguments);
- Q_UNUSED(errorString);
+ Q_UNUSED(arguments)
+ Q_UNUSED(errorString)
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
replaceCppCodeStyle();
diff --git a/src/plugins/clangpchmanager/CMakeLists.txt b/src/plugins/clangpchmanager/CMakeLists.txt
index 6b36a88060..a012d090c9 100644
--- a/src/plugins/clangpchmanager/CMakeLists.txt
+++ b/src/plugins/clangpchmanager/CMakeLists.txt
@@ -4,12 +4,17 @@ add_qtc_plugin(ClangPchManager
DEFINES CLANGPCHMANAGER_LIB
PLUGIN_DEPENDS Core CppTools
SOURCES
+ clangindexingprojectsettings.cpp clangindexingprojectsettings.h
+ clangindexingprojectsettingswidget.cpp clangindexingprojectsettingswidget.h clangindexingprojectsettingswidget.ui
+ clangindexingsettingsmanager.cpp clangindexingsettingsmanager.h
clangpchmanager_global.h
clangpchmanagerplugin.cpp clangpchmanagerplugin.h
pchmanagerclient.cpp pchmanagerclient.h
pchmanagerconnectionclient.cpp pchmanagerconnectionclient.h
pchmanagernotifierinterface.cpp pchmanagernotifierinterface.h
pchmanagerprojectupdater.cpp pchmanagerprojectupdater.h
+ preprocessormacrocollector.cpp preprocessormacrocollector.h
+ preprocessormacrowidget.cpp preprocessormacrowidget.h
progressmanager.h
progressmanagerinterface.h
projectupdater.cpp projectupdater.h
diff --git a/src/plugins/clangpchmanager/clangindexingprojectsettings.cpp b/src/plugins/clangpchmanager/clangindexingprojectsettings.cpp
new file mode 100644
index 0000000000..d8be4be390
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingprojectsettings.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "clangindexingprojectsettings.h"
+
+#include <projectexplorer/project.h>
+
+namespace ClangPchManager {
+
+namespace {
+Utils::NameValueItems fromQVariantMap(const QVariantMap &variantMap,
+ Utils::NameValueItem::Operation operation)
+{
+ Utils::NameValueItems nameValueItems;
+ nameValueItems.reserve(variantMap.size());
+
+ auto end = variantMap.end();
+
+ for (auto iterator = variantMap.cbegin(); iterator != end; ++iterator) // QMap iterators are broken
+ nameValueItems.push_back({iterator.key(), iterator.value().toString(), operation});
+
+ return nameValueItems;
+}
+
+} // namespace
+
+ClangIndexingProjectSettings::ClangIndexingProjectSettings(ProjectExplorer::Project *project)
+ : m_project(project)
+{}
+
+void ClangIndexingProjectSettings::saveMacros(const Utils::NameValueItems &items)
+{
+ QVariantMap unsets;
+ QVariantMap sets;
+
+ for (const Utils::NameValueItem &item : items) {
+ using Operation = Utils::NameValueItem::Operation;
+ switch (item.operation) {
+ case Operation::Set:
+ sets[item.name] = item.value;
+ break;
+ case Operation::Unset:
+ unsets[item.name] = item.value;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (sets.size())
+ m_project->setNamedSettings("set_indexing_macro", sets);
+ else
+ m_project->setNamedSettings("set_indexing_macro", {});
+
+ if (unsets.size())
+ m_project->setNamedSettings("unset_indexing_macro", unsets);
+ else
+ m_project->setNamedSettings("unset_indexing_macro", {});
+}
+
+Utils::NameValueItems ClangIndexingProjectSettings::readMacros() const
+{
+ QVariant unsets = m_project->namedSettings("unset_indexing_macro");
+
+ Utils::NameValueItems items = fromQVariantMap(unsets.toMap(), Utils::NameValueItem::Unset);
+
+ QVariant sets = m_project->namedSettings("set_indexing_macro");
+
+ items += fromQVariantMap(sets.toMap(), Utils::NameValueItem::Set);
+
+ return items;
+}
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangindexingprojectsettings.h b/src/plugins/clangpchmanager/clangindexingprojectsettings.h
new file mode 100644
index 0000000000..7571034a28
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingprojectsettings.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "clangpchmanager_global.h"
+
+#include <utils/namevalueitem.h>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace ClangPchManager {
+
+class CLANGPCHMANAGER_EXPORT ClangIndexingProjectSettings
+{
+public:
+ ClangIndexingProjectSettings(ProjectExplorer::Project *project);
+
+ Utils::NameValueItems readMacros() const;
+ void saveMacros(const Utils::NameValueItems &items);
+
+private:
+ ProjectExplorer::Project *m_project;
+};
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.cpp b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.cpp
new file mode 100644
index 0000000000..25e77b58a0
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "clangindexingprojectsettingswidget.h"
+#include "ui_clangindexingprojectsettingswidget.h"
+
+#include <cpptools/cppmodelmanager.h>
+#include <projectexplorer/project.h>
+
+#include "preprocessormacrocollector.h"
+#include "preprocessormacrowidget.h"
+
+namespace ClangPchManager {
+ClangIndexingProjectSettingsWidget::ClangIndexingProjectSettingsWidget(ClangIndexingProjectSettings *settings)
+ : ui(new Ui::ClangIndexingProjectSettingsWidget)
+{
+ ui->setupUi(this);
+ ui->preprocessorMacrosWidget->setSettings(settings);
+}
+
+ClangIndexingProjectSettingsWidget::~ClangIndexingProjectSettingsWidget()
+{
+ delete ui;
+}
+
+void ClangIndexingProjectSettingsWidget::onProjectPartsUpdated(ProjectExplorer::Project *project)
+{
+ const CppTools::ProjectInfo projectInfo = CppTools::CppModelManager::instance()->projectInfo(
+ project);
+
+ PreprocessorMacroCollector collector;
+
+ for (auto projectPart : projectInfo.projectParts())
+ collector.add(projectPart->projectMacros);
+
+ ui->preprocessorMacrosWidget->setBasePreprocessorMacros(collector.macros());
+}
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.h b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.h
new file mode 100644
index 0000000000..d46d811938
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QWidget>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace Ui {
+class ClangIndexingProjectSettingsWidget;
+}
+
+namespace ClangPchManager {
+
+class ClangIndexingProjectSettings;
+
+class ClangIndexingProjectSettingsWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit ClangIndexingProjectSettingsWidget(ClangIndexingProjectSettings *settings);
+ ~ClangIndexingProjectSettingsWidget();
+
+ void onProjectPartsUpdated(ProjectExplorer::Project *project);
+
+private:
+ Ui::ClangIndexingProjectSettingsWidget *ui;
+};
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.ui b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.ui
new file mode 100644
index 0000000000..e54a2a7a91
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingprojectsettingswidget.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ClangIndexingProjectSettingsWidget</class>
+ <widget class="QWidget" name="ClangIndexingProjectSettingsWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="ClangPchManager::PreprocessorMacroWidget" name="preprocessorMacrosWidget" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>ClangPchManager::PreprocessorMacroWidget</class>
+ <extends>QWidget</extends>
+ <header>preprocessormacrowidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/clangpchmanager/clangindexingsettingsmanager.cpp b/src/plugins/clangpchmanager/clangindexingsettingsmanager.cpp
new file mode 100644
index 0000000000..786581d73d
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingsettingsmanager.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "clangindexingsettingsmanager.h"
+
+#include "clangindexingprojectsettings.h"
+
+namespace ClangPchManager {
+
+ClangIndexingSettingsManager::ClangIndexingSettingsManager() = default;
+
+ClangIndexingSettingsManager::~ClangIndexingSettingsManager() = default;
+
+ClangIndexingProjectSettings *ClangIndexingSettingsManager::settings(ProjectExplorer::Project *project)
+{
+ auto &setting = m_settings[project];
+
+ if (!setting)
+ setting = std::make_unique<ClangIndexingProjectSettings>(project);
+
+ return setting.get();
+}
+
+void ClangIndexingSettingsManager::remove(ProjectExplorer::Project *project)
+{
+ m_settings.erase(project);
+}
+
+bool ClangIndexingSettingsManager::hasSettings(ProjectExplorer::Project *project) const
+{
+ return m_settings.find(project) != m_settings.end();
+}
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangindexingsettingsmanager.h b/src/plugins/clangpchmanager/clangindexingsettingsmanager.h
new file mode 100644
index 0000000000..a8399f62cf
--- /dev/null
+++ b/src/plugins/clangpchmanager/clangindexingsettingsmanager.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "clangpchmanager_global.h"
+
+#include <map>
+#include <memory>
+
+namespace ProjectExplorer {
+class Project;
+}
+
+namespace ClangPchManager {
+
+class ClangIndexingProjectSettings;
+
+class CLANGPCHMANAGER_EXPORT ClangIndexingSettingsManager
+{
+public:
+ ClangIndexingSettingsManager();
+ ~ClangIndexingSettingsManager();
+
+ ClangIndexingProjectSettings *settings(ProjectExplorer::Project *project);
+ void remove(ProjectExplorer::Project *project);
+
+ bool hasSettings(ProjectExplorer::Project *project) const;
+
+private:
+ std::map<ProjectExplorer::Project *, std::unique_ptr<ClangIndexingProjectSettings>> m_settings;
+};
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/clangpchmanager-source.pri b/src/plugins/clangpchmanager/clangpchmanager-source.pri
index c0eb7ba90a..a74d61313c 100644
--- a/src/plugins/clangpchmanager/clangpchmanager-source.pri
+++ b/src/plugins/clangpchmanager/clangpchmanager-source.pri
@@ -7,18 +7,24 @@ shared|dll {
INCLUDEPATH += $$PWD
HEADERS += \
+ $$PWD/clangindexingprojectsettings.h \
+ $$PWD/clangindexingsettingsmanager.h \
$$PWD/pchmanagerclient.h \
$$PWD/pchmanagernotifierinterface.h \
$$PWD/pchmanagerconnectionclient.h \
$$PWD/clangpchmanager_global.h \
+ $$PWD/preprocessormacrocollector.h \
$$PWD/projectupdater.h \
$$PWD/pchmanagerprojectupdater.h \
$$PWD/progressmanager.h \
$$PWD/progressmanagerinterface.h
SOURCES += \
+ $$PWD/clangindexingprojectsettings.cpp \
+ $$PWD/clangindexingsettingsmanager.cpp \
$$PWD/pchmanagerclient.cpp \
$$PWD/pchmanagernotifierinterface.cpp \
$$PWD/pchmanagerconnectionclient.cpp \
+ $$PWD/preprocessormacrocollector.cpp \
$$PWD/projectupdater.cpp \
$$PWD/pchmanagerprojectupdater.cpp
diff --git a/src/plugins/clangpchmanager/clangpchmanager.pro b/src/plugins/clangpchmanager/clangpchmanager.pro
index e222ffd3d4..b0bc548c20 100644
--- a/src/plugins/clangpchmanager/clangpchmanager.pro
+++ b/src/plugins/clangpchmanager/clangpchmanager.pro
@@ -12,8 +12,15 @@ win32 {
HEADERS += \
$$PWD/clangpchmanagerplugin.h \
+ clangindexingprojectsettingswidget.h \
+ preprocessormacrowidget.h \
qtcreatorprojectupdater.h
SOURCES += \
$$PWD/clangpchmanagerplugin.cpp \
+ clangindexingprojectsettingswidget.cpp \
+ preprocessormacrowidget.cpp \
qtcreatorprojectupdater.cpp
+
+FORMS += \
+ clangindexingprojectsettingswidget.ui
diff --git a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp
index c50a4db7b9..98e455b0ea 100644
--- a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp
+++ b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp
@@ -25,8 +25,10 @@
#include "clangpchmanagerplugin.h"
-#include "pchmanagerconnectionclient.h"
+#include "clangindexingprojectsettingswidget.h"
+#include "clangindexingsettingsmanager.h"
#include "pchmanagerclient.h"
+#include "pchmanagerconnectionclient.h"
#include "progressmanager.h"
#include "qtcreatorprojectupdater.h"
@@ -38,12 +40,14 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
+#include <projectexplorer/projectpanelfactory.h>
#include <utils/hostosinfo.h>
#include <QFutureInterface>
#include <chrono>
+#include <map>
using namespace std::chrono_literals;
@@ -58,6 +62,26 @@ QString backendProcessPath()
+ QStringLiteral(QTC_HOST_EXE_SUFFIX);
}
+void addIndexingProjectPaneWidget(ClangIndexingSettingsManager &settingsManager)
+{
+ auto factory = new ProjectExplorer::ProjectPanelFactory;
+ factory->setPriority(120);
+ factory->setDisplayName(ClangIndexingProjectSettingsWidget::tr("Clang Indexing"));
+ factory->setCreateWidgetFunction([&](ProjectExplorer::Project *project) {
+ auto widget = new ClangIndexingProjectSettingsWidget(settingsManager.settings(project));
+
+ widget->onProjectPartsUpdated(project);
+
+ QObject::connect(CppTools::CppModelManager::instance(),
+ &CppTools::CppModelManager::projectPartsUpdated,
+ widget,
+ &ClangIndexingProjectSettingsWidget::onProjectPartsUpdated);
+
+ return widget;
+ });
+ ProjectExplorer::ProjectPanelFactory::registerFactory(factory);
+}
+
} // anonymous namespace
class ClangPchManagerPluginData
@@ -83,10 +107,12 @@ public:
ClangBackEnd::ProjectPartsStorage<Sqlite::Database> projectPartsStorage{database};
PchManagerClient pchManagerClient{pchCreationProgressManager, dependencyCreationProgressManager};
PchManagerConnectionClient connectionClient{&pchManagerClient};
+ ClangIndexingSettingsManager settingsManager;
QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(),
pchManagerClient,
filePathCache,
- projectPartsStorage};
+ projectPartsStorage,
+ settingsManager};
};
std::unique_ptr<ClangPchManagerPluginData> ClangPchManagerPlugin::d;
@@ -102,6 +128,8 @@ bool ClangPchManagerPlugin::initialize(const QStringList & /*arguments*/, QStrin
startBackend();
+ addIndexingProjectPaneWidget(d->settingsManager);
+
return true;
}
@@ -133,4 +161,9 @@ PchManagerClient &ClangPchManagerPlugin::pchManagerClient()
return d->pchManagerClient;
}
+ClangIndexingSettingsManager &ClangPchManagerPlugin::settingsManager()
+{
+ return d->settingsManager;
+}
+
} // namespace ClangRefactoring
diff --git a/src/plugins/clangpchmanager/clangpchmanagerplugin.h b/src/plugins/clangpchmanager/clangpchmanagerplugin.h
index 60c7d2b266..f472b769b4 100644
--- a/src/plugins/clangpchmanager/clangpchmanagerplugin.h
+++ b/src/plugins/clangpchmanager/clangpchmanagerplugin.h
@@ -33,6 +33,7 @@
namespace ClangPchManager {
+class ClangIndexingSettingsManager;
class ClangPchManagerPluginData;
class PchManagerClient;
@@ -50,6 +51,7 @@ public:
ShutdownFlag aboutToShutdown();
static PchManagerClient &pchManagerClient();
+ static ClangIndexingSettingsManager &settingsManager();
private:
void startBackend();
diff --git a/src/plugins/clangpchmanager/pchmanagerprojectupdater.h b/src/plugins/clangpchmanager/pchmanagerprojectupdater.h
index fd1b98eab4..8d41e56476 100644
--- a/src/plugins/clangpchmanager/pchmanagerprojectupdater.h
+++ b/src/plugins/clangpchmanager/pchmanagerprojectupdater.h
@@ -35,8 +35,9 @@ public:
PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
PchManagerClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
- : ProjectUpdater(server, filePathCache, projectPartsStorage)
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangIndexingSettingsManager &settingsManager)
+ : ProjectUpdater(server, filePathCache, projectPartsStorage, settingsManager)
, m_client(client)
{}
diff --git a/src/plugins/clangpchmanager/preprocessormacrocollector.cpp b/src/plugins/clangpchmanager/preprocessormacrocollector.cpp
new file mode 100644
index 0000000000..03b38daeff
--- /dev/null
+++ b/src/plugins/clangpchmanager/preprocessormacrocollector.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "preprocessormacrocollector.h"
+
+namespace ClangPchManager {
+
+namespace {
+PreprocessorMacros toSortedMacros(const ProjectExplorer::Macros &macros)
+{
+ PreprocessorMacros sortedMacros;
+ sortedMacros.reserve(macros.size());
+
+ for (const ProjectExplorer::Macro &macro : macros)
+ if (macro.type == ProjectExplorer::MacroType::Define)
+ sortedMacros.push_back({QString::fromUtf8(macro.key), QString::fromUtf8(macro.value)});
+
+ std::sort(sortedMacros.begin(), sortedMacros.end());
+
+ return sortedMacros;
+}
+} // namespace
+
+void PreprocessorMacroCollector::add(const ProjectExplorer::Macros &macros)
+{
+ PreprocessorMacros sortedMacros = toSortedMacros(macros);
+ std::sort(sortedMacros.begin(), sortedMacros.end());
+
+ PreprocessorMacros mergedMacros;
+ mergedMacros.reserve(sortedMacros.size() + m_macros.size());
+
+ std::set_union(m_macros.begin(),
+ m_macros.end(),
+ sortedMacros.begin(),
+ sortedMacros.end(),
+ std::back_inserter(mergedMacros));
+
+ m_macros = mergedMacros;
+}
+
+const PreprocessorMacros &PreprocessorMacroCollector::macros() const
+{
+ return m_macros;
+}
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/preprocessormacrocollector.h b/src/plugins/clangpchmanager/preprocessormacrocollector.h
new file mode 100644
index 0000000000..2de2553df3
--- /dev/null
+++ b/src/plugins/clangpchmanager/preprocessormacrocollector.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QString>
+#include <QVector>
+
+#include <projectexplorer/projectmacro.h>
+
+#include <utility>
+
+namespace ClangPchManager {
+
+using PreprocessorMacro = std::pair<QString, QString>;
+using PreprocessorMacros = QVector<PreprocessorMacro>;
+
+class PreprocessorMacroCollector
+{
+public:
+ void add(const ProjectExplorer::Macros &macros);
+
+ const PreprocessorMacros &macros() const;
+
+private:
+ PreprocessorMacros m_macros;
+};
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/preprocessormacrowidget.cpp b/src/plugins/clangpchmanager/preprocessormacrowidget.cpp
new file mode 100644
index 0000000000..19c421935b
--- /dev/null
+++ b/src/plugins/clangpchmanager/preprocessormacrowidget.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "preprocessormacrowidget.h"
+#include "clangindexingprojectsettings.h"
+
+#include <utils/detailswidget.h>
+#include <utils/headerviewstretcher.h>
+#include <utils/itemviews.h>
+#include <utils/namevaluedictionary.h>
+#include <utils/namevalueitem.h>
+#include <utils/namevaluemodel.h>
+#include <utils/namevaluesdialog.h>
+#include <utils/namevaluevalidator.h>
+
+#include <coreplugin/find/itemviewfind.h>
+
+#include <QLineEdit>
+#include <QStyledItemDelegate>
+#include <QVBoxLayout>
+
+namespace ClangPchManager {
+
+class ProcessorMacroDelegate : public QStyledItemDelegate
+{
+public:
+ ProcessorMacroDelegate(Utils::NameValueModel *model, QTreeView *view)
+ : QStyledItemDelegate(view)
+ , m_model(model)
+ , m_view(view)
+ {}
+
+ QWidget *createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override
+ {
+ QWidget *w = QStyledItemDelegate::createEditor(parent, option, index);
+ if (index.column() != 0)
+ return w;
+
+ if (auto edit = qobject_cast<QLineEdit *>(w))
+ edit->setValidator(new Utils::NameValueValidator(
+ edit, m_model, m_view, index, PreprocessorMacroWidget::tr("Macro already exists.")));
+ return w;
+ }
+
+private:
+ Utils::NameValueModel *m_model;
+ QTreeView *m_view;
+};
+
+PreprocessorMacroWidget::PreprocessorMacroWidget(QWidget *parent) : QWidget(parent)
+{
+ m_model = std::make_unique<Utils::NameValueModel>();
+ connect(m_model.get(),
+ &Utils::NameValueModel::userChangesChanged,
+ this,
+ &PreprocessorMacroWidget::userChangesChanged);
+ connect(m_model.get(),
+ &QAbstractItemModel::modelReset,
+ this,
+ &PreprocessorMacroWidget::invalidateCurrentIndex);
+
+ connect(m_model.get(), &Utils::NameValueModel::focusIndex, this, &PreprocessorMacroWidget::focusIndex);
+
+ auto vbox = new QVBoxLayout(this);
+ vbox->setContentsMargins(0, 0, 0, 0);
+
+ m_detailsContainer = new Utils::DetailsWidget(this);
+
+ auto details = new QWidget(m_detailsContainer);
+ m_detailsContainer->setWidget(details);
+ details->setVisible(false);
+
+ auto vbox2 = new QVBoxLayout(details);
+ vbox2->setMargin(0);
+
+ auto horizontalLayout = new QHBoxLayout;
+ horizontalLayout->setMargin(0);
+ auto tree = new Utils::TreeView(this);
+ connect(tree, &QAbstractItemView::activated, tree, [tree](const QModelIndex &idx) {
+ tree->edit(idx);
+ });
+ m_preprocessorMacrosView = tree;
+ m_preprocessorMacrosView->setModel(m_model.get());
+ m_preprocessorMacrosView->setItemDelegate(
+ new ProcessorMacroDelegate(m_model.get(), m_preprocessorMacrosView));
+ m_preprocessorMacrosView->setMinimumHeight(400);
+ m_preprocessorMacrosView->setRootIsDecorated(false);
+ m_preprocessorMacrosView->setUniformRowHeights(true);
+ new Utils::HeaderViewStretcher(m_preprocessorMacrosView->header(), 1);
+ m_preprocessorMacrosView->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_preprocessorMacrosView->setSelectionBehavior(QAbstractItemView::SelectItems);
+ m_preprocessorMacrosView->setFrameShape(QFrame::NoFrame);
+ QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_preprocessorMacrosView,
+ Core::ItemViewFind::LightColored);
+ findWrapper->setFrameStyle(QFrame::StyledPanel);
+ horizontalLayout->addWidget(findWrapper);
+
+ auto buttonLayout = new QVBoxLayout();
+
+ m_editButton = new QPushButton(this);
+ m_editButton->setText(tr("Ed&it"));
+ buttonLayout->addWidget(m_editButton);
+
+ m_addButton = new QPushButton(this);
+ m_addButton->setText(tr("&Add"));
+ buttonLayout->addWidget(m_addButton);
+
+ m_resetButton = new QPushButton(this);
+ m_resetButton->setEnabled(false);
+ m_resetButton->setText(tr("&Reset"));
+ buttonLayout->addWidget(m_resetButton);
+
+ m_unsetButton = new QPushButton(this);
+ m_unsetButton->setEnabled(false);
+ m_unsetButton->setText(tr("&Unset"));
+ buttonLayout->addWidget(m_unsetButton);
+
+ buttonLayout->addStretch();
+
+ horizontalLayout->addLayout(buttonLayout);
+ vbox2->addLayout(horizontalLayout);
+
+ vbox->addWidget(m_detailsContainer);
+
+ connect(m_model.get(),
+ &QAbstractItemModel::dataChanged,
+ this,
+ &PreprocessorMacroWidget::updateButtons);
+
+ connect(m_editButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::editButtonClicked);
+ connect(m_addButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::addButtonClicked);
+ connect(m_resetButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::removeButtonClicked);
+ connect(m_unsetButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::unsetButtonClicked);
+ connect(m_preprocessorMacrosView->selectionModel(),
+ &QItemSelectionModel::currentChanged,
+ this,
+ &PreprocessorMacroWidget::currentIndexChanged);
+ connect(m_detailsContainer,
+ &Utils::DetailsWidget::linkActivated,
+ this,
+ &PreprocessorMacroWidget::linkActivated);
+ connect(m_model.get(),
+ &Utils::NameValueModel::userChangesChanged,
+ this,
+ &PreprocessorMacroWidget::updateSummaryText);
+ connect(m_model.get(),
+ &Utils::NameValueModel::userChangesChanged,
+ this,
+ &PreprocessorMacroWidget::saveSettings);
+}
+
+void PreprocessorMacroWidget::setBasePreprocessorMacros(const PreprocessorMacros &macros)
+{
+ m_model->setUserChanges(m_settings->readMacros());
+ m_model->setBaseNameValueDictionary(Utils::NameValueDictionary{macros});
+}
+
+void PreprocessorMacroWidget::setSettings(ClangIndexingProjectSettings *settings)
+{
+ m_settings = settings;
+}
+
+PreprocessorMacroWidget::~PreprocessorMacroWidget() = default;
+
+void PreprocessorMacroWidget::updateButtons()
+{
+ currentIndexChanged(m_preprocessorMacrosView->currentIndex());
+}
+
+void PreprocessorMacroWidget::focusIndex(const QModelIndex &index)
+{
+ m_preprocessorMacrosView->setCurrentIndex(index);
+ m_preprocessorMacrosView->setFocus();
+
+ m_preprocessorMacrosView->scrollTo(index, QAbstractItemView::PositionAtTop);
+}
+
+void PreprocessorMacroWidget::invalidateCurrentIndex()
+{
+ currentIndexChanged(QModelIndex());
+}
+
+void PreprocessorMacroWidget::editButtonClicked()
+{
+ m_preprocessorMacrosView->edit(m_preprocessorMacrosView->currentIndex());
+}
+
+void PreprocessorMacroWidget::addButtonClicked()
+{
+ QModelIndex index = m_model->addVariable();
+ m_preprocessorMacrosView->setCurrentIndex(index);
+ m_preprocessorMacrosView->edit(index);
+}
+
+void PreprocessorMacroWidget::removeButtonClicked()
+{
+ const QString &name = m_model->indexToVariable(m_preprocessorMacrosView->currentIndex());
+ m_model->resetVariable(name);
+}
+
+void PreprocessorMacroWidget::unsetButtonClicked()
+{
+ const QString &name = m_model->indexToVariable(m_preprocessorMacrosView->currentIndex());
+ if (!m_model->canReset(name))
+ m_model->resetVariable(name);
+ else
+ m_model->unsetVariable(name);
+}
+
+void PreprocessorMacroWidget::currentIndexChanged(const QModelIndex &current)
+{
+ if (current.isValid()) {
+ m_editButton->setEnabled(true);
+ const QString &name = m_model->indexToVariable(current);
+ bool modified = m_model->canReset(name) && m_model->changes(name);
+ bool unset = m_model->canUnset(name);
+ m_resetButton->setEnabled(modified || unset);
+ m_unsetButton->setEnabled(!unset);
+ } else {
+ m_editButton->setEnabled(false);
+ m_resetButton->setEnabled(false);
+ m_unsetButton->setEnabled(false);
+ }
+}
+
+void PreprocessorMacroWidget::linkActivated(const QString &link)
+{
+ m_detailsContainer->setState(Utils::DetailsWidget::Expanded);
+ QModelIndex idx = m_model->variableToIndex(link);
+ focusIndex(idx);
+}
+
+void PreprocessorMacroWidget::updateSummaryText()
+{
+ Utils::NameValueItems items = m_model->userChanges();
+ Utils::NameValueItem::sort(&items);
+
+ QString text;
+ for (const Utils::EnvironmentItem &item : items) {
+ if (item.name != Utils::NameValueModel::tr("<VARIABLE>")) {
+ text.append(QLatin1String("<br>"));
+ if (item.operation == Utils::NameValueItem::Unset)
+ text.append(tr("Unset <a href=\"%1\"><b>%1</b></a>").arg(item.name.toHtmlEscaped()));
+ else
+ text.append(tr("Set <a href=\"%1\"><b>%1</b></a> to <b>%2</b>")
+ .arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped()));
+ }
+ }
+
+ m_detailsContainer->setSummaryText(text);
+}
+
+void PreprocessorMacroWidget::saveSettings()
+{
+ m_settings->saveMacros(m_model->userChanges());
+}
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/preprocessormacrowidget.h b/src/plugins/clangpchmanager/preprocessormacrowidget.h
new file mode 100644
index 0000000000..0c4c01545c
--- /dev/null
+++ b/src/plugins/clangpchmanager/preprocessormacrowidget.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QPushButton>
+#include <QTreeView>
+
+#include <memory>
+
+namespace Utils {
+class DetailsWidget;
+class NameValueModel;
+} // namespace Utils
+
+namespace ClangPchManager {
+class ClangIndexingProjectSettings;
+using PreprocessorMacro = std::pair<QString, QString>;
+using PreprocessorMacros = QVector<PreprocessorMacro>;
+
+class PreprocessorMacroWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit PreprocessorMacroWidget(QWidget *parent = nullptr);
+ ~PreprocessorMacroWidget() override;
+ void setBasePreprocessorMacros(const PreprocessorMacros &macros);
+ void setSettings(ClangIndexingProjectSettings *settings);
+
+signals:
+ void userChangesChanged();
+
+private:
+ void updateButtons();
+ void focusIndex(const QModelIndex &index);
+ void invalidateCurrentIndex();
+ void editButtonClicked();
+ void addButtonClicked();
+ void removeButtonClicked();
+ void unsetButtonClicked();
+ void currentIndexChanged(const QModelIndex &current);
+ void linkActivated(const QString &link);
+ void updateSummaryText();
+ void saveSettings();
+
+private:
+ std::unique_ptr<Utils::NameValueModel> m_model;
+ Utils::DetailsWidget *m_detailsContainer;
+ QTreeView *m_preprocessorMacrosView;
+ QPushButton *m_editButton;
+ QPushButton *m_addButton;
+ QPushButton *m_resetButton;
+ QPushButton *m_unsetButton;
+ ClangIndexingProjectSettings *m_settings = {};
+};
+
+} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp
index 3d340aea88..a26ae9e203 100644
--- a/src/plugins/clangpchmanager/projectupdater.cpp
+++ b/src/plugins/clangpchmanager/projectupdater.cpp
@@ -27,6 +27,8 @@
#include "pchmanagerclient.h"
+#include <clangindexingprojectsettings.h>
+#include <clangindexingsettingsmanager.h>
#include <filepathid.h>
#include <pchmanagerserverinterface.h>
#include <removegeneratedfilesmessage.h>
@@ -42,6 +44,7 @@
#include <projectexplorer/buildconfiguration.h>
#include <utils/algorithm.h>
+#include <utils/namevalueitem.h>
#include <algorithm>
#include <functional>
@@ -175,9 +178,63 @@ void cleanupMacros(ClangBackEnd::CompilerMacros &macros)
macros.erase(newEnd, macros.end());
}
+
+void updateWithSettings(ClangBackEnd::CompilerMacros &macros,
+ Utils::NameValueItems &&settingsItems,
+ int &index)
+{
+ std::sort(settingsItems.begin(), settingsItems.end(), [](const auto &first, const auto &second) {
+ return std::tie(first.operation, first.name, first.value)
+ < std::tie(first.operation, second.name, second.value);
+ });
+
+ auto point = std::partition_point(settingsItems.begin(), settingsItems.end(), [](const auto &entry) {
+ return entry.operation == Utils::NameValueItem::Set;
+ });
+
+ std::transform(
+ settingsItems.begin(),
+ point,
+ std::back_inserter(macros),
+ [&](const Utils::NameValueItem &settingsMacro) {
+ return ClangBackEnd::CompilerMacro{settingsMacro.name, settingsMacro.value, ++index};
+ });
+
+ std::sort(macros.begin(), macros.end(), [](const auto &first, const auto &second) {
+ return std::tie(first.key, first.value) < std::tie(second.key, second.value);
+ });
+
+ ClangBackEnd::CompilerMacros result;
+ result.reserve(macros.size());
+
+ ClangBackEnd::CompilerMacros convertedSettingsMacros;
+ convertedSettingsMacros.resize(std::distance(point, settingsItems.end()));
+ std::transform(
+ point,
+ settingsItems.end(),
+ std::back_inserter(convertedSettingsMacros),
+ [&](const Utils::NameValueItem &settingsMacro) {
+ return ClangBackEnd::CompilerMacro{settingsMacro.name, settingsMacro.value, ++index};
+ });
+
+ std::set_difference(macros.begin(),
+ macros.end(),
+ convertedSettingsMacros.begin(),
+ convertedSettingsMacros.end(),
+ std::back_inserter(result),
+ [](const ClangBackEnd::CompilerMacro &first,
+ const ClangBackEnd::CompilerMacro &second) {
+ return std::tie(first.key, first.value)
+ < std::tie(second.key, second.value);
+ });
+
+ macros = std::move(result);
+}
+
} // namespace
-ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectExplorer::Macros &projectMacros)
+ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(
+ const ProjectExplorer::Macros &projectMacros, Utils::NameValueItems &&settingsMacros) const
{
int index = 0;
auto macros = Utils::transform<ClangBackEnd::CompilerMacros>(
@@ -186,6 +243,7 @@ ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectE
});
cleanupMacros(macros);
+ updateWithSettings(macros, std::move(settingsMacros), index);
std::sort(macros.begin(), macros.end());
@@ -291,9 +349,12 @@ ClangBackEnd::ProjectPartContainer ProjectUpdater::toProjectPartContainer(
ClangBackEnd::ProjectPartId projectPartId = m_projectPartsStorage.fetchProjectPartId(
projectPartName);
+ ClangIndexingProjectSettings *settings = m_settingsManager.settings(projectPart->project);
+
return ClangBackEnd::ProjectPartContainer(projectPartId,
Utils::SmallStringVector(arguments),
- createCompilerMacros(projectPart->projectMacros),
+ createCompilerMacros(projectPart->projectMacros,
+ settings->readMacros()),
std::move(includeSearchPaths.system),
std::move(includeSearchPaths.project),
std::move(headerAndSources.headers),
diff --git a/src/plugins/clangpchmanager/projectupdater.h b/src/plugins/clangpchmanager/projectupdater.h
index 044b86f637..4c4300d194 100644
--- a/src/plugins/clangpchmanager/projectupdater.h
+++ b/src/plugins/clangpchmanager/projectupdater.h
@@ -37,6 +37,8 @@
#include <projectexplorer/headerpath.h>
+#include <utils/environmentfwd.h>
+
namespace ProjectExplorer {
class Macro;
using Macros = QVector<Macro>;
@@ -59,6 +61,8 @@ namespace ClangPchManager {
class HeaderAndSources;
class PchManagerClient;
+class ClangIndexingSettingsManager;
+class ClangIndexingProjectSettings;
class CLANGPCHMANAGER_EXPORT ProjectUpdater
{
@@ -71,10 +75,12 @@ public:
ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangIndexingSettingsManager &settingsManager)
: m_server(server)
, m_filePathCache(filePathCache)
, m_projectPartsStorage(projectPartsStorage)
+ , m_settingsManager(settingsManager)
{}
void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts,
@@ -98,8 +104,8 @@ public:
void addToHeaderAndSources(HeaderAndSources &headerAndSources,
const CppTools::ProjectFile &projectFile) const;
static QStringList toolChainArguments(CppTools::ProjectPart *projectPart);
- static ClangBackEnd::CompilerMacros createCompilerMacros(
- const ProjectExplorer::Macros &projectMacros);
+ ClangBackEnd::CompilerMacros createCompilerMacros(const ProjectExplorer::Macros &projectMacros,
+ Utils::NameValueItems &&settingsMacros) const;
static SystemAndProjectIncludeSearchPaths createIncludeSearchPaths(
const CppTools::ProjectPart &projectPart);
static ClangBackEnd::FilePaths createExcludedPaths(
@@ -115,6 +121,7 @@ private:
ClangBackEnd::ProjectManagementServerInterface &m_server;
ClangBackEnd::FilePathCachingInterface &m_filePathCache;
ClangBackEnd::ProjectPartsStorageInterface &m_projectPartsStorage;
+ ClangIndexingSettingsManager &m_settingsManager;
};
} // namespace ClangPchManager
diff --git a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h
index 1cdef70b79..143ffea655 100644
--- a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h
+++ b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h
@@ -59,8 +59,9 @@ public:
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClientType &client,
ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
- : ProjectUpdaterType(server, client, filePathCache, projectPartsStorage)
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangIndexingSettingsManager &settingsManager)
+ : ProjectUpdaterType(server, client, filePathCache, projectPartsStorage, settingsManager)
{
connectToCppModelManager();
}
@@ -74,7 +75,6 @@ public:
void projectPartsUpdated(ProjectExplorer::Project *project)
{
-
ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project), {}); // TODO add support for toolchainarguments
}
diff --git a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp
index 059eff4c78..03917ebd13 100644
--- a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp
+++ b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp
@@ -42,8 +42,8 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
-#include <extensionsystem/pluginmanager.h>
#include <cpptools/cpptoolsconstants.h>
+#include <extensionsystem/pluginmanager.h>
#include <refactoringdatabaseinitializer.h>
#include <filepathcaching.h>
@@ -103,16 +103,13 @@ public:
QtCreatorRefactoringProjectUpdater projectUpdate{connectionClient.serverProxy(),
ClangPchManagerPlugin::pchManagerClient(),
filePathCache,
- projectPartsStorage};
+ projectPartsStorage,
+ ClangPchManagerPlugin::settingsManager()};
};
-ClangRefactoringPlugin::ClangRefactoringPlugin()
-{
-}
+ClangRefactoringPlugin::ClangRefactoringPlugin() = default;
-ClangRefactoringPlugin::~ClangRefactoringPlugin()
-{
-}
+ClangRefactoringPlugin::~ClangRefactoringPlugin() = default;
static bool useClangFilters()
{
@@ -131,8 +128,8 @@ bool ClangRefactoringPlugin::initialize(const QStringList & /*arguments*/, QStri
connectBackend();
startBackend();
- CppTools::CppModelManager::addRefactoringEngine(
- CppTools::RefactoringEngineType::ClangRefactoring, &refactoringEngine());
+ CppTools::CppModelManager::addRefactoringEngine(CppTools::RefactoringEngineType::ClangRefactoring,
+ &refactoringEngine());
initializeFilters();
diff --git a/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.cpp b/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.cpp
index dea3ccfeec..2d71b7b9fb 100644
--- a/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.cpp
+++ b/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.cpp
@@ -64,12 +64,14 @@ QtCreatorRefactoringProjectUpdater::QtCreatorRefactoringProjectUpdater(
ClangBackEnd::ProjectManagementServerInterface &server,
ClangPchManager::PchManagerClient &pchManagerClient,
ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangPchManager::ClangIndexingSettingsManager &settingsManager)
: RefactoringProjectUpdater(server,
pchManagerClient,
*cppModelManager(),
filePathCache,
- projectPartsStorage)
+ projectPartsStorage,
+ settingsManager)
{
connectToCppModelManager();
}
diff --git a/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.h b/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.h
index 85d635a3af..7fd16afa16 100644
--- a/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.h
+++ b/src/plugins/clangrefactoring/qtcreatorrefactoringprojectupdater.h
@@ -32,11 +32,11 @@ namespace ClangRefactoring {
class QtCreatorRefactoringProjectUpdater final : public RefactoringProjectUpdater
{
public:
- QtCreatorRefactoringProjectUpdater(
- ClangBackEnd::ProjectManagementServerInterface &server,
- ClangPchManager::PchManagerClient &pchManagerClient,
- ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage);
+ QtCreatorRefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
+ ClangPchManager::PchManagerClient &pchManagerClient,
+ ClangBackEnd::FilePathCachingInterface &filePathCache,
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangPchManager::ClangIndexingSettingsManager &settingsManager);
private:
void abstractEditorUpdated(const QString &filePath, const QByteArray &contents);
diff --git a/src/plugins/clangrefactoring/refactoringprojectupdater.h b/src/plugins/clangrefactoring/refactoringprojectupdater.h
index a9559ef94e..643bf74667 100644
--- a/src/plugins/clangrefactoring/refactoringprojectupdater.h
+++ b/src/plugins/clangrefactoring/refactoringprojectupdater.h
@@ -40,8 +40,9 @@ public:
ClangPchManager::PchManagerClient &pchManagerClient,
CppTools::CppModelManagerInterface &cppModelManager,
ClangBackEnd::FilePathCachingInterface &filePathCache,
- ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
- : ClangPchManager::ProjectUpdater(server, filePathCache, projectPartsStorage)
+ ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
+ ClangPchManager::ClangIndexingSettingsManager &settingsManager)
+ : ClangPchManager::ProjectUpdater(server, filePathCache, projectPartsStorage, settingsManager)
, ClangPchManager::PchManagerNotifierInterface(pchManagerClient)
, m_cppModelManager(cppModelManager)
{
diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
index 62f7030c6d..59e73c8e35 100644
--- a/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
+++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.cpp
@@ -630,19 +630,16 @@ void ExternalToolConfig::updateEffectiveArguments()
void ExternalToolConfig::editEnvironmentChanges()
{
- bool ok;
const QString placeholderText = Utils::HostOsInfo::isWindowsHost()
? tr("PATH=C:\\dev\\bin;${PATH}")
: tr("PATH=/opt/bin:${PATH}");
- const QList<Utils::EnvironmentItem> newItems =
- Utils::EnvironmentDialog::getEnvironmentItems(&ok, ui->environmentLabel,
- m_environment,
- placeholderText);
- if (!ok)
- return;
-
- m_environment = newItems;
- updateEnvironmentLabel();
+ const auto newItems = Utils::EnvironmentDialog::getEnvironmentItems(ui->environmentLabel,
+ m_environment,
+ placeholderText);
+ if (newItems) {
+ m_environment = *newItems;
+ updateEnvironmentLabel();
+ }
}
void ExternalToolConfig::updateEnvironmentLabel()
diff --git a/src/plugins/coreplugin/dialogs/externaltoolconfig.h b/src/plugins/coreplugin/dialogs/externaltoolconfig.h
index 298b70c54f..386eeee38a 100644
--- a/src/plugins/coreplugin/dialogs/externaltoolconfig.h
+++ b/src/plugins/coreplugin/dialogs/externaltoolconfig.h
@@ -27,14 +27,14 @@
#include "../externaltool.h"
+#include <utils/environmentfwd.h>
+
#include <QAbstractItemModel>
#include <QDialog>
#include <QWidget>
QT_FORWARD_DECLARE_CLASS(QPlainTextEdit)
-namespace Utils { class EnvironmentItem; }
-
namespace Core {
namespace Internal {
@@ -108,9 +108,9 @@ private:
void updateEnvironmentLabel();
Ui::ExternalToolConfig *ui;
- QList<Utils::EnvironmentItem> m_environment;
+ Utils::EnvironmentItems m_environment;
ExternalToolModel *m_model;
};
} // Internal
-} // Core
+} // namespace Core
diff --git a/src/plugins/coreplugin/externaltool.cpp b/src/plugins/coreplugin/externaltool.cpp
index 0ef88fb3fa..93a688324d 100644
--- a/src/plugins/coreplugin/externaltool.cpp
+++ b/src/plugins/coreplugin/externaltool.cpp
@@ -190,7 +190,7 @@ Environment ExternalTool::baseEnvironment() const
return Environment::systemEnvironment();
}
-QList<EnvironmentItem> ExternalTool::environmentUserChanges() const
+EnvironmentItems ExternalTool::environmentUserChanges() const
{
return m_environment;
}
@@ -297,7 +297,7 @@ void ExternalTool::setBaseEnvironmentProviderId(Id id)
m_baseEnvironmentProviderId = id;
}
-void ExternalTool::setEnvironmentUserChanges(const QList<EnvironmentItem> &items)
+void ExternalTool::setEnvironmentUserChanges(const EnvironmentItems &items)
{
m_environment = items;
}
@@ -600,10 +600,10 @@ bool ExternalToolRunner::resolve()
m_resolvedEnvironment = m_tool->baseEnvironment();
MacroExpander *expander = globalMacroExpander();
- QList<EnvironmentItem> expandedEnvironment
- = Utils::transform(m_tool->environmentUserChanges(), [expander](const EnvironmentItem &item) {
- return EnvironmentItem(item.name, expander->expand(item.value), item.operation);
- });
+ EnvironmentItems expandedEnvironment = Utils::transform(
+ m_tool->environmentUserChanges(), [expander](const EnvironmentItem &item) {
+ return EnvironmentItem(item.name, expander->expand(item.value), item.operation);
+ });
m_resolvedEnvironment.modify(expandedEnvironment);
{
diff --git a/src/plugins/coreplugin/externaltool.h b/src/plugins/coreplugin/externaltool.h
index 394ee091a5..4294615cb9 100644
--- a/src/plugins/coreplugin/externaltool.h
+++ b/src/plugins/coreplugin/externaltool.h
@@ -71,7 +71,7 @@ public:
QString workingDirectory() const;
Id baseEnvironmentProviderId() const;
Utils::Environment baseEnvironment() const;
- QList<Utils::EnvironmentItem> environmentUserChanges() const;
+ Utils::EnvironmentItems environmentUserChanges() const;
void setFileName(const QString &fileName);
void setPreset(QSharedPointer<ExternalTool> preset);
@@ -101,7 +101,7 @@ public:
void setInput(const QString &input);
void setWorkingDirectory(const QString &workingDirectory);
void setBaseEnvironmentProviderId(Id id);
- void setEnvironmentUserChanges(const QList<Utils::EnvironmentItem> &items);
+ void setEnvironmentUserChanges(const Utils::EnvironmentItems &items);
private:
QString m_id;
@@ -114,7 +114,7 @@ private:
QString m_input;
QString m_workingDirectory;
Id m_baseEnvironmentProviderId;
- QList<Utils::EnvironmentItem> m_environment;
+ Utils::EnvironmentItems m_environment;
OutputHandling m_outputHandling = ShowInPane;
OutputHandling m_errorHandling = ShowInPane;
bool m_modifiesCurrentDocument = false;
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index e267822b97..31226e5e85 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -319,12 +319,12 @@ bool BuildConfiguration::useSystemEnvironment() const
return !m_clearSystemEnvironment;
}
-QList<Utils::EnvironmentItem> BuildConfiguration::userEnvironmentChanges() const
+Utils::EnvironmentItems BuildConfiguration::userEnvironmentChanges() const
{
return m_userEnvironmentChanges;
}
-void BuildConfiguration::setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff)
+void BuildConfiguration::setUserEnvironmentChanges(const Utils::EnvironmentItems &diff)
{
if (m_userEnvironmentChanges == diff)
return;
diff --git a/src/plugins/projectexplorer/buildconfiguration.h b/src/plugins/projectexplorer/buildconfiguration.h
index c9ba394946..2d260ad4a3 100644
--- a/src/plugins/projectexplorer/buildconfiguration.h
+++ b/src/plugins/projectexplorer/buildconfiguration.h
@@ -62,8 +62,8 @@ public:
Utils::Environment baseEnvironment() const;
QString baseEnvironmentText() const;
Utils::Environment environment() const;
- void setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff);
- QList<Utils::EnvironmentItem> userEnvironmentChanges() const;
+ void setUserEnvironmentChanges(const Utils::EnvironmentItems &diff);
+ Utils::EnvironmentItems userEnvironmentChanges() const;
bool useSystemEnvironment() const;
void setUseSystemEnvironment(bool b);
@@ -117,7 +117,7 @@ private:
void emitBuildDirectoryChanged();
bool m_clearSystemEnvironment = false;
- QList<Utils::EnvironmentItem> m_userEnvironmentChanges;
+ Utils::EnvironmentItems m_userEnvironmentChanges;
QList<BuildStepList *> m_stepLists;
ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr;
Utils::FilePath m_lastEmmitedBuildDirectory;
diff --git a/src/plugins/projectexplorer/environmentaspect.cpp b/src/plugins/projectexplorer/environmentaspect.cpp
index 0b0eff1e37..68eff43620 100644
--- a/src/plugins/projectexplorer/environmentaspect.cpp
+++ b/src/plugins/projectexplorer/environmentaspect.cpp
@@ -62,7 +62,7 @@ void EnvironmentAspect::setBaseEnvironmentBase(int base)
}
}
-void EnvironmentAspect::setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff)
+void EnvironmentAspect::setUserEnvironmentChanges(const Utils::EnvironmentItems &diff)
{
if (m_userChanges != diff) {
m_userChanges = diff;
diff --git a/src/plugins/projectexplorer/environmentaspect.h b/src/plugins/projectexplorer/environmentaspect.h
index 6657d1dfe8..ef5ed2907e 100644
--- a/src/plugins/projectexplorer/environmentaspect.h
+++ b/src/plugins/projectexplorer/environmentaspect.h
@@ -49,8 +49,8 @@ public:
int baseEnvironmentBase() const;
void setBaseEnvironmentBase(int base);
- QList<Utils::EnvironmentItem> userEnvironmentChanges() const { return m_userChanges; }
- void setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff);
+ Utils::EnvironmentItems userEnvironmentChanges() const { return m_userChanges; }
+ void setUserEnvironmentChanges(const Utils::EnvironmentItems &diff);
void addSupportedBaseEnvironment(const QString &displayName,
const std::function<Utils::Environment()> &getter);
@@ -70,7 +70,7 @@ public:
signals:
void baseEnvironmentChanged();
- void userEnvironmentChangesChanged(const QList<Utils::EnvironmentItem> &diff);
+ void userEnvironmentChangesChanged(const Utils::EnvironmentItems &diff);
void environmentChanged();
protected:
@@ -88,7 +88,7 @@ private:
QString displayName;
};
- QList<Utils::EnvironmentItem> m_userChanges;
+ Utils::EnvironmentItems m_userChanges;
QList<EnvironmentModifier> m_modifiers;
QList<BaseEnvironment> m_baseEnvironments;
int m_base = -1;
diff --git a/src/plugins/projectexplorer/environmentaspectwidget.cpp b/src/plugins/projectexplorer/environmentaspectwidget.cpp
index 0898a3f1b6..db341ab609 100644
--- a/src/plugins/projectexplorer/environmentaspectwidget.cpp
+++ b/src/plugins/projectexplorer/environmentaspectwidget.cpp
@@ -132,7 +132,7 @@ void EnvironmentAspectWidget::userChangesEdited()
m_ignoreChange = false;
}
-void EnvironmentAspectWidget::changeUserChanges(QList<Utils::EnvironmentItem> changes)
+void EnvironmentAspectWidget::changeUserChanges(Utils::EnvironmentItems changes)
{
if (m_ignoreChange)
return;
diff --git a/src/plugins/projectexplorer/environmentaspectwidget.h b/src/plugins/projectexplorer/environmentaspectwidget.h
index 6ca8164f05..44acee2f61 100644
--- a/src/plugins/projectexplorer/environmentaspectwidget.h
+++ b/src/plugins/projectexplorer/environmentaspectwidget.h
@@ -61,7 +61,7 @@ private:
void baseEnvironmentSelected(int idx);
void changeBaseEnvironment();
void userChangesEdited();
- void changeUserChanges(QList<Utils::EnvironmentItem> changes);
+ void changeUserChanges(Utils::EnvironmentItems changes);
void environmentChanged();
EnvironmentAspect *m_aspect;
diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp
index d1dcd488fe..673aa61cfc 100644
--- a/src/plugins/projectexplorer/environmentwidget.cpp
+++ b/src/plugins/projectexplorer/environmentwidget.cpp
@@ -30,11 +30,12 @@
#include <utils/detailswidget.h>
#include <utils/environment.h>
-#include <utils/environmentmodel.h>
#include <utils/environmentdialog.h>
+#include <utils/environmentmodel.h>
#include <utils/headerviewstretcher.h>
#include <utils/hostosinfo.h>
#include <utils/itemviews.h>
+#include <utils/namevaluevalidator.h>
#include <utils/tooltip/tooltip.h>
#include <QDir>
@@ -51,48 +52,6 @@
namespace ProjectExplorer {
-class EnvironmentValidator : public QValidator
-{
- Q_OBJECT
-public:
- EnvironmentValidator(QWidget *parent, Utils::EnvironmentModel *model, QTreeView *view,
- const QModelIndex &index) :
- QValidator(parent), m_model(model), m_view(view), m_index(index)
- {
- m_hideTipTimer.setInterval(2000);
- m_hideTipTimer.setSingleShot(true);
- connect(&m_hideTipTimer, &QTimer::timeout,
- this, [](){Utils::ToolTip::hide();});
- }
-
- QValidator::State validate(QString &in, int &pos) const override
- {
- Q_UNUSED(pos)
- QModelIndex idx = m_model->variableToIndex(in);
- if (idx.isValid() && idx != m_index)
- return QValidator::Intermediate;
- Utils::ToolTip::hide();
- m_hideTipTimer.stop();
- return QValidator::Acceptable;
- }
-
- void fixup(QString &input) const override
- {
- Q_UNUSED(input)
-
- QPoint pos = m_view->mapToGlobal(m_view->visualRect(m_index).topLeft());
- pos -= Utils::ToolTip::offsetFromPosition();
- Utils::ToolTip::show(pos, tr("Variable already exists."));
- m_hideTipTimer.start();
- // do nothing
- }
-private:
- Utils::EnvironmentModel *m_model;
- QTreeView *m_view;
- QModelIndex m_index;
- mutable QTimer m_hideTipTimer;
-};
-
class EnvironmentDelegate : public QStyledItemDelegate
{
public:
@@ -108,7 +67,8 @@ public:
return w;
if (auto edit = qobject_cast<QLineEdit *>(w))
- edit->setValidator(new EnvironmentValidator(edit, m_model, m_view, index));
+ edit->setValidator(new Utils::NameValueValidator(
+ edit, m_model, m_view, index, EnvironmentWidget::tr("Variable already exists.")));
return w;
}
private:
@@ -301,12 +261,12 @@ void EnvironmentWidget::setBaseEnvironmentText(const QString &text)
updateSummaryText();
}
-QList<Utils::EnvironmentItem> EnvironmentWidget::userChanges() const
+Utils::EnvironmentItems EnvironmentWidget::userChanges() const
{
return d->m_model->userChanges();
}
-void EnvironmentWidget::setUserChanges(const QList<Utils::EnvironmentItem> &list)
+void EnvironmentWidget::setUserChanges(const Utils::EnvironmentItems &list)
{
d->m_model->setUserChanges(list);
updateSummaryText();
@@ -320,7 +280,7 @@ void EnvironmentWidget::setOpenTerminalFunc(const EnvironmentWidget::OpenTermina
void EnvironmentWidget::updateSummaryText()
{
- QList<Utils::EnvironmentItem> list = d->m_model->userChanges();
+ Utils::EnvironmentItems list = d->m_model->userChanges();
Utils::EnvironmentItem::sort(&list);
QString text;
@@ -455,14 +415,12 @@ void EnvironmentWidget::prependPathButtonClicked()
void EnvironmentWidget::batchEditEnvironmentButtonClicked()
{
- const QList<Utils::EnvironmentItem> changes = d->m_model->userChanges();
+ const Utils::EnvironmentItems changes = d->m_model->userChanges();
- bool ok;
- const QList<Utils::EnvironmentItem> newChanges = Utils::EnvironmentDialog::getEnvironmentItems(&ok, this, changes);
- if (!ok)
- return;
+ const auto newChanges = Utils::EnvironmentDialog::getEnvironmentItems(this, changes);
- d->m_model->setUserChanges(newChanges);
+ if (newChanges)
+ d->m_model->setUserChanges(*newChanges);
}
void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current)
@@ -491,5 +449,3 @@ void EnvironmentWidget::invalidateCurrentIndex()
}
} // namespace ProjectExplorer
-
-#include "environmentwidget.moc"
diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h
index 927dc9b0c1..2a7e84c024 100644
--- a/src/plugins/projectexplorer/environmentwidget.h
+++ b/src/plugins/projectexplorer/environmentwidget.h
@@ -27,6 +27,8 @@
#include "projectexplorer_export.h"
+#include <utils/environmentfwd.h>
+
#include <QWidget>
#include <functional>
@@ -34,11 +36,6 @@
QT_FORWARD_DECLARE_CLASS(QModelIndex)
-namespace Utils {
-class Environment;
-class EnvironmentItem;
-} // namespace Utils
-
namespace ProjectExplorer {
class EnvironmentWidgetPrivate;
@@ -56,8 +53,8 @@ public:
void setBaseEnvironmentText(const QString &text);
void setBaseEnvironment(const Utils::Environment &env);
- QList<Utils::EnvironmentItem> userChanges() const;
- void setUserChanges(const QList<Utils::EnvironmentItem> &list);
+ Utils::EnvironmentItems userChanges() const;
+ void setUserChanges(const Utils::EnvironmentItems &list);
using OpenTerminalFunc = std::function<void(const Utils::Environment &env)>;
void setOpenTerminalFunc(const OpenTerminalFunc &func);
diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp
index adcc8f180e..5c65198486 100644
--- a/src/plugins/projectexplorer/extracompiler.cpp
+++ b/src/plugins/projectexplorer/extracompiler.cpp
@@ -254,7 +254,7 @@ Utils::Environment ExtraCompiler::buildEnvironment() const
if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
return bc->environment();
} else {
- QList<Utils::EnvironmentItem> changes =
+ Utils::EnvironmentItems changes =
EnvironmentKitAspect::environmentChanges(target->kit());
Utils::Environment env = Utils::Environment::systemEnvironment();
env.modify(changes);
diff --git a/src/plugins/projectexplorer/kitinformation.cpp b/src/plugins/projectexplorer/kitinformation.cpp
index 4ca258df1a..562e090806 100644
--- a/src/plugins/projectexplorer/kitinformation.cpp
+++ b/src/plugins/projectexplorer/kitinformation.cpp
@@ -1150,7 +1150,7 @@ private:
void refresh() override
{
- const QList<Utils::EnvironmentItem> changes = currentEnvironment();
+ const Utils::EnvironmentItems changes = currentEnvironment();
QString shortSummary = Utils::EnvironmentItem::toStringList(changes).join(QLatin1String("; "));
QFontMetrics fm(m_summaryLabel->font());
shortSummary = fm.elidedText(shortSummary, Qt::ElideRight, m_summaryLabel->width());
@@ -1159,32 +1159,29 @@ private:
void editEnvironmentChanges()
{
- bool ok;
Utils::MacroExpander *expander = m_kit->macroExpander();
Utils::EnvironmentDialog::Polisher polisher = [expander](QWidget *w) {
Core::VariableChooser::addSupportForChildWidgets(w, expander);
};
- QList<Utils::EnvironmentItem>
- changes = Utils::EnvironmentDialog::getEnvironmentItems(&ok,
- m_summaryLabel,
- currentEnvironment(),
- QString(),
- polisher);
- if (!ok)
+ auto changes = Utils::EnvironmentDialog::getEnvironmentItems(m_summaryLabel,
+ currentEnvironment(),
+ QString(),
+ polisher);
+ if (!changes)
return;
if (Utils::HostOsInfo::isWindowsHost()) {
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
- if (m_vslangCheckbox->isChecked() && changes.indexOf(forceMSVCEnglishItem) < 0)
- changes.append(forceMSVCEnglishItem);
+ if (m_vslangCheckbox->isChecked() && changes->indexOf(forceMSVCEnglishItem) < 0)
+ changes->append(forceMSVCEnglishItem);
}
- EnvironmentKitAspect::setEnvironmentChanges(m_kit, changes);
+ EnvironmentKitAspect::setEnvironmentChanges(m_kit, *changes);
}
- QList<Utils::EnvironmentItem> currentEnvironment() const
+ Utils::EnvironmentItems currentEnvironment() const
{
- QList<Utils::EnvironmentItem> changes = EnvironmentKitAspect::environmentChanges(m_kit);
+ Utils::EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit);
if (Utils::HostOsInfo::isWindowsHost()) {
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
@@ -1207,8 +1204,7 @@ private:
"just forces UTF-8 output (may vary depending on the used MSVC "
"compiler)."));
connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) {
- QList<Utils::EnvironmentItem> changes
- = EnvironmentKitAspect::environmentChanges(m_kit);
+ Utils::EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit);
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0)
changes.removeAll(forceMSVCEnglishItem);
@@ -1254,7 +1250,7 @@ void EnvironmentKitAspect::fix(Kit *k)
const QVariant variant = k->value(EnvironmentKitAspect::id());
if (!variant.isNull() && !variant.canConvert(QVariant::List)) {
qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName()));
- setEnvironmentChanges(k, QList<Utils::EnvironmentItem>());
+ setEnvironmentChanges(k, Utils::EnvironmentItems());
}
}
@@ -1283,14 +1279,14 @@ Core::Id EnvironmentKitAspect::id()
return "PE.Profile.Environment";
}
-QList<Utils::EnvironmentItem> EnvironmentKitAspect::environmentChanges(const Kit *k)
+Utils::EnvironmentItems EnvironmentKitAspect::environmentChanges(const Kit *k)
{
if (k)
return Utils::EnvironmentItem::fromStringList(k->value(EnvironmentKitAspect::id()).toStringList());
- return QList<Utils::EnvironmentItem>();
+ return Utils::EnvironmentItems();
}
-void EnvironmentKitAspect::setEnvironmentChanges(Kit *k, const QList<Utils::EnvironmentItem> &changes)
+void EnvironmentKitAspect::setEnvironmentChanges(Kit *k, const Utils::EnvironmentItems &changes)
{
if (k)
k->setValue(EnvironmentKitAspect::id(), Utils::EnvironmentItem::toStringList(changes));
diff --git a/src/plugins/projectexplorer/kitinformation.h b/src/plugins/projectexplorer/kitinformation.h
index 037b4b9394..57660db588 100644
--- a/src/plugins/projectexplorer/kitinformation.h
+++ b/src/plugins/projectexplorer/kitinformation.h
@@ -186,8 +186,8 @@ public:
ItemList toUserOutput(const Kit *k) const override;
static Core::Id id();
- static QList<Utils::EnvironmentItem> environmentChanges(const Kit *k);
- static void setEnvironmentChanges(Kit *k, const QList<Utils::EnvironmentItem> &changes);
+ static Utils::EnvironmentItems environmentChanges(const Kit *k);
+ static void setEnvironmentChanges(Kit *k, const Utils::EnvironmentItems &changes);
};
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp
index 557a03a5d6..0343edb401 100644
--- a/src/plugins/projectexplorer/msvctoolchain.cpp
+++ b/src/plugins/projectexplorer/msvctoolchain.cpp
@@ -715,7 +715,7 @@ void MsvcToolChain::environmentModifications(
const Utils::Environment inEnv = Utils::Environment::systemEnvironment();
Utils::Environment outEnv;
QMap<QString, QString> envPairs;
- QList<Utils::EnvironmentItem> diff;
+ Utils::EnvironmentItems diff;
Utils::optional<QString> error = generateEnvironmentSettings(inEnv,
vcvarsBat,
varsBatArg,
@@ -764,7 +764,7 @@ void MsvcToolChain::initEnvModWatcher(const QFuture<GenerateEnvResult> &future)
m_envModWatcher.setFuture(future);
}
-void MsvcToolChain::updateEnvironmentModifications(QList<Utils::EnvironmentItem> modifications)
+void MsvcToolChain::updateEnvironmentModifications(Utils::EnvironmentItems modifications)
{
Utils::EnvironmentItem::sort(&modifications);
if (modifications != m_environmentModifications) {
diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h
index bc0adb00ba..4a2b5057a3 100644
--- a/src/plugins/projectexplorer/msvctoolchain.h
+++ b/src/plugins/projectexplorer/msvctoolchain.h
@@ -28,6 +28,7 @@
#include "abi.h"
#include "abiwidget.h"
#include "toolchain.h"
+#include "toolchaincache.h"
#include "toolchainconfigwidget.h"
#include <QFutureWatcher>
@@ -142,7 +143,7 @@ protected:
struct GenerateEnvResult
{
Utils::optional<QString> error;
- QList<Utils::EnvironmentItem> environmentItems;
+ Utils::EnvironmentItems environmentItems;
};
static void environmentModifications(QFutureInterface<GenerateEnvResult> &future,
QString vcvarsBat,
@@ -154,11 +155,11 @@ protected:
mutable HeaderPaths m_headerPaths;
private:
- void updateEnvironmentModifications(QList<Utils::EnvironmentItem> modifications);
+ void updateEnvironmentModifications(Utils::EnvironmentItems modifications);
void rescanForCompiler();
void detectInstalledAbis();
- mutable QList<Utils::EnvironmentItem> m_environmentModifications;
+ mutable Utils::EnvironmentItems m_environmentModifications;
mutable QFutureWatcher<GenerateEnvResult> m_envModWatcher;
mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment.
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
index e82e90fedc..a659a5dd66 100644
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
@@ -98,7 +98,7 @@ bool QmlProjectItem::matchesFile(const QString &filePath) const
return false;
}
-QList<Utils::EnvironmentItem> QmlProjectItem::environment() const
+Utils::EnvironmentItems QmlProjectItem::environment() const
{
return m_environment;
}
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
index 4ba9afcd5f..a6982443d9 100644
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
+++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
@@ -65,7 +65,7 @@ public:
void appendContent(QmlProjectContentItem *item) { m_content.append(item); }
- QList<Utils::EnvironmentItem> environment() const;
+ Utils::EnvironmentItems environment() const;
void addToEnviroment(const QString &key, const QString &value);
signals:
@@ -77,7 +77,7 @@ protected:
QStringList m_importPaths;
QStringList m_fileSelectors;
QString m_mainFile;
- QList<Utils::EnvironmentItem> m_environment;
+ Utils::EnvironmentItems m_environment;
QList<QmlProjectContentItem *> m_content; // content property
};
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 5b518ccc87..ecfe48378b 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -206,7 +206,7 @@ Utils::FilePath QmlProject::targetFile(const Utils::FilePath &sourceFile,
return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
}
-QList<Utils::EnvironmentItem> QmlProject::environment() const
+Utils::EnvironmentItems QmlProject::environment() const
{
if (m_projectItem)
return m_projectItem.data()->environment();
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index b3ce817f19..c75fa83614 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -69,7 +69,7 @@ public:
Utils::FilePath targetFile(const Utils::FilePath &sourceFile,
const ProjectExplorer::Target *target) const;
- QList<Utils::EnvironmentItem> environment() const;
+ Utils::EnvironmentItems environment() const;
QStringList customImportPaths() const;
QStringList customFileSelectors() const;
diff --git a/src/plugins/qnx/qnxconfiguration.cpp b/src/plugins/qnx/qnxconfiguration.cpp
index d05ae172ff..11a846e612 100644
--- a/src/plugins/qnx/qnxconfiguration.cpp
+++ b/src/plugins/qnx/qnxconfiguration.cpp
@@ -107,7 +107,7 @@ FilePath QnxConfiguration::qccCompilerPath() const
return m_qccCompiler;
}
-QList<EnvironmentItem> QnxConfiguration::qnxEnv() const
+EnvironmentItems QnxConfiguration::qnxEnv() const
{
return m_qnxEnv;
}
diff --git a/src/plugins/qnx/qnxconfiguration.h b/src/plugins/qnx/qnxconfiguration.h
index ebb77c825f..41649ce6bf 100644
--- a/src/plugins/qnx/qnxconfiguration.h
+++ b/src/plugins/qnx/qnxconfiguration.h
@@ -61,7 +61,7 @@ public:
Utils::FilePath qnxTarget() const;
Utils::FilePath qnxHost() const;
Utils::FilePath qccCompilerPath() const;
- QList<Utils::EnvironmentItem> qnxEnv() const;
+ Utils::EnvironmentItems qnxEnv() const;
QnxVersionNumber version() const;
QVariantMap toMap() const;
@@ -97,7 +97,7 @@ private:
Utils::FilePath m_qnxTarget;
Utils::FilePath m_qnxHost;
Utils::FilePath m_qccCompiler;
- QList<Utils::EnvironmentItem> m_qnxEnv;
+ Utils::EnvironmentItems m_qnxEnv;
QnxVersionNumber m_version;
class Target
diff --git a/src/plugins/qnx/qnxqtversion.cpp b/src/plugins/qnx/qnxqtversion.cpp
index ffddcf7811..b096f16a80 100644
--- a/src/plugins/qnx/qnxqtversion.cpp
+++ b/src/plugins/qnx/qnxqtversion.cpp
@@ -184,7 +184,7 @@ void QnxQtVersion::updateEnvironment() const
}
}
-QList<Utils::EnvironmentItem> QnxQtVersion::environment() const
+Utils::EnvironmentItems QnxQtVersion::environment() const
{
return QnxUtils::qnxEnvironment(sdpPath());
}
diff --git a/src/plugins/qnx/qnxqtversion.h b/src/plugins/qnx/qnxqtversion.h
index 6479954bf8..d41e19852c 100644
--- a/src/plugins/qnx/qnxqtversion.h
+++ b/src/plugins/qnx/qnxqtversion.h
@@ -73,13 +73,13 @@ protected:
private:
void updateEnvironment() const;
- QList<Utils::EnvironmentItem> environment() const;
+ Utils::EnvironmentItems environment() const;
QString m_sdpPath;
mutable QString m_cpuDir;
mutable bool m_environmentUpToDate = false;
- mutable QList<Utils::EnvironmentItem> m_qnxEnv;
+ mutable Utils::EnvironmentItems m_qnxEnv;
};
class QnxQtVersionFactory : public QtSupport::QtVersionFactory
diff --git a/src/plugins/qnx/qnxtoolchain.cpp b/src/plugins/qnx/qnxtoolchain.cpp
index 376ae63711..30c1f9b475 100644
--- a/src/plugins/qnx/qnxtoolchain.cpp
+++ b/src/plugins/qnx/qnxtoolchain.cpp
@@ -50,7 +50,7 @@ static Abis detectTargetAbis(const FilePath &sdpPath)
FilePath qnxTarget;
if (!sdpPath.fileName().isEmpty()) {
- QList<Utils::EnvironmentItem> environment = QnxUtils::qnxEnvironment(sdpPath.toString());
+ Utils::EnvironmentItems environment = QnxUtils::qnxEnvironment(sdpPath.toString());
foreach (const Utils::EnvironmentItem &item, environment) {
if (item.name == QLatin1Literal("QNX_TARGET"))
qnxTarget = FilePath::fromString(item.value);
@@ -72,12 +72,11 @@ static Abis detectTargetAbis(const FilePath &sdpPath)
return result;
}
-static void setQnxEnvironment(Environment &env, const QList<EnvironmentItem> &qnxEnv)
+static void setQnxEnvironment(Environment &env, const EnvironmentItems &qnxEnv)
{
// We only need to set QNX_HOST and QNX_TARGET needed when running qcc
foreach (const EnvironmentItem &item, qnxEnv) {
- if (item.name == QLatin1String("QNX_HOST") ||
- item.name == QLatin1String("QNX_TARGET") )
+ if (item.name == QLatin1String("QNX_HOST") || item.name == QLatin1String("QNX_TARGET"))
env.set(item.name, item.value);
}
}
diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp
index 9d61864558..3d34dd74bb 100644
--- a/src/plugins/qnx/qnxutils.cpp
+++ b/src/plugins/qnx/qnxutils.cpp
@@ -73,9 +73,9 @@ QString QnxUtils::cpuDirShortDescription(const QString &cpuDir)
return cpuDir;
}
-QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileName)
+Utils::EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const QString &fileName)
{
- QList <Utils::EnvironmentItem> items;
+ Utils::EnvironmentItems items;
if (!QFileInfo::exists(fileName))
return items;
@@ -206,7 +206,7 @@ QList<ConfigInstallInformation> QnxUtils::installedConfigs(const QString &config
return sdpList;
}
-QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdpPath)
+Utils::EnvironmentItems QnxUtils::qnxEnvironment(const QString &sdpPath)
{
return qnxEnvironmentFromEnvFile(envFilePath(sdpPath));
}
diff --git a/src/plugins/qnx/qnxutils.h b/src/plugins/qnx/qnxutils.h
index ae8367e43b..63ef5dd86e 100644
--- a/src/plugins/qnx/qnxutils.h
+++ b/src/plugins/qnx/qnxutils.h
@@ -70,11 +70,11 @@ class QnxUtils
public:
static QString addQuotes(const QString &string);
static QString cpuDirShortDescription(const QString &cpuDir);
- static QList<Utils::EnvironmentItem> qnxEnvironmentFromEnvFile(const QString &fileName);
+ static Utils::EnvironmentItems qnxEnvironmentFromEnvFile(const QString &fileName);
static QString envFilePath(const QString &sdpPath);
static QString defaultTargetVersion(const QString &sdpPath);
static QList<ConfigInstallInformation> installedConfigs(const QString &configPath = QString());
- static QList<Utils::EnvironmentItem> qnxEnvironment(const QString &sdpPath);
+ static Utils::EnvironmentItems qnxEnvironment(const QString &sdpPath);
static QList<QnxTarget> findTargets(const Utils::FilePath &basePath);
static ProjectExplorer::Abi convertAbi(const ProjectExplorer::Abi &abi);
static ProjectExplorer::Abis convertAbis(const ProjectExplorer::Abis &abis);
diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp
index 36d2d03e2d..4b8c4a5ad8 100644
--- a/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp
+++ b/src/plugins/remotelinux/remotelinuxenvironmentaspect.cpp
@@ -34,7 +34,7 @@ const char DISPLAY_KEY[] = "DISPLAY";
const char VERSION_KEY[] = "RemoteLinux.EnvironmentAspect.Version";
const int ENVIRONMENTASPECT_VERSION = 1; // Version was introduced in 4.3 with the value 1
-static bool displayAlreadySet(const QList<Utils::EnvironmentItem> &changes)
+static bool displayAlreadySet(const Utils::EnvironmentItems &changes)
{
return Utils::contains(changes, [](const Utils::EnvironmentItem &item) {
return item.name == DISPLAY_KEY;
diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp
index b4bafcc8ad..1634512b50 100644
--- a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp
+++ b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp
@@ -102,6 +102,7 @@ newFrontendActionFactory(Factory *consumerFactory,
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
{
compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true;
+ compilerInstance.getDiagnosticOpts().ErrorLimit = 1;
return clang::ASTFrontendAction::BeginInvocation(compilerInstance);
}
diff --git a/src/tools/sdktool/sdktool.pro b/src/tools/sdktool/sdktool.pro
index 9869d50dc4..379a1b10ca 100644
--- a/src/tools/sdktool/sdktool.pro
+++ b/src/tools/sdktool/sdktool.pro
@@ -33,6 +33,8 @@ SOURCES += \
$$UTILS/environment.cpp \
$$UTILS/fileutils.cpp \
$$UTILS/hostosinfo.cpp \
+ $$UTILS/namevaluedictionary.cpp \
+ $$UTILS/namevalueitem.cpp \
$$UTILS/persistentsettings.cpp \
$$UTILS/qtcassert.cpp \
$$UTILS/qtcprocess.cpp \
@@ -63,6 +65,8 @@ HEADERS += \
$$UTILS/environment.h \
$$UTILS/fileutils.h \
$$UTILS/hostosinfo.h \
+ $$UTILS/namevaluedictionary.h \
+ $$UTILS/namevalueitem.h \
$$UTILS/persistentsettings.h \
$$UTILS/qtcassert.h \
$$UTILS/qtcprocess.h \
diff --git a/tests/unit/mockup/projectexplorer/project.h b/tests/unit/mockup/projectexplorer/project.h
index e6e321ee43..3e0fef904b 100644
--- a/tests/unit/mockup/projectexplorer/project.h
+++ b/tests/unit/mockup/projectexplorer/project.h
@@ -43,6 +43,10 @@ public:
Target *activeTarget() const { return {}; }
+ QVariant namedSettings(const QString &name) const { return settings.at(name); }
+ void setNamedSettings(const QString &name, const QVariant &value) { settings[name] = value; }
+
Utils::FileName rootProjectDirectoryPath;
+ std::map<QString, QVariant> settings;
};
} // namespace ProjectExplorer
diff --git a/tests/unit/unittest/clangindexingsettingsmanager-test.cpp b/tests/unit/unittest/clangindexingsettingsmanager-test.cpp
new file mode 100644
index 0000000000..e3c4eb7c67
--- /dev/null
+++ b/tests/unit/unittest/clangindexingsettingsmanager-test.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "googletest.h"
+
+#include <clangindexingsettingsmanager.h>
+#include <projectexplorer/project.h>
+
+namespace {
+class ClangIndexingSettingsManager : public testing::Test
+{
+protected:
+ ClangPchManager::ClangIndexingSettingsManager manager;
+ ProjectExplorer::Project project;
+ ProjectExplorer::Project project2;
+};
+
+TEST_F(ClangIndexingSettingsManager, FetchSettings)
+{
+ auto setting = manager.settings(&project);
+
+ ASSERT_THAT(setting, Not(IsNull()));
+}
+
+TEST_F(ClangIndexingSettingsManager, SettingsAreTheSameForTheSameProject)
+{
+ auto setting1 = manager.settings(&project);
+
+ auto setting2 = manager.settings(&project);
+
+ ASSERT_THAT(setting1, Eq(setting2));
+}
+
+TEST_F(ClangIndexingSettingsManager, SettingsAreTheDifferentForDifferentProjects)
+{
+ manager.settings(&project);
+ manager.settings(&project2);
+
+ auto setting1 = manager.settings(&project);
+
+ auto setting2 = manager.settings(&project2);
+
+ ASSERT_THAT(setting1, Not(Eq(setting2)));
+}
+
+TEST_F(ClangIndexingSettingsManager, RemoveSettings)
+{
+ manager.settings(&project);
+
+ manager.remove(&project);
+
+ ASSERT_FALSE(manager.hasSettings(&project));
+}
+
+TEST_F(ClangIndexingSettingsManager, RemoveNonExistingSettings)
+{
+ manager.remove(&project);
+
+ ASSERT_FALSE(manager.hasSettings(&project));
+}
+} // namespace
diff --git a/tests/unit/unittest/pchmanagerclient-test.cpp b/tests/unit/unittest/pchmanagerclient-test.cpp
index 6c74143e4d..5f9fffbf01 100644
--- a/tests/unit/unittest/pchmanagerclient-test.cpp
+++ b/tests/unit/unittest/pchmanagerclient-test.cpp
@@ -34,10 +34,11 @@
#include <pchmanagerclient.h>
#include <pchmanagerprojectupdater.h>
+#include <clangindexingsettingsmanager.h>
#include <filepathcaching.h>
-#include <refactoringdatabaseinitializer.h>
#include <precompiledheadersupdatedmessage.h>
#include <progressmessage.h>
+#include <refactoringdatabaseinitializer.h>
#include <removegeneratedfilesmessage.h>
#include <removeprojectpartsmessage.h>
#include <updategeneratedfilesmessage.h>
@@ -60,10 +61,12 @@ protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
+ ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer,
client,
filePathCache,
- mockProjectPartsStorage};
+ mockProjectPartsStorage,
+ settingsManager};
ClangBackEnd::ProjectPartId projectPartId{1};
ClangBackEnd::FilePath pchFilePath{"/path/to/pch"};
PrecompiledHeadersUpdatedMessage message{{{projectPartId, pchFilePath.clone(), 1}}};
diff --git a/tests/unit/unittest/preprocessormacrocollector-test.cpp b/tests/unit/unittest/preprocessormacrocollector-test.cpp
new file mode 100644
index 0000000000..94eaa01a8b
--- /dev/null
+++ b/tests/unit/unittest/preprocessormacrocollector-test.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "googletest.h"
+
+#include <preprocessormacrocollector.h>
+
+namespace {
+
+using ProjectExplorer::Macros;
+using ProjectExplorer::MacroType;
+using PM = ClangPchManager::PreprocessorMacro;
+
+class PreprocessorMacrosManager : public testing::Test
+{
+protected:
+ Macros macros1{{"yi", "1"}, {"er", "2"}};
+ Macros macros2{{"san", "3"}, {"se", "4"}};
+ Macros macrosWithDuplicates{{"yi", "1"}, {"san", "3"}, {"se", "4"}, {"er", "0"}};
+ ClangPchManager::PreprocessorMacroCollector manager;
+};
+
+TEST_F(PreprocessorMacrosManager, Add)
+{
+ manager.add(macros1);
+
+ ASSERT_THAT(manager.macros(), ElementsAre(PM{"er", "2"}, PM{"yi", "1"}));
+}
+
+TEST_F(PreprocessorMacrosManager, AddMore)
+{
+ manager.add(macros1);
+
+ manager.add(macros2);
+
+ ASSERT_THAT(manager.macros(),
+ ElementsAre(PM{"er", "2"}, PM{"san", "3"}, PM{"se", "4"}, PM{"yi", "1"}));
+}
+
+TEST_F(PreprocessorMacrosManager, FilterDuplicates)
+{
+ manager.add(macros1);
+
+ manager.add(macrosWithDuplicates);
+
+ ASSERT_THAT(manager.macros(),
+ ElementsAre(PM{"er", "0"}, PM{"er", "2"}, PM{"san", "3"}, PM{"se", "4"}, PM{"yi", "1"}));
+}
+} // namespace
diff --git a/tests/unit/unittest/projectupdater-test.cpp b/tests/unit/unittest/projectupdater-test.cpp
index 960a256469..c4744148ab 100644
--- a/tests/unit/unittest/projectupdater-test.cpp
+++ b/tests/unit/unittest/projectupdater-test.cpp
@@ -35,6 +35,8 @@
#include <pchmanagerprojectupdater.h>
+#include <clangindexingprojectsettings.h>
+#include <clangindexingsettingsmanager.h>
#include <filepathcaching.h>
#include <pchmanagerclient.h>
#include <precompiledheaderstorage.h>
@@ -52,6 +54,7 @@
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/algorithm.h>
+#include <utils/namevalueitem.h>
namespace {
@@ -94,7 +97,7 @@ protected:
projectPart.files.push_back(source2ProjectFile);
projectPart.files.push_back(nonActiveProjectFile);
projectPart.displayName = "projectb";
- projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}};
+ projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}, {"POO", "3"}};
projectPartId = projectPartsStorage.fetchProjectPartId(Utils::SmallString{projectPart.id()});
projectPart2.project = &project;
@@ -138,6 +141,9 @@ protected:
Utils::Language::Cxx,
Utils::LanguageVersion::LatestCxx,
Utils::LanguageExtension::None};
+
+ auto settings = settingsManager.settings(&project);
+ settings->saveMacros({{"POO", "3", Utils::NameValueItem::Unset}});
}
protected:
@@ -151,7 +157,11 @@ protected:
mockDependencyCreationProgressManager};
MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient};
NiceMock<MockPchManagerServer> mockPchManagerServer;
- ClangPchManager::ProjectUpdater updater{mockPchManagerServer, filePathCache, projectPartsStorage};
+ ClangPchManager::ClangIndexingSettingsManager settingsManager;
+ ClangPchManager::ProjectUpdater updater{mockPchManagerServer,
+ filePathCache,
+ projectPartsStorage,
+ settingsManager};
ClangBackEnd::ProjectPartId projectPartId;
ClangBackEnd::ProjectPartId projectPartId2;
Utils::PathStringVector headerPaths = {"/path/to/header1.h", "/path/to/header2.h"};
@@ -243,10 +253,12 @@ TEST_F(ProjectUpdater, CallRemoveProjectParts)
TEST_F(ProjectUpdater, CallPrecompiledHeaderRemovedInPchManagerProjectUpdater)
{
+ ClangPchManager::ClangIndexingSettingsManager settingManager;
ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer,
pchManagerClient,
filePathCache,
- projectPartsStorage};
+ projectPartsStorage,
+ settingManager};
ClangBackEnd::RemoveProjectPartsMessage message{{projectPartId, projectPartId2}};
EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId));
@@ -283,9 +295,11 @@ TEST_F(ProjectUpdater, CallStorageInsideTransaction)
MockProjectPartsStorage mockProjectPartsStorage;
ON_CALL(mockProjectPartsStorage, transactionBackend())
.WillByDefault(ReturnRef(mockSqliteTransactionBackend));
+ ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangPchManager::ProjectUpdater updater{mockPchManagerServer,
filePathCache,
- mockProjectPartsStorage};
+ mockProjectPartsStorage,
+ settingsManager};
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartId(Eq(projectPartName)));
@@ -303,7 +317,7 @@ TEST_F(ProjectUpdater, CreateSortedExcludedPaths)
TEST_F(ProjectUpdater, CreateSortedCompilerMacros)
{
- auto paths = updater.createCompilerMacros({{"DEFINE", "1"}, {"FOO", "2"}, {"BAR", "1"}});
+ auto paths = updater.createCompilerMacros({{"DEFINE", "1"}, {"FOO", "2"}, {"BAR", "1"}}, {});
ASSERT_THAT(paths, ElementsAre(CompilerMacro{"BAR", "1", 1},
CompilerMacro{"FOO", "2", 2},
@@ -312,12 +326,28 @@ TEST_F(ProjectUpdater, CreateSortedCompilerMacros)
TEST_F(ProjectUpdater, FilterCompilerMacros)
{
- auto paths = updater.createCompilerMacros(
- {{"DEFINE", "1"}, {"QT_TESTCASE_BUILDDIR", "2"}, {"BAR", "1"}});
+ auto paths = updater.createCompilerMacros({{"DEFINE", "1"},
+ {"QT_TESTCASE_BUILDDIR", "2"},
+ {"BAR", "1"}},
+ {});
ASSERT_THAT(paths, ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"DEFINE", "1", 3}));
}
+TEST_F(ProjectUpdater, FilterSettingsMacros)
+{
+ auto paths = updater.createCompilerMacros({{"YI", "1"}, {"SAN", "3"}, {"SE", "4"}, {"WU", "5"}},
+ {{"SE", "44", Utils::NameValueItem::Unset},
+ {"ER", "2", Utils::NameValueItem::Set},
+ {"WU", "5", Utils::NameValueItem::Unset}});
+
+ ASSERT_THAT(paths,
+ ElementsAre(CompilerMacro{"ER", "2", 3},
+ CompilerMacro{"SE", "4", 3},
+ CompilerMacro{"YI", "1", 1},
+ CompilerMacro{"SAN", "3", 2}));
+}
+
TEST_F(ProjectUpdater, CreateSortedIncludeSearchPaths)
{
CppTools::ProjectPart projectPart;
diff --git a/tests/unit/unittest/refactoringprojectupdater-test.cpp b/tests/unit/unittest/refactoringprojectupdater-test.cpp
index 8d5e60df91..6331fc3016 100644
--- a/tests/unit/unittest/refactoringprojectupdater-test.cpp
+++ b/tests/unit/unittest/refactoringprojectupdater-test.cpp
@@ -32,10 +32,11 @@
#include <sqlitedatabase.h>
+#include <clangindexingsettingsmanager.h>
+#include <clangrefactoringservermessages.h>
#include <filepathcaching.h>
#include <precompiledheadersupdatedmessage.h>
#include <refactoringdatabaseinitializer.h>
-#include <clangrefactoringservermessages.h>
#include <pchmanagerclient.h>
@@ -84,11 +85,13 @@ protected:
mockDependencyCreationProgressManager};
MockCppModelManager mockCppModelManager;
ProjectExplorer::Project project;
+ ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangRefactoring::RefactoringProjectUpdater updater{mockRefactoringServer,
pchManagerClient,
mockCppModelManager,
filePathCache,
- mockProjectPartsStorage};
+ mockProjectPartsStorage,
+ settingsManager};
Utils::SmallString projectPartId;
};
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 8e0a4d6577..5ea9ba2fef 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -47,6 +47,7 @@ DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\"
SOURCES += \
changedfilepathcompressor-test.cpp \
+ clangindexingsettingsmanager-test.cpp \
clangpathwatcher-test.cpp \
clangqueryexamplehighlightmarker-test.cpp \
clangqueryhighlightmarker-test.cpp \
@@ -67,6 +68,7 @@ SOURCES += \
pchmanagerclientserverinprocess-test.cpp \
pchmanagerclient-test.cpp \
pchmanagerserver-test.cpp \
+ preprocessormacrocollector-test.cpp \
processevents-utilities.cpp \
projectpartsmanager-test.cpp \
projectpartsstorage-test.cpp \