diff --git a/es-app/src/CollectionSystemManager.cpp b/es-app/src/CollectionSystemManager.cpp index a040a8e4e..440abf7fa 100644 --- a/es-app/src/CollectionSystemManager.cpp +++ b/es-app/src/CollectionSystemManager.cpp @@ -15,6 +15,7 @@ #include "ThemeData.h" #include #include +#include /* Handling the getting, initialization, deinitialization, saving and deletion of * a CollectionSystemManager Instance */ @@ -97,29 +98,37 @@ void CollectionSystemManager::deinit() } } -void CollectionSystemManager::saveCustomCollection(SystemData* sys) +bool CollectionSystemManager::saveCustomCollection(SystemData* sys) { std::string name = sys->getName(); std::unordered_map games = sys->getRootFolder()->getChildrenByFilename(); bool found = mCustomCollectionSystemsData.find(name) != mCustomCollectionSystemsData.cend(); - if (found) { - CollectionSystemData sysData = mCustomCollectionSystemsData.at(name); - if (sysData.needsSave) - { - std::ofstream configFile; - configFile.open(getCustomCollectionConfigPath(name)); - for(std::unordered_map::const_iterator iter = games.cbegin(); iter != games.cend(); ++iter) - { - std::string path = iter->first; - configFile << path << std::endl; - } - configFile.close(); - } - } - else + if (!found) { LOG(LogError) << "Couldn't find collection to save! " << name; + return false; } + + CollectionSystemData sysData = mCustomCollectionSystemsData.at(name); + if (sysData.needsSave) + { + std::string absCollectionFn = getCustomCollectionConfigPath(name); + std::ofstream configFile; + configFile.open(absCollectionFn); + if (!configFile.good()) + { + auto const errNo = errno; + LOG(LogError) << "Failed to create file, collection not created: " << absCollectionFn << ": " << std::strerror(errNo) << " (" << errNo << ")"; + return false; + } + for(std::unordered_map::const_iterator iter = games.cbegin(); iter != games.cend(); ++iter) + { + std::string path = iter->first; + configFile << path << std::endl; + } + configFile.close(); + } + return true; } /* Methods to load all Collections into memory, and handle enabling the active ones */ @@ -128,7 +137,7 @@ void CollectionSystemManager::loadCollectionSystems(bool async) { initAutoCollectionSystems(); CollectionSystemDecl decl = mCollectionSystemDeclsIndex[CUSTOM_COLL_ID]; - mCustomCollectionsBundle = createNewCollectionEntry(decl.name, decl, false); + mCustomCollectionsBundle = createNewCollectionEntry(decl.name, decl, CollectionFlags::NONE); // we will also load custom systems here initCustomCollectionSystems(); if(Settings::getInstance()->getString("CollectionSystemsAuto") != "" || Settings::getInstance()->getString("CollectionSystemsCustom") != "") @@ -375,6 +384,7 @@ bool CollectionSystemManager::isThemeCustomCollectionCompatible(std::vector 0) { - name = name.substr(0, name.size()-4); + name = name.substr(0, name.size() - infix.size()); } return getValidNewCollectionName(name, index+1); } @@ -448,7 +458,7 @@ void CollectionSystemManager::setEditMode(std::string collectionName, bool quiet mEditingCollectionSystemData = sysData; if (!quiet) { - GuiInfoPopup* s = new GuiInfoPopup(mWindow, "Editing the '" + Utils::String::toUpper(collectionName) + "' Collection. Add/remove games with Y.", 10000); + GuiInfoPopup* s = new GuiInfoPopup(mWindow, "Editing the '" + Utils::String::toUpper(collectionName) + "' Collection. Add/remove games with Y.", 8000); mWindow->setInfoPopup(s); } } @@ -456,14 +466,14 @@ void CollectionSystemManager::setEditMode(std::string collectionName, bool quiet void CollectionSystemManager::exitEditMode(bool quiet) { if (!quiet) { - GuiInfoPopup* s = new GuiInfoPopup(mWindow, "Finished editing the '" + mEditingCollection + "' Collection.", 4000); + GuiInfoPopup* s = new GuiInfoPopup(mWindow, "Finished editing the '" + Utils::String::toUpper(mEditingCollection) + "' Collection.", 4000); mWindow->setInfoPopup(s); } if (mIsEditingCustom) { mIsEditingCustom = false; mEditingCollection = "Favorites"; - mEditingCollectionSystemData->system->onMetaDataSavePoint(); + saveCustomCollection(mEditingCollectionSystemData->system); } } @@ -656,7 +666,7 @@ void CollectionSystemManager::initAutoCollectionSystems() CollectionSystemDecl sysDecl = it->second; if (!sysDecl.isCustom) { - SystemData* newCol = createNewCollectionEntry(sysDecl.name, sysDecl); + SystemData* newCol = createNewCollectionEntry(sysDecl.name, sysDecl, CollectionFlags::HOLD_IN_MAP); if (sysDecl.type == AUTO_RANDOM) mRandomCollection = newCol; } @@ -756,17 +766,20 @@ SystemData* CollectionSystemManager::getAllGamesCollection() return allSysData->system; } -SystemData* CollectionSystemManager::addNewCustomCollection(std::string name) +SystemData* CollectionSystemManager::addNewCustomCollection(std::string name, bool needsSave) { CollectionSystemDecl decl = mCollectionSystemDeclsIndex[CUSTOM_COLL_ID]; decl.themeFolder = name; decl.name = name; decl.longName = name; - return createNewCollectionEntry(name, decl); + CollectionFlags flags = CollectionFlags::HOLD_IN_MAP; + if (needsSave) + flags = flags | CollectionFlags::NEEDS_SAVE; + return createNewCollectionEntry(name, decl, flags); } // creates a new, empty Collection system, based on the name and declaration -SystemData* CollectionSystemManager::createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, bool index) +SystemData* CollectionSystemManager::createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, const CollectionFlags flags) { SystemData* newSys = new SystemData(name, sysDecl.longName, mCollectionEnvData, sysDecl.themeFolder, true); @@ -775,9 +788,9 @@ SystemData* CollectionSystemManager::createNewCollectionEntry(std::string name, newCollectionData.decl = sysDecl; newCollectionData.isEnabled = false; newCollectionData.isPopulated = false; - newCollectionData.needsSave = false; + newCollectionData.needsSave = (flags & CollectionFlags::NEEDS_SAVE) == CollectionFlags::NEEDS_SAVE ? true : false; - if (index) + if ((flags & CollectionFlags::HOLD_IN_MAP) == CollectionFlags::HOLD_IN_MAP) { if (!sysDecl.isCustom) { diff --git a/es-app/src/CollectionSystemManager.h b/es-app/src/CollectionSystemManager.h index b0cede21c..b979f9d25 100644 --- a/es-app/src/CollectionSystemManager.h +++ b/es-app/src/CollectionSystemManager.h @@ -30,6 +30,24 @@ enum CollectionSystemType CUSTOM_COLLECTION }; +// Flags when loading or creating a collection +enum class CollectionFlags : uint8_t +{ + NONE, // create only + HOLD_IN_MAP, // create and keep in mAutoCollectionSystemsData or mCustomCollectionSystemsData + NEEDS_SAVE // force save of newly added collection +}; + +constexpr CollectionFlags operator|(CollectionFlags a,CollectionFlags b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +constexpr CollectionFlags operator&(CollectionFlags a, CollectionFlags b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} + struct CollectionSystemDecl { CollectionSystemType type; // type of system @@ -58,7 +76,7 @@ class CollectionSystemManager static CollectionSystemManager* get(); static void init(Window* window); static void deinit(); - void saveCustomCollection(SystemData* sys); + bool saveCustomCollection(SystemData* sys); void loadCollectionSystems(bool async=false); void loadEnabledListFromSettings(); @@ -74,7 +92,7 @@ class CollectionSystemManager inline SystemData* getCustomCollectionsBundle() { return mCustomCollectionsBundle; }; inline SystemData* getRandomCollection() { return mRandomCollection; }; std::vector getUnusedSystemsFromTheme(); - SystemData* addNewCustomCollection(std::string name); + SystemData* addNewCustomCollection(std::string name, bool needsSave = false); bool isThemeGenericCollectionCompatible(bool genericCustomCollections); bool isThemeCustomCollectionCompatible(std::vector stringVector); @@ -107,7 +125,7 @@ class CollectionSystemManager void initAutoCollectionSystems(); void initCustomCollectionSystems(); - SystemData* createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, bool index = true); + SystemData* createNewCollectionEntry(std::string name, CollectionSystemDecl sysDecl, const CollectionFlags flags); void populateAutoCollection(CollectionSystemData* sysData); void populateCustomCollection(CollectionSystemData* sysData); void addRandomGames(SystemData* newSys, SystemData* sourceSystem, FileData* rootFolder, FileFilterIndex* index, diff --git a/es-app/src/guis/GuiCollectionSystemsOptions.cpp b/es-app/src/guis/GuiCollectionSystemsOptions.cpp index cd58229ff..1019e7078 100644 --- a/es-app/src/guis/GuiCollectionSystemsOptions.cpp +++ b/es-app/src/guis/GuiCollectionSystemsOptions.cpp @@ -1,7 +1,10 @@ +#include + #include "guis/GuiCollectionSystemsOptions.h" #include "components/OptionListComponent.h" #include "components/SwitchComponent.h" +#include "guis/GuiInfoPopup.h" #include "guis/GuiRandomCollectionOptions.h" #include "guis/GuiSettings.h" #include "guis/GuiTextEditPopup.h" @@ -25,50 +28,59 @@ void GuiCollectionSystemsOptions::initializeMenu() // manage random collection addEntry("RANDOM GAME COLLECTION SETTINGS", 0x777777FF, true, [this] { openRandomCollectionSettings(); }); - // add "Create New Custom Collection from Theme" - std::vector unusedFolders = CollectionSystemManager::get()->getUnusedSystemsFromTheme(); - if (unusedFolders.size() > 0) + + ComponentListRow row; + if(CollectionSystemManager::get()->isEditing()) { - addEntry("CREATE NEW CUSTOM COLLECTION FROM THEME", 0x777777FF, true, - [this, unusedFolders] { - auto s = new GuiSettings(mWindow, "SELECT THEME FOLDER"); - std::shared_ptr< OptionListComponent > folderThemes = std::make_shared< OptionListComponent >(mWindow, "SELECT THEME FOLDER", true); + row.addElement(std::make_shared(mWindow, "FINISH EDITING '" + Utils::String::toUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); + row.makeAcceptInputHandler(std::bind(&GuiCollectionSystemsOptions::exitEditMode, this)); + mMenu.addRow(row); + } + else + { + // add "Create New Custom Collection from Theme" + std::vector unusedFolders = CollectionSystemManager::get()->getUnusedSystemsFromTheme(); + if (unusedFolders.size() > 0) + { + addEntry("CREATE NEW CUSTOM COLLECTION FROM THEME", 0x777777FF, true, + [this, unusedFolders] { + auto s = new GuiSettings(mWindow, "SELECT THEME FOLDER"); + std::shared_ptr< OptionListComponent > folderThemes = std::make_shared< OptionListComponent >(mWindow, "SELECT THEME FOLDER", true); - // add Custom Systems - for(auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ ) - { - ComponentListRow row; - std::string name = *it; + // add Custom Systems + for(auto it = unusedFolders.cbegin() ; it != unusedFolders.cend() ; it++ ) + { + ComponentListRow row; + std::string name = *it; - std::function createCollectionCall = [name, this, s] { - createCollection(name); - }; - row.makeAcceptInputHandler(createCollectionCall); + std::function createCollectionCall = [name, this, s] { + createCollection(name); + }; + row.makeAcceptInputHandler(createCollectionCall); - auto themeFolder = std::make_shared(mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF); - row.addElement(themeFolder, true); - s->addRow(row); - } - mWindow->pushGui(s); + auto themeFolder = std::make_shared(mWindow, Utils::String::toUpper(name), Font::get(FONT_SIZE_SMALL), 0x777777FF); + row.addElement(themeFolder, true); + s->addRow(row); + } + mWindow->pushGui(s); + }); + } + + row.addElement(std::make_shared(mWindow, "CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); + auto createCustomCollection = [this](const std::string& newVal) { + std::string name = newVal; + // we need to store the first Gui and remove it, as it'll be deleted by the actual Gui + Window* window = mWindow; + GuiComponent* topGui = window->peekGui(); + window->removeGui(topGui); + createCollection(name); + }; + row.makeAcceptInputHandler([this, createCustomCollection] { + mWindow->pushGui(new GuiTextEditPopup(mWindow, "New Collection Name", "", createCustomCollection, false)); }); + mMenu.addRow(row); } - ComponentListRow row; - row.addElement(std::make_shared(mWindow, "CREATE NEW CUSTOM COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); - auto createCustomCollection = [this](const std::string& newVal) { - std::string name = newVal; - // we need to store the first Gui and remove it, as it'll be deleted by the actual Gui - Window* window = mWindow; - GuiComponent* topGui = window->peekGui(); - window->removeGui(topGui); - createCollection(name); - }; - row.makeAcceptInputHandler([this, createCustomCollection] { - mWindow->pushGui(new GuiTextEditPopup(mWindow, "New Collection Name", "", createCustomCollection, false)); - }); - - mMenu.addRow(row); - bundleCustomCollections = std::make_shared(mWindow); bundleCustomCollections->setState(Settings::getInstance()->getBool("UseCustomCollectionsSystem")); mMenu.addWithLabel("GROUP UNTHEMED CUSTOM COLLECTIONS", bundleCustomCollections); @@ -103,14 +115,6 @@ void GuiCollectionSystemsOptions::initializeMenu() mMenu.addWithLabel("ADD/REMOVE GAMES WHILE SCREENSAVER TO", defaultScreenSaverCollection); - if(CollectionSystemManager::get()->isEditing()) - { - row.elements.clear(); - row.addElement(std::make_shared(mWindow, "FINISH EDITING '" + Utils::String::toUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true); - row.makeAcceptInputHandler(std::bind(&GuiCollectionSystemsOptions::exitEditMode, this)); - mMenu.addRow(row); - } - mMenu.addButton("BACK", "back", std::bind(&GuiCollectionSystemsOptions::applySettings, this)); mMenu.setPosition((Renderer::getScreenWidth() - mMenu.getSize().x()) / 2, Renderer::getScreenHeight() * 0.15f); @@ -137,8 +141,15 @@ void GuiCollectionSystemsOptions::addEntry(const char* name, unsigned int color, void GuiCollectionSystemsOptions::createCollection(std::string inName) { - std::string name = CollectionSystemManager::get()->getValidNewCollectionName(inName); - SystemData* newSys = CollectionSystemManager::get()->addNewCustomCollection(name); + CollectionSystemManager* collSysMgr = CollectionSystemManager::get(); + std::string name = collSysMgr->getValidNewCollectionName(inName); + + SystemData* newSys = collSysMgr->addNewCustomCollection(name, true); + if (!collSysMgr->saveCustomCollection(newSys)) { + GuiInfoPopup* s = new GuiInfoPopup(mWindow, "Failed creating '" + Utils::String::toUpper(name) + "' Collection. See log for details.", 8000); + mWindow->setInfoPopup(s); + return; + } customOptionList->add(name, name, true); std::string outAuto = Utils::String::vectorToDelimitedString(autoOptionList->getSelectedObjects(), ","); std::string outCustom = Utils::String::vectorToDelimitedString(customOptionList->getSelectedObjects(), ","); @@ -146,10 +157,9 @@ void GuiCollectionSystemsOptions::createCollection(std::string inName) ViewController::get()->goToSystemView(newSys); Window* window = mWindow; - CollectionSystemManager::get()->setEditMode(name); + collSysMgr->setEditMode(name); while(window->peekGui() && window->peekGui() != ViewController::get()) delete window->peekGui(); - return; } void GuiCollectionSystemsOptions::openRandomCollectionSettings()