Merge branch 'Cockatrice:master' into filter-multi-word-creatures

This commit is contained in:
Paul Carroll 2025-08-18 10:11:57 -04:00 committed by GitHub
commit ff25ecaec0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 1472 additions and 1159 deletions

View file

@ -7,8 +7,6 @@ project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${
set(cockatrice_SOURCES set(cockatrice_SOURCES
${VERSION_STRING_CPP} ${VERSION_STRING_CPP}
# sort by alphabetical order, so that there is no debate about where to add new sources to the list # sort by alphabetical order, so that there is no debate about where to add new sources to the list
src/client/game_logic/abstract_client.cpp
src/client/game_logic/key_signals.cpp
src/client/get_text_with_max.cpp src/client/get_text_with_max.cpp
src/client/menus/deck_editor/deck_editor_menu.cpp src/client/menus/deck_editor/deck_editor_menu.cpp
src/client/network/client_update_checker.cpp src/client/network/client_update_checker.cpp
@ -201,6 +199,7 @@ set(cockatrice_SOURCES
src/game/cards/exact_card.cpp src/game/cards/exact_card.cpp
src/game/deckview/deck_view.cpp src/game/deckview/deck_view.cpp
src/game/deckview/deck_view_container.cpp src/game/deckview/deck_view_container.cpp
src/game/deckview/tabbed_deck_view_container.cpp
src/game/filters/deck_filter_string.cpp src/game/filters/deck_filter_string.cpp
src/game/filters/filter_builder.cpp src/game/filters/filter_builder.cpp
src/game/filters/filter_card.cpp src/game/filters/filter_card.cpp
@ -226,6 +225,7 @@ set(cockatrice_SOURCES
src/game/zones/view_zone.cpp src/game/zones/view_zone.cpp
src/game/zones/view_zone_widget.cpp src/game/zones/view_zone_widget.cpp
src/main.cpp src/main.cpp
src/server/abstract_client.cpp
src/server/chat_view/chat_view.cpp src/server/chat_view/chat_view.cpp
src/server/handle_public_servers.cpp src/server/handle_public_servers.cpp
src/server/local_client.cpp src/server/local_client.cpp
@ -256,6 +256,7 @@ set(cockatrice_SOURCES
src/settings/shortcut_treeview.cpp src/settings/shortcut_treeview.cpp
src/settings/shortcuts_settings.cpp src/settings/shortcuts_settings.cpp
src/utility/card_info_comparator.cpp src/utility/card_info_comparator.cpp
src/utility/key_signals.cpp
src/utility/levenshtein.cpp src/utility/levenshtein.cpp
src/utility/logger.cpp src/utility/logger.cpp
src/utility/sequence_edit.cpp src/utility/sequence_edit.cpp

View file

@ -1,6 +1,5 @@
#include "abstract_tab_deck_editor.h" #include "abstract_tab_deck_editor.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tapped_out_interface.h" #include "../../client/tapped_out_interface.h"
#include "../../client/ui/widgets/cards/card_info_frame_widget.h" #include "../../client/ui/widgets/cards/card_info_frame_widget.h"
#include "../../deck/deck_stats_interface.h" #include "../../deck/deck_stats_interface.h"
@ -9,6 +8,7 @@
#include "../../dialogs/dlg_load_deck_from_website.h" #include "../../dialogs/dlg_load_deck_from_website.h"
#include "../../game/cards/card_database_manager.h" #include "../../game/cards/card_database_manager.h"
#include "../../game/cards/card_database_model.h" #include "../../game/cards/card_database_model.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
#include "../ui/picture_loader/picture_loader.h" #include "../ui/picture_loader/picture_loader.h"
@ -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

@ -1,11 +1,11 @@
#include "tab_account.h" #include "tab_account.h"
#include "../../deck/custom_line_edit.h" #include "../../deck/custom_line_edit.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/user/user_info_box.h" #include "../../server/user/user_info_box.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../../server/user/user_list_widget.h" #include "../../server/user/user_list_widget.h"
#include "../game_logic/abstract_client.h"
#include "../sound_engine.h" #include "../sound_engine.h"
#include "pb/event_add_to_list.pb.h" #include "pb/event_add_to_list.pb.h"
#include "pb/event_remove_from_list.pb.h" #include "pb/event_remove_from_list.pb.h"

View file

@ -1,7 +1,7 @@
#include "tab_admin.h" #include "tab_admin.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../game_logic/abstract_client.h"
#include "pb/admin_commands.pb.h" #include "pb/admin_commands.pb.h"
#include "pb/event_replay_added.pb.h" #include "pb/event_replay_added.pb.h"
#include "pb/moderator_commands.pb.h" #include "pb/moderator_commands.pb.h"

View file

@ -1,6 +1,5 @@
#include "tab_deck_editor.h" #include "tab_deck_editor.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tapped_out_interface.h" #include "../../client/tapped_out_interface.h"
#include "../../client/ui/widgets/cards/card_info_frame_widget.h" #include "../../client/ui/widgets/cards/card_info_frame_widget.h"
#include "../../dialogs/dlg_load_deck.h" #include "../../dialogs/dlg_load_deck.h"
@ -9,6 +8,7 @@
#include "../../game/cards/card_database_model.h" #include "../../game/cards/card_database_model.h"
#include "../../game/filters/filter_builder.h" #include "../../game/filters/filter_builder.h"
#include "../../game/filters/filter_tree_model.h" #include "../../game/filters/filter_tree_model.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
#include "../menus/deck_editor/deck_editor_menu.h" #include "../menus/deck_editor/deck_editor_menu.h"

View file

@ -2,7 +2,7 @@
#define WINDOW_DECKEDITOR_H #define WINDOW_DECKEDITOR_H
#include "../../game/cards/card_info.h" #include "../../game/cards/card_info.h"
#include "../game_logic/key_signals.h" #include "../../utility/key_signals.h"
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
#include "abstract_tab_deck_editor.h" #include "abstract_tab_deck_editor.h"

View file

@ -1,8 +1,8 @@
#ifndef TAB_DECK_STORAGE_H #ifndef TAB_DECK_STORAGE_H
#define TAB_DECK_STORAGE_H #define TAB_DECK_STORAGE_H
#include "../../server/abstract_client.h"
#include "../../server/remote/remote_decklist_tree_widget.h" #include "../../server/remote/remote_decklist_tree_widget.h"
#include "../game_logic/abstract_client.h"
#include "tab.h" #include "tab.h"
class ServerInfo_User; class ServerInfo_User;

View file

@ -7,17 +7,18 @@
#include "../../game/cards/card_database.h" #include "../../game/cards/card_database.h"
#include "../../game/cards/card_database_manager.h" #include "../../game/cards/card_database_manager.h"
#include "../../game/deckview/deck_view_container.h" #include "../../game/deckview/deck_view_container.h"
#include "../../game/deckview/tabbed_deck_view_container.h"
#include "../../game/game_scene.h" #include "../../game/game_scene.h"
#include "../../game/game_view.h" #include "../../game/game_view.h"
#include "../../game/player/player.h" #include "../../game/player/player.h"
#include "../../game/player/player_list_widget.h" #include "../../game/player/player_list_widget.h"
#include "../../game/zones/card_zone.h" #include "../../game/zones/card_zone.h"
#include "../../main.h" #include "../../main.h"
#include "../../server/abstract_client.h"
#include "../../server/message_log_widget.h" #include "../../server/message_log_widget.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
#include "../game_logic/abstract_client.h"
#include "../network/replay_timeline_widget.h" #include "../network/replay_timeline_widget.h"
#include "../ui/line_edit_completer.h" #include "../ui/line_edit_completer.h"
#include "../ui/phases_toolbar.h" #include "../ui/phases_toolbar.h"
@ -261,6 +262,10 @@ void TabGame::retranslateUi()
sayLabel->setText(tr("&Say:")); sayLabel->setText(tr("&Say:"));
} }
if (aCardMenu) {
aCardMenu->setText(tr("Selected cards"));
}
viewMenu->setTitle(tr("&View")); viewMenu->setTitle(tr("&View"));
cardInfoDockMenu->setTitle(tr("Card Info")); cardInfoDockMenu->setTitle(tr("Card Info"));
messageLayoutDockMenu->setTitle(tr("Messages")); messageLayoutDockMenu->setTitle(tr("Messages"));
@ -288,9 +293,9 @@ void TabGame::retranslateUi()
QMapIterator<int, Player *> i(players); QMapIterator<int, Player *> i(players);
while (i.hasNext()) while (i.hasNext())
i.next().value()->retranslateUi(); i.next().value()->retranslateUi();
QMapIterator<int, DeckViewContainer *> j(deckViewContainers); QMapIterator<int, TabbedDeckViewContainer *> j(deckViewContainers);
while (j.hasNext()) while (j.hasNext())
j.next().value()->retranslateUi(); j.next().value()->playerDeckView->retranslateUi();
scene->retranslateUi(); scene->retranslateUi();
} }
@ -376,15 +381,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()
@ -407,11 +416,6 @@ void TabGame::adminLockChanged(bool lock)
sayEdit->setVisible(v); sayEdit->setVisible(v);
} }
bool TabGame::isSpectator()
{
return spectator;
}
void TabGame::actGameInfo() void TabGame::actGameInfo()
{ {
DlgCreateGame dlg(gameInfo, roomGameTypes, this); DlgCreateGame dlg(gameInfo, roomGameTypes, this);
@ -561,7 +565,7 @@ void TabGame::actCompleterChanged()
Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info) Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
{ {
bool local = ((clients.size() > 1) || (playerId == localPlayerId)); bool local = clients.size() > 1 || playerId == localPlayerId;
auto *newPlayer = new Player(info, playerId, local, judge, this); auto *newPlayer = new Player(info, playerId, local, judge, this);
connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *))); connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *)));
QString newPlayerName = "@" + newPlayer->getName(); QString newPlayerName = "@" + newPlayer->getName();
@ -572,14 +576,15 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
scene->addPlayer(newPlayer); scene->addPlayer(newPlayer);
connect(newPlayer, &Player::newCardAdded, this, &TabGame::newCardAdded); connect(newPlayer, &Player::newCardAdded, this, &TabGame::newCardAdded);
connect(newPlayer, &Player::cardMenuUpdated, this, &TabGame::setCardMenu);
messageLog->connectToPlayer(newPlayer); messageLog->connectToPlayer(newPlayer);
if (local && !spectator) { if (local && !spectator) {
if (clients.size() == 1) if (clients.size() == 1)
newPlayer->setShortcutsActive(); newPlayer->setShortcutsActive();
auto *deckView = new DeckViewContainer(playerId, this); auto *deckView = new TabbedDeckViewContainer(playerId, this);
connect(deckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded); connect(deckView->playerDeckView, &DeckViewContainer::newCardAdded, this, &TabGame::newCardAdded);
deckViewContainers.insert(playerId, deckView); deckViewContainers.insert(playerId, deckView);
deckViewContainerLayout->addWidget(deckView); deckViewContainerLayout->addWidget(deckView);
@ -587,8 +592,8 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
QString deckPath = SettingsCache::instance().debug().getDeckPathForPlayer(newPlayer->getName()); QString deckPath = SettingsCache::instance().debug().getDeckPathForPlayer(newPlayer->getName());
if (!deckPath.isEmpty()) { if (!deckPath.isEmpty()) {
QTimer::singleShot(0, this, [deckView, deckPath] { QTimer::singleShot(0, this, [deckView, deckPath] {
deckView->loadDeckFromFile(deckPath); deckView->playerDeckView->loadDeckFromFile(deckPath);
deckView->readyAndUpdate(); deckView->playerDeckView->readyAndUpdate();
}); });
} }
} }
@ -773,11 +778,11 @@ void TabGame::startGame(bool _resuming)
{ {
currentPhase = -1; currentPhase = -1;
QMapIterator<int, DeckViewContainer *> i(deckViewContainers); QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
i.value()->setReadyStart(false); i.value()->playerDeckView->setReadyStart(false);
i.value()->setVisualDeckStorageExists(false); i.value()->playerDeckView->setVisualDeckStorageExists(false);
i.value()->hide(); i.value()->hide();
} }
@ -799,7 +804,7 @@ void TabGame::stopGame()
currentPhase = -1; currentPhase = -1;
activePlayer = -1; activePlayer = -1;
QMapIterator<int, DeckViewContainer *> i(deckViewContainers); QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
while (i.hasNext()) { while (i.hasNext()) {
i.next(); i.next();
i.value()->show(); i.value()->show();
@ -845,6 +850,9 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event,
const GameEventContext & /*context*/) const GameEventContext & /*context*/)
{ {
const int playerListSize = event.player_list_size(); const int playerListSize = event.player_list_size();
QVector<QPair<int, QPair<QString, QString>>> opponentDecksToDisplay;
for (int i = 0; i < playerListSize; ++i) { for (int i = 0; i < playerListSize; ++i) {
const ServerInfo_Player &playerInfo = event.player_list(i); const ServerInfo_Player &playerInfo = event.player_list(i);
const ServerInfo_PlayerProperties &prop = playerInfo.properties(); const ServerInfo_PlayerProperties &prop = playerInfo.properties();
@ -867,16 +875,23 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event,
} }
player->processPlayerInfo(playerInfo); player->processPlayerInfo(playerInfo);
if (player->getLocal()) { if (player->getLocal()) {
DeckViewContainer *deckViewContainer = deckViewContainers.value(playerId); TabbedDeckViewContainer *deckViewContainer = deckViewContainers.value(playerId);
if (playerInfo.has_deck_list()) { if (playerInfo.has_deck_list()) {
DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list())); DeckLoader newDeck(QString::fromStdString(playerInfo.deck_list()));
PictureLoader::cacheCardPixmaps( PictureLoader::cacheCardPixmaps(
CardDatabaseManager::getInstance()->getCards(newDeck.getCardRefList())); CardDatabaseManager::getInstance()->getCards(newDeck.getCardRefList()));
deckViewContainer->setDeck(newDeck); deckViewContainer->playerDeckView->setDeck(newDeck);
player->setDeck(newDeck); player->setDeck(newDeck);
} }
deckViewContainer->setReadyStart(prop.ready_start()); deckViewContainer->playerDeckView->setReadyStart(prop.ready_start());
deckViewContainer->setSideboardLocked(prop.sideboard_locked()); deckViewContainer->playerDeckView->setSideboardLocked(prop.sideboard_locked());
} else {
if (!gameInfo.share_decklists_on_load()) {
continue;
}
opponentDecksToDisplay.append(
qMakePair(playerId, qMakePair(playerName, QString::fromStdString(playerInfo.deck_list()))));
} }
} }
} }
@ -891,6 +906,21 @@ void TabGame::eventGameStateChanged(const Event_GameStateChanged &event,
} }
} }
for (const auto &entry : opponentDecksToDisplay) {
int playerId = entry.first;
QString playerName = entry.second.first;
QString deckList = entry.second.second;
DeckList loader;
loader.loadFromString_Native(deckList);
QMapIterator<int, TabbedDeckViewContainer *> it(deckViewContainers);
while (it.hasNext()) {
it.next();
it.value()->addOpponentDeckView(loader, playerId, playerName);
}
}
secondsElapsed = event.seconds_elapsed(); secondsElapsed = event.seconds_elapsed();
if (event.game_started() && !gameInfo.started()) { if (event.game_started() && !gameInfo.started()) {
@ -922,7 +952,7 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &
case GameEventContext::READY_START: { case GameEventContext::READY_START: {
bool ready = prop.ready_start(); bool ready = prop.ready_start();
if (player->getLocal()) if (player->getLocal())
deckViewContainers.value(player->getId())->setReadyStart(ready); deckViewContainers.value(player->getId())->playerDeckView->setReadyStart(ready);
if (ready) if (ready)
messageLog->logReadyStart(player); messageLog->logReadyStart(player);
else else
@ -953,11 +983,20 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &
Context_DeckSelect deckSelect = context.GetExtension(Context_DeckSelect::ext); Context_DeckSelect deckSelect = context.GetExtension(Context_DeckSelect::ext);
messageLog->logDeckSelect(player, QString::fromStdString(deckSelect.deck_hash()), messageLog->logDeckSelect(player, QString::fromStdString(deckSelect.deck_hash()),
deckSelect.sideboard_size()); deckSelect.sideboard_size());
if (gameInfo.share_decklists_on_load() && deckSelect.has_deck_list() && eventPlayerId != localPlayerId) {
DeckList loader;
loader.loadFromString_Native(QString::fromStdString(deckSelect.deck_list()));
QMapIterator<int, TabbedDeckViewContainer *> i(deckViewContainers);
while (i.hasNext()) {
i.next();
i.value()->addOpponentDeckView(loader, eventPlayerId, player->getName());
}
}
break; break;
} }
case GameEventContext::SET_SIDEBOARD_LOCK: { case GameEventContext::SET_SIDEBOARD_LOCK: {
if (player->getLocal()) if (player->getLocal())
deckViewContainers.value(player->getId())->setSideboardLocked(prop.sideboard_locked()); deckViewContainers.value(player->getId())->playerDeckView->setSideboardLocked(prop.sideboard_locked());
messageLog->logSetSideboardLock(player, prop.sideboard_locked()); messageLog->logSetSideboardLock(player, prop.sideboard_locked());
break; break;
} }
@ -1209,22 +1248,21 @@ Player *TabGame::getActiveLocalPlayer() const
void TabGame::setActiveCard(CardItem *card) void TabGame::setActiveCard(CardItem *card)
{ {
activeCard = card; activeCard = card;
updateCardMenu(card);
} }
void TabGame::updateCardMenu(AbstractCardItem *card) /**
* @param menu The menu to set. Pass in nullptr to set the menu to empty.
*/
void TabGame::setCardMenu(QMenu *menu)
{ {
if (card == nullptr) { if (!aCardMenu) {
return; return;
} }
Player *player;
if ((clients.size() > 1) || !players.contains(localPlayerId)) { if (menu) {
player = card->getOwner(); aCardMenu->setMenu(menu);
} else { } else {
player = players.value(localPlayerId); aCardMenu->setMenu(new QMenu);
}
if (player != nullptr) {
player->updateCardMenu(static_cast<CardItem *>(card));
} }
} }
@ -1249,7 +1287,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;
@ -1281,6 +1319,11 @@ void TabGame::createMenuItems()
gameMenu->addAction(aConcede); gameMenu->addAction(aConcede);
gameMenu->addAction(aFocusChat); gameMenu->addAction(aFocusChat);
gameMenu->addAction(aLeaveGame); gameMenu->addAction(aLeaveGame);
gameMenu->addSeparator();
aCardMenu = gameMenu->addMenu(new QMenu(this));
addTabMenu(gameMenu); addTabMenu(gameMenu);
} }
@ -1299,11 +1342,14 @@ 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);
gameMenu->addAction(aCloseReplay); gameMenu->addAction(aCloseReplay);
aCardMenu = nullptr;
addTabMenu(gameMenu); addTabMenu(gameMenu);
} }

