Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jakub Mrowinski 2025-01-02 00:04:51 +01:00
commit ec895e3481
24 changed files with 3558 additions and 2653 deletions

View file

@ -1,19 +1,20 @@
FROM ubuntu:bionic FROM ubuntu:24.04
MAINTAINER Zach Halpern <zahalpern+github@gmail.com>
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y\ RUN apt-get update && apt-get install -y\
build-essential\ build-essential \
cmake\ cmake \
git\ file \
libprotobuf-dev\ g++ \
libqt5sql5-mysql\ git \
libmysqlclient-dev\ libmariadb-dev-compat \
libqt5websockets5-dev\ libprotobuf-dev \
protobuf-compiler\ libqt6sql6-mysql \
qt5-default\ qt6-websockets-dev \
qtbase5-dev\ protobuf-compiler \
qttools5-dev-tools\ qt6-tools-dev \
qttools5-dev qt6-tools-dev-tools
COPY . /home/servatrice/code/ COPY . /home/servatrice/code/
WORKDIR /home/servatrice/code WORKDIR /home/servatrice/code
@ -25,7 +26,6 @@ RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=
WORKDIR /home/servatrice WORKDIR /home/servatrice
EXPOSE 4747 EXPOSE 4747 4748
ENTRYPOINT [ "servatrice", "--log-to-console" ] ENTRYPOINT [ "servatrice", "--log-to-console" ]

View file

@ -282,7 +282,7 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<name>BetaReleaseChannel</name> <name>BetaReleaseChannel</name>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="203"/> <location filename="src/client/network/release_channel.cpp" line="203"/>
<source>Beta Releases</source> <source>Beta</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -424,21 +424,29 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context> <context>
<name>CardInfoFrameWidget</name> <name>CardInfoFrameWidget</name>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="66"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="69"/>
<source>Image</source> <source>Image</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="67"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="70"/>
<source>Description</source> <source>Description</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="68"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="71"/>
<source>Both</source> <source>Both</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
<context>
<name>CardInfoPictureWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_picture_widget.cpp" line="256"/>
<source>View related cards</source>
<translation type="unfinished"></translation>
</message>
</context>
<context> <context>
<name>CardInfoTextWidget</name> <name>CardInfoTextWidget</name>
<message> <message>
@ -481,121 +489,121 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
<context> <context>
<name>CardZone</name> <name>CardZone</name>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="72"/> <location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>their hand</source> <source>their hand</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="72"/> <location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>%1&apos;s hand</source> <source>%1&apos;s hand</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="76"/>
<source>their library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="77"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="79"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="80"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="82"/> <location filename="src/game/zones/card_zone.cpp" line="82"/>
<source>their library</source> <source>their library</source>
<comment>reveal zone</comment> <comment>look at zone</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="83"/> <location filename="src/game/zones/card_zone.cpp" line="83"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="86"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="88"/>
<source>their library</source>
<comment>reveal zone</comment> <comment>reveal zone</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="85"/> <location filename="src/game/zones/card_zone.cpp" line="89"/>
<source>%1&apos;s library</source>
<comment>reveal zone</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>their library</source> <source>their library</source>
<comment>shuffle</comment> <comment>shuffle</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="85"/> <location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>shuffle</comment> <comment>shuffle</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="87"/> <location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>their library</source> <source>their library</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="87"/> <location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<source>their graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="90"/>
<source>%1&apos;s graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<source>their exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="92"/>
<source>%1&apos;s exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="96"/> <location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>their graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>%1&apos;s graveyard</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>their exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>%1&apos;s exile</source>
<comment>nominative</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="102"/>
<source>their sideboard</source> <source>their sideboard</source>
<comment>look at zone</comment> <comment>look at zone</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="97"/> <location filename="src/game/zones/card_zone.cpp" line="103"/>
<source>%1&apos;s sideboard</source> <source>%1&apos;s sideboard</source>
<comment>look at zone</comment> <comment>look at zone</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="99"/> <location filename="src/game/zones/card_zone.cpp" line="105"/>
<source>their sideboard</source> <source>their sideboard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="100"/> <location filename="src/game/zones/card_zone.cpp" line="106"/>
<source>%1&apos;s sideboard</source> <source>%1&apos;s sideboard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -4682,7 +4690,7 @@ Cockatrice will now reload the card database.</source>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="1901"/> <location filename="src/game/player/player.cpp" line="1901"/>
<location filename="src/game/player/player.cpp" line="3564"/> <location filename="src/game/player/player.cpp" line="3565"/>
<source>Number:</source> <source>Number:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -4793,7 +4801,7 @@ Cockatrice will now reload the card database.</source>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="1753"/> <location filename="src/game/player/player.cpp" line="1753"/>
<location filename="src/game/player/player.cpp" line="4084"/> <location filename="src/game/player/player.cpp" line="4085"/>
<source>C&amp;reate another %1 token</source> <source>C&amp;reate another %1 token</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -4808,47 +4816,47 @@ Cockatrice will now reload the card database.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3351"/> <location filename="src/game/player/player.cpp" line="3352"/>
<source>Change power/toughness</source> <source>Change power/toughness</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3351"/> <location filename="src/game/player/player.cpp" line="3352"/>
<source>Change stats to:</source> <source>Change stats to:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3470"/> <location filename="src/game/player/player.cpp" line="3471"/>
<source>Set annotation</source> <source>Set annotation</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3471"/> <location filename="src/game/player/player.cpp" line="3472"/>
<source>Please enter the new annotation:</source> <source>Please enter the new annotation:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3564"/> <location filename="src/game/player/player.cpp" line="3565"/>
<source>Set counters</source> <source>Set counters</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3839"/> <location filename="src/game/player/player.cpp" line="3840"/>
<source>Re&amp;veal to...</source> <source>Re&amp;veal to...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3909"/> <location filename="src/game/player/player.cpp" line="3910"/>
<source>View related cards</source> <source>View related cards</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3957"/> <location filename="src/game/player/player.cpp" line="3958"/>
<source>Token: </source> <source>Token: </source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3974"/> <location filename="src/game/player/player.cpp" line="3975"/>
<source>All tokens</source> <source>All tokens</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -5458,7 +5466,7 @@ Please check your shortcut settings!</source>
<name>StableReleaseChannel</name> <name>StableReleaseChannel</name>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="89"/> <location filename="src/client/network/release_channel.cpp" line="89"/>
<source>Stable Releases</source> <source>Default</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
@ -5819,17 +5827,17 @@ Please check your shortcut settings!</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1185"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1188"/>
<source>Open in new tab</source> <source>Open in new tab</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1214"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1217"/>
<source>Are you sure?</source> <source>Are you sure?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1215"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1218"/>
<source>The decklist has been modified. <source>The decklist has been modified.
Do you want to save the changes?</source> Do you want to save the changes?</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -5845,8 +5853,8 @@ Do you want to save the changes?</source>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>Error</source> <source>Error</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -5873,12 +5881,12 @@ Please check that the directory is writable and try again.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<source>There are no cards in your deck to be exported</source> <source>There are no cards in your deck to be exported</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>No deck was selected to be saved.</source> <source>No deck was selected to be saved.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View file

@ -64,6 +64,7 @@ void TabDeckEditor::createDeckDock()
deckView->header()->setSectionResizeMode(QHeaderView::ResizeToContents); deckView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
deckView->installEventFilter(&deckViewKeySignals); deckView->installEventFilter(&deckViewKeySignals);
deckView->setContextMenuPolicy(Qt::CustomContextMenu); deckView->setContextMenuPolicy(Qt::CustomContextMenu);
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &))); SLOT(updateCardInfoRight(const QModelIndex &, const QModelIndex &)));
connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this, connect(deckView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex &, const QModelIndex &)), this,
@ -1038,6 +1039,9 @@ bool TabDeckEditor::actSaveDeckAs()
return false; return false;
} }
setModified(false); setModified(false);
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
return true; return true;
} }
@ -1238,6 +1242,23 @@ CardInfoPtr TabDeckEditor::currentCardInfo() const
return CardDatabaseManager::getInstance()->getCard(cardName); return CardDatabaseManager::getInstance()->getCard(cardName);
} }
/**
* Gets the index of all the currently selected card nodes in the decklist table.
* The list is in reverse order of the visual selection, so that rows can be deleted while iterating over them.
*
* @return A model index list containing all selected card nodes
*/
QModelIndexList TabDeckEditor::getSelectedCardNodes() const
{
auto selectedRows = deckView->selectionModel()->selectedRows();
const auto notLeafNode = [this](const auto &index) { return deckModel->hasChildren(index); };
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
std::reverse(selectedRows.begin(), selectedRows.end());
return selectedRows;
}
void TabDeckEditor::addCardHelper(QString zoneName) void TabDeckEditor::addCardHelper(QString zoneName)
{ {
const CardInfoPtr info = currentCardInfo(); const CardInfoPtr info = currentCardInfo();
@ -1248,6 +1269,7 @@ void TabDeckEditor::addCardHelper(QString zoneName)
QModelIndex newCardIndex = deckModel->addPreferredPrintingCard(info->getName(), zoneName, false); QModelIndex newCardIndex = deckModel->addPreferredPrintingCard(info->getName(), zoneName, false);
recursiveExpand(newCardIndex); recursiveExpand(newCardIndex);
deckView->clearSelection();
deckView->setCurrentIndex(newCardIndex); deckView->setCurrentIndex(newCardIndex);
setModified(true); setModified(true);
searchEdit->setSelection(0, searchEdit->text().length()); searchEdit->setSelection(0, searchEdit->text().length());
@ -1296,25 +1318,41 @@ void TabDeckEditor::actAddCardToSideboard()
void TabDeckEditor::actRemoveCard() void TabDeckEditor::actRemoveCard()
{ {
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex(); auto selectedRows = getSelectedCardNodes();
if (!currentIndex.isValid() || deckModel->hasChildren(currentIndex))
return;
deckModel->removeRow(currentIndex.row(), currentIndex.parent());
DeckLoader *const deck = deckModel->getDeckList(); // hack to maintain the old reselection behavior when currently selected row of a single-selection gets deleted
setSaveStatus(!deck->isEmpty()); // TODO: remove the hack and also handle reselection when all rows of a multi-selection gets deleted
setModified(true); if (selectedRows.length() == 1) {
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
bool modified = false;
for (const auto &index : selectedRows) {
if (!index.isValid() || deckModel->hasChildren(index)) {
continue;
}
deckModel->removeRow(index.row(), index.parent());
modified = true;
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
if (modified) {
DeckLoader *const deck = deckModel->getDeckList();
setSaveStatus(!deck->isEmpty());
setModified(true);
}
} }
void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset) void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset)
{ {
if (!idx.isValid() || offset == 0) if (!idx.isValid() || deckModel->hasChildren(idx)) {
return; return;
}
const QModelIndex numberIndex = idx.sibling(idx.row(), 0); const QModelIndex numberIndex = idx.sibling(idx.row(), 0);
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt(); const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
const int new_count = count + offset; const int new_count = count + offset;
deckView->setCurrentIndex(numberIndex);
if (new_count <= 0) if (new_count <= 0)
deckModel->removeRow(idx.row(), idx.parent()); deckModel->removeRow(idx.row(), idx.parent());
else else
@ -1325,14 +1363,18 @@ void TabDeckEditor::offsetCountAtIndex(const QModelIndex &idx, int offset)
void TabDeckEditor::decrementCardHelper(QString zoneName) void TabDeckEditor::decrementCardHelper(QString zoneName)
{ {
const CardInfoPtr info = currentCardInfo(); const CardInfoPtr info = currentCardInfo();
QModelIndex idx;
if (!info) if (!info)
return; return;
if (info->getIsToken()) if (info->getIsToken())
zoneName = DECK_ZONE_TOKENS; zoneName = DECK_ZONE_TOKENS;
idx = deckModel->findCard(info->getName(), zoneName); QModelIndex idx = deckModel->findCard(info->getName(), zoneName);
if (!idx.isValid()) {
return;
}
deckView->clearSelection();
deckView->setCurrentIndex(idx);
offsetCountAtIndex(idx, -1); offsetCountAtIndex(idx, -1);
} }
@ -1354,14 +1396,28 @@ void TabDeckEditor::copyDatabaseCellContents()
void TabDeckEditor::actIncrement() void TabDeckEditor::actIncrement()
{ {
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex(); auto selectedRows = getSelectedCardNodes();
offsetCountAtIndex(currentIndex, 1);
for (const auto &index : selectedRows) {
offsetCountAtIndex(index, 1);
}
} }
void TabDeckEditor::actDecrement() void TabDeckEditor::actDecrement()
{ {
const QModelIndex &currentIndex = deckView->selectionModel()->currentIndex(); auto selectedRows = getSelectedCardNodes();
offsetCountAtIndex(currentIndex, -1);
// hack to maintain the old reselection behavior when currently selected row of a single-selection gets deleted
// TODO: remove the hack and also handle reselection when all rows of a multi-selection gets deleted
if (selectedRows.length() == 1) {
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
}
for (const auto &index : selectedRows) {
offsetCountAtIndex(index, -1);
}
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
} }
void TabDeckEditor::setDeck(DeckLoader *_deck) void TabDeckEditor::setDeck(DeckLoader *_deck)

View file

@ -111,6 +111,8 @@ private:
void recursiveExpand(const QModelIndex &index); void recursiveExpand(const QModelIndex &index);
void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation); void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
QModelIndexList getSelectedCardNodes() const;
CardDatabaseModel *databaseModel; CardDatabaseModel *databaseModel;
CardDatabaseDisplayModel *databaseDisplayModel; CardDatabaseDisplayModel *databaseDisplayModel;
DeckListModel *deckModel; DeckListModel *deckModel;

View file

@ -25,7 +25,7 @@ AbstractCardItem::AbstractCardItem(QGraphicsItem *parent,
setCacheMode(DeviceCoordinateCache); setCacheMode(DeviceCoordinateCache);
connect(&SettingsCache::instance(), SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate())); connect(&SettingsCache::instance(), SIGNAL(displayCardNamesChanged()), this, SLOT(callUpdate()));
cardInfoUpdated(); refreshCardInfo();
} }
AbstractCardItem::~AbstractCardItem() AbstractCardItem::~AbstractCardItem()
@ -51,7 +51,7 @@ void AbstractCardItem::pixmapUpdated()
emit sigPixmapUpdated(); emit sigPixmapUpdated();
} }
void AbstractCardItem::cardInfoUpdated() void AbstractCardItem::refreshCardInfo()
{ {
info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(name, providerId); info = CardDatabaseManager::getInstance()->getCardByNameAndProviderId(name, providerId);
@ -185,7 +185,7 @@ void AbstractCardItem::setName(const QString &_name)
disconnect(info.data(), nullptr, this, nullptr); disconnect(info.data(), nullptr, this, nullptr);
name = _name; name = _name;
cardInfoUpdated(); refreshCardInfo();
} }
void AbstractCardItem::setProviderId(const QString &_providerId) void AbstractCardItem::setProviderId(const QString &_providerId)
@ -200,7 +200,7 @@ void AbstractCardItem::setProviderId(const QString &_providerId)
} }
providerId = _providerId; providerId = _providerId;
cardInfoUpdated(); refreshCardInfo();
} }
void AbstractCardItem::setHovered(bool _hovered) void AbstractCardItem::setHovered(bool _hovered)

View file

@ -28,11 +28,14 @@ private:
qreal realZValue; qreal realZValue;
private slots: private slots:
void pixmapUpdated(); void pixmapUpdated();
void cardInfoUpdated();
void callUpdate() void callUpdate()
{ {
update(); update();
} }
public slots:
void refreshCardInfo();
signals: signals:
void hovered(AbstractCardItem *card); void hovered(AbstractCardItem *card);
void showCardInfoPopup(const QPoint &pos, const QString &cardName, const QString &providerId); void showCardInfoPopup(const QPoint &pos, const QString &cardName, const QString &providerId);

View file

@ -217,13 +217,15 @@ void CardItem::setAttachedTo(CardItem *_attachedTo)
} }
} }
void CardItem::resetState() void CardItem::resetState(bool keepAnnotations)
{ {
attacking = false; attacking = false;
facedown = false; facedown = false;
counters.clear(); counters.clear();
pt.clear(); pt.clear();
annotation.clear(); if (!keepAnnotations) {
annotation.clear();
}
attachedTo = 0; attachedTo = 0;
attachedCards.clear(); attachedCards.clear();
setTapped(false, false); setTapped(false, false);

View file

@ -139,7 +139,7 @@ public:
{ {
return attachedCards; return attachedCards;
} }
void resetState(); void resetState(bool keepAnnotations = false);
void processCardInfo(const ServerInfo_Card &_info); void processCardInfo(const ServerInfo_Card &_info);
QMenu *getCardMenu() const QMenu *getCardMenu() const

View file

@ -1,5 +1,6 @@
#include "card_zone.h" #include "card_zone.h"
#include "../cards/card_database_manager.h"
#include "../cards/card_item.h" #include "../cards/card_item.h"
#include "../player/player.h" #include "../player/player.h"
#include "pb/command_move_card.pb.h" #include "pb/command_move_card.pb.h"
@ -31,6 +32,11 @@ CardZone::CardZone(Player *_p,
{ {
if (!isView) if (!isView)
player->addZone(this); player->addZone(this);
// If we join a game before the card db finishes loading, the cards might have the wrong printings.
// Force refresh all cards in the zone when db finishes loading to fix that.
connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this,
&CardZone::refreshCardInfos);
} }
CardZone::~CardZone() CardZone::~CardZone()
@ -119,6 +125,13 @@ bool CardZone::showContextMenu(const QPoint &screenPos)
return false; return false;
} }
void CardZone::refreshCardInfos()
{
for (const auto &cardItem : cards) {
cardItem->refreshCardInfo();
}
}
void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event) void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
{ {
if (event->button() == Qt::RightButton) { if (event->button() == Qt::RightButton) {

View file

@ -43,6 +43,9 @@ public slots:
void moveAllToZone(); void moveAllToZone();
bool showContextMenu(const QPoint &screenPos); bool showContextMenu(const QPoint &screenPos);
private slots:
void refreshCardInfos();
public: public:
enum enum
{ {

View file

@ -37,7 +37,7 @@ void StackZone::addCardImpl(CardItem *card, int x, int /*y*/)
card->setName(); card->setName();
} }
card->setParentItem(this); card->setParentItem(this);
card->resetState(); card->resetState(true);
card->setVisible(true); card->setVisible(true);
card->update(); card->update();
} }

File diff suppressed because it is too large Load diff

View file

@ -281,8 +281,8 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<name>BetaReleaseChannel</name> <name>BetaReleaseChannel</name>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="203"/> <location filename="src/client/network/release_channel.cpp" line="203"/>
<source>Beta Releases</source> <source>Beta</source>
<translation>Beta Releases</translation> <translation>Beta</translation>
</message> </message>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="229"/> <location filename="src/client/network/release_channel.cpp" line="229"/>
@ -423,21 +423,29 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<context> <context>
<name>CardInfoFrameWidget</name> <name>CardInfoFrameWidget</name>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="66"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="69"/>
<source>Image</source> <source>Image</source>
<translation>Image</translation> <translation>Image</translation>
</message> </message>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="67"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="70"/>
<source>Description</source> <source>Description</source>
<translation>Description</translation> <translation>Description</translation>
</message> </message>
<message> <message>
<location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="68"/> <location filename="src/client/ui/widgets/cards/card_info_frame_widget.cpp" line="71"/>
<source>Both</source> <source>Both</source>
<translation>Both</translation> <translation>Both</translation>
</message> </message>
</context> </context>
<context>
<name>CardInfoPictureWidget</name>
<message>
<location filename="src/client/ui/widgets/cards/card_info_picture_widget.cpp" line="256"/>
<source>View related cards</source>
<translation>View related cards</translation>
</message>
</context>
<context> <context>
<name>CardInfoTextWidget</name> <name>CardInfoTextWidget</name>
<message> <message>
@ -480,121 +488,121 @@ This is only saved for moderators and cannot be seen by the banned person.</tran
<context> <context>
<name>CardZone</name> <name>CardZone</name>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="72"/> <location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>their hand</source> <source>their hand</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>their hand</translation> <translation>their hand</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="72"/> <location filename="src/game/zones/card_zone.cpp" line="78"/>
<source>%1&apos;s hand</source> <source>%1&apos;s hand</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>%1&apos;s hand</translation> <translation>%1&apos;s hand</translation>
</message> </message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="76"/>
<source>their library</source>
<comment>look at zone</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="77"/>
<source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="79"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation>of their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="80"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation>of %1&apos;s library</translation>
</message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="82"/> <location filename="src/game/zones/card_zone.cpp" line="82"/>
<source>their library</source> <source>their library</source>
<comment>reveal zone</comment> <comment>look at zone</comment>
<translation>their library</translation> <translation>their library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="83"/> <location filename="src/game/zones/card_zone.cpp" line="83"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>look at zone</comment>
<translation>%1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="85"/>
<source>of their library</source>
<comment>top cards of zone,</comment>
<translation>of their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="86"/>
<source>of %1&apos;s library</source>
<comment>top cards of zone</comment>
<translation>of %1&apos;s library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="88"/>
<source>their library</source>
<comment>reveal zone</comment>
<translation>their library</translation>
</message>
<message>
<location filename="src/game/zones/card_zone.cpp" line="89"/>
<source>%1&apos;s library</source>
<comment>reveal zone</comment> <comment>reveal zone</comment>
<translation>%1&apos;s library</translation> <translation>%1&apos;s library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="85"/> <location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>their library</source> <source>their library</source>
<comment>shuffle</comment> <comment>shuffle</comment>
<translation>their library</translation> <translation>their library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="85"/> <location filename="src/game/zones/card_zone.cpp" line="91"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>shuffle</comment> <comment>shuffle</comment>
<translation>%1&apos;s library</translation> <translation>%1&apos;s library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="87"/> <location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>their library</source> <source>their library</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>their library</translation> <translation>their library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="87"/> <location filename="src/game/zones/card_zone.cpp" line="93"/>
<source>%1&apos;s library</source> <source>%1&apos;s library</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>%1&apos;s library</translation> <translation>%1&apos;s library</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="90"/> <location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>their graveyard</source> <source>their graveyard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>their graveyard</translation> <translation>their graveyard</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="90"/> <location filename="src/game/zones/card_zone.cpp" line="96"/>
<source>%1&apos;s graveyard</source> <source>%1&apos;s graveyard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>%1&apos;s graveyard</translation> <translation>%1&apos;s graveyard</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="92"/> <location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>their exile</source> <source>their exile</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>their exile</translation> <translation>their exile</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="92"/> <location filename="src/game/zones/card_zone.cpp" line="98"/>
<source>%1&apos;s exile</source> <source>%1&apos;s exile</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>%1&apos;s exile</translation> <translation>%1&apos;s exile</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="96"/> <location filename="src/game/zones/card_zone.cpp" line="102"/>
<source>their sideboard</source> <source>their sideboard</source>
<comment>look at zone</comment> <comment>look at zone</comment>
<translation>their sideboard</translation> <translation>their sideboard</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="97"/> <location filename="src/game/zones/card_zone.cpp" line="103"/>
<source>%1&apos;s sideboard</source> <source>%1&apos;s sideboard</source>
<comment>look at zone</comment> <comment>look at zone</comment>
<translation>%1&apos;s sideboard</translation> <translation>%1&apos;s sideboard</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="99"/> <location filename="src/game/zones/card_zone.cpp" line="105"/>
<source>their sideboard</source> <source>their sideboard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>their sideboard</translation> <translation>their sideboard</translation>
</message> </message>
<message> <message>
<location filename="src/game/zones/card_zone.cpp" line="100"/> <location filename="src/game/zones/card_zone.cpp" line="106"/>
<source>%1&apos;s sideboard</source> <source>%1&apos;s sideboard</source>
<comment>nominative</comment> <comment>nominative</comment>
<translation>%1&apos;s sideboard</translation> <translation>%1&apos;s sideboard</translation>
@ -4705,7 +4713,7 @@ Cockatrice will now reload the card database.</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="1901"/> <location filename="src/game/player/player.cpp" line="1901"/>
<location filename="src/game/player/player.cpp" line="3564"/> <location filename="src/game/player/player.cpp" line="3565"/>
<source>Number:</source> <source>Number:</source>
<translation>Number:</translation> <translation>Number:</translation>
</message> </message>
@ -4816,7 +4824,7 @@ Cockatrice will now reload the card database.</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="1753"/> <location filename="src/game/player/player.cpp" line="1753"/>
<location filename="src/game/player/player.cpp" line="4084"/> <location filename="src/game/player/player.cpp" line="4085"/>
<source>C&amp;reate another %1 token</source> <source>C&amp;reate another %1 token</source>
<translation>C&amp;reate another %1 token</translation> <translation>C&amp;reate another %1 token</translation>
</message> </message>
@ -4831,47 +4839,47 @@ Cockatrice will now reload the card database.</translation>
<translation>Place card X cards from top of library</translation> <translation>Place card X cards from top of library</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3351"/> <location filename="src/game/player/player.cpp" line="3352"/>
<source>Change power/toughness</source> <source>Change power/toughness</source>
<translation>Change power/toughness</translation> <translation>Change power/toughness</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3351"/> <location filename="src/game/player/player.cpp" line="3352"/>
<source>Change stats to:</source> <source>Change stats to:</source>
<translation>Change stats to:</translation> <translation>Change stats to:</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3470"/> <location filename="src/game/player/player.cpp" line="3471"/>
<source>Set annotation</source> <source>Set annotation</source>
<translation>Set annotation</translation> <translation>Set annotation</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3471"/> <location filename="src/game/player/player.cpp" line="3472"/>
<source>Please enter the new annotation:</source> <source>Please enter the new annotation:</source>
<translation>Please enter the new annotation:</translation> <translation>Please enter the new annotation:</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3564"/> <location filename="src/game/player/player.cpp" line="3565"/>
<source>Set counters</source> <source>Set counters</source>
<translation>Set counters</translation> <translation>Set counters</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3839"/> <location filename="src/game/player/player.cpp" line="3840"/>
<source>Re&amp;veal to...</source> <source>Re&amp;veal to...</source>
<translation>Re&amp;veal to...</translation> <translation>Re&amp;veal to...</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3909"/> <location filename="src/game/player/player.cpp" line="3910"/>
<source>View related cards</source> <source>View related cards</source>
<translation>View related cards</translation> <translation>View related cards</translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3957"/> <location filename="src/game/player/player.cpp" line="3958"/>
<source>Token: </source> <source>Token: </source>
<translation>Token: </translation> <translation>Token: </translation>
</message> </message>
<message> <message>
<location filename="src/game/player/player.cpp" line="3974"/> <location filename="src/game/player/player.cpp" line="3975"/>
<source>All tokens</source> <source>All tokens</source>
<translation>All tokens</translation> <translation>All tokens</translation>
</message> </message>
@ -5483,8 +5491,8 @@ Please check your shortcut settings!</translation>
<name>StableReleaseChannel</name> <name>StableReleaseChannel</name>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="89"/> <location filename="src/client/network/release_channel.cpp" line="89"/>
<source>Stable Releases</source> <source>Default</source>
<translation>Stable Releases</translation> <translation>Default</translation>
</message> </message>
<message> <message>
<location filename="src/client/network/release_channel.cpp" line="105"/> <location filename="src/client/network/release_channel.cpp" line="105"/>
@ -5844,17 +5852,17 @@ Please check your shortcut settings!</translation>
<translation>Could not open deck at %1</translation> <translation>Could not open deck at %1</translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1185"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1188"/>
<source>Open in new tab</source> <source>Open in new tab</source>
<translation>Open in new tab</translation> <translation>Open in new tab</translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1214"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1217"/>
<source>Are you sure?</source> <source>Are you sure?</source>
<translation>Are you sure?</translation> <translation>Are you sure?</translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1215"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1218"/>
<source>The decklist has been modified. <source>The decklist has been modified.
Do you want to save the changes?</source> Do you want to save the changes?</source>
<translation>The decklist has been modified. <translation>The decklist has been modified.
@ -5871,8 +5879,8 @@ Do you want to save the changes?</translation>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="994"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1015"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1036"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>Error</source> <source>Error</source>
<translation>Error</translation> <translation>Error</translation>
</message> </message>
@ -5900,12 +5908,12 @@ Please check that the directory is writable and try again.</translation>
<translation>Save deck</translation> <translation>Save deck</translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1105"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1108"/>
<source>There are no cards in your deck to be exported</source> <source>There are no cards in your deck to be exported</source>
<translation>There are no cards in your deck to be exported</translation> <translation>There are no cards in your deck to be exported</translation>
</message> </message>
<message> <message>
<location filename="src/client/tabs/tab_deck_editor.cpp" line="1117"/> <location filename="src/client/tabs/tab_deck_editor.cpp" line="1120"/>
<source>No deck was selected to be saved.</source> <source>No deck was selected to be saved.</source>
<translation>No deck was selected to be saved.</translation> <translation>No deck was selected to be saved.</translation>
</message> </message>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -54,13 +54,15 @@ Server_Card::~Server_Card()
} }
} }
void Server_Card::resetState() void Server_Card::resetState(bool keepAnnotations)
{ {
counters.clear(); counters.clear();
setTapped(false); setTapped(false);
setAttacking(false); setAttacking(false);
setPT(QString()); setPT(QString());
setAnnotation(QString()); if (!keepAnnotations) {
setAnnotation(QString());
}
setDoesntUntap(false); setDoesntUntap(false);
} }

