Fix signal connection nodiscard warnings (#4818)
This commit is contained in:
@@ -20,22 +20,23 @@ AccountSwitchWidget::AccountSwitchWidget(QWidget *parent)
|
||||
this->addItem(userName);
|
||||
}
|
||||
|
||||
app->accounts->twitch.userListUpdated.connect([=, this]() {
|
||||
this->blockSignals(true);
|
||||
this->managedConnections_.managedConnect(
|
||||
app->accounts->twitch.userListUpdated, [=, this]() {
|
||||
this->blockSignals(true);
|
||||
|
||||
this->clear();
|
||||
this->clear();
|
||||
|
||||
this->addItem(ANONYMOUS_USERNAME_LABEL);
|
||||
this->addItem(ANONYMOUS_USERNAME_LABEL);
|
||||
|
||||
for (const auto &userName : app->accounts->twitch.getUsernames())
|
||||
{
|
||||
this->addItem(userName);
|
||||
}
|
||||
for (const auto &userName : app->accounts->twitch.getUsernames())
|
||||
{
|
||||
this->addItem(userName);
|
||||
}
|
||||
|
||||
this->refreshSelection();
|
||||
this->refreshSelection();
|
||||
|
||||
this->blockSignals(false);
|
||||
});
|
||||
this->blockSignals(false);
|
||||
});
|
||||
|
||||
this->refreshSelection();
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "pajlada/signals/signalholder.hpp"
|
||||
|
||||
#include <QListWidget>
|
||||
|
||||
namespace chatterino {
|
||||
@@ -15,6 +17,8 @@ public:
|
||||
|
||||
private:
|
||||
void refreshSelection();
|
||||
|
||||
pajlada::Signals::SignalHolder managedConnections_;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
@@ -246,7 +246,9 @@ EmotePopup::EmotePopup(QWidget *parent)
|
||||
MessageElementFlag::Default, MessageElementFlag::AlwaysShow,
|
||||
MessageElementFlag::EmoteImages});
|
||||
view->setEnableScrollingToBottom(false);
|
||||
view->linkClicked.connect(clicked);
|
||||
// We can safely ignore this signal connection since the ChannelView is deleted
|
||||
// either when the notebook is deleted, or when our main layout is deleted.
|
||||
std::ignore = view->linkClicked.connect(clicked);
|
||||
|
||||
if (addToNotebook)
|
||||
{
|
||||
|
||||
@@ -84,9 +84,12 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||
this->ui_.threadView->setMinimumSize(400, 100);
|
||||
this->ui_.threadView->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
this->ui_.threadView->mouseDown.connect([this](QMouseEvent *) {
|
||||
this->giveFocus(Qt::MouseFocusReason);
|
||||
});
|
||||
// We can safely ignore this signal's connection since threadView will always be deleted before
|
||||
// the ReplyThreadPopup
|
||||
std::ignore =
|
||||
this->ui_.threadView->mouseDown.connect([this](QMouseEvent *) {
|
||||
this->giveFocus(Qt::MouseFocusReason);
|
||||
});
|
||||
|
||||
// Create SplitInput with inline replying disabled
|
||||
this->ui_.replyInput =
|
||||
@@ -97,8 +100,10 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||
this->updateInputUI();
|
||||
}));
|
||||
|
||||
// clear SplitInput selection when selecting in ChannelView
|
||||
this->ui_.threadView->selectionChanged.connect([this]() {
|
||||
// We can safely ignore this signal's connection since threadView will always be deleted before
|
||||
// the ReplyThreadPopup
|
||||
std::ignore = this->ui_.threadView->selectionChanged.connect([this]() {
|
||||
// clear SplitInput selection when selecting in ChannelView
|
||||
if (this->ui_.replyInput->hasSelection())
|
||||
{
|
||||
this->ui_.replyInput->clearSelection();
|
||||
@@ -106,7 +111,9 @@ ReplyThreadPopup::ReplyThreadPopup(bool closeAutomatically, QWidget *parent,
|
||||
});
|
||||
|
||||
// clear ChannelView selection when selecting in SplitInput
|
||||
this->ui_.replyInput->selectionChanged.connect([this]() {
|
||||
// We can safely ignore this signal's connection since replyInput will always be deleted before
|
||||
// the ReplyThreadPopup
|
||||
std::ignore = this->ui_.replyInput->selectionChanged.connect([this]() {
|
||||
if (this->ui_.threadView->hasSelection())
|
||||
{
|
||||
this->ui_.threadView->clearSelection();
|
||||
|
||||
@@ -170,7 +170,9 @@ SelectChannelDialog::SelectChannelDialog(QWidget *parent)
|
||||
view->getTableView()->horizontalHeader()->setSectionHidden(4, true);
|
||||
view->getTableView()->horizontalHeader()->setSectionHidden(5, true);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal's connection since the button won't be
|
||||
// accessible after this dialog is closed
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
auto unique = IrcServerData{};
|
||||
unique.id = Irc::instance().uniqueId();
|
||||
|
||||
|
||||
@@ -438,8 +438,10 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
|
||||
});
|
||||
|
||||
// userstate
|
||||
this->userStateChanged_.connect([this, mod, unmod, vip,
|
||||
unvip]() mutable {
|
||||
// We can safely ignore this signal connection since this is a private signal, and
|
||||
// we only connect once
|
||||
std::ignore = this->userStateChanged_.connect([this, mod, unmod, vip,
|
||||
unvip]() mutable {
|
||||
TwitchChannel *twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get());
|
||||
|
||||
@@ -469,17 +471,22 @@ UserInfoPopup::UserInfoPopup(bool closeAutomatically, QWidget *parent,
|
||||
{
|
||||
auto timeout = moderation.emplace<TimeoutWidget>();
|
||||
|
||||
this->userStateChanged_.connect([this, lineMod, timeout]() mutable {
|
||||
TwitchChannel *twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->underlyingChannel_.get());
|
||||
// We can safely ignore this signal connection since this is a private signal, and
|
||||
// we only connect once
|
||||
std::ignore =
|
||||
this->userStateChanged_.connect([this, lineMod, timeout]() mutable {
|
||||
TwitchChannel *twitchChannel = dynamic_cast<TwitchChannel *>(
|
||||
this->underlyingChannel_.get());
|
||||
|
||||
bool hasModRights =
|
||||
twitchChannel ? twitchChannel->hasModRights() : false;
|
||||
lineMod->setVisible(hasModRights);
|
||||
timeout->setVisible(hasModRights);
|
||||
});
|
||||
bool hasModRights =
|
||||
twitchChannel ? twitchChannel->hasModRights() : false;
|
||||
lineMod->setVisible(hasModRights);
|
||||
timeout->setVisible(hasModRights);
|
||||
});
|
||||
|
||||
timeout->buttonClicked.connect([this](auto item) {
|
||||
// We can safely ignore this signal connection since we own the button, and
|
||||
// the button will always be destroyed before the UserInfoPopup
|
||||
std::ignore = timeout->buttonClicked.connect([this](auto item) {
|
||||
TimeoutWidget::Action action;
|
||||
int arg;
|
||||
std::tie(action, arg) = item;
|
||||
|
||||
@@ -227,7 +227,9 @@ void ChannelView::initializeLayout()
|
||||
|
||||
void ChannelView::initializeScrollbar()
|
||||
{
|
||||
this->scrollBar_->getCurrentValueChanged().connect([this] {
|
||||
// We can safely ignore the scroll bar's signal connection since the scroll bar will
|
||||
// always be destroyed before the ChannelView
|
||||
std::ignore = this->scrollBar_->getCurrentValueChanged().connect([this] {
|
||||
if (this->isVisible())
|
||||
{
|
||||
this->performLayout(true);
|
||||
|
||||
@@ -33,7 +33,8 @@ AccountsPage::AccountsPage()
|
||||
view->getTableView()->horizontalHeader()->setVisible(false);
|
||||
view->getTableView()->horizontalHeader()->setStretchLastSection(true);
|
||||
|
||||
view->addButtonPressed.connect([this] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([this] {
|
||||
LoginDialog d(this);
|
||||
d.exec();
|
||||
});
|
||||
|
||||
@@ -45,7 +45,8 @@ CommandPage::CommandPage()
|
||||
view->setTitles({"Trigger", "Command", "Show In\nMessage Menu"});
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
1, QHeaderView::Stretch);
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getApp()->commands->items.append(
|
||||
Command{"/command", "I made a new command HeyGuys"});
|
||||
});
|
||||
|
||||
@@ -44,7 +44,8 @@ FiltersPage::FiltersPage()
|
||||
view->getTableView()->setColumnWidth(2, 125);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
ChannelFilterEditorDialog d(
|
||||
static_cast<QWidget *>(&(getApp()->windows->getMainWindow())));
|
||||
if (d.exec() == QDialog::Accepted)
|
||||
|
||||
@@ -195,13 +195,17 @@ ColorButton *GeneralPageView::addColorButton(
|
||||
auto dialog = new ColorPickerDialog(QColor(setting), this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->show();
|
||||
dialog->closed.connect([&setting, colorButton](QColor selected) {
|
||||
if (selected.isValid())
|
||||
{
|
||||
setting = selected.name(QColor::HexArgb);
|
||||
colorButton->setColor(selected);
|
||||
}
|
||||
});
|
||||
// We can safely ignore this signal connection, for now, since the
|
||||
// colorButton & setting are never deleted and the signal is deleted
|
||||
// once the dialog is closed
|
||||
std::ignore = dialog->closed.connect(
|
||||
[&setting, colorButton](QColor selected) {
|
||||
if (selected.isValid())
|
||||
{
|
||||
setting = selected.name(QColor::HexArgb);
|
||||
colorButton->setColor(selected);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this->groups_.back().widgets.push_back({label, {text}});
|
||||
|
||||
@@ -90,7 +90,8 @@ HighlightingPage::HighlightingPage()
|
||||
view->getTableView()->setColumnWidth(0, 400);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->highlightedMessages.append(HighlightPhrase{
|
||||
"my phrase", true, true, false, false, false, "",
|
||||
*ColorProvider::instance().color(
|
||||
@@ -141,7 +142,8 @@ HighlightingPage::HighlightingPage()
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->highlightedUsers.append(HighlightPhrase{
|
||||
"highlighted user", true, true, false, false, false, "",
|
||||
*ColorProvider::instance().color(
|
||||
@@ -182,7 +184,8 @@ HighlightingPage::HighlightingPage()
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([this] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([this] {
|
||||
auto d = std::make_shared<BadgePickerDialog>(
|
||||
availableBadges, this);
|
||||
|
||||
@@ -236,7 +239,8 @@ HighlightingPage::HighlightingPage()
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->blacklistedUsers.append(
|
||||
HighlightBlacklistUser{"blacklisted user", false});
|
||||
});
|
||||
@@ -329,7 +333,10 @@ void HighlightingPage::openColorDialog(const QModelIndex &clicked,
|
||||
auto dialog = new ColorPickerDialog(initial, this);
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->show();
|
||||
dialog->closed.connect([=](auto selected) {
|
||||
// We can safely ignore this signal connection since the view and tab are never deleted
|
||||
// TODO: The QModelIndex clicked is technically not safe to persist here since the model
|
||||
// can be changed between the color dialog being created & the color dialog being closed
|
||||
std::ignore = dialog->closed.connect([=](auto selected) {
|
||||
if (selected.isValid())
|
||||
{
|
||||
view->getModel()->setData(clicked, selected, Qt::DecorationRole);
|
||||
|
||||
@@ -63,7 +63,8 @@ void addPhrasesTab(LayoutCreator<QVBoxLayout> layout)
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->ignoredMessages.append(
|
||||
IgnorePhrase{"my pattern", false, false,
|
||||
getSettings()->ignoredPhraseReplace.getValue(), true});
|
||||
|
||||
@@ -34,7 +34,8 @@ KeyboardSettingsPage::KeyboardSettingsPage()
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
1, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([view, model] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([view, model] {
|
||||
EditHotkeyDialog dialog(nullptr);
|
||||
bool wasAccepted = dialog.exec() == 1;
|
||||
|
||||
|
||||
@@ -169,7 +169,8 @@ ModerationPage::ModerationPage()
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->loggedChannels.append(ChannelLog("channel"));
|
||||
});
|
||||
|
||||
@@ -209,7 +210,8 @@ ModerationPage::ModerationPage()
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
0, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->moderationActions.append(
|
||||
ModerationAction("/timeout {user.name} 300"));
|
||||
});
|
||||
|
||||
@@ -36,7 +36,8 @@ NicknamesPage::NicknamesPage()
|
||||
view->getTableView()->horizontalHeader()->setSectionResizeMode(
|
||||
1, QHeaderView::Stretch);
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getSettings()->nicknames.append(
|
||||
Nickname{"Username", "Nickname", false, false});
|
||||
});
|
||||
|
||||
@@ -109,7 +109,8 @@ NotificationPage::NotificationPage()
|
||||
view->getTableView()->setColumnWidth(0, 200);
|
||||
});
|
||||
|
||||
view->addButtonPressed.connect([] {
|
||||
// We can safely ignore this signal connection since we own the view
|
||||
std::ignore = view->addButtonPressed.connect([] {
|
||||
getApp()
|
||||
->notifications->channelMap[Platform::Twitch]
|
||||
.append("channel");
|
||||
|
||||
@@ -247,7 +247,8 @@ Split::Split(QWidget *parent)
|
||||
this->updateInputPlaceholder();
|
||||
|
||||
// clear SplitInput selection when selecting in ChannelView
|
||||
this->view_->selectionChanged.connect([this]() {
|
||||
// this connection can be ignored since the ChannelView is owned by this Split
|
||||
std::ignore = this->view_->selectionChanged.connect([this]() {
|
||||
if (this->input_->hasSelection())
|
||||
{
|
||||
this->input_->clearSelection();
|
||||
@@ -255,55 +256,60 @@ Split::Split(QWidget *parent)
|
||||
});
|
||||
|
||||
// clear ChannelView selection when selecting in SplitInput
|
||||
this->input_->selectionChanged.connect([this]() {
|
||||
// this connection can be ignored since the SplitInput is owned by this Split
|
||||
std::ignore = this->input_->selectionChanged.connect([this]() {
|
||||
if (this->view_->hasSelection())
|
||||
{
|
||||
this->view_->clearSelection();
|
||||
}
|
||||
});
|
||||
|
||||
this->view_->openChannelIn.connect([this](
|
||||
QString twitchChannel,
|
||||
FromTwitchLinkOpenChannelIn openIn) {
|
||||
ChannelPtr channel = getApp()->twitch->getOrAddChannel(twitchChannel);
|
||||
switch (openIn)
|
||||
{
|
||||
case FromTwitchLinkOpenChannelIn::Split:
|
||||
this->openSplitRequested.invoke(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::Tab:
|
||||
this->joinChannelInNewTab(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::BrowserPlayer:
|
||||
this->openChannelInBrowserPlayer(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::Streamlink:
|
||||
this->openChannelInStreamlink(twitchChannel);
|
||||
break;
|
||||
default:
|
||||
qCWarning(chatterinoWidget)
|
||||
<< "Unhandled \"FromTwitchLinkOpenChannelIn\" enum value: "
|
||||
<< static_cast<int>(openIn);
|
||||
}
|
||||
});
|
||||
// this connection can be ignored since the ChannelView is owned by this Split
|
||||
std::ignore = this->view_->openChannelIn.connect(
|
||||
[this](QString twitchChannel, FromTwitchLinkOpenChannelIn openIn) {
|
||||
ChannelPtr channel =
|
||||
getApp()->twitch->getOrAddChannel(twitchChannel);
|
||||
switch (openIn)
|
||||
{
|
||||
case FromTwitchLinkOpenChannelIn::Split:
|
||||
this->openSplitRequested.invoke(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::Tab:
|
||||
this->joinChannelInNewTab(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::BrowserPlayer:
|
||||
this->openChannelInBrowserPlayer(channel);
|
||||
break;
|
||||
case FromTwitchLinkOpenChannelIn::Streamlink:
|
||||
this->openChannelInStreamlink(twitchChannel);
|
||||
break;
|
||||
default:
|
||||
qCWarning(chatterinoWidget)
|
||||
<< "Unhandled \"FromTwitchLinkOpenChannelIn\" enum "
|
||||
"value: "
|
||||
<< static_cast<int>(openIn);
|
||||
}
|
||||
});
|
||||
|
||||
this->input_->textChanged.connect([this](const QString &newText) {
|
||||
if (getSettings()->showEmptyInput)
|
||||
{
|
||||
// We always show the input regardless of the text, so we can early out here
|
||||
return;
|
||||
}
|
||||
// this connection can be ignored since the SplitInput is owned by this Split
|
||||
std::ignore =
|
||||
this->input_->textChanged.connect([this](const QString &newText) {
|
||||
if (getSettings()->showEmptyInput)
|
||||
{
|
||||
// We always show the input regardless of the text, so we can early out here
|
||||
return;
|
||||
}
|
||||
|
||||
if (newText.isEmpty())
|
||||
{
|
||||
this->input_->hide();
|
||||
}
|
||||
else if (this->input_->isHidden())
|
||||
{
|
||||
// Text updated and the input was previously hidden, show it
|
||||
this->input_->show();
|
||||
}
|
||||
});
|
||||
if (newText.isEmpty())
|
||||
{
|
||||
this->input_->hide();
|
||||
}
|
||||
else if (this->input_->isHidden())
|
||||
{
|
||||
// Text updated and the input was previously hidden, show it
|
||||
this->input_->show();
|
||||
}
|
||||
});
|
||||
|
||||
getSettings()->showEmptyInput.connect(
|
||||
[this](const bool &showEmptyInput, auto) {
|
||||
@@ -367,7 +373,9 @@ Split::Split(QWidget *parent)
|
||||
// Forward textEdit's focusLost event
|
||||
this->focusLost.invoke();
|
||||
});
|
||||
this->input_->ui_.textEdit->imagePasted.connect(
|
||||
|
||||
// this connection can be ignored since the SplitInput is owned by this Split
|
||||
std::ignore = this->input_->ui_.textEdit->imagePasted.connect(
|
||||
[this](const QMimeData *source) {
|
||||
if (!getSettings()->imageUploaderEnabled)
|
||||
return;
|
||||
@@ -896,7 +904,9 @@ void Split::showChangeChannelPopup(const char *dialogTitle, bool empty,
|
||||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dialog->setWindowTitle(dialogTitle);
|
||||
dialog->show();
|
||||
dialog->closed.connect([=, this] {
|
||||
// We can safely ignore this signal connection since the dialog will be closed before
|
||||
// this Split is closed
|
||||
std::ignore = dialog->closed.connect([=, this] {
|
||||
if (dialog->hasSeletedChannel())
|
||||
{
|
||||
this->setChannel(dialog->getSelectedChannel());
|
||||
|
||||
+124
-123
@@ -44,43 +44,45 @@ using namespace chatterino;
|
||||
// 5 minutes
|
||||
constexpr const uint64_t THUMBNAIL_MAX_AGE_MS = 5ULL * 60 * 1000;
|
||||
|
||||
auto formatRoomMode(TwitchChannel &channel) -> QString
|
||||
auto formatRoomModeUnclean(
|
||||
const SharedAccessGuard<const TwitchChannel::RoomModes> &modes) -> QString
|
||||
{
|
||||
QString text;
|
||||
|
||||
if (modes->r9k)
|
||||
{
|
||||
auto modes = channel.accessRoomModes();
|
||||
|
||||
if (modes->r9k)
|
||||
text += "r9k, ";
|
||||
}
|
||||
if (modes->slowMode > 0)
|
||||
{
|
||||
text += QString("slow(%1), ").arg(localizeNumbers(modes->slowMode));
|
||||
}
|
||||
if (modes->emoteOnly)
|
||||
{
|
||||
text += "emote, ";
|
||||
}
|
||||
if (modes->submode)
|
||||
{
|
||||
text += "sub, ";
|
||||
}
|
||||
if (modes->followerOnly != -1)
|
||||
{
|
||||
if (modes->followerOnly != 0)
|
||||
{
|
||||
text += "r9k, ";
|
||||
text += QString("follow(%1m), ")
|
||||
.arg(localizeNumbers(modes->followerOnly));
|
||||
}
|
||||
if (modes->slowMode > 0)
|
||||
else
|
||||
{
|
||||
text += QString("slow(%1), ").arg(localizeNumbers(modes->slowMode));
|
||||
}
|
||||
if (modes->emoteOnly)
|
||||
{
|
||||
text += "emote, ";
|
||||
}
|
||||
if (modes->submode)
|
||||
{
|
||||
text += "sub, ";
|
||||
}
|
||||
if (modes->followerOnly != -1)
|
||||
{
|
||||
if (modes->followerOnly != 0)
|
||||
{
|
||||
text += QString("follow(%1m), ")
|
||||
.arg(localizeNumbers(modes->followerOnly));
|
||||
}
|
||||
else
|
||||
{
|
||||
text += QString("follow, ");
|
||||
}
|
||||
text += QString("follow, ");
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void cleanRoomModeText(QString &text, bool hasModRights)
|
||||
{
|
||||
if (text.length() > 2)
|
||||
{
|
||||
text = text.mid(0, text.size() - 2);
|
||||
@@ -97,12 +99,10 @@ auto formatRoomMode(TwitchChannel &channel) -> QString
|
||||
}
|
||||
}
|
||||
|
||||
if (text.isEmpty() && channel.hasModRights())
|
||||
if (text.isEmpty() && hasModRights)
|
||||
{
|
||||
return "none";
|
||||
text = "none";
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
auto formatTooltip(const TwitchChannel::StreamStatus &s, QString thumbnail)
|
||||
@@ -231,13 +231,16 @@ SplitHeader::SplitHeader(Split *split)
|
||||
this->handleChannelChanged();
|
||||
this->updateModerationModeIcon();
|
||||
|
||||
this->split_->focused.connect([this]() {
|
||||
// The lifetime of these signals are tied to the lifetime of the Split.
|
||||
// Since the SplitHeader is owned by the Split, they will always be destroyed
|
||||
// at the same time.
|
||||
std::ignore = this->split_->focused.connect([this]() {
|
||||
this->themeChangedEvent();
|
||||
});
|
||||
this->split_->focusLost.connect([this]() {
|
||||
std::ignore = this->split_->focusLost.connect([this]() {
|
||||
this->themeChangedEvent();
|
||||
});
|
||||
this->split_->channelChanged.connect([this]() {
|
||||
std::ignore = this->split_->channelChanged.connect([this]() {
|
||||
this->handleChannelChanged();
|
||||
});
|
||||
|
||||
@@ -257,6 +260,8 @@ SplitHeader::SplitHeader(Split *split)
|
||||
|
||||
void SplitHeader::initializeLayout()
|
||||
{
|
||||
assert(this->layout() == nullptr);
|
||||
|
||||
auto *layout = makeLayout<QHBoxLayout>({
|
||||
// space
|
||||
makeWidget<BaseWidget>([](auto w) {
|
||||
@@ -277,7 +282,6 @@ void SplitHeader::initializeLayout()
|
||||
this->modeButton_ = makeWidget<EffectLabel>([&](auto w) {
|
||||
w->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
w->hide();
|
||||
this->initializeModeSignals(*w);
|
||||
w->setMenu(this->createChatModeMenu());
|
||||
}),
|
||||
// moderator
|
||||
@@ -573,43 +577,23 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
{
|
||||
auto menu = std::make_unique<QMenu>();
|
||||
|
||||
auto *setSub = new QAction("Subscriber only", this);
|
||||
auto *setEmote = new QAction("Emote only", this);
|
||||
auto *setSlow = new QAction("Slow", this);
|
||||
auto *setR9k = new QAction("R9K", this);
|
||||
auto *setFollowers = new QAction("Followers only", this);
|
||||
this->modeActionSetSub = new QAction("Subscriber only", this);
|
||||
this->modeActionSetEmote = new QAction("Emote only", this);
|
||||
this->modeActionSetSlow = new QAction("Slow", this);
|
||||
this->modeActionSetR9k = new QAction("R9K", this);
|
||||
this->modeActionSetFollowers = new QAction("Followers only", this);
|
||||
|
||||
setFollowers->setCheckable(true);
|
||||
setSub->setCheckable(true);
|
||||
setEmote->setCheckable(true);
|
||||
setSlow->setCheckable(true);
|
||||
setR9k->setCheckable(true);
|
||||
this->modeActionSetFollowers->setCheckable(true);
|
||||
this->modeActionSetSub->setCheckable(true);
|
||||
this->modeActionSetEmote->setCheckable(true);
|
||||
this->modeActionSetSlow->setCheckable(true);
|
||||
this->modeActionSetR9k->setCheckable(true);
|
||||
|
||||
menu->addAction(setEmote);
|
||||
menu->addAction(setSub);
|
||||
menu->addAction(setSlow);
|
||||
menu->addAction(setR9k);
|
||||
menu->addAction(setFollowers);
|
||||
|
||||
this->managedConnections_.managedConnect(
|
||||
this->modeUpdateRequested_,
|
||||
[this, setSub, setEmote, setSlow, setR9k, setFollowers]() {
|
||||
auto *twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get());
|
||||
if (twitchChannel == nullptr)
|
||||
{
|
||||
this->modeButton_->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
auto roomModes = twitchChannel->accessRoomModes();
|
||||
|
||||
setR9k->setChecked(roomModes->r9k);
|
||||
setSlow->setChecked(roomModes->slowMode > 0);
|
||||
setEmote->setChecked(roomModes->emoteOnly);
|
||||
setSub->setChecked(roomModes->submode);
|
||||
setFollowers->setChecked(roomModes->followerOnly != -1);
|
||||
});
|
||||
menu->addAction(this->modeActionSetEmote);
|
||||
menu->addAction(this->modeActionSetSub);
|
||||
menu->addAction(this->modeActionSetSlow);
|
||||
menu->addAction(this->modeActionSetR9k);
|
||||
menu->addAction(this->modeActionSetFollowers);
|
||||
|
||||
auto execCommand = [this](const QString &command) {
|
||||
auto text = getApp()->getCommands()->execCommand(
|
||||
@@ -622,44 +606,44 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
action->setChecked(!action->isChecked());
|
||||
};
|
||||
|
||||
QObject::connect(setSub, &QAction::triggered, this,
|
||||
[setSub, toggle]() mutable {
|
||||
toggle("/subscribers", setSub);
|
||||
QObject::connect(this->modeActionSetSub, &QAction::triggered, this,
|
||||
[this, toggle]() mutable {
|
||||
toggle("/subscribers", this->modeActionSetSub);
|
||||
});
|
||||
|
||||
QObject::connect(setEmote, &QAction::triggered, this,
|
||||
[setEmote, toggle]() mutable {
|
||||
toggle("/emoteonly", setEmote);
|
||||
QObject::connect(this->modeActionSetEmote, &QAction::triggered, this,
|
||||
[this, toggle]() mutable {
|
||||
toggle("/emoteonly", this->modeActionSetEmote);
|
||||
});
|
||||
|
||||
QObject::connect(
|
||||
setSlow, &QAction::triggered, this, [setSlow, this, execCommand]() {
|
||||
if (!setSlow->isChecked())
|
||||
{
|
||||
execCommand("/slowoff");
|
||||
setSlow->setChecked(false);
|
||||
return;
|
||||
};
|
||||
auto ok = bool();
|
||||
auto seconds =
|
||||
QInputDialog::getInt(this, "", "Seconds:", 10, 0, 500, 1, &ok,
|
||||
Qt::FramelessWindowHint);
|
||||
if (ok)
|
||||
{
|
||||
execCommand(QString("/slow %1").arg(seconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
setSlow->setChecked(false);
|
||||
}
|
||||
});
|
||||
QObject::connect(this->modeActionSetSlow, &QAction::triggered, this,
|
||||
[this, execCommand]() {
|
||||
if (!this->modeActionSetSlow->isChecked())
|
||||
{
|
||||
execCommand("/slowoff");
|
||||
this->modeActionSetSlow->setChecked(false);
|
||||
return;
|
||||
};
|
||||
auto ok = bool();
|
||||
auto seconds = QInputDialog::getInt(
|
||||
this, "", "Seconds:", 10, 0, 500, 1, &ok,
|
||||
Qt::FramelessWindowHint);
|
||||
if (ok)
|
||||
{
|
||||
execCommand(QString("/slow %1").arg(seconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->modeActionSetSlow->setChecked(false);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(setFollowers, &QAction::triggered, this,
|
||||
[setFollowers, this, execCommand]() {
|
||||
if (!setFollowers->isChecked())
|
||||
QObject::connect(this->modeActionSetFollowers, &QAction::triggered, this,
|
||||
[this, execCommand]() {
|
||||
if (!this->modeActionSetFollowers->isChecked())
|
||||
{
|
||||
execCommand("/followersoff");
|
||||
setFollowers->setChecked(false);
|
||||
this->modeActionSetFollowers->setChecked(false);
|
||||
return;
|
||||
};
|
||||
auto ok = bool();
|
||||
@@ -673,13 +657,13 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
}
|
||||
else
|
||||
{
|
||||
setFollowers->setChecked(false);
|
||||
this->modeActionSetFollowers->setChecked(false);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(setR9k, &QAction::triggered, this,
|
||||
[setR9k, toggle]() mutable {
|
||||
toggle("/r9kbeta", setR9k);
|
||||
QObject::connect(this->modeActionSetR9k, &QAction::triggered, this,
|
||||
[this, toggle]() mutable {
|
||||
toggle("/r9kbeta", this->modeActionSetR9k);
|
||||
});
|
||||
|
||||
return menu;
|
||||
@@ -687,30 +671,47 @@ std::unique_ptr<QMenu> SplitHeader::createChatModeMenu()
|
||||
|
||||
void SplitHeader::updateRoomModes()
|
||||
{
|
||||
this->modeUpdateRequested_.invoke();
|
||||
}
|
||||
assert(this->modeButton_ != nullptr);
|
||||
|
||||
void SplitHeader::initializeModeSignals(EffectLabel &label)
|
||||
{
|
||||
this->modeUpdateRequested_.connect([this, &label] {
|
||||
if (auto *twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
||||
// Update the mode button
|
||||
if (auto *twitchChannel =
|
||||
dynamic_cast<TwitchChannel *>(this->split_->getChannel().get()))
|
||||
{
|
||||
this->modeButton_->setEnable(twitchChannel->hasModRights());
|
||||
|
||||
QString text;
|
||||
{
|
||||
label.setEnable(twitchChannel->hasModRights());
|
||||
auto roomModes = twitchChannel->accessRoomModes();
|
||||
text = formatRoomModeUnclean(roomModes);
|
||||
|
||||
// set the label text
|
||||
auto text = formatRoomMode(*twitchChannel);
|
||||
// Set menu action
|
||||
this->modeActionSetR9k->setChecked(roomModes->r9k);
|
||||
this->modeActionSetSlow->setChecked(roomModes->slowMode > 0);
|
||||
this->modeActionSetEmote->setChecked(roomModes->emoteOnly);
|
||||
this->modeActionSetSub->setChecked(roomModes->submode);
|
||||
this->modeActionSetFollowers->setChecked(roomModes->followerOnly !=
|
||||
-1);
|
||||
}
|
||||
cleanRoomModeText(text, twitchChannel->hasModRights());
|
||||
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
label.getLabel().setText(text);
|
||||
label.show();
|
||||
return;
|
||||
}
|
||||
// set the label text
|
||||
|
||||
if (!text.isEmpty())
|
||||
{
|
||||
this->modeButton_->getLabel().setText(text);
|
||||
this->modeButton_->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->modeButton_->hide();
|
||||
}
|
||||
|
||||
label.hide();
|
||||
});
|
||||
// Update the mode button menu actions
|
||||
}
|
||||
else
|
||||
{
|
||||
this->modeButton_->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void SplitHeader::resetThumbnail()
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
|
||||
void updateChannelText();
|
||||
void updateModerationModeIcon();
|
||||
// Invoked when SplitHeader should update anything refering to a TwitchChannel's mode
|
||||
// has changed (e.g. sub mode toggled)
|
||||
void updateRoomModes();
|
||||
|
||||
protected:
|
||||
@@ -75,7 +77,14 @@ private:
|
||||
// ui
|
||||
Button *dropdownButton_{};
|
||||
Label *titleLabel_{};
|
||||
|
||||
EffectLabel *modeButton_{};
|
||||
QAction *modeActionSetEmote{};
|
||||
QAction *modeActionSetSub{};
|
||||
QAction *modeActionSetSlow{};
|
||||
QAction *modeActionSetR9k{};
|
||||
QAction *modeActionSetFollowers{};
|
||||
|
||||
Button *moderationButton_{};
|
||||
Button *viewersButton_{};
|
||||
Button *addButton_{};
|
||||
@@ -86,8 +95,8 @@ private:
|
||||
bool doubleClicked_{false};
|
||||
bool menuVisible_{false};
|
||||
|
||||
// signals
|
||||
pajlada::Signals::NoArgSignal modeUpdateRequested_;
|
||||
// managedConnections_ contains connections for signals that are not managed by us
|
||||
// and don't change when the parent Split changes its underlying channel
|
||||
pajlada::Signals::SignalHolder managedConnections_;
|
||||
pajlada::Signals::SignalHolder channelConnections_;
|
||||
std::vector<boost::signals2::scoped_connection> bSignals_;
|
||||
|
||||
@@ -63,7 +63,9 @@ SplitInput::SplitInput(QWidget *parent, Split *_chatWidget,
|
||||
// misc
|
||||
this->installKeyPressedEvent();
|
||||
this->addShortcuts();
|
||||
this->ui_.textEdit->focusLost.connect([this] {
|
||||
// The textEdit's signal will be destroyed before this SplitInput is
|
||||
// destroyed, so we can safely ignore this signal's connection.
|
||||
std::ignore = this->ui_.textEdit->focusLost.connect([this] {
|
||||
this->hideCompletionPopup();
|
||||
});
|
||||
this->scaleChangedEvent(this->scale());
|
||||
@@ -293,23 +295,25 @@ void SplitInput::openEmotePopup()
|
||||
this->emotePopup_ = new EmotePopup(this);
|
||||
this->emotePopup_->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
this->emotePopup_->linkClicked.connect([this](const Link &link) {
|
||||
if (link.type == Link::InsertText)
|
||||
{
|
||||
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
||||
QString textToInsert(link.value + " ");
|
||||
|
||||
// If symbol before cursor isn't space or empty
|
||||
// Then insert space before emote.
|
||||
if (cursor.position() > 0 &&
|
||||
!this->getInputText()[cursor.position() - 1].isSpace())
|
||||
// The EmotePopup is closed & destroyed when this is destroyed, meaning it's safe to ignore this connection
|
||||
std::ignore =
|
||||
this->emotePopup_->linkClicked.connect([this](const Link &link) {
|
||||
if (link.type == Link::InsertText)
|
||||
{
|
||||
textToInsert = " " + textToInsert;
|
||||
QTextCursor cursor = this->ui_.textEdit->textCursor();
|
||||
QString textToInsert(link.value + " ");
|
||||
|
||||
// If symbol before cursor isn't space or empty
|
||||
// Then insert space before emote.
|
||||
if (cursor.position() > 0 &&
|
||||
!this->getInputText()[cursor.position() - 1].isSpace())
|
||||
{
|
||||
textToInsert = " " + textToInsert;
|
||||
}
|
||||
this->insertText(textToInsert);
|
||||
this->ui_.textEdit->activateWindow();
|
||||
}
|
||||
this->insertText(textToInsert);
|
||||
this->ui_.textEdit->activateWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this->emotePopup_->resize(int(300 * this->emotePopup_->scale()),
|
||||
@@ -649,33 +653,40 @@ bool SplitInput::eventFilter(QObject *obj, QEvent *event)
|
||||
|
||||
void SplitInput::installKeyPressedEvent()
|
||||
{
|
||||
this->ui_.textEdit->keyPressed.disconnectAll();
|
||||
this->ui_.textEdit->keyPressed.connect([this](QKeyEvent *event) {
|
||||
if (auto *popup = this->inputCompletionPopup_.data())
|
||||
{
|
||||
if (popup->isVisible())
|
||||
// We can safely ignore this signal's connection because SplitInput owns
|
||||
// the textEdit object, so it will always be deleted before SplitInput
|
||||
std::ignore =
|
||||
this->ui_.textEdit->keyPressed.connect([this](QKeyEvent *event) {
|
||||
if (auto *popup = this->inputCompletionPopup_.data())
|
||||
{
|
||||
if (popup->eventFilter(nullptr, event))
|
||||
if (popup->isVisible())
|
||||
{
|
||||
event->accept();
|
||||
return;
|
||||
if (popup->eventFilter(nullptr, event))
|
||||
{
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// One of the last remaining of it's kind, the copy shortcut.
|
||||
// For some bizarre reason Qt doesn't want this key be rebound.
|
||||
// TODO(Mm2PL): Revisit in Qt6, maybe something changed?
|
||||
if ((event->key() == Qt::Key_C || event->key() == Qt::Key_Insert) &&
|
||||
event->modifiers() == Qt::ControlModifier)
|
||||
{
|
||||
if (this->channelView_->hasSelection())
|
||||
// One of the last remaining of it's kind, the copy shortcut.
|
||||
// For some bizarre reason Qt doesn't want this key be rebound.
|
||||
// TODO(Mm2PL): Revisit in Qt6, maybe something changed?
|
||||
if ((event->key() == Qt::Key_C || event->key() == Qt::Key_Insert) &&
|
||||
event->modifiers() == Qt::ControlModifier)
|
||||
{
|
||||
this->channelView_->copySelectedText();
|
||||
event->accept();
|
||||
if (this->channelView_->hasSelection())
|
||||
{
|
||||
this->channelView_->copySelectedText();
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(this->keyPressedEventInstalled == false);
|
||||
this->keyPressedEventInstalled = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SplitInput::mousePressEvent(QMouseEvent *event)
|
||||
|
||||
@@ -91,6 +91,9 @@ protected:
|
||||
void addShortcuts() override;
|
||||
void initLayout();
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
#ifdef DEBUG
|
||||
bool keyPressedEventInstalled{};
|
||||
#endif
|
||||
void installKeyPressedEvent();
|
||||
void onCursorPositionChanged();
|
||||
void onTextChanged();
|
||||
|
||||
Reference in New Issue
Block a user