View file

@ -13,6 +13,7 @@
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QMap> #include <QMap>
class TabbedDeckViewContainer;
inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game"); inline Q_LOGGING_CATEGORY(TabGameLog, "tab_game");
class UserListProxy; class UserListProxy;
@ -105,7 +106,7 @@ private:
PhasesToolbar *phasesToolbar; PhasesToolbar *phasesToolbar;
GameScene *scene; GameScene *scene;
GameView *gameView; GameView *gameView;
QMap<int, DeckViewContainer *> deckViewContainers; QMap<int, TabbedDeckViewContainer *> deckViewContainers;
QVBoxLayout *deckViewContainerLayout; QVBoxLayout *deckViewContainerLayout;
QWidget *gamePlayAreaWidget, *deckViewContainerWidget; QWidget *gamePlayAreaWidget, *deckViewContainerWidget;
QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock; QDockWidget *cardInfoDock, *messageLayoutDock, *playerListDock, *replayDock;
@ -118,6 +119,7 @@ private:
*aPlayerListDockVisible, *aPlayerListDockFloating, *aReplayDockVisible, *aReplayDockFloating; *aPlayerListDockVisible, *aPlayerListDockFloating, *aReplayDockVisible, *aReplayDockFloating;
QAction *aFocusChat; QAction *aFocusChat;
QList<QAction *> phaseActions; QList<QAction *> phaseActions;
QAction *aCardMenu;
Player *addPlayer(int playerId, const ServerInfo_User &info); Player *addPlayer(int playerId, const ServerInfo_User &info);
@ -171,7 +173,7 @@ private slots:
void incrementGameTime(); void incrementGameTime();
void adminLockChanged(bool lock); void adminLockChanged(bool lock);
void newCardAdded(AbstractCardItem *card); void newCardAdded(AbstractCardItem *card);
void updateCardMenu(AbstractCardItem *card); void setCardMenu(QMenu *menu);
void actGameInfo(); void actGameInfo();
void actConcede(); void actConcede();
@ -202,6 +204,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 +217,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;
@ -231,15 +236,14 @@ public:
return gameInfo.game_id(); return gameInfo.game_id();
} }
QString getTabText() const override; QString getTabText() const override;
bool getSpectator() const bool isSpectator() const
{ {
return spectator; return spectator;
} }
bool getSpectatorsSeeEverything() const bool isSpectatorsOmniscient() const
{ {
return gameInfo.spectators_omniscient(); return gameInfo.spectators_omniscient();
} }
bool isSpectator();
Player *getActiveLocalPlayer() const; Player *getActiveLocalPlayer() const;
AbstractClient *getClientForPlayer(int playerId) const; AbstractClient *getClientForPlayer(int playerId) const;

View file

@ -2,8 +2,8 @@
#include "../../deck/custom_line_edit.h" #include "../../deck/custom_line_edit.h"
#include "../../dialogs/dlg_manage_sets.h" #include "../../dialogs/dlg_manage_sets.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../game_logic/abstract_client.h"
#include "pb/moderator_commands.pb.h" #include "pb/moderator_commands.pb.h"
#include "pb/response_viewlog_history.pb.h" #include "pb/response_viewlog_history.pb.h"
#include "trice_limits.h" #include "trice_limits.h"

View file

@ -2,11 +2,11 @@
#include "../../deck/custom_line_edit.h" #include "../../deck/custom_line_edit.h"
#include "../../main.h" #include "../../main.h"
#include "../../server/abstract_client.h"
#include "../../server/chat_view/chat_view.h" #include "../../server/chat_view/chat_view.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
#include "../game_logic/abstract_client.h"
#include "../sound_engine.h" #include "../sound_engine.h"
#include "pb/event_user_message.pb.h" #include "pb/event_user_message.pb.h"
#include "pb/serverinfo_user.pb.h" #include "pb/serverinfo_user.pb.h"
@ -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

@ -1,9 +1,9 @@
#include "tab_replays.h" #include "tab_replays.h"
#include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/remote/remote_replay_list_tree_widget.h" #include "../../server/remote/remote_replay_list_tree_widget.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
#include "../game_logic/abstract_client.h"
#include "pb/command_replay_delete_match.pb.h" #include "pb/command_replay_delete_match.pb.h"
#include "pb/command_replay_download.pb.h" #include "pb/command_replay_download.pb.h"
#include "pb/command_replay_modify_match.pb.h" #include "pb/command_replay_modify_match.pb.h"
@ -29,6 +29,29 @@
TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo) TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User *currentUserInfo)
: Tab(_tabSupervisor), client(_client) : Tab(_tabSupervisor), client(_client)
{
leftGroupBox = createLeftLayout();
rightGroupBox = createRightLayout();
// combine layouts
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(leftGroupBox);
hbox->addWidget(rightGroupBox);
retranslateUi();
QWidget *mainWidget = new QWidget(this);
mainWidget->setLayout(hbox);
setCentralWidget(mainWidget);
connect(client, &AbstractClient::replayAddedEventReceived, this, &TabReplays::replayAddedEventReceived);
connect(client, &AbstractClient::userInfoChanged, this, &TabReplays::handleConnected);
connect(client, &AbstractClient::statusChanged, this, &TabReplays::handleConnectionChanged);
setRemoteEnabled(currentUserInfo && currentUserInfo->user_level() & ServerInfo_User::IsRegistered);
}
QGroupBox *TabReplays::createLeftLayout()
{ {
localDirModel = new QFileSystemModel(this); localDirModel = new QFileSystemModel(this);
localDirModel->setRootPath(SettingsCache::instance().getReplaysPath()); localDirModel->setRootPath(SettingsCache::instance().getReplaysPath());
@ -52,46 +75,24 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
dummyToolBar->setSizePolicy(sizePolicy); dummyToolBar->setSizePolicy(sizePolicy);
dummyToolBar->setVisible(false); dummyToolBar->setVisible(false);
leftToolBar = new QToolBar(this); QToolBar *toolBar = new QToolBar(this);
leftToolBar->setOrientation(Qt::Horizontal); toolBar->setOrientation(Qt::Horizontal);
leftToolBar->setIconSize(QSize(32, 32)); toolBar->setIconSize(QSize(32, 32));
QToolBar *leftRightmostToolBar = new QToolBar(this); QToolBar *rightmostToolBar = new QToolBar(this);
leftRightmostToolBar->setOrientation(Qt::Horizontal); rightmostToolBar->setOrientation(Qt::Horizontal);
leftRightmostToolBar->setIconSize(QSize(32, 32)); rightmostToolBar->setIconSize(QSize(32, 32));
QGridLayout *leftToolBarLayout = new QGridLayout; QGridLayout *toolBarLayout = new QGridLayout;
leftToolBarLayout->addWidget(dummyToolBar, 0, 0, Qt::AlignLeft); toolBarLayout->addWidget(dummyToolBar, 0, 0, Qt::AlignLeft);
leftToolBarLayout->addWidget(leftToolBar, 0, 1, Qt::AlignHCenter); toolBarLayout->addWidget(toolBar, 0, 1, Qt::AlignHCenter);
leftToolBarLayout->addWidget(leftRightmostToolBar, 0, 2, Qt::AlignRight); toolBarLayout->addWidget(rightmostToolBar, 0, 2, Qt::AlignRight);
QVBoxLayout *leftVbox = new QVBoxLayout; QVBoxLayout *vbox = new QVBoxLayout;
leftVbox->addWidget(localDirView); vbox->addWidget(localDirView);
leftVbox->addLayout(leftToolBarLayout); vbox->addLayout(toolBarLayout);
leftGroupBox = new QGroupBox; QGroupBox *groupBox = new QGroupBox;
leftGroupBox->setLayout(leftVbox); groupBox->setLayout(vbox);
// Right side layout
rightToolBar = new QToolBar;
rightToolBar->setOrientation(Qt::Horizontal);
rightToolBar->setIconSize(QSize(32, 32));
QHBoxLayout *rightToolBarLayout = new QHBoxLayout;
rightToolBarLayout->addStretch();
rightToolBarLayout->addWidget(rightToolBar);
rightToolBarLayout->addStretch();
serverDirView = new RemoteReplayList_TreeWidget(client);
QVBoxLayout *rightVbox = new QVBoxLayout;
rightVbox->addWidget(serverDirView);
rightVbox->addLayout(rightToolBarLayout);
rightGroupBox = new QGroupBox;
rightGroupBox->setLayout(rightVbox);
// combine layouts
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(leftGroupBox);
hbox->addWidget(rightGroupBox);
// Left side actions // Left side actions
aOpenLocalReplay = new QAction(this); aOpenLocalReplay = new QAction(this);
@ -112,6 +113,36 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
aOpenReplaysFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_DirOpenIcon)); aOpenReplaysFolder->setIcon(qApp->style()->standardIcon(QStyle::SP_DirOpenIcon));
connect(aOpenReplaysFolder, &QAction::triggered, this, &TabReplays::actOpenReplaysFolder); connect(aOpenReplaysFolder, &QAction::triggered, this, &TabReplays::actOpenReplaysFolder);
// Add actions to toolbars
toolBar->addAction(aOpenLocalReplay);
toolBar->addAction(aRenameLocal);
toolBar->addAction(aNewLocalFolder);
toolBar->addAction(aDeleteLocalReplay);
rightmostToolBar->addAction(aOpenReplaysFolder);
return groupBox;
}
QGroupBox *TabReplays::createRightLayout()
{
serverDirView = new RemoteReplayList_TreeWidget(client);
// Right side layout
QToolBar *toolBar = new QToolBar;
toolBar->setOrientation(Qt::Horizontal);
toolBar->setIconSize(QSize(32, 32));
QHBoxLayout *toolBarLayout = new QHBoxLayout;
toolBarLayout->addStretch();
toolBarLayout->addWidget(toolBar);
toolBarLayout->addStretch();
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(serverDirView);
vbox->addLayout(toolBarLayout);
QGroupBox *groupBox = new QGroupBox;
groupBox->setLayout(vbox);
// Right side actions // Right side actions
aOpenRemoteReplay = new QAction(this); aOpenRemoteReplay = new QAction(this);
aOpenRemoteReplay->setIcon(QPixmap("theme:icons/view")); aOpenRemoteReplay->setIcon(QPixmap("theme:icons/view"));
@ -128,29 +159,12 @@ TabReplays::TabReplays(TabSupervisor *_tabSupervisor, AbstractClient *_client, c
connect(aDeleteRemoteReplay, &QAction::triggered, this, &TabReplays::actDeleteRemoteReplay); connect(aDeleteRemoteReplay, &QAction::triggered, this, &TabReplays::actDeleteRemoteReplay);
// Add actions to toolbars // Add actions to toolbars
leftToolBar->addAction(aOpenLocalReplay); toolBar->addAction(aOpenRemoteReplay);
leftToolBar->addAction(aRenameLocal); toolBar->addAction(aDownload);
leftToolBar->addAction(aNewLocalFolder); toolBar->addAction(aKeep);
leftToolBar->addAction(aDeleteLocalReplay); toolBar->addAction(aDeleteRemoteReplay);
leftRightmostToolBar->addAction(aOpenReplaysFolder); return groupBox;
rightToolBar->addAction(aOpenRemoteReplay);
rightToolBar->addAction(aDownload);
rightToolBar->addAction(aKeep);
rightToolBar->addAction(aDeleteRemoteReplay);
retranslateUi();
QWidget *mainWidget = new QWidget(this);
mainWidget->setLayout(hbox);
setCentralWidget(mainWidget);
connect(client, &AbstractClient::replayAddedEventReceived, this, &TabReplays::replayAddedEventReceived);
connect(client, &AbstractClient::userInfoChanged, this, &TabReplays::handleConnected);
connect(client, &AbstractClient::statusChanged, this, &TabReplays::handleConnectionChanged);
setRemoteEnabled(currentUserInfo && currentUserInfo->user_level() & ServerInfo_User::IsRegistered);
} }
void TabReplays::retranslateUi() void TabReplays::retranslateUi()

