Fix signal connection nodiscard warnings (#4818)

This commit is contained in:
pajlada
2023-09-16 13:52:51 +02:00
committed by GitHub
parent 2d5f078306
commit 8fe3af3522
40 changed files with 709 additions and 554 deletions
+12 -11
View File
@@ -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();
+4
View File
@@ -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
+3 -1
View File
@@ -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)
{
+13 -6
View File
@@ -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();
+3 -1
View File
@@ -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();
+18 -11
View File
@@ -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;
+3 -1
View File
@@ -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);
+2 -1
View File
@@ -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();
});
+2 -1
View File
@@ -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"});
});
+2 -1
View File
@@ -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)
+11 -7
View File
@@ -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}});
+12 -5
View File
@@ -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);
+2 -1
View File
@@ -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;
+4 -2
View File
@@ -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"));
});
+2 -1
View File
@@ -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");
+54 -44
View File
@@ -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
View File
@@ -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()
+11 -2
View File
@@ -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_;
+47 -36
View File
@@ -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)
+3
View File
@@ -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();