diff --git a/src/plugins/projectexplorer/environmentaspectwidget.h b/src/plugins/projectexplorer/environmentaspectwidget.h index b5127d889e8..6ca8164f058 100644 --- a/src/plugins/projectexplorer/environmentaspectwidget.h +++ b/src/plugins/projectexplorer/environmentaspectwidget.h @@ -53,6 +53,7 @@ public: explicit EnvironmentAspectWidget(EnvironmentAspect *aspect, QWidget *additionalWidget = nullptr); virtual EnvironmentAspect *aspect() const; + EnvironmentWidget *envWidget() const { return m_environmentWidget; } QWidget *additionalWidget() const; diff --git a/src/plugins/projectexplorer/environmentwidget.cpp b/src/plugins/projectexplorer/environmentwidget.cpp index d3384a8f298..d1dcd488fea 100644 --- a/src/plugins/projectexplorer/environmentwidget.cpp +++ b/src/plugins/projectexplorer/environmentwidget.cpp @@ -127,6 +127,7 @@ public: Utils::EnvironmentModel *m_model; QString m_baseEnvironmentText; + EnvironmentWidget::OpenTerminalFunc m_openTerminalFunc; Utils::DetailsWidget *m_detailsContainer; QTreeView *m_environmentView; QPushButton *m_editButton; @@ -227,6 +228,7 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additi d->m_terminalButton = new QPushButton(this); d->m_terminalButton->setText(tr("Open &Terminal")); d->m_terminalButton->setToolTip(tr("Open a terminal with this environment set up.")); + d->m_terminalButton->setEnabled(type == TypeLocal); buttonLayout->addWidget(d->m_terminalButton); buttonLayout->addStretch(); @@ -251,7 +253,14 @@ EnvironmentWidget::EnvironmentWidget(QWidget *parent, Type type, QWidget *additi connect(d->m_environmentView->selectionModel(), &QItemSelectionModel::currentChanged, this, &EnvironmentWidget::environmentCurrentIndexChanged); connect(d->m_terminalButton, &QAbstractButton::clicked, - this, &EnvironmentWidget::openTerminal); + this, [this] { + Utils::Environment env = d->m_model->baseEnvironment(); + env.modify(d->m_model->userChanges()); + if (d->m_openTerminalFunc) + d->m_openTerminalFunc(env); + else + Core::FileUtils::openTerminal(QDir::currentPath(), env); + }); connect(d->m_detailsContainer, &Utils::DetailsWidget::linkActivated, this, &EnvironmentWidget::linkActivated); @@ -303,6 +312,12 @@ void EnvironmentWidget::setUserChanges(const QList &list updateSummaryText(); } +void EnvironmentWidget::setOpenTerminalFunc(const EnvironmentWidget::OpenTerminalFunc &func) +{ + d->m_openTerminalFunc = func; + d->m_terminalButton->setEnabled(bool(func)); +} + void EnvironmentWidget::updateSummaryText() { QList list = d->m_model->userChanges(); @@ -450,13 +465,6 @@ void EnvironmentWidget::batchEditEnvironmentButtonClicked() d->m_model->setUserChanges(newChanges); } -void EnvironmentWidget::openTerminal() -{ - Utils::Environment env = d->m_model->baseEnvironment(); - env.modify(d->m_model->userChanges()); - Core::FileUtils::openTerminal(QDir::currentPath(), env); -} - void EnvironmentWidget::environmentCurrentIndexChanged(const QModelIndex ¤t) { if (current.isValid()) { diff --git a/src/plugins/projectexplorer/environmentwidget.h b/src/plugins/projectexplorer/environmentwidget.h index 55e617a4739..927dc9b0c10 100644 --- a/src/plugins/projectexplorer/environmentwidget.h +++ b/src/plugins/projectexplorer/environmentwidget.h @@ -59,6 +59,9 @@ public: QList userChanges() const; void setUserChanges(const QList &list); + using OpenTerminalFunc = std::function; + void setOpenTerminalFunc(const OpenTerminalFunc &func); + signals: void userChangesChanged(); void detailsVisibleChanged(bool visible); @@ -71,7 +74,6 @@ private: void appendPathButtonClicked(); void prependPathButtonClicked(); void batchEditEnvironmentButtonClicked(); - void openTerminal(); void environmentCurrentIndexChanged(const QModelIndex ¤t); void invalidateCurrentIndex(); void updateSummaryText(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 6f5d8fb20a6..e6b22eb4bbd 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -197,24 +198,7 @@ LinuxDevice::LinuxDevice() if (Utils::HostOsInfo::isAnyUnixHost()) { addDeviceAction({tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) { - DeviceProcess * const proc = device->createProcess(nullptr); - QObject::connect(proc, &DeviceProcess::finished, [proc] { - if (!proc->errorString().isEmpty()) { - Core::MessageManager::write(tr("Error running remote shell: %1") - .arg(proc->errorString()), - Core::MessageManager::ModeSwitch); - } - proc->deleteLater(); - }); - QObject::connect(proc, &DeviceProcess::error, [proc] { - Core::MessageManager::write(tr("Error starting remote shell."), - Core::MessageManager::ModeSwitch); - proc->deleteLater(); - }); - Runnable runnable; - runnable.device = device; - proc->setRunInTerminal(true); - proc->start(runnable); + device.staticCast()->startRemoteShell(Utils::Environment()); }}); } } @@ -284,6 +268,35 @@ bool LinuxDevice::supportsRSync() const return extraData("RemoteLinux.SupportsRSync").toBool(); } +void LinuxDevice::startRemoteShell(const Utils::Environment &env) const +{ + DeviceProcess * const proc = createProcess(nullptr); + QObject::connect(proc, &DeviceProcess::finished, [proc] { + if (!proc->errorString().isEmpty()) { + Core::MessageManager::write(tr("Error running remote shell: %1") + .arg(proc->errorString()), + Core::MessageManager::ModeSwitch); + } + proc->deleteLater(); + }); + QObject::connect(proc, &DeviceProcess::error, [proc] { + Core::MessageManager::write(tr("Error starting remote shell."), + Core::MessageManager::ModeSwitch); + proc->deleteLater(); + }); + Runnable runnable; + runnable.device = sharedFromThis(); + runnable.environment = env; + + // It seems we cannot pass an environment to OpenSSH dynamically + // without specifying an executable. + if (env.size() > 0) + runnable.executable = "/bin/sh"; + + proc->setRunInTerminal(true); + proc->start(runnable); +} + namespace Internal { diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index 18faf4ae059..c8e8d8bf314 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -32,6 +32,8 @@ #include +namespace Utils { class Environment; } + namespace RemoteLinux { class REMOTELINUX_EXPORT LinuxDevice : public ProjectExplorer::IDevice @@ -62,6 +64,8 @@ public: void setSupportsRsync(bool supportsRsync); bool supportsRSync() const; + void startRemoteShell(const Utils::Environment &env) const; + protected: LinuxDevice(); }; diff --git a/src/plugins/remotelinux/linuxdeviceprocess.cpp b/src/plugins/remotelinux/linuxdeviceprocess.cpp index a2d673c5cc4..00bd28b6e56 100644 --- a/src/plugins/remotelinux/linuxdeviceprocess.cpp +++ b/src/plugins/remotelinux/linuxdeviceprocess.cpp @@ -99,7 +99,8 @@ QString LinuxDeviceProcess::fullCommandLine(const Runnable &runnable) const if (!envString.isEmpty()) fullCommandLine.append(envString); if (!runInTerminal()) - fullCommandLine.append(" exec "); + fullCommandLine.append(" exec"); + fullCommandLine.append(' '); fullCommandLine.append(quote(runnable.executable)); if (!runnable.commandLineArguments.isEmpty()) { fullCommandLine.append(QLatin1Char(' ')); diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp index 28e87fd8803..b244a5e129c 100644 --- a/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp +++ b/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp @@ -25,11 +25,15 @@ #include "remotelinuxenvironmentaspectwidget.h" +#include "linuxdevice.h" #include "remotelinuxrunconfiguration.h" #include "remotelinuxenvironmentreader.h" -#include +#include +#include #include +#include +#include #include #include @@ -63,6 +67,20 @@ RemoteLinuxEnvironmentAspectWidget::RemoteLinuxEnvironmentAspectWidget this, &RemoteLinuxEnvironmentAspectWidget::fetchEnvironmentFinished); connect(deviceEnvReader, &RemoteLinuxEnvironmentReader::error, this, &RemoteLinuxEnvironmentAspectWidget::fetchEnvironmentError); + + const EnvironmentWidget::OpenTerminalFunc openTerminalFunc + = [target](const Utils::Environment &env) { + IDevice::ConstPtr device = DeviceKitAspect::device(target->kit()); + if (!device) { + QMessageBox::critical(Core::ICore::mainWindow(), tr("Cannot open terminal"), + tr("Cannot open remote terminal: Current kit has no device.")); + return; + } + const auto linuxDevice = device.dynamicCast(); + QTC_ASSERT(linuxDevice, return); + linuxDevice->startRemoteShell(env); + }; + envWidget()->setOpenTerminalFunc(openTerminalFunc); } RemoteLinuxEnvironmentAspect *RemoteLinuxEnvironmentAspectWidget::aspect() const