View file

@ -1,7 +1,7 @@
#ifndef TAB_REPLAYS_H #ifndef TAB_REPLAYS_H
#define TAB_REPLAYS_H #define TAB_REPLAYS_H
#include "../game_logic/abstract_client.h" #include "../../server/abstract_client.h"
#include "tab.h" #include "tab.h"
class ServerInfo_User; class ServerInfo_User;
@ -23,7 +23,6 @@ private:
AbstractClient *client; AbstractClient *client;
QTreeView *localDirView; QTreeView *localDirView;
QFileSystemModel *localDirModel; QFileSystemModel *localDirModel;
QToolBar *leftToolBar, *rightToolBar;
RemoteReplayList_TreeWidget *serverDirView; RemoteReplayList_TreeWidget *serverDirView;
QGroupBox *leftGroupBox, *rightGroupBox; QGroupBox *leftGroupBox, *rightGroupBox;
@ -31,6 +30,9 @@ private:
QAction *aOpenReplaysFolder; QAction *aOpenReplaysFolder;
QAction *aOpenRemoteReplay, *aDownload, *aKeep, *aDeleteRemoteReplay; QAction *aOpenRemoteReplay, *aDownload, *aKeep, *aDeleteRemoteReplay;
QGroupBox *createLeftLayout();
QGroupBox *createRightLayout();
void setRemoteEnabled(bool enabled); void setRemoteEnabled(bool enabled);
void downloadNodeAtIndex(const QModelIndex &curLeft, const QModelIndex &curRight); void downloadNodeAtIndex(const QModelIndex &curLeft, const QModelIndex &curRight);

View file

@ -1,9 +1,9 @@
#include "tab_room.h" #include "tab_room.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../dialogs/dlg_settings.h" #include "../../dialogs/dlg_settings.h"
#include "../../game/game_selector.h" #include "../../game/game_selector.h"
#include "../../main.h" #include "../../main.h"
#include "../../server/abstract_client.h"
#include "../../server/chat_view/chat_view.h" #include "../../server/chat_view/chat_view.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
@ -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

@ -1,6 +1,6 @@
#include "tab_server.h" #include "tab_server.h"
#include "../../client/game_logic/abstract_client.h" #include "../../server/abstract_client.h"
#include "../../server/pending_command.h" #include "../../server/pending_command.h"
#include "../../server/user/user_list_widget.h" #include "../../server/user/user_list_widget.h"
#include "pb/event_list_rooms.pb.h" #include "pb/event_list_rooms.pb.h"

View file

@ -1,7 +1,7 @@
#include "tab_supervisor.h" #include "tab_supervisor.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../main.h" #include "../../main.h"
#include "../../server/abstract_client.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../../server/user/user_list_widget.h" #include "../../server/user/user_list_widget.h"
#include "../../settings/cache_settings.h" #include "../../settings/cache_settings.h"
@ -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

@ -11,6 +11,7 @@
#include <QNetworkDiskCache> #include <QNetworkDiskCache>
#include <QNetworkReply> #include <QNetworkReply>
#include <QThread> #include <QThread>
#include <QThreadPool>
// Card back returned by gatherer when card is not found // Card back returned by gatherer when card is not found
static const QStringList MD5_BLACKLIST = {"db0c48db407a907c16ade38de048a441"}; static const QStringList MD5_BLACKLIST = {"db0c48db407a907c16ade38de048a441"};
@ -28,16 +29,7 @@ PictureLoaderWorkerWork::PictureLoaderWorkerWork(const PictureLoaderWorker *work
// Hook up signals to settings // Hook up signals to settings
connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged())); connect(&SettingsCache::instance(), SIGNAL(picDownloadChanged()), this, SLOT(picDownloadChanged()));
pictureLoaderThread = new QThread; startNextPicDownload();
moveToThread(pictureLoaderThread);
connect(pictureLoaderThread, &QThread::started, this, &PictureLoaderWorkerWork::startNextPicDownload);
// clean up threads once loading finishes
connect(this, &QObject::destroyed, pictureLoaderThread, &QThread::quit);
connect(pictureLoaderThread, &QThread::finished, pictureLoaderThread, &QObject::deleteLater);
pictureLoaderThread->start(QThread::LowPriority);
} }
void PictureLoaderWorkerWork::startNextPicDownload() void PictureLoaderWorkerWork::startNextPicDownload()

View file

@ -33,7 +33,6 @@ public slots:
void handleNetworkReply(QNetworkReply *reply); void handleNetworkReply(QNetworkReply *reply);
private: private:
QThread *pictureLoaderThread;
bool picDownload; bool picDownload;
void startNextPicDownload(); void startNextPicDownload();

View file

@ -3,7 +3,7 @@
#include "../../../../deck/custom_line_edit.h" #include "../../../../deck/custom_line_edit.h"
#include "../../../../game/cards/card_database_model.h" #include "../../../../game/cards/card_database_model.h"
#include "../../../game_logic/key_signals.h" #include "../../../../utility/key_signals.h"
#include "../../../tabs/abstract_tab_deck_editor.h" #include "../../../tabs/abstract_tab_deck_editor.h"
#include <QHBoxLayout> #include <QHBoxLayout>

View file

@ -3,7 +3,7 @@
#include "../../../../deck/custom_line_edit.h" #include "../../../../deck/custom_line_edit.h"
#include "../../../../game/cards/card_info.h" #include "../../../../game/cards/card_info.h"
#include "../../../game_logic/key_signals.h" #include "../../../../utility/key_signals.h"
#include "../../../tabs/abstract_tab_deck_editor.h" #include "../../../tabs/abstract_tab_deck_editor.h"
#include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h" #include "../visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"

View file

@ -1,7 +1,7 @@
#ifndef DECK_EDITOR_FILTER_DOCK_WIDGET_H #ifndef DECK_EDITOR_FILTER_DOCK_WIDGET_H
#define DECK_EDITOR_FILTER_DOCK_WIDGET_H #define DECK_EDITOR_FILTER_DOCK_WIDGET_H
#include "../../../game_logic/key_signals.h" #include "../../../../utility/key_signals.h"
#include "../../../tabs/abstract_tab_deck_editor.h" #include "../../../tabs/abstract_tab_deck_editor.h"
#include <QDockWidget> #include <QDockWidget>

View file

@ -140,16 +140,22 @@ void CardAmountWidget::updateCardCount()
*/ */
void CardAmountWidget::addPrinting(const QString &zone) void CardAmountWidget::addPrinting(const QString &zone)
{ {
// Add the card and expand the list UI
auto newCardIndex = deckModel->addCard(rootCard, zone); auto newCardIndex = deckModel->addCard(rootCard, zone);
recursiveExpand(newCardIndex); recursiveExpand(newCardIndex);
// Check if a card without a providerId already exists in the deckModel and replace it, if so.
QModelIndex find_card = deckModel->findCard(rootCard.getName(), zone); QModelIndex find_card = deckModel->findCard(rootCard.getName(), zone);
if (find_card.isValid() && find_card != newCardIndex) { QString foundProviderId = deckModel->data(find_card.sibling(find_card.row(), 4), Qt::DisplayRole).toString();
if (find_card.isValid() && find_card != newCardIndex && foundProviderId == "") {
auto amount = deckModel->data(find_card, Qt::DisplayRole); auto amount = deckModel->data(find_card, Qt::DisplayRole);
for (int i = 0; i < amount.toInt() - 1; i++) { for (int i = 0; i < amount.toInt() - 1; i++) {
deckModel->addCard(rootCard, zone); deckModel->addCard(rootCard, zone);
} }
deckModel->removeRow(find_card.row(), find_card.parent()); deckModel->removeRow(find_card.row(), find_card.parent());
} }
// Set Index and Focus as if the user had just clicked the new card and modify the deckEditor saveState
newCardIndex = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(), newCardIndex = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
rootCard.getPrinting().getProperty("num")); rootCard.getPrinting().getProperty("num"));
deckView->setCurrentIndex(newCardIndex); deckView->setCurrentIndex(newCardIndex);

View file

@ -6,7 +6,7 @@
#include "../../../../game/cards/card_database.h" #include "../../../../game/cards/card_database.h"
#include "../../../../game/cards/card_database_model.h" #include "../../../../game/cards/card_database_model.h"
#include "../../../../game/filters/filter_tree_model.h" #include "../../../../game/filters/filter_tree_model.h"
#include "../../../game_logic/key_signals.h" #include "../../../../utility/key_signals.h"
#include "../../../tabs/abstract_tab_deck_editor.h" #include "../../../tabs/abstract_tab_deck_editor.h"
#include "../../layouts/flow_layout.h" #include "../../layouts/flow_layout.h"
#include "../cards/card_info_picture_with_text_overlay_widget.h" #include "../cards/card_info_picture_with_text_overlay_widget.h"

View file

@ -20,7 +20,7 @@
#ifndef WINDOW_H #ifndef WINDOW_H
#define WINDOW_H #define WINDOW_H
#include "../game_logic/abstract_client.h" #include "../../server/abstract_client.h"
#include "pb/response.pb.h" #include "pb/response.pb.h"
#include <QList> #include <QList>

View file

@ -397,6 +397,7 @@ void DeckLoader::clearSetNamesAndNumbers()
// Set the providerId on the card // Set the providerId on the card
card->setCardSetShortName(nullptr); card->setCardSetShortName(nullptr);
card->setCardCollectorNumber(nullptr); card->setCardCollectorNumber(nullptr);
card->setCardProviderId(nullptr);
}; };
forEachCard(clearSetNameAndNumber); forEachCard(clearSetNameAndNumber);

View file

@ -102,9 +102,15 @@ void DlgCreateGame::sharedCtor()
startingLifeTotalEdit->setValue(20); startingLifeTotalEdit->setValue(20);
startingLifeTotalLabel->setBuddy(startingLifeTotalEdit); startingLifeTotalLabel->setBuddy(startingLifeTotalEdit);
shareDecklistsOnLoadLabel = new QLabel(tr("Open decklists in lobby"));
shareDecklistsOnLoadCheckBox = new QCheckBox();
shareDecklistsOnLoadLabel->setBuddy(shareDecklistsOnLoadCheckBox);
QGridLayout *gameSetupOptionsLayout = new QGridLayout; QGridLayout *gameSetupOptionsLayout = new QGridLayout;
gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0); gameSetupOptionsLayout->addWidget(startingLifeTotalLabel, 0, 0);
gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1); gameSetupOptionsLayout->addWidget(startingLifeTotalEdit, 0, 1);
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadLabel, 1, 0);
gameSetupOptionsLayout->addWidget(shareDecklistsOnLoadCheckBox, 1, 1);
gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options")); gameSetupOptionsGroupBox = new QGroupBox(tr("Game setup options"));
gameSetupOptionsGroupBox->setLayout(gameSetupOptionsLayout); gameSetupOptionsGroupBox->setLayout(gameSetupOptionsLayout);
@ -149,6 +155,7 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameType
spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything()); spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything());
createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator()); createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator());
startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal()); startingLifeTotalEdit->setValue(SettingsCache::instance().getDefaultStartingLifeTotal());
shareDecklistsOnLoadCheckBox->setChecked(SettingsCache::instance().getShareDecklistsOnLoad());
if (!rememberGameSettings->isChecked()) { if (!rememberGameSettings->isChecked()) {
actReset(); actReset();
@ -181,6 +188,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMap<int, QS
spectatorsSeeEverythingCheckBox->setEnabled(false); spectatorsSeeEverythingCheckBox->setEnabled(false);
createGameAsSpectatorCheckBox->setEnabled(false); createGameAsSpectatorCheckBox->setEnabled(false);
startingLifeTotalEdit->setEnabled(false); startingLifeTotalEdit->setEnabled(false);
shareDecklistsOnLoadCheckBox->setEnabled(false);
descriptionEdit->setText(QString::fromStdString(gameInfo.description())); descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
maxPlayersEdit->setValue(gameInfo.max_players()); maxPlayersEdit->setValue(gameInfo.max_players());
@ -225,6 +233,7 @@ void DlgCreateGame::actReset()
createGameAsSpectatorCheckBox->setChecked(false); createGameAsSpectatorCheckBox->setChecked(false);
startingLifeTotalEdit->setValue(20); startingLifeTotalEdit->setValue(20);
shareDecklistsOnLoadCheckBox->setChecked(false);
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes); QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
while (gameTypeCheckBoxIterator.hasNext()) { while (gameTypeCheckBoxIterator.hasNext()) {
@ -253,6 +262,7 @@ void DlgCreateGame::actOK()
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier); cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked()); cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
cmd.set_starting_life_total(startingLifeTotalEdit->value()); cmd.set_starting_life_total(startingLifeTotalEdit->value());
cmd.set_share_decklists_on_load(shareDecklistsOnLoadCheckBox->isChecked());
QString _gameTypes = QString(); QString _gameTypes = QString();
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes); QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
@ -276,6 +286,7 @@ void DlgCreateGame::actOK()
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked()); SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked()); SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value()); SettingsCache::instance().setDefaultStartingLifeTotal(startingLifeTotalEdit->value());
SettingsCache::instance().setShareDecklistsOnLoad(shareDecklistsOnLoadCheckBox->isChecked());
SettingsCache::instance().setGameTypes(_gameTypes); SettingsCache::instance().setGameTypes(_gameTypes);
} }
PendingCommand *pend = room->prepareRoomCommand(cmd); PendingCommand *pend = room->prepareRoomCommand(cmd);

