/* Copyright (C) 2012 Sebastian Herbord. All rights reserved. This file is part of Mod Organizer. Mod Organizer is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Mod Organizer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see . */ #include "transfersavesdialog.h" #include "iplugingame.h" #include "isavegame.h" #include "savegameinfo.h" #include "ui_transfersavesdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace MOBase; using namespace MOShared; TransferSavesDialog::TransferSavesDialog(const Profile& profile, IPluginGame const* gamePlugin, QWidget* parent) : TutorableDialog("TransferSaves", parent), ui(new Ui::TransferSavesDialog), m_Profile(profile), m_GamePlugin(gamePlugin) { ui->setupUi(this); ui->label_2->setText(tr("Characters for profile %1").arg(m_Profile.name())); refreshGlobalSaves(); refreshLocalSaves(); refreshGlobalCharacters(); refreshLocalCharacters(); } TransferSavesDialog::~TransferSavesDialog() { delete ui; } void TransferSavesDialog::refreshGlobalSaves() { refreshSaves(m_GlobalSaves, m_GamePlugin->savesDirectory().absolutePath()); } void TransferSavesDialog::refreshLocalSaves() { refreshSaves(m_LocalSaves, m_Profile.savePath()); } void TransferSavesDialog::refreshGlobalCharacters() { refreshCharacters(m_GlobalSaves, ui->globalCharacterList, ui->copyToLocalBtn, ui->moveToLocalBtn); } void TransferSavesDialog::refreshLocalCharacters() { refreshCharacters(m_LocalSaves, ui->localCharacterList, ui->copyToGlobalBtn, ui->moveToGlobalBtn); } bool TransferSavesDialog::testOverwrite(OverwriteMode& overwriteMode, const QString& destinationFile) { QMessageBox::StandardButton res = overwriteMode == OVERWRITE_YES ? QMessageBox::Yes : QMessageBox::No; if (overwriteMode == OVERWRITE_ASK) { res = QMessageBox::question(this, tr("Overwrite"), tr("Overwrite the file \"%1\"").arg(destinationFile), QMessageBox::Yes | QMessageBox::No | QMessageBox::YesToAll | QMessageBox::NoToAll); if (res == QMessageBox::YesToAll) { overwriteMode = OVERWRITE_YES; res = QMessageBox::Yes; } else if (res == QMessageBox::NoToAll) { overwriteMode = OVERWRITE_NO; res = QMessageBox::No; } } return res == QMessageBox::Yes; } #define MOVE_SAVES "Move all save games of character \"%1\"" #define COPY_SAVES "Copy all save games of character \"%1\"" #define TO_PROFILE "to the profile?" #define TO_GLOBAL \ "to the global location? Please be aware that this will mess up the running number " \ "of save games." void TransferSavesDialog::on_moveToLocalBtn_clicked() { QString character = ui->globalCharacterList->currentItem()->text(); if (transferCharacters( character, MOVE_SAVES TO_PROFILE, m_GamePlugin->savesDirectory(), m_GlobalSaves[character], m_Profile.savePath(), [this](const QString& source, const QString& destination) -> bool { return shellMove(source, destination, this); }, "Failed to move {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); refreshLocalSaves(); refreshLocalCharacters(); } } void TransferSavesDialog::on_copyToLocalBtn_clicked() { QString character = ui->globalCharacterList->currentItem()->text(); if (transferCharacters( character, COPY_SAVES TO_PROFILE, m_GamePlugin->savesDirectory(), m_GlobalSaves[character], m_Profile.savePath(), [this](const QString& source, const QString& destination) -> bool { return shellCopy(source, destination, this); }, "Failed to copy {} to {}")) { refreshLocalSaves(); refreshLocalCharacters(); } } void TransferSavesDialog::on_moveToGlobalBtn_clicked() { QString character = ui->localCharacterList->currentItem()->text(); if (transferCharacters( character, MOVE_SAVES TO_GLOBAL, m_Profile.savePath(), m_LocalSaves[character], m_GamePlugin->savesDirectory().absolutePath(), [this](const QString& source, const QString& destination) -> bool { return shellMove(source, destination, this); }, "Failed to move {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); refreshLocalSaves(); refreshLocalCharacters(); } } void TransferSavesDialog::on_copyToGlobalBtn_clicked() { QString character = ui->localCharacterList->currentItem()->text(); if (transferCharacters( character, COPY_SAVES TO_GLOBAL, m_Profile.savePath(), m_LocalSaves[character], m_GamePlugin->savesDirectory().absolutePath(), [this](const QString& source, const QString& destination) -> bool { return shellCopy(source, destination, this); }, "Failed to copy {} to {}")) { refreshGlobalSaves(); refreshGlobalCharacters(); } } void TransferSavesDialog::on_doneButton_clicked() { close(); } void TransferSavesDialog::on_globalCharacterList_currentTextChanged( const QString& currentText) { ui->globalSavesList->clear(); // sadly this can get called while we're resetting the list, with an invalid // name, so we have to check. SaveCollection::const_iterator saveList = m_GlobalSaves.find(currentText); if (saveList != m_GlobalSaves.end()) { for (SaveListItem const& save : saveList->second) { ui->globalSavesList->addItem(QFileInfo(save->getFilepath()).fileName()); } } } void TransferSavesDialog::on_localCharacterList_currentTextChanged( const QString& currentText) { ui->localSavesList->clear(); // sadly this can get called while we're resetting the list, with an invalid // name, so we have to check. SaveCollection::const_iterator saveList = m_LocalSaves.find(currentText); if (saveList != m_LocalSaves.end()) { for (SaveListItem const& save : saveList->second) { ui->localSavesList->addItem(QFileInfo(save->getFilepath()).fileName()); } } } void TransferSavesDialog::refreshSaves(SaveCollection& saveCollection, QString const& savedir) { saveCollection.clear(); auto saves = m_GamePlugin->listSaves(savedir); std::sort(saves.begin(), saves.end(), [](auto const& lhs, auto const& rhs) { return lhs->getCreationTime() > rhs->getCreationTime(); }); for (auto& save : saves) { saveCollection[save->getSaveGroupIdentifier()].push_back(save); } } void TransferSavesDialog::refreshCharacters(const SaveCollection& saveCollection, QListWidget* charList, QPushButton* copy, QPushButton* move) { charList->clear(); for (SaveCollection::value_type const& val : saveCollection) { charList->addItem(val.first); } if (charList->count() > 0) { charList->setCurrentRow(0); copy->setEnabled(true); move->setEnabled(true); } else { copy->setEnabled(false); move->setEnabled(false); } } bool TransferSavesDialog::transferCharacters( QString const& character, char const* message, QDir const& sourceDirectory, SaveList& saves, QDir const& destination, const std::function& method, std::format_string errmsg) { if (QMessageBox::question(this, tr("Confirm"), tr(message).arg(character), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { return false; } OverwriteMode overwriteMode = OVERWRITE_ASK; for (SaveListItem const& save : saves) { for (QString source : save->allFiles()) { QFileInfo sourceFile(source); QString destinationFile( destination.absoluteFilePath(sourceDirectory.relativeFilePath(source))); // If the file is already there, let them skip (or not). if (QFile::exists(destinationFile)) { if (!testOverwrite(overwriteMode, destinationFile)) { continue; } // OK, they want to remove it. QFile::remove(destinationFile); } if (!method(sourceFile.absoluteFilePath(), destinationFile)) { log::error(errmsg, sourceFile.absoluteFilePath(), std::move(destinationFile)); } } } return true; }