mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-01 02:53:56 -07:00
Abstract deck editor (#5646)
* Generify TabDeckEditor. * Connect dockTopLevelChanged signals. * Connect eventFilters. * Remove comments. * Fix ze build (accidentally deleted a line) * Fix some pointer chaining. * Be a lot saner about some signals/slots, as in, individual Deck Editor widgets now internally determine their CardInfo and then simply communicate this to the DeckEditor * Lint. * DeckDock can handle its own menu. * DeckDock can handle its own decrement. * DeckDock now notifies the deck editor on deck change, instead of individually modifying menu items and modification status. * Rename. * Include pixelmap generator for icon. * Directly use an AbstractTabDeckEditor as parent. * Move clearing database filter into signal/slot relation. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
6df97a156f
commit
93d28717e0
34 changed files with 2370 additions and 1810 deletions
534
cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
Normal file
534
cockatrice/src/client/tabs/abstract_tab_deck_editor.cpp
Normal file
|
|
@ -0,0 +1,534 @@
|
|||
#include "abstract_tab_deck_editor.h"
|
||||
|
||||
#include "../../client/game_logic/abstract_client.h"
|
||||
#include "../../client/tapped_out_interface.h"
|
||||
#include "../../client/ui/widgets/cards/card_info_frame_widget.h"
|
||||
#include "../../deck/deck_stats_interface.h"
|
||||
#include "../../dialogs/dlg_load_deck.h"
|
||||
#include "../../dialogs/dlg_load_deck_from_clipboard.h"
|
||||
#include "../../game/cards/card_database_manager.h"
|
||||
#include "../../game/cards/card_database_model.h"
|
||||
#include "../../server/pending_command.h"
|
||||
#include "../../settings/cache_settings.h"
|
||||
#include "../ui/picture_loader/picture_loader.h"
|
||||
#include "../ui/pixel_map_generator.h"
|
||||
#include "pb/command_deck_upload.pb.h"
|
||||
#include "pb/response.pb.h"
|
||||
#include "tab_supervisor.h"
|
||||
#include "trice_limits.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
#include <QDesktopServices>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QHeaderView>
|
||||
#include <QLineEdit>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QPrintPreviewDialog>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QSplitter>
|
||||
#include <QTextStream>
|
||||
#include <QTreeView>
|
||||
#include <QUrl>
|
||||
|
||||
AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
||||
{
|
||||
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
|
||||
|
||||
databaseDisplayDockWidget = new DeckEditorDatabaseDisplayWidget(this);
|
||||
deckDockWidget = new DeckEditorDeckDockWidget(this);
|
||||
cardInfoDockWidget = new DeckEditorCardInfoDockWidget(this);
|
||||
filterDockWidget = new DeckEditorFilterDockWidget(this);
|
||||
printingSelectorDockWidget = new DeckEditorPrintingSelectorDockWidget(this);
|
||||
|
||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
|
||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
|
||||
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
|
||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
|
||||
&AbstractTabDeckEditor::updateCard);
|
||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::addCardToMainDeck, this,
|
||||
&AbstractTabDeckEditor::actAddCard);
|
||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::addCardToSideboard, this,
|
||||
&AbstractTabDeckEditor::actAddCardToSideboard);
|
||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromMainDeck, this,
|
||||
&AbstractTabDeckEditor::actDecrementCard);
|
||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::decrementCardFromSideboard, this,
|
||||
&AbstractTabDeckEditor::actDecrementCardFromSideboard);
|
||||
|
||||
connect(filterDockWidget, &DeckEditorFilterDockWidget::clearAllDatabaseFilters, databaseDisplayDockWidget,
|
||||
&DeckEditorDatabaseDisplayWidget::clearAllDatabaseFilters);
|
||||
|
||||
connect(&SettingsCache::instance().shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::updateCard(CardInfoPtr _card)
|
||||
{
|
||||
cardInfoDockWidget->updateCard(_card);
|
||||
printingSelectorDockWidget->printingSelector->setCard(_card, DECK_ZONE_MAIN);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::onDeckChanged()
|
||||
{
|
||||
setModified(true);
|
||||
deckMenu->setSaveStatus(!getDeckList()->isEmpty());
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::addCardHelper(const CardInfoPtr info, QString zoneName)
|
||||
{
|
||||
if (!info)
|
||||
return;
|
||||
if (info->getIsToken())
|
||||
zoneName = DECK_ZONE_TOKENS;
|
||||
|
||||
QModelIndex newCardIndex = deckDockWidget->deckModel->addPreferredPrintingCard(info->getName(), zoneName, false);
|
||||
// recursiveExpand(newCardIndex);
|
||||
deckDockWidget->deckView->clearSelection();
|
||||
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
|
||||
setModified(true);
|
||||
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actAddCard(CardInfoPtr info)
|
||||
{
|
||||
if (QApplication::keyboardModifiers() & Qt::ControlModifier)
|
||||
actAddCardToSideboard(info);
|
||||
else
|
||||
addCardHelper(info, DECK_ZONE_MAIN);
|
||||
deckMenu->setSaveStatus(true);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actAddCardToSideboard(CardInfoPtr info)
|
||||
{
|
||||
addCardHelper(info, DECK_ZONE_SIDE);
|
||||
deckMenu->setSaveStatus(true);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actDecrementCard(CardInfoPtr info)
|
||||
{
|
||||
emit decrementCard(info, DECK_ZONE_MAIN);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actDecrementCardFromSideboard(CardInfoPtr info)
|
||||
{
|
||||
emit decrementCard(info, DECK_ZONE_SIDE);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actSwapCard(CardInfoPtr info, QString zoneName)
|
||||
{
|
||||
QString providerId = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("uuid");
|
||||
QString collectorNumber = CardDatabaseManager::getInstance()->getSetInfoForCard(info).getProperty("num");
|
||||
deckDockWidget->swapCard(
|
||||
deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber));
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::setDeck(DeckLoader *_deck)
|
||||
{
|
||||
deckDockWidget->setDeck(_deck);
|
||||
PictureLoader::cacheCardPixmaps(CardDatabaseManager::getInstance()->getCards(getDeckList()->getCardList()));
|
||||
setModified(false);
|
||||
|
||||
// If they load a deck, make the deck list appear
|
||||
aDeckDockVisible->setChecked(true);
|
||||
deckDockWidget->setVisible(aDeckDockVisible->isChecked());
|
||||
}
|
||||
|
||||
DeckLoader *AbstractTabDeckEditor::getDeckList() const
|
||||
{
|
||||
return deckDockWidget->getDeckList();
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::setModified(bool _modified)
|
||||
{
|
||||
modified = _modified;
|
||||
emit tabTextChanged(this, getTabText());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if this tab is a blank newly opened tab, as if it was just created with the `New Deck` action.
|
||||
*/
|
||||
bool AbstractTabDeckEditor::isBlankNewDeck() const
|
||||
{
|
||||
DeckLoader *deck = getDeckList();
|
||||
return !modified && deck->hasNotBeenLoaded();
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actNewDeck()
|
||||
{
|
||||
auto deckOpenLocation = confirmOpen(false);
|
||||
|
||||
if (deckOpenLocation == CANCELLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (deckOpenLocation == NEW_TAB) {
|
||||
emit openDeckEditor(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanDeckAndResetModified();
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::cleanDeckAndResetModified()
|
||||
{
|
||||
deckMenu->setSaveStatus(false);
|
||||
deckDockWidget->cleanDeck();
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Displays the save confirmation dialogue that is shown before loading a deck, if required. Takes into
|
||||
* account the `openDeckInNewTab` settting.
|
||||
*
|
||||
* @param openInSameTabIfBlank Open the deck in the same tab instead of a new tab if the current tab is completely
|
||||
* blank. Only relevant when the `openDeckInNewTab` setting is enabled.
|
||||
*
|
||||
* @returns An enum that indicates if and where to load the deck
|
||||
*/
|
||||
AbstractTabDeckEditor::DeckOpenLocation AbstractTabDeckEditor::confirmOpen(const bool openInSameTabIfBlank)
|
||||
{
|
||||
// handle `openDeckInNewTab` setting
|
||||
if (SettingsCache::instance().getOpenDeckInNewTab()) {
|
||||
if (openInSameTabIfBlank && isBlankNewDeck()) {
|
||||
return SAME_TAB;
|
||||
} else {
|
||||
return NEW_TAB;
|
||||
}
|
||||
}
|
||||
|
||||
// early return if deck is unmodified
|
||||
if (!modified) {
|
||||
return SAME_TAB;
|
||||
}
|
||||
|
||||
// do the save confirmation dialogue
|
||||
tabSupervisor->setCurrentWidget(this);
|
||||
|
||||
QMessageBox *msgBox = createSaveConfirmationWindow();
|
||||
QPushButton *newTabButton = msgBox->addButton(tr("Open in new tab"), QMessageBox::ApplyRole);
|
||||
|
||||
int ret = msgBox->exec();
|
||||
|
||||
// `exec()` returns an opaque value if a non-standard button was clicked.
|
||||
// Directly check if newTabButton was clicked before switching over the standard buttons.
|
||||
if (msgBox->clickedButton() == newTabButton) {
|
||||
return NEW_TAB;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case QMessageBox::Save:
|
||||
return actSaveDeck() ? SAME_TAB : CANCELLED;
|
||||
case QMessageBox::Discard:
|
||||
return SAME_TAB;
|
||||
default:
|
||||
return CANCELLED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates the base save confirmation dialogue box.
|
||||
*
|
||||
* @returns A QMessageBox that can be further modified
|
||||
*/
|
||||
QMessageBox *AbstractTabDeckEditor::createSaveConfirmationWindow()
|
||||
{
|
||||
QMessageBox *msgBox = new QMessageBox(this);
|
||||
msgBox->setIcon(QMessageBox::Warning);
|
||||
msgBox->setWindowTitle(tr("Are you sure?"));
|
||||
msgBox->setText(tr("The decklist has been modified.\nDo you want to save the changes?"));
|
||||
msgBox->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
return msgBox;
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actLoadDeck()
|
||||
{
|
||||
auto deckOpenLocation = confirmOpen();
|
||||
|
||||
if (deckOpenLocation == CANCELLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
DlgLoadDeck dialog(this);
|
||||
if (!dialog.exec())
|
||||
return;
|
||||
|
||||
QString fileName = dialog.selectedFiles().at(0);
|
||||
openDeckFromFile(fileName, deckOpenLocation);
|
||||
deckDockWidget->updateBannerCardComboBox();
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actOpenRecent(const QString &fileName)
|
||||
{
|
||||
auto deckOpenLocation = confirmOpen();
|
||||
|
||||
if (deckOpenLocation == CANCELLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
openDeckFromFile(fileName, deckOpenLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually opens the deck from file
|
||||
* @param fileName The path of the deck to open
|
||||
* @param deckOpenLocation Which tab to open the deck
|
||||
*/
|
||||
void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation)
|
||||
{
|
||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
||||
|
||||
auto *l = new DeckLoader;
|
||||
if (l->loadFromFile(fileName, fmt, true)) {
|
||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||
if (deckOpenLocation == NEW_TAB) {
|
||||
emit openDeckEditor(l);
|
||||
} else {
|
||||
deckMenu->setSaveStatus(false);
|
||||
setDeck(l);
|
||||
}
|
||||
} else {
|
||||
delete l;
|
||||
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
|
||||
}
|
||||
deckMenu->setSaveStatus(true);
|
||||
}
|
||||
|
||||
bool AbstractTabDeckEditor::actSaveDeck()
|
||||
{
|
||||
DeckLoader *const deck = getDeckList();
|
||||
if (deck->getLastRemoteDeckId() != -1) {
|
||||
QString deckString = deck->writeToString_Native();
|
||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Could not save remote deck"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Command_DeckUpload cmd;
|
||||
cmd.set_deck_id(static_cast<google::protobuf::uint32>(deck->getLastRemoteDeckId()));
|
||||
cmd.set_deck_list(deckString.toStdString());
|
||||
|
||||
PendingCommand *pend = AbstractClient::prepareSessionCommand(cmd);
|
||||
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
|
||||
SLOT(saveDeckRemoteFinished(Response)));
|
||||
tabSupervisor->getClient()->sendCommand(pend);
|
||||
|
||||
return true;
|
||||
} else if (deck->getLastFileName().isEmpty())
|
||||
return actSaveDeckAs();
|
||||
else if (deck->saveToFile(deck->getLastFileName(), deck->getLastFileFormat())) {
|
||||
setModified(false);
|
||||
return true;
|
||||
}
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||
{
|
||||
QFileDialog dialog(this, tr("Save deck"));
|
||||
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||
dialog.setDefaultSuffix("cod");
|
||||
dialog.setNameFilters(DeckLoader::fileNameFilters);
|
||||
dialog.selectFile(getDeckList()->getName().trimmed() + ".cod");
|
||||
if (!dialog.exec())
|
||||
return false;
|
||||
|
||||
QString fileName = dialog.selectedFiles().at(0);
|
||||
DeckLoader::FileFormat fmt = DeckLoader::getFormatFromName(fileName);
|
||||
|
||||
if (!getDeckList()->saveToFile(fileName, fmt)) {
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
||||
return false;
|
||||
}
|
||||
setModified(false);
|
||||
|
||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::saveDeckRemoteFinished(const Response &response)
|
||||
{
|
||||
if (response.response_code() != Response::RespOk)
|
||||
QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved."));
|
||||
else
|
||||
setModified(false);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actLoadDeckFromClipboard()
|
||||
{
|
||||
auto deckOpenLocation = confirmOpen();
|
||||
|
||||
if (deckOpenLocation == CANCELLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
DlgLoadDeckFromClipboard dlg(this);
|
||||
if (!dlg.exec())
|
||||
return;
|
||||
|
||||
if (deckOpenLocation == NEW_TAB) {
|
||||
emit openDeckEditor(dlg.getDeckList());
|
||||
} else {
|
||||
setDeck(dlg.getDeckList());
|
||||
setModified(true);
|
||||
}
|
||||
|
||||
deckMenu->setSaveStatus(true);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboard()
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
getDeckList()->saveToStream_Plain(stream);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Selection);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetNameAndNumber()
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
getDeckList()->saveToStream_Plain(stream, true, false);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Selection);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
getDeckList()->saveToStream_Plain(stream, false);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Selection);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetNameAndNumber()
|
||||
{
|
||||
QString buffer;
|
||||
QTextStream stream(&buffer);
|
||||
getDeckList()->saveToStream_Plain(stream, false, false);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Clipboard);
|
||||
QApplication::clipboard()->setText(buffer, QClipboard::Selection);
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actPrintDeck()
|
||||
{
|
||||
auto *dlg = new QPrintPreviewDialog(this);
|
||||
connect(dlg, SIGNAL(paintRequested(QPrinter *)), deckDockWidget->deckModel, SLOT(printDeckList(QPrinter *)));
|
||||
dlg->exec();
|
||||
}
|
||||
|
||||
// Action called when export deck to decklist menu item is pressed.
|
||||
void AbstractTabDeckEditor::actExportDeckDecklist()
|
||||
{
|
||||
// Get the decklist class for the deck.
|
||||
DeckLoader *const deck = getDeckList();
|
||||
// create a string to load the decklist url into.
|
||||
QString decklistUrlString;
|
||||
// check if deck is not null
|
||||
if (deck) {
|
||||
// Get the decklist url string from the deck loader class.
|
||||
decklistUrlString = deck->exportDeckToDecklist();
|
||||
// Check to make sure the string isn't empty.
|
||||
if (QString::compare(decklistUrlString, "", Qt::CaseInsensitive) == 0) {
|
||||
// Show an error if the deck is empty, and return.
|
||||
QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported"));
|
||||
return;
|
||||
}
|
||||
// Encode the string recieved from the model to make sure all characters are encoded.
|
||||
// first we put it into a qurl object
|
||||
QUrl decklistUrl = QUrl(decklistUrlString);
|
||||
// we get the correctly encoded url.
|
||||
decklistUrlString = decklistUrl.toEncoded();
|
||||
// We open the url in the user's default browser
|
||||
QDesktopServices::openUrl(decklistUrlString);
|
||||
} else {
|
||||
// if there's no deck loader object, return an error
|
||||
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be saved."));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
|
||||
{
|
||||
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
|
||||
this); // it deletes itself when done
|
||||
interface->analyzeDeck(getDeckList());
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
|
||||
{
|
||||
auto *interface = new TappedOutInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(),
|
||||
this); // it deletes itself when done
|
||||
interface->analyzeDeck(getDeckList());
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::filterTreeChanged(FilterTree *filterTree)
|
||||
{
|
||||
databaseDisplayDockWidget->setFilterTree(filterTree);
|
||||
}
|
||||
|
||||
// Method uses to sync docks state with menu items state
|
||||
bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::Close) {
|
||||
if (o == cardInfoDockWidget) {
|
||||
aCardInfoDockVisible->setChecked(false);
|
||||
aCardInfoDockFloating->setEnabled(false);
|
||||
} else if (o == deckDockWidget) {
|
||||
aDeckDockVisible->setChecked(false);
|
||||
aDeckDockFloating->setEnabled(false);
|
||||
} else if (o == filterDockWidget) {
|
||||
aFilterDockVisible->setChecked(false);
|
||||
aFilterDockFloating->setEnabled(false);
|
||||
} else if (o == printingSelectorDockWidget) {
|
||||
aPrintingSelectorDockVisible->setChecked(false);
|
||||
aPrintingSelectorDockFloating->setEnabled(false);
|
||||
}
|
||||
}
|
||||
if (o == this && e->type() == QEvent::Hide) {
|
||||
LayoutsSettings &layouts = SettingsCache::instance().layouts();
|
||||
layouts.setDeckEditorLayoutState(saveState());
|
||||
layouts.setDeckEditorGeometry(saveGeometry());
|
||||
layouts.setDeckEditorCardSize(cardInfoDockWidget->size());
|
||||
layouts.setDeckEditorFilterSize(filterDockWidget->size());
|
||||
layouts.setDeckEditorDeckSize(deckDockWidget->size());
|
||||
layouts.setDeckEditorPrintingSelectorSize(printingSelectorDockWidget->size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AbstractTabDeckEditor::confirmClose()
|
||||
{
|
||||
if (modified) {
|
||||
tabSupervisor->setCurrentWidget(this);
|
||||
int ret = createSaveConfirmationWindow()->exec();
|
||||
if (ret == QMessageBox::Save)
|
||||
return actSaveDeck();
|
||||
else if (ret == QMessageBox::Cancel)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbstractTabDeckEditor::closeRequest(bool forced)
|
||||
{
|
||||
if (!forced && !confirmClose()) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit deckEditorClosing(this);
|
||||
close();
|
||||
}
|
||||
147
cockatrice/src/client/tabs/abstract_tab_deck_editor.h
Normal file
147
cockatrice/src/client/tabs/abstract_tab_deck_editor.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#ifndef TAB_GENERIC_DECK_EDITOR_H
|
||||
#define TAB_GENERIC_DECK_EDITOR_H
|
||||
|
||||
#include "../../game/cards/card_database.h"
|
||||
#include "../menus/deck_editor/deck_editor_menu.h"
|
||||
#include "../ui/widgets/deck_editor/deck_editor_card_info_dock_widget.h"
|
||||
#include "../ui/widgets/deck_editor/deck_editor_database_display_widget.h"
|
||||
#include "../ui/widgets/deck_editor/deck_editor_deck_dock_widget.h"
|
||||
#include "../ui/widgets/deck_editor/deck_editor_filter_dock_widget.h"
|
||||
#include "../ui/widgets/deck_editor/deck_editor_printing_selector_dock_widget.h"
|
||||
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
||||
#include "tab.h"
|
||||
|
||||
class CardDatabaseModel;
|
||||
class CardDatabaseDisplayModel;
|
||||
|
||||
class CardInfoFrameWidget;
|
||||
class DeckLoader;
|
||||
class DeckEditorMenu;
|
||||
class DeckEditorCardInfoDockWidget;
|
||||
class DeckEditorDatabaseDisplayWidget;
|
||||
class DeckEditorDeckDockWidget;
|
||||
class DeckEditorFilterDockWidget;
|
||||
class DeckEditorPrintingSelectorDockWidget;
|
||||
class DeckPreviewDeckTagsDisplayWidget;
|
||||
class Response;
|
||||
class FilterTreeModel;
|
||||
class FilterBuilder;
|
||||
|
||||
class QTreeView;
|
||||
class QTextEdit;
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class QGroupBox;
|
||||
class QMessageBox;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class QPushButton;
|
||||
class QDockWidget;
|
||||
class QMenu;
|
||||
class QAction;
|
||||
|
||||
class AbstractTabDeckEditor : public Tab
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit AbstractTabDeckEditor(TabSupervisor *_tabSupervisor);
|
||||
|
||||
// UI and Navigation
|
||||
virtual void createMenus() = 0;
|
||||
[[nodiscard]] virtual QString getTabText() const override = 0;
|
||||
bool confirmClose();
|
||||
virtual void retranslateUi() override = 0;
|
||||
|
||||
// Deck Management
|
||||
virtual void setDeck(DeckLoader *_deckLoader);
|
||||
DeckLoader *getDeckList() const;
|
||||
void setModified(bool _windowModified);
|
||||
|
||||
// UI Elements
|
||||
DeckEditorMenu *deckMenu;
|
||||
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget;
|
||||
DeckEditorCardInfoDockWidget *cardInfoDockWidget;
|
||||
DeckEditorDeckDockWidget *deckDockWidget;
|
||||
DeckEditorFilterDockWidget *filterDockWidget;
|
||||
DeckEditorPrintingSelectorDockWidget *printingSelectorDockWidget;
|
||||
|
||||
public slots:
|
||||
void onDeckChanged();
|
||||
void updateCard(CardInfoPtr _card);
|
||||
void actAddCard(CardInfoPtr info);
|
||||
void actAddCardToSideboard(CardInfoPtr info);
|
||||
void actDecrementCard(CardInfoPtr info);
|
||||
void actDecrementCardFromSideboard(CardInfoPtr info);
|
||||
void actOpenRecent(const QString &fileName);
|
||||
void filterTreeChanged(FilterTree *filterTree);
|
||||
void closeRequest(bool forced = false) override;
|
||||
virtual void showPrintingSelector() = 0;
|
||||
virtual void dockTopLevelChanged(bool topLevel) = 0;
|
||||
|
||||
signals:
|
||||
void openDeckEditor(const DeckLoader *deckLoader);
|
||||
void deckEditorClosing(AbstractTabDeckEditor *tab);
|
||||
void decrementCard(CardInfoPtr card, QString zoneName);
|
||||
|
||||
protected slots:
|
||||
// Deck Operations
|
||||
virtual void actNewDeck();
|
||||
void cleanDeckAndResetModified();
|
||||
virtual void actLoadDeck();
|
||||
bool actSaveDeck();
|
||||
bool actSaveDeckAs();
|
||||
virtual void actLoadDeckFromClipboard();
|
||||
void actSaveDeckToClipboard();
|
||||
void actSaveDeckToClipboardNoSetNameAndNumber();
|
||||
void actSaveDeckToClipboardRaw();
|
||||
void actSaveDeckToClipboardRawNoSetNameAndNumber();
|
||||
void actPrintDeck();
|
||||
void actExportDeckDecklist();
|
||||
void actAnalyzeDeckDeckstats();
|
||||
void actAnalyzeDeckTappedout();
|
||||
|
||||
// Remote Save
|
||||
void saveDeckRemoteFinished(const Response &r);
|
||||
|
||||
// UI Layout Management
|
||||
virtual void loadLayout() = 0;
|
||||
virtual void restartLayout() = 0;
|
||||
virtual void freeDocksSize() = 0;
|
||||
virtual void refreshShortcuts() = 0;
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
virtual void dockVisibleTriggered() = 0;
|
||||
virtual void dockFloatingTriggered() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Enum for selecting deck open location
|
||||
*/
|
||||
enum DeckOpenLocation
|
||||
{
|
||||
CANCELLED,
|
||||
SAME_TAB,
|
||||
NEW_TAB
|
||||
};
|
||||
|
||||
DeckOpenLocation confirmOpen(bool openInSameTabIfBlank = true);
|
||||
QMessageBox *createSaveConfirmationWindow();
|
||||
bool isBlankNewDeck() const;
|
||||
|
||||
// Helper functions for card actions
|
||||
void addCardHelper(CardInfoPtr info, QString zoneName);
|
||||
void actSwapCard(CardInfoPtr info, QString zoneName);
|
||||
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
|
||||
|
||||
// UI Menu Elements
|
||||
QMenu *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *printingSelectorDockMenu;
|
||||
|
||||
QAction *aResetLayout;
|
||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
||||
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
||||
|
||||
bool modified;
|
||||
};
|
||||
|
||||
#endif // TAB_GENERIC_DECK_EDITOR_H
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,194 +1,41 @@
|
|||
#ifndef WINDOW_DECKEDITOR_H
|
||||
#define WINDOW_DECKEDITOR_H
|
||||
|
||||
#include "../../deck/custom_line_edit.h"
|
||||
#include "../../game/cards/card_database.h"
|
||||
#include "../game_logic/key_signals.h"
|
||||
#include "../ui/widgets/printing_selector/printing_selector.h"
|
||||
#include "../ui/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.h"
|
||||
#include "tab.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDir>
|
||||
#include "abstract_tab_deck_editor.h"
|
||||
|
||||
class CardDatabaseModel;
|
||||
class CardDatabaseDisplayModel;
|
||||
class DeckListModel;
|
||||
class QTreeView;
|
||||
|
||||
class CardInfoFrameWidget;
|
||||
class QTextEdit;
|
||||
class QLabel;
|
||||
class DeckLoader;
|
||||
class DeckPreviewDeckTagsDisplayWidget;
|
||||
class Response;
|
||||
class FilterTreeModel;
|
||||
class FilterBuilder;
|
||||
class QComboBox;
|
||||
class QGroupBox;
|
||||
class QMessageBox;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class QPushButton;
|
||||
class QDockWidget;
|
||||
|
||||
class TabDeckEditor : public Tab
|
||||
class TabDeckEditor : public AbstractTabDeckEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void updateName(const QString &name);
|
||||
void updateComments();
|
||||
void updateBannerCardComboBox();
|
||||
void setBannerCard(int);
|
||||
void updateHash();
|
||||
void updateCardInfoLeft(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updateCardInfoRight(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updatePrintingSelectorDatabase(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updatePrintingSelectorDeckView(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void updateSearch(const QString &search);
|
||||
void databaseCustomMenu(QPoint point);
|
||||
void decklistCustomMenu(QPoint point);
|
||||
void updateRecentlyOpened();
|
||||
|
||||
void actNewDeck();
|
||||
void actLoadDeck();
|
||||
void actOpenRecent(const QString &fileName);
|
||||
void actClearRecents();
|
||||
bool actSaveDeck();
|
||||
bool actSaveDeckAs();
|
||||
void actLoadDeckFromClipboard();
|
||||
void actSaveDeckToClipboard();
|
||||
void actSaveDeckToClipboardNoSetNameAndNumber();
|
||||
void actSaveDeckToClipboardRaw();
|
||||
void actSaveDeckToClipboardRawNoSetNameAndNumber();
|
||||
void actPrintDeck();
|
||||
void actExportDeckDecklist();
|
||||
void actAnalyzeDeckDeckstats();
|
||||
void actAnalyzeDeckTappedout();
|
||||
|
||||
void actClearFilterAll();
|
||||
void actClearFilterOne();
|
||||
|
||||
void actSwapCard();
|
||||
void actAddCard();
|
||||
void actAddCardToSideboard();
|
||||
void actRemoveCard();
|
||||
void actIncrement();
|
||||
void actDecrement();
|
||||
void actDecrementCard();
|
||||
void actDecrementCardFromSideboard();
|
||||
void copyDatabaseCellContents();
|
||||
|
||||
void saveDeckRemoteFinished(const Response &r);
|
||||
void filterViewCustomContextMenu(const QPoint &point);
|
||||
void filterRemove(QAction *action);
|
||||
|
||||
void loadLayout();
|
||||
void restartLayout();
|
||||
void freeDocksSize();
|
||||
void refreshShortcuts();
|
||||
protected slots:
|
||||
void loadLayout() override;
|
||||
void restartLayout() override;
|
||||
void freeDocksSize() override;
|
||||
void refreshShortcuts() override;
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
void dockVisibleTriggered();
|
||||
void dockFloatingTriggered();
|
||||
void dockTopLevelChanged(bool topLevel);
|
||||
void saveDbHeaderState();
|
||||
void setSaveStatus(bool newStatus);
|
||||
void showSearchSyntaxHelp();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Which tab to open the new deck in
|
||||
*/
|
||||
enum DeckOpenLocation
|
||||
{
|
||||
CANCELLED,
|
||||
SAME_TAB,
|
||||
NEW_TAB
|
||||
};
|
||||
|
||||
DeckOpenLocation confirmOpen(const bool openInSameTabIfBlank = true);
|
||||
QMessageBox *createSaveConfirmationWindow();
|
||||
|
||||
bool isBlankNewDeck() const;
|
||||
CardInfoPtr currentCardInfo() const;
|
||||
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
||||
void decrementCardHelper(QString zoneName);
|
||||
bool swapCard(const QModelIndex &idx);
|
||||
void recursiveExpand(const QModelIndex &index);
|
||||
void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
|
||||
|
||||
QModelIndexList getSelectedCardNodes() const;
|
||||
|
||||
CardDatabaseModel *databaseModel;
|
||||
CardDatabaseDisplayModel *databaseDisplayModel;
|
||||
DeckListModel *deckModel;
|
||||
QTreeView *databaseView;
|
||||
|
||||
QTreeView *deckView;
|
||||
KeySignals deckViewKeySignals;
|
||||
CardInfoFrameWidget *cardInfo;
|
||||
PrintingSelector *printingSelector;
|
||||
SearchLineEdit *searchEdit;
|
||||
KeySignals searchKeySignals;
|
||||
|
||||
QLabel *nameLabel;
|
||||
LineEditUnfocusable *nameEdit;
|
||||
QLabel *commentsLabel;
|
||||
QTextEdit *commentsEdit;
|
||||
QLabel *bannerCardLabel;
|
||||
QComboBox *bannerCardComboBox;
|
||||
DeckPreviewDeckTagsDisplayWidget *deckTagsDisplayWidget;
|
||||
QLabel *hashLabel1;
|
||||
LineEditUnfocusable *hashLabel;
|
||||
FilterTreeModel *filterModel;
|
||||
QTreeView *filterView;
|
||||
KeySignals filterViewKeySignals;
|
||||
QWidget *filterBox;
|
||||
|
||||
QMenu *deckMenu, *viewMenu, *cardInfoDockMenu, *deckDockMenu, *filterDockMenu, *printingSelectorDockMenu,
|
||||
*analyzeDeckMenu, *saveDeckToClipboardMenu, *loadRecentDeckMenu;
|
||||
QAction *aNewDeck, *aLoadDeck, *aClearRecents, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard,
|
||||
*aSaveDeckToClipboard, *aSaveDeckToClipboardNoSetNameAndNumber, *aSaveDeckToClipboardRaw,
|
||||
*aSaveDeckToClipboardRawNoSetNameAndNumber, *aPrintDeck, *aExportDeckDecklist, *aAnalyzeDeckDeckstats,
|
||||
*aAnalyzeDeckTappedout, *aClose;
|
||||
QAction *aClearFilterAll, *aClearFilterOne;
|
||||
QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
|
||||
QAction *aResetLayout;
|
||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating, *aFilterDockVisible,
|
||||
*aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
||||
|
||||
bool modified;
|
||||
QVBoxLayout *centralFrame;
|
||||
QHBoxLayout *searchLayout;
|
||||
QDockWidget *cardInfoDock;
|
||||
QDockWidget *deckDock;
|
||||
QDockWidget *filterDock;
|
||||
QDockWidget *printingSelectorDock;
|
||||
QWidget *centralWidget;
|
||||
void dockVisibleTriggered() override;
|
||||
void dockFloatingTriggered() override;
|
||||
void dockTopLevelChanged(bool topLevel) override;
|
||||
|
||||
public:
|
||||
explicit TabDeckEditor(TabSupervisor *_tabSupervisor);
|
||||
void retranslateUi() override;
|
||||
QString getTabText() const override;
|
||||
void setDeck(DeckLoader *_deckLoader);
|
||||
void setModified(bool _windowModified);
|
||||
bool confirmClose();
|
||||
void createDeckDock();
|
||||
void createCardInfoDock();
|
||||
void createFiltersDock();
|
||||
void createPrintingSelectorDock();
|
||||
void createMenus();
|
||||
void createCentralFrame();
|
||||
void updateCardInfo(CardInfoPtr _card);
|
||||
void addCardHelper(CardInfoPtr info, QString zoneName);
|
||||
void createMenus() override;
|
||||
|
||||
public slots:
|
||||
void closeRequest(bool forced = false) override;
|
||||
void showPrintingSelector();
|
||||
signals:
|
||||
void openDeckEditor(const DeckLoader *deckLoader);
|
||||
void deckEditorClosing(TabDeckEditor *tab);
|
||||
void showPrintingSelector() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ void TabSupervisor::retranslateUi()
|
|||
QListIterator<TabGame *> replayIterator(replayTabs);
|
||||
while (replayIterator.hasNext())
|
||||
tabs.append(replayIterator.next());
|
||||
QListIterator<TabDeckEditor *> deckEditorIterator(deckEditorTabs);
|
||||
QListIterator<AbstractTabDeckEditor *> deckEditorIterator(deckEditorTabs);
|
||||
while (deckEditorIterator.hasNext())
|
||||
tabs.append(deckEditorIterator.next());
|
||||
QMapIterator<QString, TabMessage *> messageIterator(messageTabs);
|
||||
|
|
@ -242,7 +242,7 @@ bool TabSupervisor::closeRequest()
|
|||
}
|
||||
}
|
||||
|
||||
for (TabDeckEditor *tab : deckEditorTabs) {
|
||||
for (AbstractTabDeckEditor *tab : deckEditorTabs) {
|
||||
if (!tab->confirmClose())
|
||||
return false;
|
||||
}
|
||||
|
|
@ -706,8 +706,8 @@ TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
|
|||
auto *tab = new TabDeckEditor(this);
|
||||
if (deckToOpen)
|
||||
tab->setDeck(new DeckLoader(*deckToOpen));
|
||||
connect(tab, &TabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
||||
connect(tab, &TabDeckEditor::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
|
||||
connect(tab, &AbstractTabDeckEditor::deckEditorClosing, this, &TabSupervisor::deckEditorClosed);
|
||||
connect(tab, &AbstractTabDeckEditor::openDeckEditor, this, &TabSupervisor::addDeckEditorTab);
|
||||
myAddTab(tab);
|
||||
deckEditorTabs.append(tab);
|
||||
setCurrentWidget(tab);
|
||||
|
|
@ -726,7 +726,7 @@ TabEdhRec *TabSupervisor::addEdhrecTab(const CardInfoPtr &cardToQuery, bool isCo
|
|||
return tab;
|
||||
}
|
||||
|
||||
void TabSupervisor::deckEditorClosed(TabDeckEditor *tab)
|
||||
void TabSupervisor::deckEditorClosed(AbstractTabDeckEditor *tab)
|
||||
{
|
||||
if (tab == currentWidget())
|
||||
emit setMenu();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "../../deck/deck_loader.h"
|
||||
#include "../../server/user/user_list_proxy.h"
|
||||
#include "abstract_tab_deck_editor.h"
|
||||
#include "api/edhrec/tab_edhrec.h"
|
||||
#include "visual_deck_storage/tab_deck_storage_visual.h"
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ private:
|
|||
QMap<int, TabGame *> gameTabs;
|
||||
QList<TabGame *> replayTabs;
|
||||
QMap<QString, TabMessage *> messageTabs;
|
||||
QList<TabDeckEditor *> deckEditorTabs;
|
||||
QList<AbstractTabDeckEditor *> deckEditorTabs;
|
||||
bool isLocalGame;
|
||||
|
||||
QAction *aTabDeckEditor, *aTabVisualDeckStorage, *aTabServer, *aTabAccount, *aTabDeckStorage, *aTabReplays,
|
||||
|
|
@ -132,7 +133,7 @@ public:
|
|||
{
|
||||
return roomTabs;
|
||||
}
|
||||
QList<TabDeckEditor *> getDeckEditorTabs() const
|
||||
QList<AbstractTabDeckEditor *> getDeckEditorTabs() const
|
||||
{
|
||||
return deckEditorTabs;
|
||||
}
|
||||
|
|
@ -174,7 +175,7 @@ private slots:
|
|||
void processUserLeft(const QString &userName);
|
||||
void processUserJoined(const ServerInfo_User &userInfo);
|
||||
void talkLeft(TabMessage *tab);
|
||||
void deckEditorClosed(TabDeckEditor *tab);
|
||||
void deckEditorClosed(AbstractTabDeckEditor *tab);
|
||||
void tabUserEvent(bool globalEvent);
|
||||
void updateTabText(Tab *tab, const QString &newTabText);
|
||||
void processRoomEvent(const RoomEvent &event);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue