Refactor highlight blacklist to use the model system

Fix #560
This commit is contained in:
Rasmus Karlsson 2018-07-04 11:22:27 +00:00
parent 362dcb88bc
commit 03b7fae09e
9 changed files with 212 additions and 16 deletions

View file

@ -112,6 +112,7 @@ SOURCES += \
src/controllers/commands/CommandModel.cpp \ src/controllers/commands/CommandModel.cpp \
src/controllers/highlights/HighlightController.cpp \ src/controllers/highlights/HighlightController.cpp \
src/controllers/highlights/HighlightModel.cpp \ src/controllers/highlights/HighlightModel.cpp \
src/controllers/highlights/HighlightBlacklistModel.cpp \
src/controllers/ignores/IgnoreController.cpp \ src/controllers/ignores/IgnoreController.cpp \
src/controllers/ignores/IgnoreModel.cpp \ src/controllers/ignores/IgnoreModel.cpp \
src/controllers/taggedusers/TaggedUser.cpp \ src/controllers/taggedusers/TaggedUser.cpp \
@ -254,7 +255,9 @@ HEADERS += \
src/controllers/commands/CommandModel.hpp \ src/controllers/commands/CommandModel.hpp \
src/controllers/highlights/HighlightController.hpp \ src/controllers/highlights/HighlightController.hpp \
src/controllers/highlights/HighlightModel.hpp \ src/controllers/highlights/HighlightModel.hpp \
src/controllers/highlights/HighlightBlacklistModel.hpp \
src/controllers/highlights/HighlightPhrase.hpp \ src/controllers/highlights/HighlightPhrase.hpp \
src/controllers/highlights/HighlightBlacklistUser.hpp \
src/controllers/ignores/IgnoreController.hpp \ src/controllers/ignores/IgnoreController.hpp \
src/controllers/ignores/IgnoreModel.hpp \ src/controllers/ignores/IgnoreModel.hpp \
src/controllers/ignores/IgnorePhrase.hpp \ src/controllers/ignores/IgnorePhrase.hpp \

View file

@ -0,0 +1,33 @@
#include "controllers/highlights/HighlightBlacklistModel.hpp"
#include "Application.hpp"
#include "singletons/Settings.hpp"
#include "util/StandardItemHelper.hpp"
namespace chatterino {
// commandmodel
HighlightBlacklistModel::HighlightBlacklistModel(QObject *parent)
: SignalVectorModel<HighlightBlacklistUser>(2, parent)
{
}
// turn a vector item into a model row
HighlightBlacklistUser HighlightBlacklistModel::getItemFromRow(
std::vector<QStandardItem *> &row, const HighlightBlacklistUser &original)
{
// key, regex
return HighlightBlacklistUser{row[0]->data(Qt::DisplayRole).toString(),
row[1]->data(Qt::CheckStateRole).toBool()};
}
// turns a row in the model into a vector item
void HighlightBlacklistModel::getRowFromItem(const HighlightBlacklistUser &item,
std::vector<QStandardItem *> &row)
{
setStringItem(row[0], item.getPattern());
setBoolItem(row[1], item.isRegex());
}
} // namespace chatterino

View file

@ -0,0 +1,28 @@
#pragma once
#include <QObject>
#include "common/SignalVectorModel.hpp"
#include "controllers/highlights/HighlightBlacklistUser.hpp"
namespace chatterino {
class HighlightController;
class HighlightBlacklistModel : public SignalVectorModel<HighlightBlacklistUser>
{
explicit HighlightBlacklistModel(QObject *parent);
protected:
// turn a vector item into a model row
virtual HighlightBlacklistUser getItemFromRow(std::vector<QStandardItem *> &row,
const HighlightBlacklistUser &original) override;
// turns a row in the model into a vector item
virtual void getRowFromItem(const HighlightBlacklistUser &item,
std::vector<QStandardItem *> &row) override;
friend class HighlightController;
};
} // namespace chatterino

View file