View file

@ -36,12 +36,13 @@ private:
QMap<int, QRadioButton *> gameTypeCheckBoxes; QMap<int, QRadioButton *> gameTypeCheckBoxes;
QGroupBox *generalGroupBox, *spectatorsGroupBox, *gameSetupOptionsGroupBox; QGroupBox *generalGroupBox, *spectatorsGroupBox, *gameSetupOptionsGroupBox;
QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel, *startingLifeTotalLabel; QLabel *descriptionLabel, *passwordLabel, *maxPlayersLabel, *startingLifeTotalLabel, *shareDecklistsOnLoadLabel;
QLineEdit *descriptionEdit, *passwordEdit; QLineEdit *descriptionEdit, *passwordEdit;
QSpinBox *maxPlayersEdit, *startingLifeTotalEdit; QSpinBox *maxPlayersEdit, *startingLifeTotalEdit;
QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox; QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox;
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox, QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
*spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox; *spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox;
QCheckBox *shareDecklistsOnLoadCheckBox;
QDialogButtonBox *buttonBox; QDialogButtonBox *buttonBox;
QPushButton *clearButton; QPushButton *clearButton;
QCheckBox *rememberGameSettings; QCheckBox *rememberGameSettings;

View file

@ -198,7 +198,16 @@ void DlgCreateToken::tokenSelectionChanged(const QModelIndex &current, const QMo
annotationEdit->setText(""); annotationEdit->setText("");
} }
pic->setCard(CardDatabaseManager::getInstance()->getPreferredCard(cardInfo)); const auto &cardProviderId =
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName());
if (!cardProviderId.isEmpty()) {
CardRef ref;
ref.name = cardInfo->getName();
ref.providerId = cardProviderId;
pic->setCard(CardDatabaseManager::getInstance()->getCard(ref));
} else {
pic->setCard(CardDatabaseManager::getInstance()->getPreferredCard(cardInfo));
}
} }
void DlgCreateToken::updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const void DlgCreateToken::updateSearchFieldWithoutUpdatingFilter(const QString &newValue) const
@ -250,5 +259,6 @@ TokenInfo DlgCreateToken::getTokenInfo() const
.pt = ptEdit->text(), .pt = ptEdit->text(),
.annotation = annotationEdit->text(), .annotation = annotationEdit->text(),
.destroy = destroyCheckBox->isChecked(), .destroy = destroyCheckBox->isChecked(),
.faceDown = faceDownCheckBox->isChecked()}; .faceDown = faceDownCheckBox->isChecked(),
.providerId = SettingsCache::instance().cardOverrides().getCardPreferenceOverride(nameEdit->text())};
} }

View file

@ -25,6 +25,7 @@ struct TokenInfo
QString annotation; QString annotation;
bool destroy = true; bool destroy = true;
bool faceDown = false; bool faceDown = false;
QString providerId;
}; };
class DlgCreateToken : public QDialog class DlgCreateToken : public QDialog

View file

@ -40,6 +40,9 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddy")); hideNotBuddyCreatedGames = new QCheckBox(tr("Hide games not created by buddy"));
hideNotBuddyCreatedGames->setChecked(gamesProxyModel->getHideNotBuddyCreatedGames()); hideNotBuddyCreatedGames->setChecked(gamesProxyModel->getHideNotBuddyCreatedGames());
hideOpenDecklistGames = new QCheckBox(tr("Hide games with forced open decklists"));
hideOpenDecklistGames->setChecked(gamesProxyModel->getHideOpenDecklistGames());
maxGameAgeComboBox = new QComboBox(); maxGameAgeComboBox = new QComboBox();
maxGameAgeComboBox->setEditable(false); maxGameAgeComboBox->setEditable(false);
maxGameAgeComboBox->addItems(gameAgeMap.values()); maxGameAgeComboBox->addItems(gameAgeMap.values());
@ -115,6 +118,7 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
restrictionsLayout->addWidget(hideBuddiesOnlyGames, 3, 0); restrictionsLayout->addWidget(hideBuddiesOnlyGames, 3, 0);
restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0); restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0);
restrictionsLayout->addWidget(hideNotBuddyCreatedGames, 5, 0); restrictionsLayout->addWidget(hideNotBuddyCreatedGames, 5, 0);
restrictionsLayout->addWidget(hideOpenDecklistGames, 6, 0);
auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions")); auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
restrictionsGroupBox->setLayout(restrictionsLayout); restrictionsGroupBox->setLayout(restrictionsLayout);
@ -218,6 +222,11 @@ bool DlgFilterGames::getHideNotBuddyCreatedGames() const
return hideNotBuddyCreatedGames->isChecked(); return hideNotBuddyCreatedGames->isChecked();
} }
bool DlgFilterGames::getHideOpenDecklistGames() const
{
return hideOpenDecklistGames->isChecked();
}
QString DlgFilterGames::getGameNameFilter() const QString DlgFilterGames::getGameNameFilter() const
{ {
return gameNameFilterEdit->text(); return gameNameFilterEdit->text();

View file

@ -27,6 +27,7 @@ private:
QCheckBox *hidePasswordProtectedGames; QCheckBox *hidePasswordProtectedGames;
QCheckBox *hideIgnoredUserGames; QCheckBox *hideIgnoredUserGames;
QCheckBox *hideNotBuddyCreatedGames; QCheckBox *hideNotBuddyCreatedGames;
QCheckBox *hideOpenDecklistGames;
QLineEdit *gameNameFilterEdit; QLineEdit *gameNameFilterEdit;
QLineEdit *creatorNameFilterEdit; QLineEdit *creatorNameFilterEdit;
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes; QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
@ -57,6 +58,8 @@ public:
void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden); void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden);
bool getHideBuddiesOnlyGames() const; bool getHideBuddiesOnlyGames() const;
void setHideBuddiesOnlyGames(bool _hideBuddiesOnlyGames); void setHideBuddiesOnlyGames(bool _hideBuddiesOnlyGames);
bool getHideOpenDecklistGames() const;
void setHideOpenDecklistGames(bool _hideOpenDecklistGames);
bool getHideIgnoredUserGames() const; bool getHideIgnoredUserGames() const;
void setHideIgnoredUserGames(bool _hideIgnoredUserGames); void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
bool getHideNotBuddyCreatedGames() const; bool getHideNotBuddyCreatedGames() const;

View file

@ -24,30 +24,17 @@ CardItem::CardItem(Player *_owner, QGraphicsItem *parent, const CardRef &cardRef
{ {
owner->addCard(this); owner->addCard(this);
cardMenu = new QMenu;
ptMenu = new QMenu;
moveMenu = new QMenu;
connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) { connect(&SettingsCache::instance().cardCounters(), &CardCounterSettings::colorChanged, this, [this](int counterId) {
if (counters.contains(counterId)) if (counters.contains(counterId))
update(); update();
}); });
retranslateUi();
}
CardItem::~CardItem()
{
delete cardMenu;
delete ptMenu;
delete moveMenu;
} }
void CardItem::prepareDelete() void CardItem::prepareDelete()
{ {
if (owner != nullptr) { if (owner != nullptr) {
if (owner->getCardMenu() == cardMenu) { if (owner->getGame()->getActiveCard() == this) {
owner->setCardMenu(nullptr); owner->updateCardMenu(nullptr);
owner->getGame()->setActiveCard(nullptr); owner->getGame()->setActiveCard(nullptr);
} }
owner = nullptr; owner = nullptr;
@ -79,8 +66,6 @@ void CardItem::setZone(CardZone *_zone)
void CardItem::retranslateUi() void CardItem::retranslateUi()
{ {
moveMenu->setTitle(tr("&Move to"));
ptMenu->setTitle(tr("&Power / toughness"));
} }
void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) void CardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
@ -274,7 +259,7 @@ void CardItem::deleteDragItem()
void CardItem::drawArrow(const QColor &arrowColor) void CardItem::drawArrow(const QColor &arrowColor)
{ {
if (static_cast<TabGame *>(owner->parent())->getSpectator()) if (static_cast<TabGame *>(owner->parent())->isSpectator())
return; return;
Player *arrowOwner = static_cast<TabGame *>(owner->parent())->getActiveLocalPlayer(); Player *arrowOwner = static_cast<TabGame *>(owner->parent())->getActiveLocalPlayer();
@ -297,7 +282,7 @@ void CardItem::drawArrow(const QColor &arrowColor)
void CardItem::drawAttachArrow() void CardItem::drawAttachArrow()
{ {
if (static_cast<TabGame *>(owner->parent())->getSpectator()) if (static_cast<TabGame *>(owner->parent())->isSpectator())
return; return;
auto *arrow = new ArrowAttachItem(this); auto *arrow = new ArrowAttachItem(this);
@ -422,9 +407,13 @@ void CardItem::handleClickedToPlay(bool shiftHeld)
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::RightButton) { if (event->button() == Qt::RightButton) {
if (cardMenu != nullptr && !cardMenu->isEmpty() && owner != nullptr) {
cardMenu->popup(event->screenPos()); if (owner != nullptr) {
return; owner->getGame()->setActiveCard(this);
if (QMenu *cardMenu = owner->updateCardMenu(this)) {
cardMenu->popup(event->screenPos());
return;
}
} }
} else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) && } else if ((event->modifiers() != Qt::AltModifier) && (event->button() == Qt::LeftButton) &&
(!SettingsCache::instance().getDoubleClickToPlay())) { (!SettingsCache::instance().getDoubleClickToPlay())) {
@ -477,11 +466,11 @@ QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value)
{ {
if ((change == ItemSelectedHasChanged) && owner != nullptr) { if ((change == ItemSelectedHasChanged) && owner != nullptr) {
if (value == true) { if (value == true) {
owner->setCardMenu(cardMenu);
owner->getGame()->setActiveCard(this); owner->getGame()->setActiveCard(this);
} else if (owner->getCardMenu() == cardMenu) { owner->updateCardMenu(this);
owner->setCardMenu(nullptr); } else if (owner->scene()->selectedItems().isEmpty()) {
owner->getGame()->setActiveCard(nullptr); owner->getGame()->setActiveCard(nullptr);
owner->updateCardMenu(nullptr);
} }
} }
return AbstractCardItem::itemChange(change, value); return AbstractCardItem::itemChange(change, value);

View file

@ -33,8 +33,6 @@ private:
CardItem *attachedTo; CardItem *attachedTo;
QList<CardItem *> attachedCards; QList<CardItem *> attachedCards;
QMenu *cardMenu, *ptMenu, *moveMenu;
void prepareDelete(); void prepareDelete();
void handleClickedToPlay(bool shiftHeld); void handleClickedToPlay(bool shiftHeld);
public slots: public slots:
@ -54,7 +52,7 @@ public:
const CardRef &cardRef = {}, const CardRef &cardRef = {},
int _cardid = -1, int _cardid = -1,
CardZone *_zone = nullptr); CardZone *_zone = nullptr);
~CardItem() override;
void retranslateUi(); void retranslateUi();
CardZone *getZone() const CardZone *getZone() const
{ {
@ -135,19 +133,6 @@ public:
void resetState(bool keepAnnotations = false); void resetState(bool keepAnnotations = false);
void processCardInfo(const ServerInfo_Card &_info); void processCardInfo(const ServerInfo_Card &_info);
QMenu *getCardMenu() const
{
return cardMenu;
}
QMenu *getPTMenu() const
{
return ptMenu;
}
QMenu *getMoveMenu() const
{
return moveMenu;
}
bool animationEvent(); bool animationEvent();
CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown); CardDragItem *createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown);
void deleteDragItem(); void deleteDragItem();

View file

@ -458,6 +458,12 @@ bool CardDatabase::isPreferredPrinting(const CardRef &cardRef) const
return cardRef.providerId == getPreferredPrintingProviderId(cardRef.name); return cardRef.providerId == getPreferredPrintingProviderId(cardRef.name);
} }
ExactCard CardDatabase::getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const
{
PrintingInfo relatedPrinting = getSpecificPrinting(cardName, otherPrinting.getSet()->getCorrectedShortName(), "");
return ExactCard(guessCard({cardName}).getCardPtr(), relatedPrinting);
}
void CardDatabase::refreshCachedReverseRelatedCards() void CardDatabase::refreshCachedReverseRelatedCards()
{ {
for (const CardInfoPtr &card : cards) for (const CardInfoPtr &card : cards)

View file

@ -82,6 +82,7 @@ public:
getSpecificPrinting(const QString &cardName, const QString &setShortName, const QString &collectorNumber) const; getSpecificPrinting(const QString &cardName, const QString &setShortName, const QString &collectorNumber) const;
QString getPreferredPrintingProviderId(const QString &cardName) const; QString getPreferredPrintingProviderId(const QString &cardName) const;
bool isPreferredPrinting(const CardRef &cardRef) const; bool isPreferredPrinting(const CardRef &cardRef) const;
ExactCard getCardFromSameSet(const QString &cardName, const PrintingInfo &otherPrinting) const;
[[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const; [[nodiscard]] ExactCard guessCard(const CardRef &cardRef) const;

View file

@ -0,0 +1,64 @@
#include "tabbed_deck_view_container.h"
#include "../../client/tabs/tab_game.h"
#include "deck_view.h"
TabbedDeckViewContainer::TabbedDeckViewContainer(int _playerId, TabGame *parent)
: QTabWidget(nullptr), playerId(_playerId), parentGame(parent)
{
setTabsClosable(true);
connect(this, &QTabWidget::tabCloseRequested, this, &TabbedDeckViewContainer::closeTab);
playerDeckView = new DeckViewContainer(playerId, parentGame);
int playerTabIndex = addTab(playerDeckView, "Your Deck");
tabBar()->setTabButton(playerTabIndex, QTabBar::RightSide, nullptr);
updateTabBarVisibility();
}
void TabbedDeckViewContainer::addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName)
{
if (opponentDeckViews.contains(opponentId)) {
opponentDeckViews[opponentId]->setDeck(opponentDeck);
} else {
auto *opponentDeckView = new DeckView(this);
opponentDeckView->setDeck(opponentDeck);
addTab(opponentDeckView, QString("%1's Deck").arg(opponentName));
opponentDeckViews.insert(opponentId, opponentDeckView);
}
updateTabBarVisibility();
}
void TabbedDeckViewContainer::closeTab(int index)
{
QWidget *widgetToClose = widget(index);
// Prevent removing the player tab
if (widgetToClose == playerDeckView) {
return;
}
// Remove it from map if it's an opponent
auto it = opponentDeckViews.begin();
while (it != opponentDeckViews.end()) {
if (it.value() == widgetToClose) {
it = opponentDeckViews.erase(it);
} else {
++it;
}
}
removeTab(index);
widgetToClose->deleteLater();
updateTabBarVisibility();
}
void TabbedDeckViewContainer::updateTabBarVisibility()
{
if (tabBar()->count() <= 1) {
tabBar()->hide();
} else {
tabBar()->show();
}
}

View file

@ -0,0 +1,23 @@
#ifndef TABBED_DECK_VIEW_CONTAINER_H
#define TABBED_DECK_VIEW_CONTAINER_H
#include "deck_view_container.h"
#include <QTabWidget>
class TabbedDeckViewContainer : public QTabWidget
{
Q_OBJECT
public:
explicit TabbedDeckViewContainer(int _playerId, TabGame *parent);
void closeTab(int index);
void updateTabBarVisibility();
void addOpponentDeckView(const DeckList &opponentDeck, int opponentId, QString opponentName);
int playerId;
TabGame *parentGame;
DeckViewContainer *playerDeckView;
QMap<int, DeckView *> opponentDeckViews;
};
#endif // TABBED_DECK_VIEW_CONTAINER_H

View file

@ -1,6 +1,5 @@
#include "game_selector.h" #include "game_selector.h"
#include "../client/game_logic/abstract_client.h"
#include "../client/get_text_with_max.h" #include "../client/get_text_with_max.h"
#include "../client/tabs/tab_account.h" #include "../client/tabs/tab_account.h"
#include "../client/tabs/tab_game.h" #include "../client/tabs/tab_game.h"
@ -8,6 +7,7 @@
#include "../client/tabs/tab_supervisor.h" #include "../client/tabs/tab_supervisor.h"
#include "../dialogs/dlg_create_game.h" #include "../dialogs/dlg_create_game.h"
#include "../dialogs/dlg_filter_games.h" #include "../dialogs/dlg_filter_games.h"
#include "../server/abstract_client.h"
#include "../server/pending_command.h" #include "../server/pending_command.h"
#include "../server/user/user_list_manager.h" #include "../server/user/user_list_manager.h"
#include "games_model.h" #include "games_model.h"
@ -161,6 +161,7 @@ void GameSelector::actSetFilter()
gameListProxyModel->setHidePasswordProtectedGames(dlg.getHidePasswordProtectedGames()); gameListProxyModel->setHidePasswordProtectedGames(dlg.getHidePasswordProtectedGames());
gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames()); gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames());
gameListProxyModel->setHideNotBuddyCreatedGames(dlg.getHideNotBuddyCreatedGames()); gameListProxyModel->setHideNotBuddyCreatedGames(dlg.getHideNotBuddyCreatedGames());
gameListProxyModel->setHideOpenDecklistGames(dlg.getHideOpenDecklistGames());
gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter()); gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter());
gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter()); gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter());
gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter()); gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter());

