Add a dialog to prompt user to convert to .cod format if trying to apply tags to a .txt deck. (#5514)

* Add a dialog to prompt user to convert to .cod format if trying to apply tags to a .txt deck.

* Lint mocks.

* Address comments, move dialog to appropriate folder.

* Unlint.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL
2025-01-25 04:20:30 +01:00
committed by GitHub
parent 4e96157091
commit ce416df3fb
14 changed files with 229 additions and 6 deletions

View File

@@ -35,6 +35,7 @@ set(cockatrice_SOURCES
src/deck/deck_list_model.cpp
src/deck/deck_stats_interface.cpp
src/dialogs/dlg_connect.cpp
src/dialogs/dlg_convert_deck_to_cod_format.cpp
src/dialogs/dlg_create_token.cpp
src/dialogs/dlg_create_game.cpp
src/dialogs/dlg_edit_avatar.cpp

View File

@@ -1,5 +1,7 @@
#include "deck_preview_tag_addition_widget.h"
#include "../../../../../dialogs/dlg_convert_deck_to_cod_format.h"
#include "../../../../../settings/cache_settings.h"
#include "deck_preview_tag_dialog.h"
#include <QFontMetrics>
@@ -40,11 +42,50 @@ void DeckPreviewTagAdditionWidget::mousePressEvent(QMouseEvent *event)
QStringList knownTags = parent->parent->parent->gatherAllTagsFromFlowWidget();
QStringList activeTags = parent->deckLoader->getTags();
DeckPreviewTagDialog dialog(knownTags, activeTags);
if (dialog.exec() == QDialog::Accepted) {
QStringList updatedTags = dialog.getActiveTags();
parent->deckLoader->setTags(updatedTags);
parent->deckLoader->saveToFile(parent->parent->filePath, DeckLoader::CockatriceFormat);
bool canAddTags = true;
if (parent->deckLoader->getLastFileFormat() != DeckLoader::CockatriceFormat) {
canAddTags = false;
// Retrieve saved preference if the prompt is disabled
if (!SettingsCache::instance().getVisualDeckStoragePromptForConversion()) {
if (SettingsCache::instance().getVisualDeckStorageAlwaysConvert()) {
parent->deckLoader->convertToCockatriceFormat(parent->parent->filePath);
parent->parent->filePath = parent->deckLoader->getLastFileName();
parent->parent->refreshBannerCardText();
canAddTags = true;
}
} else {
// Show the dialog to the user
DialogConvertDeckToCodFormat conversionDialog(parent);
if (conversionDialog.exec() == QDialog::Accepted) {
parent->deckLoader->convertToCockatriceFormat(parent->parent->filePath);
parent->parent->filePath = parent->deckLoader->getLastFileName();
parent->parent->refreshBannerCardText();
canAddTags = true;
if (conversionDialog.dontAskAgain()) {
SettingsCache::instance().setVisualDeckStoragePromptForConversion(Qt::CheckState::Unchecked);
SettingsCache::instance().setVisualDeckStorageAlwaysConvert(Qt::CheckState::Checked);
}
} else {
SettingsCache::instance().setVisualDeckStorageAlwaysConvert(Qt::CheckState::Unchecked);
if (conversionDialog.dontAskAgain()) {
SettingsCache::instance().setVisualDeckStoragePromptForConversion(Qt::CheckState::Unchecked);
} else {
SettingsCache::instance().setVisualDeckStoragePromptForConversion(Qt::CheckState::Checked);
}
}
}
}
if (canAddTags) {
DeckPreviewTagDialog dialog(knownTags, activeTags);
if (dialog.exec() == QDialog::Accepted) {
QStringList updatedTags = dialog.getActiveTags();
parent->deckLoader->setTags(updatedTags);
parent->deckLoader->saveToFile(parent->parent->filePath, DeckLoader::CockatriceFormat);
}
}
}

View File

@@ -17,7 +17,7 @@ DeckPreviewWidget::DeckPreviewWidget(VisualDeckStorageWidget *_parent, const QSt
deckLoader = new DeckLoader();
connect(deckLoader, &DeckLoader::loadFinished, this, &DeckPreviewWidget::initializeUi);
deckLoader->loadFromFileAsync(filePath, DeckLoader::CockatriceFormat, false);
deckLoader->loadFromFileAsync(filePath, DeckLoader::getFormatFromName(filePath), false);
bannerCardDisplayWidget = new DeckPreviewCardPictureWidget(this);
@@ -88,6 +88,12 @@ void DeckPreviewWidget::setFilePath(const QString &_filePath)
filePath = _filePath;
}
void DeckPreviewWidget::refreshBannerCardText()
{
bannerCardDisplayWidget->setOverlayText(
deckLoader->getName().isEmpty() ? QFileInfo(deckLoader->getLastFileName()).fileName() : deckLoader->getName());
}
void DeckPreviewWidget::imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance)
{
Q_UNUSED(instance);

View File

@@ -33,6 +33,7 @@ signals:
public slots:
void setFilePath(const QString &filePath);
void refreshBannerCardText();
void imageClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
void imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewCardPictureWidget *instance);
void initializeUi(bool deckLoadSuccess);

View File

@@ -6,6 +6,7 @@
#include "decklist.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFutureWatcher>
@@ -481,6 +482,53 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
}
}
bool DeckLoader::convertToCockatriceFormat(QString fileName)
{
// Change the file extension to .cod
QFileInfo fileInfo(fileName);
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
// Open the new file for writing
QFile file(newFileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
qCWarning(DeckLoaderLog) << "Failed to open file for writing:" << newFileName;
return false;
}
bool result = false;
// Perform file modifications based on the detected format
switch (getFormatFromName(fileName)) {
case PlainTextFormat:
// Save in Cockatrice's native format
result = saveToFile_Native(&file);
break;
case CockatriceFormat:
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
result = true;
break;
default:
qCWarning(DeckLoaderLog) << "Unsupported file format for conversion:" << fileName;
result = false;
break;
}
file.close();
// Delete the old file if conversion was successful
if (result) {
if (!QFile::remove(fileName)) {
qCWarning(DeckLoaderLog) << "Failed to delete original file:" << fileName;
} else {
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
}
lastFileName = newFileName;
lastFileFormat = CockatriceFormat;
}
return result;
}
QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneName)
{
CardInfoPtr card = CardDatabaseManager::getInstance()->getCard(cardName);

View File

@@ -59,6 +59,7 @@ public:
// overload
bool saveToStream_Plain(QTextStream &out, bool addComments = true, bool addSetNameAndNumber = true);
bool convertToCockatriceFormat(QString fileName);
protected:
void saveToStream_DeckHeader(QTextStream &out);

View File

@@ -0,0 +1,40 @@
#include "dlg_convert_deck_to_cod_format.h"
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QLabel>
#include <QVBoxLayout>
DialogConvertDeckToCodFormat::DialogConvertDeckToCodFormat(QWidget *parent) : QDialog(parent)
{
layout = new QVBoxLayout(this);
label = new QLabel();
layout->addWidget(label);
dontAskAgainCheckbox = new QCheckBox(this);
layout->addWidget(dontAskAgainCheckbox);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
layout->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::accepted, this, [this]() { accept(); });
connect(buttonBox, &QDialogButtonBox::rejected, this, [this]() { reject(); });
setLayout(layout);
retranslateUi();
}
void DialogConvertDeckToCodFormat::retranslateUi()
{
setWindowTitle(tr("Deck Format Conversion"));
label->setText(
tr("You tried to add a tag to a .txt format deck.\n Tags can only be added to .cod format decks.\n Do "
"you want to convert the deck to the .cod format?"));
dontAskAgainCheckbox->setText(tr("Remember and automatically apply choice in the future"));
}
bool DialogConvertDeckToCodFormat::dontAskAgain() const
{
return dontAskAgainCheckbox->isChecked();
}

View File

@@ -0,0 +1,29 @@
#ifndef DIALOG_CONVERT_DECK_TO_COD_FORMAT_H
#define DIALOG_CONVERT_DECK_TO_COD_FORMAT_H
#include <QCheckBox>
#include <QDialog>
#include <QDialogButtonBox>
#include <QLabel>
#include <QVBoxLayout>
class DialogConvertDeckToCodFormat : public QDialog
{
Q_OBJECT
public:
explicit DialogConvertDeckToCodFormat(QWidget *parent);
void retranslateUi();
bool dontAskAgain() const;
private:
QVBoxLayout *layout;
QLabel *label;
QCheckBox *dontAskAgainCheckbox;
QDialogButtonBox *buttonBox;
Q_DISABLE_COPY(DialogConvertDeckToCodFormat)
};
#endif // DIALOG_CONVERT_DECK_TO_COD_FORMAT_H

View File

@@ -573,6 +573,15 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
connect(&useTearOffMenusCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
[](const QT_STATE_CHANGED_T state) { SettingsCache::instance().setUseTearOffMenus(state == Qt::Checked); });
visualDeckStoragePromptForConversionCheckBox.setChecked(
SettingsCache::instance().getVisualDeckStoragePromptForConversion());
connect(&visualDeckStoragePromptForConversionCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setVisualDeckStoragePromptForConversion);
visualDeckStorageAlwaysConvertCheckBox.setChecked(SettingsCache::instance().getVisualDeckStorageAlwaysConvert());
connect(&visualDeckStorageAlwaysConvertCheckBox, &QCheckBox::QT_STATE_CHANGED, &SettingsCache::instance(),
&SettingsCache::setVisualDeckStorageAlwaysConvert);
auto *generalGrid = new QGridLayout;
generalGrid->addWidget(&doubleClickToPlayCheckBox, 0, 0);
generalGrid->addWidget(&clickPlaysAllSelectedCheckBox, 1, 0);
@@ -580,6 +589,8 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
generalGrid->addWidget(&closeEmptyCardViewCheckBox, 3, 0);
generalGrid->addWidget(&annotateTokensCheckBox, 4, 0);
generalGrid->addWidget(&useTearOffMenusCheckBox, 5, 0);
generalGrid->addWidget(&visualDeckStoragePromptForConversionCheckBox, 6, 0);
generalGrid->addWidget(&visualDeckStorageAlwaysConvertCheckBox, 7, 0);
generalGroupBox = new QGroupBox;
generalGroupBox->setLayout(generalGrid);
@@ -658,6 +669,8 @@ void UserInterfaceSettingsPage::retranslateUi()
closeEmptyCardViewCheckBox.setText(tr("Close card view window when last card is removed"));
annotateTokensCheckBox.setText(tr("Annotate card text on tokens"));
useTearOffMenusCheckBox.setText(tr("Use tear-off menus, allowing right click menus to persist on screen"));
visualDeckStoragePromptForConversionCheckBox.setText(tr("Prompt before converting .txt decks to .cod format"));
visualDeckStorageAlwaysConvertCheckBox.setText(tr("Always convert if not prompted"));
notificationsGroupBox->setTitle(tr("Notifications settings"));
notificationsEnabledCheckBox.setText(tr("Enable notifications in taskbar"));
specNotificationsEnabledCheckBox.setText(tr("Notify in the taskbar for game events while you are spectating"));

