Skip to content

Commit

Permalink
Merge PR #5923: Channel filter improvements
Browse files Browse the repository at this point in the history
Closes #1737
Closes #1830

This MR contains two changes:

    Add the "Channel Filter" toggle action to the menu bar especially for use in the minimal view as specified in 

Missing context menu entry to toggle channel filtering in minimal view. #1737
Implement a "channel pin" flag as specified by
Show channel when filtering #1830. I was almost done when I realized that @hacst already had a merge request going some time ago... (Add 'always visible' channels to filtering mechanism #2612) We implemented this in a very similar way and I added them as a co-author.
  • Loading branch information
Krzmbrzl authored Nov 27, 2022
2 parents e2debec + eb6ef5a commit 9c33451
Show file tree
Hide file tree
Showing 59 changed files with 788 additions and 280 deletions.
90 changes: 87 additions & 3 deletions src/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@
#include <QtCore/QStack>

#ifdef MUMBLE
# include <queue>
# include "PluginManager.h"
# include "Global.h"
# include "Database.h"
# include "ServerHandler.h"

QHash< int, Channel * > Channel::c_qhChannels;
QReadWriteLock Channel::c_qrwlChannels;
Expand All @@ -30,11 +33,11 @@ Channel::Channel(int id, const QString &name, QObject *p) : QObject(p) {
cParent->addChannel(this);
#ifdef MUMBLE
uiPermissions = 0;
bFiltered = false;
m_filterMode = ChannelFilterMode::NORMAL;

hasEnterRestrictions.store(false);
localUserCanEnter.store(true);
#endif
#endif // MUMBLE
}

Channel::~Channel() {
Expand Down Expand Up @@ -84,7 +87,88 @@ void Channel::remove(Channel *c) {
QWriteLocker lock(&c_qrwlChannels);
c_qhChannels.remove(c->iId);
}
#endif

void Channel::setFilterMode(ChannelFilterMode filterMode) {
m_filterMode = filterMode;
ServerHandlerPtr sh = Global::get().sh;
if (sh) {
Global::get().db->setChannelFilterMode(sh->qbaDigest, iId, m_filterMode);
}
}

void Channel::clearFilterMode() {
if (m_filterMode != ChannelFilterMode::NORMAL) {
setFilterMode(ChannelFilterMode::NORMAL);
}
}

bool Channel::isFiltered() const {
if (!Global::get().s.bFilterActive) {
// Channel filtering is disabled
return false;
}

const Channel *userChannel = nullptr;

if (Global::get().uiSession != 0) {
const ClientUser *user = ClientUser::get(Global::get().uiSession);
if (user) {
userChannel = user->cChannel;
}
}

bool hasUser = false;
bool hasHide = false;
bool hasPin = false;

// Iterate tree down
std::queue< const Channel * > channelSearch;
channelSearch.push(this);

while (!channelSearch.empty()) {
const Channel *c = channelSearch.front();
channelSearch.pop();

// Never hide channel, if user resides in this channel or a subchannel
if (userChannel && c == userChannel) {
return false;
}

if (c->m_filterMode == ChannelFilterMode::PIN) {
hasPin = true;
}

if (!c->qlUsers.isEmpty()) {
hasUser = true;
}

for (const Channel *currentSubChannel : c->qlChannels) {
channelSearch.push(currentSubChannel);
}
}

// Iterate tree up
const Channel *c = this;
while (c) {
if (c->m_filterMode == ChannelFilterMode::HIDE) {
hasHide = true;
break;
}
c = c->cParent;
}

if (hasPin) {
return false;
}

if (hasHide) {
return true;
}

return Global::get().s.bFilterHidesEmptyChannels && !hasUser;
}

#endif // MUMBLE

bool Channel::lessThan(const Channel *first, const Channel *second) {
if ((first->iPosition != second->iPosition) && (first->cParent == second->cParent))
Expand Down
8 changes: 7 additions & 1 deletion src/Channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#ifdef MUMBLE
# include <atomic>
# include "ChannelFilterMode.h"
#endif

class User;
Expand Down Expand Up @@ -71,7 +72,12 @@ class Channel : public QObject {

#ifdef MUMBLE
unsigned int uiPermissions;
bool bFiltered;

ChannelFilterMode m_filterMode;

void setFilterMode(ChannelFilterMode filterMode);
void clearFilterMode();
bool isFiltered() const;

static QHash< int, Channel * > c_qhChannels;
static QReadWriteLock c_qrwlChannels;
Expand Down
1 change: 1 addition & 0 deletions src/mumble/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ set(MUMBLE_SOURCES
"Cert.cpp"
"Cert.h"
"Cert.ui"
"ChannelFilterMode.h"
"ClientUser.cpp"
"ClientUser.h"
"ConfigDialog.cpp"
Expand Down
21 changes: 21 additions & 0 deletions src/mumble/ChannelFilterMode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2022 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 <https://www.mumble.info/LICENSE>.

#ifndef MUMBLE_CHANNELFILTERMODE_H_
#define MUMBLE_CHANNELFILTERMODE_H_

/// Visibility modifiers used when applying the channel filter
/// The channel the user is in will be always visible
/// This enum is used in the client DB, only append new entries
enum class ChannelFilterMode {
/// The default channel filtering behavior
NORMAL,
/// Channel is filtered, if the channel filter is active
HIDE,
/// Channel is not filtered, even if it is empty
PIN
};

#endif
38 changes: 26 additions & 12 deletions src/mumble/Database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ Database::Database(const QString &dbname) {
"`server_cert_digest` TEXT NOT NULL, `channel_id` INTEGER NOT NULL)"));
execQueryAndLogFailure(query, QLatin1String("CREATE UNIQUE INDEX IF NOT EXISTS `filtered_channels_entry` ON "
"`filtered_channels`(`server_cert_digest`, `channel_id`)"));
query.exec(QLatin1String("ALTER TABLE `filtered_channels` ADD COLUMN `filter_mode` INTEGER DEFAULT ")
+ QString::number(
static_cast< int >(ChannelFilterMode::HIDE))); // Upgrade path, failing this query is not noteworthy

execQueryAndLogFailure(query, QLatin1String("CREATE TABLE IF NOT EXISTS `pingcache` (`id` INTEGER PRIMARY KEY "
"AUTOINCREMENT, `hostname` TEXT, `port` INTEGER, `ping` INTEGER)"));
Expand Down Expand Up @@ -396,30 +399,41 @@ void Database::setLocalMuted(const QString &hash, bool muted) {
execQueryAndLogFailure(query);
}

bool Database::isChannelFiltered(const QByteArray &server_cert_digest, const int channel_id) {
ChannelFilterMode Database::getChannelFilterMode(const QByteArray &server_cert_digest, const int channel_id) {
QSqlQuery query(db);

query.prepare(QLatin1String(
"SELECT `channel_id` FROM `filtered_channels` WHERE `server_cert_digest` = ? AND `channel_id` = ?"));
"SELECT `filter_mode` FROM `filtered_channels` WHERE `server_cert_digest` = ? AND `channel_id` = ?"));
query.addBindValue(server_cert_digest);
query.addBindValue(channel_id);
execQueryAndLogFailure(query);

return query.next();
if (query.first()) {
return static_cast< ChannelFilterMode >(query.value(0).toInt());
}

return ChannelFilterMode::NORMAL;
}

void Database::setChannelFiltered(const QByteArray &server_cert_digest, const int channel_id, const bool hidden) {
void Database::setChannelFilterMode(const QByteArray &server_cert_digest, const int channel_id,
const ChannelFilterMode filterMode) {
QSqlQuery query(db);

if (hidden)
query.prepare(
QLatin1String("INSERT INTO `filtered_channels` (`server_cert_digest`, `channel_id`) VALUES (?, ?)"));
else
query.prepare(
QLatin1String("DELETE FROM `filtered_channels` WHERE `server_cert_digest` = ? AND `channel_id` = ?"));
switch (filterMode) {
case ChannelFilterMode::NORMAL:
query.prepare(
QLatin1String("DELETE FROM `filtered_channels` WHERE `server_cert_digest` = ? AND `channel_id` = ?"));
break;
case ChannelFilterMode::PIN:
case ChannelFilterMode::HIDE:
query.prepare(QLatin1String("INSERT OR REPLACE INTO `filtered_channels` (`server_cert_digest`, "
"`channel_id`, `filter_mode`) VALUES (?, ?, ?)"));
query.bindValue(2, static_cast< int >(filterMode));
break;
}

query.addBindValue(server_cert_digest);
query.addBindValue(channel_id);
query.bindValue(0, server_cert_digest);
query.bindValue(1, channel_id);

execQueryAndLogFailure(query);
}
Expand Down
5 changes: 3 additions & 2 deletions src/mumble/Database.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#ifndef MUMBLE_MUMBLE_DATABASE_H_
#define MUMBLE_MUMBLE_DATABASE_H_

#include "Channel.h"
#include "Settings.h"
#include "UnresolvedServerAddress.h"
#include <QSqlDatabase>
Expand Down Expand Up @@ -54,8 +55,8 @@ class Database : public QObject {
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);
ChannelFilterMode getChannelFilterMode(const QByteArray &server_cert_digest, int channel_id);
void setChannelFilterMode(const QByteArray &server_cert_digest, int channel_id, ChannelFilterMode filterMode);

QMap< UnresolvedServerAddress, unsigned int > getPingCache();
void setPingCache(const QMap< UnresolvedServerAddress, unsigned int > &cache);
Expand Down
38 changes: 31 additions & 7 deletions src/mumble/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ void MainWindow::updateTrayIcon() {

void MainWindow::updateUserModel() {
UserModel *um = static_cast< UserModel * >(qtvUsers->model());
um->toggleChannelFiltered(nullptr); // Force a UI refresh
um->forceVisualUpdate();
}

void MainWindow::updateTransmitModeComboBox(Settings::AudioTransmit newMode) {
Expand Down Expand Up @@ -2219,6 +2219,7 @@ void MainWindow::on_qmConfig_aboutToShow() {
qmConfig->addAction(qaAudioTTS);
qmConfig->addSeparator();
qmConfig->addAction(qaConfigMinimal);
qmConfig->addAction(qaFilterToggle);

qaTalkingUIToggle->setChecked(Global::get().talkingUI && Global::get().talkingUI->isVisible());

Expand Down Expand Up @@ -2261,7 +2262,8 @@ void MainWindow::qmChannel_aboutToShow() {
// hiding the root is nonsense
if (c && c->cParent) {
qmChannel->addSeparator();
qmChannel->addAction(qaChannelFilter);
qmChannel->addAction(qaChannelHide);
qmChannel->addAction(qaChannelPin);
}

#ifndef Q_OS_MAC
Expand Down Expand Up @@ -2304,8 +2306,10 @@ void MainWindow::qmChannel_aboutToShow() {
}
}

if (c)
qaChannelFilter->setChecked(c->bFiltered);
if (c) {
qaChannelHide->setChecked(c->m_filterMode == ChannelFilterMode::HIDE);
qaChannelPin->setChecked(c->m_filterMode == ChannelFilterMode::PIN);
}

qaChannelAdd->setEnabled(add);
qaChannelRemove->setEnabled(remove);
Expand Down Expand Up @@ -2349,12 +2353,31 @@ void MainWindow::on_qaChannelListen_triggered() {
}
}

void MainWindow::on_qaChannelFilter_triggered() {
void MainWindow::on_qaChannelHide_triggered() {
Channel *c = getContextMenuChannel();

if (c) {
UserModel *um = static_cast< UserModel * >(qtvUsers->model());
if (qaChannelHide->isChecked()) {
c->setFilterMode(ChannelFilterMode::HIDE);
} else {
c->setFilterMode(ChannelFilterMode::NORMAL);
}
um->forceVisualUpdate(c);
}
}

void MainWindow::on_qaChannelPin_triggered() {
Channel *c = getContextMenuChannel();

if (c) {
UserModel *um = static_cast< UserModel * >(qtvUsers->model());
um->toggleChannelFiltered(c);
if (qaChannelPin->isChecked()) {
c->setFilterMode(ChannelFilterMode::PIN);
} else {
c->setFilterMode(ChannelFilterMode::NORMAL);
}
um->forceVisualUpdate(c);
}
}

Expand Down Expand Up @@ -2575,7 +2598,8 @@ void MainWindow::updateMenuPermissions() {
qaChannelUnlinkAll->setEnabled(p & (ChanACL::Write | ChanACL::LinkChannel));
qaChannelCopyURL->setEnabled(target.channel);
qaChannelSendMessage->setEnabled(p & (ChanACL::Write | ChanACL::TextMessage));
qaChannelFilter->setEnabled(true);
qaChannelHide->setEnabled(target.channel);
qaChannelPin->setEnabled(target.channel);

bool chatBarEnabled = false;
if (Global::get().uiSession) {
Expand Down
3 changes: 2 additions & 1 deletion src/mumble/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ public slots:
void on_qaChannelUnlink_triggered();
void on_qaChannelUnlinkAll_triggered();
void on_qaChannelSendMessage_triggered();
void on_qaChannelFilter_triggered();
void on_qaChannelHide_triggered();
void on_qaChannelPin_triggered();
void on_qaChannelCopyURL_triggered();
void on_qaAudioReset_triggered();
void on_qaAudioMute_triggered();
Expand Down
12 changes: 10 additions & 2 deletions src/mumble/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,7 @@
<activeon>skin:filter_on.svg</activeon>skin:filter_off.svg</iconset>
</property>
<property name="text">
<string>&amp;Filter on/off</string>
<string>Channel &amp;Filter</string>
</property>
<property name="toolTip">
<string>Toggle the channel filter (Alt+F)</string>
Expand Down Expand Up @@ -897,14 +897,22 @@ the channel's context menu.</string>
<string>&amp;Join Channel</string>
</property>
</action>
<action name="qaChannelFilter">
<action name="qaChannelHide">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Hide Channel when Filtering</string>
</property>
</action>
<action name="qaChannelPin">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Pin Channel when Filtering</string>
</property>
</action>
<action name="qaUserCommentView">
<property name="text">
<string>View Comment...</string>
Expand Down
Loading

0 comments on commit 9c33451

Please sign in to comment.