View file

@ -153,6 +153,8 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
result.append(tr("buddies only")); result.append(tr("buddies only"));
if (gameentry.only_registered()) if (gameentry.only_registered())
result.append(tr("reg. users only")); result.append(tr("reg. users only"));
if (gameentry.share_decklists_on_load())
result.append(tr("open decklists"));
return result.join(", "); return result.join(", ");
} }
case Qt::DecorationRole: { case Qt::DecorationRole: {
@ -320,6 +322,12 @@ void GamesProxyModel::setHideNotBuddyCreatedGames(bool value)
invalidateFilter(); invalidateFilter();
} }
void GamesProxyModel::setHideOpenDecklistGames(bool _hideOpenDecklistGames)
{
hideOpenDecklistGames = _hideOpenDecklistGames;
invalidateFilter();
}
void GamesProxyModel::setGameNameFilter(const QString &_gameNameFilter) void GamesProxyModel::setGameNameFilter(const QString &_gameNameFilter)
{ {
gameNameFilter = _gameNameFilter; gameNameFilter = _gameNameFilter;
@ -398,6 +406,7 @@ void GamesProxyModel::resetFilterParameters()
hideBuddiesOnlyGames = false; hideBuddiesOnlyGames = false;
hideIgnoredUserGames = false; hideIgnoredUserGames = false;
hideNotBuddyCreatedGames = false; hideNotBuddyCreatedGames = false;
hideOpenDecklistGames = false;
gameNameFilter = QString(); gameNameFilter = QString();
creatorNameFilter = QString(); creatorNameFilter = QString();
gameTypeFilter.clear(); gameTypeFilter.clear();
@ -415,7 +424,7 @@ void GamesProxyModel::resetFilterParameters()
bool GamesProxyModel::areFilterParametersSetToDefaults() const bool GamesProxyModel::areFilterParametersSetToDefaults() const
{ {
return !hideFullGames && !hideGamesThatStarted && !hidePasswordProtectedGames && !hideBuddiesOnlyGames && return !hideFullGames && !hideGamesThatStarted && !hidePasswordProtectedGames && !hideBuddiesOnlyGames &&
!hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() && !hideOpenDecklistGames && !hideIgnoredUserGames && !hideNotBuddyCreatedGames && gameNameFilter.isEmpty() &&
creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN && creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE && maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE &&
!showOnlyIfSpectatorsCanWatch && !showSpectatorPasswordProtected && !showOnlyIfSpectatorsCanChat && !showOnlyIfSpectatorsCanWatch && !showSpectatorPasswordProtected && !showOnlyIfSpectatorsCanChat &&
@ -431,6 +440,7 @@ void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameType
hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames(); hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames();
hideBuddiesOnlyGames = gameFilters.isHideBuddiesOnlyGames(); hideBuddiesOnlyGames = gameFilters.isHideBuddiesOnlyGames();
hideNotBuddyCreatedGames = gameFilters.isHideNotBuddyCreatedGames(); hideNotBuddyCreatedGames = gameFilters.isHideNotBuddyCreatedGames();
hideOpenDecklistGames = gameFilters.isHideOpenDecklistGames();
gameNameFilter = gameFilters.getGameNameFilter(); gameNameFilter = gameFilters.getGameNameFilter();
creatorNameFilter = gameFilters.getCreatorNameFilter(); creatorNameFilter = gameFilters.getCreatorNameFilter();
maxPlayersFilterMin = gameFilters.getMinPlayers(); maxPlayersFilterMin = gameFilters.getMinPlayers();
@ -461,6 +471,7 @@ void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameType
gameFilters.setHidePasswordProtectedGames(hidePasswordProtectedGames); gameFilters.setHidePasswordProtectedGames(hidePasswordProtectedGames);
gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames); gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames);
gameFilters.setHideNotBuddyCreatedGames(hideNotBuddyCreatedGames); gameFilters.setHideNotBuddyCreatedGames(hideNotBuddyCreatedGames);
gameFilters.setHideOpenDecklistGames(hideOpenDecklistGames);
gameFilters.setGameNameFilter(gameNameFilter); gameFilters.setGameNameFilter(gameNameFilter);
gameFilters.setCreatorNameFilter(creatorNameFilter); gameFilters.setCreatorNameFilter(creatorNameFilter);
@ -504,6 +515,9 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
if (hideBuddiesOnlyGames && game.only_buddies()) { if (hideBuddiesOnlyGames && game.only_buddies()) {
return false; return false;
} }
if (hideOpenDecklistGames && game.share_decklists_on_load()) {
return false;
}
if (hideIgnoredUserGames && userListProxy->isUserIgnored(QString::fromStdString(game.creator_info().name()))) { if (hideIgnoredUserGames && userListProxy->isUserIgnored(QString::fromStdString(game.creator_info().name()))) {
return false; return false;
} }

View file

@ -81,6 +81,7 @@ private:
bool hideGamesThatStarted; bool hideGamesThatStarted;
bool hidePasswordProtectedGames; bool hidePasswordProtectedGames;
bool hideNotBuddyCreatedGames; bool hideNotBuddyCreatedGames;
bool hideOpenDecklistGames;
QString gameNameFilter, creatorNameFilter; QString gameNameFilter, creatorNameFilter;
QSet<int> gameTypeFilter; QSet<int> gameTypeFilter;
quint32 maxPlayersFilterMin, maxPlayersFilterMax; quint32 maxPlayersFilterMin, maxPlayersFilterMax;
@ -121,6 +122,11 @@ public:
return hideNotBuddyCreatedGames; return hideNotBuddyCreatedGames;
} }
void setHideNotBuddyCreatedGames(bool value); void setHideNotBuddyCreatedGames(bool value);
bool getHideOpenDecklistGames() const
{
return hideOpenDecklistGames;
}
void setHideOpenDecklistGames(bool _hideOpenDecklistGames);
QString getGameNameFilter() const QString getGameNameFilter() const
{ {
return gameNameFilter; return gameNameFilter;

View file

@ -150,8 +150,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this)); stack = addZone(new StackZone(this, (int)table->boundingRect().height(), this));
hand = addZone(new HandZone(this, hand = addZone(new HandZone(this, _local || _judge || (_parent->isSpectator() && _parent->isSpectatorsOmniscient()),
_local || _judge || (_parent->getSpectator() && _parent->getSpectatorsSeeEverything()),
(int)table->boundingRect().height(), this)); (int)table->boundingRect().height(), this));
connect(hand, &HandZone::cardCountChanged, handCounter, &HandCounter::updateNumber); connect(hand, &HandZone::cardCountChanged, handCounter, &HandCounter::updateNumber);
connect(handCounter, &HandCounter::showContextMenu, hand, &HandZone::showContextMenu); connect(handCounter, &HandCounter::showContextMenu, hand, &HandZone::showContextMenu);
@ -210,6 +209,8 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
connect(aViewLibrary, &QAction::triggered, this, &Player::actViewLibrary); connect(aViewLibrary, &QAction::triggered, this, &Player::actViewLibrary);
aViewHand = new QAction(this); aViewHand = new QAction(this);
connect(aViewHand, &QAction::triggered, this, &Player::actViewHand); connect(aViewHand, &QAction::triggered, this, &Player::actViewHand);
aSortHand = new QAction(this);
connect(aSortHand, &QAction::triggered, this, &Player::actSortHand);
aViewTopCards = new QAction(this); aViewTopCards = new QAction(this);
connect(aViewTopCards, &QAction::triggered, this, &Player::actViewTopCards); connect(aViewTopCards, &QAction::triggered, this, &Player::actViewTopCards);
@ -298,6 +299,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
if (local || judge) { if (local || judge) {
handMenu = playerMenu->addTearOffMenu(QString()); handMenu = playerMenu->addTearOffMenu(QString());
handMenu->addAction(aViewHand); handMenu->addAction(aViewHand);
handMenu->addAction(aSortHand);
playerLists.append(mRevealHand = handMenu->addMenu(QString())); playerLists.append(mRevealHand = handMenu->addMenu(QString()));
playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString())); playerLists.append(mRevealRandomHandCard = handMenu->addMenu(QString()));
handMenu->addSeparator(); handMenu->addSeparator();
@ -417,6 +419,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);
@ -424,6 +429,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();
@ -442,11 +448,6 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
initSayMenu(); initSayMenu();
} }
aCardMenu = new QAction(this);
aCardMenu->setEnabled(false);
playerMenu->addSeparator();
playerMenu->addAction(aCardMenu);
if (local || judge) { if (local || judge) {
for (auto &playerList : playerLists) { for (auto &playerList : playerLists) {
@ -791,6 +792,7 @@ void Player::retranslateUi()
aViewLibrary->setText(tr("&View library")); aViewLibrary->setText(tr("&View library"));
aViewHand->setText(tr("&View hand")); aViewHand->setText(tr("&View hand"));
aSortHand->setText(tr("&Sort hand"));
aViewTopCards->setText(tr("View &top cards of library...")); aViewTopCards->setText(tr("View &top cards of library..."));
aViewBottomCards->setText(tr("View bottom cards of library...")); aViewBottomCards->setText(tr("View bottom cards of library..."));
mRevealLibrary->setTitle(tr("Reveal &library to...")); mRevealLibrary->setTitle(tr("Reveal &library to..."));
@ -843,6 +845,7 @@ void Player::retranslateUi()
aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString())); aViewZone->setText(tr("View custom zone '%1'").arg(aViewZone->data().toString()));
} }
aIncrementAllCardCounters->setText(tr("Increment all card counters"));
aUntapAll->setText(tr("&Untap all permanents")); aUntapAll->setText(tr("&Untap all permanents"));
aRollDie->setText(tr("R&oll die...")); aRollDie->setText(tr("R&oll die..."));
aCreateToken->setText(tr("&Create token...")); aCreateToken->setText(tr("&Create token..."));
@ -861,8 +864,6 @@ void Player::retranslateUi()
} }
} }
aCardMenu->setText(tr("Selec&ted cards"));
if (local) { if (local) {
sayMenu->setTitle(tr("S&ay")); sayMenu->setTitle(tr("S&ay"));
} }
@ -954,43 +955,17 @@ void Player::setShortcutsActive()
aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand")); aMoveToHand->setShortcuts(shortcuts.getShortcut("Player/aMoveToHand"));
aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard")); aMoveToGraveyard->setShortcuts(shortcuts.getShortcut("Player/aMoveToGraveyard"));
aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile")); aMoveToExile->setShortcuts(shortcuts.getShortcut("Player/aMoveToExile"));
aSortHand->setShortcuts(shortcuts.getShortcut("Player/aSortHand"));
aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll")); aSelectAll->setShortcuts(shortcuts.getShortcut("Player/aSelectAll"));
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);
@ -998,44 +973,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.
@ -1084,6 +1060,8 @@ 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());
QMapIterator<int, AbstractCounter *> counterIterator(counters); QMapIterator<int, AbstractCounter *> counterIterator(counters);
while (counterIterator.hasNext()) { while (counterIterator.hasNext()) {
@ -1154,6 +1132,11 @@ void Player::actViewHand()
static_cast<GameScene *>(scene())->toggleZoneView(this, "hand", -1); static_cast<GameScene *>(scene())->toggleZoneView(this, "hand", -1);
} }
void Player::actSortHand()
{
hand->sortHand();
}
void Player::actViewTopCards() void Player::actViewTopCards()
{ {
int deckSize = zones.value("deck")->getCards().size(); int deckSize = zones.value("deck")->getCards().size();
@ -1849,7 +1832,8 @@ void Player::actCreateToken()
lastTokenInfo = dlg.getTokenInfo(); lastTokenInfo = dlg.getTokenInfo();
ExactCard correctedCard = CardDatabaseManager::getInstance()->guessCard({lastTokenInfo.name}); ExactCard correctedCard =
CardDatabaseManager::getInstance()->guessCard({lastTokenInfo.name, lastTokenInfo.providerId});
if (correctedCard) { if (correctedCard) {
lastTokenInfo.name = correctedCard.getName(); lastTokenInfo.name = correctedCard.getName();
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow()); lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard.getInfo().getTableRow());
@ -1872,6 +1856,7 @@ void Player::actCreateAnotherToken()
Command_CreateToken cmd; Command_CreateToken cmd;
cmd.set_zone("table"); cmd.set_zone("table");
cmd.set_card_name(lastTokenInfo.name.toStdString()); cmd.set_card_name(lastTokenInfo.name.toStdString());
cmd.set_card_provider_id(lastTokenInfo.providerId.toStdString());
cmd.set_color(lastTokenInfo.color.toStdString()); cmd.set_color(lastTokenInfo.color.toStdString());
cmd.set_pt(lastTokenInfo.pt.toStdString()); cmd.set_pt(lastTokenInfo.pt.toStdString());
cmd.set_annotation(lastTokenInfo.annotation.toStdString()); cmd.set_annotation(lastTokenInfo.annotation.toStdString());
@ -1912,9 +1897,9 @@ void Player::actCreateRelatedCard()
* then let's allow it to be created via "create another token" * then let's allow it to be created via "create another token"
*/ */
if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) { if (createRelatedFromRelation(sourceCard, cardRelation) && cardRelation->getCanCreateAnother()) {
ExactCard cardInfo = ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(
CardDatabaseManager::getInstance()->getCard({cardRelation->getName(), sourceCard->getProviderId()}); cardRelation->getName(), sourceCard->getCard().getPrinting());
setLastToken(cardInfo.getCardPtr()); setLastToken(relatedCard.getCardPtr());
} }
} }
@ -2076,13 +2061,18 @@ void Player::createCard(const CardItem *sourceCard,
cmd.set_x(gridPoint.x()); cmd.set_x(gridPoint.x());
cmd.set_y(gridPoint.y()); cmd.set_y(gridPoint.y());
ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardInfo->getName(),
sourceCard->getCard().getPrinting());
switch (attachType) { switch (attachType) {
case CardRelation::DoesNotAttach: case CardRelation::DoesNotAttach:
cmd.set_target_zone("table"); cmd.set_target_zone("table");
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
break; break;
case CardRelation::AttachTo: case CardRelation::AttachTo:
cmd.set_target_zone("table"); // We currently only support creating tokens on the table cmd.set_target_zone("table"); // We currently only support creating tokens on the table
cmd.set_card_provider_id(relatedCard.getPrinting().getUuid().toStdString());
cmd.set_target_card_id(sourceCard->getId()); cmd.set_target_card_id(sourceCard->getId());
cmd.set_target_mode(Command_CreateToken::ATTACH_TO); cmd.set_target_mode(Command_CreateToken::ATTACH_TO);
break; break;
@ -2791,7 +2781,7 @@ void Player::processPlayerInfo(const ServerInfo_Player &info)
switch (zoneInfo.type()) { switch (zoneInfo.type()) {
case ServerInfo_Zone::PrivateZone: case ServerInfo_Zone::PrivateZone:
contentsKnown = local || judge || (game->getSpectator() && game->getSpectatorsSeeEverything()); contentsKnown = local || judge || (game->isSpectator() && game->isSpectatorsOmniscient());
break; break;
case ServerInfo_Zone::PublicZone: case ServerInfo_Zone::PublicZone:
@ -3038,6 +3028,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();
@ -3861,20 +3896,12 @@ void Player::refreshShortcuts()
} }
} }
void Player::updateCardMenu(const CardItem *card) QMenu *Player::createCardMenu(const CardItem *card)
{ {
// If bad card OR is a spectator (as spectators don't need card menus), return if (card == nullptr) {
// only update the menu if the card is actually selected return nullptr;
if (card == nullptr || (game->isSpectator() && !judge) || game->getActiveCard() != card) {
return;
} }
QMenu *cardMenu = card->getCardMenu();
QMenu *ptMenu = card->getPTMenu();
QMenu *moveMenu = card->getMoveMenu();
cardMenu->clear();
bool revealedCard = false; bool revealedCard = false;
bool writeableCard = getLocalOrJudge(); bool writeableCard = getLocalOrJudge();
if (auto *view = qobject_cast<ZoneViewZone *>(card->getZone())) { if (auto *view = qobject_cast<ZoneViewZone *>(card->getZone())) {
@ -3887,6 +3914,8 @@ void Player::updateCardMenu(const CardItem *card)
} }
} }
QMenu *cardMenu = new QMenu;
if (revealedCard) { if (revealedCard) {
cardMenu->addAction(aHide); cardMenu->addAction(aHide);
cardMenu->addAction(aClone); cardMenu->addAction(aClone);
@ -3897,18 +3926,6 @@ void Player::updateCardMenu(const CardItem *card)
} else if (writeableCard) { } else if (writeableCard) {
bool canModifyCard = judge || card->getOwner() == this; bool canModifyCard = judge || card->getOwner() == this;
if (moveMenu->isEmpty() && canModifyCard) {
moveMenu->addAction(aMoveToTopLibrary);
moveMenu->addAction(aMoveToXfromTopOfLibrary);
moveMenu->addAction(aMoveToBottomLibrary);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToHand);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToGraveyard);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToExile);
}
if (card->getZone()) { if (card->getZone()) {
if (card->getZone()->getName() == "table") { if (card->getZone()->getName() == "table") {
// Card is on the battlefield // Card is on the battlefield
@ -3924,23 +3941,7 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectAll);
cardMenu->addAction(aSelectRow); cardMenu->addAction(aSelectRow);
return; return cardMenu;
}
if (ptMenu->isEmpty()) {
ptMenu->addAction(aIncP);
ptMenu->addAction(aDecP);
ptMenu->addAction(aFlowP);
ptMenu->addSeparator();
ptMenu->addAction(aIncT);
ptMenu->addAction(aDecT);
ptMenu->addAction(aFlowT);
ptMenu->addSeparator();
ptMenu->addAction(aIncPT);
ptMenu->addAction(aDecPT);
ptMenu->addSeparator();
ptMenu->addAction(aSetPT);
ptMenu->addAction(aResetPT);
} }
cardMenu->addAction(aTap); cardMenu->addAction(aTap);
@ -3960,11 +3961,11 @@ void Player::updateCardMenu(const CardItem *card)
} }
cardMenu->addAction(aDrawArrow); cardMenu->addAction(aDrawArrow);
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addMenu(ptMenu); cardMenu->addMenu(createPtMenu());
cardMenu->addAction(aSetAnnotation); cardMenu->addAction(aSetAnnotation);
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aClone); cardMenu->addAction(aClone);
cardMenu->addMenu(moveMenu); cardMenu->addMenu(createMoveMenu());
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectAll);
cardMenu->addAction(aSelectRow); cardMenu->addAction(aSelectRow);
@ -3988,7 +3989,7 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addAction(aDrawArrow); cardMenu->addAction(aDrawArrow);
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aClone); cardMenu->addAction(aClone);
cardMenu->addMenu(moveMenu); cardMenu->addMenu(createMoveMenu());
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectAll);
} else { } else {
@ -4009,7 +4010,7 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aClone); cardMenu->addAction(aClone);
cardMenu->addMenu(moveMenu); cardMenu->addMenu(createMoveMenu());
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectAll);
cardMenu->addAction(aSelectColumn); cardMenu->addAction(aSelectColumn);
@ -4039,7 +4040,7 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addSeparator(); cardMenu->addSeparator();
cardMenu->addAction(aClone); cardMenu->addAction(aClone);
cardMenu->addMenu(moveMenu); cardMenu->addMenu(createMoveMenu());
// actions that are really wonky when done from deck or sideboard // actions that are really wonky when done from deck or sideboard
if (card->getZone()->getName() == "hand") { if (card->getZone()->getName() == "hand") {
@ -4060,7 +4061,7 @@ void Player::updateCardMenu(const CardItem *card)
} }
} }
} else { } else {
cardMenu->addMenu(moveMenu); cardMenu->addMenu(createMoveMenu());
} }
} else { } else {
if (card->getZone() && card->getZone()->getName() != "hand") { if (card->getZone() && card->getZone()->getName() != "hand") {
@ -4074,6 +4075,42 @@ void Player::updateCardMenu(const CardItem *card)
cardMenu->addAction(aSelectAll); cardMenu->addAction(aSelectAll);
} }
} }
return cardMenu;
}
QMenu *Player::createMoveMenu() const
{
QMenu *moveMenu = new QMenu("Move to");
moveMenu->addAction(aMoveToTopLibrary);
moveMenu->addAction(aMoveToXfromTopOfLibrary);
moveMenu->addAction(aMoveToBottomLibrary);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToHand);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToGraveyard);
moveMenu->addSeparator();
moveMenu->addAction(aMoveToExile);
return moveMenu;
}
QMenu *Player::createPtMenu() const
{
QMenu *ptMenu = new QMenu("Power / toughness");
ptMenu->addAction(aIncP);
ptMenu->addAction(aDecP);
ptMenu->addAction(aFlowP);
ptMenu->addSeparator();
ptMenu->addAction(aIncT);
ptMenu->addAction(aDecT);
ptMenu->addAction(aFlowT);
ptMenu->addSeparator();
ptMenu->addAction(aIncPT);
ptMenu->addAction(aDecPT);
ptMenu->addSeparator();
ptMenu->addAction(aSetPT);
ptMenu->addAction(aResetPT);
return ptMenu;
} }
void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu) void Player::addRelatedCardView(const CardItem *card, QMenu *cardMenu)
@ -4130,8 +4167,8 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
int index = 0; int index = 0;
QAction *createRelatedCards = nullptr; QAction *createRelatedCards = nullptr;
for (const CardRelation *cardRelation : relatedCards) { for (const CardRelation *cardRelation : relatedCards) {
ExactCard relatedCard = ExactCard relatedCard = CardDatabaseManager::getInstance()->getCardFromSameSet(cardRelation->getName(),
CardDatabaseManager::getInstance()->getCard({cardRelation->getName(), exactCard.getPrinting().getUuid()}); card->getCard().getPrinting());
if (!relatedCard) { if (!relatedCard) {
relatedCard = CardDatabaseManager::getInstance()->getCard({cardRelation->getName()}); relatedCard = CardDatabaseManager::getInstance()->getCard({cardRelation->getName()});
} }
@ -4175,31 +4212,38 @@ 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);
} }
} }
void Player::setCardMenu(QMenu *menu) /**
* Creates a card menu from the given card and sets it as the currently active card menu.
* Will first check if the card should have a card menu, and no-ops if not.
*
* @param card The card to create the menu for. Pass nullptr to disable the card menu.
* @return The new card menu, or nullptr if failed.
*/
QMenu *Player::updateCardMenu(const CardItem *card)
{ {
if (aCardMenu != nullptr) { if (!card) {
aCardMenu->setEnabled(menu != nullptr); emit cardMenuUpdated(nullptr);
if (menu) {
aCardMenu->setMenu(menu);
}
}
}
QMenu *Player::getCardMenu() const
{
if (aCardMenu != nullptr) {
return aCardMenu->menu();
} else {
return nullptr; return nullptr;
} }
// If is spectator (as spectators don't need card menus), return
// only update the menu if the card is actually selected
if ((game->isSpectator() && !judge) || game->getActiveCard() != card) {
return nullptr;
}
QMenu *menu = createCardMenu(card);
emit cardMenuUpdated(menu);
return menu;
} }
QString Player::getName() const QString Player::getName() const
@ -4271,7 +4315,9 @@ void Player::setLastToken(CardInfoPtr cardInfo)
.color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(), .color = cardInfo->getColors().isEmpty() ? QString() : cardInfo->getColors().left(1).toLower(),
.pt = cardInfo->getPowTough(), .pt = cardInfo->getPowTough(),
.annotation = SettingsCache::instance().getAnnotateTokens() ? cardInfo->getText() : "", .annotation = SettingsCache::instance().getAnnotateTokens() ? cardInfo->getText() : "",
.destroy = true}; .destroy = true,
.providerId =
SettingsCache::instance().cardOverrides().getCardPreferenceOverride(cardInfo->getName())};
lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow()); lastTokenTableRow = TableZone::clampValidTableRow(2 - cardInfo->getTableRow());
aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenInfo.name)); aCreateAnotherToken->setText(tr("C&reate another %1 token").arg(lastTokenInfo.name));

