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>
This commit is contained in:
Marco Bubke
2019-05-07 16:51:22 +02:00
parent f636f06b45
commit 4bae5de36b
84 changed files with 2990 additions and 1197 deletions

View File

@@ -87,6 +87,11 @@ add_qtc_library(Utils
mimetypes/mimeprovider.cpp mimetypes/mimeprovider_p.h mimetypes/mimeprovider.cpp mimetypes/mimeprovider_p.h
mimetypes/mimetype.cpp mimetypes/mimetype.h mimetypes/mimetype_p.h mimetypes/mimetype.cpp mimetypes/mimetype.h mimetypes/mimetype_p.h
mimetypes/mimetypeparser.cpp mimetypes/mimetypeparser_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 navigationtreeview.cpp navigationtreeview.h
networkaccessmanager.cpp networkaccessmanager.h networkaccessmanager.cpp networkaccessmanager.h
newclasswidget.cpp newclasswidget.h newclasswidget.ui newclasswidget.cpp newclasswidget.h newclasswidget.ui

View File

@@ -39,11 +39,12 @@ Q_GLOBAL_STATIC_WITH_ARGS(Utils::Environment, staticSystemEnvironment,
Q_GLOBAL_STATIC(QVector<Utils::EnvironmentProvider>, environmentProviders) Q_GLOBAL_STATIC(QVector<Utils::EnvironmentProvider>, environmentProviders)
static QMap<QString, QString>::iterator findKey(QMap<QString, QString> &input, Utils::OsType osType, namespace Utils {
const QString &key)
static NameValueMap::iterator findKey(NameValueMap &input, Utils::OsType osType, const QString &key)
{ {
const Qt::CaseSensitivity casing const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
= (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive; : Qt::CaseSensitive;
for (auto it = input.begin(); it != input.end(); ++it) { for (auto it = input.begin(); it != input.end(); ++it) {
if (key.compare(it.key(), casing) == 0) if (key.compare(it.key(), casing) == 0)
return it; return it;
@@ -51,12 +52,12 @@ static QMap<QString, QString>::iterator findKey(QMap<QString, QString> &input, U
return input.end(); return input.end();
} }
static QMap<QString, QString>::const_iterator findKey(const QMap<QString, QString> &input, static NameValueMap::const_iterator findKey(const NameValueMap &input,
Utils::OsType osType, Utils::OsType osType,
const QString &key) const QString &key)
{ {
const Qt::CaseSensitivity casing const Qt::CaseSensitivity casing = (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive
= (osType == Utils::OsTypeWindows) ? Qt::CaseInsensitive : Qt::CaseSensitive; : Qt::CaseSensitive;
for (auto it = input.constBegin(); it != input.constEnd(); ++it) { for (auto it = input.constBegin(); it != input.constEnd(); ++it) {
if (key.compare(it.key(), casing) == 0) if (key.compare(it.key(), casing) == 0)
return it; return it;
@@ -64,198 +65,6 @@ static QMap<QString, QString>::const_iterator findKey(const QMap<QString, QStrin
return input.constEnd(); 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 Environment::toProcessEnvironment() const
{ {
QProcessEnvironment result; QProcessEnvironment result;
@@ -264,52 +73,6 @@ QProcessEnvironment Environment::toProcessEnvironment() const
return result; return result;
} }
void Environment::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 Environment::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 Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
{
QTC_ASSERT(!key.contains('='), return);
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
} else {
// Append unless it is already there
const QString toAppend = sep + value;
if (!it.value().endsWith(toAppend))
it.value().append(toAppend);
}
}
void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
{
QTC_ASSERT(!key.contains('='), return);
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
} else {
// Prepend unless it is already there
const QString toPrepend = value + sep;
if (!it.value().startsWith(toPrepend))
it.value().prepend(toPrepend);
}
}
void Environment::appendOrSetPath(const QString &value) void Environment::appendOrSetPath(const QString &value)
{ {
appendOrSet("PATH", QDir::toNativeSeparators(value), appendOrSet("PATH", QDir::toNativeSeparators(value),
@@ -322,6 +85,34 @@ void Environment::prependOrSetPath(const QString &value)
QString(OsSpecificAspects::pathListSeparator(m_osType))); QString(OsSpecificAspects::pathListSeparator(m_osType)));
} }
void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
{
QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
} else {
// Append unless it is already there
const QString toAppend = sep + value;
if (!it.value().endsWith(toAppend))
it.value().append(toAppend);
}
}
void Environment::prependOrSet(const QString &key, const QString &value, const QString &sep)
{
QTC_ASSERT(!key.contains('='), return );
auto it = findKey(m_values, m_osType, key);
if (it == m_values.end()) {
m_values.insert(key, value);
} else {
// Prepend unless it is already there
const QString toPrepend = value + sep;
if (!it.value().startsWith(toPrepend))
it.value().prepend(toPrepend);
}
}
void Environment::prependOrSetLibrarySearchPath(const QString &value) void Environment::prependOrSetLibrarySearchPath(const QString &value)
{ {
switch (m_osType) { switch (m_osType) {
@@ -387,11 +178,6 @@ void Environment::setupEnglishOutput(QStringList *environment)
*environment = env.toStringList(); *environment = env.toStringList();
} }
void Environment::clear()
{
m_values.clear();
}
FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory, FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory,
QSet<FilePath> &alreadyChecked) const QSet<FilePath> &alreadyChecked) const
{ {
@@ -494,122 +280,7 @@ FilePathList Environment::path() const
return Utils::transform(pathComponents, &FilePath::fromUserInput); return Utils::transform(pathComponents, &FilePath::fromUserInput);
} }
QString Environment::value(const QString &key) const void Environment::modifySystemEnvironment(const EnvironmentItems &list)
{
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)
{ {
staticSystemEnvironment->modify(list); staticSystemEnvironment->modify(list);
} }

View File

@@ -27,8 +27,9 @@
#include "fileutils.h" #include "fileutils.h"
#include "hostosinfo.h" #include "hostosinfo.h"
#include "namevaluedictionary.h"
#include "namevalueitem.h"
#include "optional.h" #include "optional.h"
#include "utils_global.h"
#include <QMap> #include <QMap>
#include <QStringList> #include <QStringList>
@@ -39,71 +40,18 @@ QT_FORWARD_DECLARE_CLASS(QDebug)
QT_FORWARD_DECLARE_CLASS(QProcessEnvironment) QT_FORWARD_DECLARE_CLASS(QProcessEnvironment)
namespace Utils { namespace Utils {
class Environment;
class QTCREATOR_UTILS_EXPORT EnvironmentItem class QTCREATOR_UTILS_EXPORT Environment final : public NameValueDictionary
{ {
public: 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 Environment systemEnvironment();
static void setupEnglishOutput(Environment *environment); static void setupEnglishOutput(Environment *environment);
static void setupEnglishOutput(QProcessEnvironment *environment); static void setupEnglishOutput(QProcessEnvironment *environment);
static void setupEnglishOutput(QStringList *environment); static void setupEnglishOutput(QStringList *environment);
QStringList toStringList() const;
QProcessEnvironment toProcessEnvironment() 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 appendOrSet(const QString &key, const QString &value, const QString &sep = QString());
void prependOrSet(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 prependOrSetLibrarySearchPath(const QString &value);
void prependOrSetLibrarySearchPaths(const QStringList &values); 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 &)>; using PathFilter = std::function<bool(const FilePath &)>;
FilePath searchInPath(const QString &executable, FilePath searchInPath(const QString &executable,
const FilePathList &additionalDirs = FilePathList(), const FilePathList &additionalDirs = FilePathList(),
@@ -138,16 +76,11 @@ public:
FilePath expandVariables(const FilePath &input) const; FilePath expandVariables(const FilePath &input) const;
QStringList expandVariables(const QStringList &input) const; QStringList expandVariables(const QStringList &input) const;
bool operator!=(const Environment &other) const; static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!!
bool operator==(const Environment &other) const;
static void modifySystemEnvironment(const QList<EnvironmentItem> &list); // use with care!!!
private: private:
FilePath searchInDirectory(const QStringList &execs, const FilePath &directory, FilePath searchInDirectory(const QStringList &execs, const FilePath &directory,
QSet<FilePath> &alreadyChecked) const; QSet<FilePath> &alreadyChecked) const;
QMap<QString, QString> m_values;
OsType m_osType;
}; };
class QTCREATOR_UTILS_EXPORT EnvironmentProvider class QTCREATOR_UTILS_EXPORT EnvironmentProvider

View File

@@ -35,144 +35,19 @@
namespace Utils { namespace Utils {
namespace Internal { Utils::optional<EnvironmentItems> EnvironmentDialog::getEnvironmentItems(
QWidget *parent, const EnvironmentItems &initial, const QString &placeholderText, Polisher polisher)
static QList<EnvironmentItem> cleanUp(
const QList<EnvironmentItem> &items)
{ {
QList<EnvironmentItem> uniqueItems; return getNameValueItems(
QSet<QString> uniqueSet; parent,
for (int i = items.count() - 1; i >= 0; i--) { initial,
EnvironmentItem item = items.at(i); placeholderText,
if (HostOsInfo::isWindowsHost()) polisher,
item.name = item.name.toUpper(); tr("Edit Environment"),
const QString &itemName = item.name; tr("Enter one environment variable per line.\n"
QString emptyName = itemName; "To set or change a variable, use VARIABLE=VALUE.\n"
emptyName.remove(QLatin1Char(' ')); "Existing variables can be referenced in a VALUE with ${OTHER}.\n"
if (!emptyName.isEmpty() && !uniqueSet.contains(itemName)) { "To clear a variable, put its name on a line with nothing else on it."));
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
{
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>();
} }
} // namespace Utils } // namespace Utils
#include "environmentdialog.moc"

View File

@@ -25,36 +25,20 @@
#pragma once #pragma once
#include "utils_global.h"
#include "environment.h" #include "environment.h"
#include "namevaluesdialog.h"
#include <QDialog> #include <thread>
namespace Utils { namespace Utils {
namespace Internal { class EnvironmentDialogPrivate; } class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public NameValuesDialog
class QTCREATOR_UTILS_EXPORT EnvironmentDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EnvironmentDialog(QWidget *parent = nullptr); static Utils::optional<EnvironmentItems> getEnvironmentItems(QWidget *parent = nullptr,
~EnvironmentDialog() override; const EnvironmentItems &initial = {},
const QString &placeholderText = {},
void setEnvironmentItems(const QList<EnvironmentItem> &items); Polisher polish = {});
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;
}; };
} // namespace Utils } // namespace Utils

View File

@@ -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

View File

@@ -33,360 +33,12 @@
#include <QFont> #include <QFont>
namespace Utils { namespace Utils {
namespace Internal { const Environment &EnvironmentModel::baseEnvironment() const
class EnvironmentModelPrivate
{ {
public: return static_cast<const Environment &>(baseNameValueDictionary());
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
{
return d->m_resultEnvironment.key(d->m_resultEnvironment.constBegin() + index.row());
}
void EnvironmentModel::setBaseEnvironment(const Environment &env) void EnvironmentModel::setBaseEnvironment(const Environment &env)
{ {
if (d->m_baseEnvironment == env) setBaseNameValueDictionary(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");
}
/// *****************
/// 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 } // namespace Utils

View File

@@ -25,55 +25,17 @@
#pragma once #pragma once
#include "utils_global.h" #include "namevaluemodel.h"
#include <QAbstractTableModel>
namespace Utils { namespace Utils {
class Environment;
class EnvironmentItem;
namespace Internal { class EnvironmentModelPrivate; } class QTCREATOR_UTILS_EXPORT EnvironmentModel : public NameValueModel
class QTCREATOR_UTILS_EXPORT EnvironmentModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit EnvironmentModel(QObject *parent = nullptr); const Environment &baseEnvironment() const;
~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;
void setBaseEnvironment(const Environment &env); 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 } // namespace Utils

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -27,6 +27,10 @@ SOURCES += \
$$PWD/environment.cpp \ $$PWD/environment.cpp \
$$PWD/environmentmodel.cpp \ $$PWD/environmentmodel.cpp \
$$PWD/environmentdialog.cpp \ $$PWD/environmentdialog.cpp \
$$PWD/namevaluedictionary.cpp \
$$PWD/namevalueitem.cpp \
$$PWD/namevaluemodel.cpp \
$$PWD/namevaluesdialog.cpp \
$$PWD/qrcparser.cpp \ $$PWD/qrcparser.cpp \
$$PWD/qtcprocess.cpp \ $$PWD/qtcprocess.cpp \
$$PWD/reloadpromptutils.cpp \ $$PWD/reloadpromptutils.cpp \
@@ -125,19 +129,24 @@ SOURCES += \
$$PWD/fixedsizeclicklabel.cpp \ $$PWD/fixedsizeclicklabel.cpp \
$$PWD/removefiledialog.cpp \ $$PWD/removefiledialog.cpp \
$$PWD/differ.cpp \ $$PWD/differ.cpp \
$$PWD/jsontreeitem.cpp $$PWD/jsontreeitem.cpp \
$$PWD/namevaluevalidator.cpp
win32:SOURCES += $$PWD/consoleprocess_win.cpp win32:SOURCES += $$PWD/consoleprocess_win.cpp
else:SOURCES += $$PWD/consoleprocess_unix.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp
HEADERS += \ HEADERS += \
$$PWD/environmentfwd.h \
$$PWD/genericconstants.h \ $$PWD/genericconstants.h \
$$PWD/globalfilechangeblocker.h \ $$PWD/globalfilechangeblocker.h \
$$PWD/benchmarker.h \ $$PWD/benchmarker.h \
$$PWD/environment.h \ $$PWD/environment.h \
$$PWD/environmentmodel.h \ $$PWD/environmentmodel.h \
$$PWD/environmentdialog.h \ $$PWD/environmentdialog.h \
$$PWD/namevaluedictionary.h \
$$PWD/namevalueitem.h \
$$PWD/namevaluemodel.h \
$$PWD/namevaluesdialog.h \
$$PWD/pointeralgorithm.h \ $$PWD/pointeralgorithm.h \
$$PWD/qrcparser.h \ $$PWD/qrcparser.h \
$$PWD/qtcprocess.h \ $$PWD/qtcprocess.h \
@@ -270,7 +279,8 @@ HEADERS += \
$$PWD/differ.h \ $$PWD/differ.h \
$$PWD/cpplanguage_details.h \ $$PWD/cpplanguage_details.h \
$$PWD/jsontreeitem.h \ $$PWD/jsontreeitem.h \
$$PWD/listmodel.h $$PWD/listmodel.h \
$$PWD/namevaluevalidator.h
FORMS += $$PWD/filewizardpage.ui \ FORMS += $$PWD/filewizardpage.ui \
$$PWD/newclasswidget.ui \ $$PWD/newclasswidget.ui \

View File

@@ -150,7 +150,7 @@ static QString constructOmittedDetailsString(const QStringList &omitted)
"configuration page for \"%1\":") + '\n' + omitted.join('\n'); "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) { auto removedVars = Utils::transform<QStringList>(diff, [](const Utils::EnvironmentItem &it) {
return it.name; return it.name;
@@ -204,10 +204,10 @@ void TestRunner::scheduleNext()
m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory()); m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory());
const Utils::Environment &original = m_currentConfig->environment(); const Utils::Environment &original = m_currentConfig->environment();
Utils::Environment environment = m_currentConfig->filteredEnvironment(original); Utils::Environment environment = m_currentConfig->filteredEnvironment(original);
const QList<Utils::EnvironmentItem> removedVariables const Utils::EnvironmentItems removedVariables = Utils::filtered(
= Utils::filtered(original.diff(environment), [](const Utils::EnvironmentItem &it) { original.diff(environment), [](const Utils::EnvironmentItem &it) {
return it.operation == Utils::EnvironmentItem::Unset; return it.operation == Utils::EnvironmentItem::Unset;
}); });
if (!removedVariables.isEmpty()) { if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables) const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(m_currentConfig->displayName()); .arg(m_currentConfig->displayName());
@@ -560,10 +560,10 @@ void TestRunner::debugTests()
} }
Utils::Environment original(inferior.environment); Utils::Environment original(inferior.environment);
inferior.environment = config->filteredEnvironment(original); inferior.environment = config->filteredEnvironment(original);
const QList<Utils::EnvironmentItem> removedVariables const Utils::EnvironmentItems removedVariables = Utils::filtered(
= Utils::filtered(original.diff(inferior.environment), [](const Utils::EnvironmentItem &it) { original.diff(inferior.environment), [](const Utils::EnvironmentItem &it) {
return it.operation == Utils::EnvironmentItem::Unset; return it.operation == Utils::EnvironmentItem::Unset;
}); });
if (!removedVariables.isEmpty()) { if (!removedVariables.isEmpty()) {
const QString &details = constructOmittedVariablesDetailsString(removedVariables) const QString &details = constructOmittedVariablesDetailsString(removedVariables)
.arg(config->displayName()); .arg(config->displayName());

View File

@@ -60,9 +60,8 @@ static void addProjectPanelWidget()
auto panelFactory = new ProjectExplorer::ProjectPanelFactory(); auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
panelFactory->setPriority(60); panelFactory->setPriority(60);
panelFactory->setDisplayName(ClangProjectSettingsWidget::tr("Clang Code Model")); panelFactory->setDisplayName(ClangProjectSettingsWidget::tr("Clang Code Model"));
panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project) { panelFactory->setCreateWidgetFunction(
return new ClangProjectSettingsWidget(project); [&](ProjectExplorer::Project *project) { return new ClangProjectSettingsWidget(project); });
});
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
} }

View File

@@ -106,8 +106,8 @@ static void replaceCppCodeStyle()
bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorString) bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorString)
{ {
Q_UNUSED(arguments); Q_UNUSED(arguments)
Q_UNUSED(errorString); Q_UNUSED(errorString)
#ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED
replaceCppCodeStyle(); replaceCppCodeStyle();

View File

@@ -4,12 +4,17 @@ add_qtc_plugin(ClangPchManager
DEFINES CLANGPCHMANAGER_LIB DEFINES CLANGPCHMANAGER_LIB
PLUGIN_DEPENDS Core CppTools PLUGIN_DEPENDS Core CppTools
SOURCES SOURCES
clangindexingprojectsettings.cpp clangindexingprojectsettings.h
clangindexingprojectsettingswidget.cpp clangindexingprojectsettingswidget.h clangindexingprojectsettingswidget.ui
clangindexingsettingsmanager.cpp clangindexingsettingsmanager.h
clangpchmanager_global.h clangpchmanager_global.h
clangpchmanagerplugin.cpp clangpchmanagerplugin.h clangpchmanagerplugin.cpp clangpchmanagerplugin.h
pchmanagerclient.cpp pchmanagerclient.h pchmanagerclient.cpp pchmanagerclient.h
pchmanagerconnectionclient.cpp pchmanagerconnectionclient.h pchmanagerconnectionclient.cpp pchmanagerconnectionclient.h
pchmanagernotifierinterface.cpp pchmanagernotifierinterface.h pchmanagernotifierinterface.cpp pchmanagernotifierinterface.h
pchmanagerprojectupdater.cpp pchmanagerprojectupdater.h pchmanagerprojectupdater.cpp pchmanagerprojectupdater.h
preprocessormacrocollector.cpp preprocessormacrocollector.h
preprocessormacrowidget.cpp preprocessormacrowidget.h
progressmanager.h progressmanager.h
progressmanagerinterface.h progressmanagerinterface.h
projectupdater.cpp projectupdater.h projectupdater.cpp projectupdater.h

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -7,18 +7,24 @@ shared|dll {
INCLUDEPATH += $$PWD INCLUDEPATH += $$PWD
HEADERS += \ HEADERS += \
$$PWD/clangindexingprojectsettings.h \
$$PWD/clangindexingsettingsmanager.h \
$$PWD/pchmanagerclient.h \ $$PWD/pchmanagerclient.h \
$$PWD/pchmanagernotifierinterface.h \ $$PWD/pchmanagernotifierinterface.h \
$$PWD/pchmanagerconnectionclient.h \ $$PWD/pchmanagerconnectionclient.h \
$$PWD/clangpchmanager_global.h \ $$PWD/clangpchmanager_global.h \
$$PWD/preprocessormacrocollector.h \
$$PWD/projectupdater.h \ $$PWD/projectupdater.h \
$$PWD/pchmanagerprojectupdater.h \ $$PWD/pchmanagerprojectupdater.h \
$$PWD/progressmanager.h \ $$PWD/progressmanager.h \
$$PWD/progressmanagerinterface.h $$PWD/progressmanagerinterface.h
SOURCES += \ SOURCES += \
$$PWD/clangindexingprojectsettings.cpp \
$$PWD/clangindexingsettingsmanager.cpp \
$$PWD/pchmanagerclient.cpp \ $$PWD/pchmanagerclient.cpp \
$$PWD/pchmanagernotifierinterface.cpp \ $$PWD/pchmanagernotifierinterface.cpp \
$$PWD/pchmanagerconnectionclient.cpp \ $$PWD/pchmanagerconnectionclient.cpp \
$$PWD/preprocessormacrocollector.cpp \
$$PWD/projectupdater.cpp \ $$PWD/projectupdater.cpp \
$$PWD/pchmanagerprojectupdater.cpp $$PWD/pchmanagerprojectupdater.cpp

View File

@@ -12,8 +12,15 @@ win32 {
HEADERS += \ HEADERS += \
$$PWD/clangpchmanagerplugin.h \ $$PWD/clangpchmanagerplugin.h \
clangindexingprojectsettingswidget.h \
preprocessormacrowidget.h \
qtcreatorprojectupdater.h qtcreatorprojectupdater.h
SOURCES += \ SOURCES += \
$$PWD/clangpchmanagerplugin.cpp \ $$PWD/clangpchmanagerplugin.cpp \
clangindexingprojectsettingswidget.cpp \
preprocessormacrowidget.cpp \
qtcreatorprojectupdater.cpp qtcreatorprojectupdater.cpp
FORMS += \
clangindexingprojectsettingswidget.ui

View File

@@ -25,8 +25,10 @@
#include "clangpchmanagerplugin.h" #include "clangpchmanagerplugin.h"
#include "pchmanagerconnectionclient.h" #include "clangindexingprojectsettingswidget.h"
#include "clangindexingsettingsmanager.h"
#include "pchmanagerclient.h" #include "pchmanagerclient.h"
#include "pchmanagerconnectionclient.h"
#include "progressmanager.h" #include "progressmanager.h"
#include "qtcreatorprojectupdater.h" #include "qtcreatorprojectupdater.h"
@@ -38,12 +40,14 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectpanelfactory.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <QFutureInterface> #include <QFutureInterface>
#include <chrono> #include <chrono>
#include <map>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@@ -58,6 +62,26 @@ QString backendProcessPath()
+ QStringLiteral(QTC_HOST_EXE_SUFFIX); + 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 } // anonymous namespace
class ClangPchManagerPluginData class ClangPchManagerPluginData
@@ -83,10 +107,12 @@ public:
ClangBackEnd::ProjectPartsStorage<Sqlite::Database> projectPartsStorage{database}; ClangBackEnd::ProjectPartsStorage<Sqlite::Database> projectPartsStorage{database};
PchManagerClient pchManagerClient{pchCreationProgressManager, dependencyCreationProgressManager}; PchManagerClient pchManagerClient{pchCreationProgressManager, dependencyCreationProgressManager};
PchManagerConnectionClient connectionClient{&pchManagerClient}; PchManagerConnectionClient connectionClient{&pchManagerClient};
ClangIndexingSettingsManager settingsManager;
QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(), QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(),
pchManagerClient, pchManagerClient,
filePathCache, filePathCache,
projectPartsStorage}; projectPartsStorage,
settingsManager};
}; };
std::unique_ptr<ClangPchManagerPluginData> ClangPchManagerPlugin::d; std::unique_ptr<ClangPchManagerPluginData> ClangPchManagerPlugin::d;
@@ -102,6 +128,8 @@ bool ClangPchManagerPlugin::initialize(const QStringList & /*arguments*/, QStrin
startBackend(); startBackend();
addIndexingProjectPaneWidget(d->settingsManager);
return true; return true;
} }
@@ -133,4 +161,9 @@ PchManagerClient &ClangPchManagerPlugin::pchManagerClient()
return d->pchManagerClient; return d->pchManagerClient;
} }
ClangIndexingSettingsManager &ClangPchManagerPlugin::settingsManager()
{
return d->settingsManager;
}
} // namespace ClangRefactoring } // namespace ClangRefactoring

View File

@@ -33,6 +33,7 @@
namespace ClangPchManager { namespace ClangPchManager {
class ClangIndexingSettingsManager;
class ClangPchManagerPluginData; class ClangPchManagerPluginData;
class PchManagerClient; class PchManagerClient;
@@ -50,6 +51,7 @@ public:
ShutdownFlag aboutToShutdown(); ShutdownFlag aboutToShutdown();
static PchManagerClient &pchManagerClient(); static PchManagerClient &pchManagerClient();
static ClangIndexingSettingsManager &settingsManager();
private: private:
void startBackend(); void startBackend();

View File

@@ -35,8 +35,9 @@ public:
PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
PchManagerClient &client, PchManagerClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage) ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
: ProjectUpdater(server, filePathCache, projectPartsStorage) ClangIndexingSettingsManager &settingsManager)
: ProjectUpdater(server, filePathCache, projectPartsStorage, settingsManager)
, m_client(client) , m_client(client)
{} {}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -27,6 +27,8 @@
#include "pchmanagerclient.h" #include "pchmanagerclient.h"
#include <clangindexingprojectsettings.h>
#include <clangindexingsettingsmanager.h>
#include <filepathid.h> #include <filepathid.h>
#include <pchmanagerserverinterface.h> #include <pchmanagerserverinterface.h>
#include <removegeneratedfilesmessage.h> #include <removegeneratedfilesmessage.h>
@@ -42,6 +44,7 @@
#include <projectexplorer/buildconfiguration.h> #include <projectexplorer/buildconfiguration.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/namevalueitem.h>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
@@ -175,9 +178,63 @@ void cleanupMacros(ClangBackEnd::CompilerMacros &macros)
macros.erase(newEnd, macros.end()); 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 } // namespace
ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectExplorer::Macros &projectMacros) ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(
const ProjectExplorer::Macros &projectMacros, Utils::NameValueItems &&settingsMacros) const
{ {
int index = 0; int index = 0;
auto macros = Utils::transform<ClangBackEnd::CompilerMacros>( auto macros = Utils::transform<ClangBackEnd::CompilerMacros>(
@@ -186,6 +243,7 @@ ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectE
}); });
cleanupMacros(macros); cleanupMacros(macros);
updateWithSettings(macros, std::move(settingsMacros), index);
std::sort(macros.begin(), macros.end()); std::sort(macros.begin(), macros.end());
@@ -291,9 +349,12 @@ ClangBackEnd::ProjectPartContainer ProjectUpdater::toProjectPartContainer(
ClangBackEnd::ProjectPartId projectPartId = m_projectPartsStorage.fetchProjectPartId( ClangBackEnd::ProjectPartId projectPartId = m_projectPartsStorage.fetchProjectPartId(
projectPartName); projectPartName);
ClangIndexingProjectSettings *settings = m_settingsManager.settings(projectPart->project);
return ClangBackEnd::ProjectPartContainer(projectPartId, return ClangBackEnd::ProjectPartContainer(projectPartId,
Utils::SmallStringVector(arguments), Utils::SmallStringVector(arguments),
createCompilerMacros(projectPart->projectMacros), createCompilerMacros(projectPart->projectMacros,
settings->readMacros()),
std::move(includeSearchPaths.system), std::move(includeSearchPaths.system),
std::move(includeSearchPaths.project), std::move(includeSearchPaths.project),
std::move(headerAndSources.headers), std::move(headerAndSources.headers),

View File

@@ -37,6 +37,8 @@
#include <projectexplorer/headerpath.h> #include <projectexplorer/headerpath.h>
#include <utils/environmentfwd.h>
namespace ProjectExplorer { namespace ProjectExplorer {
class Macro; class Macro;
using Macros = QVector<Macro>; using Macros = QVector<Macro>;
@@ -59,6 +61,8 @@ namespace ClangPchManager {
class HeaderAndSources; class HeaderAndSources;
class PchManagerClient; class PchManagerClient;
class ClangIndexingSettingsManager;
class ClangIndexingProjectSettings;
class CLANGPCHMANAGER_EXPORT ProjectUpdater class CLANGPCHMANAGER_EXPORT ProjectUpdater
{ {
@@ -71,10 +75,12 @@ public:
ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage) ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangIndexingSettingsManager &settingsManager)
: m_server(server) : m_server(server)
, m_filePathCache(filePathCache) , m_filePathCache(filePathCache)
, m_projectPartsStorage(projectPartsStorage) , m_projectPartsStorage(projectPartsStorage)
, m_settingsManager(settingsManager)
{} {}
void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts, void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts,
@@ -98,8 +104,8 @@ public:
void addToHeaderAndSources(HeaderAndSources &headerAndSources, void addToHeaderAndSources(HeaderAndSources &headerAndSources,
const CppTools::ProjectFile &projectFile) const; const CppTools::ProjectFile &projectFile) const;
static QStringList toolChainArguments(CppTools::ProjectPart *projectPart); static QStringList toolChainArguments(CppTools::ProjectPart *projectPart);
static ClangBackEnd::CompilerMacros createCompilerMacros( ClangBackEnd::CompilerMacros createCompilerMacros(const ProjectExplorer::Macros &projectMacros,
const ProjectExplorer::Macros &projectMacros); Utils::NameValueItems &&settingsMacros) const;
static SystemAndProjectIncludeSearchPaths createIncludeSearchPaths( static SystemAndProjectIncludeSearchPaths createIncludeSearchPaths(
const CppTools::ProjectPart &projectPart); const CppTools::ProjectPart &projectPart);
static ClangBackEnd::FilePaths createExcludedPaths( static ClangBackEnd::FilePaths createExcludedPaths(
@@ -115,6 +121,7 @@ private:
ClangBackEnd::ProjectManagementServerInterface &m_server; ClangBackEnd::ProjectManagementServerInterface &m_server;
ClangBackEnd::FilePathCachingInterface &m_filePathCache; ClangBackEnd::FilePathCachingInterface &m_filePathCache;
ClangBackEnd::ProjectPartsStorageInterface &m_projectPartsStorage; ClangBackEnd::ProjectPartsStorageInterface &m_projectPartsStorage;
ClangIndexingSettingsManager &m_settingsManager;
}; };
} // namespace ClangPchManager } // namespace ClangPchManager

View File

@@ -59,8 +59,9 @@ public:
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClientType &client, ClientType &client,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage) ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
: ProjectUpdaterType(server, client, filePathCache, projectPartsStorage) ClangIndexingSettingsManager &settingsManager)
: ProjectUpdaterType(server, client, filePathCache, projectPartsStorage, settingsManager)
{ {
connectToCppModelManager(); connectToCppModelManager();
} }
@@ -74,7 +75,6 @@ public:
void projectPartsUpdated(ProjectExplorer::Project *project) void projectPartsUpdated(ProjectExplorer::Project *project)
{ {
ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project), {}); // TODO add support for toolchainarguments ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project), {}); // TODO add support for toolchainarguments
} }

View File

@@ -42,8 +42,8 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <cpptools/cpptoolsconstants.h> #include <cpptools/cpptoolsconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <refactoringdatabaseinitializer.h> #include <refactoringdatabaseinitializer.h>
#include <filepathcaching.h> #include <filepathcaching.h>
@@ -103,16 +103,13 @@ public:
QtCreatorRefactoringProjectUpdater projectUpdate{connectionClient.serverProxy(), QtCreatorRefactoringProjectUpdater projectUpdate{connectionClient.serverProxy(),
ClangPchManagerPlugin::pchManagerClient(), ClangPchManagerPlugin::pchManagerClient(),
filePathCache, filePathCache,
projectPartsStorage}; projectPartsStorage,
ClangPchManagerPlugin::settingsManager()};
}; };
ClangRefactoringPlugin::ClangRefactoringPlugin() ClangRefactoringPlugin::ClangRefactoringPlugin() = default;
{
}
ClangRefactoringPlugin::~ClangRefactoringPlugin() ClangRefactoringPlugin::~ClangRefactoringPlugin() = default;
{
}
static bool useClangFilters() static bool useClangFilters()
{ {
@@ -131,8 +128,8 @@ bool ClangRefactoringPlugin::initialize(const QStringList & /*arguments*/, QStri
connectBackend(); connectBackend();
startBackend(); startBackend();
CppTools::CppModelManager::addRefactoringEngine( CppTools::CppModelManager::addRefactoringEngine(CppTools::RefactoringEngineType::ClangRefactoring,
CppTools::RefactoringEngineType::ClangRefactoring, &refactoringEngine()); &refactoringEngine());
initializeFilters(); initializeFilters();

View File

@@ -64,12 +64,14 @@ QtCreatorRefactoringProjectUpdater::QtCreatorRefactoringProjectUpdater(
ClangBackEnd::ProjectManagementServerInterface &server, ClangBackEnd::ProjectManagementServerInterface &server,
ClangPchManager::PchManagerClient &pchManagerClient, ClangPchManager::PchManagerClient &pchManagerClient,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage) ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangPchManager::ClangIndexingSettingsManager &settingsManager)
: RefactoringProjectUpdater(server, : RefactoringProjectUpdater(server,
pchManagerClient, pchManagerClient,
*cppModelManager(), *cppModelManager(),
filePathCache, filePathCache,
projectPartsStorage) projectPartsStorage,
settingsManager)
{ {
connectToCppModelManager(); connectToCppModelManager();
} }

View File

@@ -32,11 +32,11 @@ namespace ClangRefactoring {
class QtCreatorRefactoringProjectUpdater final : public RefactoringProjectUpdater class QtCreatorRefactoringProjectUpdater final : public RefactoringProjectUpdater
{ {
public: public:
QtCreatorRefactoringProjectUpdater( QtCreatorRefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::ProjectManagementServerInterface &server, ClangPchManager::PchManagerClient &pchManagerClient,
ClangPchManager::PchManagerClient &pchManagerClient, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage); ClangPchManager::ClangIndexingSettingsManager &settingsManager);
private: private:
void abstractEditorUpdated(const QString &filePath, const QByteArray &contents); void abstractEditorUpdated(const QString &filePath, const QByteArray &contents);

View File

@@ -40,8 +40,9 @@ public:
ClangPchManager::PchManagerClient &pchManagerClient, ClangPchManager::PchManagerClient &pchManagerClient,
CppTools::CppModelManagerInterface &cppModelManager, CppTools::CppModelManagerInterface &cppModelManager,
ClangBackEnd::FilePathCachingInterface &filePathCache, ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage) ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
: ClangPchManager::ProjectUpdater(server, filePathCache, projectPartsStorage) ClangPchManager::ClangIndexingSettingsManager &settingsManager)
: ClangPchManager::ProjectUpdater(server, filePathCache, projectPartsStorage, settingsManager)
, ClangPchManager::PchManagerNotifierInterface(pchManagerClient) , ClangPchManager::PchManagerNotifierInterface(pchManagerClient)
, m_cppModelManager(cppModelManager) , m_cppModelManager(cppModelManager)
{ {

View File

@@ -630,19 +630,16 @@ void ExternalToolConfig::updateEffectiveArguments()
void ExternalToolConfig::editEnvironmentChanges() void ExternalToolConfig::editEnvironmentChanges()
{ {
bool ok;
const QString placeholderText = Utils::HostOsInfo::isWindowsHost() const QString placeholderText = Utils::HostOsInfo::isWindowsHost()
? tr("PATH=C:\\dev\\bin;${PATH}") ? tr("PATH=C:\\dev\\bin;${PATH}")
: tr("PATH=/opt/bin:${PATH}"); : tr("PATH=/opt/bin:${PATH}");
const QList<Utils::EnvironmentItem> newItems = const auto newItems = Utils::EnvironmentDialog::getEnvironmentItems(ui->environmentLabel,
Utils::EnvironmentDialog::getEnvironmentItems(&ok, ui->environmentLabel, m_environment,
m_environment, placeholderText);
placeholderText); if (newItems) {
if (!ok) m_environment = *newItems;
return; updateEnvironmentLabel();
}
m_environment = newItems;
updateEnvironmentLabel();
} }
void ExternalToolConfig::updateEnvironmentLabel() void ExternalToolConfig::updateEnvironmentLabel()

View File

@@ -27,14 +27,14 @@
#include "../externaltool.h" #include "../externaltool.h"
#include <utils/environmentfwd.h>
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QDialog> #include <QDialog>
#include <QWidget> #include <QWidget>
QT_FORWARD_DECLARE_CLASS(QPlainTextEdit) QT_FORWARD_DECLARE_CLASS(QPlainTextEdit)
namespace Utils { class EnvironmentItem; }
namespace Core { namespace Core {
namespace Internal { namespace Internal {
@@ -108,9 +108,9 @@ private:
void updateEnvironmentLabel(); void updateEnvironmentLabel();
Ui::ExternalToolConfig *ui; Ui::ExternalToolConfig *ui;
QList<Utils::EnvironmentItem> m_environment; Utils::EnvironmentItems m_environment;
ExternalToolModel *m_model; ExternalToolModel *m_model;
}; };
} // Internal } // Internal
} // Core } // namespace Core

View File

@@ -190,7 +190,7 @@ Environment ExternalTool::baseEnvironment() const
return Environment::systemEnvironment(); return Environment::systemEnvironment();
} }
QList<EnvironmentItem> ExternalTool::environmentUserChanges() const EnvironmentItems ExternalTool::environmentUserChanges() const
{ {
return m_environment; return m_environment;
} }
@@ -297,7 +297,7 @@ void ExternalTool::setBaseEnvironmentProviderId(Id id)
m_baseEnvironmentProviderId = id; m_baseEnvironmentProviderId = id;
} }
void ExternalTool::setEnvironmentUserChanges(const QList<EnvironmentItem> &items) void ExternalTool::setEnvironmentUserChanges(const EnvironmentItems &items)
{ {
m_environment = items; m_environment = items;
} }
@@ -600,10 +600,10 @@ bool ExternalToolRunner::resolve()
m_resolvedEnvironment = m_tool->baseEnvironment(); m_resolvedEnvironment = m_tool->baseEnvironment();
MacroExpander *expander = globalMacroExpander(); MacroExpander *expander = globalMacroExpander();
QList<EnvironmentItem> expandedEnvironment EnvironmentItems expandedEnvironment = Utils::transform(
= Utils::transform(m_tool->environmentUserChanges(), [expander](const EnvironmentItem &item) { m_tool->environmentUserChanges(), [expander](const EnvironmentItem &item) {
return EnvironmentItem(item.name, expander->expand(item.value), item.operation); return EnvironmentItem(item.name, expander->expand(item.value), item.operation);
}); });
m_resolvedEnvironment.modify(expandedEnvironment); m_resolvedEnvironment.modify(expandedEnvironment);
{ {

View File

@@ -71,7 +71,7 @@ public:
QString workingDirectory() const; QString workingDirectory() const;
Id baseEnvironmentProviderId() const; Id baseEnvironmentProviderId() const;
Utils::Environment baseEnvironment() const; Utils::Environment baseEnvironment() const;
QList<Utils::EnvironmentItem> environmentUserChanges() const; Utils::EnvironmentItems environmentUserChanges() const;
void setFileName(const QString &fileName); void setFileName(const QString &fileName);
void setPreset(QSharedPointer<ExternalTool> preset); void setPreset(QSharedPointer<ExternalTool> preset);
@@ -101,7 +101,7 @@ public:
void setInput(const QString &input); void setInput(const QString &input);
void setWorkingDirectory(const QString &workingDirectory); void setWorkingDirectory(const QString &workingDirectory);
void setBaseEnvironmentProviderId(Id id); void setBaseEnvironmentProviderId(Id id);
void setEnvironmentUserChanges(const QList<Utils::EnvironmentItem> &items); void setEnvironmentUserChanges(const Utils::EnvironmentItems &items);
private: private:
QString m_id; QString m_id;
@@ -114,7 +114,7 @@ private:
QString m_input; QString m_input;
QString m_workingDirectory; QString m_workingDirectory;
Id m_baseEnvironmentProviderId; Id m_baseEnvironmentProviderId;
QList<Utils::EnvironmentItem> m_environment; Utils::EnvironmentItems m_environment;
OutputHandling m_outputHandling = ShowInPane; OutputHandling m_outputHandling = ShowInPane;
OutputHandling m_errorHandling = ShowInPane; OutputHandling m_errorHandling = ShowInPane;
bool m_modifiesCurrentDocument = false; bool m_modifiesCurrentDocument = false;

View File

@@ -319,12 +319,12 @@ bool BuildConfiguration::useSystemEnvironment() const
return !m_clearSystemEnvironment; return !m_clearSystemEnvironment;
} }
QList<Utils::EnvironmentItem> BuildConfiguration::userEnvironmentChanges() const Utils::EnvironmentItems BuildConfiguration::userEnvironmentChanges() const
{ {
return m_userEnvironmentChanges; return m_userEnvironmentChanges;
} }
void BuildConfiguration::setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff) void BuildConfiguration::setUserEnvironmentChanges(const Utils::EnvironmentItems &diff)
{ {
if (m_userEnvironmentChanges == diff) if (m_userEnvironmentChanges == diff)
return; return;

View File

@@ -62,8 +62,8 @@ public:
Utils::Environment baseEnvironment() const; Utils::Environment baseEnvironment() const;
QString baseEnvironmentText() const; QString baseEnvironmentText() const;
Utils::Environment environment() const; Utils::Environment environment() const;
void setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff); void setUserEnvironmentChanges(const Utils::EnvironmentItems &diff);
QList<Utils::EnvironmentItem> userEnvironmentChanges() const; Utils::EnvironmentItems userEnvironmentChanges() const;
bool useSystemEnvironment() const; bool useSystemEnvironment() const;
void setUseSystemEnvironment(bool b); void setUseSystemEnvironment(bool b);
@@ -117,7 +117,7 @@ private:
void emitBuildDirectoryChanged(); void emitBuildDirectoryChanged();
bool m_clearSystemEnvironment = false; bool m_clearSystemEnvironment = false;
QList<Utils::EnvironmentItem> m_userEnvironmentChanges; Utils::EnvironmentItems m_userEnvironmentChanges;
QList<BuildStepList *> m_stepLists; QList<BuildStepList *> m_stepLists;
ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr; ProjectExplorer::BaseStringAspect *m_buildDirectoryAspect = nullptr;
Utils::FilePath m_lastEmmitedBuildDirectory; Utils::FilePath m_lastEmmitedBuildDirectory;

View File

@@ -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) { if (m_userChanges != diff) {
m_userChanges = diff; m_userChanges = diff;

View File

@@ -49,8 +49,8 @@ public:
int baseEnvironmentBase() const; int baseEnvironmentBase() const;
void setBaseEnvironmentBase(int base); void setBaseEnvironmentBase(int base);
QList<Utils::EnvironmentItem> userEnvironmentChanges() const { return m_userChanges; } Utils::EnvironmentItems userEnvironmentChanges() const { return m_userChanges; }
void setUserEnvironmentChanges(const QList<Utils::EnvironmentItem> &diff); void setUserEnvironmentChanges(const Utils::EnvironmentItems &diff);
void addSupportedBaseEnvironment(const QString &displayName, void addSupportedBaseEnvironment(const QString &displayName,
const std::function<Utils::Environment()> &getter); const std::function<Utils::Environment()> &getter);
@@ -70,7 +70,7 @@ public:
signals: signals:
void baseEnvironmentChanged(); void baseEnvironmentChanged();
void userEnvironmentChangesChanged(const QList<Utils::EnvironmentItem> &diff); void userEnvironmentChangesChanged(const Utils::EnvironmentItems &diff);
void environmentChanged(); void environmentChanged();
protected: protected:
@@ -88,7 +88,7 @@ private:
QString displayName; QString displayName;
}; };
QList<Utils::EnvironmentItem> m_userChanges; Utils::EnvironmentItems m_userChanges;
QList<EnvironmentModifier> m_modifiers; QList<EnvironmentModifier> m_modifiers;
QList<BaseEnvironment> m_baseEnvironments; QList<BaseEnvironment> m_baseEnvironments;
int m_base = -1; int m_base = -1;

View File

@@ -132,7 +132,7 @@ void EnvironmentAspectWidget::userChangesEdited()
m_ignoreChange = false; m_ignoreChange = false;
} }
void EnvironmentAspectWidget::changeUserChanges(QList<Utils::EnvironmentItem> changes) void EnvironmentAspectWidget::changeUserChanges(Utils::EnvironmentItems changes)
{ {
if (m_ignoreChange) if (m_ignoreChange)
return; return;

View File

@@ -61,7 +61,7 @@ private:
void baseEnvironmentSelected(int idx); void baseEnvironmentSelected(int idx);
void changeBaseEnvironment(); void changeBaseEnvironment();
void userChangesEdited(); void userChangesEdited();
void changeUserChanges(QList<Utils::EnvironmentItem> changes); void changeUserChanges(Utils::EnvironmentItems changes);
void environmentChanged(); void environmentChanged();
EnvironmentAspect *m_aspect; EnvironmentAspect *m_aspect;

View File

@@ -30,11 +30,12 @@
#include <utils/detailswidget.h> #include <utils/detailswidget.h>
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/environmentmodel.h>
#include <utils/environmentdialog.h> #include <utils/environmentdialog.h>
#include <utils/environmentmodel.h>
#include <utils/headerviewstretcher.h> #include <utils/headerviewstretcher.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/itemviews.h> #include <utils/itemviews.h>
#include <utils/namevaluevalidator.h>
#include <utils/tooltip/tooltip.h> #include <utils/tooltip/tooltip.h>
#include <QDir> #include <QDir>
@@ -51,48 +52,6 @@
namespace ProjectExplorer { 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 class EnvironmentDelegate : public QStyledItemDelegate
{ {
public: public:
@@ -108,7 +67,8 @@ public:
return w; return w;
if (auto edit = qobject_cast<QLineEdit *>(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; return w;
} }
private: private:
@@ -301,12 +261,12 @@ void EnvironmentWidget::setBaseEnvironmentText(const QString &text)
updateSummaryText(); updateSummaryText();
} }
QList<Utils::EnvironmentItem> EnvironmentWidget::userChanges() const Utils::EnvironmentItems EnvironmentWidget::userChanges() const
{ {
return d->m_model->userChanges(); 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); d->m_model->setUserChanges(list);
updateSummaryText(); updateSummaryText();
@@ -320,7 +280,7 @@ void EnvironmentWidget::setOpenTerminalFunc(const EnvironmentWidget::OpenTermina
void EnvironmentWidget::updateSummaryText() void EnvironmentWidget::updateSummaryText()
{ {
QList<Utils::EnvironmentItem> list = d->m_model->userChanges(); Utils::EnvironmentItems list = d->m_model->userChanges();
Utils::EnvironmentItem::sort(&list); Utils::EnvironmentItem::sort(&list);
QString text; QString text;
@@ -455,14 +415,12 @@ void EnvironmentWidget::prependPathButtonClicked()
void EnvironmentWidget::batchEditEnvironmentButtonClicked() void EnvironmentWidget::batchEditEnvironmentButtonClicked()
{ {
const QList<Utils::EnvironmentItem> changes = d->m_model->userChanges(); const Utils::EnvironmentItems changes = d->m_model->userChanges();
bool ok; const auto newChanges = Utils::EnvironmentDialog::getEnvironmentItems(this, changes);
const QList<Utils::EnvironmentItem> newChanges = Utils::EnvironmentDialog::getEnvironmentItems(&ok, this, changes);
if (!ok)
return;
d->m_model->setUserChanges(newChanges); if (newChanges)
d->m_model->setUserChanges(*newChanges);
} }
void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current) void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex &current)
@@ -491,5 +449,3 @@ void EnvironmentWidget::invalidateCurrentIndex()
} }
} // namespace ProjectExplorer } // namespace ProjectExplorer
#include "environmentwidget.moc"

View File

@@ -27,6 +27,8 @@
#include "projectexplorer_export.h" #include "projectexplorer_export.h"
#include <utils/environmentfwd.h>
#include <QWidget> #include <QWidget>
#include <functional> #include <functional>
@@ -34,11 +36,6 @@
QT_FORWARD_DECLARE_CLASS(QModelIndex) QT_FORWARD_DECLARE_CLASS(QModelIndex)
namespace Utils {
class Environment;
class EnvironmentItem;
} // namespace Utils
namespace ProjectExplorer { namespace ProjectExplorer {
class EnvironmentWidgetPrivate; class EnvironmentWidgetPrivate;
@@ -56,8 +53,8 @@ public:
void setBaseEnvironmentText(const QString &text); void setBaseEnvironmentText(const QString &text);
void setBaseEnvironment(const Utils::Environment &env); void setBaseEnvironment(const Utils::Environment &env);
QList<Utils::EnvironmentItem> userChanges() const; Utils::EnvironmentItems userChanges() const;
void setUserChanges(const QList<Utils::EnvironmentItem> &list); void setUserChanges(const Utils::EnvironmentItems &list);
using OpenTerminalFunc = std::function<void(const Utils::Environment &env)>; using OpenTerminalFunc = std::function<void(const Utils::Environment &env)>;
void setOpenTerminalFunc(const OpenTerminalFunc &func); void setOpenTerminalFunc(const OpenTerminalFunc &func);

View File

@@ -254,7 +254,7 @@ Utils::Environment ExtraCompiler::buildEnvironment() const
if (BuildConfiguration *bc = target->activeBuildConfiguration()) { if (BuildConfiguration *bc = target->activeBuildConfiguration()) {
return bc->environment(); return bc->environment();
} else { } else {
QList<Utils::EnvironmentItem> changes = Utils::EnvironmentItems changes =
EnvironmentKitAspect::environmentChanges(target->kit()); EnvironmentKitAspect::environmentChanges(target->kit());
Utils::Environment env = Utils::Environment::systemEnvironment(); Utils::Environment env = Utils::Environment::systemEnvironment();
env.modify(changes); env.modify(changes);

View File

@@ -1150,7 +1150,7 @@ private:
void refresh() override void refresh() override
{ {
const QList<Utils::EnvironmentItem> changes = currentEnvironment(); const Utils::EnvironmentItems changes = currentEnvironment();
QString shortSummary = Utils::EnvironmentItem::toStringList(changes).join(QLatin1String("; ")); QString shortSummary = Utils::EnvironmentItem::toStringList(changes).join(QLatin1String("; "));
QFontMetrics fm(m_summaryLabel->font()); QFontMetrics fm(m_summaryLabel->font());
shortSummary = fm.elidedText(shortSummary, Qt::ElideRight, m_summaryLabel->width()); shortSummary = fm.elidedText(shortSummary, Qt::ElideRight, m_summaryLabel->width());
@@ -1159,32 +1159,29 @@ private:
void editEnvironmentChanges() void editEnvironmentChanges()
{ {
bool ok;
Utils::MacroExpander *expander = m_kit->macroExpander(); Utils::MacroExpander *expander = m_kit->macroExpander();
Utils::EnvironmentDialog::Polisher polisher = [expander](QWidget *w) { Utils::EnvironmentDialog::Polisher polisher = [expander](QWidget *w) {
Core::VariableChooser::addSupportForChildWidgets(w, expander); Core::VariableChooser::addSupportForChildWidgets(w, expander);
}; };
QList<Utils::EnvironmentItem> auto changes = Utils::EnvironmentDialog::getEnvironmentItems(m_summaryLabel,
changes = Utils::EnvironmentDialog::getEnvironmentItems(&ok, currentEnvironment(),
m_summaryLabel, QString(),
currentEnvironment(), polisher);
QString(), if (!changes)
polisher);
if (!ok)
return; return;
if (Utils::HostOsInfo::isWindowsHost()) { if (Utils::HostOsInfo::isWindowsHost()) {
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033"); const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (m_vslangCheckbox->isChecked() && changes.indexOf(forceMSVCEnglishItem) < 0) if (m_vslangCheckbox->isChecked() && changes->indexOf(forceMSVCEnglishItem) < 0)
changes.append(forceMSVCEnglishItem); 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()) { if (Utils::HostOsInfo::isWindowsHost()) {
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033"); const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
@@ -1207,8 +1204,7 @@ private:
"just forces UTF-8 output (may vary depending on the used MSVC " "just forces UTF-8 output (may vary depending on the used MSVC "
"compiler).")); "compiler)."));
connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) { connect(m_vslangCheckbox, &QCheckBox::toggled, this, [this](bool checked) {
QList<Utils::EnvironmentItem> changes Utils::EnvironmentItems changes = EnvironmentKitAspect::environmentChanges(m_kit);
= EnvironmentKitAspect::environmentChanges(m_kit);
const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033"); const Utils::EnvironmentItem forceMSVCEnglishItem("VSLANG", "1033");
if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0) if (!checked && changes.indexOf(forceMSVCEnglishItem) >= 0)
changes.removeAll(forceMSVCEnglishItem); changes.removeAll(forceMSVCEnglishItem);
@@ -1254,7 +1250,7 @@ void EnvironmentKitAspect::fix(Kit *k)
const QVariant variant = k->value(EnvironmentKitAspect::id()); const QVariant variant = k->value(EnvironmentKitAspect::id());
if (!variant.isNull() && !variant.canConvert(QVariant::List)) { if (!variant.isNull() && !variant.canConvert(QVariant::List)) {
qWarning("Kit \"%s\" has a wrong environment value set.", qPrintable(k->displayName())); 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"; return "PE.Profile.Environment";
} }
QList<Utils::EnvironmentItem> EnvironmentKitAspect::environmentChanges(const Kit *k) Utils::EnvironmentItems EnvironmentKitAspect::environmentChanges(const Kit *k)
{ {
if (k) if (k)
return Utils::EnvironmentItem::fromStringList(k->value(EnvironmentKitAspect::id()).toStringList()); 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) if (k)
k->setValue(EnvironmentKitAspect::id(), Utils::EnvironmentItem::toStringList(changes)); k->setValue(EnvironmentKitAspect::id(), Utils::EnvironmentItem::toStringList(changes));

View File

@@ -186,8 +186,8 @@ public:
ItemList toUserOutput(const Kit *k) const override; ItemList toUserOutput(const Kit *k) const override;
static Core::Id id(); static Core::Id id();
static QList<Utils::EnvironmentItem> environmentChanges(const Kit *k); static Utils::EnvironmentItems environmentChanges(const Kit *k);
static void setEnvironmentChanges(Kit *k, const QList<Utils::EnvironmentItem> &changes); static void setEnvironmentChanges(Kit *k, const Utils::EnvironmentItems &changes);
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -715,7 +715,7 @@ void MsvcToolChain::environmentModifications(
const Utils::Environment inEnv = Utils::Environment::systemEnvironment(); const Utils::Environment inEnv = Utils::Environment::systemEnvironment();
Utils::Environment outEnv; Utils::Environment outEnv;
QMap<QString, QString> envPairs; QMap<QString, QString> envPairs;
QList<Utils::EnvironmentItem> diff; Utils::EnvironmentItems diff;
Utils::optional<QString> error = generateEnvironmentSettings(inEnv, Utils::optional<QString> error = generateEnvironmentSettings(inEnv,
vcvarsBat, vcvarsBat,
varsBatArg, varsBatArg,
@@ -764,7 +764,7 @@ void MsvcToolChain::initEnvModWatcher(const QFuture<GenerateEnvResult> &future)
m_envModWatcher.setFuture(future); m_envModWatcher.setFuture(future);
} }
void MsvcToolChain::updateEnvironmentModifications(QList<Utils::EnvironmentItem> modifications) void MsvcToolChain::updateEnvironmentModifications(Utils::EnvironmentItems modifications)
{ {
Utils::EnvironmentItem::sort(&modifications); Utils::EnvironmentItem::sort(&modifications);
if (modifications != m_environmentModifications) { if (modifications != m_environmentModifications) {

View File

@@ -28,6 +28,7 @@
#include "abi.h" #include "abi.h"
#include "abiwidget.h" #include "abiwidget.h"
#include "toolchain.h" #include "toolchain.h"
#include "toolchaincache.h"
#include "toolchainconfigwidget.h" #include "toolchainconfigwidget.h"
#include <QFutureWatcher> #include <QFutureWatcher>
@@ -142,7 +143,7 @@ protected:
struct GenerateEnvResult struct GenerateEnvResult
{ {
Utils::optional<QString> error; Utils::optional<QString> error;
QList<Utils::EnvironmentItem> environmentItems; Utils::EnvironmentItems environmentItems;
}; };
static void environmentModifications(QFutureInterface<GenerateEnvResult> &future, static void environmentModifications(QFutureInterface<GenerateEnvResult> &future,
QString vcvarsBat, QString vcvarsBat,
@@ -154,11 +155,11 @@ protected:
mutable HeaderPaths m_headerPaths; mutable HeaderPaths m_headerPaths;
private: private:
void updateEnvironmentModifications(QList<Utils::EnvironmentItem> modifications); void updateEnvironmentModifications(Utils::EnvironmentItems modifications);
void rescanForCompiler(); void rescanForCompiler();
void detectInstalledAbis(); void detectInstalledAbis();
mutable QList<Utils::EnvironmentItem> m_environmentModifications; mutable Utils::EnvironmentItems m_environmentModifications;
mutable QFutureWatcher<GenerateEnvResult> m_envModWatcher; mutable QFutureWatcher<GenerateEnvResult> m_envModWatcher;
mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment. mutable Utils::Environment m_lastEnvironment; // Last checked 'incoming' environment.

View File

@@ -98,7 +98,7 @@ bool QmlProjectItem::matchesFile(const QString &filePath) const
return false; return false;
} }
QList<Utils::EnvironmentItem> QmlProjectItem::environment() const Utils::EnvironmentItems QmlProjectItem::environment() const
{ {
return m_environment; return m_environment;
} }

View File

@@ -65,7 +65,7 @@ public:
void appendContent(QmlProjectContentItem *item) { m_content.append(item); } 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); void addToEnviroment(const QString &key, const QString &value);
signals: signals:
@@ -77,7 +77,7 @@ protected:
QStringList m_importPaths; QStringList m_importPaths;
QStringList m_fileSelectors; QStringList m_fileSelectors;
QString m_mainFile; QString m_mainFile;
QList<Utils::EnvironmentItem> m_environment; Utils::EnvironmentItems m_environment;
QList<QmlProjectContentItem *> m_content; // content property QList<QmlProjectContentItem *> m_content; // content property
}; };

View File

@@ -206,7 +206,7 @@ Utils::FilePath QmlProject::targetFile(const Utils::FilePath &sourceFile,
return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative))); return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
} }
QList<Utils::EnvironmentItem> QmlProject::environment() const Utils::EnvironmentItems QmlProject::environment() const
{ {
if (m_projectItem) if (m_projectItem)
return m_projectItem.data()->environment(); return m_projectItem.data()->environment();

View File

@@ -69,7 +69,7 @@ public:
Utils::FilePath targetFile(const Utils::FilePath &sourceFile, Utils::FilePath targetFile(const Utils::FilePath &sourceFile,
const ProjectExplorer::Target *target) const; const ProjectExplorer::Target *target) const;
QList<Utils::EnvironmentItem> environment() const; Utils::EnvironmentItems environment() const;
QStringList customImportPaths() const; QStringList customImportPaths() const;
QStringList customFileSelectors() const; QStringList customFileSelectors() const;

View File

@@ -107,7 +107,7 @@ FilePath QnxConfiguration::qccCompilerPath() const
return m_qccCompiler; return m_qccCompiler;
} }
QList<EnvironmentItem> QnxConfiguration::qnxEnv() const EnvironmentItems QnxConfiguration::qnxEnv() const
{ {
return m_qnxEnv; return m_qnxEnv;
} }

View File

@@ -61,7 +61,7 @@ public:
Utils::FilePath qnxTarget() const; Utils::FilePath qnxTarget() const;
Utils::FilePath qnxHost() const; Utils::FilePath qnxHost() const;
Utils::FilePath qccCompilerPath() const; Utils::FilePath qccCompilerPath() const;
QList<Utils::EnvironmentItem> qnxEnv() const; Utils::EnvironmentItems qnxEnv() const;
QnxVersionNumber version() const; QnxVersionNumber version() const;
QVariantMap toMap() const; QVariantMap toMap() const;
@@ -97,7 +97,7 @@ private:
Utils::FilePath m_qnxTarget; Utils::FilePath m_qnxTarget;
Utils::FilePath m_qnxHost; Utils::FilePath m_qnxHost;
Utils::FilePath m_qccCompiler; Utils::FilePath m_qccCompiler;
QList<Utils::EnvironmentItem> m_qnxEnv; Utils::EnvironmentItems m_qnxEnv;
QnxVersionNumber m_version; QnxVersionNumber m_version;
class Target class Target

View File

@@ -184,7 +184,7 @@ void QnxQtVersion::updateEnvironment() const
} }
} }
QList<Utils::EnvironmentItem> QnxQtVersion::environment() const Utils::EnvironmentItems QnxQtVersion::environment() const
{ {
return QnxUtils::qnxEnvironment(sdpPath()); return QnxUtils::qnxEnvironment(sdpPath());
} }

View File

@@ -73,13 +73,13 @@ protected:
private: private:
void updateEnvironment() const; void updateEnvironment() const;
QList<Utils::EnvironmentItem> environment() const; Utils::EnvironmentItems environment() const;
QString m_sdpPath; QString m_sdpPath;
mutable QString m_cpuDir; mutable QString m_cpuDir;
mutable bool m_environmentUpToDate = false; mutable bool m_environmentUpToDate = false;
mutable QList<Utils::EnvironmentItem> m_qnxEnv; mutable Utils::EnvironmentItems m_qnxEnv;
}; };
class QnxQtVersionFactory : public QtSupport::QtVersionFactory class QnxQtVersionFactory : public QtSupport::QtVersionFactory

View File

@@ -50,7 +50,7 @@ static Abis detectTargetAbis(const FilePath &sdpPath)
FilePath qnxTarget; FilePath qnxTarget;
if (!sdpPath.fileName().isEmpty()) { 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) { foreach (const Utils::EnvironmentItem &item, environment) {
if (item.name == QLatin1Literal("QNX_TARGET")) if (item.name == QLatin1Literal("QNX_TARGET"))
qnxTarget = FilePath::fromString(item.value); qnxTarget = FilePath::fromString(item.value);
@@ -72,12 +72,11 @@ static Abis detectTargetAbis(const FilePath &sdpPath)
return result; 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 // We only need to set QNX_HOST and QNX_TARGET needed when running qcc
foreach (const EnvironmentItem &item, qnxEnv) { foreach (const EnvironmentItem &item, qnxEnv) {
if (item.name == QLatin1String("QNX_HOST") || if (item.name == QLatin1String("QNX_HOST") || item.name == QLatin1String("QNX_TARGET"))
item.name == QLatin1String("QNX_TARGET") )
env.set(item.name, item.value); env.set(item.name, item.value);
} }
} }

View File

@@ -73,9 +73,9 @@ QString QnxUtils::cpuDirShortDescription(const QString &cpuDir)
return 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)) if (!QFileInfo::exists(fileName))
return items; return items;
@@ -206,7 +206,7 @@ QList<ConfigInstallInformation> QnxUtils::installedConfigs(const QString &config
return sdpList; return sdpList;
} }
QList<Utils::EnvironmentItem> QnxUtils::qnxEnvironment(const QString &sdpPath) Utils::EnvironmentItems QnxUtils::qnxEnvironment(const QString &sdpPath)
{ {
return qnxEnvironmentFromEnvFile(envFilePath(sdpPath)); return qnxEnvironmentFromEnvFile(envFilePath(sdpPath));
} }

View File

@@ -70,11 +70,11 @@ class QnxUtils
public: public:
static QString addQuotes(const QString &string); static QString addQuotes(const QString &string);
static QString cpuDirShortDescription(const QString &cpuDir); 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 envFilePath(const QString &sdpPath);
static QString defaultTargetVersion(const QString &sdpPath); static QString defaultTargetVersion(const QString &sdpPath);
static QList<ConfigInstallInformation> installedConfigs(const QString &configPath = QString()); 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 QList<QnxTarget> findTargets(const Utils::FilePath &basePath);
static ProjectExplorer::Abi convertAbi(const ProjectExplorer::Abi &abi); static ProjectExplorer::Abi convertAbi(const ProjectExplorer::Abi &abi);
static ProjectExplorer::Abis convertAbis(const ProjectExplorer::Abis &abis); static ProjectExplorer::Abis convertAbis(const ProjectExplorer::Abis &abis);

View File

@@ -34,7 +34,7 @@ const char DISPLAY_KEY[] = "DISPLAY";
const char VERSION_KEY[] = "RemoteLinux.EnvironmentAspect.Version"; const char VERSION_KEY[] = "RemoteLinux.EnvironmentAspect.Version";
const int ENVIRONMENTASPECT_VERSION = 1; // Version was introduced in 4.3 with the value 1 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 Utils::contains(changes, [](const Utils::EnvironmentItem &item) {
return item.name == DISPLAY_KEY; return item.name == DISPLAY_KEY;

View File

@@ -102,6 +102,7 @@ newFrontendActionFactory(Factory *consumerFactory,
bool BeginInvocation(clang::CompilerInstance &compilerInstance) override bool BeginInvocation(clang::CompilerInstance &compilerInstance) override
{ {
compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true; compilerInstance.getPreprocessorOpts().AllowPCHWithCompilerErrors = true;
compilerInstance.getDiagnosticOpts().ErrorLimit = 1;
return clang::ASTFrontendAction::BeginInvocation(compilerInstance); return clang::ASTFrontendAction::BeginInvocation(compilerInstance);
} }

View File

@@ -33,6 +33,8 @@ SOURCES += \
$$UTILS/environment.cpp \ $$UTILS/environment.cpp \
$$UTILS/fileutils.cpp \ $$UTILS/fileutils.cpp \
$$UTILS/hostosinfo.cpp \ $$UTILS/hostosinfo.cpp \
$$UTILS/namevaluedictionary.cpp \
$$UTILS/namevalueitem.cpp \
$$UTILS/persistentsettings.cpp \ $$UTILS/persistentsettings.cpp \
$$UTILS/qtcassert.cpp \ $$UTILS/qtcassert.cpp \
$$UTILS/qtcprocess.cpp \ $$UTILS/qtcprocess.cpp \
@@ -63,6 +65,8 @@ HEADERS += \
$$UTILS/environment.h \ $$UTILS/environment.h \
$$UTILS/fileutils.h \ $$UTILS/fileutils.h \
$$UTILS/hostosinfo.h \ $$UTILS/hostosinfo.h \
$$UTILS/namevaluedictionary.h \
$$UTILS/namevalueitem.h \
$$UTILS/persistentsettings.h \ $$UTILS/persistentsettings.h \
$$UTILS/qtcassert.h \ $$UTILS/qtcassert.h \
$$UTILS/qtcprocess.h \ $$UTILS/qtcprocess.h \

View File

@@ -43,6 +43,10 @@ public:
Target *activeTarget() const { return {}; } 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; Utils::FileName rootProjectDirectoryPath;
std::map<QString, QVariant> settings;
}; };
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -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

View File

@@ -34,10 +34,11 @@
#include <pchmanagerclient.h> #include <pchmanagerclient.h>
#include <pchmanagerprojectupdater.h> #include <pchmanagerprojectupdater.h>
#include <clangindexingsettingsmanager.h>
#include <filepathcaching.h> #include <filepathcaching.h>
#include <refactoringdatabaseinitializer.h>
#include <precompiledheadersupdatedmessage.h> #include <precompiledheadersupdatedmessage.h>
#include <progressmessage.h> #include <progressmessage.h>
#include <refactoringdatabaseinitializer.h>
#include <removegeneratedfilesmessage.h> #include <removegeneratedfilesmessage.h>
#include <removeprojectpartsmessage.h> #include <removeprojectpartsmessage.h>
#include <updategeneratedfilesmessage.h> #include <updategeneratedfilesmessage.h>
@@ -60,10 +61,12 @@ protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database}; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
ClangBackEnd::FilePathCaching filePathCache{database}; ClangBackEnd::FilePathCaching filePathCache{database};
ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer, ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer,
client, client,
filePathCache, filePathCache,
mockProjectPartsStorage}; mockProjectPartsStorage,
settingsManager};
ClangBackEnd::ProjectPartId projectPartId{1}; ClangBackEnd::ProjectPartId projectPartId{1};
ClangBackEnd::FilePath pchFilePath{"/path/to/pch"}; ClangBackEnd::FilePath pchFilePath{"/path/to/pch"};
PrecompiledHeadersUpdatedMessage message{{{projectPartId, pchFilePath.clone(), 1}}}; PrecompiledHeadersUpdatedMessage message{{{projectPartId, pchFilePath.clone(), 1}}};

View File

@@ -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

View File

@@ -35,6 +35,8 @@
#include <pchmanagerprojectupdater.h> #include <pchmanagerprojectupdater.h>
#include <clangindexingprojectsettings.h>
#include <clangindexingsettingsmanager.h>
#include <filepathcaching.h> #include <filepathcaching.h>
#include <pchmanagerclient.h> #include <pchmanagerclient.h>
#include <precompiledheaderstorage.h> #include <precompiledheaderstorage.h>
@@ -52,6 +54,7 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/namevalueitem.h>
namespace { namespace {
@@ -94,7 +97,7 @@ protected:
projectPart.files.push_back(source2ProjectFile); projectPart.files.push_back(source2ProjectFile);
projectPart.files.push_back(nonActiveProjectFile); projectPart.files.push_back(nonActiveProjectFile);
projectPart.displayName = "projectb"; projectPart.displayName = "projectb";
projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}}; projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}, {"POO", "3"}};
projectPartId = projectPartsStorage.fetchProjectPartId(Utils::SmallString{projectPart.id()}); projectPartId = projectPartsStorage.fetchProjectPartId(Utils::SmallString{projectPart.id()});
projectPart2.project = &project; projectPart2.project = &project;
@@ -138,6 +141,9 @@ protected:
Utils::Language::Cxx, Utils::Language::Cxx,
Utils::LanguageVersion::LatestCxx, Utils::LanguageVersion::LatestCxx,
Utils::LanguageExtension::None}; Utils::LanguageExtension::None};
auto settings = settingsManager.settings(&project);
settings->saveMacros({{"POO", "3", Utils::NameValueItem::Unset}});
} }
protected: protected:
@@ -151,7 +157,11 @@ protected:
mockDependencyCreationProgressManager}; mockDependencyCreationProgressManager};
MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient}; MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient};
NiceMock<MockPchManagerServer> mockPchManagerServer; NiceMock<MockPchManagerServer> mockPchManagerServer;
ClangPchManager::ProjectUpdater updater{mockPchManagerServer, filePathCache, projectPartsStorage}; ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangPchManager::ProjectUpdater updater{mockPchManagerServer,
filePathCache,
projectPartsStorage,
settingsManager};
ClangBackEnd::ProjectPartId projectPartId; ClangBackEnd::ProjectPartId projectPartId;
ClangBackEnd::ProjectPartId projectPartId2; ClangBackEnd::ProjectPartId projectPartId2;
Utils::PathStringVector headerPaths = {"/path/to/header1.h", "/path/to/header2.h"}; Utils::PathStringVector headerPaths = {"/path/to/header1.h", "/path/to/header2.h"};
@@ -243,10 +253,12 @@ TEST_F(ProjectUpdater, CallRemoveProjectParts)
TEST_F(ProjectUpdater, CallPrecompiledHeaderRemovedInPchManagerProjectUpdater) TEST_F(ProjectUpdater, CallPrecompiledHeaderRemovedInPchManagerProjectUpdater)
{ {
ClangPchManager::ClangIndexingSettingsManager settingManager;
ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer, ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer,
pchManagerClient, pchManagerClient,
filePathCache, filePathCache,
projectPartsStorage}; projectPartsStorage,
settingManager};
ClangBackEnd::RemoveProjectPartsMessage message{{projectPartId, projectPartId2}}; ClangBackEnd::RemoveProjectPartsMessage message{{projectPartId, projectPartId2}};
EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId)); EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId));
@@ -283,9 +295,11 @@ TEST_F(ProjectUpdater, CallStorageInsideTransaction)
MockProjectPartsStorage mockProjectPartsStorage; MockProjectPartsStorage mockProjectPartsStorage;
ON_CALL(mockProjectPartsStorage, transactionBackend()) ON_CALL(mockProjectPartsStorage, transactionBackend())
.WillByDefault(ReturnRef(mockSqliteTransactionBackend)); .WillByDefault(ReturnRef(mockSqliteTransactionBackend));
ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangPchManager::ProjectUpdater updater{mockPchManagerServer, ClangPchManager::ProjectUpdater updater{mockPchManagerServer,
filePathCache, filePathCache,
mockProjectPartsStorage}; mockProjectPartsStorage,
settingsManager};
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartId(Eq(projectPartName))); EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartId(Eq(projectPartName)));
@@ -303,7 +317,7 @@ TEST_F(ProjectUpdater, CreateSortedExcludedPaths)
TEST_F(ProjectUpdater, CreateSortedCompilerMacros) 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}, ASSERT_THAT(paths, ElementsAre(CompilerMacro{"BAR", "1", 1},
CompilerMacro{"FOO", "2", 2}, CompilerMacro{"FOO", "2", 2},
@@ -312,12 +326,28 @@ TEST_F(ProjectUpdater, CreateSortedCompilerMacros)
TEST_F(ProjectUpdater, FilterCompilerMacros) TEST_F(ProjectUpdater, FilterCompilerMacros)
{ {
auto paths = updater.createCompilerMacros( auto paths = updater.createCompilerMacros({{"DEFINE", "1"},
{{"DEFINE", "1"}, {"QT_TESTCASE_BUILDDIR", "2"}, {"BAR", "1"}}); {"QT_TESTCASE_BUILDDIR", "2"},
{"BAR", "1"}},
{});
ASSERT_THAT(paths, ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"DEFINE", "1", 3})); 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) TEST_F(ProjectUpdater, CreateSortedIncludeSearchPaths)
{ {
CppTools::ProjectPart projectPart; CppTools::ProjectPart projectPart;

View File

@@ -32,10 +32,11 @@
#include <sqlitedatabase.h> #include <sqlitedatabase.h>
#include <clangindexingsettingsmanager.h>
#include <clangrefactoringservermessages.h>
#include <filepathcaching.h> #include <filepathcaching.h>
#include <precompiledheadersupdatedmessage.h> #include <precompiledheadersupdatedmessage.h>
#include <refactoringdatabaseinitializer.h> #include <refactoringdatabaseinitializer.h>
#include <clangrefactoringservermessages.h>
#include <pchmanagerclient.h> #include <pchmanagerclient.h>
@@ -84,11 +85,13 @@ protected:
mockDependencyCreationProgressManager}; mockDependencyCreationProgressManager};
MockCppModelManager mockCppModelManager; MockCppModelManager mockCppModelManager;
ProjectExplorer::Project project; ProjectExplorer::Project project;
ClangPchManager::ClangIndexingSettingsManager settingsManager;
ClangRefactoring::RefactoringProjectUpdater updater{mockRefactoringServer, ClangRefactoring::RefactoringProjectUpdater updater{mockRefactoringServer,
pchManagerClient, pchManagerClient,
mockCppModelManager, mockCppModelManager,
filePathCache, filePathCache,
mockProjectPartsStorage}; mockProjectPartsStorage,
settingsManager};
Utils::SmallString projectPartId; Utils::SmallString projectPartId;
}; };

View File

@@ -47,6 +47,7 @@ DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\"
SOURCES += \ SOURCES += \
changedfilepathcompressor-test.cpp \ changedfilepathcompressor-test.cpp \
clangindexingsettingsmanager-test.cpp \
clangpathwatcher-test.cpp \ clangpathwatcher-test.cpp \
clangqueryexamplehighlightmarker-test.cpp \ clangqueryexamplehighlightmarker-test.cpp \
clangqueryhighlightmarker-test.cpp \ clangqueryhighlightmarker-test.cpp \
@@ -67,6 +68,7 @@ SOURCES += \
pchmanagerclientserverinprocess-test.cpp \ pchmanagerclientserverinprocess-test.cpp \
pchmanagerclient-test.cpp \ pchmanagerclient-test.cpp \
pchmanagerserver-test.cpp \ pchmanagerserver-test.cpp \
preprocessormacrocollector-test.cpp \
processevents-utilities.cpp \ processevents-utilities.cpp \
projectpartsmanager-test.cpp \ projectpartsmanager-test.cpp \
projectpartsstorage-test.cpp \ projectpartsstorage-test.cpp \