diff --git a/es-app/src/CollectionSystemsManager.cpp b/es-app/src/CollectionSystemsManager.cpp index 522174808..a5fbde3f7 100644 --- a/es-app/src/CollectionSystemsManager.cpp +++ b/es-app/src/CollectionSystemsManager.cpp @@ -935,6 +935,74 @@ void CollectionSystemsManager::reactivateCustomCollectionEntry(FileData* game) } } +void CollectionSystemsManager::repopulateCollection(SystemData* sysData) +{ + for (auto it = mAutoCollectionSystemsData.cbegin(); + it != mAutoCollectionSystemsData.cend(); it++) { + if ((*it).second.system == sysData) { + LOG(LogDebug) << "CollectionSystemsManager::repopulateCollection(): " + "Repopulating auto collection '" << it->first << "'."; + + CollectionSystemData* autoSystem = &mAutoCollectionSystemsData[it->first]; + std::vector<FileData*> systemEntries = + autoSystem->system->getRootFolder()->getFilesRecursive(true, true, false); + + if (systemEntries.empty()) + return; + + // Delete all children from the system and remove them from the index too. + for (FileData* entry : systemEntries) { + autoSystem->system->getIndex()->removeFromIndex(entry); + autoSystem->system->getRootFolder()->removeChild(entry); + delete entry; + } + + // Flag the collection as not populated so it gets repopulated. + autoSystem->isPopulated = false; + populateAutoCollection(autoSystem); + + // The cursor value is now pointing to some random memory address so we need to set + // it to something valid, as done here by selecting the first child. This does however + // not mean it's the first row of the gamelist, so we follow up with selecting the + // first entry after that. If doing this second step without the first step we would + // crash the application as it would try to access the old (now invalid) pointer. + auto autoView = ViewController::get()->getGameListView(autoSystem->system).get(); + autoView->setCursor(autoSystem->system->getRootFolder()-> + getChildrenRecursive().front()); + autoView->setCursor(autoView->getFirstEntry()); + } + } + + for (auto it = mCustomCollectionSystemsData.cbegin(); + it != mCustomCollectionSystemsData.cend(); it++) { + if ((*it).second.system == sysData) { + LOG(LogDebug) << "CollectionSystemsManager::repopulateCollection(): " + "Repopulating custom collection '" << it->first << "'."; + + CollectionSystemData* customSystem = &mCustomCollectionSystemsData[it->first]; + std::vector<FileData*> systemEntries = + customSystem->system->getRootFolder()->getFilesRecursive(true, true, false); + + if (systemEntries.empty()) + return; + + for (FileData* entry : systemEntries) { + customSystem->system->getIndex()->removeFromIndex(entry); + customSystem->system->getRootFolder()->removeChild(entry); + delete entry; + } + + customSystem->isPopulated = false; + populateCustomCollection(customSystem); + + auto autoView = ViewController::get()->getGameListView(customSystem->system).get(); + autoView->setCursor(customSystem->system->getRootFolder()-> + getChildrenRecursive().front()); + autoView->setCursor(autoView->getFirstEntry()); + } + } +} + void CollectionSystemsManager::initAutoCollectionSystems() { for (std::map<std::string, CollectionSystemDecl, stringComparator>::const_iterator @@ -1038,6 +1106,13 @@ void CollectionSystemsManager::populateAutoCollection(CollectionSystemData* sysD // collection was trimmed down to 50 items. If we don't do this, the game count will // not be correct as it would include all the games prior to trimming. if (rootFolder->getName() == "recent") { + // The following is needed to avoid a crash when repopulating the system as the previous + // cursor pointer may point to a random memory address. + auto recentGamelist = ViewController::get()->getGameListView(rootFolder->getSystem()).get(); + recentGamelist->setCursor(rootFolder->getSystem()->getRootFolder()-> + getChildrenRecursive().front()); + recentGamelist->setCursor(recentGamelist->getFirstEntry()); + ViewController::get()->getGameListView(rootFolder->getSystem()).get()-> onFileChanged(rootFolder->getChildren().front(), false); } diff --git a/es-app/src/CollectionSystemsManager.h b/es-app/src/CollectionSystemsManager.h index 81f8e559c..b90fd8288 100644 --- a/es-app/src/CollectionSystemsManager.h +++ b/es-app/src/CollectionSystemsManager.h @@ -112,6 +112,9 @@ public: // Reactivate a game in all custom collections where it has an entry in the configuration file. void reactivateCustomCollectionEntry(FileData* game); + // Repopulate the collection, which is basically a forced update of its complete content. + void repopulateCollection(SystemData* sysData); + inline std::map<std::string, CollectionSystemData, stringComparator> getAutoCollectionSystems() { return mAutoCollectionSystemsData; }; inline std::map<std::string, CollectionSystemData, stringComparator> diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.cpp b/es-app/src/guis/GuiCollectionSystemsOptions.cpp index e5458346a..902de5bff 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.cpp +++ b/es-app/src/guis/GuiCollectionSystemsOptions.cpp @@ -14,6 +14,7 @@ #include "guis/GuiMsgBox.h" #include "guis/GuiSettings.h" #include "guis/GuiTextEditPopup.h" +#include "utils/StringUtil.h" #include "views/ViewController.h" #include "CollectionSystemsManager.h" @@ -49,7 +50,7 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions( collection_systems_auto->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled); addWithLabel("AUTOMATIC GAME COLLECTIONS", collection_systems_auto); - addSaveFunc([this] { + addSaveFunc([this, autoSystems] { std::string autoSystemsSelected = Utils::String::vectorToCommaString(collection_systems_auto->getSelectedObjects(), true); std::string autoSystemsConfig = Settings::getInstance()->getString("CollectionSystemsAuto"); @@ -57,6 +58,29 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions( if (CollectionSystemsManager::get()->isEditing()) CollectionSystemsManager::get()->exitEditMode(); Settings::getInstance()->setString("CollectionSystemsAuto", autoSystemsSelected); + // Check if any systems have been enabled, and if so repopulate them, which results in + // a complete initialization of their content. This is necessary as collections aren't + // updated while they are disabled. + std::vector<std::string> addedAutoSystems; + if (autoSystemsConfig == "") { + addedAutoSystems = Utils::String::delimitedStringToVector(autoSystemsSelected, ","); + } + else if (autoSystemsSelected != "") { + std::vector<std::string> selectedVector = + Utils::String::delimitedStringToVector(autoSystemsSelected, ","); + std::vector<std::string> configuredVector = + Utils::String::delimitedStringToVector(autoSystemsConfig, ","); + for (std::string system : selectedVector) { + if (std::find(configuredVector.begin(), configuredVector.end(), system) == + configuredVector.end()) + addedAutoSystems.push_back(system); + } + } + if (!addedAutoSystems.empty()) { + for (std::string system : addedAutoSystems) + CollectionSystemsManager::get()-> + repopulateCollection(autoSystems.find(system)->second.system); + } setNeedsSaving(); setNeedsReloading(); setNeedsCollectionsUpdate(); @@ -76,7 +100,7 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions( collection_systems_custom->add(it->second.decl.longName, it->second.decl.name, it->second.isEnabled); addWithLabel("CUSTOM GAME COLLECTIONS", collection_systems_custom); - addSaveFunc([this] { + addSaveFunc([this, customSystems] { if (!mDeletedCustomCollection) { std::string customSystemsSelected = Utils::String::vectorToCommaString( collection_systems_custom->getSelectedObjects(), true); @@ -87,6 +111,30 @@ GuiCollectionSystemsOptions::GuiCollectionSystemsOptions( CollectionSystemsManager::get()->exitEditMode(); Settings::getInstance()->setString("CollectionSystemsCustom", customSystemsSelected); + // Check if any systems have been enabled, and if so repopulate them, which + // results in a complete initialization of their content. This is necessary as + // collections aren't updated while they are disabled. + std::vector<std::string> addedCustomSystems; + if (customSystemsConfig == "") { + addedCustomSystems = + Utils::String::delimitedStringToVector(customSystemsSelected, ","); + } + else if (customSystemsSelected != "") { + std::vector<std::string> selectedVector = + Utils::String::delimitedStringToVector(customSystemsSelected, ","); + std::vector<std::string> configuredVector = + Utils::String::delimitedStringToVector(customSystemsConfig, ","); + for (std::string system : selectedVector) { + if (std::find(configuredVector.begin(), configuredVector.end(), system) == + configuredVector.end()) + addedCustomSystems.push_back(system); + } + } + if (!addedCustomSystems.empty()) { + for (std::string system : addedCustomSystems) + CollectionSystemsManager::get()-> + repopulateCollection(customSystems.find(system)->second.system); + } setNeedsSaving(); setNeedsReloading(); setNeedsCollectionsUpdate();