// this updates all collection files related to the argument file void CollectionSystemManager::updateCollectionSystems(FileData* file) { // collection files use the full path as key, to avoid clashes std::string key = file->getFullPath(); // find games in collection systems for(auto sysIt = SystemData::sSystemVector.begin(); sysIt != SystemData::sSystemVector.end(); sysIt++) { if ((*sysIt)->isCollection()) { const std::unordered_map<std::string, FileData*>& children = (*sysIt)->getRootFolder()->getChildrenByFilename(); bool found = children.find(key) != children.end(); FileData* rootFolder = (*sysIt)->getRootFolder(); FileFilterIndex* fileIndex = (*sysIt)->getIndex(); std::string name = (*sysIt)->getName(); if (found) { // if we found it, we need to update it FileData* collectionEntry = children.at(key); // remove from index, so we can re-index metadata after refreshing fileIndex->removeFromIndex(collectionEntry); collectionEntry->refreshMetadata(); if (name == "favorites" && file->metadata.get("favorite") == "false") { // need to check if still marked as favorite, if not remove ViewController::get()->getGameListView((*sysIt)).get()->remove(collectionEntry, false); ViewController::get()->onFileChanged((*sysIt)->getRootFolder(), FILE_REMOVED); } else { // re-index with new metadata fileIndex->addToIndex(collectionEntry); ViewController::get()->onFileChanged(collectionEntry, FILE_METADATA_CHANGED); } } else { // we didn't find it here - we need to check if we should add it if (name == "recent" && file->metadata.get("playcount") > "0" || name == "favorites" && file->metadata.get("favorite") == "true") { CollectionFileData* newGame = new CollectionFileData(file, (*sysIt)); rootFolder->addChild(newGame); fileIndex->addToIndex(newGame); ViewController::get()->onFileChanged(file, FILE_METADATA_CHANGED); ViewController::get()->getGameListView((*sysIt))->onFileChanged(newGame, FILE_METADATA_CHANGED); } } rootFolder->sort(getSortType(mCollectionSystemDecls[name].defaultSort)); ViewController::get()->onFileChanged(rootFolder, FILE_SORTED); } } }
void CollectionSystemManager::loadAutoCollectionSystems() { for(std::map<std::string, CollectionSystemDecl>::iterator it = mCollectionSystemDecls.begin() ; it != mCollectionSystemDecls.end() ; it++ ) { CollectionSystemDecl sysDecl = it->second; if (!sysDecl.isCustom && !findCollectionSystem(sysDecl.name)) { SystemData* newSys = new SystemData(sysDecl.name, sysDecl.longName, mCollectionEnvData, sysDecl.themeFolder, true); FileData* rootFolder = newSys->getRootFolder(); FileFilterIndex* index = newSys->getIndex(); for(auto sysIt = SystemData::sSystemVector.begin(); sysIt != SystemData::sSystemVector.end(); sysIt++) { if ((*sysIt)->isGameSystem()) { std::vector<FileData*> files = (*sysIt)->getRootFolder()->getFilesRecursive(GAME); for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++) { bool include = includeFileInAutoCollections((*gameIt)); switch(sysDecl.type) { case AUTO_LAST_PLAYED: include = include && (*gameIt)->metadata.get("playcount") > "0"; break; case AUTO_FAVORITES: // we may still want to add files we don't want in auto collections in "favorites" include = (*gameIt)->metadata.get("favorite") == "true"; break; } if (include) { CollectionFileData* newGame = new CollectionFileData(*gameIt, newSys); rootFolder->addChild(newGame); index->addToIndex(newGame); } } } } rootFolder->sort(getSortType(sysDecl.defaultSort)); mAutoCollectionSystems.push_back(newSys); CollectionSystemData newCollectionData; newCollectionData.system = newSys; newCollectionData.decl = sysDecl; newCollectionData.isEnabled = false; mAllCollectionSystems[sysDecl.name] = newCollectionData; } } }
FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type, bool trustGamelist) { // first, verify that path is within the system's root folder FileData* root = system->getRootFolder(); fs::path relative; bool contains = false; if (trustGamelist) { relative = removeCommonPathUsingStrings(path, root->getPath(), contains); } else { relative = removeCommonPath(path, root->getPath(), contains); } if(!contains) { LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\""; return NULL; } auto path_it = relative.begin(); FileData* treeNode = root; bool found = false; while(path_it != relative.end()) { const std::unordered_map<std::string, FileData*>& children = treeNode->getChildrenByFilename(); std::string key = path_it->string(); found = children.find(key) != children.end(); if (found) { treeNode = children.at(key); } // this is the end if(path_it == --relative.end()) { if(found) return treeNode; if(type == FOLDER) { LOG(LogWarning) << "gameList: folder doesn't already exist, won't create"; return NULL; } FileData* file = new FileData(type, path, system); treeNode->addChild(file); return file; } if(!found) { // don't create folders unless it's leading up to a game // if type is a folder it's gonna be empty, so don't bother if(type == FOLDER) { LOG(LogWarning) << "gameList: folder doesn't already exist, won't create"; return NULL; } // create missing folder FileData* folder = new FileData(FOLDER, treeNode->getPath().stem() / *path_it, system); treeNode->addChild(folder); treeNode = folder; } path_it++; } return NULL; }
void parseGamelist(SystemData* system) { std::string xmlpath = system->getGamelistPath(false); if(!boost::filesystem::exists(xmlpath)) return; LOG(LogInfo) << "Parsing XML file \"" << xmlpath << "\"..."; pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(xmlpath.c_str()); if(!result) { LOG(LogError) << "Error parsing XML file \"" << xmlpath << "\"!\n " << result.description(); return; } pugi::xml_node root = doc.child("gameList"); if(!root) { LOG(LogError) << "Could not find <gameList> node in gamelist \"" << xmlpath << "\"!"; return; } fs::path relativeTo = system->getStartPath(); FileData* rootFd = system->getRootFolder(); // parse folders first //const char* tag = "folder"; for(pugi::xml_node fileNode = root.child("folder"); fileNode; fileNode = fileNode.next_sibling("folder")) { fs::path path = resolvePath(fileNode.child("path").text().get(), relativeTo, false); FileData* file = new FileData(FOLDER, path, system); rootFd->addChild(file); //load the metadata //std::string defaultName = file->metadata.get("name"); std::string defaultName = "defaultName"; file->metadata = MetaDataList::createFromXML(FOLDER_METADATA, fileNode, relativeTo); //make sure name gets set if one didn't exist if(file->metadata.get("name").empty()) file->metadata.set("name", defaultName); // parse game items for current folder for (pugi::xml_node childNode = fileNode.child("game"); childNode; childNode = childNode.next_sibling("game")) { fs::path path = resolvePath(childNode.child("path").text().get(), relativeTo, false); FileData* newFile = new FileData(GAME, path, system); file->addChild(newFile); newFile->metadata = MetaDataList::createFromXML(GAME_METADATA, childNode, relativeTo); //make sure name gets set if one didn't exist if(newFile->metadata.get("name").empty()) newFile->metadata.set("name", defaultName); } } /* const char* tagList[2] = { "game", "folder" }; FileType typeList[2] = { GAME, FOLDER }; for(int i = 0; i < 2; i++) { const char* tag = tagList[i]; FileType type = typeList[i]; for(pugi::xml_node fileNode = root.child(tag); fileNode; fileNode = fileNode.next_sibling(tag)) { fs::path path = resolvePath(fileNode.child("path").text().get(), relativeTo, false); FileData* file = new FileData(GAME, path, system); rootFd->addChild(file); //load the metadata //std::string defaultName = file->metadata.get("name"); std::string defaultName = "defaultName"; file->metadata = MetaDataList::createFromXML(GAME_METADATA, fileNode, relativeTo); //make sure name gets set if one didn't exist if(file->metadata.get("name").empty()) file->metadata.set("name", defaultName); } } */ }
FileData* findOrCreateFile(SystemData* system, const boost::filesystem::path& path, FileType type) { // first, verify that path is within the system's root folder FileData* root = system->getRootFolder(); bool contains = false; fs::path relative = removeCommonPath(path, root->getPath(), contains); if(!contains) { LOG(LogError) << "File path \"" << path << "\" is outside system path \"" << system->getStartPath() << "\""; return NULL; } auto path_it = relative.begin(); FileData* treeNode = root; bool found = false; while(path_it != relative.end()) { const std::vector<FileData*>& children = treeNode->getChildren(); found = false; for(auto child_it = children.begin(); child_it != children.end(); child_it++) { if((*child_it)->getPath().filename() == *path_it) { treeNode = *child_it; found = true; break; } } // this is the end if(path_it == --relative.end()) { if(found) return treeNode; if(type == FOLDER) { LOG(LogWarning) << "gameList: folder doesn't already exist, won't create"; return NULL; } //LOG(LogInfo) << "File type" << type << " File path \"" << path << "System " << system; FileData* file = new FileData(type, path, system); treeNode->addChild(file); return file; } if(!found) { // don't create folders unless it's leading up to a game // if type is a folder it's gonna be empty, so don't bother if(type == FOLDER) { LOG(LogWarning) << "gameList: folder doesn't already exist, won't create"; return NULL; } // create missing folder FileData* folder = new FileData(FOLDER, treeNode->getPath().stem() / *path_it, system); treeNode->addChild(folder); treeNode = folder; } path_it++; } return NULL; }