Merge branch 'master' into sort-hands

This commit is contained in:
Zach H 2025-08-02 00:26:20 -04:00 committed by GitHub
commit 86a94ae95e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 181 additions and 151 deletions

View file

@ -549,6 +549,12 @@ void AbstractTabDeckEditor::filterTreeChanged(FilterTree *filterTree)
databaseDisplayDockWidget->setFilterTree(filterTree); databaseDisplayDockWidget->setFilterTree(filterTree);
} }
void AbstractTabDeckEditor::closeEvent(QCloseEvent *event)
{
emit deckEditorClosing(this);
event->accept();
}
// Method uses to sync docks state with menu items state // Method uses to sync docks state with menu items state
bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e) bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e)
{ {
@ -592,12 +598,11 @@ bool AbstractTabDeckEditor::confirmClose()
return true; return true;
} }
void AbstractTabDeckEditor::closeRequest(bool forced) bool AbstractTabDeckEditor::closeRequest()
{ {
if (!forced && !confirmClose()) { if (!confirmClose()) {
return; return false;
} }
emit deckEditorClosing(this); return close();
close();
} }

View file

@ -78,7 +78,7 @@ public slots:
void actDecrementCardFromSideboard(const ExactCard &card); void actDecrementCardFromSideboard(const ExactCard &card);
void actOpenRecent(const QString &fileName); void actOpenRecent(const QString &fileName);
void filterTreeChanged(FilterTree *filterTree); void filterTreeChanged(FilterTree *filterTree);
void closeRequest(bool forced = false) override; bool closeRequest() override;
virtual void showPrintingSelector() = 0; virtual void showPrintingSelector() = 0;
virtual void dockTopLevelChanged(bool topLevel) = 0; virtual void dockTopLevelChanged(bool topLevel) = 0;
@ -117,6 +117,7 @@ protected slots:
virtual void freeDocksSize() = 0; virtual void freeDocksSize() = 0;
virtual void refreshShortcuts() = 0; virtual void refreshShortcuts() = 0;
void closeEvent(QCloseEvent *event) override;
bool eventFilter(QObject *o, QEvent *e) override; bool eventFilter(QObject *o, QEvent *e) override;
virtual void dockVisibleTriggered() = 0; virtual void dockVisibleTriggered() = 0;
virtual void dockFloatingTriggered() = 0; virtual void dockFloatingTriggered() = 0;

View file

@ -43,16 +43,7 @@ void Tab::deleteCardInfoPopup(const QString &cardName)
} }
} }
/** bool Tab::closeRequest()
* Overrides the closeEvent in order to emit a close signal
*/
void Tab::closeEvent(QCloseEvent *event)
{ {
emit closed(); return close();
event->accept();
}
void Tab::closeRequest(bool /*forced*/)
{
close();
} }

View file

@ -15,12 +15,6 @@ class Tab : public QMainWindow
signals: signals:
void userEvent(bool globalEvent = true); void userEvent(bool globalEvent = true);
void tabTextChanged(Tab *tab, const QString &newTabText); void tabTextChanged(Tab *tab, const QString &newTabText);
/**
* Emitted when the tab is closed (because Qt doesn't provide a built-in close signal)
* This signal is emitted from this class's overridden Tab::closeEvent method.
* Make sure any subclasses that override closeEvent still emit this signal from there.
*/
void closed();
protected: protected:
TabSupervisor *tabSupervisor; TabSupervisor *tabSupervisor;
@ -31,7 +25,6 @@ protected:
protected slots: protected slots:
void showCardInfoPopup(const QPoint &pos, const CardRef &cardRef); void showCardInfoPopup(const QPoint &pos, const CardRef &cardRef);
void deleteCardInfoPopup(const QString &cardName); void deleteCardInfoPopup(const QString &cardName);
void closeEvent(QCloseEvent *event) override;
private: private:
CardRef currentCard; CardRef currentCard;
@ -59,13 +52,16 @@ public:
} }
virtual QString getTabText() const = 0; virtual QString getTabText() const = 0;
virtual void retranslateUi() = 0; virtual void retranslateUi() = 0;
/** /**
* Sends a request to close the tab. * Nicely asks to close the tab.
* Signals for cleanup should be emitted from this method instead of the destructor. * Override this method to do checks or ask for confirmation before closing the tab.
* If you need to force close the tab, just call close() instead.
* *
* @param forced whether this close request was initiated by the user or forced by the server. * @return True if the tab is successfully closed.
*/ */
virtual void closeRequest(bool forced = false); virtual bool closeRequest();
virtual void tabActivated() virtual void tabActivated()
{ {
} }

