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;
}