diff --git a/cockatrice/src/game/deckview/deck_view_container.cpp b/cockatrice/src/game/deckview/deck_view_container.cpp index c7876a12f..44b2be6d1 100644 --- a/cockatrice/src/game/deckview/deck_view_container.cpp +++ b/cockatrice/src/game/deckview/deck_view_container.cpp @@ -260,16 +260,15 @@ void DeckViewContainer::loadLocalDeck() void DeckViewContainer::loadDeckFromFile(const QString &filePath) { DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath); - DeckLoader deck(this); - bool success = deck.loadFromFile(filePath, fmt, true); + std::optional deckOpt = DeckLoader::loadFromFile(filePath, fmt, true); - if (!success) { + if (!deckOpt) { QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded.")); return; } - loadDeckFromDeckList(deck.getDeck().deckList); + loadDeckFromDeckList(deckOpt.value().deckList); } void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck) diff --git a/cockatrice/src/interface/deck_loader/deck_loader.cpp b/cockatrice/src/interface/deck_loader/deck_loader.cpp index 45c3ec1ba..305cd34d9 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.cpp +++ b/cockatrice/src/interface/deck_loader/deck_loader.cpp @@ -29,24 +29,26 @@ DeckLoader::DeckLoader(QObject *parent) : QObject(parent) { } -bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest) +std::optional +DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest) { QFile file(fileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; + qCWarning(DeckLoaderLog) << "File does not exist:" << fileName; + return std::nullopt; } bool result = false; - DeckList deckList = DeckList(); + DeckList deckList; switch (fmt) { case DeckFileFormat::PlainText: result = deckList.loadFromFile_Plain(&file); break; case DeckFileFormat::Cockatrice: { result = deckList.loadFromFile_Native(&file); - qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result; if (!result) { - qCInfo(DeckLoaderLog) << "Retrying as plain format"; + qCInfo(DeckLoaderLog) << "Failed to load " << fileName + << "as cockatrice format; retrying as plain format"; file.seek(0); result = deckList.loadFromFile_Plain(&file); fmt = DeckFileFormat::PlainText; @@ -58,120 +60,112 @@ bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fm break; } - if (result) { - loadedDeck.deckList = deckList; - loadedDeck.lastLoadInfo = { - .fileName = fileName, - .fileFormat = fmt, - }; - if (userRequest) { - updateLastLoadedTimestamp(fileName, fmt); - } - - emit deckLoaded(); + if (!result) { + qCWarning(DeckLoaderLog) << "Failed to load " << fileName << "as" << fmt; + return std::nullopt; } - qCInfo(DeckLoaderLog) << "Deck was loaded -" << result; - return result; -} + LoadedDeck::LoadInfo lastLoadInfo = { + .fileName = fileName, + .fileFormat = fmt, + }; + LoadedDeck loadedDeck = {deckList, lastLoadInfo}; -bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest) -{ - auto *watcher = new QFutureWatcher(this); - - connect(watcher, &QFutureWatcher::finished, this, [this, watcher, fileName, fmt, userRequest]() { - const bool result = watcher->result(); - watcher->deleteLater(); - - if (result) { - loadedDeck.lastLoadInfo = { - .fileName = fileName, - .fileFormat = fmt, - }; - if (userRequest) { - updateLastLoadedTimestamp(fileName, fmt); - } - emit deckLoaded(); - } - - emit loadFinished(result); - }); - - QFuture future = QtConcurrent::run([=, this]() { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return false; - } - - switch (fmt) { - case DeckFileFormat::PlainText: - return loadedDeck.deckList.loadFromFile_Plain(&file); - case DeckFileFormat::Cockatrice: { - bool result = false; - result = loadedDeck.deckList.loadFromFile_Native(&file); - if (!result) { - file.seek(0); - return loadedDeck.deckList.loadFromFile_Plain(&file); - } - return result; - } - default: - return false; - break; - } - }); - - watcher->setFuture(future); - return true; // Return immediately to indicate the async task was started -} - -bool DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId) -{ - bool result = loadedDeck.deckList.loadFromString_Native(nativeString); - if (result) { - loadedDeck.lastLoadInfo = { - .remoteDeckId = remoteDeckId, - }; - - emit deckLoaded(); + if (userRequest) { + updateLastLoadedTimestamp(loadedDeck); } - return result; + + qCDebug(DeckLoaderLog) << "Loaded deck" << fileName << "with userRequest:" << userRequest; + + return loadedDeck; } -bool DeckLoader::saveToFile(const QString &fileName, DeckFileFormat::Format fmt) +void DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest) +{ + QFuture future = QtConcurrent::run([=, this] { + std::optional deckOpt = loadFromFile(fileName, fmt, userRequest); + if (deckOpt) { + loadedDeck = deckOpt.value(); + } + emit loadFinished(deckOpt.has_value()); + }); +} + +std::optional DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId) +{ + DeckList deckList; + bool success = deckList.loadFromString_Native(nativeString); + + if (!success) { + qCWarning(DeckLoaderLog) << "Failed to load remote deck with id" << remoteDeckId << ":" << nativeString; + return std::nullopt; + } + + LoadedDeck::LoadInfo lastLoadInfo = {.remoteDeckId = remoteDeckId}; + LoadedDeck loadedDeck = {deckList, lastLoadInfo}; + + qCDebug(DeckLoaderLog) << "Loaded remote deck with id" << remoteDeckId; + + return loadedDeck; +} + +std::optional +DeckLoader::saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt) { QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - return false; + qCWarning(DeckLoaderLog) << "Could not create or open file:" << fileName; + return std::nullopt; } - bool result = false; + bool success = false; switch (fmt) { case DeckFileFormat::PlainText: - result = loadedDeck.deckList.saveToFile_Plain(&file); + success = deck.saveToFile_Plain(&file); break; case DeckFileFormat::Cockatrice: - result = loadedDeck.deckList.saveToFile_Native(&file); - qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result; + success = deck.saveToFile_Native(&file); break; } - if (result) { - loadedDeck.lastLoadInfo = { - .fileName = fileName, - .fileFormat = fmt, - }; - qCInfo(DeckLoaderLog) << "Deck was saved -" << result; - } - file.flush(); file.close(); - return result; + qCInfo(DeckLoaderLog) << "Saved deck to " << fileName << "with format" << fmt << "-" << success; + + if (!success) { + return std::nullopt; + } + + LoadedDeck::LoadInfo lastLoadInfo = {fileName, fmt}; + return lastLoadInfo; } -bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt) +bool DeckLoader::saveToFile(const LoadedDeck &deck) { + auto opt = saveToFile(deck.deckList, deck.lastLoadInfo.fileName, deck.lastLoadInfo.fileFormat); + return opt.has_value(); +} + +bool DeckLoader::saveToNewFile(LoadedDeck &deck, const QString &fileName, DeckFileFormat::Format fmt) +{ + std::optional infoOpt = saveToFile(deck.deckList, fileName, fmt); + + if (infoOpt) { + deck.lastLoadInfo = infoOpt.value(); + } + + return infoOpt.has_value(); +} + +/** + * @brief Updates the lastLoadedTimestamp field in the file corresponding to the deck, without changing the + * FileModificationTime of the file. + */ +bool DeckLoader::updateLastLoadedTimestamp(LoadedDeck &deck) +{ + QString fileName = deck.lastLoadInfo.fileName; + QFileInfo fileInfo(fileName); if (!fileInfo.exists()) { qCWarning(DeckLoaderLog) << "File does not exist:" << fileName; @@ -190,24 +184,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileForm bool result = false; // Perform file modifications - switch (fmt) { + switch (deck.lastLoadInfo.fileFormat) { case DeckFileFormat::PlainText: - result = loadedDeck.deckList.saveToFile_Plain(&file); + result = deck.deckList.saveToFile_Plain(&file); break; case DeckFileFormat::Cockatrice: - loadedDeck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString()); - result = loadedDeck.deckList.saveToFile_Native(&file); + deck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString()); + result = deck.deckList.saveToFile_Native(&file); break; } file.close(); // Close the file to ensure changes are flushed if (result) { - loadedDeck.lastLoadInfo = { - .fileName = fileName, - .fileFormat = fmt, - }; - // Re-open the file and set the original timestamp if (!file.open(QIODevice::ReadWrite)) { qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName; @@ -434,8 +423,13 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out, } } -bool DeckLoader::convertToCockatriceFormat(const QString &fileName) +bool DeckLoader::convertToCockatriceFormat(LoadedDeck &deck) { + QString fileName = deck.lastLoadInfo.fileName; + if (fileName.isEmpty()) { + return false; + } + // Change the file extension to .cod QFileInfo fileInfo(fileName); QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod"); @@ -453,7 +447,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName) switch (DeckFileFormat::getFormatFromName(fileName)) { case DeckFileFormat::PlainText: // Save in Cockatrice's native format - result = loadedDeck.deckList.saveToFile_Native(&file); + result = deck.deckList.saveToFile_Native(&file); break; case DeckFileFormat::Cockatrice: qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed."; @@ -474,7 +468,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName) } else { qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName; } - loadedDeck.lastLoadInfo = { + deck.lastLoadInfo = { .fileName = newFileName, .fileFormat = DeckFileFormat::Cockatrice, }; diff --git a/cockatrice/src/interface/deck_loader/deck_loader.h b/cockatrice/src/interface/deck_loader/deck_loader.h index ec5636995..1780e2706 100644 --- a/cockatrice/src/interface/deck_loader/deck_loader.h +++ b/cockatrice/src/interface/deck_loader/deck_loader.h @@ -20,7 +20,6 @@ class DeckLoader : public QObject { Q_OBJECT signals: - void deckLoaded(); void loadFinished(bool success); public: @@ -53,11 +52,60 @@ public: return loadedDeck.lastLoadInfo.isEmpty(); } - bool loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false); - bool loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest); - bool loadFromRemote(const QString &nativeString, int remoteDeckId); - bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt); - bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt); + /** + * @brief Asynchronously loads a deck from a local file into this DeckLoader. + * The `loadFinished` signal will be emitted when the load finishes. + * Once the loading finishes, the deck can be accessed with `getDeck` + * @param fileName The file to load + * @param fmt The format of the file to load + * @param userRequest Whether the load was manually requested by the user, instead of being done in the background. + */ + void loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest); + + /** + * @brief Loads a deck from a local file. + * @param fileName The file to load + * @param fmt The format of the file to load + * @param userRequest Whether the load was manually requested by the user, instead of being done in the background. + * @return An optional containing the LoadedDeck, or empty if the load failed. + */ + static std::optional + loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false); + + /** + * @brief Loads a deck from the response of a remote deck request + * @param nativeString The deck string, in cod format + * @param remoteDeckId The remote deck id + * @return An optional containing the LoadedDeck, or empty if the load failed. + */ + static std::optional loadFromRemote(const QString &nativeString, int remoteDeckId); + + /** + * @brief Saves a DeckList to a local file. + * @param deck The DeckList + * @param fileName The file to write to + * @param fmt The deck file format to use + * @return An optional containing the LoadInfo for the new file, or empty if the save failed. + */ + static std::optional + saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt); + + /** + * @brief Saves a LoadedDeck to a local file. + * Uses the lastLoadInfo in the LoadedDeck to determine where to save to. + * @param deck The LoadedDeck to save. Should have valid lastLoadInfo. + * @return Whether the save succeeded. + */ + static bool saveToFile(const LoadedDeck &deck); + + /** + * @brief Saves a LoadedDeck to a new local file. + * @param deck The LoadedDeck to save. Will update the lastLoadInfo. + * @param fileName The file to write to + * @param fmt The deck file format to use + * @return Whether the save succeeded. + */ + static bool saveToNewFile(LoadedDeck &deck, const QString &fileName, DeckFileFormat::Format fmt); static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website); @@ -74,7 +122,13 @@ public: */ static void printDeckList(QPrinter *printer, const DeckList &deckList); - bool convertToCockatriceFormat(const QString &fileName); + /** + * Converts the given deck's file to the cockatrice file format. + * Uses the lastLoadInfo in the LoadedDeck to determine the current name of the file and where to save to. + * @param deck The deck to convert. Should have valid lastLoadInfo. Will update the lastLoadInfo. + * @return Whether the conversion succeeded. + */ + static bool convertToCockatriceFormat(LoadedDeck &deck); LoadedDeck &getDeck() { @@ -90,6 +144,7 @@ public: } private: + static bool updateLastLoadedTimestamp(LoadedDeck &deck); static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node); static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList); diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp index 803a93108..269326257 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ b/cockatrice/src/interface/widgets/general/home_widget.cpp @@ -78,10 +78,9 @@ void HomeWidget::initializeBackgroundFromSource() void HomeWidget::loadBackgroundSourceDeck() { - DeckLoader deckLoader = DeckLoader(this); - deckLoader.loadFromFile(SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice, - false); - backgroundSourceDeck = deckLoader.getDeck().deckList; + std::optional deckOpt = DeckLoader::loadFromFile( + SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice, false); + backgroundSourceDeck = deckOpt.has_value() ? deckOpt.value().deckList : DeckList(); } void HomeWidget::updateRandomCard() diff --git a/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.cpp b/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.cpp index c20eb650d..0043c0496 100644 --- a/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.cpp +++ b/cockatrice/src/interface/widgets/tabs/abstract_tab_deck_editor.cpp @@ -313,13 +313,13 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo { DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName); - auto l = DeckLoader(this); - if (l.loadFromFile(fileName, fmt, true)) { + std::optional deckOpt = DeckLoader::loadFromFile(fileName, fmt, true); + if (deckOpt) { if (deckOpenLocation == NEW_TAB) { - emit openDeckEditor(l.getDeck()); + emit openDeckEditor(deckOpt.value()); } else { deckMenu->setSaveStatus(false); - openDeck(l.getDeck()); + openDeck(deckOpt.value()); } } else { QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName)); @@ -355,9 +355,7 @@ bool AbstractTabDeckEditor::actSaveDeck() if (loadedDeck.lastLoadInfo.fileName.isEmpty()) return actSaveDeckAs(); - auto deckLoader = DeckLoader(this); - deckLoader.setDeck(loadedDeck); - if (deckLoader.saveToFile(loadedDeck.lastLoadInfo.fileName, loadedDeck.lastLoadInfo.fileFormat)) { + if (DeckLoader::saveToFile(loadedDeck)) { deckStateManager->setModified(false); return true; } @@ -374,14 +372,14 @@ bool AbstractTabDeckEditor::actSaveDeck() */ bool AbstractTabDeckEditor::actSaveDeckAs() { - LoadedDeck loadedDeck = deckStateManager->toLoadedDeck(); + DeckList deckList = deckStateManager->getDeckList(); QFileDialog dialog(this, tr("Save deck")); dialog.setDirectory(SettingsCache::instance().getDeckPath()); dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setDefaultSuffix("cod"); dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS); - dialog.selectFile(loadedDeck.deckList.getName().trimmed()); + dialog.selectFile(deckList.getName().trimmed()); if (!dialog.exec()) return false; @@ -389,16 +387,15 @@ bool AbstractTabDeckEditor::actSaveDeckAs() QString fileName = dialog.selectedFiles().at(0); DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName); - DeckLoader deckLoader = DeckLoader(this); - deckLoader.setDeck(loadedDeck); - if (!deckLoader.saveToFile(fileName, fmt)) { + std::optional infoOpt = DeckLoader::saveToFile(deckList, fileName, fmt); + if (!infoOpt) { QMessageBox::critical( this, tr("Error"), tr("The deck could not be saved.\nPlease check that the directory is writable and try again.")); return false; } - deckStateManager->setLastLoadInfo({.fileName = fileName, .fileFormat = fmt}); + deckStateManager->setLastLoadInfo(infoOpt.value()); deckStateManager->setModified(false); SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName); diff --git a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp index 73b3fc0ac..26e3f2ecf 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_deck_storage.cpp @@ -241,11 +241,11 @@ void TabDeckStorage::actOpenLocalDeck() continue; QString filePath = localDirModel->filePath(curLeft); - auto deckLoader = new DeckLoader(this); - if (!deckLoader->loadFromFile(filePath, DeckFileFormat::Cockatrice, true)) + std::optional deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true); + if (!deckOpt) continue; - emit openDeckEditor(deckLoader->getDeck()); + emit openDeckEditor(deckOpt.value()); } } @@ -307,13 +307,13 @@ void TabDeckStorage::uploadDeck(const QString &filePath, const QString &targetPa QFile deckFile(filePath); QFileInfo deckFileInfo(deckFile); - DeckLoader deckLoader(this); - if (!deckLoader.loadFromFile(filePath, DeckFileFormat::Cockatrice)) { + std::optional deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true); + if (!deckOpt) { QMessageBox::critical(this, tr("Error"), tr("Invalid deck file")); return; } - DeckList deck = deckLoader.getDeck().deckList; + DeckList deck = deckOpt.value().deckList; if (deck.getName().isEmpty()) { bool ok; @@ -434,11 +434,11 @@ void TabDeckStorage::openRemoteDeckFinished(const Response &r, const CommandCont const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext); const Command_DeckDownload &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDownload::ext); - DeckLoader loader(this); - if (!loader.loadFromRemote(QString::fromStdString(resp.deck()), cmd.deck_id())) + std::optional deckOpt = DeckLoader::loadFromRemote(QString::fromStdString(resp.deck()), cmd.deck_id()); + if (!deckOpt) return; - emit openDeckEditor(loader.getDeck()); + emit openDeckEditor(deckOpt.value()); } void TabDeckStorage::actDownload() @@ -496,10 +496,7 @@ void TabDeckStorage::downloadFinished(const Response &r, DeckList deckList = DeckList(QString::fromStdString(resp.deck())); - DeckLoader deckLoader(this); - deckLoader.setDeck({deckList, {}}); - - deckLoader.saveToFile(filePath, DeckFileFormat::Cockatrice); + DeckLoader::saveToFile(deckList, filePath, DeckFileFormat::Cockatrice); } void TabDeckStorage::actNewFolder() diff --git a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp b/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp index 9570702ed..0cbcb641a 100644 --- a/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp +++ b/cockatrice/src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp @@ -24,11 +24,12 @@ TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor) void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath) { - auto deckLoader = DeckLoader(this); - if (!deckLoader.loadFromFile(filePath, DeckFileFormat::getFormatFromName(filePath), true)) { + std::optional deckOpt = + DeckLoader::loadFromFile(filePath, DeckFileFormat::getFormatFromName(filePath), true); + if (!deckOpt) { QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(filePath)); return; } - emit openDeckEditor(deckLoader.getDeck()); + emit openDeckEditor(deckOpt.value()); } diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp index d57cda1c6..8cd1004de 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_deck_tags_display_widget.cpp @@ -77,10 +77,10 @@ static QStringList findAllKnownTags() QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath()); QStringList knownTags; - auto loader = DeckLoader(nullptr); for (const QString &file : allFiles) { - loader.loadFromFile(file, DeckFileFormat::getFormatFromName(file), false); - QStringList tags = loader.getDeck().deckList.getTags(); + std::optional deckOpt = + DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), false); + QStringList tags = deckOpt.has_value() ? deckOpt->deckList.getTags() : QStringList(); knownTags.append(tags); knownTags.removeDuplicates(); } @@ -124,7 +124,7 @@ static bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath) static void convertFileToCockatriceFormat(DeckPreviewWidget *deckPreviewWidget) { - deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath); + DeckLoader::convertToCockatriceFormat(deckPreviewWidget->deckLoader->getDeck()); deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getDeck().lastLoadInfo.fileName; deckPreviewWidget->refreshBannerCardText(); } diff --git a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp index f98e37e16..5c55db456 100644 --- a/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp +++ b/cockatrice/src/interface/widgets/visual_deck_storage/deck_preview/deck_preview_widget.cpp @@ -288,7 +288,7 @@ void DeckPreviewWidget::setBannerCard(int /* changedIndex */) auto [name, id] = bannerCardComboBox->currentData().value>(); CardRef cardRef = {name, id}; deckLoader->getDeck().deckList.setBannerCard(cardRef); - deckLoader->saveToFile(filePath, DeckFileFormat::getFormatFromName(filePath)); + DeckLoader::saveToFile(deckLoader->getDeck()); bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef)); } @@ -311,7 +311,7 @@ void DeckPreviewWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewC void DeckPreviewWidget::setTags(const QStringList &tags) { deckLoader->getDeck().deckList.setTags(tags); - deckLoader->saveToFile(filePath, DeckFileFormat::Cockatrice); + DeckLoader::saveToFile(deckLoader->getDeck()); } QMenu *DeckPreviewWidget::createRightClickMenu() @@ -386,7 +386,7 @@ void DeckPreviewWidget::actRenameDeck() // write change deckLoader->getDeck().deckList.setName(newName); - deckLoader->saveToFile(filePath, DeckFileFormat::getFormatFromName(filePath)); + DeckLoader::saveToFile(deckLoader->getDeck()); // update VDS refreshBannerCardText(); diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp index a294601fb..71a04cce3 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.cpp @@ -182,7 +182,7 @@ bool DeckList::loadFromFile_Native(QIODevice *device) return loadFromXml(&xml); } -bool DeckList::saveToFile_Native(QIODevice *device) +bool DeckList::saveToFile_Native(QIODevice *device) const { QXmlStreamWriter xml(device); xml.setAutoFormatting(true); @@ -393,7 +393,7 @@ bool DeckList::loadFromFile_Plain(QIODevice *device) return loadFromStream_Plain(in, false); } -bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) +bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const { auto writeToStream = [&stream, prefixSideboardCards, slashTappedOutSplitCards](const auto node, const auto card) { if (prefixSideboardCards && node->getName() == DECK_ZONE_SIDE) { @@ -410,13 +410,13 @@ bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards return true; } -bool DeckList::saveToFile_Plain(QIODevice *device, bool prefixSideboardCards, bool slashTappedOutSplitCards) +bool DeckList::saveToFile_Plain(QIODevice *device, bool prefixSideboardCards, bool slashTappedOutSplitCards) const { QTextStream out(device); return saveToStream_Plain(out, prefixSideboardCards, slashTappedOutSplitCards); } -QString DeckList::writeToString_Plain(bool prefixSideboardCards, bool slashTappedOutSplitCards) +QString DeckList::writeToString_Plain(bool prefixSideboardCards, bool slashTappedOutSplitCards) const { QString result; QTextStream out(&result); diff --git a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h index d0ca55342..808733b09 100644 --- a/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h +++ b/libcockatrice_deck_list/libcockatrice/deck_list/deck_list.h @@ -201,16 +201,17 @@ public: bool loadFromString_Native(const QString &nativeString); QString writeToString_Native() const; bool loadFromFile_Native(QIODevice *device); - bool saveToFile_Native(QIODevice *device); + bool saveToFile_Native(QIODevice *device) const; ///@} /// @name Serialization (Plain text) ///@{ bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata); bool loadFromFile_Plain(QIODevice *device); - bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards); - bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false); - QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false); + bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const; + bool + saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const; + QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const; ///@} /// @name Deck manipulation