From ba27c8f8bbed711c1ddca906fc8b206077ef7616 Mon Sep 17 00:00:00 2001 From: tandunn Date: Fri, 18 Dec 2020 17:36:29 -0500 Subject: [PATCH 1/2] FEAT(client): Add possibility to set nickname As requested in #3967 this commit implements the ability to set nicknames for other users when connected to the same server. The change is added to the client database by the user id for persistence. In order to set a nickname, a user can right click on that user and click Set Nickname. This opens a window where the user can enter the new nickname. If the text field is cleared, no nickname is displayed. Implements #3967 --- src/mumble/CMakeLists.txt | 3 + src/mumble/ClientUser.cpp | 12 ++++ src/mumble/ClientUser.h | 5 ++ src/mumble/Database.cpp | 24 +++++++ src/mumble/Database.h | 3 + src/mumble/LookConfig.cpp | 2 + src/mumble/LookConfig.ui | 14 +++- src/mumble/MainWindow.cpp | 18 +++++ src/mumble/MainWindow.h | 4 ++ src/mumble/MainWindow.ui | 11 +++ src/mumble/Messages.cpp | 1 + src/mumble/Settings.cpp | 3 + src/mumble/Settings.h | 1 + src/mumble/UserLocalNicknameDialog.cpp | 93 ++++++++++++++++++++++++++ src/mumble/UserLocalNicknameDialog.h | 41 ++++++++++++ src/mumble/UserLocalNicknameDialog.ui | 53 +++++++++++++++ src/mumble/UserModel.cpp | 15 ++++- 17 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 src/mumble/UserLocalNicknameDialog.cpp create mode 100644 src/mumble/UserLocalNicknameDialog.h create mode 100644 src/mumble/UserLocalNicknameDialog.ui diff --git a/src/mumble/CMakeLists.txt b/src/mumble/CMakeLists.txt index 7fc604127..87bee30c5 100644 --- a/src/mumble/CMakeLists.txt +++ b/src/mumble/CMakeLists.txt @@ -209,6 +209,9 @@ set(MUMBLE_SOURCES "UserInformation.ui" "UserListModel.cpp" "UserListModel.h" + "UserLocalNicknameDialog.cpp" + "UserLocalNicknameDialog.h" + "UserLocalNicknameDialog.ui" "UserLocalVolumeDialog.cpp" "UserLocalVolumeDialog.h" "UserLocalVolumeDialog.ui" diff --git a/src/mumble/ClientUser.cpp b/src/mumble/ClientUser.cpp index 221cf36bd..6655cf76e 100644 --- a/src/mumble/ClientUser.cpp +++ b/src/mumble/ClientUser.cpp @@ -24,6 +24,10 @@ float ClientUser::getLocalVolumeAdjustments() const { return m_localVolume; } +QString ClientUser::getLocalNickname() const { + return m_localNickname; +} + ClientUser *ClientUser::get(unsigned int uiSession) { QReadLocker lock(&c_qrwlUsers); ClientUser *p = c_qmUsers.value(uiSession); @@ -240,6 +244,14 @@ void ClientUser::setLocalVolumeAdjustment(float adjustment) { emit localVolumeAdjustmentsChanged(m_localVolume, oldAdjustment); } +void ClientUser::setLocalNickname(const QString &nickname) { + if (m_localNickname != nickname) { + m_localNickname = nickname; + + emit localNicknameChanged(); + } +} + bool ClientUser::lessThanOverlay(const ClientUser *first, const ClientUser *second) { if (g.s.os.osSort == OverlaySettings::LastStateChange) { // Talkers above non-talkers diff --git a/src/mumble/ClientUser.h b/src/mumble/ClientUser.h index 4b2ddab5f..ec080c63b 100644 --- a/src/mumble/ClientUser.h +++ b/src/mumble/ClientUser.h @@ -20,6 +20,7 @@ private: protected: float m_localVolume = 1.0f; + QString m_localNickname; public: Settings::TalkState tsState; @@ -42,6 +43,8 @@ public: float getLocalVolumeAdjustments() const; + QString getLocalNickname() const; + /** * Determines whether a user is active or not * A user is active when it is currently speaking or when the user has @@ -81,12 +84,14 @@ public slots: void setPrioritySpeaker(bool priority); void setRecording(bool recording); void setLocalVolumeAdjustment(float adjustment); + void setLocalNickname(const QString &nickname); signals: void talkingStateChanged(); void muteDeafStateChanged(); void prioritySpeakerStateChanged(); void recordingStateChanged(); void localVolumeAdjustmentsChanged(float newAdjustment, float oldAdjustment); + void localNicknameChanged(); }; #endif diff --git a/src/mumble/Database.cpp b/src/mumble/Database.cpp index 48b52988c..10f40d407 100644 --- a/src/mumble/Database.cpp +++ b/src/mumble/Database.cpp @@ -207,6 +207,9 @@ Database::Database(const QString &dbname) { execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `volume` (`id` INTEGER PRIMARY KEY " "AUTOINCREMENT, `hash` TEXT, `volume` FLOAT)")); execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `volume_hash` ON `volume`(`hash`)")); + execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `nicknames` (`id` INTEGER PRIMARY KEY " + "AUTOINCREMENT, `hash` TEXT, `nickname` TEXT)")); + execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `nicknames_hash` ON `nicknames`(`hash`)")); // Note: A previous snapshot version created a table called 'hidden' execQueryAndLogFailure( @@ -365,6 +368,27 @@ float Database::getUserLocalVolume(const QString &hash) { return 1.0f; } +void Database::setUserLocalNickname(const QString &hash, const QString &nickname) { + QSqlQuery query(db); + + query.prepare(QLatin1String("INSERT OR REPLACE INTO `nicknames` (`hash`, `nickname`) VALUES (?,?)")); + query.addBindValue(hash); + query.addBindValue(nickname); + execQueryAndLogFailure(query); +} + +QString Database::getUserLocalNickname(const QString &hash) { + QSqlQuery query(db); + + query.prepare(QLatin1String("SELECT `nickname` FROM `nicknames` WHERE `hash` = ?")); + query.addBindValue(hash); + execQueryAndLogFailure(query); + if (query.first()) { + return query.value(0).toString(); + } + return QString(); +} + void Database::setLocalMuted(const QString &hash, bool muted) { QSqlQuery query(db); diff --git a/src/mumble/Database.h b/src/mumble/Database.h index e139053a8..4bed1914d 100644 --- a/src/mumble/Database.h +++ b/src/mumble/Database.h @@ -51,6 +51,9 @@ public: float getUserLocalVolume(const QString &hash); void setUserLocalVolume(const QString &hash, float volume); + QString getUserLocalNickname(const QString &hash); + void setUserLocalNickname(const QString &hash, const QString &nickname); + bool isChannelFiltered(const QByteArray &server_cert_digest, const int channel_id); void setChannelFiltered(const QByteArray &server_cert_digest, const int channel_id, bool hidden); diff --git a/src/mumble/LookConfig.cpp b/src/mumble/LookConfig.cpp index 71c7164d8..0b72abbe6 100644 --- a/src/mumble/LookConfig.cpp +++ b/src/mumble/LookConfig.cpp @@ -182,6 +182,7 @@ void LookConfig::load(const Settings &r) { loadCheckBox(qcbStateInTray, r.bStateInTray); loadCheckBox(qcbShowUserCount, r.bShowUserCount); loadCheckBox(qcbShowVolumeAdjustments, r.bShowVolumeAdjustments); + loadCheckBox(qcbShowNicknamesOnly, r.bShowNicknamesOnly); loadCheckBox(qcbShowContextMenuInMenuBar, r.bShowContextMenuInMenuBar); loadCheckBox(qcbShowTransmitModeComboBox, r.bShowTransmitModeComboBox); loadCheckBox(qcbHighContrast, r.bHighContrast); @@ -244,6 +245,7 @@ void LookConfig::save() const { s.bStateInTray = qcbStateInTray->isChecked(); s.bShowUserCount = qcbShowUserCount->isChecked(); s.bShowVolumeAdjustments = qcbShowVolumeAdjustments->isChecked(); + s.bShowNicknamesOnly = qcbShowNicknamesOnly->isChecked(); s.bShowContextMenuInMenuBar = qcbShowContextMenuInMenuBar->isChecked(); s.bShowTransmitModeComboBox = qcbShowTransmitModeComboBox->isChecked(); s.bHighContrast = qcbHighContrast->isChecked(); diff --git a/src/mumble/LookConfig.ui b/src/mumble/LookConfig.ui index 6b2cc1c57..bd804382d 100644 --- a/src/mumble/LookConfig.ui +++ b/src/mumble/LookConfig.ui @@ -681,7 +681,7 @@ Channel Tree - + Filter automatically hides empty channels @@ -722,7 +722,7 @@ - + Use selected item as the chat bar target @@ -779,6 +779,16 @@ + + + + Hide the username for each user if they have a nickname. + + + Show nicknames only + + + diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp index 89904bca8..cd5a17bfb 100644 --- a/src/mumble/MainWindow.cpp +++ b/src/mumble/MainWindow.cpp @@ -48,6 +48,7 @@ #include "User.h" #include "UserEdit.h" #include "UserInformation.h" +#include "UserLocalNicknameDialog.h" #include "UserLocalVolumeDialog.h" #include "UserModel.h" #include "Utils.h" @@ -1600,6 +1601,7 @@ void MainWindow::qmUser_aboutToShow() { if (g.s.bTTS) qmUser->addAction(qaUserLocalIgnoreTTS); qmUser->addAction(qaUserLocalVolume); + qmUser->addAction(qaUserLocalNickname); if (isSelf) qmUser->addAction(qaSelfComment); @@ -1656,6 +1658,7 @@ void MainWindow::qmUser_aboutToShow() { qaUserKick->setEnabled(false); qaUserBan->setEnabled(false); qaUserTextMessage->setEnabled(false); + qaUserLocalNickname->setEnabled(false); qaUserLocalMute->setEnabled(false); qaUserLocalVolume->setEnabled(false); qaUserLocalIgnore->setEnabled(false); @@ -1667,6 +1670,7 @@ void MainWindow::qmUser_aboutToShow() { qaUserKick->setEnabled(!isSelf); qaUserBan->setEnabled(!isSelf); qaUserTextMessage->setEnabled(true); + qaUserLocalNickname->setEnabled(!isSelf); qaUserLocalMute->setEnabled(!isSelf); qaUserLocalVolume->setEnabled(!isSelf); qaUserLocalIgnore->setEnabled(!isSelf); @@ -1969,6 +1973,20 @@ void MainWindow::openTextMessageDialog(ClientUser *p) { delete texm; } +void MainWindow::on_qaUserLocalNickname_triggered() { + ClientUser *p = getContextMenuUser(); + + if (!p) + return; + + openUserLocalNicknameDialog(*p); +} + +void MainWindow::openUserLocalNicknameDialog(const ClientUser &p) { + unsigned int session = p.uiSession; + UserLocalNicknameDialog::present(session, qmUserNicknameTracker); +} + void MainWindow::on_qaUserCommentView_triggered() { ClientUser *p = getContextMenuUser(); // This has to be done here because UserModel could've set it. diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h index 109568bfa..8d04221b9 100644 --- a/src/mumble/MainWindow.h +++ b/src/mumble/MainWindow.h @@ -18,6 +18,7 @@ #include "Mumble.pb.h" #include "Usage.h" #include "UserLocalVolumeDialog.h" +#include "UserLocalNicknameDialog.h" #include "ui_MainWindow.h" @@ -69,6 +70,7 @@ public: qiIconMuteSuppressed; QIcon qiTalkingOn, qiTalkingWhisper, qiTalkingShout, qiTalkingOff; QMap< unsigned int, UserLocalVolumeDialog * > qmUserVolTracker; + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > qmUserNicknameTracker; /// "Action" for when there are no actions available QAction *qaEmpty; @@ -119,6 +121,7 @@ public: void updateChatBar(); void openTextMessageDialog(ClientUser *p); + void openUserLocalNicknameDialog(const ClientUser &p); void openUserLocalVolumeDialog(ClientUser *p); #ifdef Q_OS_WIN @@ -210,6 +213,7 @@ public slots: void on_qaUserLocalIgnore_triggered(); void on_qaUserLocalIgnoreTTS_triggered(); void on_qaUserLocalMute_triggered(); + void on_qaUserLocalNickname_triggered(); void on_qaUserLocalVolume_triggered(); void on_qaUserTextMessage_triggered(); void on_qaUserRegister_triggered(); diff --git a/src/mumble/MainWindow.ui b/src/mumble/MainWindow.ui index e5891e264..9b520b2de 100644 --- a/src/mumble/MainWindow.ui +++ b/src/mumble/MainWindow.ui @@ -378,6 +378,17 @@ Sends a text message to another user. + + + &Set Nickname... + + + Set a local nickname + + + Sets a local nickname for another user. + + &Add... diff --git a/src/mumble/Messages.cpp b/src/mumble/Messages.cpp index f41335f19..204c7c507 100644 --- a/src/mumble/Messages.cpp +++ b/src/mumble/Messages.cpp @@ -553,6 +553,7 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) { if (g.db->isLocalIgnoredTTS(pDst->qsHash)) pDst->setLocalIgnoreTTS(true); pDst->setLocalVolumeAdjustment(g.db->getUserLocalVolume(pDst->qsHash)); + pDst->setLocalNickname(g.db->getUserLocalNickname(pDst->qsHash)); } if (msg.has_self_deaf() || msg.has_self_mute()) { diff --git a/src/mumble/Settings.cpp b/src/mumble/Settings.cpp index dfc0bf786..fbb802424 100644 --- a/src/mumble/Settings.cpp +++ b/src/mumble/Settings.cpp @@ -379,6 +379,7 @@ Settings::Settings() { bUsage = true; bShowUserCount = false; bShowVolumeAdjustments = true; + bShowNicknamesOnly = false; bChatBarUseSelection = false; bFilterHidesEmptyChannels = true; bFilterActive = false; @@ -867,6 +868,7 @@ void Settings::load(QSettings *settings_ptr) { SAVELOAD(bUsage, "ui/usage"); SAVELOAD(bShowUserCount, "ui/showusercount"); SAVELOAD(bShowVolumeAdjustments, "ui/showVolumeAdjustments"); + SAVELOAD(bShowNicknamesOnly, "ui/showNicknamesOnly"); SAVELOAD(bChatBarUseSelection, "ui/chatbaruseselection"); SAVELOAD(bFilterHidesEmptyChannels, "ui/filterhidesemptychannels"); SAVELOAD(bFilterActive, "ui/filteractive"); @@ -1237,6 +1239,7 @@ void Settings::save() { SAVELOAD(bUsage, "ui/usage"); SAVELOAD(bShowUserCount, "ui/showusercount"); SAVELOAD(bShowVolumeAdjustments, "ui/showVolumeAdjustments"); + SAVELOAD(bShowNicknamesOnly, "ui/showNicknamesOnly"); SAVELOAD(bChatBarUseSelection, "ui/chatbaruseselection"); SAVELOAD(bFilterHidesEmptyChannels, "ui/filterhidesemptychannels"); SAVELOAD(bFilterActive, "ui/filteractive"); diff --git a/src/mumble/Settings.h b/src/mumble/Settings.h index ee7de014e..7dd399dc0 100644 --- a/src/mumble/Settings.h +++ b/src/mumble/Settings.h @@ -335,6 +335,7 @@ struct Settings { bool bUsage; bool bShowUserCount; bool bShowVolumeAdjustments; + bool bShowNicknamesOnly; bool bChatBarUseSelection; bool bFilterHidesEmptyChannels; bool bFilterActive; diff --git a/src/mumble/UserLocalNicknameDialog.cpp b/src/mumble/UserLocalNicknameDialog.cpp new file mode 100644 index 000000000..afb43bc88 --- /dev/null +++ b/src/mumble/UserLocalNicknameDialog.cpp @@ -0,0 +1,93 @@ +// Copyright 2020 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#include "UserLocalNicknameDialog.h" +#include "ClientUser.h" +#include "Database.h" +#include "MainWindow.h" + +#include +#include + +// We define a global macro called 'g'. This can lead to issues when included code uses 'g' as a type or parameter name +// (like protobuf 3.7 does). As such, for now, we have to make this our last include. +#include "Global.h" + +UserLocalNicknameDialog::UserLocalNicknameDialog( + unsigned int sessionId, + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > &qmUserNicknameTracker) + : QDialog(nullptr), m_clientSession(sessionId), m_qmUserNicknameTracker(qmUserNicknameTracker) { + setupUi(this); + + qleUserLocalNickname->setFocus(); + + qleUserLocalNickname->setAccessibleName(tr("User nickname")); + + ClientUser *user = ClientUser::get(sessionId); + if (!user) { + UserLocalNicknameDialog::close(); + } else { + QString title = tr("Adjusting local nickname for %1").arg(user->qsName); + setWindowTitle(title); + qleUserLocalNickname->setText(user->getLocalNickname()); + m_originalNickname = qleUserLocalNickname->text(); + } + + if (g.mw && g.mw->windowFlags() & Qt::WindowStaysOnTopHint) { + // If the main window is set to always be on top of other windows, we should make the + // nickname dialog behave the same in order for it to not get hidden behind the main window. + setWindowFlags(Qt::WindowStaysOnTopHint); + } +} + +void UserLocalNicknameDialog::closeEvent(QCloseEvent *event) { + m_qmUserNicknameTracker.erase(m_clientSession); + event->accept(); +} + +void UserLocalNicknameDialog::present( + unsigned int sessionId, + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > &qmUserNicknameTracker) { + if (qmUserNicknameTracker.find(sessionId) != qmUserNicknameTracker.end()) { + qmUserNicknameTracker.at(sessionId)->show(); + qmUserNicknameTracker.at(sessionId)->raise(); + } else { + std::unique_ptr< UserLocalNicknameDialog > userNickname = + std::make_unique< UserLocalNicknameDialog >(sessionId, qmUserNicknameTracker); + userNickname->show(); + qmUserNicknameTracker.insert(std::make_pair(sessionId, std::move(userNickname))); + } +} + +void UserLocalNicknameDialog::on_qleUserLocalNickname_textChanged(const QString &text) { + ClientUser *user = ClientUser::get(m_clientSession); + if (user) { + user->setLocalNickname(text); + } +} + +void UserLocalNicknameDialog::on_qbbUserLocalNickname_clicked(QAbstractButton *button) { + if (button == qbbUserLocalNickname->button(QDialogButtonBox::Reset)) { + qleUserLocalNickname->setText(m_originalNickname); + } else if (button == qbbUserLocalNickname->button(QDialogButtonBox::Ok)) { + ClientUser *user = ClientUser::get(m_clientSession); + if (user) { + if (!user->qsHash.isEmpty()) { + g.db->setUserLocalNickname(user->qsHash, user->getLocalNickname()); + } else { + g.mw->logChangeNotPermanent(QObject::tr("Local Nickname Adjustment..."), user); + } + } + UserLocalNicknameDialog::close(); + } else if (button == qbbUserLocalNickname->button(QDialogButtonBox::Cancel)) { + qleUserLocalNickname->setText(m_originalNickname); + UserLocalNicknameDialog::close(); + } +} + +void UserLocalNicknameDialog::reject() { + m_qmUserNicknameTracker.erase(m_clientSession); + UserLocalNicknameDialog::close(); +} diff --git a/src/mumble/UserLocalNicknameDialog.h b/src/mumble/UserLocalNicknameDialog.h new file mode 100644 index 000000000..7655135f6 --- /dev/null +++ b/src/mumble/UserLocalNicknameDialog.h @@ -0,0 +1,41 @@ +// Copyright 2020 The Mumble Developers. All rights reserved. +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file at the root of the +// Mumble source tree or at . + +#ifndef MUMBLE_MUMBLE_USERNICKNAME_H_ +#define MUMBLE_MUMBLE_USERNICKNAME_H_ + +#include +#include + +#include "ClientUser.h" +#include "ui_UserLocalNicknameDialog.h" + +class UserLocalNicknameDialog : public QDialog, private Ui::UserLocalNicknameDialog { + Q_OBJECT + Q_DISABLE_COPY(UserLocalNicknameDialog); + + /// The session ID for the user that the dialog is changing the nickname for. + unsigned int m_clientSession; + + /// The user's original nickname when entering the dialog. + QString m_originalNickname; + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > &m_qmUserNicknameTracker; + +public slots: + void closeEvent(QCloseEvent *event); + void on_qleUserLocalNickname_textChanged(const QString &text); + void on_qbbUserLocalNickname_clicked(QAbstractButton *b); + void reject(); + +public: + static void + present(unsigned int sessionId, + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > &qmUserNicknameTracker); + UserLocalNicknameDialog( + unsigned int sessionId, + std::unordered_map< unsigned int, std::unique_ptr< UserLocalNicknameDialog > > &qmUserNicknameTracker); +}; + +#endif diff --git a/src/mumble/UserLocalNicknameDialog.ui b/src/mumble/UserLocalNicknameDialog.ui new file mode 100644 index 000000000..b75b1c594 --- /dev/null +++ b/src/mumble/UserLocalNicknameDialog.ui @@ -0,0 +1,53 @@ + + + UserLocalNicknameDialog + + + + 0 + 0 + 500 + 80 + + + + + 500 + 80 + + + + + 16777215 + 224 + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + false + + + + + + + Local nickname for other users + + + <b>Adjust the nickname of other users locally</b><br /> + + + + + + + + diff --git a/src/mumble/UserModel.cpp b/src/mumble/UserModel.cpp index 764eaa447..31487ea38 100644 --- a/src/mumble/UserModel.cpp +++ b/src/mumble/UserModel.cpp @@ -1019,6 +1019,7 @@ ClientUser *UserModel::addUser(unsigned int id, const QString &name) { connect(p, SIGNAL(prioritySpeakerStateChanged()), this, SLOT(userStateChanged())); connect(p, SIGNAL(recordingStateChanged()), this, SLOT(userStateChanged())); connect(p, &ClientUser::localVolumeAdjustmentsChanged, this, &UserModel::userStateChanged); + connect(p, &ClientUser::localNicknameChanged, this, &UserModel::userStateChanged); Channel *c = Channel::get(0); ModelItem *citem = ModelItem::c_qhChannels.value(c); @@ -1959,18 +1960,30 @@ QString UserModel::createDisplayString(const ClientUser &user, bool isChannelLis friendTag = QString::fromLatin1("(%2)").arg(user.qsFriendName); } + // Create a nickname-tag + QString nickname = user.getLocalNickname(); + // Create a tag that indicates the volume adjustments QString volumeTag; if (std::abs(localVolumeDecibel) > 0 && g.s.bShowVolumeAdjustments) { volumeTag = QString::asprintf("|%+d|", localVolumeDecibel); } - QString displayString = user.qsName; + QString displayString; + if (!g.s.bShowNicknamesOnly || nickname.isEmpty()) { + displayString += user.qsName; + } else { + displayString += nickname; + } if (!friendTag.isEmpty()) { displayString += " " + friendTag; } + if (!g.s.bShowNicknamesOnly && !nickname.isEmpty() && user.qsName.compare(nickname, Qt::CaseInsensitive) != 0) { + displayString += " " + QString::fromLatin1("[%1]").arg(nickname); + } + if (!volumeTag.isEmpty()) { displayString += " " + volumeTag; } From 43030fba5c6050774f0888a6a6564c0a2a2dadf5 Mon Sep 17 00:00:00 2001 From: tandunn Date: Sat, 19 Dec 2020 14:50:00 -0500 Subject: [PATCH 2/2] TRANSLATION: Update translation files Scanning directory './src'... Scanning directory './src/mumble'... Updating 'src/mumble/mumble_en.ts'... Found 1920 source text(s) (10 new and 1910 already existing) --- src/mumble/mumble_en.ts | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/mumble/mumble_en.ts b/src/mumble/mumble_en.ts index bf0fc6fea..18e63d454 100644 --- a/src/mumble/mumble_en.ts +++ b/src/mumble/mumble_en.ts @@ -4298,6 +4298,14 @@ The setting only applies for new messages, the already shown ones will retain th Show local user's listeners (ears) + + Hide the username for each user if they have a nickname. + + + + Show nicknames only + + MainWindow @@ -6138,6 +6146,18 @@ Valid options are: Global Shortcut + + &Set Nickname... + + + + Set a local nickname + + + + Sets a local nickname for another user. + + Manual @@ -7129,6 +7149,10 @@ See <a href="https://wiki.mumble.info/wiki/Installing_Mumble">th Do you really want to reset all settings (not only the ones currently visible) to their default value? + + Local Nickname Adjustment... + + RichTextEditor @@ -7664,6 +7688,25 @@ An access token is a text string, which can be used as a password for very simpl + + UserLocalNicknameDialog + + Local nickname for other users + + + + <b>Adjust the nickname of other users locally</b><br /> + + + + User nickname + + + + Adjusting local nickname for %1 + + + UserLocalVolumeDialog