mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-09 01:23:57 -07:00
Merge branch 'master' into 6269/ci/strip-fat-bins
This commit is contained in:
commit
fa795c2cb6
47 changed files with 752 additions and 121 deletions
|
|
@ -53,7 +53,6 @@ set(cockatrice_SOURCES
|
||||||
src/game/board/abstract_card_drag_item.cpp
|
src/game/board/abstract_card_drag_item.cpp
|
||||||
src/game/board/abstract_card_item.cpp
|
src/game/board/abstract_card_item.cpp
|
||||||
src/game/board/abstract_counter.cpp
|
src/game/board/abstract_counter.cpp
|
||||||
src/game/board/abstract_graphics_item.cpp
|
|
||||||
src/game/board/arrow_item.cpp
|
src/game/board/arrow_item.cpp
|
||||||
src/game/board/arrow_target.cpp
|
src/game/board/arrow_target.cpp
|
||||||
src/game/board/card_drag_item.cpp
|
src/game/board/card_drag_item.cpp
|
||||||
|
|
@ -113,6 +112,7 @@ set(cockatrice_SOURCES
|
||||||
src/game/zones/table_zone.cpp
|
src/game/zones/table_zone.cpp
|
||||||
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/game_graphics/board/abstract_graphics_item.cpp
|
||||||
src/interface/card_picture_loader/card_picture_loader.cpp
|
src/interface/card_picture_loader/card_picture_loader.cpp
|
||||||
src/interface/card_picture_loader/card_picture_loader_local.cpp
|
src/interface/card_picture_loader/card_picture_loader_local.cpp
|
||||||
src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.cpp
|
src/interface/card_picture_loader/card_picture_loader_request_status_display_widget.cpp
|
||||||
|
|
@ -145,6 +145,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_analytics/mana_base_widget.cpp
|
src/interface/widgets/deck_analytics/mana_base_widget.cpp
|
||||||
src/interface/widgets/deck_analytics/mana_curve_widget.cpp
|
src/interface/widgets/deck_analytics/mana_curve_widget.cpp
|
||||||
src/interface/widgets/deck_analytics/mana_devotion_widget.cpp
|
src/interface/widgets/deck_analytics/mana_devotion_widget.cpp
|
||||||
|
src/interface/widgets/deck_editor/deck_list_history_manager_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_card_info_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_database_display_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_deck_dock_widget.cpp
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,14 @@
|
||||||
|
|
||||||
<file>resources/icons/arrow_bottom_green.svg</file>
|
<file>resources/icons/arrow_bottom_green.svg</file>
|
||||||
<file>resources/icons/arrow_down_green.svg</file>
|
<file>resources/icons/arrow_down_green.svg</file>
|
||||||
|
<file>resources/icons/arrow_history.svg</file>
|
||||||
<file>resources/icons/arrow_left_green.svg</file>
|
<file>resources/icons/arrow_left_green.svg</file>
|
||||||
|
<file>resources/icons/arrow_redo.svg</file>
|
||||||
<file>resources/icons/arrow_right_blue.svg</file>
|
<file>resources/icons/arrow_right_blue.svg</file>
|
||||||
<file>resources/icons/arrow_right_green.svg</file>
|
<file>resources/icons/arrow_right_green.svg</file>
|
||||||
<file>resources/icons/arrow_top_green.svg</file>
|
<file>resources/icons/arrow_top_green.svg</file>
|
||||||
<file>resources/icons/arrow_up_green.svg</file>
|
<file>resources/icons/arrow_up_green.svg</file>
|
||||||
|
<file>resources/icons/arrow_undo.svg</file>
|
||||||
<file>resources/icons/clearsearch.svg</file>
|
<file>resources/icons/clearsearch.svg</file>
|
||||||
<file>resources/icons/cogwheel.svg</file>
|
<file>resources/icons/cogwheel.svg</file>
|
||||||
<file>resources/icons/conceded.svg</file>
|
<file>resources/icons/conceded.svg</file>
|
||||||
|
|
|
||||||
8
cockatrice/resources/icons/arrow_history.svg
Normal file
8
cockatrice/resources/icons/arrow_history.svg
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||||
|
<title>
|
||||||
|
history
|
||||||
|
</title>
|
||||||
|
<path d="M9 6v5h.06l2.48 2.47 1.41-1.41L11 10.11V6H9z"/>
|
||||||
|
<path d="M10 1a9 9 0 0 0-7.85 13.35L.5 16H6v-5.5l-2.38 2.38A7 7 0 1 1 10 17v2a9 9 0 0 0 0-18z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 332 B |
40
cockatrice/resources/icons/arrow_redo.svg
Normal file
40
cockatrice/resources/icons/arrow_redo.svg
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="windows-1252"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px"
|
||||||
|
y="0px" width="485.212px" height="485.212px" viewBox="0 0 485.212 485.212"
|
||||||
|
style="enable-background:new 0 0 485.212 485.212;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M242.607,424.559c-75.252,0-136.468-61.209-136.468-136.465c0-75.252,61.216-136.466,136.468-136.466v90.978 l151.629-121.302L242.607,0v90.978c-108.687,0-197.117,88.432-197.117,197.117c0,108.691,88.43,197.118,197.117,197.118 c108.687,0,197.114-88.427,197.114-197.118h-60.645C379.077,363.35,317.859,424.559,242.607,424.559z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1,018 B |
40
cockatrice/resources/icons/arrow_undo.svg
Normal file
40
cockatrice/resources/icons/arrow_undo.svg
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?xml version="1.0" encoding="windows-1252"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" x="0px"
|
||||||
|
y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M256,448c79.406,0,144-64.594,144-144s-64.594-144-144-144v96L96,128L256,0v96c114.688,0,208,93.313,208,208 c0,114.688-93.312,208-208,208c-114.687,0-208-93.312-208-208h64C112,383.406,176.594,448,256,448z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 874 B |
|
|
@ -7,8 +7,8 @@
|
||||||
#ifndef ABSTRACTCARDITEM_H
|
#ifndef ABSTRACTCARDITEM_H
|
||||||
#define ABSTRACTCARDITEM_H
|
#define ABSTRACTCARDITEM_H
|
||||||
|
|
||||||
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
#include "arrow_target.h"
|
#include "arrow_target.h"
|
||||||
#include "graphics_item_type.h"
|
|
||||||
|
|
||||||
#include <libcockatrice/card/printing/exact_card.h>
|
#include <libcockatrice/card/printing/exact_card.h>
|
||||||
#include <libcockatrice/utility/card_ref.h>
|
#include <libcockatrice/utility/card_ref.h>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#ifndef ARROWTARGET_H
|
#ifndef ARROWTARGET_H
|
||||||
#define ARROWTARGET_H
|
#define ARROWTARGET_H
|
||||||
|
|
||||||
#include "abstract_graphics_item.h"
|
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "counter_general.h"
|
#include "counter_general.h"
|
||||||
|
|
||||||
|
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||||
#include "../../interface/pixel_map_generator.h"
|
#include "../../interface/pixel_map_generator.h"
|
||||||
#include "abstract_graphics_item.h"
|
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -330,7 +330,7 @@ void DeckViewScene::setDeck(const DeckList &_deck)
|
||||||
if (deck)
|
if (deck)
|
||||||
delete deck;
|
delete deck;
|
||||||
|
|
||||||
deck = new DeckList(_deck);
|
deck = new DeckList(_deck.writeToString_Native());
|
||||||
rebuildTree();
|
rebuildTree();
|
||||||
applySideboardPlan(deck->getCurrentSideboardPlan());
|
applySideboardPlan(deck->getCurrentSideboardPlan());
|
||||||
rearrangeItems();
|
rearrangeItems();
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
#ifndef HANDCOUNTER_H
|
#ifndef HANDCOUNTER_H
|
||||||
#define HANDCOUNTER_H
|
#define HANDCOUNTER_H
|
||||||
|
|
||||||
#include "board/abstract_graphics_item.h"
|
#include "../game_graphics/board/abstract_graphics_item.h"
|
||||||
#include "board/graphics_item_type.h"
|
#include "../game_graphics/board/graphics_item_type.h"
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#ifndef PHASESTOOLBAR_H
|
#ifndef PHASESTOOLBAR_H
|
||||||
#define PHASESTOOLBAR_H
|
#define PHASESTOOLBAR_H
|
||||||
|
|
||||||
#include "board/abstract_graphics_item.h"
|
#include "../game_graphics/board/abstract_graphics_item.h"
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include <QGraphicsObject>
|
#include <QGraphicsObject>
|
||||||
|
|
|
||||||
|
|
@ -263,9 +263,10 @@ void Player::deleteCard(CardItem *card)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setDeck(const DeckLoader &_deck)
|
// TODO: Does a player need a DeckLoader?
|
||||||
|
void Player::setDeck(DeckLoader &_deck)
|
||||||
{
|
{
|
||||||
deck = new DeckLoader(_deck);
|
deck = new DeckLoader(this, _deck.getDeckList());
|
||||||
|
|
||||||
emit deckChanged();
|
emit deckChanged();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
#ifndef PLAYER_H
|
#ifndef PLAYER_H
|
||||||
#define PLAYER_H
|
#define PLAYER_H
|
||||||
|
|
||||||
|
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||||
#include "../board/abstract_graphics_item.h"
|
|
||||||
#include "../dialogs/dlg_create_token.h"
|
#include "../dialogs/dlg_create_token.h"
|
||||||
#include "menu/player_menu.h"
|
#include "menu/player_menu.h"
|
||||||
#include "player_actions.h"
|
#include "player_actions.h"
|
||||||
|
|
@ -130,7 +130,7 @@ public:
|
||||||
return playerMenu;
|
return playerMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDeck(const DeckLoader &_deck);
|
void setDeck(DeckLoader &_deck);
|
||||||
|
|
||||||
[[nodiscard]] DeckLoader *getDeck() const
|
[[nodiscard]] DeckLoader *getDeck() const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#ifndef COCKATRICE_PLAYER_AREA_H
|
#ifndef COCKATRICE_PLAYER_AREA_H
|
||||||
#define COCKATRICE_PLAYER_AREA_H
|
#define COCKATRICE_PLAYER_AREA_H
|
||||||
|
|
||||||
#include "../board/graphics_item_type.h"
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
#include "QGraphicsItem"
|
#include "QGraphicsItem"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
#ifndef PLAYERTARGET_H
|
#ifndef PLAYERTARGET_H
|
||||||
#define PLAYERTARGET_H
|
#define PLAYERTARGET_H
|
||||||
|
|
||||||
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
#include "../board/abstract_counter.h"
|
#include "../board/abstract_counter.h"
|
||||||
#include "../board/arrow_target.h"
|
#include "../board/arrow_target.h"
|
||||||
#include "../board/graphics_item_type.h"
|
|
||||||
|
|
||||||
#include <QFont>
|
#include <QFont>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
#ifndef CARDZONE_H
|
#ifndef CARDZONE_H
|
||||||
#define CARDZONE_H
|
#define CARDZONE_H
|
||||||
|
|
||||||
#include "../board/abstract_graphics_item.h"
|
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||||
#include "../board/graphics_item_type.h"
|
#include "../../game_graphics/board/graphics_item_type.h"
|
||||||
#include "logic/card_zone_logic.h"
|
#include "logic/card_zone_logic.h"
|
||||||
|
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
|
||||||
|
|
@ -33,19 +33,6 @@ DeckLoader::DeckLoader(QObject *parent)
|
||||||
DeckLoader::DeckLoader(QObject *parent, DeckList *_deckList)
|
DeckLoader::DeckLoader(QObject *parent, DeckList *_deckList)
|
||||||
: QObject(parent), deckList(_deckList), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
|
: QObject(parent), deckList(_deckList), lastFileFormat(CockatriceFormat), lastRemoteDeckId(-1)
|
||||||
{
|
{
|
||||||
deckList->setParent(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckLoader::DeckLoader(const DeckLoader &other)
|
|
||||||
: QObject(), deckList(other.deckList), lastFileName(other.lastFileName), lastFileFormat(other.lastFileFormat),
|
|
||||||
lastRemoteDeckId(other.lastRemoteDeckId)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckLoader::setDeckList(DeckList *_deckList)
|
|
||||||
{
|
|
||||||
deckList = _deckList;
|
|
||||||
deckList->setParent(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest)
|
bool DeckLoader::loadFromFile(const QString &fileName, FileFormat fmt, bool userRequest)
|
||||||
|
|
@ -165,12 +152,14 @@ bool DeckLoader::saveToFile(const QString &fileName, FileFormat fmt)
|
||||||
break;
|
break;
|
||||||
case CockatriceFormat:
|
case CockatriceFormat:
|
||||||
result = deckList->saveToFile_Native(&file);
|
result = deckList->saveToFile_Native(&file);
|
||||||
|
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
lastFileName = fileName;
|
lastFileName = fileName;
|
||||||
lastFileFormat = fmt;
|
lastFileFormat = fmt;
|
||||||
|
qCInfo(DeckLoaderLog) << "Deck was saved -" << result;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.flush();
|
file.flush();
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,9 @@ private:
|
||||||
public:
|
public:
|
||||||
DeckLoader(QObject *parent);
|
DeckLoader(QObject *parent);
|
||||||
DeckLoader(QObject *parent, DeckList *_deckList);
|
DeckLoader(QObject *parent, DeckList *_deckList);
|
||||||
void setDeckList(DeckList *_deckList);
|
DeckLoader(const DeckLoader &) = delete;
|
||||||
DeckLoader(const DeckLoader &other);
|
DeckLoader &operator=(const DeckLoader &) = delete;
|
||||||
|
|
||||||
const QString &getLastFileName() const
|
const QString &getLastFileName() const
|
||||||
{
|
{
|
||||||
return lastFileName;
|
return lastFileName;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,30 @@
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
#include <libcockatrice/utility/trice_limits.h>
|
#include <libcockatrice/utility/trice_limits.h>
|
||||||
|
|
||||||
|
static int findRestoreIndex(const CardRef &wanted, const QComboBox *combo)
|
||||||
|
{
|
||||||
|
// Try providerId + name (strongest match)
|
||||||
|
if (!wanted.providerId.isEmpty()) {
|
||||||
|
for (int i = 0; i < combo->count(); ++i) {
|
||||||
|
auto pair = combo->itemData(i).value<QPair<QString, QString>>();
|
||||||
|
if (pair.second == wanted.providerId && pair.first == wanted.name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try name only
|
||||||
|
for (int i = 0; i < combo->count(); ++i) {
|
||||||
|
auto pair = combo->itemData(i).value<QPair<QString, QString>>();
|
||||||
|
if (pair.first == wanted.name) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent)
|
DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent)
|
||||||
: QDockWidget(parent), deckEditor(parent)
|
: QDockWidget(parent), deckEditor(parent)
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +52,11 @@ DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::createDeckDock()
|
void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
{
|
{
|
||||||
|
historyManager = new DeckListHistoryManager();
|
||||||
|
|
||||||
|
connect(deckEditor, &AbstractTabDeckEditor::cardAboutToBeAdded, this,
|
||||||
|
&DeckEditorDeckDockWidget::onCardAboutToBeAdded);
|
||||||
|
|
||||||
deckModel = new DeckListModel(this);
|
deckModel = new DeckListModel(this);
|
||||||
deckModel->setObjectName("deckModel");
|
deckModel->setObjectName("deckModel");
|
||||||
connect(deckModel, &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
|
connect(deckModel, &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
|
||||||
|
|
@ -37,6 +66,10 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
proxy = new DeckListStyleProxy(this);
|
proxy = new DeckListStyleProxy(this);
|
||||||
proxy->setSourceModel(deckModel);
|
proxy->setSourceModel(deckModel);
|
||||||
|
|
||||||
|
historyManagerWidget = new DeckListHistoryManagerWidget(deckModel, proxy, historyManager, this);
|
||||||
|
connect(historyManagerWidget, &DeckListHistoryManagerWidget::requestDisplayWidgetSync, this,
|
||||||
|
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
|
||||||
|
|
||||||
deckView = new QTreeView();
|
deckView = new QTreeView();
|
||||||
deckView->setObjectName("deckView");
|
deckView->setObjectName("deckView");
|
||||||
deckView->setModel(proxy);
|
deckView->setModel(proxy);
|
||||||
|
|
@ -65,7 +98,15 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
nameEdit->setMaxLength(MAX_NAME_LENGTH);
|
nameEdit->setMaxLength(MAX_NAME_LENGTH);
|
||||||
nameEdit->setObjectName("nameEdit");
|
nameEdit->setObjectName("nameEdit");
|
||||||
nameLabel->setBuddy(nameEdit);
|
nameLabel->setBuddy(nameEdit);
|
||||||
connect(nameEdit, &LineEditUnfocusable::textChanged, this, &DeckEditorDeckDockWidget::updateName);
|
|
||||||
|
nameDebounceTimer = new QTimer(this);
|
||||||
|
nameDebounceTimer->setSingleShot(true);
|
||||||
|
nameDebounceTimer->setInterval(300); // debounce duration in ms
|
||||||
|
connect(nameDebounceTimer, &QTimer::timeout, this, [this]() { updateName(nameEdit->text()); });
|
||||||
|
|
||||||
|
connect(nameEdit, &LineEditUnfocusable::textChanged, this, [this]() {
|
||||||
|
nameDebounceTimer->start(); // restart debounce timer
|
||||||
|
});
|
||||||
|
|
||||||
quickSettingsWidget = new SettingsButtonWidget(this);
|
quickSettingsWidget = new SettingsButtonWidget(this);
|
||||||
|
|
||||||
|
|
@ -95,7 +136,16 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
commentsEdit->setMinimumHeight(nameEdit->minimumSizeHint().height());
|
commentsEdit->setMinimumHeight(nameEdit->minimumSizeHint().height());
|
||||||
commentsEdit->setObjectName("commentsEdit");
|
commentsEdit->setObjectName("commentsEdit");
|
||||||
commentsLabel->setBuddy(commentsEdit);
|
commentsLabel->setBuddy(commentsEdit);
|
||||||
connect(commentsEdit, &QTextEdit::textChanged, this, &DeckEditorDeckDockWidget::updateComments);
|
|
||||||
|
commentsDebounceTimer = new QTimer(this);
|
||||||
|
commentsDebounceTimer->setSingleShot(true);
|
||||||
|
commentsDebounceTimer->setInterval(400); // longer debounce for multi-line
|
||||||
|
connect(commentsDebounceTimer, &QTimer::timeout, this, [this]() { updateComments(); });
|
||||||
|
|
||||||
|
connect(commentsEdit, &QTextEdit::textChanged, this, [this]() {
|
||||||
|
commentsDebounceTimer->start(); // restart debounce timer
|
||||||
|
});
|
||||||
|
|
||||||
bannerCardLabel = new QLabel();
|
bannerCardLabel = new QLabel();
|
||||||
bannerCardLabel->setObjectName("bannerCardLabel");
|
bannerCardLabel->setObjectName("bannerCardLabel");
|
||||||
bannerCardLabel->setText(tr("Banner Card"));
|
bannerCardLabel->setText(tr("Banner Card"));
|
||||||
|
|
@ -187,7 +237,8 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
lowerLayout->addWidget(tbDecrement, 0, 3);
|
lowerLayout->addWidget(tbDecrement, 0, 3);
|
||||||
lowerLayout->addWidget(tbRemoveCard, 0, 4);
|
lowerLayout->addWidget(tbRemoveCard, 0, 4);
|
||||||
lowerLayout->addWidget(tbSwapCard, 0, 5);
|
lowerLayout->addWidget(tbSwapCard, 0, 5);
|
||||||
lowerLayout->addWidget(deckView, 1, 0, 1, 6);
|
lowerLayout->addWidget(historyManagerWidget, 0, 6);
|
||||||
|
lowerLayout->addWidget(deckView, 1, 0, 1, 7);
|
||||||
|
|
||||||
// Create widgets for both layouts to make splitter work correctly
|
// Create widgets for both layouts to make splitter work correctly
|
||||||
auto *topWidget = new QWidget;
|
auto *topWidget = new QWidget;
|
||||||
|
|
@ -249,6 +300,8 @@ void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateName(const QString &name)
|
void DeckEditorDeckDockWidget::updateName(const QString &name)
|
||||||
{
|
{
|
||||||
|
historyManager->save(deckLoader->getDeckList()->createMemento(
|
||||||
|
QString(tr("Rename deck to \"%1\" from \"%2\"")).arg(name).arg(deckLoader->getDeckList()->getName())));
|
||||||
deckModel->getDeckList()->setName(name);
|
deckModel->getDeckList()->setName(name);
|
||||||
deckEditor->setModified(name.isEmpty());
|
deckEditor->setModified(name.isEmpty());
|
||||||
emit nameChanged();
|
emit nameChanged();
|
||||||
|
|
@ -257,6 +310,11 @@ void DeckEditorDeckDockWidget::updateName(const QString &name)
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateComments()
|
void DeckEditorDeckDockWidget::updateComments()
|
||||||
{
|
{
|
||||||
|
historyManager->save(
|
||||||
|
deckLoader->getDeckList()->createMemento(QString(tr("Updated comments (was %1 chars, now %2 chars)"))
|
||||||
|
.arg(deckLoader->getDeckList()->getComments().size())
|
||||||
|
.arg(commentsEdit->toPlainText().size())));
|
||||||
|
|
||||||
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
|
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
|
||||||
deckEditor->setModified(commentsEdit->toPlainText().isEmpty());
|
deckEditor->setModified(commentsEdit->toPlainText().isEmpty());
|
||||||
emit commentsChanged();
|
emit commentsChanged();
|
||||||
|
|
@ -272,8 +330,8 @@ void DeckEditorDeckDockWidget::updateHash()
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
{
|
{
|
||||||
// Store the current text of the combo box
|
// Store current banner card identity
|
||||||
QString currentText = bannerCardComboBox->currentText();
|
CardRef wanted = deckModel->getDeckList()->getBannerCard();
|
||||||
|
|
||||||
// Block signals temporarily
|
// Block signals temporarily
|
||||||
bool wasBlocked = bannerCardComboBox->blockSignals(true);
|
bool wasBlocked = bannerCardComboBox->blockSignals(true);
|
||||||
|
|
@ -281,54 +339,51 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
// Clear the existing items in the combo box
|
// Clear the existing items in the combo box
|
||||||
bannerCardComboBox->clear();
|
bannerCardComboBox->clear();
|
||||||
|
|
||||||
// Prepare the new items with deduplication
|
// Collect unique (name, providerId) pairs
|
||||||
QSet<QPair<QString, QString>> bannerCardSet;
|
QSet<QPair<QString, QString>> bannerCardSet;
|
||||||
QList<DecklistCardNode *> cardsInDeck = deckModel->getDeckList()->getCardNodes();
|
QList<DecklistCardNode *> cardsInDeck = deckModel->getDeckList()->getCardNodes();
|
||||||
|
|
||||||
for (auto currentCard : cardsInDeck) {
|
for (auto currentCard : cardsInDeck) {
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
if (!CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
|
||||||
if (CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
|
continue;
|
||||||
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Insert one entry per distinct card, ignore copies
|
||||||
|
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to sorted list
|
||||||
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
QList<QPair<QString, QString>> pairList = bannerCardSet.values();
|
||||||
|
|
||||||
// Sort QList by the first() element of the QPair
|
// Sort QList by the first() element of the QPair
|
||||||
std::sort(pairList.begin(), pairList.end(), [](const QPair<QString, QString> &a, const QPair<QString, QString> &b) {
|
std::sort(pairList.begin(), pairList.end(),
|
||||||
return a.first.toLower() < b.first.toLower();
|
[](const auto &a, const auto &b) { return a.first.toLower() < b.first.toLower(); });
|
||||||
});
|
|
||||||
|
|
||||||
|
// Add to combo box
|
||||||
for (const auto &pair : pairList) {
|
for (const auto &pair : pairList) {
|
||||||
bannerCardComboBox->addItem(pair.first, QVariant::fromValue(pair));
|
bannerCardComboBox->addItem(pair.first, QVariant::fromValue(pair));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to restore the previous selection by finding the currentText
|
// Try to find an index with a matching card
|
||||||
int restoredIndex = bannerCardComboBox->findText(currentText);
|
int restoreIndex = findRestoreIndex(wanted, bannerCardComboBox);
|
||||||
if (restoredIndex != -1) {
|
|
||||||
bannerCardComboBox->setCurrentIndex(restoredIndex);
|
// Handle results
|
||||||
if (deckModel->getDeckList()->getBannerCard().providerId !=
|
if (restoreIndex != -1) {
|
||||||
bannerCardComboBox->currentData().value<QPair<QString, QString>>().second) {
|
bannerCardComboBox->setCurrentIndex(restoreIndex);
|
||||||
setBannerCard(restoredIndex);
|
setBannerCard(restoreIndex);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Add a placeholder "-" and set it as the current selection
|
// Add a placeholder "-" and set it as the current selection
|
||||||
int bannerIndex = bannerCardComboBox->findText(deckModel->getDeckList()->getBannerCard().name);
|
|
||||||
if (bannerIndex != -1) {
|
|
||||||
bannerCardComboBox->setCurrentIndex(bannerIndex);
|
|
||||||
} else {
|
|
||||||
bannerCardComboBox->insertItem(0, "-");
|
bannerCardComboBox->insertItem(0, "-");
|
||||||
bannerCardComboBox->setCurrentIndex(0);
|
bannerCardComboBox->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Restore the previous signal blocking state
|
// Restore signal state
|
||||||
bannerCardComboBox->blockSignals(wasBlocked);
|
bannerCardComboBox->blockSignals(wasBlocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
|
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
|
||||||
{
|
{
|
||||||
|
historyManager->save(deckLoader->getDeckList()->createMemento(tr("Banner card changed")));
|
||||||
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
||||||
deckModel->getDeckList()->setBannerCard({name, id});
|
deckModel->getDeckList()->setBannerCard({name, id});
|
||||||
deckEditor->setModified(true);
|
deckEditor->setModified(true);
|
||||||
|
|
@ -372,21 +427,40 @@ void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck)
|
||||||
connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree);
|
connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree);
|
||||||
connect(deckLoader->getDeckList(), &DeckList::deckHashChanged, deckModel, &DeckListModel::deckHashChanged);
|
connect(deckLoader->getDeckList(), &DeckList::deckHashChanged, deckModel, &DeckListModel::deckHashChanged);
|
||||||
|
|
||||||
nameEdit->setText(deckModel->getDeckList()->getName());
|
historyManager->clear();
|
||||||
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
historyManagerWidget->setDeckListModel(deckModel);
|
||||||
|
|
||||||
syncBannerCardComboBoxSelectionWithDeck();
|
syncDisplayWidgetsToModel();
|
||||||
updateBannerCardComboBox();
|
|
||||||
updateHash();
|
|
||||||
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
|
||||||
deckView->expandAll();
|
|
||||||
deckView->expandAll();
|
|
||||||
|
|
||||||
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
|
||||||
|
|
||||||
emit deckChanged();
|
emit deckChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
|
||||||
|
{
|
||||||
|
nameEdit->blockSignals(true);
|
||||||
|
nameEdit->setText(deckModel->getDeckList()->getName());
|
||||||
|
nameEdit->blockSignals(false);
|
||||||
|
|
||||||
|
commentsEdit->blockSignals(true);
|
||||||
|
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
||||||
|
commentsEdit->blockSignals(false);
|
||||||
|
|
||||||
|
bannerCardComboBox->blockSignals(true);
|
||||||
|
syncBannerCardComboBoxSelectionWithDeck();
|
||||||
|
updateBannerCardComboBox();
|
||||||
|
bannerCardComboBox->blockSignals(false);
|
||||||
|
updateHash();
|
||||||
|
sortDeckModelToDeckView();
|
||||||
|
expandAll();
|
||||||
|
|
||||||
|
deckTagsDisplayWidget->connectDeckList(deckModel->getDeckList());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::sortDeckModelToDeckView()
|
||||||
|
{
|
||||||
|
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
|
}
|
||||||
|
|
||||||
DeckLoader *DeckEditorDeckDockWidget::getDeckLoader()
|
DeckLoader *DeckEditorDeckDockWidget::getDeckLoader()
|
||||||
{
|
{
|
||||||
return deckLoader;
|
return deckLoader;
|
||||||
|
|
@ -422,6 +496,12 @@ void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)
|
||||||
deckView->expand(index);
|
deckView->expand(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::expandAll()
|
||||||
|
{
|
||||||
|
deckView->expandAll();
|
||||||
|
deckView->expandAll();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the index of all the currently selected card nodes in the decklist table.
|
* 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.
|
* The list is in reverse order of the visual selection, so that rows can be deleted while iterating over them.
|
||||||
|
|
@ -441,6 +521,14 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
|
||||||
return selectedRows;
|
return selectedRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::onCardAboutToBeAdded(const ExactCard &addedCard, const QString &zoneName)
|
||||||
|
{
|
||||||
|
historyManager->save(deckLoader->getDeckList()->createMemento(
|
||||||
|
QString(tr("Added (%1): %2 (%3) %4"))
|
||||||
|
.arg(zoneName, addedCard.getName(), addedCard.getPrinting().getSet()->getCorrectedShortName(),
|
||||||
|
addedCard.getPrinting().getProperty("num"))));
|
||||||
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::actIncrement()
|
void DeckEditorDeckDockWidget::actIncrement()
|
||||||
{
|
{
|
||||||
auto selectedRows = getSelectedCardNodes();
|
auto selectedRows = getSelectedCardNodes();
|
||||||
|
|
@ -559,6 +647,11 @@ void DeckEditorDeckDockWidget::actRemoveCard()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QModelIndex sourceIndex = proxy->mapToSource(index);
|
QModelIndex sourceIndex = proxy->mapToSource(index);
|
||||||
|
QString cardName = sourceIndex.sibling(sourceIndex.row(), 1).data().toString();
|
||||||
|
|
||||||
|
historyManager->save(
|
||||||
|
deckLoader->getDeckList()->createMemento(QString(tr("Removed \"%1\" (all copies)")).arg(cardName)));
|
||||||
|
|
||||||
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
||||||
isModified = true;
|
isModified = true;
|
||||||
}
|
}
|
||||||
|
|
@ -579,9 +672,21 @@ void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int of
|
||||||
QModelIndex sourceIndex = proxy->mapToSource(idx);
|
QModelIndex sourceIndex = proxy->mapToSource(idx);
|
||||||
|
|
||||||
const QModelIndex numberIndex = sourceIndex.sibling(sourceIndex.row(), 0);
|
const QModelIndex numberIndex = sourceIndex.sibling(sourceIndex.row(), 0);
|
||||||
|
const QModelIndex nameIndex = sourceIndex.sibling(sourceIndex.row(), 1);
|
||||||
|
|
||||||
|
const QString cardName = deckModel->data(nameIndex, Qt::EditRole).toString();
|
||||||
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;
|
||||||
|
|
||||||
|
const auto reason =
|
||||||
|
QString(tr("%1 %2 × \"%3\" (%4)"))
|
||||||
|
.arg(offset > 0 ? tr("Added") : tr("Removed"))
|
||||||
|
.arg(qAbs(offset))
|
||||||
|
.arg(cardName)
|
||||||
|
.arg(deckModel->data(sourceIndex.sibling(sourceIndex.row(), 4), Qt::DisplayRole).toString());
|
||||||
|
|
||||||
|
historyManager->save(deckLoader->getDeckList()->createMemento(reason));
|
||||||
|
|
||||||
if (new_count <= 0) {
|
if (new_count <= 0) {
|
||||||
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@
|
||||||
#include "../../key_signals.h"
|
#include "../../key_signals.h"
|
||||||
#include "../utility/custom_line_edit.h"
|
#include "../utility/custom_line_edit.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"
|
||||||
|
#include "deck_list_history_manager_widget.h"
|
||||||
#include "deck_list_style_proxy.h"
|
#include "deck_list_style_proxy.h"
|
||||||
|
#include "libcockatrice/deck_list/deck_list_history_manager.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
|
|
@ -53,6 +55,8 @@ public slots:
|
||||||
void cleanDeck();
|
void cleanDeck();
|
||||||
void updateBannerCardComboBox();
|
void updateBannerCardComboBox();
|
||||||
void setDeck(DeckLoader *_deck);
|
void setDeck(DeckLoader *_deck);
|
||||||
|
void syncDisplayWidgetsToModel();
|
||||||
|
void sortDeckModelToDeckView();
|
||||||
DeckLoader *getDeckLoader();
|
DeckLoader *getDeckLoader();
|
||||||
DeckList *getDeckList();
|
DeckList *getDeckList();
|
||||||
void actIncrement();
|
void actIncrement();
|
||||||
|
|
@ -61,6 +65,7 @@ public slots:
|
||||||
void actDecrementSelection();
|
void actDecrementSelection();
|
||||||
void actSwapCard();
|
void actSwapCard();
|
||||||
void actRemoveCard();
|
void actRemoveCard();
|
||||||
|
void onCardAboutToBeAdded(const ExactCard &card, const QString &zoneName);
|
||||||
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
@ -73,14 +78,18 @@ signals:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractTabDeckEditor *deckEditor;
|
AbstractTabDeckEditor *deckEditor;
|
||||||
|
DeckListHistoryManager *historyManager;
|
||||||
|
DeckListHistoryManagerWidget *historyManagerWidget;
|
||||||
KeySignals deckViewKeySignals;
|
KeySignals deckViewKeySignals;
|
||||||
QLabel *nameLabel;
|
QLabel *nameLabel;
|
||||||
LineEditUnfocusable *nameEdit;
|
LineEditUnfocusable *nameEdit;
|
||||||
|
QTimer *nameDebounceTimer;
|
||||||
SettingsButtonWidget *quickSettingsWidget;
|
SettingsButtonWidget *quickSettingsWidget;
|
||||||
QCheckBox *showBannerCardCheckBox;
|
QCheckBox *showBannerCardCheckBox;
|
||||||
QCheckBox *showTagsWidgetCheckBox;
|
QCheckBox *showTagsWidgetCheckBox;
|
||||||
QLabel *commentsLabel;
|
QLabel *commentsLabel;
|
||||||
QTextEdit *commentsEdit;
|
QTextEdit *commentsEdit;
|
||||||
|
QTimer *commentsDebounceTimer;
|
||||||
QLabel *bannerCardLabel;
|
QLabel *bannerCardLabel;
|
||||||
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
||||||
QLabel *hashLabel1;
|
QLabel *hashLabel1;
|
||||||
|
|
@ -104,6 +113,7 @@ private slots:
|
||||||
void updateShowBannerCardComboBox(bool visible);
|
void updateShowBannerCardComboBox(bool visible);
|
||||||
void updateShowTagsWidget(bool visible);
|
void updateShowTagsWidget(bool visible);
|
||||||
void syncBannerCardComboBoxSelectionWithDeck();
|
void syncBannerCardComboBoxSelectionWithDeck();
|
||||||
|
void expandAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECK_EDITOR_DECK_DOCK_WIDGET_H
|
#endif // DECK_EDITOR_DECK_DOCK_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
#include "deck_list_history_manager_widget.h"
|
||||||
|
|
||||||
|
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckListModel *_deckListModel,
|
||||||
|
DeckListStyleProxy *_styleProxy,
|
||||||
|
DeckListHistoryManager *manager,
|
||||||
|
QWidget *parent)
|
||||||
|
: QWidget(parent), deckListModel(_deckListModel), styleProxy(_styleProxy), historyManager(manager)
|
||||||
|
{
|
||||||
|
layout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
aUndo = new QAction(QString(), this);
|
||||||
|
aUndo->setIcon(QPixmap("theme:icons/arrow_undo"));
|
||||||
|
aUndo->setShortcut(QKeySequence::Undo);
|
||||||
|
aUndo->setShortcutContext(Qt::ApplicationShortcut);
|
||||||
|
connect(aUndo, &QAction::triggered, this, &DeckListHistoryManagerWidget::doUndo);
|
||||||
|
|
||||||
|
undoButton = new QToolButton(this);
|
||||||
|
undoButton->setDefaultAction(aUndo);
|
||||||
|
|
||||||
|
aRedo = new QAction(QString(), this);
|
||||||
|
aRedo->setIcon(QPixmap("theme:icons/arrow_redo"));
|
||||||
|
aRedo->setShortcut(QKeySequence::Redo);
|
||||||
|
aRedo->setShortcutContext(Qt::ApplicationShortcut);
|
||||||
|
connect(aRedo, &QAction::triggered, this, &DeckListHistoryManagerWidget::doRedo);
|
||||||
|
|
||||||
|
redoButton = new QToolButton(this);
|
||||||
|
redoButton->setDefaultAction(aRedo);
|
||||||
|
|
||||||
|
layout->addWidget(undoButton);
|
||||||
|
layout->addWidget(redoButton);
|
||||||
|
|
||||||
|
historyButton = new SettingsButtonWidget(this);
|
||||||
|
historyButton->setButtonIcon(QPixmap("theme:icons/arrow_history"));
|
||||||
|
|
||||||
|
historyLabel = new QLabel(this);
|
||||||
|
|
||||||
|
historyList = new QListWidget(this);
|
||||||
|
|
||||||
|
historyButton->addSettingsWidget(historyLabel);
|
||||||
|
historyButton->addSettingsWidget(historyList);
|
||||||
|
|
||||||
|
layout->addWidget(historyButton);
|
||||||
|
|
||||||
|
connect(historyList, &QListWidget::itemClicked, this, &DeckListHistoryManagerWidget::onListClicked);
|
||||||
|
|
||||||
|
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this,
|
||||||
|
&DeckListHistoryManagerWidget::refreshList);
|
||||||
|
|
||||||
|
refreshList();
|
||||||
|
retranslateUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
undoButton->setToolTip(tr("Undo"));
|
||||||
|
redoButton->setToolTip(tr("Redo"));
|
||||||
|
historyButton->setToolTip(tr("Undo/Redo history"));
|
||||||
|
historyLabel->setText(tr("Click on an entry to revert to that point in the history."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::setDeckListModel(DeckListModel *_deckListModel)
|
||||||
|
{
|
||||||
|
deckListModel = _deckListModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::refreshList()
|
||||||
|
{
|
||||||
|
historyList->clear();
|
||||||
|
|
||||||
|
// Fill redo section first (oldest redo at top, newest redo closest to divider)
|
||||||
|
const auto redoStack = historyManager->getRedoStack();
|
||||||
|
for (int i = 0; i < redoStack.size(); ++i) { // iterate forward
|
||||||
|
auto item = new QListWidgetItem(tr("[redo] ") + redoStack[i].getReason(), historyList);
|
||||||
|
item->setData(Qt::UserRole, QVariant("redo"));
|
||||||
|
item->setData(Qt::UserRole + 1, i); // index in redo stack
|
||||||
|
item->setForeground(Qt::gray);
|
||||||
|
historyList->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divider
|
||||||
|
if (!historyManager->getUndoStack().isEmpty() && !historyManager->getRedoStack().isEmpty()) {
|
||||||
|
auto divider = new QListWidgetItem("──────────", historyList);
|
||||||
|
divider->setFlags(Qt::NoItemFlags); // not selectable
|
||||||
|
historyList->addItem(divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill undo section
|
||||||
|
const auto undoStack = historyManager->getUndoStack();
|
||||||
|
for (int i = undoStack.size() - 1; i >= 0; --i) {
|
||||||
|
auto item = new QListWidgetItem(tr("[undo] ") + undoStack[i].getReason(), historyList);
|
||||||
|
item->setData(Qt::UserRole, QVariant("undo"));
|
||||||
|
item->setData(Qt::UserRole + 1, i); // index in undo stack
|
||||||
|
historyList->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button enabled states
|
||||||
|
undoButton->setEnabled(historyManager->canUndo());
|
||||||
|
redoButton->setEnabled(historyManager->canRedo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::doUndo()
|
||||||
|
{
|
||||||
|
if (!historyManager->canUndo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
historyManager->undo(deckListModel->getDeckList());
|
||||||
|
deckListModel->rebuildTree();
|
||||||
|
emit deckListModel->layoutChanged();
|
||||||
|
emit requestDisplayWidgetSync();
|
||||||
|
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::doRedo()
|
||||||
|
{
|
||||||
|
if (!historyManager->canRedo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
historyManager->redo(deckListModel->getDeckList());
|
||||||
|
deckListModel->rebuildTree();
|
||||||
|
|
||||||
|
emit deckListModel->layoutChanged();
|
||||||
|
emit requestDisplayWidgetSync();
|
||||||
|
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::onListClicked(QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
// Ignore non-selectable items (like divider)
|
||||||
|
if (!(item->flags() & Qt::ItemIsSelectable)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString mode = item->data(Qt::UserRole).toString();
|
||||||
|
int index = item->data(Qt::UserRole + 1).toInt();
|
||||||
|
|
||||||
|
if (mode == "redo") {
|
||||||
|
const auto redoStack = historyManager->getRedoStack();
|
||||||
|
int steps = redoStack.size() - index;
|
||||||
|
for (int i = 0; i < steps; ++i) {
|
||||||
|
historyManager->redo(deckListModel->getDeckList());
|
||||||
|
}
|
||||||
|
} else if (mode == "undo") {
|
||||||
|
const auto undoStack = historyManager->getUndoStack();
|
||||||
|
int steps = undoStack.size() - 1 - index;
|
||||||
|
for (int i = 0; i < steps + 1; ++i) {
|
||||||
|
historyManager->undo(deckListModel->getDeckList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deckListModel->rebuildTree();
|
||||||
|
|
||||||
|
emit deckListModel->layoutChanged();
|
||||||
|
emit requestDisplayWidgetSync();
|
||||||
|
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef COCKATRICE_DECK_EDITOR_DECK_LIST_HISTORY_MANAGER_WIDGET_H
|
||||||
|
#define COCKATRICE_DECK_EDITOR_DECK_LIST_HISTORY_MANAGER_WIDGET_H
|
||||||
|
|
||||||
|
#ifndef COCKATRICE_DECK_UNDO_WIDGET_H
|
||||||
|
#define COCKATRICE_DECK_UNDO_WIDGET_H
|
||||||
|
|
||||||
|
#include "../quick_settings/settings_button_widget.h"
|
||||||
|
#include "deck_list_style_proxy.h"
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QToolButton>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
||||||
|
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||||
|
|
||||||
|
class DeckListHistoryManagerWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestDisplayWidgetSync();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckListHistoryManagerWidget(DeckListModel *deckListModel,
|
||||||
|
DeckListStyleProxy *styleProxy,
|
||||||
|
DeckListHistoryManager *manager,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
void setDeckListModel(DeckListModel *_deckListModel);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void refreshList();
|
||||||
|
void onListClicked(QListWidgetItem *item);
|
||||||
|
void doUndo();
|
||||||
|
void doRedo();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DeckListModel *deckListModel;
|
||||||
|
DeckListStyleProxy *styleProxy;
|
||||||
|
DeckListHistoryManager *historyManager;
|
||||||
|
|
||||||
|
QHBoxLayout *layout;
|
||||||
|
QAction *aUndo;
|
||||||
|
QToolButton *undoButton;
|
||||||
|
QAction *aRedo;
|
||||||
|
QToolButton *redoButton;
|
||||||
|
SettingsButtonWidget *historyButton;
|
||||||
|
QLabel *historyLabel;
|
||||||
|
QListWidget *historyList;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_UNDO_WIDGET_H
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_EDITOR_DECK_LIST_HISTORY_MANAGER_WIDGET_H
|
||||||
|
|
@ -7,9 +7,13 @@
|
||||||
|
|
||||||
QVariant DeckListStyleProxy::data(const QModelIndex &index, int role) const
|
QVariant DeckListStyleProxy::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
|
QModelIndex src = mapToSource(index);
|
||||||
|
if (!src.isValid())
|
||||||
|
return {};
|
||||||
|
|
||||||
QVariant value = QIdentityProxyModel::data(index, role);
|
QVariant value = QIdentityProxyModel::data(index, role);
|
||||||
|
|
||||||
const bool isCard = QIdentityProxyModel::data(index, DeckRoles::IsCardRole).toBool();
|
bool isCard = src.data(DeckRoles::IsCardRole).toBool();
|
||||||
|
|
||||||
if (role == Qt::FontRole && !isCard) {
|
if (role == Qt::FontRole && !isCard) {
|
||||||
QFont f;
|
QFont f;
|
||||||
|
|
@ -24,7 +28,7 @@ QVariant DeckListStyleProxy::data(const QModelIndex &index, int role) const
|
||||||
int base = 255 - (index.row() % 2) * 30;
|
int base = 255 - (index.row() % 2) * 30;
|
||||||
return legal ? QBrush(QColor(base, base, base)) : QBrush(QColor(255, base / 3, base / 3));
|
return legal ? QBrush(QColor(base, base, base)) : QBrush(QColor(255, base / 3, base / 3));
|
||||||
} else {
|
} else {
|
||||||
int depth = QIdentityProxyModel::data(index, DeckRoles::DepthRole).toInt();
|
int depth = src.data(DeckRoles::DepthRole).toInt();
|
||||||
int color = 90 + 60 * depth;
|
int color = 90 + 60 * depth;
|
||||||
return QBrush(QColor(color, 255, color));
|
return QBrush(QColor(color, 255, color));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,16 +133,16 @@ void DlgLoadDeckFromClipboard::actOK()
|
||||||
/**
|
/**
|
||||||
* Creates the dialog window for the "Edit deck in clipboard" action
|
* Creates the dialog window for the "Edit deck in clipboard" action
|
||||||
*
|
*
|
||||||
* @param deckList The existing deck in the deck editor. Copies the instance
|
* @param _deckLoader The existing deck in the deck editor. Copies the instance
|
||||||
* @param _annotated Whether to add annotations to the text that is loaded from the deck
|
* @param _annotated Whether to add annotations to the text that is loaded from the deck
|
||||||
* @param parent The parent widget
|
* @param parent The parent widget
|
||||||
*/
|
*/
|
||||||
DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent)
|
DlgEditDeckInClipboard::DlgEditDeckInClipboard(DeckLoader *_deckLoader, bool _annotated, QWidget *parent)
|
||||||
: AbstractDlgDeckTextEdit(parent), annotated(_annotated)
|
: AbstractDlgDeckTextEdit(parent), annotated(_annotated)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Edit deck in clipboard"));
|
setWindowTitle(tr("Edit deck in clipboard"));
|
||||||
|
|
||||||
deckLoader = new DeckLoader(deckList);
|
deckLoader = new DeckLoader(this, _deckLoader->getDeckList());
|
||||||
deckLoader->setParent(this);
|
deckLoader->setParent(this);
|
||||||
|
|
||||||
DlgEditDeckInClipboard::actRefresh();
|
DlgEditDeckInClipboard::actRefresh();
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ private:
|
||||||
bool annotated;
|
bool annotated;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DlgEditDeckInClipboard(const DeckLoader &deckList, bool _annotated, QWidget *parent = nullptr);
|
explicit DlgEditDeckInClipboard(DeckLoader *_deckLoader, bool _annotated, QWidget *parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] DeckLoader *getDeckList() const override
|
[[nodiscard]] DeckLoader *getDeckList() const override
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,8 @@ void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, QString zoneNam
|
||||||
if (card.getInfo().getIsToken())
|
if (card.getInfo().getIsToken())
|
||||||
zoneName = DECK_ZONE_TOKENS;
|
zoneName = DECK_ZONE_TOKENS;
|
||||||
|
|
||||||
|
emit cardAboutToBeAdded(card, zoneName);
|
||||||
|
|
||||||
QModelIndex newCardIndex = deckDockWidget->deckModel->addCard(card, zoneName);
|
QModelIndex newCardIndex = deckDockWidget->deckModel->addCard(card, zoneName);
|
||||||
deckDockWidget->deckView->clearSelection();
|
deckDockWidget->deckView->clearSelection();
|
||||||
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
|
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
|
||||||
|
|
@ -486,7 +488,7 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard()
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
|
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
|
||||||
{
|
{
|
||||||
DlgEditDeckInClipboard dlg(*getDeckLoader(), annotated, this);
|
DlgEditDeckInClipboard dlg(getDeckLoader(), annotated, this);
|
||||||
if (!dlg.exec())
|
if (!dlg.exec())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,7 @@ public slots:
|
||||||
virtual void dockTopLevelChanged(bool topLevel) = 0;
|
virtual void dockTopLevelChanged(bool topLevel) = 0;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void cardAboutToBeAdded(const ExactCard &addedCard, const QString &zoneName);
|
||||||
/** @brief Emitted when a deck should be opened in a new editor tab. */
|
/** @brief Emitted when a deck should be opened in a new editor tab. */
|
||||||
void openDeckEditor(DeckLoader *deckLoader);
|
void openDeckEditor(DeckLoader *deckLoader);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -242,11 +242,11 @@ void TabDeckStorage::actOpenLocalDeck()
|
||||||
continue;
|
continue;
|
||||||
QString filePath = localDirModel->filePath(curLeft);
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
DeckLoader deckLoader(this);
|
auto deckLoader = new DeckLoader(this);
|
||||||
if (!deckLoader.loadFromFile(filePath, DeckLoader::CockatriceFormat, true))
|
if (!deckLoader->loadFromFile(filePath, DeckLoader::CockatriceFormat, true))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
emit openDeckEditor(&deckLoader);
|
emit openDeckEditor(deckLoader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -869,7 +869,7 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(DeckLoader *deckToOpen)
|
||||||
{
|
{
|
||||||
auto *tab = new TabDeckEditor(this);
|
auto *tab = new TabDeckEditor(this);
|
||||||
if (deckToOpen)
|
if (deckToOpen)
|
||||||
tab->openDeck(new DeckLoader(this, deckToOpen->getDeckList()));
|
tab->openDeck(deckToOpen);
|
||||||
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
||||||
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
|
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
|
||||||
myAddTab(tab);
|
myAddTab(tab);
|
||||||
|
|
@ -882,7 +882,7 @@ TabDeckEditorVisual *TabSupervisor::addVisualDeckEditorTab(DeckLoader *deckToOpe
|
||||||
{
|
{
|
||||||
auto *tab = new TabDeckEditorVisual(this);
|
auto *tab = new TabDeckEditorVisual(this);
|
||||||
if (deckToOpen)
|
if (deckToOpen)
|
||||||
tab->openDeck(new DeckLoader(this, deckToOpen->getDeckList()));
|
tab->openDeck(deckToOpen);
|
||||||
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
||||||
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addVisualDeckEditorTab);
|
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addVisualDeckEditorTab);
|
||||||
myAddTab(tab);
|
myAddTab(tab);
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@ TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
|
||||||
|
|
||||||
void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath)
|
void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath)
|
||||||
{
|
{
|
||||||
DeckLoader deckLoader(this);
|
auto deckLoader = new DeckLoader(this);
|
||||||
if (!deckLoader.loadFromFile(filePath, DeckLoader::getFormatFromName(filePath), true)) {
|
if (!deckLoader->loadFromFile(filePath, DeckLoader::getFormatFromName(filePath), true)) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(filePath));
|
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(filePath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit openDeckEditor(&deckLoader);
|
emit openDeckEditor(deckLoader);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
<xs:attribute type="xs:string" name="rarity" use="optional" />
|
<xs:attribute type="xs:string" name="rarity" use="optional" />
|
||||||
<xs:attribute type="xs:boolean" name="isOnlineOnly" use="optional" />
|
<xs:attribute type="xs:boolean" name="isOnlineOnly" use="optional" />
|
||||||
<xs:attribute type="xs:boolean" name="isRebalanced" use="optional" />
|
<xs:attribute type="xs:boolean" name="isRebalanced" use="optional" />
|
||||||
|
<xs:attribute type="xs:string" name="flavorName" use="optional"/>
|
||||||
</xs:extension>
|
</xs:extension>
|
||||||
</xs:simpleContent>
|
</xs:simpleContent>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ CardInfo::CardInfo(const QString &_name,
|
||||||
{
|
{
|
||||||
simpleName = CardInfo::simplifyName(name);
|
simpleName = CardInfo::simplifyName(name);
|
||||||
|
|
||||||
refreshCachedSetNames();
|
refreshCachedSets();
|
||||||
}
|
}
|
||||||
|
|
||||||
CardInfoPtr CardInfo::newInstance(const QString &_name)
|
CardInfoPtr CardInfo::newInstance(const QString &_name)
|
||||||
|
|
@ -84,7 +84,7 @@ void CardInfo::addToSet(const CardSetPtr &_set, const PrintingInfo _info)
|
||||||
setsToPrintings[_set->getShortName()].append(_info);
|
setsToPrintings[_set->getShortName()].append(_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshCachedSetNames();
|
refreshCachedSets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardInfo::combineLegalities(const QVariantHash &props)
|
void CardInfo::combineLegalities(const QVariantHash &props)
|
||||||
|
|
@ -98,6 +98,12 @@ void CardInfo::combineLegalities(const QVariantHash &props)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardInfo::refreshCachedSets()
|
||||||
|
{
|
||||||
|
refreshCachedSetNames();
|
||||||
|
refreshCachedAltNames();
|
||||||
|
}
|
||||||
|
|
||||||
void CardInfo::refreshCachedSetNames()
|
void CardInfo::refreshCachedSetNames()
|
||||||
{
|
{
|
||||||
QStringList setList;
|
QStringList setList;
|
||||||
|
|
@ -113,6 +119,21 @@ void CardInfo::refreshCachedSetNames()
|
||||||
setsNames = setList.join(", ");
|
setsNames = setList.join(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardInfo::refreshCachedAltNames()
|
||||||
|
{
|
||||||
|
altNames.clear();
|
||||||
|
|
||||||
|
// update the altNames with the flavorNames
|
||||||
|
for (const auto &printings : setsToPrintings) {
|
||||||
|
for (const auto &printing : printings) {
|
||||||
|
QString flavorName = printing.getFlavorName();
|
||||||
|
if (!flavorName.isEmpty()) {
|
||||||
|
altNames.insert(flavorName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString CardInfo::simplifyName(const QString &name)
|
QString CardInfo::simplifyName(const QString &name)
|
||||||
{
|
{
|
||||||
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
|
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,9 @@ private:
|
||||||
QList<CardRelation *> reverseRelatedCards; ///< Cards that refer back to this card.
|
QList<CardRelation *> reverseRelatedCards; ///< Cards that refer back to this card.
|
||||||
QList<CardRelation *> reverseRelatedCardsToMe; ///< Cards that consider this card as related.
|
QList<CardRelation *> reverseRelatedCardsToMe; ///< Cards that consider this card as related.
|
||||||
SetToPrintingsMap setsToPrintings; ///< Mapping from set names to printing variations.
|
SetToPrintingsMap setsToPrintings; ///< Mapping from set names to printing variations.
|
||||||
QString setsNames; ///< Cached, human-readable list of set names.
|
|
||||||
UiAttributes uiAttributes; ///< Attributes that affect display and game logic
|
UiAttributes uiAttributes; ///< Attributes that affect display and game logic
|
||||||
|
QString setsNames; ///< Cached, human-readable list of set names.
|
||||||
|
QSet<QString> altNames; ///< Cached set of alternate names, used when searching
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -114,7 +115,8 @@ public:
|
||||||
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), text(other.text),
|
: QObject(other.parent()), name(other.name), simpleName(other.simpleName), text(other.text),
|
||||||
isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
|
isToken(other.isToken), properties(other.properties), relatedCards(other.relatedCards),
|
||||||
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
|
reverseRelatedCards(other.reverseRelatedCards), reverseRelatedCardsToMe(other.reverseRelatedCardsToMe),
|
||||||
setsToPrintings(other.setsToPrintings), setsNames(other.setsNames), uiAttributes(other.uiAttributes)
|
setsToPrintings(other.setsToPrintings), uiAttributes(other.uiAttributes), setsNames(other.setsNames),
|
||||||
|
altNames(other.altNames)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,6 +187,10 @@ public:
|
||||||
{
|
{
|
||||||
return simpleName;
|
return simpleName;
|
||||||
}
|
}
|
||||||
|
const QSet<QString> &getAltNames()
|
||||||
|
{
|
||||||
|
return altNames;
|
||||||
|
};
|
||||||
const QString &getText() const
|
const QString &getText() const
|
||||||
{
|
{
|
||||||
return text;
|
return text;
|
||||||
|
|
@ -303,11 +309,11 @@ public:
|
||||||
void combineLegalities(const QVariantHash &props);
|
void combineLegalities(const QVariantHash &props);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Refreshes the cached, human-readable list of set names.
|
* @brief Refreshes all cached fields that are calculated from the contained sets and printings.
|
||||||
*
|
*
|
||||||
* Typically called after adding or modifying set memberships.
|
* Typically called after adding or modifying set memberships or printings.
|
||||||
*/
|
*/
|
||||||
void refreshCachedSetNames();
|
void refreshCachedSets();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Simplifies a name for fuzzy matching.
|
* @brief Simplifies a name for fuzzy matching.
|
||||||
|
|
@ -319,6 +325,21 @@ public:
|
||||||
*/
|
*/
|
||||||
static QString simplifyName(const QString &name);
|
static QString simplifyName(const QString &name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Refreshes the cached, human-readable list of set names.
|
||||||
|
*
|
||||||
|
* Typically called after adding or modifying set memberships.
|
||||||
|
*/
|
||||||
|
void refreshCachedSetNames();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Refreshes the cached list of alt names for the card.
|
||||||
|
*
|
||||||
|
* Typically called after adding or modifying the contained printings.
|
||||||
|
*/
|
||||||
|
void refreshCachedAltNames();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/**
|
/**
|
||||||
* @brief Emitted when a pixmap for this card has been updated or finished loading.
|
* @brief Emitted when a pixmap for this card has been updated or finished loading.
|
||||||
|
|
|
||||||
|
|
@ -194,8 +194,9 @@ void CardDatabase::markAllSetsAsKnown()
|
||||||
void CardDatabase::notifyEnabledSetsChanged()
|
void CardDatabase::notifyEnabledSetsChanged()
|
||||||
{
|
{
|
||||||
// refresh the list of cached set names
|
// refresh the list of cached set names
|
||||||
for (const CardInfoPtr &card : cards)
|
for (const CardInfoPtr &card : cards) {
|
||||||
card->refreshCachedSetNames();
|
card->refreshCachedSets();
|
||||||
|
}
|
||||||
|
|
||||||
// inform the carddatabasemodels that they need to re-check their list of cards
|
// inform the carddatabasemodels that they need to re-check their list of cards
|
||||||
emit cardDatabaseEnabledSetsChanged();
|
emit cardDatabaseEnabledSetsChanged();
|
||||||
|
|
|
||||||
|
|
@ -13,3 +13,8 @@ QString PrintingInfo::getUuid() const
|
||||||
{
|
{
|
||||||
return properties.value("uuid").toString();
|
return properties.value("uuid").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString PrintingInfo::getFlavorName() const
|
||||||
|
{
|
||||||
|
return properties.value("flavorName").toString();
|
||||||
|
}
|
||||||
|
|
@ -110,6 +110,13 @@ public:
|
||||||
* @return A string representing the providerID.
|
* @return A string representing the providerID.
|
||||||
*/
|
*/
|
||||||
QString getUuid() const;
|
QString getUuid() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the flavorName for this printing.
|
||||||
|
*
|
||||||
|
* @return The flavorName, or empty if it isn't present.
|
||||||
|
*/
|
||||||
|
QString getFlavorName() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_PRINTING_INFO_H
|
#endif // COCKATRICE_PRINTING_INFO_H
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@ set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
libcockatrice/deck_list/abstract_deck_list_card_node.h libcockatrice/deck_list/abstract_deck_list_node.h
|
libcockatrice/deck_list/abstract_deck_list_card_node.h
|
||||||
libcockatrice/deck_list/deck_list.h libcockatrice/deck_list/deck_list_card_node.h
|
libcockatrice/deck_list/abstract_deck_list_node.h
|
||||||
|
libcockatrice/deck_list/deck_list.h
|
||||||
|
libcockatrice/deck_list/deck_list_card_node.h
|
||||||
|
libcockatrice/deck_list/deck_list_history_manager.h
|
||||||
|
libcockatrice/deck_list/deck_list_memento.h
|
||||||
libcockatrice/deck_list/inner_deck_list_node.h
|
libcockatrice/deck_list/inner_deck_list_node.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -16,9 +20,13 @@ endif()
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
libcockatrice_deck_list STATIC
|
libcockatrice_deck_list STATIC
|
||||||
${MOC_SOURCES} libcockatrice/deck_list/abstract_deck_list_card_node.cpp
|
${MOC_SOURCES}
|
||||||
libcockatrice/deck_list/abstract_deck_list_node.cpp libcockatrice/deck_list/deck_list.cpp
|
libcockatrice/deck_list/abstract_deck_list_card_node.cpp
|
||||||
libcockatrice/deck_list/deck_list_card_node.cpp libcockatrice/deck_list/inner_deck_list_node.cpp
|
libcockatrice/deck_list/abstract_deck_list_node.cpp
|
||||||
|
libcockatrice/deck_list/deck_list.cpp
|
||||||
|
libcockatrice/deck_list/deck_list_card_node.cpp
|
||||||
|
libcockatrice/deck_list/deck_list_history_manager.cpp
|
||||||
|
libcockatrice/deck_list/inner_deck_list_node.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(libcockatrice_deck_list libcockatrice_protocol)
|
add_dependencies(libcockatrice_deck_list libcockatrice_protocol)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "abstract_deck_list_node.h"
|
#include "abstract_deck_list_node.h"
|
||||||
#include "deck_list_card_node.h"
|
#include "deck_list_card_node.h"
|
||||||
|
#include "deck_list_memento.h"
|
||||||
#include "inner_deck_list_node.h"
|
#include "inner_deck_list_node.h"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
|
@ -80,20 +81,6 @@ DeckList::DeckList()
|
||||||
root = new InnerDecklistNode;
|
root = new InnerDecklistNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: https://qt-project.org/doc/qt-4.8/qobject.html#no-copy-constructor-or-assignment-operator
|
|
||||||
DeckList::DeckList(const DeckList &other)
|
|
||||||
: QObject(), name(other.name), comments(other.comments), bannerCard(other.bannerCard),
|
|
||||||
lastLoadedTimestamp(other.lastLoadedTimestamp), tags(other.tags), cachedDeckHash(other.cachedDeckHash)
|
|
||||||
{
|
|
||||||
root = new InnerDecklistNode(other.getRoot());
|
|
||||||
|
|
||||||
QMapIterator<QString, SideboardPlan *> spIterator(other.getSideboardPlans());
|
|
||||||
while (spIterator.hasNext()) {
|
|
||||||
spIterator.next();
|
|
||||||
sideboardPlans.insert(spIterator.key(), new SideboardPlan(spIterator.key(), spIterator.value()->getMoveList()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckList::DeckList(const QString &nativeString)
|
DeckList::DeckList(const QString &nativeString)
|
||||||
{
|
{
|
||||||
root = new InnerDecklistNode;
|
root = new InnerDecklistNode;
|
||||||
|
|
@ -734,3 +721,14 @@ void DeckList::forEachCard(const std::function<void(InnerDecklistNode *, Decklis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeckListMemento DeckList::createMemento(const QString &reason) const
|
||||||
|
{
|
||||||
|
return DeckListMemento(writeToString_Native(), reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckList::restoreMemento(const DeckListMemento &m)
|
||||||
|
{
|
||||||
|
cleanList();
|
||||||
|
loadFromString_Native(m.getMemento());
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef DECKLIST_H
|
#ifndef DECKLIST_H
|
||||||
#define DECKLIST_H
|
#define DECKLIST_H
|
||||||
|
|
||||||
|
#include "deck_list_memento.h"
|
||||||
#include "inner_deck_list_node.h"
|
#include "inner_deck_list_node.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
@ -215,8 +216,9 @@ public slots:
|
||||||
public:
|
public:
|
||||||
/// @brief Construct an empty deck.
|
/// @brief Construct an empty deck.
|
||||||
explicit DeckList();
|
explicit DeckList();
|
||||||
/// @brief Deep-copy constructor.
|
/// @brief Delete copy constructor.
|
||||||
DeckList(const DeckList &other);
|
DeckList(const DeckList &) = delete;
|
||||||
|
DeckList &operator=(const DeckList &) = delete;
|
||||||
/// @brief Construct from a serialized native-format string.
|
/// @brief Construct from a serialized native-format string.
|
||||||
explicit DeckList(const QString &nativeString);
|
explicit DeckList(const QString &nativeString);
|
||||||
~DeckList() override;
|
~DeckList() override;
|
||||||
|
|
@ -316,6 +318,8 @@ public:
|
||||||
* @param func Function taking (zone node, card node).
|
* @param func Function taking (zone node, card node).
|
||||||
*/
|
*/
|
||||||
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func) const;
|
void forEachCard(const std::function<void(InnerDecklistNode *, DecklistCardNode *)> &func) const;
|
||||||
|
DeckListMemento createMemento(const QString &reason) const;
|
||||||
|
void restoreMemento(const DeckListMemento &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include "deck_list_history_manager.h"
|
||||||
|
|
||||||
|
void DeckListHistoryManager::save(const DeckListMemento &memento)
|
||||||
|
{
|
||||||
|
undoStack.push(memento);
|
||||||
|
redoStack.clear();
|
||||||
|
emit undoRedoStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManager::clear()
|
||||||
|
{
|
||||||
|
undoStack.clear();
|
||||||
|
redoStack.clear();
|
||||||
|
emit undoRedoStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManager::undo(DeckList *deck)
|
||||||
|
{
|
||||||
|
if (undoStack.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Peek at the memento we are going to restore
|
||||||
|
const DeckListMemento &mementoToRestore = undoStack.top();
|
||||||
|
|
||||||
|
// Save current state for redo
|
||||||
|
DeckListMemento currentState = deck->createMemento(mementoToRestore.getReason());
|
||||||
|
redoStack.push(currentState);
|
||||||
|
|
||||||
|
// Pop the last state from undo stack and restore it
|
||||||
|
DeckListMemento memento = undoStack.pop();
|
||||||
|
deck->restoreMemento(memento);
|
||||||
|
|
||||||
|
emit undoRedoStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManager::redo(DeckList *deck)
|
||||||
|
{
|
||||||
|
if (redoStack.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Peek at the memento we are going to restore
|
||||||
|
const DeckListMemento &mementoToRestore = redoStack.top();
|
||||||
|
|
||||||
|
// Save current state for undo
|
||||||
|
DeckListMemento currentState = deck->createMemento(mementoToRestore.getReason());
|
||||||
|
undoStack.push(currentState);
|
||||||
|
|
||||||
|
// Pop the next state from redo stack and restore it
|
||||||
|
DeckListMemento memento = redoStack.pop();
|
||||||
|
deck->restoreMemento(memento);
|
||||||
|
|
||||||
|
emit undoRedoStateChanged();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef COCKATRICE_DECK_LIST_HISTORY_MANAGER_H
|
||||||
|
#define COCKATRICE_DECK_LIST_HISTORY_MANAGER_H
|
||||||
|
|
||||||
|
#include "deck_list.h"
|
||||||
|
#include "deck_list_memento.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QStack>
|
||||||
|
|
||||||
|
class DeckListHistoryManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void undoRedoStateChanged();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckListHistoryManager(QObject *parent = nullptr) : QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void save(const DeckListMemento &memento);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
bool canUndo() const
|
||||||
|
{
|
||||||
|
return !undoStack.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canRedo() const
|
||||||
|
{
|
||||||
|
return !redoStack.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void undo(DeckList *deck);
|
||||||
|
|
||||||
|
void redo(DeckList *deck);
|
||||||
|
|
||||||
|
QStack<DeckListMemento> getRedoStack() const
|
||||||
|
{
|
||||||
|
return redoStack;
|
||||||
|
}
|
||||||
|
QStack<DeckListMemento> getUndoStack() const
|
||||||
|
{
|
||||||
|
return undoStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QStack<DeckListMemento> undoStack;
|
||||||
|
QStack<DeckListMemento> redoStack;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_LIST_HISTORY_MANAGER_H
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef COCKATRICE_DECK_LIST_MEMENTO_H
|
||||||
|
#define COCKATRICE_DECK_LIST_MEMENTO_H
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class DeckListMemento
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeckListMemento() = default;
|
||||||
|
explicit DeckListMemento(const QString &memento, const QString &reason = QString())
|
||||||
|
: memento(memento), reason(reason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getMemento() const
|
||||||
|
{
|
||||||
|
return memento;
|
||||||
|
}
|
||||||
|
QString getReason() const
|
||||||
|
{
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString memento;
|
||||||
|
QString reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_LIST_MEMENTO_H
|
||||||
|
|
@ -533,14 +533,14 @@ void DeckListModel::cleanList()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param _deck The deck. Takes ownership of the object
|
* @param _deck The deck.
|
||||||
*/
|
*/
|
||||||
void DeckListModel::setDeckList(DeckList *_deck)
|
void DeckListModel::setDeckList(DeckList *_deck)
|
||||||
{
|
{
|
||||||
deckList->deleteLater();
|
if (deckList != _deck) {
|
||||||
deckList = _deck;
|
deckList = _deck;
|
||||||
deckList->setParent(this);
|
|
||||||
rebuildTree();
|
rebuildTree();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ExactCard> DeckListModel::getCards() const
|
QList<ExactCard> DeckListModel::getCards() const
|
||||||
|
|
|
||||||
|
|
@ -293,6 +293,13 @@ int OracleImporter::importCardsFromSet(const CardSetPtr ¤tSet, const QList
|
||||||
printingInfo.setProperty(xmlPropertyName, propertyValue);
|
printingInfo.setProperty(xmlPropertyName, propertyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle flavorNames specially due to double-faced cards
|
||||||
|
QString faceFlavorName = getStringPropertyFromMap(card, "faceFlavorName");
|
||||||
|
QString flavorName = !faceFlavorName.isEmpty() ? faceFlavorName : getStringPropertyFromMap(card, "flavorName");
|
||||||
|
if (!flavorName.isEmpty()) {
|
||||||
|
printingInfo.setProperty("flavorName", flavorName);
|
||||||
|
}
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
for (auto i = identifierProperties.cbegin(), end = identifierProperties.cend(); i != end; ++i) {
|
for (auto i = identifierProperties.cbegin(), end = identifierProperties.cend(); i != end; ++i) {
|
||||||
QString mtgjsonProperty = i.key();
|
QString mtgjsonProperty = i.key();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue