From 4f8c71d62626aa61fb4d13f80bc043d5e6492c3e Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 12 Feb 2016 19:08:25 +0100 Subject: merged master into new_vfs_library --- src/CMakeLists.txt | 21 -- src/aboutdialog.cpp | 8 + src/aboutdialog.h | 7 +- src/activatemodsdialog.cpp | 22 +- src/activatemodsdialog.h | 10 +- src/iuserinterface.h | 1 + src/mainwindow.cpp | 299 ++++++++++++--------------- src/mainwindow.h | 111 ++++++---- src/modinfo.h | 1 - src/nexusinterface.cpp | 2 +- src/organizer.pro | 9 - src/organizercore.cpp | 36 +++- src/organizercore.h | 28 ++- src/organizerproxy.cpp | 13 +- src/organizerproxy.h | 6 +- src/profile.cpp | 36 +++- src/profile.h | 19 +- src/profilesdialog.cpp | 23 ++- src/profilesdialog.h | 15 +- src/savegame.cpp | 69 ------- src/savegameinfowidget.cpp | 65 ------ src/savegameinfowidget.h | 61 ------ src/savegameinfowidget.ui | 209 ------------------- src/savegameinfowidgetgamebryo.cpp | 80 -------- src/savegameinfowidgetgamebryo.h | 44 ---- src/selfupdater.cpp | 29 ++- src/selfupdater.h | 19 +- src/shared/shared.pro | 10 - src/transfersavesdialog.cpp | 411 +++++++++++++++++++------------------ src/transfersavesdialog.h | 33 ++- 30 files changed, 649 insertions(+), 1048 deletions(-) delete mode 100644 src/savegame.cpp delete mode 100644 src/savegameinfowidget.cpp delete mode 100644 src/savegameinfowidget.h delete mode 100644 src/savegameinfowidget.ui delete mode 100644 src/savegameinfowidgetgamebryo.cpp delete mode 100644 src/savegameinfowidgetgamebryo.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4cd16f04..6eec86a9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,10 +18,6 @@ SET(organizer_SRCS settings.cpp selfupdater.cpp selectiondialog.cpp - savegameinfowidgetgamebryo.cpp - savegameinfowidget.cpp - savegamegamebryo.cpp - savegame.cpp queryoverwritedialog.cpp profilesdialog.cpp profile.cpp @@ -94,13 +90,7 @@ SET(organizer_SRCS shared/windows_error.cpp shared/error_report.cpp shared/directoryentry.cpp - shared/gameinfo.cpp - shared/oblivioninfo.cpp - shared/fallout3info.cpp - shared/fallout4info.cpp - shared/falloutnvinfo.cpp shared/util.cpp - shared/skyriminfo.cpp shared/appconfig.cpp shared/leaktrace.cpp shared/stackdata.cpp @@ -115,10 +105,6 @@ SET(organizer_HDRS settings.h selfupdater.h selectiondialog.h - savegameinfowidgetgamebryo.h - savegameinfowidget.h - savegamegamebyro.h - savegame.h queryoverwritedialog.h profilesdialog.h profile.h @@ -191,13 +177,7 @@ SET(organizer_HDRS shared/windows_error.h shared/error_report.h shared/directoryentry.h - shared/gameinfo.h - shared/oblivioninfo.h - shared/fallout3info.h - shared/fallout4info.h - shared/falloutnvinfo.h shared/util.h - shared/skyriminfo.h shared/appconfig.h shared/appconfig.inc shared/leaktrace.h @@ -210,7 +190,6 @@ SET(organizer_UIS simpleinstalldialog.ui settingsdialog.ui selectiondialog.ui - savegameinfowidget.ui queryoverwritedialog.ui profilesdialog.ui overwriteinfodialog.ui diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index 6fce2acb..3657a10d 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -22,6 +22,14 @@ along with Mod Organizer. If not, see . #include "ui_aboutdialog.h" #include +#include +#include +#include +#include +#include +#include +#include + AboutDialog::AboutDialog(const QString &version, QWidget *parent) : QDialog(parent) diff --git a/src/aboutdialog.h b/src/aboutdialog.h index c3b38c10..103a0d2f 100644 --- a/src/aboutdialog.h +++ b/src/aboutdialog.h @@ -22,10 +22,11 @@ along with Mod Organizer. If not, see . #define ABOUTDIALOG_H #include -#include +class QListWidgetItem; +#include +#include + #include -#include -#include namespace Ui { class AboutDialog; diff --git a/src/activatemodsdialog.cpp b/src/activatemodsdialog.cpp index fd56ae3e..5ef0a4e5 100644 --- a/src/activatemodsdialog.cpp +++ b/src/activatemodsdialog.cpp @@ -21,9 +21,14 @@ along with Mod Organizer. If not, see . #include "ui_activatemodsdialog.h" #include +#include #include +#include +#include -ActivateModsDialog::ActivateModsDialog(const std::map > &missingPlugins, QWidget *parent) +#include + +ActivateModsDialog::ActivateModsDialog(SaveGameInfo::MissingAssets const &missingAssets, QWidget *parent) : TutorableDialog("ActivateMods", parent), ui(new Ui::ActivateModsDialog) { ui->setupUi(this); @@ -40,18 +45,17 @@ ActivateModsDialog::ActivateModsDialog(const std::mapsetRowCount(missingPlugins.size()); + modsTable->setRowCount(missingAssets.size()); - for (std::map >::const_iterator espIter = missingPlugins.begin(); - espIter != missingPlugins.end(); ++espIter, ++row) { - modsTable->setCellWidget(row, 0, new QLabel(espIter->first)); - if (espIter->second.size() == 0) { + for (SaveGameInfo::MissingAssets::const_iterator espIter = missingAssets.begin(); + espIter != missingAssets.end(); ++espIter, ++row) { + modsTable->setCellWidget(row, 0, new QLabel(espIter.key())); + if (espIter->size() == 0) { modsTable->setCellWidget(row, 1, new QLabel(tr("not found"))); } else { QComboBox* combo = new QComboBox(); - for (std::vector::const_iterator modIter = espIter->second.begin(); - modIter != espIter->second.end(); ++modIter) { - combo->addItem(*modIter); + for (QString const &mod : espIter.value()) { + combo->addItem(mod); } modsTable->setCellWidget(row, 1, combo); } diff --git a/src/activatemodsdialog.h b/src/activatemodsdialog.h index 08dbad8d..f36b5fde 100644 --- a/src/activatemodsdialog.h +++ b/src/activatemodsdialog.h @@ -20,8 +20,14 @@ along with Mod Organizer. If not, see . #ifndef ACTIVATEMODSDIALOG_H #define ACTIVATEMODSDIALOG_H +#include "savegameinfo.h" #include "tutorabledialog.h" -#include + +#include + +class QString; +class QWidget; + #include namespace Ui { @@ -42,7 +48,7 @@ public: * @param missingPlugins a map containing missing plugins that need to be activated * @param parent ... Defaults to 0. **/ - explicit ActivateModsDialog(const std::map > &missingPlugins, QWidget *parent = 0); + explicit ActivateModsDialog(SaveGameInfo::MissingAssets const &missingAssets, QWidget *parent = 0); ~ActivateModsDialog(); /** diff --git a/src/iuserinterface.h b/src/iuserinterface.h index e6b39ee1..19e58c75 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -7,6 +7,7 @@ #include #include +class QSettings; class IUserInterface { diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c242bfe6..db7bd682 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -20,7 +20,24 @@ along with Mod Organizer. If not, see . #include "mainwindow.h" #include "ui_mainwindow.h" +#include "directoryentry.h" +#include "directoryrefresher.h" +#include "executableinfo.h" +#include "executableslist.h" +#include "guessedvalue.h" +#include "imodinterface.h" +#include "iplugingame.h" +#include "iplugindiagnose.h" +#include "isavegame.h" +#include "isavegameinfowidget.h" +#include "nexusinterface.h" +#include "organizercore.h" +#include "pluginlistsortproxy.h" +#include "previewgenerator.h" +#include "savegameinfo.h" #include "spawn.h" +#include "versioninfo.h" + #include "report.h" #include "modlist.h" #include "modlistsortproxy.h" @@ -31,7 +48,6 @@ along with Mod Organizer. If not, see . #include "editexecutablesdialog.h" #include "categories.h" #include "categoriesdialog.h" -#include "utility.h" #include "modinfodialog.h" #include "overwriteinfodialog.h" #include "activatemodsdialog.h" @@ -41,16 +57,13 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include "installationmanager.h" #include "lockeddialog.h" -#include "syncoverwritedialog.h" #include "logbuffer.h" #include "downloadlistsortproxy.h" #include "motddialog.h" #include "filedialogmemory.h" -#include "questionboxmemory.h" #include "tutorialmanager.h" #include "modflagicondelegate.h" #include "genericicondelegate.h" -#include "credentialsdialog.h" #include "selectiondialog.h" #include "csvbuilder.h" #include "savetextasdialog.h" @@ -59,62 +72,86 @@ along with Mod Organizer. If not, see . #include "browserdialog.h" #include "aboutdialog.h" #include "safewritefile.h" -//? -//#include "isavegame.h" -//#include "savegameinfo.h" -//? #include "nxmaccessmanager.h" -#include -#include +#include "appconfig.h" #include -#include #include #include -#include #include -#include #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) #include #else #include #endif -#include -#include #ifndef Q_MOC_RUN #include @@ -123,18 +160,16 @@ along with Mod Organizer. If not, see . #include #endif -#include #include -#include -#include -#include -#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include +#include #ifdef TEST_MODELS #include "modeltest.h" @@ -826,37 +861,24 @@ void MainWindow::setBrowserGeometry(const QByteArray &geometry) m_IntegratedBrowser.restoreGeometry(geometry); } - -SaveGameGamebryo *MainWindow::getSaveGame(const QString &name) -{ - IPluginGame const *game = m_OrganizerCore.managedGame(); - return new SaveGameGamebryo(this, name, game); -} - - -SaveGameGamebryo *MainWindow::getSaveGame(QListWidgetItem *item) -{ - try { - SaveGameGamebryo *saveGame = getSaveGame(item->data(Qt::UserRole).toString()); - saveGame->setParent(item->listWidget()); - return saveGame; - } catch (const std::exception &e) { - reportError(tr("failed to read savegame: %1").arg(e.what())); - return nullptr; - } -} - - -void MainWindow::displaySaveGameInfo(const SaveGameGamebryo *save, QPoint pos) +void MainWindow::displaySaveGameInfo(QListWidgetItem *newItem) { + QString const &save = newItem->data(Qt::UserRole).toString(); if (m_CurrentSaveView == nullptr) { - m_CurrentSaveView = new SaveGameInfoWidgetGamebryo(save, m_OrganizerCore.pluginList(), this); - } else { - m_CurrentSaveView->setSave(save); + IPluginGame const *game = m_OrganizerCore.managedGame(); + SaveGameInfo const *info = game->feature(); + if (info != nullptr) { + m_CurrentSaveView = info->getSaveGameWidget(this); + } + if (m_CurrentSaveView == nullptr) { + return; + } } + m_CurrentSaveView->setSave(save); QRect screenRect = QApplication::desktop()->availableGeometry(m_CurrentSaveView); + QPoint pos = QCursor::pos(); if (pos.x() + m_CurrentSaveView->width() > screenRect.right()) { pos.rx() -= (m_CurrentSaveView->width() + 2); } else { @@ -871,8 +893,9 @@ void MainWindow::displaySaveGameInfo(const SaveGameGamebryo *save, QPoint pos) m_CurrentSaveView->move(pos); m_CurrentSaveView->show(); + m_CurrentSaveView->setProperty("displayItem", qVariantFromValue(static_cast(newItem))); + ui->savegameList->activateWindow(); - connect(m_CurrentSaveView, SIGNAL(closeSaveInfo()), this, SLOT(hideSaveGameInfo())); } @@ -880,21 +903,15 @@ void MainWindow::saveSelectionChanged(QListWidgetItem *newItem) { if (newItem == nullptr) { hideSaveGameInfo(); - } else if ((m_CurrentSaveView == nullptr) || (newItem != m_CurrentSaveView->property("displayItem").value())) { - const SaveGameGamebryo *save = getSaveGame(newItem); - if (save != nullptr) { - displaySaveGameInfo(save, QCursor::pos()); - m_CurrentSaveView->setProperty("displayItem", qVariantFromValue((void*)newItem)); - } + } else if (m_CurrentSaveView == nullptr || newItem != m_CurrentSaveView->property("displayItem").value()) { + displaySaveGameInfo(newItem); } } - void MainWindow::hideSaveGameInfo() { if (m_CurrentSaveView != nullptr) { - disconnect(m_CurrentSaveView, SIGNAL(closeSaveInfo()), this, SLOT(hideSaveGameInfo())); m_CurrentSaveView->deleteLater(); m_CurrentSaveView = nullptr; } @@ -1258,7 +1275,7 @@ QDir MainWindow::currentSavesDir() const { QDir savesDir; if (m_OrganizerCore.currentProfile()->localSavesEnabled()) { - savesDir.setPath(m_OrganizerCore.currentProfile()->absolutePath() + "/saves"); + savesDir.setPath(m_OrganizerCore.currentProfile()->savePath()); } else { wchar_t path[MAX_PATH]; ::GetPrivateProfileStringW( @@ -3002,109 +3019,47 @@ void MainWindow::on_categoriesList_itemSelectionChanged() void MainWindow::deleteSavegame_clicked() { - QModelIndexList selectedIndexes = ui->savegameList->selectionModel()->selectedIndexes(); + SaveGameInfo const *info = m_OrganizerCore.managedGame()->feature(); QString savesMsgLabel; QStringList deleteFiles; int count = 0; - for (const QModelIndex &idx : selectedIndexes) { - QString name = idx.data().toString(); - SaveGame *save = new SaveGame(this, idx.data(Qt::UserRole).toString(), m_OrganizerCore.managedGame()); + for (const QModelIndex &idx : ui->savegameList->selectionModel()->selectedIndexes()) { + QString name = idx.data(Qt::UserRole).toString(); if (count < 10) { savesMsgLabel += "
  • " + QFileInfo(name).completeBaseName() + "
  • "; } ++count; - deleteFiles << save->saveFiles(); + if (info == nullptr) { + deleteFiles.push_back(name); + } else { + ISaveGame const *save = info->getSaveGameInfo(name); + deleteFiles += save->allFiles(); + } } if (count > 10) { savesMsgLabel += "
  • ... " + tr("%1 more").arg(count - 10) + "
  • "; } - if (QMessageBox::question(this, tr("Confirm"), tr("Are you sure you want to remove the following %n save(s)?
      %1

    Removed saves will be sent to the Recycle Bin.", "", selectedIndexes.count()) - .arg(savesMsgLabel), + if (QMessageBox::question(this, tr("Confirm"), + tr("Are you sure you want to remove the following %n save(s)?
    " + "
      %1

    " + "Removed saves will be sent to the Recycle Bin.", "", count) + .arg(savesMsgLabel), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { shellDelete(deleteFiles, true); // recycle bin delete. } } -void MainWindow::fixMods_clicked() +void MainWindow::fixMods_clicked(SaveGameInfo::MissingAssets const &missingAssets) { - QListWidgetItem *selectedItem = ui->savegameList->currentItem(); - - if (selectedItem == nullptr) - return; - - // if required, parse the save game - if (selectedItem->data(Qt::UserRole).isNull()) { - QVariant temp; - SaveGameGamebryo *save = getSaveGame(selectedItem->data(Qt::UserRole).toString()); - save->setParent(selectedItem->listWidget()); - temp.setValue(save); - selectedItem->setData(Qt::UserRole, temp); - } - - const SaveGameGamebryo *save = getSaveGame(selectedItem); - - // collect the list of missing plugins - std::map > missingPlugins; - - for (int i = 0; i < save->numPlugins(); ++i) { - const QString &pluginName = save->plugin(i); - if (!m_OrganizerCore.pluginList()->isEnabled(pluginName)) { - missingPlugins[pluginName] = std::vector(); - } - } - - // figure out, for each esp/esm, which mod, if any, contains it - QStringList espFilter("*.esp"); - espFilter.append("*.esm"); - - // search in data - { - QDir dataDir(m_OrganizerCore.managedGame()->dataDirectory()); - QStringList esps = dataDir.entryList(espFilter); - for (const QString &esp : esps) { - std::map >::iterator iter = missingPlugins.find(esp); - if (iter != missingPlugins.end()) { - iter->second.push_back(""); - } - } - } - - // search in mods - for (unsigned int i = 0; i < m_OrganizerCore.currentProfile()->numRegularMods(); ++i) { - int modIndex = m_OrganizerCore.currentProfile()->modIndexByPriority(i); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - - QStringList esps = QDir(modInfo->absolutePath()).entryList(espFilter); - for (const QString &esp : esps) { - std::map >::iterator iter = missingPlugins.find(esp); - if (iter != missingPlugins.end()) { - iter->second.push_back(modInfo->name()); - } - } - } - - // search in overwrite - { - QDir overwriteDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); - QStringList esps = overwriteDir.entryList(espFilter); - for (const QString &esp : esps) { - std::map >::iterator iter = missingPlugins.find(esp); - if (iter != missingPlugins.end()) { - iter->second.push_back(""); - } - } - } - - - ActivateModsDialog dialog(missingPlugins, this); + ActivateModsDialog dialog(missingAssets, this); if (dialog.exec() == QDialog::Accepted) { // activate the required mods, then enable all esps std::set modsToActivate = dialog.getModsToActivate(); @@ -3131,13 +3086,25 @@ void MainWindow::on_savegameList_customContextMenuRequested(const QPoint &pos) { QItemSelectionModel *selection = ui->savegameList->selectionModel(); - if (!selection->hasSelection()) + if (!selection->hasSelection()) { return; + } QMenu menu; - - if (!(selection->selectedIndexes().count() > 1)) - menu.addAction(tr("Fix Mods..."), this, SLOT(fixMods_clicked())); + QAction *action = menu.addAction(tr("Enable Mods...")); + action->setEnabled(false); + + if (selection->selectedIndexes().count() == 1) { + SaveGameInfo const *info = this->m_OrganizerCore.managedGame()->feature(); + if (info != nullptr) { + QString save = ui->savegameList->currentItem()->data(Qt::UserRole).toString(); + SaveGameInfo::MissingAssets missing = info->getMissingAssets(save); + if (missing.size() != 0) { + connect(action, &QAction::triggered, this, [this, missing]{ fixMods_clicked(missing); }); + action->setEnabled(true); + } + } + } QString deleteMenuLabel = tr("Delete %n save(s)", "", selection->selectedIndexes().count()); diff --git a/src/mainwindow.h b/src/mainwindow.h index 636fb0a3..4e2e8e21 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -20,50 +20,83 @@ along with Mod Organizer. If not, see . #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "modlist.h" -#include "pluginlist.h" -#include "plugincontainer.h" -#define WIN32_LEAN_AND_MEAN -#include -#include -#include "directoryrefresher.h" -#include -#include "settings.h" -#include "downloadmanager.h" -#include "installationmanager.h" -#include "selfupdater.h" -#include "savegamegamebyro.h" -#include "modlistsortproxy.h" -#include "pluginlistsortproxy.h" -#include "tutorialcontrol.h" -#include "savegameinfowidgetgamebryo.h" -#include "previewgenerator.h" +#include "bsafolder.h" #include "browserdialog.h" +#include "delayedfilewriter.h" +#include "errorcodes.h" +#include "imoinfo.h" #include "iuserinterface.h" -#include -#include -#include +#include "modinfo.h" +#include "modlistsortproxy.h" +#include "savegameinfo.h" +#include "tutorialcontrol.h" + +//Note the commented headers here can be replaced with forward references, +//when I get round to cleaning up main.cpp +struct Executable; +class CategoryFactory; +class LockedDialog; +class OrganizerCore; +#include "plugincontainer.h" //class PluginContainer; +class PluginListSortProxy; +namespace BSA { class Archive; } +#include "iplugingame.h" //namespace MOBase { class IPluginGame; } +namespace MOBase { class IPluginModPage; } +namespace MOBase { class IPluginTool; } +namespace MOBase { class ISaveGame; } + +namespace MOShared { class DirectoryEntry; } + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class QAction; +class QAbstractItemModel; +class QDateTime; +class QEvent; +class QFile; +class QListWidgetItem; +class QMenu; +class QModelIndex; +class QPoint; +class QProgressBar; +class QProgressDialog; +class QTranslator; +class QTreeWidgetItem; +class QUrl; +class QSettings; +class QWidget; + #ifndef Q_MOC_RUN #include #endif +//Sigh - just for HANDLE +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include +#include + namespace Ui { class MainWindow; } -class LockedDialog; -class QToolButton; -class ModListSortProxy; -class ModListGroupCategoriesProxy; class MainWindow : public QMainWindow, public IUserInterface @@ -217,10 +250,7 @@ private: void setCategoryListVisible(bool visible); - SaveGameGamebryo *getSaveGame(const QString &name); - SaveGameGamebryo *getSaveGame(QListWidgetItem *item); - - void displaySaveGameInfo(const SaveGameGamebryo *save, QPoint pos); + void displaySaveGameInfo(QListWidgetItem *newItem); HANDLE nextChildProcess(); @@ -293,7 +323,8 @@ private: QTimer m_UpdateProblemsTimer; QTime m_StartTime; - SaveGameInfoWidget *m_CurrentSaveView; + //SaveGameInfoWidget *m_CurrentSaveView; + MOBase::ISaveGameInfoWidget *m_CurrentSaveView; OrganizerCore &m_OrganizerCore; PluginContainer &m_PluginContainer; @@ -352,7 +383,7 @@ private slots: void information_clicked(); // savegame context menu void deleteSavegame_clicked(); - void fixMods_clicked(); + void fixMods_clicked(SaveGameInfo::MissingAssets const &missingAssets); // data-tree context menu void writeDataToFile(); void openDataFile(); diff --git a/src/modinfo.h b/src/modinfo.h index ae22ccd8..c10232da 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -22,7 +22,6 @@ along with Mod Organizer. If not, see . #include "imodinterface.h" #include "versioninfo.h" -//#include class QDateTime; class QDir; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index f9d9b6bd..c689501f 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -193,7 +193,7 @@ void NexusInterface::loginCompleted() void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query) { //Look for something along the lines of modulename-Vn-m + any old rubbish. - static std::regex exp("^([a-zA-Z0-9_'\"\\-.() ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*\.(zip|rar|7z)"); + static std::regex exp("^([a-zA-Z0-9_'\"\\-.() ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*\\.(zip|rar|7z)"); static std::regex simpleexp("^([a-zA-Z0-9_]+)"); QByteArray fileNameUTF8 = fileName.toUtf8(); diff --git a/src/organizer.pro b/src/organizer.pro index 1284aa40..0ef2638b 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -27,10 +27,6 @@ SOURCES += \ settings.cpp \ selfupdater.cpp \ selectiondialog.cpp \ - savegameinfowidgetgamebryo.cpp \ - savegameinfowidget.cpp \ - savegamegamebryo.cpp \ - savegame.cpp \ queryoverwritedialog.cpp \ profilesdialog.cpp \ profile.cpp \ @@ -107,10 +103,6 @@ HEADERS += \ settings.h \ selfupdater.h \ selectiondialog.h \ - savegameinfowidgetgamebryo.h \ - savegameinfowidget.h \ - savegamegamebyro.h \ - savegame.h \ queryoverwritedialog.h \ profilesdialog.h \ profile.h \ @@ -183,7 +175,6 @@ FORMS += \ simpleinstalldialog.ui \ settingsdialog.ui \ selectiondialog.ui \ - savegameinfowidget.ui \ queryoverwritedialog.ui \ profilesdialog.ui \ overwriteinfodialog.ui \ diff --git a/src/organizercore.cpp b/src/organizercore.cpp index ecadfb5d..e50f1cd7 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1,15 +1,19 @@ #include "organizercore.h" +#include "imodinterface.h" #include "iplugingame.h" -#include "mainwindow.h" +#include "iuserinterface.h" +#include "loadmechanism.h" #include "messagedialog.h" +#include "modlistsortproxy.h" +#include "plugincontainer.h" +#include "pluginlistsortproxy.h" #include "logbuffer.h" #include "credentialsdialog.h" #include "filedialogmemory.h" #include "lockeddialog.h" #include "modinfodialog.h" #include "spawn.h" -#include "safewritefile.h" #include "syncoverwritedialog.h" #include "nxmaccessmanager.h" #include @@ -18,19 +22,29 @@ #include #include #include -#include +#include "appconfig.h" #include #include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include + +#include #include +#include #include #include +#include +#include +#include + using namespace MOShared; using namespace MOBase; @@ -953,6 +967,16 @@ ModList *OrganizerCore::modList() return &m_ModList; } +QStringList OrganizerCore::modsSortedByProfilePriority() const +{ + QStringList res; + for (unsigned int i = 0; i < currentProfile()->numRegularMods(); ++i) { + int modIndex = currentProfile()->modIndexByPriority(i); + res.push_back(ModInfo::getByIndex(modIndex)->name()); + } + return res; +} + void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &arguments, const QDir ¤tDirectory, diff --git a/src/organizercore.h b/src/organizercore.h index bf6c5a8b..ea37d72c 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -2,31 +2,44 @@ #define ORGANIZERCORE_H -#include "profile.h" #include "selfupdater.h" -#include "iuserinterface.h" +#include "iuserinterface.h" //should be class IUserInterface; #include "settings.h" #include "modlist.h" +#include "modinfo.h" #include "pluginlist.h" #include "directoryrefresher.h" #include "installationmanager.h" #include "downloadmanager.h" -#include "modlistsortproxy.h" -#include "pluginlistsortproxy.h" #include "executableslist.h" #include "usvfsconnector.h" #include #include #include -#include #include -#include #include #include + +class ModListSortProxy; +class PluginListSortProxy; +class Profile; +namespace MOBase { template class GuessedValue; } +namespace MOShared { class DirectoryEntry; } + +#include +#include +#include #include #include +#include #include +class QNetworkReply; +class QUrl; +class QWidget; + +#include +#include class PluginContainer; @@ -90,7 +103,7 @@ public: m_ExecutablesList = executablesList; } - Profile *currentProfile() { return m_CurrentProfile; } + Profile *currentProfile() const { return m_CurrentProfile; } void setCurrentProfile(const QString &profileName); std::vector enabledArchives(); @@ -158,6 +171,7 @@ public: bool onAboutToRun(const std::function &func); bool onFinishedRun(const std::function &func); void refreshModList(bool saveChanges = true); + QStringList modsSortedByProfilePriority() const; /** * @brief return a descriptor of the mappings real file->virtual file diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp index 79ff50e5..fe6809e3 100644 --- a/src/organizerproxy.cpp +++ b/src/organizerproxy.cpp @@ -1,6 +1,7 @@ #include "organizerproxy.h" -#include +#include "appconfig.h" +#include "organizercore.h" #include @@ -171,7 +172,17 @@ MOBase::IModList *OrganizerProxy::modList() const return m_Proxied->modList(); } +MOBase::IProfile *OrganizerProxy::profile() const +{ + return m_Proxied->currentProfile(); +} + MOBase::IPluginGame const *OrganizerProxy::managedGame() const { return m_Proxied->managedGame(); } + +QStringList OrganizerProxy::modsSortedByProfilePriority() const +{ + return m_Proxied->modsSortedByProfilePriority(); +} diff --git a/src/organizerproxy.h b/src/organizerproxy.h index 02507dd7..77600671 100644 --- a/src/organizerproxy.h +++ b/src/organizerproxy.h @@ -3,7 +3,8 @@ #include -#include "mainwindow.h" + +class OrganizerCore; class OrganizerProxy : public MOBase::IOrganizer { @@ -38,6 +39,7 @@ public: virtual MOBase::IDownloadManager *downloadManager() const; virtual MOBase::IPluginList *pluginList() const; virtual MOBase::IModList *modList() const; + virtual MOBase::IProfile *profile() const override; virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = ""); virtual bool waitForApplication(HANDLE handle, LPDWORD exitCode = nullptr) const; virtual void refreshModList(bool saveChanges); @@ -48,6 +50,8 @@ public: virtual MOBase::IPluginGame const *managedGame() const; + virtual QStringList modsSortedByProfilePriority() const; + private: OrganizerCore *m_Proxied; diff --git a/src/profile.cpp b/src/profile.cpp index 99a6bd90..f4aab46b 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -19,31 +19,41 @@ along with Mod Organizer. If not, see . #include "profile.h" -#include "windows_error.h" #include "modinfo.h" #include "safewritefile.h" #include "settings.h" #include -#include #include -#include +#include "appconfig.h" #include #include #include #include -#include #include -#include -#include +#include // for QFile +#include // for operator|, QFlags +#include // for QIODevice, etc +#include +#include +#include // for QStringList +#include // for qDebug, qWarning, etc +#include // for qPrintable + +#include +#include // for assert +#include // for UINT_MAX, INT_MAX, etc +#include // for size_t +#include // for wcslen + +#include // for max, min +#include // for exception #include +#include // for set +#include // for find #include -#define WIN32_LEAN_AND_MEAN -#include -#include - using namespace MOBase; using namespace MOShared; @@ -690,6 +700,12 @@ QString Profile::absolutePath() const return QDir::cleanPath(m_Directory.absolutePath()); } +QString Profile::savePath() const +{ + return QDir::cleanPath(m_Directory.absoluteFilePath("saves")); + +} + void Profile::rename(const QString &newName) { QDir profileDir(Settings::instance().getProfileDirectory()); diff --git a/src/profile.h b/src/profile.h index a7d71251..ece23ef9 100644 --- a/src/profile.h +++ b/src/profile.h @@ -25,12 +25,16 @@ along with Mod Organizer. If not, see . #include #include -#include +#include #include -#include +#include +#include -#include +#include + +#include #include +#include namespace MOBase { class IPluginGame; } @@ -172,6 +176,15 @@ public: **/ QString absolutePath() const; + /** + * @return path to this profile's save games + **/ + QString savePath() const; + + /** + * @brief rename profile + * @param newName new name of profile + */ void rename(const QString &newName); /** diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp index 49fbda4e..1a47cf74 100644 --- a/src/profilesdialog.cpp +++ b/src/profilesdialog.cpp @@ -19,23 +19,28 @@ along with Mod Organizer. If not, see . #include "profilesdialog.h" #include "ui_profilesdialog.h" + +#include "appconfig.h" +#include "bsainvalidation.h" +#include "iplugingame.h" +#include "profile.h" +#include "profileinputdialog.h" #include "report.h" -#include "utility.h" #include "transfersavesdialog.h" -#include "profileinputdialog.h" -#include "mainwindow.h" -#include "aboutdialog.h" +#include "utility.h" #include "settings.h" -#include -#include -#include -#include + +#include +#include #include #include -#include +#include #include #include +#include + +#include using namespace MOBase; using namespace MOShared; diff --git a/src/profilesdialog.h b/src/profilesdialog.h index 073d92b7..0e79b94b 100644 --- a/src/profilesdialog.h +++ b/src/profilesdialog.h @@ -21,17 +21,16 @@ along with Mod Organizer. If not, see . #define PROFILESDIALOG_H #include "tutorabledialog.h" -#include -#include "profile.h" +class Profile; +class QListWidget; +class QListWidgetItem; +#include +class QString; -namespace Ui { - class ProfilesDialog; -} +namespace Ui { class ProfilesDialog; } -namespace MOBase { - class IPluginGame; -} +namespace MOBase { class IPluginGame; } /** diff --git a/src/savegame.cpp b/src/savegame.cpp deleted file mode 100644 index 2b125575..00000000 --- a/src/savegame.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -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 "savegame.h" - -#include "iplugingame.h" -#include "scriptextender.h" -#include "utility.h" - -#include -#include -#include -#include - -#include -#include - -using namespace MOBase; - -SaveGame::SaveGame(QObject *parent, const QString &filename, const MOBase::IPluginGame *game) - : QObject(parent) - , m_FileName(filename) - , m_Game(game) -{ -} - -SaveGame::~SaveGame() -{ -} - -QStringList SaveGame::attachedFiles() const -{ - QStringList result; - ScriptExtender const *extender = m_Game->feature(); - if (extender != nullptr) { - for (QString const &ext : extender->saveGameAttachmentExtensions()) { - QFileInfo fi(fileName()); - fi.setFile(fi.canonicalPath() + "/" + fi.completeBaseName() + "." + ext); - if (fi.exists()) { - result.append(fi.filePath()); - } - } - } - - return result; -} - -QStringList SaveGame::saveFiles() const -{ - QStringList result = attachedFiles(); - result.append(fileName()); - return result; -} diff --git a/src/savegameinfowidget.cpp b/src/savegameinfowidget.cpp deleted file mode 100644 index 63eefb93..00000000 --- a/src/savegameinfowidget.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* -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 "savegameinfowidget.h" -#include "ui_savegameinfowidget.h" -#include "utility.h" -#include "savegame.h" -#include - - -SaveGameInfoWidget::SaveGameInfoWidget(QWidget *parent) - : QWidget(parent) - , ui(new Ui::SaveGameInfoWidget) -{ - ui->setupUi(this); - this->setWindowFlags(Qt::ToolTip | Qt::BypassGraphicsProxyWidget); - setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / qreal(255.0)); - ui->gameFrame->setStyleSheet("background-color: transparent;"); -// installEventFilter(this); -} - -SaveGameInfoWidget::~SaveGameInfoWidget() -{ - delete ui; -} - - -void SaveGameInfoWidget::setSave(const SaveGame *saveGame) -{ - ui->saveNumLabel->setText(QString("%1").arg(saveGame->saveNumber())); - ui->characterLabel->setText(saveGame->pcName()); - ui->locationLabel->setText(saveGame->pcLocation()); - ui->levelLabel->setText(QString("%1").arg(saveGame->pcLevel())); - ui->dateLabel->setText(MOBase::ToString(saveGame->creationTime())); - ui->screenshotLabel->setPixmap(QPixmap::fromImage(saveGame->screenshot())); - if (ui->gameFrame->layout() != nullptr) { - QLayoutItem *item = nullptr; - while ((item = ui->gameFrame->layout()->takeAt(0)) != nullptr) { - delete item->widget(); - delete item; - } - ui->gameFrame->layout()->setSizeConstraint(QLayout::SetFixedSize); - } -} - -QFrame *SaveGameInfoWidget::getGameFrame() -{ - return ui->gameFrame; -} diff --git a/src/savegameinfowidget.h b/src/savegameinfowidget.h deleted file mode 100644 index dfb0f8b1..00000000 --- a/src/savegameinfowidget.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -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 . -*/ - -#ifndef SAVEGAMEINFOWIDGET_H -#define SAVEGAMEINFOWIDGET_H - -#include -#include - -namespace Ui { -class SaveGameInfoWidget; -} - -class SaveGame; - -class SaveGameInfoWidget : public QWidget -{ - Q_OBJECT - -public: - - explicit SaveGameInfoWidget(QWidget *parent = 0); - ~SaveGameInfoWidget(); - - virtual void setSave(const SaveGame *saveGame); - -signals: - - void closeSaveInfo(); - -protected: - -// virtual bool eventFilter(QObject *object, QEvent *event); - - QFrame *getGameFrame(); - -private: - -private: - - Ui::SaveGameInfoWidget *ui; - -}; - -#endif // SAVEGAMEINFOWIDGET_H diff --git a/src/savegameinfowidget.ui b/src/savegameinfowidget.ui deleted file mode 100644 index e2e9588c..00000000 --- a/src/savegameinfowidget.ui +++ /dev/null @@ -1,209 +0,0 @@ - - - SaveGameInfoWidget - - - - 0 - 0 - 400 - 300 - - - - - 0 - 0 - - - - - - - - - - - - - QFormLayout::AllNonFixedFieldsGrow - - - - - - true - - - - Save # - - - - - - - - true - - - - Character - - - - - - - - true - - - - Level - - - - - - - - true - - - - Location - - - - - - - - true - - - - Date - - - - - - - - 75 - true - - - - - - - - - - - - 75 - true - - - - - - - - - - - - 75 - true - - - - - - - - - - - - 75 - true - - - - - - - - - - - - 75 - true - - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - false - - - - - - Qt::AlignCenter - - - - - - - - diff --git a/src/savegameinfowidgetgamebryo.cpp b/src/savegameinfowidgetgamebryo.cpp deleted file mode 100644 index c97e5810..00000000 --- a/src/savegameinfowidgetgamebryo.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -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 "savegamegamebyro.h" -#include "savegameinfowidgetgamebryo.h" -#include -#include - - -SaveGameInfoWidgetGamebryo::SaveGameInfoWidgetGamebryo(const SaveGame *saveGame, PluginList *pluginList, QWidget *parent) - : SaveGameInfoWidget(parent), m_PluginList(pluginList) -{ - QVBoxLayout *gameLayout = new QVBoxLayout(); - gameLayout->setMargin(0); - gameLayout->setSpacing(2); - getGameFrame()->setLayout(gameLayout); - setSave(saveGame); -} - - -void SaveGameInfoWidgetGamebryo::setSave(const SaveGame *saveGame) -{ - SaveGameInfoWidget::setSave(saveGame); - const SaveGameGamebryo *gamebryoSave = qobject_cast(saveGame); - QLayout *layout = getGameFrame()->layout(); - QLabel *header = new QLabel(tr("Missing ESPs")); - QFont headerFont = header->font(); - QFont contentFont = headerFont; - headerFont.setItalic(true); - contentFont.setBold(true); - contentFont.setPointSize(7); - header->setFont(headerFont); - layout->addWidget(header); - int count = 0; - for (int i = 0; i < gamebryoSave->numPlugins(); ++i) { - const QString &pluginName = gamebryoSave->plugin(i); - if (m_PluginList->isEnabled(pluginName)) { - continue; - } else { - ++count; - } - - if (count > 10) { - break; - } - - QLabel *pluginLabel = new QLabel(gamebryoSave->plugin(i)); - pluginLabel->setIndent(10); - pluginLabel->setFont(contentFont); - layout->addWidget(pluginLabel); - } - if (count > 10) { - QLabel *dotDotLabel = new QLabel("..."); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - if (count == 0) { - QLabel *dotDotLabel = new QLabel(tr("None")); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } -} diff --git a/src/savegameinfowidgetgamebryo.h b/src/savegameinfowidgetgamebryo.h deleted file mode 100644 index 149a8885..00000000 --- a/src/savegameinfowidgetgamebryo.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -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 . -*/ - -#ifndef SAVEGAMEINFOWIDGETGAMEBRYO_H -#define SAVEGAMEINFOWIDGETGAMEBRYO_H - - -#include "savegameinfowidget.h" -#include "pluginlist.h" - - -class SaveGame; - -class SaveGameInfoWidgetGamebryo : public SaveGameInfoWidget -{ -public: - - explicit SaveGameInfoWidgetGamebryo(const SaveGame *saveGame, PluginList *pluginList, QWidget *parent = 0); - - virtual void setSave(const SaveGame *saveGame); - -private: - - PluginList *m_PluginList; - -}; - -#endif // SAVEGAMEINFOWIDGETGAMEBRYO_H diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index ae75b9cb..7733ae80 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -19,6 +19,8 @@ along with Mod Organizer. If not, see . #include "selfupdater.h" +#include "archive.h" +#include "callback.h" #include "utility.h" #include "installationmanager.h" #include "iplugingame.h" @@ -30,15 +32,36 @@ along with Mod Organizer. If not, see . #include #include +#include +#include +#include +#include +#include #include #include #include -#include -#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + #include +#include //for VS_FIXEDFILEINFO, GetLastError + +#include +#include +#include //for size_t +#include using namespace MOBase; using namespace MOShared; diff --git a/src/selfupdater.h b/src/selfupdater.h index 0a31b0f3..37021b42 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -21,19 +21,20 @@ along with Mod Organizer. If not, see . #define SELFUPDATER_H -#include #include -#include -#include -#include -#include - -#include - +class Archive; +class NexusInterface; namespace MOBase { class IPluginGame; } -class NexusInterface; +#include +#include +#include +#include +#include //for qint64 + +class QNetworkReply; +class QProgressDialog; /** diff --git a/src/shared/shared.pro b/src/shared/shared.pro index a64e781d..517e1e86 100644 --- a/src/shared/shared.pro +++ b/src/shared/shared.pro @@ -21,12 +21,7 @@ SOURCES += \ windows_error.cpp \ error_report.cpp \ directoryentry.cpp \ - gameinfo.cpp \ - oblivioninfo.cpp \ - fallout3info.cpp \ - falloutnvinfo.cpp \ util.cpp \ - skyriminfo.cpp \ appconfig.cpp \ leaktrace.cpp \ stackdata.cpp @@ -36,12 +31,7 @@ HEADERS += \ windows_error.h \ error_report.h \ directoryentry.h \ - gameinfo.h \ - oblivioninfo.h \ - fallout3info.h \ - falloutnvinfo.h \ util.h \ - skyriminfo.h \ appconfig.h \ appconfig.inc \ leaktrace.h \ diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp index 838d12ce..e130b1ae 100644 --- a/src/transfersavesdialog.cpp +++ b/src/transfersavesdialog.cpp @@ -21,19 +21,83 @@ along with Mod Organizer. If not, see . #include "ui_transfersavesdialog.h" #include "iplugingame.h" -#include "savegamegamebyro.h" -#include "utility.h" +#include "isavegame.h" +#include "savegameinfo.h" +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include - -#include -#include - +#include +#include using namespace MOBase; using namespace MOShared; +//These two classes give the save-transfer box a smidgin of useful info even +//if save game isn't supported yet. +namespace { + +class DummySave : public ISaveGame +{ +public: + DummySave(QString const &filename) : + m_File(filename) + {} + + ~DummySave() {} + + virtual QString getFilename() const override + { + return m_File; + } + + virtual QDateTime getCreationTime() const override + { + return QFileInfo(m_File).created(); + } + + virtual QString getSaveGroupIdentifier() const override + { + return m_File; + } + + virtual QStringList allFiles() const override + { + return { m_File }; + } + +private: + QString m_File; +}; + +class DummyInfo : public SaveGameInfo +{ +public: + virtual MOBase::ISaveGame const *getSaveGameInfo(QString const &file) const override + { + return new DummySave(file); + } + + virtual MissingAssets getMissingAssets(QString const &) const override + { + return {}; + } + + MOBase::ISaveGameInfoWidget *getSaveGameWidget(QWidget *) const override + { + return nullptr; + } +}; + +} //end anonymous namespace TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame const *gamePlugin, QWidget *parent) : TutorableDialog("TransferSaves", parent) @@ -42,6 +106,7 @@ TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame con , m_GamePlugin(gamePlugin) { ui->setupUi(this); + ui->label_2->setText(tr("Characters for profile %1").arg(m_Profile.name())); refreshGlobalSaves(); refreshLocalSaves(); refreshGlobalCharacters(); @@ -53,85 +118,27 @@ TransferSavesDialog::~TransferSavesDialog() delete ui; } - void TransferSavesDialog::refreshGlobalSaves() { - m_GlobalSaves.clear(); - QDir savesDir(m_GamePlugin->savesDirectory()); - savesDir.setNameFilters(QStringList() << QString("*.%1").arg(m_GamePlugin->savegameExtension())); - - QStringList files = savesDir.entryList(QDir::Files, QDir::Time); - - for (const QString &filename : files) { - SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename), m_GamePlugin); - save->setParent(this); - m_GlobalSaves.push_back(save); - } + refreshSaves(m_GlobalSaves, m_GamePlugin->savesDirectory().absolutePath()); } void TransferSavesDialog::refreshLocalSaves() { - m_LocalSaves.clear(); - - QDir savesDir(m_Profile.absolutePath() + "/saves"); - - savesDir.setNameFilters(QStringList() << QString("*.%1").arg(m_GamePlugin->savegameExtension())); - - QStringList files = savesDir.entryList(QDir::Files, QDir::Time); - - for (const QString &filename : files) { - SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename), m_GamePlugin); - - save->setParent(this); - m_LocalSaves.push_back(save); - } + refreshSaves(m_LocalSaves, m_Profile.savePath()); } void TransferSavesDialog::refreshGlobalCharacters() { - std::set characters; - for (std::vector::const_iterator iter = m_GlobalSaves.begin(); - iter != m_GlobalSaves.end(); ++iter) { - characters.insert((*iter)->pcName()); - } - ui->globalCharacterList->clear(); - for (std::set::const_iterator iter = characters.begin(); - iter != characters.end(); ++iter) { - ui->globalCharacterList->addItem(*iter); - } - if (ui->globalCharacterList->count() > 0) { - ui->globalCharacterList->setCurrentRow(0); - ui->copyToLocalBtn->setEnabled(true); - ui->moveToLocalBtn->setEnabled(true); - } else { - ui->copyToLocalBtn->setEnabled(false); - ui->moveToLocalBtn->setEnabled(false); - } + refreshCharacters(m_GlobalSaves, ui->globalCharacterList, ui->copyToLocalBtn, ui->moveToLocalBtn); } void TransferSavesDialog::refreshLocalCharacters() { - std::set characters; - for (std::vector::const_iterator iter = m_LocalSaves.begin(); - iter != m_LocalSaves.end(); ++iter) { - characters.insert((*iter)->pcName()); - } - ui->localCharacterList->clear(); - for (std::set::const_iterator iter = characters.begin(); - iter != characters.end(); ++iter) { - ui->localCharacterList->addItem(*iter); - } - if (ui->localCharacterList->count() > 0) { - ui->localCharacterList->setCurrentRow(0); - ui->copyToGlobalBtn->setEnabled(true); - ui->moveToGlobalBtn->setEnabled(true); - } else { - ui->copyToGlobalBtn->setEnabled(false); - ui->moveToGlobalBtn->setEnabled(false); - } + refreshCharacters(m_LocalSaves, ui->localCharacterList, ui->copyToGlobalBtn, ui->moveToGlobalBtn); } @@ -153,144 +160,75 @@ bool TransferSavesDialog::testOverwrite(OverwriteMode &overwriteMode, const QStr 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 selectedCharacter = ui->globalCharacterList->currentItem()->text(); - if (QMessageBox::question(this, tr("Confirm"), - tr("Move all save games of character \"%1\" to the profile?").arg(selectedCharacter), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - QString destination = m_Profile.absolutePath() + "/saves"; - OverwriteMode overwriteMode = OVERWRITE_ASK; - - for (std::vector::const_iterator iter = m_GlobalSaves.begin(); - iter != m_GlobalSaves.end(); ++iter) { - if ((*iter)->pcName() == selectedCharacter) { - QStringList files = (*iter)->saveFiles(); - for (const QString &file : files) { - QFileInfo fileInfo(file); - QString destinationFile = destination + "/" + fileInfo.fileName(); - if (QFile::exists(destinationFile)) { - if (testOverwrite(overwriteMode, destinationFile)) { - QFile::remove(destinationFile); - } else { - continue; - } - } - if (!shellMove(fileInfo.absoluteFilePath(), destinationFile)) { - qCritical("failed to move %s to %s: %lu", - fileInfo.absoluteFilePath().toUtf8().constData(), - destinationFile.toUtf8().constData(), - ::GetLastError()); - } - } - } - } + QString character = ui->globalCharacterList->currentItem()->text(); + if (transferCharacters( + character, MOVE_SAVES TO_PROFILE, m_GlobalSaves[character], + m_Profile.savePath(), + [this](const QString &source, const QString &destination) -> bool { + return shellMove(source, destination, this); + }, + "Failed to move %s to %s")) { + refreshGlobalSaves(); + refreshGlobalCharacters(); + refreshLocalSaves(); + refreshLocalCharacters(); } - refreshGlobalSaves(); - refreshGlobalCharacters(); - refreshLocalSaves(); - refreshLocalCharacters(); } void TransferSavesDialog::on_copyToLocalBtn_clicked() { - QString selectedCharacter = ui->globalCharacterList->currentItem()->text(); - if (QMessageBox::question(this, tr("Confirm"), - tr("Copy all save games of character \"%1\" to the profile?").arg(selectedCharacter), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - QString destination = m_Profile.absolutePath() + "/saves"; - OverwriteMode overwriteMode = OVERWRITE_ASK; - for (std::vector::const_iterator iter = m_GlobalSaves.begin(); - iter != m_GlobalSaves.end(); ++iter) { - if ((*iter)->pcName() == selectedCharacter) { - QStringList files = (*iter)->saveFiles(); - QStringList destinations; - for (const QString &file : files) { - QFileInfo fileInfo(file); - destinations.append(destination + "/" + fileInfo.fileName()); - } - shellCopy(files, destinations, this); - } - } + QString character = ui->globalCharacterList->currentItem()->text(); + if (transferCharacters( + character, COPY_SAVES TO_PROFILE, m_GlobalSaves[character], + m_Profile.savePath(), + [this](const QString &source, const QString &destination) -> bool { + return shellCopy(source, destination, this); + }, + "Failed to copy %s to %s")) { + refreshLocalSaves(); + refreshLocalCharacters(); } - refreshLocalSaves(); - refreshLocalCharacters(); } void TransferSavesDialog::on_moveToGlobalBtn_clicked() { - QString selectedCharacter = ui->localCharacterList->currentItem()->text(); - if (QMessageBox::question(this, tr("Confirm"), - tr("Move all save games of character \"%1\" to the global location? Please be aware " - "that this will mess up the running number of save games.").arg(selectedCharacter), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - - QDir destination = m_GamePlugin->savesDirectory(); - OverwriteMode overwriteMode = OVERWRITE_ASK; - for (std::vector::const_iterator iter = m_LocalSaves.begin(); - iter != m_LocalSaves.end(); ++iter) { - if ((*iter)->pcName() == selectedCharacter) { - QStringList files = (*iter)->saveFiles(); - for (const QString &file : files) { - QFileInfo fileInfo(file); - QString destinationFile = destination.filePath(fileInfo.fileName()); - if (QFile::exists(destinationFile)) { - if (testOverwrite(overwriteMode, destinationFile)) { - QFile::remove(destinationFile); - } else { - continue; - } - } - if (!shellMove(fileInfo.absoluteFilePath(), destinationFile)) { - qCritical("failed to move %s to %s", - fileInfo.absoluteFilePath().toUtf8().constData(), - destinationFile.toUtf8().constData()); - } - } - } - } + QString character = ui->localCharacterList->currentItem()->text(); + if (transferCharacters( + character, MOVE_SAVES TO_GLOBAL, m_LocalSaves[character], + m_GamePlugin->savesDirectory().absolutePath(), + [this](const QString &source, const QString &destination) -> bool { + return shellMove(source, destination, this); + }, + "Failed to move %s to %s")) { + refreshGlobalSaves(); + refreshGlobalCharacters(); + refreshLocalSaves(); + refreshLocalCharacters(); } - refreshGlobalSaves(); - refreshGlobalCharacters(); - refreshLocalSaves(); - refreshLocalCharacters(); } void TransferSavesDialog::on_copyToGlobalBtn_clicked() { - QString selectedCharacter = ui->localCharacterList->currentItem()->text(); - if (QMessageBox::question(this, tr("Confirm"), - tr("Copy all save games of character \"%1\" to the global location? Please be aware " - "that this will mess up the running number of save games.").arg(selectedCharacter), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - - QDir destination = m_GamePlugin->savesDirectory(); - OverwriteMode overwriteMode = OVERWRITE_ASK; - for (std::vector::const_iterator iter = m_LocalSaves.begin(); - iter != m_LocalSaves.end(); ++iter) { - if ((*iter)->pcName() == selectedCharacter) { - QStringList files = (*iter)->saveFiles(); - for (const QString &file : files) { - QFileInfo fileInfo(file); - QString destinationFile = destination.filePath(fileInfo.fileName()); - if (QFile::exists(destinationFile)) { - if (testOverwrite(overwriteMode, destinationFile)) { - QFile::remove(destinationFile); - } else { - continue; - } - } - if (!shellCopy(fileInfo.absoluteFilePath(), destinationFile)) { - qCritical("failed to copy %s to %s", - fileInfo.absoluteFilePath().toUtf8().constData(), - destinationFile.toUtf8().constData()); - } - } - } - } + QString character = ui->localCharacterList->currentItem()->text(); + if (transferCharacters( + character, COPY_SAVES TO_GLOBAL, m_LocalSaves[character], + m_GamePlugin->savesDirectory().absolutePath(), + [this](const QString &source, const QString &destination) -> bool { + return shellCopy(source, destination, this); + }, + "Failed to copy %s to %s")) { + refreshGlobalSaves(); + refreshGlobalCharacters(); } - refreshGlobalSaves(); - refreshGlobalCharacters(); } void TransferSavesDialog::on_doneButton_clicked() @@ -301,10 +239,12 @@ void TransferSavesDialog::on_doneButton_clicked() void TransferSavesDialog::on_globalCharacterList_currentTextChanged(const QString ¤tText) { ui->globalSavesList->clear(); - for (std::vector::const_iterator iter = m_GlobalSaves.begin(); - iter != m_GlobalSaves.end(); ++iter) { - if ((*iter)->pcName() == currentText) { - ui->globalSavesList->addItem(QFileInfo((*iter)->fileName()).fileName()); + //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->getFilename()).fileName()); } } } @@ -312,10 +252,89 @@ void TransferSavesDialog::on_globalCharacterList_currentTextChanged(const QStrin void TransferSavesDialog::on_localCharacterList_currentTextChanged(const QString ¤tText) { ui->localSavesList->clear(); - for (std::vector::const_iterator iter = m_LocalSaves.begin(); - iter != m_LocalSaves.end(); ++iter) { - if ((*iter)->pcName() == currentText) { - ui->localSavesList->addItem(QFileInfo((*iter)->fileName()).fileName()); + //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->getFilename()).fileName()); + } + } +} + +void TransferSavesDialog::refreshSaves(SaveCollection &saveCollection, QString const &savedir) +{ + saveCollection.clear(); + QDir savesDir(savedir); + savesDir.setNameFilters(QStringList() << QString("*.%1").arg(m_GamePlugin->savegameExtension())); + + SaveGameInfo const *info = m_GamePlugin->feature(); + if (info == nullptr) { + static DummyInfo dummyInfo; + info = &dummyInfo; + } + + QStringList files = savesDir.entryList(QDir::Files, QDir::Time); + for (const QString &filename : files) { + QString file = savesDir.absoluteFilePath(filename); + MOBase::ISaveGame const *save = info->getSaveGameInfo(file); + saveCollection[save->getSaveGroupIdentifier()].push_back( + std::unique_ptr(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, SaveList &saves, + QString const &dest, + const std::function &method, + char const *errmsg) +{ + if (QMessageBox::question(this, tr("Confirm"), + tr(message).arg(character), + QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) { + return false; + } + + OverwriteMode overwriteMode = OVERWRITE_ASK; + + QDir destination(dest); + for (SaveListItem const &save : saves) { + for (QString source : save->allFiles()) { + QFileInfo sourceFile(source); + QString destinationFile(destination.absoluteFilePath(sourceFile.fileName())); + + //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)) { + qCritical(errmsg, + sourceFile.absoluteFilePath().toUtf8().constData(), + destinationFile.toUtf8().constData()); + } } } + return true; } diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h index e2c556b4..6961e8c6 100644 --- a/src/transfersavesdialog.h +++ b/src/transfersavesdialog.h @@ -23,10 +23,19 @@ along with Mod Organizer. If not, see . #include "tutorabledialog.h" #include "profile.h" +class QListWidget; +#include +class QPushButton; +#include +class QWidget; + +#include +#include +#include + namespace Ui { class TransferSavesDialog; } namespace MOBase { class IPluginGame; } - -class SaveGame; +namespace MOBase { class ISaveGame; } class TransferSavesDialog : public MOBase::TutorableDialog { @@ -76,9 +85,23 @@ private: MOBase::IPluginGame const *m_GamePlugin; - std::vector m_GlobalSaves; - std::vector m_LocalSaves; - + typedef std::unique_ptr SaveListItem; + typedef std::vector SaveList; + typedef std::map SaveCollection; + SaveCollection m_GlobalSaves; + SaveCollection m_LocalSaves; + + void refreshSaves(SaveCollection &saveCollection, const QString &savedir); + void refreshCharacters(SaveCollection const &saveCollection, + QListWidget *charList, + QPushButton *copy, + QPushButton *move); + + bool transferCharacters( + QString const &character, char const *message, SaveList &saves, + QString const &dest, + const std::function &method, + char const *errmsg); }; #endif // TRANSFERSAVESDIALOG_H -- cgit v1.3.1