mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-04 04:23:55 -07:00
[DeckLoader] Make save/load methods static (#6476)
* const * [DeckLoader] make methods static * use static methods * add docs * add docs
This commit is contained in:
parent
c7c7bf550a
commit
d579c82cb9
11 changed files with 209 additions and 166 deletions
|
|
@ -260,16 +260,15 @@ void DeckViewContainer::loadLocalDeck()
|
||||||
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
{
|
{
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(filePath);
|
||||||
DeckLoader deck(this);
|
|
||||||
|
|
||||||
bool success = deck.loadFromFile(filePath, fmt, true);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, fmt, true);
|
||||||
|
|
||||||
if (!success) {
|
if (!deckOpt) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
QMessageBox::critical(this, tr("Error"), tr("The selected file could not be loaded."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDeckFromDeckList(deck.getDeck().deckList);
|
loadDeckFromDeckList(deckOpt.value().deckList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||||
|
|
|
||||||
|
|
@ -29,24 +29,26 @@ DeckLoader::DeckLoader(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
std::optional<LoadedDeck>
|
||||||
|
DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
return false;
|
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
DeckList deckList = DeckList();
|
DeckList deckList;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice: {
|
case DeckFileFormat::Cockatrice: {
|
||||||
result = deckList.loadFromFile_Native(&file);
|
result = deckList.loadFromFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
|
||||||
if (!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);
|
file.seek(0);
|
||||||
result = deckList.loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file);
|
||||||
fmt = DeckFileFormat::PlainText;
|
fmt = DeckFileFormat::PlainText;
|
||||||
|
|
@ -58,120 +60,112 @@ bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fm
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (!result) {
|
||||||
loadedDeck.deckList = deckList;
|
qCWarning(DeckLoaderLog) << "Failed to load " << fileName << "as" << fmt;
|
||||||
loadedDeck.lastLoadInfo = {
|
return std::nullopt;
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
if (userRequest) {
|
|
||||||
updateLastLoadedTimestamp(fileName, fmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit deckLoaded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qCInfo(DeckLoaderLog) << "Deck was loaded -" << result;
|
LoadedDeck::LoadInfo lastLoadInfo = {
|
||||||
return result;
|
.fileName = fileName,
|
||||||
}
|
.fileFormat = fmt,
|
||||||
|
};
|
||||||
|
LoadedDeck loadedDeck = {deckList, lastLoadInfo};
|
||||||
|
|
||||||
bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest)
|
if (userRequest) {
|
||||||
{
|
updateLastLoadedTimestamp(loadedDeck);
|
||||||
auto *watcher = new QFutureWatcher<bool>(this);
|
|
||||||
|
|
||||||
connect(watcher, &QFutureWatcher<bool>::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<bool> 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();
|
|
||||||
}
|
}
|
||||||
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<void> future = QtConcurrent::run([=, this] {
|
||||||
|
std::optional<LoadedDeck> deckOpt = loadFromFile(fileName, fmt, userRequest);
|
||||||
|
if (deckOpt) {
|
||||||
|
loadedDeck = deckOpt.value();
|
||||||
|
}
|
||||||
|
emit loadFinished(deckOpt.has_value());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<LoadedDeck> 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<LoadedDeck::LoadInfo>
|
||||||
|
DeckLoader::saveToFile(const DeckList &deck, const QString &fileName, DeckFileFormat::Format fmt)
|
||||||
{
|
{
|
||||||
QFile file(fileName);
|
QFile file(fileName);
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
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) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
success = deck.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
success = deck.saveToFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
qCInfo(DeckLoaderLog) << "Deck was saved -" << result;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.flush();
|
file.flush();
|
||||||
file.close();
|
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<LoadedDeck::LoadInfo> 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);
|
QFileInfo fileInfo(fileName);
|
||||||
if (!fileInfo.exists()) {
|
if (!fileInfo.exists()) {
|
||||||
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
qCWarning(DeckLoaderLog) << "File does not exist:" << fileName;
|
||||||
|
|
@ -190,24 +184,19 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileForm
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
// Perform file modifications
|
// Perform file modifications
|
||||||
switch (fmt) {
|
switch (deck.lastLoadInfo.fileFormat) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
result = deck.deckList.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
loadedDeck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
deck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
result = deck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close(); // Close the file to ensure changes are flushed
|
file.close(); // Close the file to ensure changes are flushed
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
loadedDeck.lastLoadInfo = {
|
|
||||||
.fileName = fileName,
|
|
||||||
.fileFormat = fmt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Re-open the file and set the original timestamp
|
// Re-open the file and set the original timestamp
|
||||||
if (!file.open(QIODevice::ReadWrite)) {
|
if (!file.open(QIODevice::ReadWrite)) {
|
||||||
qCWarning(DeckLoaderLog) << "Failed to re-open file to set timestamp:" << fileName;
|
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
|
// Change the file extension to .cod
|
||||||
QFileInfo fileInfo(fileName);
|
QFileInfo fileInfo(fileName);
|
||||||
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
|
QString newFileName = QDir::toNativeSeparators(fileInfo.path() + "/" + fileInfo.completeBaseName() + ".cod");
|
||||||
|
|
@ -453,7 +447,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
||||||
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
// Save in Cockatrice's native format
|
// Save in Cockatrice's native format
|
||||||
result = loadedDeck.deckList.saveToFile_Native(&file);
|
result = deck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
||||||
|
|
@ -474,7 +468,7 @@ bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
||||||
} else {
|
} else {
|
||||||
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
||||||
}
|
}
|
||||||
loadedDeck.lastLoadInfo = {
|
deck.lastLoadInfo = {
|
||||||
.fileName = newFileName,
|
.fileName = newFileName,
|
||||||
.fileFormat = DeckFileFormat::Cockatrice,
|
.fileFormat = DeckFileFormat::Cockatrice,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ class DeckLoader : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
signals:
|
signals:
|
||||||
void deckLoaded();
|
|
||||||
void loadFinished(bool success);
|
void loadFinished(bool success);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -53,11 +52,60 @@ public:
|
||||||
return loadedDeck.lastLoadInfo.isEmpty();
|
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);
|
* @brief Asynchronously loads a deck from a local file into this DeckLoader.
|
||||||
bool loadFromRemote(const QString &nativeString, int remoteDeckId);
|
* The `loadFinished` signal will be emitted when the load finishes.
|
||||||
bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt);
|
* Once the loading finishes, the deck can be accessed with `getDeck`
|
||||||
bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt);
|
* @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<LoadedDeck>
|
||||||
|
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<LoadedDeck> 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<LoadedDeck::LoadInfo>
|
||||||
|
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);
|
static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website);
|
||||||
|
|
||||||
|
|
@ -74,7 +122,13 @@ public:
|
||||||
*/
|
*/
|
||||||
static void printDeckList(QPrinter *printer, const DeckList &deckList);
|
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()
|
LoadedDeck &getDeck()
|
||||||
{
|
{
|
||||||
|
|
@ -90,6 +144,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool updateLastLoadedTimestamp(LoadedDeck &deck);
|
||||||
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
||||||
static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
|
static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,10 +78,9 @@ void HomeWidget::initializeBackgroundFromSource()
|
||||||
|
|
||||||
void HomeWidget::loadBackgroundSourceDeck()
|
void HomeWidget::loadBackgroundSourceDeck()
|
||||||
{
|
{
|
||||||
DeckLoader deckLoader = DeckLoader(this);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(
|
||||||
deckLoader.loadFromFile(SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice,
|
SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice, false);
|
||||||
false);
|
backgroundSourceDeck = deckOpt.has_value() ? deckOpt.value().deckList : DeckList();
|
||||||
backgroundSourceDeck = deckLoader.getDeck().deckList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HomeWidget::updateRandomCard()
|
void HomeWidget::updateRandomCard()
|
||||||
|
|
|
||||||
|
|
@ -313,13 +313,13 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo
|
||||||
{
|
{
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
||||||
|
|
||||||
auto l = DeckLoader(this);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(fileName, fmt, true);
|
||||||
if (l.loadFromFile(fileName, fmt, true)) {
|
if (deckOpt) {
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(l.getDeck());
|
emit openDeckEditor(deckOpt.value());
|
||||||
} else {
|
} else {
|
||||||
deckMenu->setSaveStatus(false);
|
deckMenu->setSaveStatus(false);
|
||||||
openDeck(l.getDeck());
|
openDeck(deckOpt.value());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
|
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())
|
if (loadedDeck.lastLoadInfo.fileName.isEmpty())
|
||||||
return actSaveDeckAs();
|
return actSaveDeckAs();
|
||||||
|
|
||||||
auto deckLoader = DeckLoader(this);
|
if (DeckLoader::saveToFile(loadedDeck)) {
|
||||||
deckLoader.setDeck(loadedDeck);
|
|
||||||
if (deckLoader.saveToFile(loadedDeck.lastLoadInfo.fileName, loadedDeck.lastLoadInfo.fileFormat)) {
|
|
||||||
deckStateManager->setModified(false);
|
deckStateManager->setModified(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -374,14 +372,14 @@ bool AbstractTabDeckEditor::actSaveDeck()
|
||||||
*/
|
*/
|
||||||
bool AbstractTabDeckEditor::actSaveDeckAs()
|
bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||||
{
|
{
|
||||||
LoadedDeck loadedDeck = deckStateManager->toLoadedDeck();
|
DeckList deckList = deckStateManager->getDeckList();
|
||||||
|
|
||||||
QFileDialog dialog(this, tr("Save deck"));
|
QFileDialog dialog(this, tr("Save deck"));
|
||||||
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
dialog.setDefaultSuffix("cod");
|
dialog.setDefaultSuffix("cod");
|
||||||
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||||
dialog.selectFile(loadedDeck.deckList.getName().trimmed());
|
dialog.selectFile(deckList.getName().trimmed());
|
||||||
|
|
||||||
if (!dialog.exec())
|
if (!dialog.exec())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -389,16 +387,15 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||||
QString fileName = dialog.selectedFiles().at(0);
|
QString fileName = dialog.selectedFiles().at(0);
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
||||||
|
|
||||||
DeckLoader deckLoader = DeckLoader(this);
|
std::optional<LoadedDeck::LoadInfo> infoOpt = DeckLoader::saveToFile(deckList, fileName, fmt);
|
||||||
deckLoader.setDeck(loadedDeck);
|
if (!infoOpt) {
|
||||||
if (!deckLoader.saveToFile(fileName, fmt)) {
|
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Error"),
|
this, tr("Error"),
|
||||||
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
deckStateManager->setLastLoadInfo({.fileName = fileName, .fileFormat = fmt});
|
deckStateManager->setLastLoadInfo(infoOpt.value());
|
||||||
|
|
||||||
deckStateManager->setModified(false);
|
deckStateManager->setModified(false);
|
||||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||||
|
|
|
||||||
|
|
@ -241,11 +241,11 @@ void TabDeckStorage::actOpenLocalDeck()
|
||||||
continue;
|
continue;
|
||||||
QString filePath = localDirModel->filePath(curLeft);
|
QString filePath = localDirModel->filePath(curLeft);
|
||||||
|
|
||||||
auto deckLoader = new DeckLoader(this);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true);
|
||||||
if (!deckLoader->loadFromFile(filePath, DeckFileFormat::Cockatrice, true))
|
if (!deckOpt)
|
||||||
continue;
|
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);
|
QFile deckFile(filePath);
|
||||||
QFileInfo deckFileInfo(deckFile);
|
QFileInfo deckFileInfo(deckFile);
|
||||||
|
|
||||||
DeckLoader deckLoader(this);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromFile(filePath, DeckFileFormat::Cockatrice, true);
|
||||||
if (!deckLoader.loadFromFile(filePath, DeckFileFormat::Cockatrice)) {
|
if (!deckOpt) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Invalid deck file"));
|
QMessageBox::critical(this, tr("Error"), tr("Invalid deck file"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckList deck = deckLoader.getDeck().deckList;
|
DeckList deck = deckOpt.value().deckList;
|
||||||
|
|
||||||
if (deck.getName().isEmpty()) {
|
if (deck.getName().isEmpty()) {
|
||||||
bool ok;
|
bool ok;
|
||||||
|
|
@ -434,11 +434,11 @@ void TabDeckStorage::openRemoteDeckFinished(const Response &r, const CommandCont
|
||||||
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
||||||
const Command_DeckDownload &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDownload::ext);
|
const Command_DeckDownload &cmd = commandContainer.session_command(0).GetExtension(Command_DeckDownload::ext);
|
||||||
|
|
||||||
DeckLoader loader(this);
|
std::optional<LoadedDeck> deckOpt = DeckLoader::loadFromRemote(QString::fromStdString(resp.deck()), cmd.deck_id());
|
||||||
if (!loader.loadFromRemote(QString::fromStdString(resp.deck()), cmd.deck_id()))
|
if (!deckOpt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit openDeckEditor(loader.getDeck());
|
emit openDeckEditor(deckOpt.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabDeckStorage::actDownload()
|
void TabDeckStorage::actDownload()
|
||||||
|
|
@ -496,10 +496,7 @@ void TabDeckStorage::downloadFinished(const Response &r,
|
||||||
|
|
||||||
DeckList deckList = DeckList(QString::fromStdString(resp.deck()));
|
DeckList deckList = DeckList(QString::fromStdString(resp.deck()));
|
||||||
|
|
||||||
DeckLoader deckLoader(this);
|
DeckLoader::saveToFile(deckList, filePath, DeckFileFormat::Cockatrice);
|
||||||
deckLoader.setDeck({deckList, {}});
|
|
||||||
|
|
||||||
deckLoader.saveToFile(filePath, DeckFileFormat::Cockatrice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabDeckStorage::actNewFolder()
|
void TabDeckStorage::actNewFolder()
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ TabDeckStorageVisual::TabDeckStorageVisual(TabSupervisor *_tabSupervisor)
|
||||||
|
|
||||||
void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath)
|
void TabDeckStorageVisual::actOpenLocalDeck(const QString &filePath)
|
||||||
{
|
{
|
||||||
auto deckLoader = DeckLoader(this);
|
std::optional<LoadedDeck> deckOpt =
|
||||||
if (!deckLoader.loadFromFile(filePath, DeckFileFormat::getFormatFromName(filePath), true)) {
|
DeckLoader::loadFromFile(filePath, DeckFileFormat::getFormatFromName(filePath), true);
|
||||||
|
if (!deckOpt) {
|
||||||
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.getDeck());
|
emit openDeckEditor(deckOpt.value());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,10 +77,10 @@ static QStringList findAllKnownTags()
|
||||||
QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath());
|
QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath());
|
||||||
|
|
||||||
QStringList knownTags;
|
QStringList knownTags;
|
||||||
auto loader = DeckLoader(nullptr);
|
|
||||||
for (const QString &file : allFiles) {
|
for (const QString &file : allFiles) {
|
||||||
loader.loadFromFile(file, DeckFileFormat::getFormatFromName(file), false);
|
std::optional<LoadedDeck> deckOpt =
|
||||||
QStringList tags = loader.getDeck().deckList.getTags();
|
DeckLoader::loadFromFile(file, DeckFileFormat::getFormatFromName(file), false);
|
||||||
|
QStringList tags = deckOpt.has_value() ? deckOpt->deckList.getTags() : QStringList();
|
||||||
knownTags.append(tags);
|
knownTags.append(tags);
|
||||||
knownTags.removeDuplicates();
|
knownTags.removeDuplicates();
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ static bool confirmOverwriteIfExists(QWidget *parent, const QString &filePath)
|
||||||
|
|
||||||
static void convertFileToCockatriceFormat(DeckPreviewWidget *deckPreviewWidget)
|
static void convertFileToCockatriceFormat(DeckPreviewWidget *deckPreviewWidget)
|
||||||
{
|
{
|
||||||
deckPreviewWidget->deckLoader->convertToCockatriceFormat(deckPreviewWidget->filePath);
|
DeckLoader::convertToCockatriceFormat(deckPreviewWidget->deckLoader->getDeck());
|
||||||
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getDeck().lastLoadInfo.fileName;
|
deckPreviewWidget->filePath = deckPreviewWidget->deckLoader->getDeck().lastLoadInfo.fileName;
|
||||||
deckPreviewWidget->refreshBannerCardText();
|
deckPreviewWidget->refreshBannerCardText();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ void DeckPreviewWidget::setBannerCard(int /* changedIndex */)
|
||||||
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
||||||
CardRef cardRef = {name, id};
|
CardRef cardRef = {name, id};
|
||||||
deckLoader->getDeck().deckList.setBannerCard(cardRef);
|
deckLoader->getDeck().deckList.setBannerCard(cardRef);
|
||||||
deckLoader->saveToFile(filePath, DeckFileFormat::getFormatFromName(filePath));
|
DeckLoader::saveToFile(deckLoader->getDeck());
|
||||||
bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef));
|
bannerCardDisplayWidget->setCard(CardDatabaseManager::query()->getCard(cardRef));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -311,7 +311,7 @@ void DeckPreviewWidget::imageDoubleClickedEvent(QMouseEvent *event, DeckPreviewC
|
||||||
void DeckPreviewWidget::setTags(const QStringList &tags)
|
void DeckPreviewWidget::setTags(const QStringList &tags)
|
||||||
{
|
{
|
||||||
deckLoader->getDeck().deckList.setTags(tags);
|
deckLoader->getDeck().deckList.setTags(tags);
|
||||||
deckLoader->saveToFile(filePath, DeckFileFormat::Cockatrice);
|
DeckLoader::saveToFile(deckLoader->getDeck());
|
||||||
}
|
}
|
||||||
|
|
||||||
QMenu *DeckPreviewWidget::createRightClickMenu()
|
QMenu *DeckPreviewWidget::createRightClickMenu()
|
||||||
|
|
@ -386,7 +386,7 @@ void DeckPreviewWidget::actRenameDeck()
|
||||||
|
|
||||||
// write change
|
// write change
|
||||||
deckLoader->getDeck().deckList.setName(newName);
|
deckLoader->getDeck().deckList.setName(newName);
|
||||||
deckLoader->saveToFile(filePath, DeckFileFormat::getFormatFromName(filePath));
|
DeckLoader::saveToFile(deckLoader->getDeck());
|
||||||
|
|
||||||
// update VDS
|
// update VDS
|
||||||
refreshBannerCardText();
|
refreshBannerCardText();
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ bool DeckList::loadFromFile_Native(QIODevice *device)
|
||||||
return loadFromXml(&xml);
|
return loadFromXml(&xml);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckList::saveToFile_Native(QIODevice *device)
|
bool DeckList::saveToFile_Native(QIODevice *device) const
|
||||||
{
|
{
|
||||||
QXmlStreamWriter xml(device);
|
QXmlStreamWriter xml(device);
|
||||||
xml.setAutoFormatting(true);
|
xml.setAutoFormatting(true);
|
||||||
|
|
@ -393,7 +393,7 @@ bool DeckList::loadFromFile_Plain(QIODevice *device)
|
||||||
return loadFromStream_Plain(in, false);
|
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) {
|
auto writeToStream = [&stream, prefixSideboardCards, slashTappedOutSplitCards](const auto node, const auto card) {
|
||||||
if (prefixSideboardCards && node->getName() == DECK_ZONE_SIDE) {
|
if (prefixSideboardCards && node->getName() == DECK_ZONE_SIDE) {
|
||||||
|
|
@ -410,13 +410,13 @@ bool DeckList::saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards
|
||||||
return true;
|
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);
|
QTextStream out(device);
|
||||||
return saveToStream_Plain(out, prefixSideboardCards, slashTappedOutSplitCards);
|
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;
|
QString result;
|
||||||
QTextStream out(&result);
|
QTextStream out(&result);
|
||||||
|
|
|
||||||
|
|
@ -201,16 +201,17 @@ public:
|
||||||
bool loadFromString_Native(const QString &nativeString);
|
bool loadFromString_Native(const QString &nativeString);
|
||||||
QString writeToString_Native() const;
|
QString writeToString_Native() const;
|
||||||
bool loadFromFile_Native(QIODevice *device);
|
bool loadFromFile_Native(QIODevice *device);
|
||||||
bool saveToFile_Native(QIODevice *device);
|
bool saveToFile_Native(QIODevice *device) const;
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/// @name Serialization (Plain text)
|
/// @name Serialization (Plain text)
|
||||||
///@{
|
///@{
|
||||||
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
bool loadFromStream_Plain(QTextStream &stream, bool preserveMetadata);
|
||||||
bool loadFromFile_Plain(QIODevice *device);
|
bool loadFromFile_Plain(QIODevice *device);
|
||||||
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
|
bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards) const;
|
||||||
bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
bool
|
||||||
QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
|
saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const;
|
||||||
|
QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false) const;
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
/// @name Deck manipulation
|
/// @name Deck manipulation
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue