From 561d90c9d99a8b608c39e0833cf47663f91a7d9a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 13 Nov 2018 20:40:31 +1000 Subject: [PATCH] [FEATURE] Add native platform interface for opening a terminal window at a specified path And implement for Linux. Add a new context menu entry to directories in browser to open a terminal window at that directory on supported platforms --- .../browser/qgsinbuiltdataitemproviders.cpp | 11 ++++++ src/native/linux/qgslinuxnative.cpp | 35 ++++++++++++++++++- src/native/linux/qgslinuxnative.h | 1 + src/native/qgsnative.cpp | 10 ++++++ src/native/qgsnative.h | 12 ++++++- 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/app/browser/qgsinbuiltdataitemproviders.cpp b/src/app/browser/qgsinbuiltdataitemproviders.cpp index 53b5eb2ab5e8..22102b497c6d 100644 --- a/src/app/browser/qgsinbuiltdataitemproviders.cpp +++ b/src/app/browser/qgsinbuiltdataitemproviders.cpp @@ -175,6 +175,17 @@ void QgsAppDirectoryItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe } ); menu->addAction( openFolder ); + if ( QgsGui::instance()->nativePlatformInterface()->capabilities() & QgsNative::NativeOpenTerminalAtPath ) + { + QAction *openTerminal = new QAction( tr( "Open in Terminal…" ), menu ); + connect( openTerminal, &QAction::triggered, this, [ = ] + { + QgsGui::instance()->nativePlatformInterface()->openTerminalAtPath( directoryItem->dirPath() ); + } ); + menu->addAction( openTerminal ); + menu->addSeparator(); + } + QAction *propertiesAction = new QAction( tr( "Properties…" ), menu ); connect( propertiesAction, &QAction::triggered, this, [ = ] { diff --git a/src/native/linux/qgslinuxnative.cpp b/src/native/linux/qgslinuxnative.cpp index ab1d4c655df9..1b71c8f70df4 100644 --- a/src/native/linux/qgslinuxnative.cpp +++ b/src/native/linux/qgslinuxnative.cpp @@ -23,10 +23,11 @@ #include #include #include +#include QgsNative::Capabilities QgsLinuxNative::capabilities() const { - return NativeDesktopNotifications | NativeFilePropertiesDialog; + return NativeDesktopNotifications | NativeFilePropertiesDialog | NativeOpenTerminalAtPath; } void QgsLinuxNative::initializeMainWindow( QWindow *, @@ -138,6 +139,38 @@ void QgsLinuxNative::setApplicationBadgeCount( int count ) QDBusConnection::sessionBus().send( message ); } +bool QgsLinuxNative::openTerminalAtPath( const QString &path ) +{ + // logic adapted from https://askubuntu.com/a/227669, + // https://github.com/Microsoft/vscode/blob/fec1775aa52e2124d3f09c7b2ac8f69c57309549/src/vs/workbench/parts/execution/electron-browser/terminal.ts + QString term = QStringLiteral( "xterm" ); + const QString desktopSession = qgetenv( "DESKTOP_SESSION" ); + const QString currentDesktop = qgetenv( "XDG_CURRENT_DESKTOP" ); + const QString gdmSession = qgetenv( "GDMSESSION" ); + const bool isDebian = QFile::exists( QStringLiteral( "/etc/debian_version" ) ); + if ( isDebian ) + { + term = QStringLiteral( "x-terminal-emulator" ); + } + else if ( desktopSession.contains( QLatin1String( "gnome" ), Qt::CaseInsensitive ) || + currentDesktop.contains( QLatin1String( "gnome" ), Qt::CaseInsensitive ) || + currentDesktop.contains( QLatin1String( "unity" ), Qt::CaseInsensitive ) ) + { + term = QStringLiteral( "gnome-terminal" ); + } + else if ( desktopSession.contains( QLatin1String( "kde" ), Qt::CaseInsensitive ) || + currentDesktop.contains( QLatin1String( "kde" ), Qt::CaseInsensitive ) || + gdmSession.contains( QLatin1String( "kde" ), Qt::CaseInsensitive ) ) + { + term = QStringLiteral( "konsole" ); + } + + QStringList arguments; + arguments << QStringLiteral( "--working-directory" ) + << path; + return QProcess::startDetached( term, QStringList(), path ); +} + /** * Automatic marshaling of a QImage for org.freedesktop.Notifications.Notify * diff --git a/src/native/linux/qgslinuxnative.h b/src/native/linux/qgslinuxnative.h index eb510dd8bb2c..32b4c056d67d 100644 --- a/src/native/linux/qgslinuxnative.h +++ b/src/native/linux/qgslinuxnative.h @@ -46,6 +46,7 @@ class NATIVE_EXPORT QgsLinuxNative : public QgsNative void setApplicationProgress( double progress ) override; void hideApplicationProgress() override; void setApplicationBadgeCount( int count ) override; + bool openTerminalAtPath( const QString &path ) override; NotificationResult showDesktopNotification( const QString &summary, const QString &body, const NotificationSettings &settings = NotificationSettings() ) override; private: QString mDesktopFile; diff --git a/src/native/qgsnative.cpp b/src/native/qgsnative.cpp index e5d76a9a0713..71607c0b126b 100644 --- a/src/native/qgsnative.cpp +++ b/src/native/qgsnative.cpp @@ -73,6 +73,16 @@ void QgsNative::setApplicationBadgeCount( int ) } +bool QgsNative::hasDarkTheme() +{ + return false; +} + +bool QgsNative::openTerminalAtPath( const QString & ) +{ + return false; +} + QgsNative::NotificationResult QgsNative::showDesktopNotification( const QString &, const QString &, const NotificationSettings & ) { NotificationResult result; diff --git a/src/native/qgsnative.h b/src/native/qgsnative.h index 0a4598066196..d63c71c5d3e3 100644 --- a/src/native/qgsnative.h +++ b/src/native/qgsnative.h @@ -45,6 +45,7 @@ class NATIVE_EXPORT QgsNative : public QObject { NativeDesktopNotifications = 1 << 1, //!< Native desktop notifications are supported. See showDesktopNotification(). NativeFilePropertiesDialog = 1 << 2, //!< Platform can show a native "file" (or folder) properties dialog. + NativeOpenTerminalAtPath = 1 << 3, //!< Platform can open a terminal (command line) at a specific path }; Q_DECLARE_FLAGS( Capabilities, Capability ) @@ -150,7 +151,16 @@ class NATIVE_EXPORT QgsNative : public QObject * Returns true if the operating system is set to utilize a "dark" theme. * \since QGIS 3.4 */ - virtual bool hasDarkTheme() {return false;} + virtual bool hasDarkTheme(); + + /** + * Opens a terminal (command line) window at the given \a path. + * + * This method is only supported when the interface returns the NativeOpenTerminalAtPath flag for capabilities(). + * + * Returns true if terminal was successfully opened. + */ + virtual bool openTerminalAtPath( const QString &path ); /** * Notification settings, for use with showDesktopNotification().