View File

@@ -142,6 +142,8 @@ private:
QCheckBox closeEmptyCardViewCheckBox;
QCheckBox annotateTokensCheckBox;
QCheckBox useTearOffMenusCheckBox;
QCheckBox visualDeckStoragePromptForConversionCheckBox;
QCheckBox visualDeckStorageAlwaysConvertCheckBox;
QCheckBox tapAnimationCheckBox;
QCheckBox openDeckInNewTabCheckBox;
QLabel rewindBufferingMsLabel;

View File

@@ -274,6 +274,9 @@ SettingsCache::SettingsCache()
settings->value("interface/visualdeckstoragedrawunusedcoloridentities", true).toBool();
visualDeckStorageUnusedColorIdentitiesOpacity =
settings->value("interface/visualdeckstorageunusedcoloridentitiesopacity", 15).toInt();
visualDeckStoragePromptForConversion =
settings->value("interface/visualdeckstoragepromptforconversion", true).toBool();
visualDeckStorageAlwaysConvert = settings->value("interface/visualdeckstoragealwaysconvert", false).toBool();
horizontalHand = settings->value("hand/horizontal", true).toBool();
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
@@ -699,6 +702,18 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visual
visualDeckStorageUnusedColorIdentitiesOpacity);
}
void SettingsCache::setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion)
{
visualDeckStoragePromptForConversion = _visualDeckStoragePromptForConversion;
settings->setValue("interface/visualdeckstoragepromptforconversion", visualDeckStoragePromptForConversion);
}
void SettingsCache::setVisualDeckStorageAlwaysConvert(QT_STATE_CHANGED_T _visualDeckStorageAlwaysConvert)
{
visualDeckStorageAlwaysConvert = _visualDeckStorageAlwaysConvert;
settings->setValue("interface/visualdeckstoragealwaysconvert", visualDeckStorageAlwaysConvert);
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand)
{
horizontalHand = static_cast<bool>(_horizontalHand);

View File

@@ -133,6 +133,8 @@ private:
int visualDeckStorageCardSize;
bool visualDeckStorageDrawUnusedColorIdentities;
int visualDeckStorageUnusedColorIdentitiesOpacity;
bool visualDeckStoragePromptForConversion;
bool visualDeckStorageAlwaysConvert;
bool horizontalHand;
bool invertVerticalCoordinate;
int minPlayersForMultiColumnLayout;
@@ -424,6 +426,14 @@ public:
{
return visualDeckStorageUnusedColorIdentitiesOpacity;
}
bool getVisualDeckStoragePromptForConversion() const
{
return visualDeckStoragePromptForConversion;
}
bool getVisualDeckStorageAlwaysConvert() const
{
return visualDeckStorageAlwaysConvert;
}
bool getHorizontalHand() const
{
return horizontalHand;
@@ -748,6 +758,8 @@ public slots:
void setVisualDeckStorageCardSize(int _visualDeckStorageCardSize);
void setVisualDeckStorageDrawUnusedColorIdentities(QT_STATE_CHANGED_T _visualDeckStorageDrawUnusedColorIdentities);
void setVisualDeckStorageUnusedColorIdentitiesOpacity(int _visualDeckStorageUnusedColorIdentitiesOpacity);
void setVisualDeckStoragePromptForConversion(QT_STATE_CHANGED_T _visualDeckStoragePromptForConversion);
void setVisualDeckStorageAlwaysConvert(QT_STATE_CHANGED_T _visualDeckStorageAlwaysConvert);
void setHorizontalHand(QT_STATE_CHANGED_T _horizontalHand);
void setInvertVerticalCoordinate(QT_STATE_CHANGED_T _invertVerticalCoordinate);
void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout);

View File

@@ -222,6 +222,13 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
{
}
void SettingsCache::setVisualDeckStoragePromptForConversion(
QT_STATE_CHANGED_T /* _visualDeckStoragePromptForConversion */)
{
}
void SettingsCache::setVisualDeckStorageAlwaysConvert(QT_STATE_CHANGED_T /* _visualDeckStorageAlwaysConvert */)
{
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}

View File

@@ -226,6 +226,13 @@ void SettingsCache::setVisualDeckStorageUnusedColorIdentitiesOpacity(
int /* _visualDeckStorageUnusedColorIdentitiesOpacity */)
{
}
void SettingsCache::setVisualDeckStoragePromptForConversion(
QT_STATE_CHANGED_T /* _visualDeckStoragePromptForConversion */)
{
}
void SettingsCache::setVisualDeckStorageAlwaysConvert(QT_STATE_CHANGED_T /* _visualDeckStorageAlwaysConvert */)
{
}
void SettingsCache::setHorizontalHand(QT_STATE_CHANGED_T /* _horizontalHand */)
{
}