@ -0,0 +1,101 @@
#pragma once
#include "common/SerializeCustom.hpp"
#include "util/RapidjsonHelpers.hpp"
#include <QRegularExpression>
#include <QString>
#include <pajlada/settings/serialize.hpp>
#include <memory>
namespace chatterino {
class HighlightBlacklistUser
{
QString pattern_;
bool isRegex_;
QRegularExpression regex_;
public:
bool operator==(const HighlightBlacklistUser &other) const
{
return std::tie(this->pattern_, this->isRegex_) == std::tie(other.pattern_, other.isRegex_);
}
HighlightBlacklistUser(const QString &pattern, bool isRegex = false)
: pattern_(pattern)
, isRegex_(isRegex)
, regex_(isRegex ? pattern : "", QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption)
{
}
const QString &getPattern() const
{
return this->pattern_;
}
bool isRegex() const
{
return this->isRegex_;
}
bool isValidRegex() const
{
return this->isRegex() && this->regex_.isValid();
}
bool isMatch(const QString &subject) const
{
if (this->isRegex()) {
if (this->isValidRegex()) {
return this->regex_.match(subject).hasMatch();
}
return false;
}
return subject.toLower() == this->pattern_.toLower();
}
};
} // namespace chatterino
namespace pajlada {
namespace Settings {
template <>
struct Serialize<chatterino::HighlightBlacklistUser> {
static rapidjson::Value get(const chatterino::HighlightBlacklistUser &value,
rapidjson::Document::AllocatorType &a)
{
rapidjson::Value ret(rapidjson::kObjectType);
AddMember(ret, "pattern", value.getPattern(), a);
AddMember(ret, "regex", value.isRegex(), a);
return ret;
}
};
template <>
struct Deserialize<chatterino::HighlightBlacklistUser> {
static chatterino::HighlightBlacklistUser get(const rapidjson::Value &value)
{
QString pattern;
bool isRegex = false;
if (!value.IsObject()) {
return chatterino::HighlightBlacklistUser(pattern, isRegex);
}
chatterino::rj::getSafe(value, "pattern", pattern);
chatterino::rj::getSafe(value, "regex", isRegex);
return chatterino::HighlightBlacklistUser(pattern, isRegex);
}
};
} // namespace Settings
} // namespace pajlada

View file

@ -1,6 +1,7 @@
#include "HighlightController.hpp" #include "HighlightController.hpp"
#include "Application.hpp" #include "Application.hpp"
#include "controllers/highlights/HighlightBlacklistModel.hpp"
#include "controllers/highlights/HighlightModel.hpp" #include "controllers/highlights/HighlightModel.hpp"
#include "widgets/dialogs/NotificationPopup.hpp" #include "widgets/dialogs/NotificationPopup.hpp"
@ -32,6 +33,26 @@ HighlightModel *HighlightController::createModel(QObject *parent)
return model; return model;
} }
HighlightBlacklistModel *HighlightController::createBlacklistModel(QObject *parent)
{
auto *model = new HighlightBlacklistModel(parent);
model->init(&this->blacklistedUsers);
return model;
}
bool HighlightController::blacklistContains(const QString &username)
{
std::vector<HighlightBlacklistUser> blacklistItems = this->blacklistedUsers.getVector();
for (const auto &blacklistedUser : blacklistItems) {
if (blacklistedUser.isMatch(username)) {
return true;
}
}
return false;
}
void HighlightController::addHighlight(const MessagePtr &msg) void HighlightController::addHighlight(const MessagePtr &msg)
{ {
// static NotificationPopup popup; // static NotificationPopup popup;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/SignalVector.hpp" #include "common/SignalVector.hpp"
#include "controllers/highlights/HighlightBlacklistUser.hpp"
#include "controllers/highlights/HighlightPhrase.hpp" #include "controllers/highlights/HighlightPhrase.hpp"
#include "messages/Message.hpp" #include "messages/Message.hpp"
#include "singletons/Settings.hpp" #include "singletons/Settings.hpp"
@ -8,6 +9,7 @@
namespace chatterino { namespace chatterino {
class HighlightModel; class HighlightModel;
class HighlightBlacklistModel;
class HighlightController class HighlightController
{ {
@ -17,8 +19,12 @@ public:
void initialize(); void initialize();
UnsortedSignalVector<HighlightPhrase> phrases; UnsortedSignalVector<HighlightPhrase> phrases;
UnsortedSignalVector<HighlightBlacklistUser> blacklistedUsers;
HighlightModel *createModel(QObject *parent); HighlightModel *createModel(QObject *parent);
HighlightBlacklistModel *createBlacklistModel(QObject *parent);
bool blacklistContains(const QString &username);
void addHighlight(const MessagePtr &msg); void addHighlight(const MessagePtr &msg);
@ -27,6 +33,7 @@ private:
ChatterinoSetting<std::vector<HighlightPhrase>> highlightsSetting = { ChatterinoSetting<std::vector<HighlightPhrase>> highlightsSetting = {
"/highlighting/highlights"}; "/highlighting/highlights"};
ChatterinoSetting<std::vector<HighlightPhrase>> blacklistSetting = {"/highlighting/blacklist"};
}; };
} // namespace chatterino } // namespace chatterino

View file

@ -440,9 +440,6 @@ void TwitchMessageBuilder::parseHighlights()
currentPlayerUrl = highlightSoundUrl; currentPlayerUrl = highlightSoundUrl;
} }
QStringList blackList =
app->settings->highlightUserBlacklist.getValue().split("\n", QString::SkipEmptyParts);
// TODO: This vector should only be rebuilt upon highlights being changed // TODO: This vector should only be rebuilt upon highlights being changed
// fourtf: should be implemented in the HighlightsController // fourtf: should be implemented in the HighlightsController
std::vector<HighlightPhrase> activeHighlights = app->highlights->phrases.getVector(); std::vector<HighlightPhrase> activeHighlights = app->highlights->phrases.getVector();
@ -459,7 +456,7 @@ void TwitchMessageBuilder::parseHighlights()
bool hasFocus = (QApplication::focusWidget() != nullptr); bool hasFocus = (QApplication::focusWidget() != nullptr);
if (!blackList.contains(this->ircMessage->nick(), Qt::CaseInsensitive)) { if (!app->highlights->blacklistContains(this->ircMessage->nick())) {
for (const HighlightPhrase &highlight : activeHighlights) { for (const HighlightPhrase &highlight : activeHighlights) {
if (highlight.isMatch(this->originalMessage)) { if (highlight.isMatch(this->originalMessage)) {
Log("Highlight because {} matches {}", this->originalMessage, Log("Highlight because {} matches {}", this->originalMessage,

View file

@ -102,7 +102,6 @@ public:
QStringSetting pathHighlightSound = {"/highlighting/highlightSoundPath", QStringSetting pathHighlightSound = {"/highlighting/highlightSoundPath",
"qrc:/sounds/ping2.wav"}; "qrc:/sounds/ping2.wav"};
QStringSetting highlightUserBlacklist = {"/highlighting/blacklistedUsers", ""};
BoolSetting highlightAlwaysPlaySound = {"/highlighting/alwaysPlaySound", false}; BoolSetting highlightAlwaysPlaySound = {"/highlighting/alwaysPlaySound", false};

View file

@ -1,6 +1,7 @@
#include "HighlightingPage.hpp" #include "HighlightingPage.hpp"
#include "Application.hpp" #include "Application.hpp"
#include "controllers/highlights/HighlightBlacklistModel.hpp"
#include "controllers/highlights/HighlightController.hpp" #include "controllers/highlights/HighlightController.hpp"
#include "controllers/highlights/HighlightModel.hpp" #include "controllers/highlights/HighlightModel.hpp"
#include "debug/Log.hpp" #include "debug/Log.hpp"
@ -63,22 +64,28 @@ HighlightingPage::HighlightingPage()
HighlightPhrase{"my phrase", true, false, false}); HighlightPhrase{"my phrase", true, false, false});
}); });
} }
auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users"); auto disabledUsers = tabs.appendTab(new QVBoxLayout, "Disabled Users");
{ {
auto text = disabledUsers.emplace<QTextEdit>().getElement(); EditableModelView *view =
disabledUsers
.emplace<EditableModelView>(app->highlights->createBlacklistModel(nullptr))
.getElement();
QObject::connect(text, &QTextEdit::textChanged, this, view->setTitles({"Pattern", "Regex"});
[this] { this->disabledUsersChangedTimer.start(200); }); view->getTableView()->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
view->getTableView()->horizontalHeader()->setSectionResizeMode(
0, QHeaderView::Stretch);
QObject::connect( // fourtf: make class extrend BaseWidget and add this to dpiChanged
&this->disabledUsersChangedTimer, &QTimer::timeout, this, [text, app]() { QTimer::singleShot(1, [view] {
QStringList list = text->toPlainText().split("\n", QString::SkipEmptyParts); view->getTableView()->resizeColumnsToContents();
list.removeDuplicates(); view->getTableView()->setColumnWidth(0, 200);
app->settings->highlightUserBlacklist = list.join("\n") + "\n";
}); });
app->settings->highlightUserBlacklist.connect([=](const QString &str, auto) { view->addButtonPressed.connect([] {
text->setPlainText(str); // getApp()->highlights->blacklistedUsers.appendItem(
HighlightBlacklistUser{"blacklisted user", false});
}); });
} }
} }