View file

@ -218,7 +218,7 @@ public:
return oldStashedCard; return oldStashedCard;
} }
void resetState(); void resetState(bool keepAnnotations = false);
QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards); QString setAttribute(CardAttribute attribute, const QString &avalue, bool allCards);
QString setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event = nullptr); QString setAttribute(CardAttribute attribute, const QString &avalue, Event_SetCardAttr *event = nullptr);

View file

@ -548,7 +548,7 @@ Response::ResponseCode Server_Player::moveCard(GameEventStorage &ges,
newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown); newX = targetzone->getFreeGridColumn(newX, yCoord, card->getName(), faceDown);
} else { } else {
yCoord = 0; yCoord = 0;
card->resetState(); card->resetState(targetzone->getName() == "stack");
} }
targetzone->insertCard(card, newX, yCoord); targetzone->insertCard(card, newX, yCoord);

View file

@ -89,7 +89,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<message> <message>
<location filename="src/oraclewizard.cpp" line="336"/> <location filename="src/oraclewizard.cpp" line="336"/>
<source>Please choose a file.</source> <source>Please choose a file.</source>
<translation>Selezina un file.</translation> <translation>Seleziona un file.</translation>
</message> </message>
<message> <message>
<location filename="src/oraclewizard.cpp" line="341"/> <location filename="src/oraclewizard.cpp" line="341"/>
@ -246,7 +246,7 @@ e pedine che verranno usate da Cockatrice.</translation>
<context> <context>
<name>OracleImporter</name> <name>OracleImporter</name>
<message> <message>
<location filename="src/oracleimporter.cpp" line="460"/> <location filename="src/oracleimporter.cpp" line="465"/>
<source>Dummy set containing tokens</source> <source>Dummy set containing tokens</source>
<translation>Set finto contenente i token</translation> <translation>Set finto contenente i token</translation>
</message> </message>