View file

@ -376,15 +376,19 @@ void TabGame::refreshShortcuts()
} }
} }
void TabGame::closeRequest(bool forced) bool TabGame::closeRequest()
{ {
if (!forced && !leaveGame()) { if (!leaveGame()) {
return; return false;
} }
emit gameClosing(this); return close();
}
close(); void TabGame::closeEvent(QCloseEvent *event)
{
emit gameClosing(this);
event->accept();
} }
void TabGame::incrementGameTime() void TabGame::incrementGameTime()
@ -1249,7 +1253,7 @@ void TabGame::createMenuItems()
aConcede = new QAction(this); aConcede = new QAction(this);
connect(aConcede, &QAction::triggered, this, &TabGame::actConcede); connect(aConcede, &QAction::triggered, this, &TabGame::actConcede);
aLeaveGame = new QAction(this); aLeaveGame = new QAction(this);
connect(aLeaveGame, &QAction::triggered, this, [this] { closeRequest(); }); connect(aLeaveGame, &QAction::triggered, this, &TabGame::closeRequest);
aFocusChat = new QAction(this); aFocusChat = new QAction(this);
connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus)); connect(aFocusChat, &QAction::triggered, sayEdit, qOverload<>(&LineEditCompleter::setFocus));
aCloseReplay = nullptr; aCloseReplay = nullptr;
@ -1299,7 +1303,7 @@ void TabGame::createReplayMenuItems()
aFocusChat = nullptr; aFocusChat = nullptr;
aLeaveGame = nullptr; aLeaveGame = nullptr;
aCloseReplay = new QAction(this); aCloseReplay = new QAction(this);
connect(aCloseReplay, &QAction::triggered, this, [this] { closeRequest(); }); connect(aCloseReplay, &QAction::triggered, this, &TabGame::closeRequest);
phasesMenu = nullptr; phasesMenu = nullptr;
gameMenu = new QMenu(this); gameMenu = new QMenu(this);

View file

@ -202,6 +202,9 @@ private slots:
void dockFloatingTriggered(); void dockFloatingTriggered();
void dockTopLevelChanged(bool topLevel); void dockTopLevelChanged(bool topLevel);
protected slots:
void closeEvent(QCloseEvent *event) override;
public: public:
TabGame(TabSupervisor *_tabSupervisor, TabGame(TabSupervisor *_tabSupervisor,
QList<AbstractClient *> &_clients, QList<AbstractClient *> &_clients,
@ -212,7 +215,7 @@ public:
~TabGame() override; ~TabGame() override;
void retranslateUi() override; void retranslateUi() override;
void updatePlayerListDockTitle(); void updatePlayerListDockTitle();
void closeRequest(bool forced = false) override; bool closeRequest() override;
const QMap<int, Player *> &getPlayers() const const QMap<int, Player *> &getPlayers() const
{ {
return players; return players;

View file

@ -39,7 +39,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor,
vbox->addWidget(sayEdit); vbox->addWidget(sayEdit);
aLeave = new QAction(this); aLeave = new QAction(this);
connect(aLeave, &QAction::triggered, this, [this] { closeRequest(); }); connect(aLeave, &QAction::triggered, this, &TabMessage::closeRequest);
messageMenu = new QMenu(this); messageMenu = new QMenu(this);
messageMenu->addAction(aLeave); messageMenu->addAction(aLeave);
@ -86,10 +86,10 @@ QString TabMessage::getTabText() const
return tr("%1 - Private chat").arg(QString::fromStdString(otherUserInfo->name())); return tr("%1 - Private chat").arg(QString::fromStdString(otherUserInfo->name()));
} }
void TabMessage::closeRequest(bool /*forced*/) void TabMessage::closeEvent(QCloseEvent *event)
{ {
emit talkClosing(this); emit talkClosing(this);
close(); event->accept();
} }
void TabMessage::sendMessage() void TabMessage::sendMessage()

View file

@ -37,6 +37,9 @@ private slots:
void addMentionTag(QString mentionTag); void addMentionTag(QString mentionTag);
void messageClicked(); void messageClicked();
protected slots:
void closeEvent(QCloseEvent *event) override;
public: public:
TabMessage(TabSupervisor *_tabSupervisor, TabMessage(TabSupervisor *_tabSupervisor,
AbstractClient *_client, AbstractClient *_client,
@ -44,7 +47,6 @@ public:
const ServerInfo_User &_otherUserInfo); const ServerInfo_User &_otherUserInfo);
~TabMessage() override; ~TabMessage() override;
void retranslateUi() override; void retranslateUi() override;
void closeRequest(bool forced = false) override;
void tabActivated() override; void tabActivated() override;
QString getUserName() const; QString getUserName() const;
QString getTabText() const override; QString getTabText() const override;

View file

@ -103,7 +103,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor,
hbox->addWidget(userList, 1); hbox->addWidget(userList, 1);
aLeaveRoom = new QAction(this); aLeaveRoom = new QAction(this);
connect(aLeaveRoom, &QAction::triggered, this, [this] { closeRequest(); }); connect(aLeaveRoom, &QAction::triggered, this, &TabRoom::closeRequest);
roomMenu = new QMenu(this); roomMenu = new QMenu(this);
roomMenu->addAction(aLeaveRoom); roomMenu->addAction(aLeaveRoom);
@ -173,11 +173,11 @@ void TabRoom::actShowPopup(const QString &message)
} }
} }
void TabRoom::closeRequest(bool /*forced*/) void TabRoom::closeEvent(QCloseEvent *event)
{ {
sendRoomCommand(prepareRoomCommand(Command_LeaveRoom())); sendRoomCommand(prepareRoomCommand(Command_LeaveRoom()));
emit roomClosing(this); emit roomClosing(this);
close(); event->accept();
} }
void TabRoom::tabActivated() void TabRoom::tabActivated()

