diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp index f196604aa5f..44c0cdc581c 100644 --- a/src/plugins/projectexplorer/buildconfiguration.cpp +++ b/src/plugins/projectexplorer/buildconfiguration.cpp @@ -116,6 +116,8 @@ BuildConfiguration::BuildConfiguration(Target *target, Core::Id id) this, &BuildConfiguration::updateCacheAndEmitEnvironmentChanged); connect(this, &BuildConfiguration::environmentChanged, this, &BuildConfiguration::emitBuildDirectoryChanged); + connect(target->project(), &Project::environmentChanged, + this, &BuildConfiguration::environmentChanged); // Many macroexpanders are based on the current project, so they may change the environment: connect(ProjectTree::instance(), &ProjectTree::currentProjectChanged, this, &BuildConfiguration::updateCacheAndEmitEnvironmentChanged); @@ -343,6 +345,7 @@ Utils::Environment BuildConfiguration::baseEnvironment() const result = Utils::Environment::systemEnvironment(); addToEnvironment(result); target()->kit()->addToEnvironment(result); + result.modify(project()->additionalEnvironment()); return result; } diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index 04d68dd42da..d89adccb456 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -283,7 +283,12 @@ void EnvironmentWidget::setUserChanges(const Utils::EnvironmentItems &list) void EnvironmentWidget::setOpenTerminalFunc(const EnvironmentWidget::OpenTerminalFunc &func) { d->m_openTerminalFunc = func; - d->m_terminalButton->setEnabled(bool(func)); + d->m_terminalButton->setVisible(bool(func)); +} + +void EnvironmentWidget::expand() +{ + d->m_detailsContainer->setState(Utils::DetailsWidget::Expanded); } void EnvironmentWidget::updateSummaryText() @@ -294,7 +299,8 @@ void EnvironmentWidget::updateSummaryText() QString text; foreach (const Utils::EnvironmentItem &item, list) { if (item.name != Utils::EnvironmentModel::tr("")) { - text.append(QLatin1String("
")); + if (!d->m_baseEnvironmentText.isEmpty() || !text.isEmpty()) + text.append(QLatin1String("
")); switch (item.operation) { case Utils::EnvironmentItem::Unset: text.append(tr("Unset %1").arg(item.name.toHtmlEscaped())); @@ -313,11 +319,15 @@ void EnvironmentWidget::updateSummaryText() if (text.isEmpty()) { //: %1 is "System Environment" or some such. - text.prepend(tr("Use %1").arg(d->m_baseEnvironmentText)); + if (!d->m_baseEnvironmentText.isEmpty()) + text.prepend(tr("Use %1").arg(d->m_baseEnvironmentText)); + else + text.prepend(tr("No environment changes")); } else { //: Yup, word puzzle. The Set/Unset phrases above are appended to this. //: %1 is "System Environment" or some such. - text.prepend(tr("Use %1 and").arg(d->m_baseEnvironmentText)); + if (!d->m_baseEnvironmentText.isEmpty()) + text.prepend(tr("Use %1 and").arg(d->m_baseEnvironmentText)); } d->m_detailsContainer->setSummaryText(text); diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h index 2a7e84c0242..d683d764ec4 100644 --- a/src/plugins/projectexplorer/environmentwidget.h +++ b/src/plugins/projectexplorer/environmentwidget.h @@ -59,6 +59,8 @@ public: using OpenTerminalFunc = std::function; void setOpenTerminalFunc(const OpenTerminalFunc &func); + void expand(); + signals: void userChangesChanged(); void detailsVisibleChanged(bool visible); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 55d32433b99..16a11a90fe9 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -90,6 +90,8 @@ const char TARGET_KEY_PREFIX[] = "ProjectExplorer.Project.Target."; const char TARGET_COUNT_KEY[] = "ProjectExplorer.Project.TargetCount"; const char EDITOR_SETTINGS_KEY[] = "ProjectExplorer.Project.EditorSettings"; const char PLUGIN_SETTINGS_KEY[] = "ProjectExplorer.Project.PluginSettings"; + +const char PROJECT_ENV_KEY[] = "ProjectExplorer.Project.Environment"; } // namespace namespace ProjectExplorer { @@ -867,6 +869,17 @@ void Project::setNamedSettings(const QString &name, const QVariant &value) d->m_pluginSettings.insert(name, value); } +void Project::setAdditionalEnvironment(const Utils::EnvironmentItems &envItems) +{ + setNamedSettings(PROJECT_ENV_KEY, Utils::NameValueItem::toStringList(envItems)); + emit environmentChanged(); +} + +Utils::EnvironmentItems Project::additionalEnvironment() const +{ + return Utils::NameValueItem::fromStringList(namedSettings(PROJECT_ENV_KEY).toStringList()); +} + bool Project::needsConfiguration() const { return d->m_targets.size() == 0; diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 243d9a079fe..8e648b5c900 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -134,6 +135,9 @@ public: QVariant namedSettings(const QString &name) const; void setNamedSettings(const QString &name, const QVariant &value); + void setAdditionalEnvironment(const Utils::EnvironmentItems &envItems); + Utils::EnvironmentItems additionalEnvironment() const; + virtual bool needsConfiguration() const; bool needsBuildConfigurations() const; virtual void configureAsExampleProject(); @@ -174,6 +178,7 @@ signals: void displayNameChanged(); void fileListChanged(); + void environmentChanged(); // Note: activeTarget can be 0 (if no targets are defined). void activeTargetChanged(ProjectExplorer::Target *target); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index 9fd84e45b7c..b6e64a2c4b8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -37,6 +37,7 @@ #include "deployablefile.h" #include "deployconfiguration.h" #include "desktoprunconfiguration.h" +#include "environmentwidget.h" #include "extraabi.h" #include "gcctoolchainfactories.h" #ifdef WITH_JOURNALD @@ -45,6 +46,7 @@ #include "jsonwizard/jsonwizardfactory.h" #include "jsonwizard/jsonwizardgeneratorfactory.h" #include "jsonwizard/jsonwizardpagefactory_p.h" +#include "namedwidget.h" #include "project.h" #include "projectexplorersettings.h" #include "projectexplorersettingspage.h" @@ -351,6 +353,29 @@ public: } }; + +class ProjectEnvironmentWidget : public NamedWidget +{ + Q_DECLARE_TR_FUNCTIONS(ProjectEnvironmentWidget) + +public: + explicit ProjectEnvironmentWidget(Project *project) : NamedWidget(tr("Project Environment")) + { + const auto vbox = new QVBoxLayout(this); + vbox->setContentsMargins(0, 0, 0, 0); + const auto envWidget = new EnvironmentWidget(this, EnvironmentWidget::TypeLocal); + envWidget->setOpenTerminalFunc({}); + envWidget->expand(); + vbox->addWidget(envWidget); + connect(envWidget, &EnvironmentWidget::userChangesChanged, + this, [project, envWidget] { + project->setAdditionalEnvironment(envWidget->userChanges()); + }); + envWidget->setUserChanges(project->additionalEnvironment()); + } +}; + + class ProjectExplorerPluginPrivate : public QObject { Q_DECLARE_TR_FUNCTIONS(ProjectExplorer::ProjectExplorerPlugin) @@ -775,6 +800,14 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er panelFactory->setCreateWidgetFunction([](Project *project) { return new DependenciesWidget(project); }); ProjectPanelFactory::registerFactory(panelFactory); + panelFactory = new ProjectPanelFactory; + panelFactory->setPriority(60); + panelFactory->setDisplayName(QCoreApplication::translate("EnvironmentPanelFactory", "Environment")); + panelFactory->setCreateWidgetFunction([](Project *project) { + return new ProjectEnvironmentWidget(project); + }); + ProjectPanelFactory::registerFactory(panelFactory); + // context menus ActionContainer *msessionContextMenu = ActionManager::createMenu(Constants::M_SESSIONCONTEXT);