View file

@ -0,0 +1,11 @@
-- Servatrice db migration from version 30 to version 31
ALTER TABLE cockatrice_log DROP INDEX `target_type`;
ALTER TABLE cockatrice_forgot_password ADD INDEX idx_emailed (`emailed`);
ALTER TABLE cockatrice_sessions ADD INDEX idx_start_time (`start_time`);
ALTER TABLE cockatrice_users ADD INDEX idx_admin (`admin`);
ALTER TABLE cockatrice_users ADD INDEX idx_active (`active`);
ALTER TABLE cockatrice_users ADD INDEX idx_privlevel (`privlevel`);
UPDATE cockatrice_schema_version SET version=31 WHERE version=30;

View file

@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_schema_version` (
PRIMARY KEY (`version`) PRIMARY KEY (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
INSERT INTO cockatrice_schema_version VALUES(30); INSERT INTO cockatrice_schema_version VALUES(31);
-- users and user data tables -- users and user data tables
CREATE TABLE IF NOT EXISTS `cockatrice_users` ( CREATE TABLE IF NOT EXISTS `cockatrice_users` (
@ -44,7 +44,10 @@ CREATE TABLE IF NOT EXISTS `cockatrice_users` (
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`), UNIQUE KEY `name` (`name`),
KEY `token` (`token`), KEY `token` (`token`),
KEY `email` (`email`) KEY `email` (`email`),
INDEX `idx_admin` (`admin`),
INDEX `idx_active` (`active`),
INDEX `idx_privlevel` (`privlevel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` ( CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` (
@ -190,7 +193,8 @@ CREATE TABLE IF NOT EXISTS `cockatrice_sessions` (
`clientid` varchar(15) NOT NULL, `clientid` varchar(15) NOT NULL,
`connection_type` ENUM('tcp', 'websocket'), `connection_type` ENUM('tcp', 'websocket'),
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `username` (`user_name`) KEY `username` (`user_name`),
INDEX `idx_start_time` (`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
-- server moderation -- server moderation
@ -230,7 +234,6 @@ CREATE TABLE IF NOT EXISTS `cockatrice_log` (
`target_name` varchar(50) NOT NULL, `target_name` varchar(50) NOT NULL,
KEY `sender_name` (`sender_name`), KEY `sender_name` (`sender_name`),
KEY `sender_ip` (`sender_ip`), KEY `sender_ip` (`sender_ip`),
KEY `target_type` (`target_type`),
KEY `target_id` (`target_id`), KEY `target_id` (`target_id`),
KEY `target_name` (`target_name`), KEY `target_name` (`target_name`),
FOREIGN KEY(`sender_id`) REFERENCES `cockatrice_users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE FOREIGN KEY(`sender_id`) REFERENCES `cockatrice_users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
@ -269,7 +272,8 @@ CREATE TABLE IF NOT EXISTS `cockatrice_forgot_password` (
`requestDate` datetime NOT NULL default '0000-00-00 00:00:00', `requestDate` datetime NOT NULL default '0000-00-00 00:00:00',
`emailed` tinyint(1) NOT NULL default 0, `emailed` tinyint(1) NOT NULL default 0,
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
KEY `user_name` (`name`) KEY `user_name` (`name`),
INDEX `idx_emailed` (`emailed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `cockatrice_audit` ( CREATE TABLE IF NOT EXISTS `cockatrice_audit` (

View file

@ -103,12 +103,25 @@ bool Servatrice_DatabaseInterface::openDatabase()
bool Servatrice_DatabaseInterface::checkSql() bool Servatrice_DatabaseInterface::checkSql()
{ {
if (!sqlDatabase.isValid()) if (!sqlDatabase.isValid()) {
return false; return false;
}
auto query = QSqlQuery(sqlDatabase); auto query = QSqlQuery(sqlDatabase);
if (query.exec("select 1") && query.isActive()) if (query.exec("select 1") && query.isActive()) {
return openDatabase(); return openDatabase();
}
if (query.lastError().isValid()) {
const auto &poolStr = instanceId == -1 ? QString("main") : QString("pool %1").arg(instanceId);
qCritical() << QString("[%1] Error executing query: %2, resetting connection")
.arg(poolStr)
.arg(query.lastError().text());
sqlDatabase.close();
return openDatabase();
}
return true; return true;
} }
@ -1197,6 +1210,11 @@ QList<ServerInfo_ChatMessage> Servatrice_DatabaseInterface::getMessageLogHistory
if (!checkSql()) if (!checkSql())
return results; return results;
if (user.isEmpty() && ipaddress.isEmpty() && gameid.isEmpty() && gamename.isEmpty()) {
// To ensure quick results and minimal lag, require an indexed field
return results;
}
// BUILD QUERY STRING BASED ON PASSED IN VALUES // BUILD QUERY STRING BASED ON PASSED IN VALUES
QString queryString = "SELECT * FROM {prefix}_log WHERE `sender_ip` IS NOT NULL"; QString queryString = "SELECT * FROM {prefix}_log WHERE `sender_ip` IS NOT NULL";
if (!user.isEmpty()) if (!user.isEmpty())

View file

@ -9,7 +9,7 @@
#include <QObject> #include <QObject>
#include <QSqlDatabase> #include <QSqlDatabase>
#define DATABASE_SCHEMA_VERSION 30 #define DATABASE_SCHEMA_VERSION 31
class Servatrice; class Servatrice;

View file

@ -158,7 +158,7 @@
"LS": "Lesotho", "LS": "Lesotho",
"LT": "Lituania", "LT": "Lituania",
"LU": "Lussemburgo", "LU": "Lussemburgo",
"LV": "Latvia", "LV": "Lettonia",
"LY": "Libia", "LY": "Libia",
"MA": "Marocco", "MA": "Marocco",
"MC": "Monaco", "MC": "Monaco",
@ -298,7 +298,7 @@
"subtitle": "Un portale digitale multi-piattaforma per giochi di carte multigiocatore" "subtitle": "Un portale digitale multi-piattaforma per giochi di carte multigiocatore"
}, },
"footer": { "footer": {
"registerPrompt": "Non ancora registrato?", "registerPrompt": "Non sei ancora registrato?",
"registerAction": "Crea un nuovo account", "registerAction": "Crea un nuovo account",
"credit": "Cockatrice è un progetto open source", "credit": "Cockatrice è un progetto open source",
"version": "Versione" "version": "Versione"
@ -314,17 +314,17 @@
}, },
"UnsupportedContainer": { "UnsupportedContainer": {
"title": "Browser non supportato", "title": "Browser non supportato",
"subtitle1": "Per favore aggiornare il browser e/o controllare i permessi.", "subtitle1": "Aggiornare il browser e/o controllare i permessi.",
"subtitle2": "Nota: la navigazione Privata può far si che il browser disabiliti certi permessi o funzionalità." "subtitle2": "Nota: la navigazione Privata può far si che il browser disabiliti certi permessi o funzionalità."
}, },
"AccountActivationDialog": { "AccountActivationDialog": {
"title": "Attivazione dell'account", "title": "Attivazione dell'account",
"subtitle1": "Il tuo account non è ancora stato attivato.", "subtitle1": "Il tuo account non è ancora stato attivato.",
"subtitle2": "È necessario fornire il token di attivazione ricevuto nell'e-mail di attivazione." "subtitle2": "È necessario fornire il codice ricevuto nell'e-mail di attivazione."
}, },
"KnownHostDialog": { "KnownHostDialog": {
"title": "{modalità, seleziona, modifica {Modifica} altro {Aggiungi}} Host conosciuto", "title": "{modalità, seleziona, modifica {Modifica} altro {Aggiungi}} Host conosciuto",
"subtitle": "L'aggiunta di un nuovo host consente di connettersi a server diversi. Inserisci i dettagli di seguito nella tua lista di host." "subtitle": "L'aggiunta di un nuovo host consente di connettersi a server diversi. Inserisci i dettagli di seguito nella lista degli host."
}, },
"RegistrationDialog": { "RegistrationDialog": {
"title": "Crea un nuovo account" "title": "Crea un nuovo account"