forked from qt-creator/qt-creator
EnvironmentWidget: Add convenient way to add to path list
Sometimes, users want to add entries into environment variables such as PATH, which can get a bit fiddly when doing it by hand. So let's add convenience UI elements for adding directories to such variables. Change-Id: I81c71ea0052893ff0a8175508b71cd73d83dd849 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -43,7 +43,8 @@ BuildEnvironmentWidget::BuildEnvironmentWidget(BuildConfiguration *bc) :
|
|||||||
m_clearSystemEnvironmentCheckBox = new QCheckBox(this);
|
m_clearSystemEnvironmentCheckBox = new QCheckBox(this);
|
||||||
m_clearSystemEnvironmentCheckBox->setText(tr("Clear system environment"));
|
m_clearSystemEnvironmentCheckBox->setText(tr("Clear system environment"));
|
||||||
|
|
||||||
m_buildEnvironmentWidget = new EnvironmentWidget(this, m_clearSystemEnvironmentCheckBox);
|
m_buildEnvironmentWidget = new EnvironmentWidget(this, EnvironmentWidget::TypeLocal,
|
||||||
|
m_clearSystemEnvironmentCheckBox);
|
||||||
vbox->addWidget(m_buildEnvironmentWidget);
|
vbox->addWidget(m_buildEnvironmentWidget);
|
||||||
|
|
||||||
connect(m_buildEnvironmentWidget, &EnvironmentWidget::userChangesChanged,
|
connect(m_buildEnvironmentWidget, &EnvironmentWidget::userChangesChanged,
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ public:
|
|||||||
using EnvironmentModifier = std::function<void(Utils::Environment &)>;
|
using EnvironmentModifier = std::function<void(Utils::Environment &)>;
|
||||||
void addModifier(const EnvironmentModifier &);
|
void addModifier(const EnvironmentModifier &);
|
||||||
|
|
||||||
|
bool isLocal() const { return m_isLocal; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void baseEnvironmentChanged();
|
void baseEnvironmentChanged();
|
||||||
void userEnvironmentChangesChanged(const QList<Utils::EnvironmentItem> &diff);
|
void userEnvironmentChangesChanged(const QList<Utils::EnvironmentItem> &diff);
|
||||||
@@ -75,6 +77,8 @@ protected:
|
|||||||
void fromMap(const QVariantMap &map) override;
|
void fromMap(const QVariantMap &map) override;
|
||||||
void toMap(QVariantMap &map) const override;
|
void toMap(QVariantMap &map) const override;
|
||||||
|
|
||||||
|
void setIsLocal(bool local) { m_isLocal = local; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// One possible choice in the Environment aspect.
|
// One possible choice in the Environment aspect.
|
||||||
struct BaseEnvironment {
|
struct BaseEnvironment {
|
||||||
@@ -84,10 +88,11 @@ private:
|
|||||||
QString displayName;
|
QString displayName;
|
||||||
};
|
};
|
||||||
|
|
||||||
int m_base = -1;
|
|
||||||
QList<Utils::EnvironmentItem> m_userChanges;
|
QList<Utils::EnvironmentItem> m_userChanges;
|
||||||
QList<EnvironmentModifier> m_modifiers;
|
QList<EnvironmentModifier> m_modifiers;
|
||||||
QList<BaseEnvironment> m_baseEnvironments;
|
QList<BaseEnvironment> m_baseEnvironments;
|
||||||
|
int m_base = -1;
|
||||||
|
bool m_isLocal = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect, QWid
|
|||||||
if (additionalWidget)
|
if (additionalWidget)
|
||||||
baseLayout->addWidget(additionalWidget);
|
baseLayout->addWidget(additionalWidget);
|
||||||
|
|
||||||
m_environmentWidget = new EnvironmentWidget(this, baseEnvironmentWidget);
|
const EnvironmentWidget::Type widgetType = aspect->isLocal()
|
||||||
|
? EnvironmentWidget::TypeLocal : EnvironmentWidget::TypeRemote;
|
||||||
|
m_environmentWidget = new EnvironmentWidget(this, widgetType, baseEnvironmentWidget);
|
||||||
m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
|
m_environmentWidget->setBaseEnvironment(m_aspect->currentUnmodifiedBaseEnvironment());
|
||||||
m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName());
|
m_environmentWidget->setBaseEnvironmentText(m_aspect->currentDisplayName());
|
||||||
m_environmentWidget->setUserChanges(m_aspect->userEnvironmentChanges());
|
m_environmentWidget->setUserChanges(m_aspect->userEnvironmentChanges());
|
||||||
|
|||||||
@@ -33,10 +33,13 @@
|
|||||||
#include <utils/environmentmodel.h>
|
#include <utils/environmentmodel.h>
|
||||||
#include <utils/environmentdialog.h>
|
#include <utils/environmentdialog.h>
|
||||||
#include <utils/headerviewstretcher.h>
|
#include <utils/headerviewstretcher.h>
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/itemviews.h>
|
#include <utils/itemviews.h>
|
||||||
#include <utils/tooltip/tooltip.h>
|
#include <utils/tooltip/tooltip.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QTreeView>
|
#include <QTreeView>
|
||||||
@@ -131,10 +134,12 @@ public:
|
|||||||
QPushButton *m_resetButton;
|
QPushButton *m_resetButton;
|
||||||
QPushButton *m_unsetButton;
|
QPushButton *m_unsetButton;
|
||||||
QPushButton *m_batchEditButton;
|
QPushButton *m_batchEditButton;
|
||||||
|
QPushButton *m_appendPathButton = nullptr;
|
||||||
|
QPushButton *m_prependPathButton = nullptr;
|
||||||
QPushButton *m_terminalButton;
|
QPushButton *m_terminalButton;
|
||||||
};
|
};
|
||||||
|
|
||||||
EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget)
|
EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additionalDetailsWidget)
|
||||||
: QWidget(parent), d(std::make_unique<EnvironmentWidgetPrivate>())
|
: QWidget(parent), d(std::make_unique<EnvironmentWidgetPrivate>())
|
||||||
{
|
{
|
||||||
d->m_model = new Utils::EnvironmentModel();
|
d->m_model = new Utils::EnvironmentModel();
|
||||||
@@ -200,6 +205,21 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetails
|
|||||||
d->m_unsetButton->setText(tr("&Unset"));
|
d->m_unsetButton->setText(tr("&Unset"));
|
||||||
buttonLayout->addWidget(d->m_unsetButton);
|
buttonLayout->addWidget(d->m_unsetButton);
|
||||||
|
|
||||||
|
if (type == TypeLocal) {
|
||||||
|
d->m_appendPathButton = new QPushButton(this);
|
||||||
|
d->m_appendPathButton->setEnabled(false);
|
||||||
|
d->m_appendPathButton->setText(tr("Append Path..."));
|
||||||
|
buttonLayout->addWidget(d->m_appendPathButton);
|
||||||
|
d->m_prependPathButton = new QPushButton(this);
|
||||||
|
d->m_prependPathButton->setEnabled(false);
|
||||||
|
d->m_prependPathButton->setText(tr("Prepend Path..."));
|
||||||
|
buttonLayout->addWidget(d->m_prependPathButton);
|
||||||
|
connect(d->m_appendPathButton, &QAbstractButton::clicked,
|
||||||
|
this, &EnvironmentWidget::appendPathButtonClicked);
|
||||||
|
connect(d->m_prependPathButton, &QAbstractButton::clicked,
|
||||||
|
this, &EnvironmentWidget::prependPathButtonClicked);
|
||||||
|
}
|
||||||
|
|
||||||
d->m_batchEditButton = new QPushButton(this);
|
d->m_batchEditButton = new QPushButton(this);
|
||||||
d->m_batchEditButton->setText(tr("&Batch Edit..."));
|
d->m_batchEditButton->setText(tr("&Batch Edit..."));
|
||||||
buttonLayout->addWidget(d->m_batchEditButton);
|
buttonLayout->addWidget(d->m_batchEditButton);
|
||||||
@@ -318,6 +338,36 @@ void EnvironmentWidget::linkActivated(const QString &link)
|
|||||||
focusIndex(idx);
|
focusIndex(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EnvironmentWidget::currentEntryIsPathList(const QModelIndex ¤t) const
|
||||||
|
{
|
||||||
|
if (!current.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Look at the name first and check it against some well-known path variables. Extend as needed.
|
||||||
|
const QString varName = d->m_model->indexToVariable(current);
|
||||||
|
if (varName.compare("PATH", Utils::HostOsInfo::fileNameCaseSensitivity()) == 0)
|
||||||
|
return true;
|
||||||
|
if (Utils::HostOsInfo::isMacHost() && varName == "DYLD_LIBRARY_PATH")
|
||||||
|
return true;
|
||||||
|
if (Utils::HostOsInfo::isAnyUnixHost() && varName == "LD_LIBRARY_PATH")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Now check the value: If it's a list of strings separated by the platform's path separator
|
||||||
|
// and at least one of the strings is an existing directory, then that's enough proof for us.
|
||||||
|
QModelIndex valueIndex = current;
|
||||||
|
if (valueIndex.column() == 0)
|
||||||
|
valueIndex = valueIndex.siblingAtColumn(1);
|
||||||
|
const QStringList entries = d->m_model->data(valueIndex).toString()
|
||||||
|
.split(Utils::HostOsInfo::pathListSeparator(), QString::SkipEmptyParts);
|
||||||
|
if (entries.length() < 2)
|
||||||
|
return false;
|
||||||
|
for (const QString &potentialDir : entries) {
|
||||||
|
if (QFileInfo(potentialDir).isDir())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void EnvironmentWidget::updateButtons()
|
void EnvironmentWidget::updateButtons()
|
||||||
{
|
{
|
||||||
environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
|
environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
|
||||||
@@ -352,6 +402,42 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked()
|
|||||||
d->m_model->unsetVariable(name);
|
d->m_model->unsetVariable(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EnvironmentWidget::amendPathList(const PathListModifier &modifier)
|
||||||
|
{
|
||||||
|
const QString varName = d->m_model->indexToVariable(d->m_environmentView->currentIndex());
|
||||||
|
const QString dir = QDir::toNativeSeparators(
|
||||||
|
QFileDialog::getExistingDirectory(this, tr("Choose a directory")));
|
||||||
|
if (dir.isEmpty())
|
||||||
|
return;
|
||||||
|
QModelIndex index = d->m_model->variableToIndex(varName);
|
||||||
|
if (!index.isValid())
|
||||||
|
return;
|
||||||
|
if (index.column() == 0)
|
||||||
|
index = index.siblingAtColumn(1);
|
||||||
|
const QString value = d->m_model->data(index).toString();
|
||||||
|
d->m_model->setData(index, modifier(value, dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvironmentWidget::appendPathButtonClicked()
|
||||||
|
{
|
||||||
|
amendPathList([](const QString &pathList, const QString &dir) {
|
||||||
|
QString newPathList = dir;
|
||||||
|
if (!pathList.isEmpty())
|
||||||
|
newPathList.prepend(Utils::HostOsInfo::pathListSeparator()).prepend(pathList);
|
||||||
|
return newPathList;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnvironmentWidget::prependPathButtonClicked()
|
||||||
|
{
|
||||||
|
amendPathList([](const QString &pathList, const QString &dir) {
|
||||||
|
QString newPathList = dir;
|
||||||
|
if (!pathList.isEmpty())
|
||||||
|
newPathList.append(Utils::HostOsInfo::pathListSeparator()).append(pathList);
|
||||||
|
return newPathList;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void EnvironmentWidget::batchEditEnvironmentButtonClicked()
|
void EnvironmentWidget::batchEditEnvironmentButtonClicked()
|
||||||
{
|
{
|
||||||
const QList<Utils::EnvironmentItem> changes = d->m_model->userChanges();
|
const QList<Utils::EnvironmentItem> changes = d->m_model->userChanges();
|
||||||
@@ -385,6 +471,10 @@ void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤
|
|||||||
d->m_resetButton->setEnabled(false);
|
d->m_resetButton->setEnabled(false);
|
||||||
d->m_unsetButton->setEnabled(false);
|
d->m_unsetButton->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
if (d->m_appendPathButton) {
|
||||||
|
d->m_appendPathButton->setEnabled(currentEntryIsPathList(current));
|
||||||
|
d->m_prependPathButton->setEnabled(currentEntryIsPathList(current));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvironmentWidget::invalidateCurrentIndex()
|
void EnvironmentWidget::invalidateCurrentIndex()
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QModelIndex)
|
QT_FORWARD_DECLARE_CLASS(QModelIndex)
|
||||||
@@ -47,7 +48,9 @@ class PROJECTEXPLORER_EXPORT EnvironmentWidget : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget = nullptr);
|
enum Type { TypeLocal, TypeRemote };
|
||||||
|
explicit EnvironmentWidget(QWidget *parent, Type type,
|
||||||
|
QWidget *additionalDetailsWidget = nullptr);
|
||||||
~EnvironmentWidget() override;
|
~EnvironmentWidget() override;
|
||||||
|
|
||||||
void setBaseEnvironmentText(const QString &text);
|
void setBaseEnvironmentText(const QString &text);
|
||||||
@@ -65,6 +68,8 @@ private:
|
|||||||
void addEnvironmentButtonClicked();
|
void addEnvironmentButtonClicked();
|
||||||
void removeEnvironmentButtonClicked();
|
void removeEnvironmentButtonClicked();
|
||||||
void unsetEnvironmentButtonClicked();
|
void unsetEnvironmentButtonClicked();
|
||||||
|
void appendPathButtonClicked();
|
||||||
|
void prependPathButtonClicked();
|
||||||
void batchEditEnvironmentButtonClicked();
|
void batchEditEnvironmentButtonClicked();
|
||||||
void openTerminal();
|
void openTerminal();
|
||||||
void environmentCurrentIndexChanged(const QModelIndex ¤t);
|
void environmentCurrentIndexChanged(const QModelIndex ¤t);
|
||||||
@@ -73,6 +78,10 @@ private:
|
|||||||
void focusIndex(const QModelIndex &index);
|
void focusIndex(const QModelIndex &index);
|
||||||
void updateButtons();
|
void updateButtons();
|
||||||
void linkActivated(const QString &link);
|
void linkActivated(const QString &link);
|
||||||
|
bool currentEntryIsPathList(const QModelIndex ¤t) const;
|
||||||
|
|
||||||
|
using PathListModifier = std::function<QString(const QString &oldList, const QString &newDir)>;
|
||||||
|
void amendPathList(const PathListModifier &modifier);
|
||||||
|
|
||||||
const std::unique_ptr<EnvironmentWidgetPrivate> d;
|
const std::unique_ptr<EnvironmentWidgetPrivate> d;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ namespace ProjectExplorer {
|
|||||||
|
|
||||||
LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target)
|
LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target)
|
||||||
{
|
{
|
||||||
|
setIsLocal(true);
|
||||||
addSupportedBaseEnvironment(tr("Clean Environment"), {});
|
addSupportedBaseEnvironment(tr("Clean Environment"), {});
|
||||||
|
|
||||||
addSupportedBaseEnvironment(tr("System Environment"), [] {
|
addSupportedBaseEnvironment(tr("System Environment"), [] {
|
||||||
|
|||||||
Reference in New Issue
Block a user