diff --git a/src/libs/utils/consoleprocess.cpp b/src/libs/utils/consoleprocess.cpp index 077cbc19d6f..191570e312d 100644 --- a/src/libs/utils/consoleprocess.cpp +++ b/src/libs/utils/consoleprocess.cpp @@ -27,6 +27,13 @@ namespace Utils { +TerminalCommand::TerminalCommand(const QString &command, const QString &openArgs, const QString &executeArgs) + : command(command) + , openArgs(openArgs) + , executeArgs(executeArgs) +{ +} + ConsoleProcess::~ConsoleProcess() { stop(); @@ -151,4 +158,16 @@ void ConsoleProcess::emitError(QProcess::ProcessError err, const QString &errorS emit processError(errorString); } +bool TerminalCommand::operator==(const TerminalCommand &other) const +{ + return other.command == command && other.executeArgs == executeArgs; +} + +bool TerminalCommand::operator<(const TerminalCommand &other) const +{ + if (command == other.command) + return executeArgs < other.executeArgs; + return command < other.command; +} + } diff --git a/src/libs/utils/consoleprocess.h b/src/libs/utils/consoleprocess.h index 7c58c55cc69..87ba28e5e31 100644 --- a/src/libs/utils/consoleprocess.h +++ b/src/libs/utils/consoleprocess.h @@ -28,6 +28,7 @@ #include "utils_global.h" #include +#include QT_BEGIN_NAMESPACE class QSettings; @@ -37,6 +38,20 @@ namespace Utils { class Environment; struct ConsoleProcessPrivate; +class QTCREATOR_UTILS_EXPORT TerminalCommand +{ +public: + TerminalCommand() = default; + TerminalCommand(const QString &command, const QString &openArgs, const QString &executeArgs); + + bool operator==(const TerminalCommand &other) const; + bool operator<(const TerminalCommand &other) const; + + QString command; + QString openArgs; + QString executeArgs; +}; + class QTCREATOR_UTILS_EXPORT ConsoleProcess : public QObject { Q_OBJECT @@ -88,17 +103,17 @@ public: #ifndef Q_OS_WIN void setSettings(QSettings *settings); - static QString defaultTerminalEmulator(); - static QStringList availableTerminalEmulators(); - static QString terminalEmulator(const QSettings *settings, bool nonEmpty = true); - static void setTerminalEmulator(QSettings *settings, const QString &term); + static TerminalCommand defaultTerminalEmulator(); + static QVector availableTerminalEmulators(); + static TerminalCommand terminalEmulator(const QSettings *settings); + static void setTerminalEmulator(QSettings *settings, const TerminalCommand &term); #else void setSettings(QSettings *) {} - static QString defaultTerminalEmulator() { return QString(); } - static QStringList availableTerminalEmulators() { return QStringList(); } - static QString terminalEmulator(const QSettings *, bool = true) { return QString(); } - static void setTerminalEmulator(QSettings *, const QString &) {} + static TerminalCommand defaultTerminalEmulator() { return TerminalCommand(); } + static QVector availableTerminalEmulators() { return {}; } + static TerminalCommand terminalEmulator(const QSettings *) { return TerminalCommand(); } + static void setTerminalEmulator(QSettings *, const TerminalCommand &) {} #endif static bool startTerminalEmulator(QSettings *settings, const QString &workingDir); @@ -144,3 +159,5 @@ private: }; } //namespace Utils + +Q_DECLARE_METATYPE(Utils::TerminalCommand) diff --git a/src/libs/utils/consoleprocess_unix.cpp b/src/libs/utils/consoleprocess_unix.cpp index be07027f6e3..82afaf85a69 100644 --- a/src/libs/utils/consoleprocess_unix.cpp +++ b/src/libs/utils/consoleprocess_unix.cpp @@ -27,6 +27,7 @@ #include "qtcprocess.h" +#include #include #include @@ -95,9 +96,12 @@ bool ConsoleProcess::start(const QString &program, const QString &args) } QtcProcess::SplitError qerr; - QtcProcess::Arguments xtermArgs = QtcProcess::prepareArgs(terminalEmulator(d->m_settings), &qerr, - HostOsInfo::hostOs(), - &d->m_environment, &d->m_workingDir); + const TerminalCommand terminal = terminalEmulator(d->m_settings); + const QtcProcess::Arguments terminalArgs = QtcProcess::prepareArgs(terminal.executeArgs, + &qerr, + HostOsInfo::hostOs(), + &d->m_environment, + &d->m_workingDir); if (qerr != QtcProcess::SplitOk) { emitError(QProcess::FailedToStart, qerr == QtcProcess::BadQuoting ? tr("Quoting error in terminal command.") @@ -138,22 +142,22 @@ bool ConsoleProcess::start(const QString &program, const QString &args) const QString stubPath = QCoreApplication::applicationDirPath() + QLatin1String("/" QTC_REL_TOOLS_PATH "/qtcreator_process_stub"); - QStringList allArgs = xtermArgs.toUnixArgs(); - allArgs << stubPath - << modeOption(d->m_mode) - << d->m_stubServer.fullServerName() - << msgPromptToClose() - << workingDirectory() - << (d->m_tempFile ? d->m_tempFile->fileName() : QString()) - << QString::number(getpid()) - << pcmd << pargs.toUnixArgs(); + const QStringList allArgs = terminalArgs.toUnixArgs() + << stubPath + << modeOption(d->m_mode) + << d->m_stubServer.fullServerName() + << msgPromptToClose() + << workingDirectory() + << (d->m_tempFile ? d->m_tempFile->fileName() : QString()) + << QString::number(getpid()) + << pcmd + << pargs.toUnixArgs(); - QString xterm = allArgs.takeFirst(); - d->m_process.start(xterm, allArgs); + d->m_process.start(terminal.command, allArgs); if (!d->m_process.waitForStarted()) { stubServerShutdown(); emitError(QProcess::UnknownError, tr("Cannot start the terminal emulator \"%1\", change the setting in the " - "Environment options.").arg(xterm)); + "Environment options.").arg(terminal.command)); delete d->m_tempFile; d->m_tempFile = 0; return false; @@ -327,83 +331,110 @@ void ConsoleProcess::stubExited() emit stubStopped(); } -struct Terminal { - const char *binary; - const char *options; -}; - -static const Terminal knownTerminals[] = +Q_GLOBAL_STATIC_WITH_ARGS(const QVector, knownTerminals, ( { - {"x-terminal-emulator", "-e"}, - {"xterm", "-e"}, - {"aterm", "-e"}, - {"Eterm", "-e"}, - {"rxvt", "-e"}, - {"urxvt", "-e"}, - {"xfce4-terminal", "-x"}, - {"konsole", "-e"}, - {"gnome-terminal", "--"} -}; + {"x-terminal-emulator", "", "-e"}, + {"xterm", "", "-e"}, + {"aterm", "", "-e"}, + {"Eterm", "", "-e"}, + {"rxvt", "", "-e"}, + {"urxvt", "", "-e"}, + {"xfce4-terminal", "", "-x"}, + {"konsole", "--separate", "-e"}, + {"gnome-terminal", "", "--"} +})); -QString ConsoleProcess::defaultTerminalEmulator() +TerminalCommand ConsoleProcess::defaultTerminalEmulator() { - if (HostOsInfo::isMacHost()) { - QString termCmd = QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/scripts/openTerminal.command"); - if (QFileInfo::exists(termCmd)) - return termCmd.replace(QLatin1Char(' '), QLatin1String("\\ ")); - return QLatin1String("/usr/X11/bin/xterm"); + static TerminalCommand defaultTerm; + if (defaultTerm.command.isEmpty()) { + defaultTerm = []() -> TerminalCommand { + if (HostOsInfo::isMacHost()) { + QString termCmd = QCoreApplication::applicationDirPath() + "/../Resources/scripts/openTerminal.command"; + if (QFileInfo::exists(termCmd)) + return {termCmd.replace(' ', "\\ "), "", ""}; + return {"/usr/X11/bin/xterm", "", "-e"}; + } + const Environment env = Environment::systemEnvironment(); + for (const TerminalCommand &term : *knownTerminals) { + const QString result = env.searchInPath(term.command).toString(); + if (!result.isEmpty()) + return {result, term.openArgs, term.executeArgs}; + } + return {"xterm", "", "-e"}; + }(); } - const Environment env = Environment::systemEnvironment(); - const int terminalCount = int(sizeof(knownTerminals) / sizeof(knownTerminals[0])); - for (int i = 0; i < terminalCount; ++i) { - QString result = env.searchInPath(QLatin1String(knownTerminals[i].binary)).toString(); - if (!result.isEmpty()) { - result += QLatin1Char(' '); - result += QLatin1String(knownTerminals[i].options); - return result; - } - } - return QLatin1String("xterm -e"); + return defaultTerm; } -QStringList ConsoleProcess::availableTerminalEmulators() +QVector ConsoleProcess::availableTerminalEmulators() { - QStringList result; + QVector result; const Environment env = Environment::systemEnvironment(); - const int terminalCount = int(sizeof(knownTerminals) / sizeof(knownTerminals[0])); - for (int i = 0; i < terminalCount; ++i) { - QString terminal = env.searchInPath(QLatin1String(knownTerminals[i].binary)).toString(); - if (!terminal.isEmpty()) { - terminal += QLatin1Char(' '); - terminal += QLatin1String(knownTerminals[i].options); - result.push_back(terminal); - } + for (const TerminalCommand &term : *knownTerminals) { + const QString command = env.searchInPath(term.command).toString(); + if (!command.isEmpty()) + result.push_back({command, term.openArgs, term.executeArgs}); } - if (!result.contains(defaultTerminalEmulator())) - result.append(defaultTerminalEmulator()); - result.sort(); + // sort and put default terminal on top + const TerminalCommand defaultTerm = defaultTerminalEmulator(); + result.removeAll(defaultTerm); + sort(result); + result.prepend(defaultTerm); return result; } -QString ConsoleProcess::terminalEmulator(const QSettings *settings, bool nonEmpty) +const char kTerminalVersion[] = "4.8"; +const char kTerminalVersionKey[] = "General/Terminal/SettingsVersion"; +const char kTerminalCommandKey[] = "General/Terminal/Command"; +const char kTerminalOpenOptionsKey[] = "General/Terminal/OpenOptions"; +const char kTerminalExecuteOptionsKey[] = "General/Terminal/ExecuteOptions"; + +TerminalCommand ConsoleProcess::terminalEmulator(const QSettings *settings) { if (settings) { - const QString value = settings->value(QLatin1String("General/TerminalEmulator")).toString(); - if (!nonEmpty || !value.isEmpty()) - return value; + if (settings->value(kTerminalVersionKey).toString() == kTerminalVersion) { + if (settings->contains(kTerminalCommandKey)) + return {settings->value(kTerminalCommandKey).toString(), + settings->value(kTerminalOpenOptionsKey).toString(), + settings->value(kTerminalExecuteOptionsKey).toString()}; + } else { + // TODO remove reading of old settings some time after 4.8 + const QString value = settings->value("General/TerminalEmulator").toString().trimmed(); + if (!value.isEmpty()) { + // split off command and options + const QStringList splitCommand = QtcProcess::splitArgs(value); + if (QTC_GUARD(!splitCommand.isEmpty())) { + const QString command = splitCommand.first(); + const QStringList quotedArgs = Utils::transform(splitCommand.mid(1), + &QtcProcess::quoteArgUnix); + const QString options = quotedArgs.join(' '); + return {command, "", options}; + } + } + } } return defaultTerminalEmulator(); } -void ConsoleProcess::setTerminalEmulator(QSettings *settings, const QString &term) +void ConsoleProcess::setTerminalEmulator(QSettings *settings, const TerminalCommand &term) { - settings->setValue(QLatin1String("General/TerminalEmulator"), term); + settings->setValue(kTerminalVersionKey, kTerminalVersion); + if (term == defaultTerminalEmulator()) { + settings->remove(kTerminalCommandKey); + settings->remove(kTerminalOpenOptionsKey); + settings->remove(kTerminalExecuteOptionsKey); + } else { + settings->setValue(kTerminalCommandKey, term.command); + settings->setValue(kTerminalOpenOptionsKey, term.openArgs); + settings->setValue(kTerminalExecuteOptionsKey, term.executeArgs); + } } bool ConsoleProcess::startTerminalEmulator(QSettings *settings, const QString &workingDir) { - const QString emu = QtcProcess::splitArgs(terminalEmulator(settings)).takeFirst(); - return QProcess::startDetached(emu, QStringList(), workingDir); + const TerminalCommand term = terminalEmulator(settings); + return QProcess::startDetached(term.command, QtcProcess::splitArgs(term.openArgs), workingDir); } } // namespace Utils diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 0f65161b666..61e64aac13b 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -69,14 +69,22 @@ QWidget *SystemSettings::widget() m_page->reloadBehavior->setCurrentIndex(EditorManager::reloadSetting()); if (HostOsInfo::isAnyUnixHost()) { - const QStringList availableTerminals = ConsoleProcess::availableTerminalEmulators(); - const QString currentTerminal = ConsoleProcess::terminalEmulator(ICore::settings(), false); - m_page->terminalComboBox->addItems(availableTerminals); - m_page->terminalComboBox->lineEdit()->setText(currentTerminal); - m_page->terminalComboBox->lineEdit()->setPlaceholderText(ConsoleProcess::defaultTerminalEmulator()); + const QVector availableTerminals = ConsoleProcess::availableTerminalEmulators(); + for (const TerminalCommand &term : availableTerminals) + m_page->terminalComboBox->addItem(term.command, qVariantFromValue(term)); + updateTerminalUi(ConsoleProcess::terminalEmulator(ICore::settings())); + connect(m_page->terminalComboBox, + QOverload::of(&QComboBox::currentIndexChanged), + this, + [this](int index) { + updateTerminalUi( + m_page->terminalComboBox->itemData(index).value()); + }); } else { m_page->terminalLabel->hide(); m_page->terminalComboBox->hide(); + m_page->terminalOpenArgs->hide(); + m_page->terminalExecuteArgs->hide(); m_page->resetTerminalButton->hide(); } @@ -156,7 +164,9 @@ void SystemSettings::apply() EditorManager::setReloadSetting(IDocument::ReloadSetting(m_page->reloadBehavior->currentIndex())); if (HostOsInfo::isAnyUnixHost()) { ConsoleProcess::setTerminalEmulator(ICore::settings(), - m_page->terminalComboBox->lineEdit()->text()); + {m_page->terminalComboBox->lineEdit()->text(), + m_page->terminalOpenArgs->text(), + m_page->terminalExecuteArgs->text()}); if (!HostOsInfo::isMacHost()) { UnixUtils::setFileBrowser(ICore::settings(), m_page->externalFileBrowserEdit->text()); @@ -193,7 +203,14 @@ void SystemSettings::finish() void SystemSettings::resetTerminal() { if (HostOsInfo::isAnyUnixHost()) - m_page->terminalComboBox->lineEdit()->clear(); + m_page->terminalComboBox->setCurrentIndex(0); +} + +void SystemSettings::updateTerminalUi(const TerminalCommand &term) +{ + m_page->terminalComboBox->lineEdit()->setText(term.command); + m_page->terminalOpenArgs->setText(term.openArgs); + m_page->terminalExecuteArgs->setText(term.executeArgs); } void SystemSettings::resetFileBrowser() diff --git a/src/plugins/coreplugin/systemsettings.h b/src/plugins/coreplugin/systemsettings.h index dbf7e09a1d8..b3263a3aa5a 100644 --- a/src/plugins/coreplugin/systemsettings.h +++ b/src/plugins/coreplugin/systemsettings.h @@ -32,6 +32,8 @@ QT_BEGIN_NAMESPACE class QMessageBox; QT_END_NAMESPACE +namespace Utils { class TerminalCommand; } + namespace Core { namespace Internal { @@ -52,6 +54,7 @@ private: void showHelpForFileBrowser(); void resetFileBrowser(); void resetTerminal(); + void updateTerminalUi(const Utils::TerminalCommand &term); void updatePath(); void variableHelpDialogCreator(const QString &helpText); diff --git a/src/plugins/coreplugin/systemsettings.ui b/src/plugins/coreplugin/systemsettings.ui index 4d36f3c9182..3113154936d 100644 --- a/src/plugins/coreplugin/systemsettings.ui +++ b/src/plugins/coreplugin/systemsettings.ui @@ -17,68 +17,67 @@ System - + + + + + + When files are externally modified: + + + + + + + 0 + + + + Always Ask + + + + + Reload All Unchanged Editors + + + + + Ignore Modifications + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + External file browser: + + + + ? - - - - Reset to default. - - - Reset - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Influences how file names are matched to decide if they are the same. - - - File system case sensitivity: - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + @@ -138,140 +137,17 @@ - - - - - - - External file browser: - - - - - - - Terminal: - - - - - - - - - - - - When files are externally modified: - - - - - - - 0 - - - - Always Ask - - - - - Reload All Unchanged Editors - - - - - Ignore Modifications - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Reset to default. - - - Reset - - - - - - - true - - - - - - - - - Warn before opening text files greater than - - - true - - - - - - - MB - - - 1 - - - 500 - - - 5 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + Patch command: - + + + + @@ -337,6 +213,154 @@ + + + + Reset to default. + + + Reset + + + + + + + + + Warn before opening text files greater than + + + true + + + + + + + MB + + + 1 + + + 500 + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Reset to default. + + + Reset + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Influences how file names are matched to decide if they are the same. + + + File system case sensitivity: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Terminal: + + + + + + + + + + 3 + 0 + + + + true + + + + + + + Command line arguments used for "Open Terminal Here". + + + + + + + Command line arguments used for "Run in terminal". + + + + + @@ -368,7 +392,6 @@ - terminalComboBox resetTerminalButton externalFileBrowserEdit resetFileBrowserButton