View file

@ -88,13 +88,15 @@ private slots:
void processRemoveMessagesEvent(const Event_RemoveMessages &event); void processRemoveMessagesEvent(const Event_RemoveMessages &event);
void refreshShortcuts(); void refreshShortcuts();
protected slots:
void closeEvent(QCloseEvent *event) override;
public: public:
TabRoom(TabSupervisor *_tabSupervisor, TabRoom(TabSupervisor *_tabSupervisor,
AbstractClient *_client, AbstractClient *_client,
ServerInfo_User *_ownUser, ServerInfo_User *_ownUser,
const ServerInfo_Room &info); const ServerInfo_Room &info);
void retranslateUi() override; void retranslateUi() override;
void closeRequest(bool forced = false) override;
void tabActivated() override; void tabActivated() override;
void processRoomEvent(const RoomEvent &event); void processRoomEvent(const RoomEvent &event);
int getRoomId() const int getRoomId() const

View file

@ -182,7 +182,16 @@ TabSupervisor::TabSupervisor(AbstractClient *_client, QMenu *tabsMenu, QWidget *
TabSupervisor::~TabSupervisor() TabSupervisor::~TabSupervisor()
{ {
stop(); // Note: this used to call stop(), but stop() is doing a bunch of stuff including emitting some signals,
// and we don't want to do that in a destructor.
for (auto &localClient : localClients) {
localClient->deleteLater();
}
localClients.clear();
delete userInfo;
userInfo = nullptr;
} }
void TabSupervisor::retranslateUi() void TabSupervisor::retranslateUi()
@ -268,26 +277,6 @@ void TabSupervisor::closeEvent(QCloseEvent *event)
event->ignore(); event->ignore();
} }
} }
// Close the game tabs in order to make sure they store their layout.
QSet<int> gameTabsToRemove;
for (auto it = gameTabs.begin(), end = gameTabs.end(); it != end; ++it) {
if (it.value()->close()) {
// Hotfix: the tab owns the `QMenu`s so they need to be cleared,
// otherwise we end up with use-after-free bugs.
if (it.value() == currentWidget()) {
emit setMenu();
}
gameTabsToRemove.insert(it.key());
} else {
event->ignore();
}
}
for (auto tabId : gameTabsToRemove) {
gameTabs.remove(tabId);
}
} }
AbstractClient *TabSupervisor::getClient() const AbstractClient *TabSupervisor::getClient() const
@ -375,7 +364,7 @@ void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex, QAction *manager
// If managed, all close requests should go through the menu action // If managed, all close requests should go through the menu action
connect(closeButton, &CloseButton::clicked, this, [manager] { checkAndTrigger(manager, false); }); connect(closeButton, &CloseButton::clicked, this, [manager] { checkAndTrigger(manager, false); });
} else { } else {
connect(closeButton, &CloseButton::clicked, tab, [tab] { tab->closeRequest(); }); connect(closeButton, &CloseButton::clicked, tab, &Tab::closeRequest);
} }
tabBar()->setTabButton(tabIndex, closeSide, closeButton); tabBar()->setTabButton(tabIndex, closeSide, closeButton);
} }
@ -469,16 +458,16 @@ void TabSupervisor::stop()
emit localGameEnded(); emit localGameEnded();
} else { } else {
if (tabAccount) { if (tabAccount) {
tabAccount->closeRequest(true); tabAccount->close();
} }
if (tabServer) { if (tabServer) {
tabServer->closeRequest(true); tabServer->close();
} }
if (tabAdmin) { if (tabAdmin) {
tabAdmin->closeRequest(true); tabAdmin->close();
} }
if (tabLog) { if (tabLog) {
tabLog->closeRequest(true); tabLog->close();
} }
} }
@ -497,7 +486,7 @@ void TabSupervisor::stop()
} }
for (const auto tab : tabsToDelete) { for (const auto tab : tabsToDelete) {
tab->closeRequest(true); tab->close();
} }
userListManager->handleDisconnect(); userListManager->handleDisconnect();
@ -521,7 +510,7 @@ void TabSupervisor::openTabVisualDeckStorage()
{ {
tabVisualDeckStorage = new TabDeckStorageVisual(this); tabVisualDeckStorage = new TabDeckStorageVisual(this);
myAddTab(tabVisualDeckStorage, aTabVisualDeckStorage); myAddTab(tabVisualDeckStorage, aTabVisualDeckStorage);
connect(tabVisualDeckStorage, &Tab::closed, this, [this] { connect(tabVisualDeckStorage, &QObject::destroyed, this, [this] {
tabVisualDeckStorage = nullptr; tabVisualDeckStorage = nullptr;
aTabVisualDeckStorage->setChecked(false); aTabVisualDeckStorage->setChecked(false);
}); });
@ -544,7 +533,7 @@ void TabSupervisor::openTabServer()
tabServer = new TabServer(this, client); tabServer = new TabServer(this, client);
connect(tabServer, &TabServer::roomJoined, this, &TabSupervisor::addRoomTab); connect(tabServer, &TabServer::roomJoined, this, &TabSupervisor::addRoomTab);
myAddTab(tabServer, aTabServer); myAddTab(tabServer, aTabServer);
connect(tabServer, &Tab::closed, this, [this] { connect(tabServer, &QObject::destroyed, this, [this] {
tabServer = nullptr; tabServer = nullptr;
aTabServer->setChecked(false); aTabServer->setChecked(false);
}); });
@ -569,7 +558,7 @@ void TabSupervisor::openTabAccount()
connect(tabAccount, &TabAccount::userJoined, this, &TabSupervisor::processUserJoined); connect(tabAccount, &TabAccount::userJoined, this, &TabSupervisor::processUserJoined);
connect(tabAccount, &TabAccount::userLeft, this, &TabSupervisor::processUserLeft); connect(tabAccount, &TabAccount::userLeft, this, &TabSupervisor::processUserLeft);
myAddTab(tabAccount, aTabAccount); myAddTab(tabAccount, aTabAccount);
connect(tabAccount, &Tab::closed, this, [this] { connect(tabAccount, &QObject::destroyed, this, [this] {
tabAccount = nullptr; tabAccount = nullptr;
aTabAccount->setChecked(false); aTabAccount->setChecked(false);
}); });
@ -592,7 +581,7 @@ void TabSupervisor::openTabDeckStorage()
tabDeckStorage = new TabDeckStorage(this, client, userInfo); tabDeckStorage = new TabDeckStorage(this, client, userInfo);
connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab); connect(tabDeckStorage, &TabDeckStorage::openDeckEditor, this, &TabSupervisor::openDeckInNewTab);
myAddTab(tabDeckStorage, aTabDeckStorage); myAddTab(tabDeckStorage, aTabDeckStorage);
connect(tabDeckStorage, &Tab::closed, this, [this] { connect(tabDeckStorage, &QObject::destroyed, this, [this] {
tabDeckStorage = nullptr; tabDeckStorage = nullptr;
aTabDeckStorage->setChecked(false); aTabDeckStorage->setChecked(false);
}); });
@ -615,7 +604,7 @@ void TabSupervisor::openTabReplays()
tabReplays = new TabReplays(this, client, userInfo); tabReplays = new TabReplays(this, client, userInfo);
connect(tabReplays, &TabReplays::openReplay, this, &TabSupervisor::openReplay); connect(tabReplays, &TabReplays::openReplay, this, &TabSupervisor::openReplay);
myAddTab(tabReplays, aTabReplays); myAddTab(tabReplays, aTabReplays);
connect(tabReplays, &Tab::closed, this, [this] { connect(tabReplays, &QObject::destroyed, this, [this] {
tabReplays = nullptr; tabReplays = nullptr;
aTabReplays->setChecked(false); aTabReplays->setChecked(false);
}); });
@ -638,7 +627,7 @@ void TabSupervisor::openTabAdmin()
tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin)); tabAdmin = new TabAdmin(this, client, (userInfo->user_level() & ServerInfo_User::IsAdmin));
connect(tabAdmin, &TabAdmin::adminLockChanged, this, &TabSupervisor::adminLockChanged); connect(tabAdmin, &TabAdmin::adminLockChanged, this, &TabSupervisor::adminLockChanged);
myAddTab(tabAdmin, aTabAdmin); myAddTab(tabAdmin, aTabAdmin);
connect(tabAdmin, &Tab::closed, this, [this] { connect(tabAdmin, &QObject::destroyed, this, [this] {
tabAdmin = nullptr; tabAdmin = nullptr;
aTabAdmin->setChecked(false); aTabAdmin->setChecked(false);
}); });
@ -660,7 +649,7 @@ void TabSupervisor::openTabLog()
{ {
tabLog = new TabLog(this, client); tabLog = new TabLog(this, client);
myAddTab(tabLog, aTabLog); myAddTab(tabLog, aTabLog);
connect(tabLog, &Tab::closed, this, [this] { connect(tabLog, &QObject::destroyed, this, [this] {
tabLog = nullptr; tabLog = nullptr;
aTabAdmin->setChecked(false); aTabAdmin->setChecked(false);
}); });

View file

@ -420,6 +420,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
connect(aCreateAnotherToken, &QAction::triggered, this, &Player::actCreateAnotherToken); connect(aCreateAnotherToken, &QAction::triggered, this, &Player::actCreateAnotherToken);
aCreateAnotherToken->setEnabled(false); aCreateAnotherToken->setEnabled(false);
aIncrementAllCardCounters = new QAction(this);
connect(aIncrementAllCardCounters, &QAction::triggered, this, &Player::incrementAllCardCounters);
createPredefinedTokenMenu = new QMenu(QString()); createPredefinedTokenMenu = new QMenu(QString());
createPredefinedTokenMenu->setEnabled(false); createPredefinedTokenMenu->setEnabled(false);
@ -427,6 +430,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
playerMenu->addSeparator(); playerMenu->addSeparator();
countersMenu = playerMenu->addMenu(QString()); countersMenu = playerMenu->addMenu(QString());
playerMenu->addAction(aIncrementAllCardCounters);
playerMenu->addSeparator(); playerMenu->addSeparator();
playerMenu->addAction(aUntapAll); playerMenu->addAction(aUntapAll);
playerMenu->addSeparator(); playerMenu->addSeparator();
@ -914,6 +918,7 @@ void Player::retranslateUi()
aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(cardCounterSettings.displayName(i))); aSetCounter[i]->setText(tr("&Set counters (%1)...").arg(cardCounterSettings.displayName(i)));
} }
aIncrementAllCardCounters->setText(tr("Increment all card counters"));
aMoveToTopLibrary->setText(tr("&Top of library in random order")); aMoveToTopLibrary->setText(tr("&Top of library in random order"));
aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library...")); aMoveToXfromTopOfLibrary->setText(tr("X cards from the top of library..."));
aMoveToBottomLibrary->setText(tr("&Bottom of library in random order")); aMoveToBottomLibrary->setText(tr("&Bottom of library in random order"));
@ -964,38 +969,11 @@ void Player::setShortcutsActive()
aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow")); aSelectRow->setShortcuts(shortcuts.getShortcut("Player/aSelectRow"));
aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn")); aSelectColumn->setShortcuts(shortcuts.getShortcut("Player/aSelectColumn"));
QList<QKeySequence> addCCShortCuts; static const QStringList colorWords = {"Red", "Yellow", "Green", "Cyan", "Purple", "Magenta"};
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCRed")); for (int i = 0; i < aAddCounter.size(); i++) {
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCYellow")); aAddCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aCC" + colorWords[i]));
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCGreen")); aRemoveCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aRC" + colorWords[i]));
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCCyan")); aSetCounter[i]->setShortcuts(shortcuts.getShortcut("Player/aSC" + colorWords[i]));
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCPurple"));
addCCShortCuts.append(shortcuts.getSingleShortcut("Player/aCCMagenta"));
QList<QKeySequence> removeCCShortCuts;
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCRed"));
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCYellow"));
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCGreen"));
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCCyan"));
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCPurple"));
removeCCShortCuts.append(shortcuts.getSingleShortcut("Player/aRCMagenta"));
QList<QKeySequence> setCCShortCuts;
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCRed"));
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCYellow"));
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCGreen"));
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCCyan"));
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCPurple"));
setCCShortCuts.append(shortcuts.getSingleShortcut("Player/aSCMagenta"));
for (int i = 0; i < addCCShortCuts.size(); ++i) {
aAddCounter[i]->setShortcut(addCCShortCuts.at(i));
}
for (int i = 0; i < removeCCShortCuts.size(); ++i) {
aRemoveCounter[i]->setShortcut(removeCCShortCuts.at(i));
}
for (int i = 0; i < setCCShortCuts.size(); ++i) {
aSetCounter[i]->setShortcut(setCCShortCuts.at(i));
} }
QMapIterator<int, AbstractCounter *> counterIterator(counters); QMapIterator<int, AbstractCounter *> counterIterator(counters);
@ -1003,44 +981,45 @@ void Player::setShortcutsActive()
counterIterator.next().value()->setShortcutsActive(); counterIterator.next().value()->setShortcutsActive();
} }
aViewSideboard->setShortcut(shortcuts.getSingleShortcut("Player/aViewSideboard")); aIncrementAllCardCounters->setShortcuts(shortcuts.getShortcut("Player/aIncrementAllCardCounters"));
aViewLibrary->setShortcut(shortcuts.getSingleShortcut("Player/aViewLibrary")); aViewSideboard->setShortcuts(shortcuts.getShortcut("Player/aViewSideboard"));
aViewHand->setShortcut(shortcuts.getSingleShortcut("Player/aViewHand")); aViewLibrary->setShortcuts(shortcuts.getShortcut("Player/aViewLibrary"));
aViewTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewTopCards")); aViewHand->setShortcuts(shortcuts.getShortcut("Player/aViewHand"));
aViewBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aViewBottomCards")); aViewTopCards->setShortcuts(shortcuts.getShortcut("Player/aViewTopCards"));
aViewGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aViewGraveyard")); aViewBottomCards->setShortcuts(shortcuts.getShortcut("Player/aViewBottomCards"));
aDrawCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCard")); aViewGraveyard->setShortcuts(shortcuts.getShortcut("Player/aViewGraveyard"));
aDrawCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawCards")); aDrawCard->setShortcuts(shortcuts.getShortcut("Player/aDrawCard"));
aUndoDraw->setShortcut(shortcuts.getSingleShortcut("Player/aUndoDraw")); aDrawCards->setShortcuts(shortcuts.getShortcut("Player/aDrawCards"));
aMulligan->setShortcut(shortcuts.getSingleShortcut("Player/aMulligan")); aUndoDraw->setShortcuts(shortcuts.getShortcut("Player/aUndoDraw"));
aShuffle->setShortcut(shortcuts.getSingleShortcut("Player/aShuffle")); aMulligan->setShortcuts(shortcuts.getShortcut("Player/aMulligan"));
aShuffleTopCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleTopCards")); aShuffle->setShortcuts(shortcuts.getShortcut("Player/aShuffle"));
aShuffleBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aShuffleBottomCards")); aShuffleTopCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleTopCards"));
aUntapAll->setShortcut(shortcuts.getSingleShortcut("Player/aUntapAll")); aShuffleBottomCards->setShortcuts(shortcuts.getShortcut("Player/aShuffleBottomCards"));
aRollDie->setShortcut(shortcuts.getSingleShortcut("Player/aRollDie")); aUntapAll->setShortcuts(shortcuts.getShortcut("Player/aUntapAll"));
aCreateToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateToken")); aRollDie->setShortcuts(shortcuts.getShortcut("Player/aRollDie"));
aCreateAnotherToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateAnotherToken")); aCreateToken->setShortcuts(shortcuts.getShortcut("Player/aCreateToken"));
aAlwaysRevealTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysRevealTopCard")); aCreateAnotherToken->setShortcuts(shortcuts.getShortcut("Player/aCreateAnotherToken"));
aAlwaysLookAtTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysLookAtTopCard")); aAlwaysRevealTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysRevealTopCard"));
aMoveTopToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlay")); aAlwaysLookAtTopCard->setShortcuts(shortcuts.getShortcut("Player/aAlwaysLookAtTopCard"));
aMoveTopToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlayFaceDown")); aMoveTopToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlay"));
aMoveTopCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToGraveyard")); aMoveTopToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveTopToPlayFaceDown"));
aMoveTopCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToGraveyard")); aMoveTopCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToGraveyard"));
aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile")); aMoveTopCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToGraveyard"));
aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile")); aMoveTopCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToExile"));
aMoveTopCardsUntil->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsUntil")); aMoveTopCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsToExile"));
aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom")); aMoveTopCardsUntil->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardsUntil"));
aDrawBottomCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCard")); aMoveTopCardToBottom->setShortcuts(shortcuts.getShortcut("Player/aMoveTopCardToBottom"));
aDrawBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCards")); aDrawBottomCard->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCard"));
aMoveBottomToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlay")); aDrawBottomCards->setShortcuts(shortcuts.getShortcut("Player/aDrawBottomCards"));
aMoveBottomToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlayFaceDown")); aMoveBottomToPlay->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlay"));
aMoveBottomCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToGrave")); aMoveBottomToPlayFaceDown->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomToPlayFaceDown"));
aMoveBottomCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToGrave")); aMoveBottomCardToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToGrave"));
aMoveBottomCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToExile")); aMoveBottomCardsToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToGrave"));
aMoveBottomCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToExile")); aMoveBottomCardToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToExile"));
aMoveBottomCardToTop->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToTop")); aMoveBottomCardsToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardsToExile"));
aPlayFacedown->setShortcut(shortcuts.getSingleShortcut("Player/aPlayFacedown")); aMoveBottomCardToTop->setShortcuts(shortcuts.getShortcut("Player/aMoveBottomCardToTop"));
aPlay->setShortcut(shortcuts.getSingleShortcut("Player/aPlay")); aPlayFacedown->setShortcuts(shortcuts.getShortcut("Player/aPlayFacedown"));
aPlay->setShortcuts(shortcuts.getShortcut("Player/aPlay"));
// Don't enable always-active shortcuts in local games, since it causes keyboard shortcuts to work inconsistently // Don't enable always-active shortcuts in local games, since it causes keyboard shortcuts to work inconsistently
// when there are more than 1 player. // when there are more than 1 player.
@ -1089,6 +1068,7 @@ void Player::setShortcutsInactive()
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence()); aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
aMoveBottomCardToExile->setShortcut(QKeySequence()); aMoveBottomCardToExile->setShortcut(QKeySequence());
aMoveBottomCardsToExile->setShortcut(QKeySequence()); aMoveBottomCardsToExile->setShortcut(QKeySequence());
aIncrementAllCardCounters->setShortcut(QKeySequence());
aSortHand->setShortcut(QKeySequence()); aSortHand->setShortcut(QKeySequence());
QMapIterator<int, AbstractCounter *> counterIterator(counters); QMapIterator<int, AbstractCounter *> counterIterator(counters);
@ -3049,6 +3029,51 @@ void Player::clearCounters()
counters.clear(); counters.clear();
} }
void Player::incrementAllCardCounters()
{
QList<CardItem *> cardsToUpdate;
auto selectedItems = scene()->selectedItems();
if (!selectedItems.isEmpty()) {
// If cards are selected, only update those
for (const auto &item : selectedItems) {
auto *card = static_cast<CardItem *>(item);
cardsToUpdate.append(card);
}
} else {
// If no cards selected, update all cards on table
const CardList &tableCards = table->getCards();
cardsToUpdate = tableCards;
}
QList<const ::google::protobuf::Message *> commandList;
for (const auto *card : cardsToUpdate) {
const auto &cardCounters = card->getCounters();
QMapIterator<int, int> counterIterator(cardCounters);
while (counterIterator.hasNext()) {
counterIterator.next();
int counterId = counterIterator.key();
int currentValue = counterIterator.value();
if (currentValue >= MAX_COUNTERS_ON_CARD) {
continue;
}
auto cmd = std::make_unique<Command_SetCardCounter>();
cmd->set_zone(card->getZone()->getName().toStdString());
cmd->set_card_id(card->getId());
cmd->set_counter_id(counterId);
cmd->set_counter_value(currentValue + 1);
commandList.append(cmd.release());
}
}
if (!commandList.isEmpty()) {
sendGameCommand(prepareGameCommand(commandList));
}
}
ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow) ArrowItem *Player::addArrow(const ServerInfo_Arrow &arrow)
{ {
const QMap<int, Player *> &playerList = game->getPlayers(); const QMap<int, Player *> &playerList = game->getPlayers();
@ -4186,8 +4211,8 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
if (createRelatedCards) { if (createRelatedCards) {
if (shortcutsActive) { if (shortcutsActive) {
createRelatedCards->setShortcut( createRelatedCards->setShortcuts(
SettingsCache::instance().shortcuts().getSingleShortcut("Player/aCreateRelatedTokens")); SettingsCache::instance().shortcuts().getShortcut("Player/aCreateRelatedTokens"));
} }
connect(createRelatedCards, &QAction::triggered, this, &Player::actCreateAllRelatedCards); connect(createRelatedCards, &QAction::triggered, this, &Player::actCreateAllRelatedCards);
cardMenu->addAction(createRelatedCards); cardMenu->addAction(createRelatedCards);

View file

@ -276,7 +276,7 @@ private:
QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT, QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT,
*aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aFlowP, *aFlowT, *aSetAnnotation, *aFlip, *aPeek, *aClone, *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aFlowP, *aFlowT, *aSetAnnotation, *aFlip, *aPeek, *aClone,
*aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToHand, *aMoveToGraveyard, *aMoveToExile,
*aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand; *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand, *aIncrementAllCardCounters;
bool movingCardsUntil; bool movingCardsUntil;
QTimer *moveTopCardTimer; QTimer *moveTopCardTimer;
@ -420,6 +420,7 @@ public:
AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value); AbstractCounter *addCounter(int counterId, const QString &name, QColor color, int radius, int value);
void delCounter(int counterId); void delCounter(int counterId);
void clearCounters(); void clearCounters();
void incrementAllCardCounters();
ArrowItem *addArrow(const ServerInfo_Arrow &arrow); ArrowItem *addArrow(const ServerInfo_Arrow &arrow);
ArrowItem *addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color); ArrowItem *addArrow(int arrowId, CardItem *startCard, ArrowTarget *targetItem, const QColor &color);

View file

@ -115,6 +115,13 @@ ShortcutKey ShortcutsSettings::getShortcut(const QString &name) const
return getDefaultShortcut(name); return getDefaultShortcut(name);
} }
/**
* Gets the first shortcut for the given action.
*
* NOTE: In most cases you should be using ShortcutsSettings::getShortcut instead,
* as that will return all shortcuts if there are multiple shortcuts.
* The only reason to use this method is if an object does not accept multiple shortcuts, such as with QButtons.
*/
QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const
{ {
return getShortcut(name).at(0); return getShortcut(name).at(0);

View file

@ -413,6 +413,10 @@ private:
{"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."), {"Player/aSetCounter_storm", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Set Other Counters..."),
parseSequenceString("Ctrl+\\"), parseSequenceString("Ctrl+\\"),
ShortcutGroup::Player_Counters)}, ShortcutGroup::Player_Counters)},
{"Player/aIncrementAllCardCounters",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Increment all card counters"),
parseSequenceString("Ctrl+Shift+A"),
ShortcutGroup::Playing_Area)},
{"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"), {"Player/aIncP", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Add Power (+1/+0)"),
parseSequenceString("Ctrl++;Ctrl+="), parseSequenceString("Ctrl++;Ctrl+="),
ShortcutGroup::Power_Toughness)}, ShortcutGroup::Power_Toughness)},