knownShells({QStringLiteral("ash"), QStringLiteral("bash"), QStringLiteral("csh"), QStringLiteral("dash"), QStringLiteral("fish"), QStringLiteral("hush"), QStringLiteral("ksh"), QStringLiteral("mksh"), QStringLiteral("pdksh"), QStringLiteral("tcsh"), QStringLiteral("zsh")});
// If only the session's shell is running, try sending an EOF for a clean exit
if (!isForegroundProcessActive() && knownShells.contains(QFileInfo(_program).fileName())) {
_shellProcess->sendEof();
if (_shellProcess->waitForFinished(1000)) {
return true;
}
qWarning() << "shell did not close, sending SIGHUP";
}
// We tried asking nicely, ask a bit less nicely
if (kill(SIGHUP)) {
return true;
} else {
qWarning() << "Process " << _shellProcess->pid() << " did not die with SIGHUP";
_shellProcess->closePty();
return (_shellProcess->waitForFinished(1000));
}
}
bool Session::closeInForceWay()
{
_autoClose = true;
_closePerUserRequest = true;
if (kill(SIGKILL)) {
return true;
} else {
qWarning() << "Process " << _shellProcess->pid() << " did not die with SIGKILL";
return false;
}
}
void Session::sendTextToTerminal(const QString& text, const QChar& eol) const
{
if (isReadOnly()) {
return;
}
if (eol.isNull()) {
_emulation->sendText(text);
} else {
_emulation->sendText(text + eol);
}
}
// Only D-Bus calls this function (via SendText or runCommand)
void Session::sendText(const QString& text) const
{
if (isReadOnly()) {
return;
}
#if !defined(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS)
if (show_disallow_certain_dbus_methods_message) {
KNotification::event(KNotification::Warning, QStringLiteral("Konsole D-Bus Warning"),
i18n("The D-Bus methods sendText/runCommand were just used. There are security concerns about allowing these methods to be public. If desired, these methods can be changed to internal use only by re-compiling Konsole. This warning will only show once for this Konsole instance.
"));
show_disallow_certain_dbus_methods_message = false;
}
#endif
_emulation->sendText(text);
}
// Only D-Bus calls this function
void Session::runCommand(const QString& command) const
{
sendText(command + QLatin1Char('\n'));
}
void Session::sendMouseEvent(int buttons, int column, int line, int eventType)
{
_emulation->sendMouseEvent(buttons, column, line, eventType);
}
void Session::done(int exitCode, QProcess::ExitStatus exitStatus)
{
// This slot should be triggered only one time
disconnect(_shellProcess,
QOverload::of(&Konsole::Pty::finished),
this, &Konsole::Session::done);
if (!_autoClose) {
_userTitle = i18nc("@info:shell This session is done", "Finished");
emit sessionAttributeChanged();
return;
}
if (_closePerUserRequest) {
emit finished();
return;
}
QString message;
if (exitCode != 0) {
if (exitStatus != QProcess::NormalExit) {
message = i18n("Program '%1' crashed.", _program);
} else {
message = i18n("Program '%1' exited with status %2.", _program, exitCode);
}
//FIXME: See comments in Session::silenceTimerDone()
KNotification::event(QStringLiteral("Finished"), message , QPixmap(),
QApplication::activeWindow(),
KNotification::CloseWhenWidgetActivated);
}
if (exitStatus != QProcess::NormalExit) {
// this seeming duplicated line is for the case when exitCode is 0
message = i18n("Program '%1' crashed.", _program);
terminalWarning(message);
} else {
emit finished();
}
}
Emulation* Session::emulation() const
{
return _emulation;
}
QString Session::keyBindings() const
{
return _emulation->keyBindings();
}
QStringList Session::environment() const
{
return _environment;
}
void Session::setEnvironment(const QStringList& environment)
{
if (isReadOnly()) {
return;
}
_environment = environment;
}
void Session::addEnvironmentEntry(const QString& entry)
{
_environment << entry;
}
int Session::sessionId() const
{
return _sessionId;
}
void Session::setKeyBindings(const QString& name)
{
_emulation->setKeyBindings(name);
}
void Session::setTitle(TitleRole role , const QString& newTitle)
{
if (title(role) != newTitle) {
if (role == NameRole) {
_nameTitle = newTitle;
} else if (role == DisplayedTitleRole) {
_displayTitle = newTitle;
}
emit sessionAttributeChanged();
}
}
QString Session::title(TitleRole role) const
{
if (role == NameRole) {
return _nameTitle;
} else if (role == DisplayedTitleRole) {
return _displayTitle;
} else {
return QString();
}
}
ProcessInfo* Session::getProcessInfo()
{
ProcessInfo* process = nullptr;
if (isForegroundProcessActive() && updateForegroundProcessInfo()) {
process = _foregroundProcessInfo;
} else {
updateSessionProcessInfo();
process = _sessionProcessInfo;
}
return process;
}
void Session::updateSessionProcessInfo()
{
Q_ASSERT(_shellProcess);
bool ok;
// The checking for pid changing looks stupid, but it is needed
// at the moment to workaround the problem that processId() might
// return 0
if ((_sessionProcessInfo == nullptr) ||
(processId() != 0 && processId() != _sessionProcessInfo->pid(&ok))) {
delete _sessionProcessInfo;
_sessionProcessInfo = ProcessInfo::newInstance(processId());
_sessionProcessInfo->setUserHomeDir();
}
_sessionProcessInfo->update();
}
bool Session::updateForegroundProcessInfo()
{
Q_ASSERT(_shellProcess);
const int foregroundPid = _shellProcess->foregroundProcessGroup();
if (foregroundPid != _foregroundPid) {
delete _foregroundProcessInfo;
_foregroundProcessInfo = ProcessInfo::newInstance(foregroundPid);
_foregroundPid = foregroundPid;
}
if (_foregroundProcessInfo != nullptr) {
_foregroundProcessInfo->update();
return _foregroundProcessInfo->isValid();
} else {
return false;
}
}
bool Session::isRemote()
{
ProcessInfo* process = getProcessInfo();
bool ok = false;
return (process->name(&ok) == QLatin1String("ssh") && ok);
}
QString Session::getDynamicTitle()
{
ProcessInfo* process = getProcessInfo();
// format tab titles using process info
bool ok = false;
if (process->name(&ok) == QLatin1String("ssh") && ok) {
SSHProcessInfo sshInfo(*process);
return sshInfo.format(tabTitleFormat(Session::RemoteTabTitle));
}
/*
* Parses an input string, looking for markers beginning with a '%'
* character and returns a string with the markers replaced
* with information from this process description.
*
* The markers recognized are:
*
+ * - %B - User's Bourne prompt sigil ($, or # for superuser).
* - %u - Name of the user which owns the process.
* - %n - Replaced with the name of the process.
* - %d - Replaced with the last part of the path name of the
* process' current working directory.
*
* (eg. if the current directory is '/home/bob' then
* 'bob' would be returned)
*
* - %D - Replaced with the current working directory of the process.
*
*/
QString title = tabTitleFormat(Session::LocalTabTitle);
// search for and replace known marker
+
+ int UID = process->userId(&ok);
+ if(!ok) {
+ title.replace(QLatin1String("%B"), QStringLiteral("-"));
+ } else {
+ //title.replace(QLatin1String("%I"), QString::number(UID));
+ if (UID == 0) {
+ title.replace(QLatin1String("%B"), QStringLiteral("#"));
+ } else {
+ title.replace(QLatin1String("%B"), QStringLiteral("$"));
+ }
+ }
+
+
title.replace(QLatin1String("%u"), process->userName());
title.replace(QLatin1String("%h"), Konsole::ProcessInfo::localHost());
title.replace(QLatin1String("%n"), process->name(&ok));
QString dir = _reportedWorkingUrl.toLocalFile();
ok = true;
if (dir.isEmpty()) {
// update current directory from process
updateWorkingDirectory();
dir = process->currentDir(&ok);
}
if(!ok) {
title.replace(QLatin1String("%d"), QStringLiteral("-"));
title.replace(QLatin1String("%D"), QStringLiteral("-"));
} else {
- if (title.contains(QLatin1String("%D"))) {
- const QString homeDir = process->userHomeDir();
- if (!homeDir.isEmpty()) {
- // Change User's Home Dir w/ ~ only at the beginning
- if (dir.startsWith(homeDir)) {
- dir.remove(0, homeDir.length());
- dir.prepend(QLatin1Char('~'));
- }
+ // allow for shortname to have the ~ as homeDir
+ const QString homeDir = process->userHomeDir();
+ if (!homeDir.isEmpty()) {
+ if (dir.startsWith(homeDir)) {
+ dir.remove(0, homeDir.length());
+ dir.prepend(QLatin1Char('~'));
}
- title.replace(QLatin1String("%D"), dir);
}
+ title.replace(QLatin1String("%D"), dir);
title.replace(QLatin1String("%d"), process->formatShortDir(dir));
}
return title;
}
QUrl Session::getUrl()
{
if (_reportedWorkingUrl.isValid()) {
return _reportedWorkingUrl;
}
QString path;
updateSessionProcessInfo();
if (_sessionProcessInfo->isValid()) {
bool ok = false;
// check if foreground process is bookmark-able
if (isForegroundProcessActive() && _foregroundProcessInfo->isValid()) {
// for remote connections, save the user and host
// bright ideas to get the directory at the other end are welcome :)
if (_foregroundProcessInfo->name(&ok) == QLatin1String("ssh") && ok) {
SSHProcessInfo sshInfo(*_foregroundProcessInfo);
QUrl url;
url.setScheme(QStringLiteral("ssh"));
url.setUserName(sshInfo.userName());
url.setHost(sshInfo.host());
const QString port = sshInfo.port();
if (!port.isEmpty() && port != QLatin1String("22")) {
url.setPort(port.toInt());
}
return url;
} else {
path = _foregroundProcessInfo->currentDir(&ok);
if (!ok) {
path.clear();
}
}
} else { // otherwise use the current working directory of the shell process
path = _sessionProcessInfo->currentDir(&ok);
if (!ok) {
path.clear();
}
}
}
return QUrl::fromLocalFile(path);
}
void Session::setIconName(const QString& iconName)
{
if (iconName != _iconName) {
_iconName = iconName;
emit sessionAttributeChanged();
}
}
void Session::setIconText(const QString& iconText)
{
_iconText = iconText;
}
QString Session::iconName() const
{
return isReadOnly() ? QStringLiteral("object-locked") : _iconName;
}
QString Session::iconText() const
{
return _iconText;
}
void Session::setHistoryType(const HistoryType& hType)
{
_emulation->setHistory(hType);
}
const HistoryType& Session::historyType() const
{
return _emulation->history();
}
void Session::clearHistory()
{
_emulation->clearHistory();
}
QStringList Session::arguments() const
{
return _arguments;
}
QString Session::program() const
{
return _program;
}
bool Session::isMonitorActivity() const
{
return _monitorActivity;
}
bool Session::isMonitorSilence() const
{
return _monitorSilence;
}
void Session::setMonitorActivity(bool monitor)
{
if (_monitorActivity == monitor) {
return;
}
_monitorActivity = monitor;
_notifiedActivity = false;
// This timer is meaningful only after activity has been notified
_activityTimer->stop();
activityStateSet(NOTIFYNORMAL);
}
void Session::setMonitorSilence(bool monitor)
{
if (_monitorSilence == monitor) {
return;
}
_monitorSilence = monitor;
if (_monitorSilence) {
_silenceTimer->start(_silenceSeconds * 1000);
} else {
_silenceTimer->stop();
}
activityStateSet(NOTIFYNORMAL);
}
void Session::setMonitorSilenceSeconds(int seconds)
{
_silenceSeconds = seconds;
if (_monitorSilence) {
_silenceTimer->start(_silenceSeconds * 1000);
}
}
void Session::setAddToUtmp(bool add)
{
_addToUtmp = add;
}
void Session::setAutoClose(bool close)
{
_autoClose = close;
}
bool Session::autoClose() const
{
return _autoClose;
}
void Session::setFlowControlEnabled(bool enabled)
{
if (isReadOnly()) {
return;
}
_flowControlEnabled = enabled;
if (_shellProcess != nullptr) {
_shellProcess->setFlowControlEnabled(_flowControlEnabled);
}
emit flowControlEnabledChanged(enabled);
}
bool Session::flowControlEnabled() const
{
if (_shellProcess != nullptr) {
return _shellProcess->flowControlEnabled();
} else {
return _flowControlEnabled;
}
}
void Session::fireZModemDownloadDetected()
{
if (!_zmodemBusy) {
QTimer::singleShot(10, this, &Konsole::Session::zmodemDownloadDetected);
_zmodemBusy = true;
}
}
void Session::fireZModemUploadDetected()
{
if (!_zmodemBusy) {
QTimer::singleShot(10, this, &Konsole::Session::zmodemUploadDetected);
}
}
void Session::cancelZModem()
{
_shellProcess->sendData(QByteArrayLiteral("\030\030\030\030")); // Abort
_zmodemBusy = false;
}
void Session::startZModem(const QString& zmodem, const QString& dir, const QStringList& list)
{
_zmodemBusy = true;
_zmodemProc = new KProcess();
_zmodemProc->setOutputChannelMode(KProcess::SeparateChannels);
*_zmodemProc << zmodem << QStringLiteral("-v") << QStringLiteral("-e") << list;
if (!dir.isEmpty()) {
_zmodemProc->setWorkingDirectory(dir);
}
connect(_zmodemProc, &KProcess::readyReadStandardOutput, this, &Konsole::Session::zmodemReadAndSendBlock);
connect(_zmodemProc, &KProcess::readyReadStandardError, this, &Konsole::Session::zmodemReadStatus);
connect(_zmodemProc,
QOverload::of(&KProcess::finished),
this, &Konsole::Session::zmodemFinished);
_zmodemProc->start();
disconnect(_shellProcess, &Konsole::Pty::receivedData,
this, &Konsole::Session::onReceiveBlock);
connect(_shellProcess, &Konsole::Pty::receivedData, this, &Konsole::Session::zmodemReceiveBlock);
_zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false,
i18n("ZModem Progress"));
connect(_zmodemProgress, &Konsole::ZModemDialog::zmodemCancel, this, &Konsole::Session::zmodemFinished);
_zmodemProgress->show();
}
void Session::zmodemReadAndSendBlock()
{
_zmodemProc->setReadChannel(QProcess::StandardOutput);
QByteArray data = _zmodemProc->read(ZMODEM_BUFFER_SIZE);
while (data.count() != 0) {
_shellProcess->sendData(data);
data = _zmodemProc->read(ZMODEM_BUFFER_SIZE);
}
}
void Session::zmodemReadStatus()
{
_zmodemProc->setReadChannel(QProcess::StandardError);
QByteArray msg = _zmodemProc->readAll();
while (!msg.isEmpty()) {
int i = msg.indexOf('\015');
int j = msg.indexOf('\012');
QByteArray txt;
if ((i != -1) && ((j == -1) || (i < j))) {
msg = msg.mid(i + 1);
} else if (j != -1) {
txt = msg.left(j);
msg = msg.mid(j + 1);
} else {
txt = msg;
msg.truncate(0);
}
if (!txt.isEmpty()) {
_zmodemProgress->addText(QString::fromLocal8Bit(txt));
}
}
}
void Session::zmodemReceiveBlock(const char* data, int len)
{
static int steps = 0;
QByteArray bytes(data, len);
_zmodemProc->write(bytes);
// Provide some feedback to dialog
if (steps > 100) {
_zmodemProgress->addProgressText(QStringLiteral("."));
steps = 0;
}
steps++;
}
void Session::zmodemFinished()
{
/* zmodemFinished() is called by QProcess's finished() and
ZModemDialog's user1Clicked(). Therefore, an invocation by
user1Clicked() will recursively invoke this function again
when the KProcess is deleted! */
if (_zmodemProc != nullptr) {
KProcess* process = _zmodemProc;
_zmodemProc = nullptr; // Set _zmodemProc to 0 avoid recursive invocations!
_zmodemBusy = false;
delete process; // Now, the KProcess may be disposed safely.
disconnect(_shellProcess, &Konsole::Pty::receivedData,
this , &Konsole::Session::zmodemReceiveBlock);
connect(_shellProcess, &Konsole::Pty::receivedData, this, &Konsole::Session::onReceiveBlock);
_shellProcess->sendData(QByteArrayLiteral("\030\030\030\030")); // Abort
_shellProcess->sendData(QByteArrayLiteral("\001\013\n")); // Try to get prompt back
_zmodemProgress->transferDone();
}
}
void Session::onReceiveBlock(const char* buf, int len)
{
_emulation->receiveData(buf, len);
}
QSize Session::size()
{
return _emulation->imageSize();
}
void Session::setSize(const QSize& size)
{
if ((size.width() <= 1) || (size.height() <= 1)) {
return;
}
emit resizeRequest(size);
}
QSize Session::preferredSize() const
{
return _preferredSize;
}
void Session::setPreferredSize(const QSize& size)
{
_preferredSize = size;
}
int Session::processId() const
{
return _shellProcess->pid();
}
void Session::setTitle(int role , const QString& title)
{
switch (role) {
case 0:
setTitle(Session::NameRole, title);
break;
case 1:
setTitle(Session::DisplayedTitleRole, title);
// without these, that title will be overridden by the expansion of
// title format shortly after, which will confuses users.
_localTabTitleFormat = title;
_remoteTabTitleFormat = title;
break;
}
}
QString Session::title(int role) const
{
switch (role) {
case 0:
return title(Session::NameRole);
case 1:
return title(Session::DisplayedTitleRole);
default:
return QString();
}
}
void Session::setTabTitleFormat(int context , const QString& format)
{
switch (context) {
case 0:
setTabTitleFormat(Session::LocalTabTitle, format);
break;
case 1:
setTabTitleFormat(Session::RemoteTabTitle, format);
break;
}
}
QString Session::tabTitleFormat(int context) const
{
switch (context) {
case 0:
return tabTitleFormat(Session::LocalTabTitle);
case 1:
return tabTitleFormat(Session::RemoteTabTitle);
default:
return QString();
}
}
void Session::setHistorySize(int lines)
{
if (isReadOnly()) {
return;
}
if (lines < 0) {
setHistoryType(HistoryTypeFile());
} else if (lines == 0) {
setHistoryType(HistoryTypeNone());
} else {
setHistoryType(CompactHistoryType(lines));
}
}
int Session::historySize() const
{
const HistoryType& currentHistory = historyType();
if (currentHistory.isEnabled()) {
if (currentHistory.isUnlimited()) {
return -1;
} else {
return currentHistory.maximumLineCount();
}
} else {
return 0;
}
}
void Session::setProfile(const QString &profileName)
{
const QList profiles = ProfileManager::instance()->allProfiles();
foreach (const Profile::Ptr &profile, profiles) {
if (profile->name() == profileName) {
SessionManager::instance()->setSessionProfile(this, profile);
}
}
}
int Session::foregroundProcessId()
{
int pid;
bool ok = false;
pid = getProcessInfo()->pid(&ok);
if (!ok) {
pid = -1;
}
return pid;
}
bool Session::isForegroundProcessActive()
{
// foreground process info is always updated after this
return (_shellProcess->pid() != _shellProcess->foregroundProcessGroup());
}
QString Session::foregroundProcessName()
{
QString name;
if (updateForegroundProcessInfo()) {
bool ok = false;
name = _foregroundProcessInfo->name(&ok);
if (!ok) {
name.clear();
}
}
return name;
}
void Session::saveSession(KConfigGroup& group)
{
group.writePathEntry("WorkingDir", currentWorkingDirectory());
group.writeEntry("LocalTab", tabTitleFormat(LocalTabTitle));
group.writeEntry("RemoteTab", tabTitleFormat(RemoteTabTitle));
group.writeEntry("SessionGuid", _uniqueIdentifier.toString());
group.writeEntry("Encoding", QString::fromUtf8(codec()));
}
void Session::restoreSession(KConfigGroup& group)
{
QString value;
value = group.readPathEntry("WorkingDir", QString());
if (!value.isEmpty()) {
setInitialWorkingDirectory(value);
}
value = group.readEntry("LocalTab");
if (!value.isEmpty()) {
setTabTitleFormat(LocalTabTitle, value);
}
value = group.readEntry("RemoteTab");
if (!value.isEmpty()) {
setTabTitleFormat(RemoteTabTitle, value);
}
value = group.readEntry("SessionGuid");
if (!value.isEmpty()) {
_uniqueIdentifier = QUuid(value);
}
value = group.readEntry("Encoding");
if (!value.isEmpty()) {
setCodec(value.toUtf8());
}
}
QString Session::validDirectory(const QString& dir) const
{
QString validDir = dir;
if (validDir.isEmpty()) {
validDir = QDir::currentPath();
}
const QFileInfo fi(validDir);
if (!fi.exists() || !fi.isDir()) {
validDir = QDir::homePath();
}
return validDir;
}
bool Session::isReadOnly() const
{
return _readOnly;
}
void Session::setReadOnly(bool readOnly)
{
if (_readOnly != readOnly) {
_readOnly = readOnly;
// Needed to update the tab icons and all
// attached views.
emit readOnlyChanged();
}
}
SessionGroup::SessionGroup(QObject* parent)
: QObject(parent), _masterMode(0)
{
}
SessionGroup::~SessionGroup() = default;
int SessionGroup::masterMode() const
{
return _masterMode;
}
QList SessionGroup::sessions() const
{
return _sessions.keys();
}
bool SessionGroup::masterStatus(Session* session) const
{
return _sessions[session];
}
void SessionGroup::addSession(Session* session)
{
connect(session, &Konsole::Session::finished, this, &Konsole::SessionGroup::sessionFinished);
_sessions.insert(session, false);
}
void SessionGroup::removeSession(Session* session)
{
disconnect(session, &Konsole::Session::finished, this, &Konsole::SessionGroup::sessionFinished);
setMasterStatus(session, false);
_sessions.remove(session);
}
void SessionGroup::sessionFinished()
{
auto* session = qobject_cast(sender());
Q_ASSERT(session);
removeSession(session);
}
void SessionGroup::setMasterMode(int mode)
{
_masterMode = mode;
}
QList SessionGroup::masters() const
{
return _sessions.keys(true);
}
void SessionGroup::setMasterStatus(Session* session , bool master)
{
const bool wasMaster = _sessions[session];
if (wasMaster == master) {
// No status change -> nothing to do.
return;
}
_sessions[session] = master;
if (master) {
connect(session->emulation(), &Konsole::Emulation::sendData, this, &Konsole::SessionGroup::forwardData);
} else {
disconnect(session->emulation(), &Konsole::Emulation::sendData,
this, &Konsole::SessionGroup::forwardData);
}
}
void SessionGroup::forwardData(const QByteArray& data)
{
static bool _inForwardData = false;
if (_inForwardData) { // Avoid recursive calls among session groups!
// A recursive call happens when a master in group A calls forwardData()
// in group B. If one of the destination sessions in group B is also a
// master of a group including the master session of group A, this would
// again call forwardData() in group A, and so on.
return;
}
_inForwardData = true;
const QList sessionsKeys = _sessions.keys();
foreach(Session* other, sessionsKeys) {
if (!_sessions[other]) {
other->emulation()->sendString(data);
}
}
_inForwardData = false;
}
diff --git a/src/TabTitleFormatButton.cpp b/src/TabTitleFormatButton.cpp
index c492328e..c48fed3d 100644
--- a/src/TabTitleFormatButton.cpp
+++ b/src/TabTitleFormatButton.cpp
@@ -1,109 +1,110 @@
/*
Copyright 2007-2008 by Robert Knight
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "TabTitleFormatButton.h"
// Qt
#include
#include
// KDE
#include
using namespace Konsole;
const TabTitleFormatButton::Element TabTitleFormatButton::_localElements[] = {
{ QStringLiteral("%n"), I18N_NOOP("Program Name: %n") },
{ QStringLiteral("%d"), I18N_NOOP("Current Directory (Short): %d") },
{ QStringLiteral("%D"), I18N_NOOP("Current Directory (Long): %D") },
{ QStringLiteral("%w"), I18N_NOOP("Window Title Set by Shell: %w") },
{ QStringLiteral("%#"), I18N_NOOP("Session Number: %#") },
{ QStringLiteral("%u"), I18N_NOOP("User Name: %u") },
- { QStringLiteral("%h"), I18N_NOOP("Local Host: %h") }
+ { QStringLiteral("%h"), I18N_NOOP("Local Host: %h") },
+ { QStringLiteral("%B"), I18N_NOOP("User's Bourne prompt sigil: %B") } // ($, or # for superuser)
};
const int TabTitleFormatButton::_localElementCount
= sizeof(_localElements) / sizeof(TabTitleFormatButton::Element);
const TabTitleFormatButton::Element TabTitleFormatButton::_remoteElements[] = {
{ QStringLiteral("%u"), I18N_NOOP("User Name: %u") },
{ QStringLiteral("%U"), I18N_NOOP("User Name@ (if given): %U") },
{ QStringLiteral("%h"), I18N_NOOP("Remote Host (Short): %h") },
{ QStringLiteral("%H"), I18N_NOOP("Remote Host (Long): %H") },
{ QStringLiteral("%c"), I18N_NOOP("Command and arguments: %c") },
{ QStringLiteral("%w"), I18N_NOOP("Window Title Set by Shell: %w") },
{ QStringLiteral("%#"), I18N_NOOP("Session Number: %#") }
};
const int TabTitleFormatButton::_remoteElementCount
= sizeof(_remoteElements) / sizeof(TabTitleFormatButton::Element);
TabTitleFormatButton::TabTitleFormatButton(QWidget *parent) :
QPushButton(parent),
_context(Session::LocalTabTitle)
{
setText(i18n("Insert"));
setMenu(new QMenu());
connect(menu(), &QMenu::triggered, this, &Konsole::TabTitleFormatButton::fireElementSelected);
}
TabTitleFormatButton::~TabTitleFormatButton()
{
menu()->deleteLater();
}
void TabTitleFormatButton::fireElementSelected(QAction *action)
{
emit dynamicElementSelected(action->data().toString());
}
void TabTitleFormatButton::setContext(Session::TabTitleContext titleContext)
{
_context = titleContext;
menu()->clear();
int count = 0;
const Element *array = nullptr;
if (titleContext == Session::LocalTabTitle) {
setToolTip(i18nc("@info:tooltip", "Insert title format"));
array = _localElements;
count = _localElementCount;
} else if (titleContext == Session::RemoteTabTitle) {
setToolTip(i18nc("@info:tooltip", "Insert remote title format"));
array = _remoteElements;
count = _remoteElementCount;
}
QList menuActions;
menuActions.reserve(count);
for (int i = 0; i < count; i++) {
QAction *action = new QAction(i18n(array[i].description), this);
action->setData(array[i].element);
menuActions << action;
}
menu()->addActions(menuActions);
}
Session::TabTitleContext TabTitleFormatButton::context() const
{
return _context;
}