View file

@ -156,6 +156,7 @@ signals:
void sizeChanged(); void sizeChanged();
void playerCountChanged(); void playerCountChanged();
void cardMenuUpdated(QMenu *cardMenu);
public slots: public slots:
void actUntapAll(); void actUntapAll();
void actRollDie(); void actRollDie();
@ -239,7 +240,7 @@ private slots:
void actSetAnnotation(); void actSetAnnotation();
void actReveal(QAction *action); void actReveal(QAction *action);
void refreshShortcuts(); void refreshShortcuts();
void actSortHand();
void initSayMenu(); void initSayMenu();
public: public:
@ -271,12 +272,11 @@ private:
*aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard, *aMoveBottomCardToExile, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard, *aMoveBottomCardToExile,
*aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard, *aDrawBottomCards; *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard, *aDrawBottomCards;
QAction *aCardMenu;
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter; QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
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; *aMoveToXfromTopOfLibrary, *aSelectAll, *aSelectRow, *aSelectColumn, *aSortHand, *aIncrementAllCardCounters;
bool movingCardsUntil; bool movingCardsUntil;
QTimer *moveTopCardTimer; QTimer *moveTopCardTimer;
@ -326,6 +326,8 @@ private:
const QString &avalue, const QString &avalue,
bool allCards, bool allCards,
EventProcessingOptions options); EventProcessingOptions options);
QMenu *createMoveMenu() const;
QMenu *createPtMenu() const;
void addRelatedCardActions(const CardItem *card, QMenu *cardMenu); void addRelatedCardActions(const CardItem *card, QMenu *cardMenu);
void addRelatedCardView(const CardItem *card, QMenu *cardMenu); void addRelatedCardView(const CardItem *card, QMenu *cardMenu);
void createCard(const CardItem *sourceCard, void createCard(const CardItem *sourceCard,
@ -420,6 +422,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);
@ -483,9 +486,8 @@ public:
{ {
return arrows; return arrows;
} }
void setCardMenu(QMenu *menu); QMenu *updateCardMenu(const CardItem *card);
QMenu *getCardMenu() const; QMenu *createCardMenu(const CardItem *card);
void updateCardMenu(const CardItem *card);
bool getActive() const bool getActive() const
{ {
return active; return active;

View file

@ -1,10 +1,10 @@
#include "player_list_widget.h" #include "player_list_widget.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_account.h"
#include "../../client/tabs/tab_game.h" #include "../../client/tabs/tab_game.h"
#include "../../client/tabs/tab_supervisor.h" #include "../../client/tabs/tab_supervisor.h"
#include "../../client/ui/pixel_map_generator.h" #include "../../client/ui/pixel_map_generator.h"
#include "../../server/abstract_client.h"
#include "../../server/user/user_context_menu.h" #include "../../server/user/user_context_menu.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../../server/user/user_list_widget.h" #include "../../server/user/user_list_widget.h"

View file

@ -127,6 +127,15 @@ void HandZone::reorganizeCards()
update(); update();
} }
void HandZone::sortHand()
{
if (cards.isEmpty()) {
return;
}
cards.sortBy({CardList::SortByMainType, CardList::SortByManaValue, CardList::SortByColorGrouping});
reorganizeCards();
}
void HandZone::setWidth(qreal _width) void HandZone::setWidth(qreal _width)
{ {
if (SettingsCache::instance().getHorizontalHand()) { if (SettingsCache::instance().getHorizontalHand()) {

View file

@ -19,6 +19,7 @@ public:
QRectF boundingRect() const override; QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void reorganizeCards() override; void reorganizeCards() override;
void sortHand();
void setWidth(qreal _width); void setWidth(qreal _width);
protected: protected:

View file

@ -1,6 +1,5 @@
#include "abstract_client.h" #include "abstract_client.h"
#include "../../server/pending_command.h"
#include "featureset.h" #include "featureset.h"
#include "get_pb_extension.h" #include "get_pb_extension.h"
#include "pb/commands.pb.h" #include "pb/commands.pb.h"
@ -18,6 +17,7 @@
#include "pb/event_user_left.pb.h" #include "pb/event_user_left.pb.h"
#include "pb/event_user_message.pb.h" #include "pb/event_user_message.pb.h"
#include "pb/server_message.pb.h" #include "pb/server_message.pb.h"
#include "pending_command.h"
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>

View file

@ -1,7 +1,7 @@
#ifndef LOCALCLIENT_H #ifndef LOCALCLIENT_H
#define LOCALCLIENT_H #define LOCALCLIENT_H
#include "../client/game_logic/abstract_client.h" #include "abstract_client.h"
#include <QLoggingCategory> #include <QLoggingCategory>

View file

@ -1,7 +1,7 @@
#ifndef REMOTECLIENT_H #ifndef REMOTECLIENT_H
#define REMOTECLIENT_H #define REMOTECLIENT_H
#include "../../client/game_logic/abstract_client.h" #include "../abstract_client.h"
#include "pb/commands.pb.h" #include "pb/commands.pb.h"
#include <QLoggingCategory> #include <QLoggingCategory>

View file

@ -1,6 +1,6 @@
#include "remote_decklist_tree_widget.h" #include "remote_decklist_tree_widget.h"
#include "../../client/game_logic/abstract_client.h" #include "../abstract_client.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "pb/command_deck_list.pb.h" #include "pb/command_deck_list.pb.h"
#include "pb/response_deck_list.pb.h" #include "pb/response_deck_list.pb.h"

View file

@ -1,6 +1,6 @@
#include "remote_replay_list_tree_widget.h" #include "remote_replay_list_tree_widget.h"
#include "../../client/game_logic/abstract_client.h" #include "../abstract_client.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "pb/command_replay_list.pb.h" #include "pb/command_replay_list.pb.h"
#include "pb/response_replay_list.pb.h" #include "pb/response_replay_list.pb.h"

View file

@ -1,10 +1,10 @@
#include "user_context_menu.h" #include "user_context_menu.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_account.h"
#include "../../client/tabs/tab_game.h" #include "../../client/tabs/tab_game.h"
#include "../../client/tabs/tab_supervisor.h" #include "../../client/tabs/tab_supervisor.h"
#include "../../game/game_selector.h" #include "../../game/game_selector.h"
#include "../abstract_client.h"
#include "../chat_view/chat_view.h" #include "../chat_view/chat_view.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "pb/command_kick_from_game.pb.h" #include "pb/command_kick_from_game.pb.h"

View file

@ -1,11 +1,11 @@
#include "user_info_box.h" #include "user_info_box.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/get_text_with_max.h" #include "../../client/get_text_with_max.h"
#include "../../client/ui/pixel_map_generator.h" #include "../../client/ui/pixel_map_generator.h"
#include "../../dialogs/dlg_edit_avatar.h" #include "../../dialogs/dlg_edit_avatar.h"
#include "../../dialogs/dlg_edit_password.h" #include "../../dialogs/dlg_edit_password.h"
#include "../../dialogs/dlg_edit_user.h" #include "../../dialogs/dlg_edit_user.h"
#include "../abstract_client.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "passwordhasher.h" #include "passwordhasher.h"
#include "pb/response_get_user_info.pb.h" #include "pb/response_get_user_info.pb.h"

View file

@ -1,7 +1,7 @@
#include "user_list_manager.h" #include "user_list_manager.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/sound_engine.h" #include "../../client/sound_engine.h"
#include "../abstract_client.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "pb/event_add_to_list.pb.h" #include "pb/event_add_to_list.pb.h"
#include "pb/event_remove_from_list.pb.h" #include "pb/event_remove_from_list.pb.h"

View file

@ -1,11 +1,11 @@
#include "user_list_widget.h" #include "user_list_widget.h"
#include "../../client/game_logic/abstract_client.h"
#include "../../client/tabs/tab_account.h" #include "../../client/tabs/tab_account.h"
#include "../../client/tabs/tab_supervisor.h" #include "../../client/tabs/tab_supervisor.h"
#include "../../client/ui/pixel_map_generator.h" #include "../../client/ui/pixel_map_generator.h"
#include "../../game/game_selector.h" #include "../../game/game_selector.h"
#include "../../server/user/user_list_manager.h" #include "../../server/user/user_list_manager.h"
#include "../abstract_client.h"
#include "../pending_command.h" #include "../pending_command.h"
#include "pb/moderator_commands.pb.h" #include "pb/moderator_commands.pb.h"
#include "pb/response_get_games_of_user.pb.h" #include "pb/response_get_games_of_user.pb.h"

View file

@ -355,6 +355,7 @@ SettingsCache::SettingsCache()
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool(); spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool(); createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt(); defaultStartingLifeTotal = settings->value("game/defaultstartinglifetotal", 20).toInt();
shareDecklistsOnLoad = settings->value("game/sharedecklistsonload", false).toBool();
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool(); rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString(); clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString(); clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
@ -1360,7 +1361,13 @@ void SettingsCache::setDefaultStartingLifeTotal(const int _defaultStartingLifeTo
{ {
defaultStartingLifeTotal = _defaultStartingLifeTotal; defaultStartingLifeTotal = _defaultStartingLifeTotal;
settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal); settings->setValue("game/defaultstartinglifetotal", defaultStartingLifeTotal);
}; }
void SettingsCache::setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad)
{
shareDecklistsOnLoad = _shareDecklistsOnLoad;
settings->setValue("game/sharedecklistsonload", shareDecklistsOnLoad);
}
void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value) void SettingsCache::setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value)
{ {
@ -1373,6 +1380,7 @@ void SettingsCache::setStartupCardUpdateCheckPromptForUpdate(bool value)
startupCardUpdateCheckPromptForUpdate = value; startupCardUpdateCheckPromptForUpdate = value;
settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate); settings->setValue("personal/startupCardUpdateCheckPromptForUpdate", startupCardUpdateCheckPromptForUpdate);
} }
void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value) void SettingsCache::setStartupCardUpdateCheckAlwaysUpdate(bool value)
{ {
startupCardUpdateCheckAlwaysUpdate = value; startupCardUpdateCheckAlwaysUpdate = value;

View file

@ -302,6 +302,7 @@ private:
bool spectatorsCanSeeEverything; bool spectatorsCanSeeEverything;
bool createGameAsSpectator; bool createGameAsSpectator;
int defaultStartingLifeTotal; int defaultStartingLifeTotal;
bool shareDecklistsOnLoad;
int keepalive; int keepalive;
int timeout; int timeout;
void translateLegacySettings(); void translateLegacySettings();
@ -805,6 +806,10 @@ public:
{ {
return defaultStartingLifeTotal; return defaultStartingLifeTotal;
} }
bool getShareDecklistsOnLoad() const
{
return shareDecklistsOnLoad;
}
bool getCreateGameAsSpectator() const bool getCreateGameAsSpectator() const
{ {
return createGameAsSpectator; return createGameAsSpectator;
@ -1032,6 +1037,7 @@ public slots:
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything); void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
void setCreateGameAsSpectator(const bool _createGameAsSpectator); void setCreateGameAsSpectator(const bool _createGameAsSpectator);
void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal); void setDefaultStartingLifeTotal(const int _defaultStartingLifeTotal);
void setShareDecklistsOnLoad(const bool _shareDecklistsOnLoad);
void setRememberGameSettings(const bool _rememberGameSettings); void setRememberGameSettings(const bool _rememberGameSettings);
void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value); void setCheckUpdatesOnStartup(QT_STATE_CHANGED_T value);
void setStartupCardUpdateCheckPromptForUpdate(bool value); void setStartupCardUpdateCheckPromptForUpdate(bool value);

View file

@ -83,6 +83,17 @@ bool GameFiltersSettings::isHideNotBuddyCreatedGames()
return !(previous == QVariant()) && previous.toBool(); return !(previous == QVariant()) && previous.toBool();
} }
void GameFiltersSettings::setHideOpenDecklistGames(bool hide)
{
setValue(hide, "hide_open_decklist_games", "filter_games");
}
bool GameFiltersSettings::isHideOpenDecklistGames()
{
QVariant previous = getValue("hide_open_decklist_games", "filter_games");
return !(previous == QVariant()) && previous.toBool();
}
void GameFiltersSettings::setGameNameFilter(QString gameName) void GameFiltersSettings::setGameNameFilter(QString gameName)
{ {
setValue(gameName, "game_name_filter", "filter_games"); setValue(gameName, "game_name_filter", "filter_games");

View file

@ -15,6 +15,8 @@ public:
bool isHidePasswordProtectedGames(); bool isHidePasswordProtectedGames();
bool isHideIgnoredUserGames(); bool isHideIgnoredUserGames();
bool isHideNotBuddyCreatedGames(); bool isHideNotBuddyCreatedGames();
void setHideOpenDecklistGames(bool hide);
bool isHideOpenDecklistGames();
QString getGameNameFilter(); QString getGameNameFilter();
QString getCreatorNameFilter(); QString getCreatorNameFilter();
int getMinPlayers(); int getMinPlayers();

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)},
@ -552,6 +556,9 @@ private:
ShortcutGroup::Move_selected)}, ShortcutGroup::Move_selected)},
{"Player/aViewHand", {"Player/aViewHand",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)}, ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Hand"), parseSequenceString(""), ShortcutGroup::View)},
{"Player/aSortHand", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Sort Hand"),
parseSequenceString("Ctrl+Shift+H"),
ShortcutGroup::View)},
{"Player/aViewGraveyard", {"Player/aViewGraveyard",
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard"), parseSequenceString("F4"), ShortcutGroup::View)}, ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard"), parseSequenceString("F4"), ShortcutGroup::View)},
{"Player/aViewLibrary", {"Player/aViewLibrary",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,4 +7,5 @@ message Context_DeckSelect {
} }
optional string deck_hash = 1; optional string deck_hash = 1;
optional int32 sideboard_size = 2 [default = -1]; optional int32 sideboard_size = 2 [default = -1];
optional string deck_list = 3;
} }

