diff --git a/src/mumble/ClientUser.cpp b/src/mumble/ClientUser.cpp index c5b7141b1..c296031a0 100644 --- a/src/mumble/ClientUser.cpp +++ b/src/mumble/ClientUser.cpp @@ -19,6 +19,7 @@ ClientUser::ClientUser(QObject *p) : QObject(p), tsState(Settings::Passive), tLastTalkStateChange(false), bLocalIgnore(false), + bLocalIgnoreTTS(false), bLocalMute(false), fPowerMin(0.0f), fPowerMax(0.0f), @@ -134,6 +135,8 @@ QString ClientUser::getFlagsString() const { flags << ClientUser::tr("Deafened (server)"); if (bLocalIgnore) flags << ClientUser::tr("Local Ignore (Text messages)"); + if (bLocalIgnoreTTS) + flags << ClientUser::tr("Local Ignore (Text-To-Speech)"); if (bLocalMute) flags << ClientUser::tr("Local Mute"); if (bSelfMute) @@ -190,6 +193,10 @@ void ClientUser::setLocalIgnore(bool ignore) { emit muteDeafStateChanged(); } +void ClientUser::setLocalIgnoreTTS(bool ignoreTTS) { + bLocalIgnoreTTS = ignoreTTS; +} + void ClientUser::setLocalMute(bool mute) { if (bLocalMute == mute) return; diff --git a/src/mumble/ClientUser.h b/src/mumble/ClientUser.h index 8089c773f..121ed3aef 100644 --- a/src/mumble/ClientUser.h +++ b/src/mumble/ClientUser.h @@ -21,6 +21,7 @@ class ClientUser : public QObject, public User { Settings::TalkState tsState; Timer tLastTalkStateChange; bool bLocalIgnore; + bool bLocalIgnoreTTS; bool bLocalMute; float fPowerMin, fPowerMax; @@ -67,6 +68,7 @@ class ClientUser : public QObject, public User { void setDeaf(bool deaf); void setSuppress(bool suppress); void setLocalIgnore(bool ignore); + void setLocalIgnoreTTS(bool ignoreTTS); void setLocalMute(bool mute); void setSelfMute(bool mute); void setSelfDeaf(bool deaf); diff --git a/src/mumble/Database.cpp b/src/mumble/Database.cpp index 408e11efb..89eb5bc90 100644 --- a/src/mumble/Database.cpp +++ b/src/mumble/Database.cpp @@ -137,6 +137,9 @@ Database::Database(const QString &dbname) { execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `ignored` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT)")); execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `ignored_hash` ON `ignored`(`hash`)")); + execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `ignored_tts` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT)")); + execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `ignored_tts_hash` ON `ignored_tts`(`hash`)")); + execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `muted` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT)")); execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `muted_hash` ON `muted`(`hash`)")); execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `volume` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `hash` TEXT, `volume` FLOAT)")); @@ -238,6 +241,26 @@ void Database::setLocalIgnored(const QString &hash, bool ignored) { execQueryAndLogFailure(query); } +bool Database::isLocalIgnoredTTS(const QString &hash) { + QSqlQuery query(db); + + query.prepare(QLatin1String("SELECT `hash` FROM `ignored_tts` WHERE `hash` = ?")); + query.addBindValue(hash); + execQueryAndLogFailure(query); + return query.next(); +} + +void Database::setLocalIgnoredTTS(const QString &hash, bool ignoredTTS) { + QSqlQuery query(db); + + if (ignoredTTS) + query.prepare(QLatin1String("INSERT INTO `ignored_tts` (`hash`) VALUES (?)")); + else + query.prepare(QLatin1String("DELETE FROM `ignored_tts` WHERE `hash` = ?")); + query.addBindValue(hash); + execQueryAndLogFailure(query); +} + bool Database::isLocalMuted(const QString &hash) { QSqlQuery query(db); diff --git a/src/mumble/Database.h b/src/mumble/Database.h index abb51a1c2..3e626c044 100644 --- a/src/mumble/Database.h +++ b/src/mumble/Database.h @@ -37,6 +37,9 @@ class Database : public QObject { bool isLocalIgnored(const QString &hash); void setLocalIgnored(const QString &hash, bool ignored); + bool isLocalIgnoredTTS(const QString &hash); + void setLocalIgnoredTTS(const QString &hash, bool ignoredTTS); + bool isLocalMuted(const QString &hash); void setLocalMuted(const QString &hash, bool muted); diff --git a/src/mumble/Log.cpp b/src/mumble/Log.cpp index be7b2429e..7a6517439 100644 --- a/src/mumble/Log.cpp +++ b/src/mumble/Log.cpp @@ -324,15 +324,15 @@ QString Log::formatChannel(::Channel *c) { return QString::fromLatin1("%2").arg(c->iId).arg(c->qsName.toHtmlEscaped()).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64())); } -void Log::logOrDefer(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS) { +void Log::logOrDefer(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS, bool ignoreTTS) { if (g.l) { // log directly as it seems the log-UI has been set-up already - g.l->log(mt, console, terse, ownMessage, overrideTTS); + g.l->log(mt, console, terse, ownMessage, overrideTTS, ignoreTTS); } else { // defer the log QMutexLocker mLock(&Log::qmDeferredLogs); - qvDeferredLogs.append(LogMessage(mt, console, terse, ownMessage, overrideTTS)); + qvDeferredLogs.append(LogMessage(mt, console, terse, ownMessage, overrideTTS, ignoreTTS)); } } @@ -494,7 +494,7 @@ QString Log::validHtml(const QString &html, QTextCursor *tc) { } } -void Log::log(MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS) { +void Log::log(MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS, bool ignoreTTS) { QDateTime dt = QDateTime::currentDateTime(); int ignore = qmIgnore.value(mt); @@ -601,7 +601,7 @@ void Log::log(MsgType mt, const QString &console, const QString &terse, bool own } // Message notification with Text-To-Speech - if (g.s.bDeaf || !g.s.bTTS || !(flags & Settings::LogTTS)) { + if (g.s.bDeaf || !g.s.bTTS || !(flags & Settings::LogTTS) || ignoreTTS) { return; } @@ -658,7 +658,7 @@ void Log::processDeferredLogs() { while (!qvDeferredLogs.isEmpty()) { LogMessage msg = qvDeferredLogs.takeFirst(); - log(msg.mt, msg.console, msg.terse, msg.ownMessage, msg.overrideTTS); + log(msg.mt, msg.console, msg.terse, msg.ownMessage, msg.overrideTTS, msg.ignoreTTS); } } @@ -682,8 +682,8 @@ void Log::postQtNotification(MsgType mt, const QString &plain) { } } -LogMessage::LogMessage(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS) : mt(mt), console(console), - terse(terse), ownMessage(ownMessage), overrideTTS(overrideTTS) { +LogMessage::LogMessage(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS, bool ignoreTTS) : mt(mt), console(console), + terse(terse), ownMessage(ownMessage), overrideTTS(overrideTTS), ignoreTTS(ignoreTTS) { } LogDocument::LogDocument(QObject *p) diff --git a/src/mumble/Log.h b/src/mumble/Log.h index 46814927e..cbd83190d 100644 --- a/src/mumble/Log.h +++ b/src/mumble/Log.h @@ -90,9 +90,9 @@ class Log : public QObject { static QString formatChannel(::Channel *c); /// Either defers the LogMessage or defers it, depending on whether Global::l is created already /// (if it is, it is used to directly log the msg) - static void logOrDefer(Log::MsgType mt, const QString &console, const QString &terse=QString(), bool ownMessage = false, const QString &overrideTTS=QString()); + static void logOrDefer(Log::MsgType mt, const QString &console, const QString &terse=QString(), bool ownMessage = false, const QString &overrideTTS=QString(), bool ignoreTTS = false); public slots: - void log(MsgType mt, const QString &console, const QString &terse=QString(), bool ownMessage = false, const QString &overrideTTS=QString()); + void log(MsgType mt, const QString &console, const QString &terse=QString(), bool ownMessage = false, const QString &overrideTTS=QString(), bool ignoreTTS = false); /// Logs LogMessages that have been deferred so far void processDeferredLogs(); }; @@ -104,9 +104,10 @@ class LogMessage { QString terse; bool ownMessage; QString overrideTTS; + bool ignoreTTS; LogMessage() = default; - LogMessage(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS); + LogMessage(Log::MsgType mt, const QString &console, const QString &terse, bool ownMessage, const QString &overrideTTS, bool ignoreTTS); }; class LogDocument : public QTextDocument { diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp index a9cb3d015..815d8003c 100644 --- a/src/mumble/MainWindow.cpp +++ b/src/mumble/MainWindow.cpp @@ -1526,6 +1526,8 @@ void MainWindow::qmUser_aboutToShow() { qmUser->addAction(qaUserPrioritySpeaker); qmUser->addAction(qaUserLocalMute); qmUser->addAction(qaUserLocalIgnore); + if (g.s.bTTS) + qmUser->addAction(qaUserLocalIgnoreTTS); qmUser->addAction(qaUserLocalVolume); if (isSelf) @@ -1585,6 +1587,7 @@ void MainWindow::qmUser_aboutToShow() { qaUserLocalMute->setEnabled(false); qaUserLocalVolume->setEnabled(false); qaUserLocalIgnore->setEnabled(false); + qaUserLocalIgnoreTTS->setEnabled(false); qaUserCommentReset->setEnabled(false); qaUserTextureReset->setEnabled(false); qaUserCommentView->setEnabled(false); @@ -1595,6 +1598,7 @@ void MainWindow::qmUser_aboutToShow() { qaUserLocalMute->setEnabled(! isSelf); qaUserLocalVolume->setEnabled(! isSelf); qaUserLocalIgnore->setEnabled(! isSelf); + qaUserLocalIgnoreTTS->setEnabled(! isSelf); // If the server's version is less than 1.4.0 it won't support the new permission to reset a comment/avatar, so fall back to the old method if (g.sh->uiVersion < 0x010400) { qaUserCommentReset->setEnabled(! p->qbaCommentHash.isEmpty() && (g.pPermissions & (ChanACL::Move | ChanACL::Write))); @@ -1610,6 +1614,7 @@ void MainWindow::qmUser_aboutToShow() { qaUserPrioritySpeaker->setChecked(p->bPrioritySpeaker); qaUserLocalMute->setChecked(p->bLocalMute); qaUserLocalIgnore->setChecked(p->bLocalIgnore); + qaUserLocalIgnoreTTS->setChecked(p->bLocalIgnoreTTS); } updateMenuPermissions(); } @@ -1690,6 +1695,18 @@ void MainWindow::on_qaUserLocalIgnore_triggered() { g.db->setLocalIgnored(p->qsHash, ignored); } +void MainWindow::on_qaUserLocalIgnoreTTS_triggered() { + ClientUser *p = getContextMenuUser(); + if (!p) + return; + + bool ignoredTTS = qaUserLocalIgnoreTTS->isChecked(); + + p->setLocalIgnoreTTS(ignoredTTS); + if (! p->qsHash.isEmpty()) + g.db->setLocalIgnoredTTS(p->qsHash, ignoredTTS); +} + void MainWindow::on_qaUserLocalVolume_triggered() { ClientUser *p = getContextMenuUser(); if (!p) { diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h index 51060e90c..41e5f6efe 100644 --- a/src/mumble/MainWindow.h +++ b/src/mumble/MainWindow.h @@ -206,6 +206,7 @@ class MainWindow : public QMainWindow, public MessageHandler, public Ui::MainWin void on_qaSelfPrioritySpeaker_triggered(); void on_qaUserPrioritySpeaker_triggered(); void on_qaUserLocalIgnore_triggered(); + void on_qaUserLocalIgnoreTTS_triggered(); void on_qaUserLocalMute_triggered(); void on_qaUserLocalVolume_triggered(); void on_qaUserTextMessage_triggered(); diff --git a/src/mumble/MainWindow.ui b/src/mumble/MainWindow.ui index ed2f28f96..e5891e264 100644 --- a/src/mumble/MainWindow.ui +++ b/src/mumble/MainWindow.ui @@ -955,6 +955,20 @@ the channel's context menu. Joins the channel of this user. + + + true + + + Disable Text-To-Speech + + + Locally disable Text-To-Speech for this user's text chat messages. + + + Silently disables Text-To-Speech for all text messages from the user. + + diff --git a/src/mumble/Messages.cpp b/src/mumble/Messages.cpp index dd9c45fe9..df134144f 100644 --- a/src/mumble/Messages.cpp +++ b/src/mumble/Messages.cpp @@ -504,6 +504,8 @@ void MainWindow::msgUserState(const MumbleProto::UserState &msg) { pDst->setLocalMute(true); if (g.db->isLocalIgnored(pDst->qsHash)) pDst->setLocalIgnore(true); + if (g.db->isLocalIgnoredTTS(pDst->qsHash)) + pDst->setLocalIgnoreTTS(true); pDst->fLocalVolume = g.db->getUserLocalVolume(pDst->qsHash); } @@ -909,7 +911,8 @@ void MainWindow::msgTextMessage(const MumbleProto::TextMessage &msg) { tr("%2%1: %3").arg(name).arg(target).arg(u8(msg.message())), tr("Message from %1").arg(plainName), false, - overrideTTS.isNull() ? QString() : overrideTTS); + overrideTTS.isNull() ? QString() : overrideTTS, + pSrc->bLocalIgnoreTTS); } /// This message is being received when the server informs the client about the access control list (ACL) for