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->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);
|
||||
|
||||
connect(m_buildEnvironmentWidget, &EnvironmentWidget::userChangesChanged,
|
||||
|
||||
@@ -66,6 +66,8 @@ public:
|
||||
using EnvironmentModifier = std::function<void(Utils::Environment &)>;
|
||||
void addModifier(const EnvironmentModifier &);
|
||||
|
||||
bool isLocal() const { return m_isLocal; }
|
||||
|
||||
signals:
|
||||
void baseEnvironmentChanged();
|
||||
void userEnvironmentChangesChanged(const QList<Utils::EnvironmentItem> &diff);
|
||||
@@ -75,6 +77,8 @@ protected:
|
||||
void fromMap(const QVariantMap &map) override;
|
||||
void toMap(QVariantMap &map) const override;
|
||||
|
||||
void setIsLocal(bool local) { m_isLocal = local; }
|
||||
|
||||
private:
|
||||
// One possible choice in the Environment aspect.
|
||||
struct BaseEnvironment {
|
||||
@@ -84,10 +88,11 @@ private:
|
||||
QString displayName;
|
||||
};
|
||||
|
||||
int m_base = -1;
|
||||
QList<Utils::EnvironmentItem> m_userChanges;
|
||||
QList<EnvironmentModifier> m_modifiers;
|
||||
QList<BaseEnvironment> m_baseEnvironments;
|
||||
int m_base = -1;
|
||||
bool m_isLocal = false;
|
||||
};
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
@@ -72,7 +72,9 @@ EnvironmentAspectWidget::EnvironmentAspectWidget(EnvironmentAspect *aspect, QWid
|
||||
if (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->setBaseEnvironmentText(m_aspect->currentDisplayName());
|
||||
m_environmentWidget->setUserChanges(m_aspect->userEnvironmentChanges());
|
||||
|
||||
@@ -33,10 +33,13 @@
|
||||
#include <utils/environmentmodel.h>
|
||||
#include <utils/environmentdialog.h>
|
||||
#include <utils/headerviewstretcher.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/itemviews.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <QPushButton>
|
||||
#include <QTreeView>
|
||||
@@ -131,10 +134,12 @@ public:
|
||||
QPushButton *m_resetButton;
|
||||
QPushButton *m_unsetButton;
|
||||
QPushButton *m_batchEditButton;
|
||||
QPushButton *m_appendPathButton = nullptr;
|
||||
QPushButton *m_prependPathButton = nullptr;
|
||||
QPushButton *m_terminalButton;
|
||||
};
|
||||
|
||||
EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget)
|
||||
EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additionalDetailsWidget)
|
||||
: QWidget(parent), d(std::make_unique<EnvironmentWidgetPrivate>())
|
||||
{
|
||||
d->m_model = new Utils::EnvironmentModel();
|
||||
@@ -200,6 +205,21 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, QWidget *additionalDetails
|
||||
d->m_unsetButton->setText(tr("&Unset"));
|
||||
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->setText(tr("&Batch Edit..."));
|
||||
buttonLayout->addWidget(d->m_batchEditButton);
|
||||
@@ -318,6 +338,36 @@ void EnvironmentWidget::linkActivated(const QString &link)
|
||||
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()
|
||||
{
|
||||
environmentCurrentIndexChanged(d->m_environmentView->currentIndex());
|
||||
@@ -352,6 +402,42 @@ void EnvironmentWidget::unsetEnvironmentButtonClicked()
|
||||
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()
|
||||
{
|
||||
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_unsetButton->setEnabled(false);
|
||||
}
|
||||
if (d->m_appendPathButton) {
|
||||
d->m_appendPathButton->setEnabled(currentEntryIsPathList(current));
|
||||
d->m_prependPathButton->setEnabled(currentEntryIsPathList(current));
|
||||
}
|
||||
}
|
||||
|
||||
void EnvironmentWidget::invalidateCurrentIndex()
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QModelIndex)
|
||||
@@ -47,7 +48,9 @@ class PROJECTEXPLORER_EXPORT EnvironmentWidget : public QWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EnvironmentWidget(QWidget *parent, QWidget *additionalDetailsWidget = nullptr);
|
||||
enum Type { TypeLocal, TypeRemote };
|
||||
explicit EnvironmentWidget(QWidget *parent, Type type,
|
||||
QWidget *additionalDetailsWidget = nullptr);
|
||||
~EnvironmentWidget() override;
|
||||
|
||||
void setBaseEnvironmentText(const QString &text);
|
||||
@@ -65,6 +68,8 @@ private:
|
||||
void addEnvironmentButtonClicked();
|
||||
void removeEnvironmentButtonClicked();
|
||||
void unsetEnvironmentButtonClicked();
|
||||
void appendPathButtonClicked();
|
||||
void prependPathButtonClicked();
|
||||
void batchEditEnvironmentButtonClicked();
|
||||
void openTerminal();
|
||||
void environmentCurrentIndexChanged(const QModelIndex ¤t);
|
||||
@@ -73,6 +78,10 @@ private:
|
||||
void focusIndex(const QModelIndex &index);
|
||||
void updateButtons();
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace ProjectExplorer {
|
||||
|
||||
LocalEnvironmentAspect::LocalEnvironmentAspect(Target *target)
|
||||
{
|
||||
setIsLocal(true);
|
||||
addSupportedBaseEnvironment(tr("Clean Environment"), {});
|
||||
|
||||
addSupportedBaseEnvironment(tr("System Environment"), [] {
|
||||
|
||||
Reference in New Issue
Block a user