View file

@ -39,6 +39,7 @@ message Command_CreateGame {
optional bool join_as_judge = 11; optional bool join_as_judge = 11;
optional bool join_as_spectator = 12; optional bool join_as_spectator = 12;
optional uint32 starting_life_total = 13; optional uint32 starting_life_total = 13;
optional bool share_decklists_on_load = 14;
} }
message Command_JoinGame { message Command_JoinGame {

View file

@ -16,6 +16,7 @@ message ServerInfo_Game {
optional bool spectators_need_password = 12; optional bool spectators_need_password = 12;
optional bool spectators_can_chat = 13; optional bool spectators_can_chat = 13;
optional bool spectators_omniscient = 14; optional bool spectators_omniscient = 14;
optional bool share_decklists_on_load = 15;
optional uint32 player_count = 30; optional uint32 player_count = 30;
optional uint32 spectators_count = 31; optional uint32 spectators_count = 31;
optional bool started = 50; optional bool started = 50;

View file

@ -21,6 +21,7 @@
#include "decklist.h" #include "decklist.h"
#include "pb/context_connection_state_changed.pb.h" #include "pb/context_connection_state_changed.pb.h"
#include "pb/context_deck_select.pb.h"
#include "pb/context_ping_changed.pb.h" #include "pb/context_ping_changed.pb.h"
#include "pb/event_delete_arrow.pb.h" #include "pb/event_delete_arrow.pb.h"
#include "pb/event_game_closed.pb.h" #include "pb/event_game_closed.pb.h"
@ -62,15 +63,16 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo,
bool _spectatorsCanTalk, bool _spectatorsCanTalk,
bool _spectatorsSeeEverything, bool _spectatorsSeeEverything,
int _startingLifeTotal, int _startingLifeTotal,
bool _shareDecklistsOnLoad,
Server_Room *_room) Server_Room *_room)
: QObject(), room(_room), nextPlayerId(0), hostId(0), creatorInfo(new ServerInfo_User(_creatorInfo)), : QObject(), room(_room), nextPlayerId(0), hostId(0), creatorInfo(new ServerInfo_User(_creatorInfo)),
gameStarted(false), gameClosed(false), gameId(_gameId), password(_password), maxPlayers(_maxPlayers), gameStarted(false), gameClosed(false), gameId(_gameId), password(_password), maxPlayers(_maxPlayers),
gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies),
onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed),
spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk),
spectatorsSeeEverything(_spectatorsSeeEverything), startingLifeTotal(_startingLifeTotal), inactivityCounter(0), spectatorsSeeEverything(_spectatorsSeeEverything), startingLifeTotal(_startingLifeTotal),
startTimeOfThisGame(0), secondsElapsed(0), firstGameStarted(false), turnOrderReversed(false), shareDecklistsOnLoad(_shareDecklistsOnLoad), inactivityCounter(0), startTimeOfThisGame(0), secondsElapsed(0),
startTime(QDateTime::currentDateTime()), pingClock(nullptr), firstGameStarted(false), turnOrderReversed(false), startTime(QDateTime::currentDateTime()), pingClock(nullptr),
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
gameMutex() gameMutex()
#else #else
@ -800,6 +802,7 @@ void Server_Game::getInfo(ServerInfo_Game &result) const
result.set_spectators_need_password(getSpectatorsNeedPassword()); result.set_spectators_need_password(getSpectatorsNeedPassword());
result.set_spectators_can_chat(spectatorsCanTalk); result.set_spectators_can_chat(spectatorsCanTalk);
result.set_spectators_omniscient(spectatorsSeeEverything); result.set_spectators_omniscient(spectatorsSeeEverything);
result.set_share_decklists_on_load(shareDecklistsOnLoad);
result.set_spectators_count(getSpectatorCount()); result.set_spectators_count(getSpectatorCount());
result.set_start_time(startTime.toSecsSinceEpoch()); result.set_start_time(startTime.toSecsSinceEpoch());
} }

View file

@ -67,6 +67,7 @@ private:
bool spectatorsCanTalk; bool spectatorsCanTalk;
bool spectatorsSeeEverything; bool spectatorsSeeEverything;
int startingLifeTotal; int startingLifeTotal;
bool shareDecklistsOnLoad;
int inactivityCounter; int inactivityCounter;
int startTimeOfThisGame, secondsElapsed; int startTimeOfThisGame, secondsElapsed;
bool firstGameStarted; bool firstGameStarted;
@ -106,7 +107,8 @@ public:
bool _spectatorsNeedPassword, bool _spectatorsNeedPassword,
bool _spectatorsCanTalk, bool _spectatorsCanTalk,
bool _spectatorsSeeEverything, bool _spectatorsSeeEverything,
int startingLifeTotal, int _startingLifeTotal,
bool _shareDecklistsOnLoad,
Server_Room *parent); Server_Room *parent);
~Server_Game() override; ~Server_Game() override;
Server_Room *getRoom() const Server_Room *getRoom() const
@ -168,6 +170,10 @@ public:
{ {
return startingLifeTotal; return startingLifeTotal;
} }
bool getShareDecklistsOnLoad() const
{
return shareDecklistsOnLoad;
}
Response::ResponseCode Response::ResponseCode
checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions, bool asJudge); checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions, bool asJudge);
bool containsUser(const QString &userName) const; bool containsUser(const QString &userName) const;

View file

@ -836,6 +836,9 @@ Server_Player::cmdDeckSelect(const Command_DeckSelect &cmd, ResponseContainer &r
Context_DeckSelect context; Context_DeckSelect context;
context.set_deck_hash(deck->getDeckHash().toStdString()); context.set_deck_hash(deck->getDeckHash().toStdString());
context.set_sideboard_size(deck->getSideboardSize()); context.set_sideboard_size(deck->getSideboardSize());
if (game->getShareDecklistsOnLoad()) {
context.set_deck_list(deck->writeToString_Native().toStdString());
}
ges.setGameEventContext(context); ges.setGameEventContext(context);
auto *re = new Response_DeckDownload; auto *re = new Response_DeckDownload;

View file

@ -96,6 +96,10 @@ public:
Server_AbstractUserInterface *_handler); Server_AbstractUserInterface *_handler);
~Server_Player() override; ~Server_Player() override;
void prepareDestroy(); void prepareDestroy();
const DeckList *getDeckList() const
{
return deck;
}
Server_AbstractUserInterface *getUserInterface() const Server_AbstractUserInterface *getUserInterface() const
{ {
return userInterface; return userInterface;

View file

@ -818,6 +818,8 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room
QString description = nameFromStdString(cmd.description()); QString description = nameFromStdString(cmd.description());
int startingLifeTotal = cmd.has_starting_life_total() ? cmd.starting_life_total() : 20; int startingLifeTotal = cmd.has_starting_life_total() ? cmd.starting_life_total() : 20;
bool shareDecklistsOnLoad = cmd.has_share_decklists_on_load() ? cmd.share_decklists_on_load() : false;
const int gameId = databaseInterface->getNextGameId(); const int gameId = databaseInterface->getNextGameId();
if (gameId == -1) { if (gameId == -1) {
return Response::RespInternalError; return Response::RespInternalError;
@ -828,7 +830,7 @@ Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room
Server_Game *game = new Server_Game( Server_Game *game = new Server_Game(
copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes,
cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.only_buddies(), onlyRegisteredUsers, cmd.spectators_allowed(), cmd.spectators_need_password(),
cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, room); cmd.spectators_can_talk(), cmd.spectators_see_everything(), startingLifeTotal, shareDecklistsOnLoad, room);
game->addPlayer(this, rc, asSpectator, asJudge, false); game->addPlayer(this, rc, asSpectator, asJudge, false);
room->addGame(game); room->addGame(game);

View file

@ -402,6 +402,9 @@ void SettingsCache::setCreateGameAsSpectator(const bool /* _createGameAsSpectato
void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */) void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */)
{ {
} }
void SettingsCache::setShareDecklistsOnLoad(const bool /* _shareDecklistsOnLoad */)
{
}
void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */) void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */)
{ {
} }

View file

@ -63,7 +63,7 @@
<location filename="src/oraclewizard.cpp" line="316"/> <location filename="src/oraclewizard.cpp" line="316"/>
<source>Sets file (%1)</source> <source>Sets file (%1)</source>
<oldsource>Sets JSON file (%1)</oldsource> <oldsource>Sets JSON file (%1)</oldsource>
<translation type="unfinished"/> <translation>Choisir le fichier (%1)</translation>
</message> </message>
<message> <message>
<location filename="src/oraclewizard.cpp" line="346"/> <location filename="src/oraclewizard.cpp" line="346"/>
@ -144,7 +144,7 @@
<message> <message>
<location filename="src/oraclewizard.cpp" line="569"/> <location filename="src/oraclewizard.cpp" line="569"/>
<source>Failed to interpret downloaded data.</source> <source>Failed to interpret downloaded data.</source>
<translation type="unfinished"/> <translation>Échec lors de l&apos;interprétation des données téléchargées.</translation>
</message> </message>
<message> <message>
<location filename="src/oraclewizard.cpp" line="582"/> <location filename="src/oraclewizard.cpp" line="582"/>
@ -303,7 +303,7 @@
<message> <message>
<location filename="src/oraclewizard.cpp" line="658"/> <location filename="src/oraclewizard.cpp" line="658"/>
<source>A cockatrice database file of %1 MB has been downloaded.</source> <source>A cockatrice database file of %1 MB has been downloaded.</source>
<translation type="unfinished"/> <translation>Un fichier de base de données Cockatrice de %1 MB a é téléchargé.</translation>
</message> </message>
<message> <message>
<location filename="src/oraclewizard.cpp" line="661"/> <location filename="src/oraclewizard.cpp" line="661"/>
@ -368,7 +368,7 @@
<message> <message>
<location filename="src/pagetemplates.cpp" line="73"/> <location filename="src/pagetemplates.cpp" line="73"/>
<source>The provided URL is not valid: </source> <source>The provided URL is not valid: </source>
<translation type="unfinished"/> <translation>L&apos;URL fournie n&apos;est pas valide :</translation>
</message> </message>
<message> <message>
<location filename="src/pagetemplates.cpp" line="77"/> <location filename="src/pagetemplates.cpp" line="77"/>
@ -401,12 +401,12 @@
<message> <message>
<location filename="src/zip/unzip.cpp" line="1176"/> <location filename="src/zip/unzip.cpp" line="1176"/>
<source>Failed to initialize or load zlib library.</source> <source>Failed to initialize or load zlib library.</source>
<translation type="unfinished"/> <translation>Impossible d&apos;initialiser ou de charger la bibliothèque zlib.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1177"/> <location filename="src/zip/unzip.cpp" line="1177"/>
<source>zlib library error.</source> <source>zlib library error.</source>
<translation type="unfinished"/> <translation>Erreur avec la bibliothèque zlib.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1178"/> <location filename="src/zip/unzip.cpp" line="1178"/>
@ -416,7 +416,7 @@
<message> <message>
<location filename="src/zip/unzip.cpp" line="1179"/> <location filename="src/zip/unzip.cpp" line="1179"/>
<source>Partially corrupted archive. Some files might be extracted.</source> <source>Partially corrupted archive. Some files might be extracted.</source>
<translation type="unfinished"/> <translation>Archive partiellement corrompue. Certains fichiers ont pu être extraits.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1180"/> <location filename="src/zip/unzip.cpp" line="1180"/>
@ -431,47 +431,47 @@
<message> <message>
<location filename="src/zip/unzip.cpp" line="1182"/> <location filename="src/zip/unzip.cpp" line="1182"/>
<source>No archive has been created yet.</source> <source>No archive has been created yet.</source>
<translation type="unfinished"/> <translation>Aucune archive n&apos;a é créée pour l&apos;instant.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1183"/> <location filename="src/zip/unzip.cpp" line="1183"/>
<source>File or directory does not exist.</source> <source>File or directory does not exist.</source>
<translation type="unfinished"/> <translation>Le fichier ou le dossier n&apos;existe pas.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1184"/> <location filename="src/zip/unzip.cpp" line="1184"/>
<source>File read error.</source> <source>File read error.</source>
<translation type="unfinished"/> <translation>Erreur lors de la lecture du fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1185"/> <location filename="src/zip/unzip.cpp" line="1185"/>
<source>File write error.</source> <source>File write error.</source>
<translation type="unfinished"/> <translation>Erreur lors de l&apos;écriture du fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1186"/> <location filename="src/zip/unzip.cpp" line="1186"/>
<source>File seek error.</source> <source>File seek error.</source>
<translation type="unfinished"/> <translation>Erreur lors de la recherche dans le fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1187"/> <location filename="src/zip/unzip.cpp" line="1187"/>
<source>Unable to create a directory.</source> <source>Unable to create a directory.</source>
<translation type="unfinished"/> <translation>Impossible de créer un répertoire.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1188"/> <location filename="src/zip/unzip.cpp" line="1188"/>
<source>Invalid device.</source> <source>Invalid device.</source>
<translation type="unfinished"/> <translation>Périphérique non valide.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1189"/> <location filename="src/zip/unzip.cpp" line="1189"/>
<source>Invalid or incompatible zip archive.</source> <source>Invalid or incompatible zip archive.</source>
<translation type="unfinished"/> <translation>Archive zip non valide ou incompatible.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1190"/> <location filename="src/zip/unzip.cpp" line="1190"/>
<source>Inconsistent headers. Archive might be corrupted.</source> <source>Inconsistent headers. Archive might be corrupted.</source>
<translation type="unfinished"/> <translation>En-têtes inconsistants. L&apos;archive peut être corrompue.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/unzip.cpp" line="1194"/> <location filename="src/zip/unzip.cpp" line="1194"/>
@ -484,17 +484,17 @@
<message> <message>
<location filename="src/zip/zip.cpp" line="1604"/> <location filename="src/zip/zip.cpp" line="1604"/>
<source>ZIP operation completed successfully.</source> <source>ZIP operation completed successfully.</source>
<translation type="unfinished"/> <translation>Opération ZIP complétée avec succès.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1605"/> <location filename="src/zip/zip.cpp" line="1605"/>
<source>Failed to initialize or load zlib library.</source> <source>Failed to initialize or load zlib library.</source>
<translation type="unfinished"/> <translation>Impossible d&apos;initialiser ou de charger la bibliothèque zlib.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1606"/> <location filename="src/zip/zip.cpp" line="1606"/>
<source>zlib library error.</source> <source>zlib library error.</source>
<translation type="unfinished"/> <translation>Erreur avec la bibliothèque zlib.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1607"/> <location filename="src/zip/zip.cpp" line="1607"/>
@ -504,32 +504,32 @@
<message> <message>
<location filename="src/zip/zip.cpp" line="1608"/> <location filename="src/zip/zip.cpp" line="1608"/>
<source>No archive has been created yet.</source> <source>No archive has been created yet.</source>
<translation type="unfinished"/> <translation>Aucune archive n&apos;a é créée pour l&apos;instant.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1609"/> <location filename="src/zip/zip.cpp" line="1609"/>
<source>File or directory does not exist.</source> <source>File or directory does not exist.</source>
<translation type="unfinished"/> <translation>Le fichier ou le dossier n&apos;existe pas.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1610"/> <location filename="src/zip/zip.cpp" line="1610"/>
<source>File read error.</source> <source>File read error.</source>
<translation type="unfinished"/> <translation>Erreur lors de la lecture du fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1611"/> <location filename="src/zip/zip.cpp" line="1611"/>
<source>File write error.</source> <source>File write error.</source>
<translation type="unfinished"/> <translation>Erreur lors de l&apos;écriture du fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1612"/> <location filename="src/zip/zip.cpp" line="1612"/>
<source>File seek error.</source> <source>File seek error.</source>
<translation type="unfinished"/> <translation>Erreur lors de la recherche dans le fichier.</translation>
</message> </message>
<message> <message>
<location filename="src/zip/zip.cpp" line="1616"/> <location filename="src/zip/zip.cpp" line="1616"/>
<source>Unknown error.</source> <source>Unknown error.</source>
<translation type="unfinished"/> <translation>Erreur inconnue.</translation>
</message> </message>
</context> </context>
<context> <context>
@ -550,7 +550,7 @@
<message> <message>
<location filename="src/main.cpp" line="63"/> <location filename="src/main.cpp" line="63"/>
<source>Run in no-confirm background mode</source> <source>Run in no-confirm background mode</source>
<translation type="unfinished"/> <translation>S&apos;exécuter en mode tâche de fond sans demande de confirmation</translation>
</message> </message>
</context> </context>
</TS> </TS>

View file

@ -369,7 +369,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<message> <message>
<location filename="src/pagetemplates.cpp" line="73"/> <location filename="src/pagetemplates.cpp" line="73"/>
<source>The provided URL is not valid: </source> <source>The provided URL is not valid: </source>
<translation type="unfinished"/> <translation>L&apos;indirizzo fornito non è valido:</translation>
</message> </message>
<message> <message>
<location filename="src/pagetemplates.cpp" line="77"/> <location filename="src/pagetemplates.cpp" line="77"/>
@ -551,7 +551,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<message> <message>
<location filename="src/main.cpp" line="63"/> <location filename="src/main.cpp" line="63"/>
<source>Run in no-confirm background mode</source> <source>Run in no-confirm background mode</source>
<translation type="unfinished"/> <translation>Esegui in background senza conferma</translation>
</message> </message>
</context> </context>
</TS> </TS>

View file

@ -406,6 +406,9 @@ void SettingsCache::setCreateGameAsSpectator(const bool /* _createGameAsSpectato
void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */) void SettingsCache::setDefaultStartingLifeTotal(const int /* _startingLifeTotal */)
{ {
} }
void SettingsCache::setShareDecklistsOnLoad(const bool /* _shareDecklistsOnLoad */)
{
}
void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */) void SettingsCache::setRememberGameSettings(const bool /* _rememberGameSettings */)
{ {
} }