Combined FolderData and GameData into one class, FileData.

You don't need to dynamic_cast everywhere to check things anymore.
Folders can have metadata now (currently not set up).
Metadata is now a public member variable instead of a function that
returns a pointer to make actually using const possible.
This commit is contained in:
Aloshi 2013-11-05 19:41:49 -06:00
parent 5c65747551
commit 3a3471cfe8
26 changed files with 416 additions and 650 deletions

View file

@ -138,8 +138,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FolderData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/GameData.h
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.h
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.h
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.h
@ -198,8 +197,8 @@ set(ES_HEADERS
)
set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/FolderData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/GameData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.cpp

98
src/FileData.cpp Normal file
View file

@ -0,0 +1,98 @@
#include "FileData.h"
#include <boost/regex/v4/regex.hpp>
namespace fs = boost::filesystem;
std::string getCleanFileName(const fs::path& path)
{
return regex_replace(path.stem().generic_string(), boost::regex("\\((.*)\\)|\\[(.*)\\]"), "");
}
FileData::FileData(FileType type, const fs::path& path)
: mType(type), mPath(path), mParent(NULL), metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA) // metadata is REALLY set in the constructor!
{
// metadata needs at least a name field (since that's what getName() will return)
if(metadata.get("name").empty())
metadata.set("name", getCleanFileName(mPath));
}
FileData::~FileData()
{
if(mParent)
mParent->removeChild(this);
}
const std::string& FileData::getThumbnailPath() const
{
if(!metadata.get("thumbnail").empty())
return metadata.get("thumbnail");
else
return metadata.get("image");
}
std::vector<FileData*> FileData::getFilesRecursive(unsigned int typeMask) const
{
std::vector<FileData*> out;
for(auto it = mChildren.begin(); it != mChildren.end(); it++)
{
if((*it)->getType() & typeMask)
out.push_back(*it);
if((*it)->getChildren().size() > 0)
{
std::vector<FileData*> subchildren = (*it)->getFilesRecursive(typeMask);
out.insert(out.end(), subchildren.cbegin(), subchildren.cend());
}
}
return out;
}
void FileData::addChild(FileData* file)
{
assert(mType == FOLDER);
assert(file->getParent() == NULL);
mChildren.push_back(file);
file->mParent = this;
}
void FileData::removeChild(FileData* file)
{
assert(mType == FOLDER);
assert(file->getParent() == this);
for(auto it = mChildren.begin(); it != mChildren.end(); it++)
{
if(*it == file)
{
mChildren.erase(it);
return;
}
}
// File somehow wasn't in our children.
assert(false);
}
void FileData::sort(ComparisonFunction& comparator, bool ascending)
{
std::sort(mChildren.begin(), mChildren.end(), comparator);
for(auto it = mChildren.begin(); it != mChildren.end(); it++)
{
if((*it)->getChildren().size() > 0)
(*it)->sort(comparator, ascending);
}
if(!ascending)
std::reverse(mChildren.begin(), mChildren.end());
}
void FileData::sort(const SortType& type)
{
sort(*type.comparisonFunction, type.ascending);
}

View file

@ -1,17 +1,62 @@
#ifndef _FILEDATA_H_
#define _FILEDATA_H_
#pragma once
#include <vector>
#include <string>
#include <boost/filesystem.hpp>
#include "MetaData.h"
//This is a really basic class that the GameData and FolderData subclass from.
//This lets us keep everything in one vector and not have to differentiate between files and folders when we just want to check the name, etc.
enum FileType
{
GAME = 1, // Cannot have children.
FOLDER = 2
};
// Used for loading/saving gamelist.xml.
const char* fileTypeToString(FileType type);
FileType stringToFileType(const char* str);
std::string getCleanFileName(const boost::filesystem::path& path);
// A tree node that holds information for a file.
class FileData
{
public:
virtual ~FileData() { };
virtual bool isFolder() const = 0;
virtual const std::string& getName() const = 0;
virtual const std::string& getPath() const = 0;
FileData(FileType type, const boost::filesystem::path& path);
virtual ~FileData();
inline const std::string& getName() const { return metadata.get("name"); }
inline FileType getType() const { return mType; }
inline const boost::filesystem::path& getPath() const { return mPath; }
inline FileData* getParent() const { return mParent; }
inline const std::vector<FileData*>& getChildren() const { return mChildren; }
virtual const std::string& getThumbnailPath() const;
std::vector<FileData*> getFilesRecursive(unsigned int typeMask) const;
void addChild(FileData* file); // Error if mType != FOLDER
void removeChild(FileData* file); //Error if mType != FOLDER
typedef bool ComparisonFunction(const FileData* a, const FileData* b);
struct SortType
{
ComparisonFunction* comparisonFunction;
bool ascending;
std::string description;
SortType(ComparisonFunction* sortFunction, bool sortAscending, const std::string & sortDescription)
: comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {}
};
#endif
void sort(ComparisonFunction& comparator, bool ascending = true);
void sort(const SortType& type);
MetaDataList metadata;
private:
FileType mType;
boost::filesystem::path mPath;
FileData* mParent;
std::vector<FileData*> mChildren;
};

62
src/FileSorts.cpp Normal file
View file

@ -0,0 +1,62 @@
#include "FileSorts.h"
namespace FileSorts
{
const FileData::SortType typesArr[] = {
FileData::SortType(&compareFileName, true, "file name, ascending")
};
const std::vector<FileData::SortType> SortTypes(typesArr, typesArr + sizeof(typesArr)/sizeof(typesArr[0]));
//returns if file1 should come before file2
bool compareFileName(const FileData* file1, const FileData* file2)
{
std::string name1 = file1->getName();
std::string name2 = file2->getName();
//min of name1/name2 .length()s
unsigned int count = name1.length() > name2.length() ? name2.length() : name1.length();
for(unsigned int i = 0; i < count; i++)
{
if(toupper(name1[i]) != toupper(name2[i]))
{
return toupper(name1[i]) < toupper(name2[i]);
}
}
return name1.length() < name2.length();
}
bool compareRating(const FileData* file1, const FileData* file2)
{
//only games have rating metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
{
return file1->metadata.getFloat("rating") < file2->metadata.getFloat("rating");
}
return false;
}
bool compareTimesPlayed(const FileData* file1, const FileData* file2)
{
//only games have playcount metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
{
return (file1)->metadata.getInt("playcount") < (file2)->metadata.getInt("playcount");
}
return false;
}
bool compareLastPlayed(const FileData* file1, const FileData* file2)
{
//only games have lastplayed metadata
if(file1->metadata.getType() == GAME_METADATA && file2->metadata.getType() == GAME_METADATA)
{
return (file1)->metadata.getTime("lastplayed") < (file2)->metadata.getTime("lastplayed");
}
return false;
}
};

14
src/FileSorts.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include <vector>
#include "FileData.h"
namespace FileSorts
{
bool compareFileName(const FileData* file1, const FileData* file2);
bool compareRating(const FileData* file1, const FileData* file2);
bool compareTimesPlayed(const FileData* file1, const FileData* fil2);
bool compareLastPlayed(const FileData* file1, const FileData* file2);
extern const std::vector<FileData::SortType> SortTypes;
};

View file

@ -1,196 +0,0 @@
#include "FolderData.h"
#include "SystemData.h"
#include "GameData.h"
#include <algorithm>
#include <iostream>
std::map<FolderData::ComparisonFunction*, std::string> FolderData::sortStateNameMap;
bool FolderData::isFolder() const { return true; }
const std::string & FolderData::getName() const { return mName; }
const std::string & FolderData::getPath() const { return mPath; }
unsigned int FolderData::getFileCount() { return mFileVector.size(); }
FolderData::FolderData(SystemData* system, std::string path, std::string name)
: mSystem(system), mPath(path), mName(name)
{
//first created folder data initializes the list
if (sortStateNameMap.empty()) {
sortStateNameMap[compareFileName] = "file name";
sortStateNameMap[compareRating] = "rating";
sortStateNameMap[compareTimesPlayed] = "times played";
sortStateNameMap[compareLastPlayed] = "last time played";
}
}
FolderData::~FolderData()
{
for(unsigned int i = 0; i < mFileVector.size(); i++)
{
delete mFileVector.at(i);
}
mFileVector.clear();
}
void FolderData::pushFileData(FileData* file)
{
mFileVector.push_back(file);
}
//sort this folder and any subfolders
void FolderData::sort(ComparisonFunction & comparisonFunction, bool ascending)
{
std::sort(mFileVector.begin(), mFileVector.end(), comparisonFunction);
for(unsigned int i = 0; i < mFileVector.size(); i++)
{
if(mFileVector.at(i)->isFolder())
((FolderData*)mFileVector.at(i))->sort(comparisonFunction, ascending);
}
if (!ascending) {
std::reverse(mFileVector.begin(), mFileVector.end());
}
}
//returns if file1 should come before file2
bool FolderData::compareFileName(const FileData* file1, const FileData* file2)
{
std::string name1 = file1->getName();
std::string name2 = file2->getName();
//min of name1/name2 .length()s
unsigned int count = name1.length() > name2.length() ? name2.length() : name1.length();
for(unsigned int i = 0; i < count; i++)
{
if(toupper(name1[i]) != toupper(name2[i]))
{
return toupper(name1[i]) < toupper(name2[i]);
}
}
return name1.length() < name2.length();
}
bool FolderData::compareRating(const FileData* file1, const FileData* file2)
{
//we need game data. try to cast
const GameData * game1 = dynamic_cast<const GameData*>(file1);
const GameData * game2 = dynamic_cast<const GameData*>(file2);
if (game1 != nullptr && game2 != nullptr) {
return const_cast<GameData*>(game1)->metadata()->getFloat("rating") < const_cast<GameData*>(game2)->metadata()->getFloat("rating");
}
return false;
}
bool FolderData::compareTimesPlayed(const FileData* file1, const FileData* file2)
{
//we need game data. try to cast
const GameData * game1 = dynamic_cast<const GameData*>(file1);
const GameData * game2 = dynamic_cast<const GameData*>(file2);
if (game1 != nullptr && game2 != nullptr) {
return const_cast<GameData*>(game1)->metadata()->getInt("playcount") < const_cast<GameData*>(game2)->metadata()->getInt("playcount");
}
return false;
}
bool FolderData::compareLastPlayed(const FileData* file1, const FileData* file2)
{
//we need game data. try to cast
const GameData * game1 = dynamic_cast<const GameData*>(file1);
const GameData * game2 = dynamic_cast<const GameData*>(file2);
if (game1 != nullptr && game2 != nullptr) {
return const_cast<GameData*>(game1)->metadata()->getTime("lastplayed") < const_cast<GameData*>(game2)->metadata()->getTime("lastplayed");
}
return false;
}
std::string FolderData::getSortStateName(ComparisonFunction & comparisonFunction, bool ascending)
{
std::string temp = sortStateNameMap[comparisonFunction];
if (ascending) {
temp.append(" (ascending)");
}
else {
temp.append(" (descending)");
}
return temp;
}
FileData* FolderData::getFile(unsigned int i) const
{
return mFileVector.at(i);
}
std::vector<FileData*> FolderData::getFiles(bool onlyFiles) const
{
std::vector<FileData*> temp;
//now check if a child is a folder and get those children in turn
std::vector<FileData*>::const_iterator fdit = mFileVector.cbegin();
while(fdit != mFileVector.cend()) {
//dynamically try to cast to FolderData type
FolderData * folder = dynamic_cast<FolderData*>(*fdit);
if (folder != nullptr) {
//add this only when user wanted it
if (!onlyFiles) {
temp.push_back(*fdit);
}
}
else {
temp.push_back(*fdit);
}
++fdit;
}
return temp;
}
std::vector<FileData*> FolderData::getFilesRecursive(bool onlyFiles) const
{
std::vector<FileData*> temp;
//now check if a child is a folder and get those children in turn
std::vector<FileData*>::const_iterator fdit = mFileVector.cbegin();
while(fdit != mFileVector.cend()) {
//dynamically try to cast to FolderData type
FolderData * folder = dynamic_cast<FolderData*>(*fdit);
if (folder != nullptr) {
//add this onyl when user wanted it
if (!onlyFiles) {
temp.push_back(*fdit);
}
//worked. Is actual folder data. recurse
std::vector<FileData*> children = folder->getFilesRecursive(onlyFiles);
//insert children into return vector
temp.insert(temp.end(), children.cbegin(), children.cend());
}
else {
temp.push_back(*fdit);
}
++fdit;
}
return temp;
}
void FolderData::removeFileRecursive(FileData* f)
{
auto iter = mFileVector.begin();
while(iter != mFileVector.end())
{
if(*iter == f)
{
delete *iter;
iter = mFileVector.erase(iter);
}else{
FolderData* folder = dynamic_cast<FolderData*>(*iter);
if(folder)
{
folder->removeFileRecursive(f);
}
iter++;
}
}
}

View file

@ -1,60 +0,0 @@
#ifndef _FOLDER_H_
#define _FOLDER_H_
#include <map>
#include <vector>
#include "FileData.h"
class SystemData;
//This class lets us hold a vector of FileDatas within under a common name.
class FolderData : public FileData
{
public:
typedef bool ComparisonFunction(const FileData* a, const FileData* b);
struct SortState
{
ComparisonFunction & comparisonFunction;
bool ascending;
std::string description;
SortState(ComparisonFunction & sortFunction, bool sortAscending, const std::string & sortDescription) : comparisonFunction(sortFunction), ascending(sortAscending), description(sortDescription) {}
};
private:
static std::map<ComparisonFunction*, std::string> sortStateNameMap;
public:
FolderData(SystemData* system, std::string path, std::string name);
~FolderData();
bool isFolder() const;
const std::string & getName() const;
const std::string & getPath() const;
unsigned int getFileCount();
FileData* getFile(unsigned int i) const;
std::vector<FileData*> getFiles(bool onlyFiles = false) const;
std::vector<FileData*> getFilesRecursive(bool onlyFiles = false) const;
void removeFileRecursive(FileData* file);
void pushFileData(FileData* file);
void sort(ComparisonFunction & comparisonFunction = compareFileName, bool ascending = true);
static bool compareFileName(const FileData* file1, const FileData* file2);
static bool compareRating(const FileData* file1, const FileData* file2);
static bool compareTimesPlayed(const FileData* file1, const FileData* file2);
static bool compareLastPlayed(const FileData* file1, const FileData* file2);
static std::string getSortStateName(ComparisonFunction & comparisonFunction = compareFileName, bool ascending = true);
private:
SystemData* mSystem;
std::string mPath;
std::string mName;
std::vector<FileData*> mFileVector;
};
#endif

View file

@ -1,84 +0,0 @@
#include "GameData.h"
#include <boost/filesystem.hpp>
#include <boost/regex/v4/regex.hpp>
#include <iostream>
#include <ctime>
#include <sstream>
GameData::GameData(const std::string& path, const MetaDataList& metadata)
: mPath(path), mBaseName(boost::filesystem::path(path).stem().string()), mMetaData(metadata)
{
if(mMetaData.get("name").empty())
mMetaData.set("name", mBaseName);
}
bool GameData::isFolder() const
{
return false;
}
const std::string& GameData::getName() const
{
return mMetaData.get("name");
}
const std::string& GameData::getPath() const
{
return mPath;
}
std::string GameData::getBashPath() const
{
//a quick and dirty way to insert a backslash before most characters that would mess up a bash path
std::string path = getPath();
const char* invalidChars = " '\"\\!$^&*(){}[]?;<>";
for(unsigned int i = 0; i < path.length(); i++)
{
char c;
unsigned int charNum = 0;
do {
c = invalidChars[charNum];
if(path[i] == c)
{
path.insert(i, "\\");
i++;
break;
}
charNum++;
} while(c != '\0');
}
return path;
}
//returns the boost::filesystem stem of our path - e.g. for "/foo/bar.rom" returns "bar"
std::string GameData::getBaseName() const
{
return mBaseName;
}
std::string GameData::getCleanName() const
{
return regex_replace(mBaseName, boost::regex("\\((.*)\\)|\\[(.*)\\]"), "");
}
void GameData::incTimesPlayed()
{
int timesPlayed = metadata()->getInt("playcount");
timesPlayed++;
std::stringstream ss;
metadata()->set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
}
void GameData::lastPlayedNow()
{
boost::posix_time::ptime time = boost::posix_time::second_clock::universal_time();
metadata()->setTime("lastplayed", time);
}
MetaDataList* GameData::metadata()
{
return &mMetaData;
}

View file

@ -1,36 +0,0 @@
#ifndef _GAMEDATA_H_
#define _GAMEDATA_H_
#include <string>
#include "FileData.h"
#include "MetaData.h"
//This class holds information about a game: at the least, its name, system, and path. Additional information is optional and read by other classes.
class GameData : public FileData
{
public:
GameData(const std::string& path, const MetaDataList& metadata);
const std::string& getName() const override;
const std::string& getPath() const override;
void incTimesPlayed();
void lastPlayedNow();
std::string getBashPath() const;
std::string getBaseName() const;
std::string getCleanName() const;
bool isFolder() const override;
MetaDataList* metadata();
private:
const std::string mPath;
const std::string mBaseName;
MetaDataList mMetaData;
};
#endif

View file

@ -141,7 +141,7 @@ int run_scraper_cmdline()
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
for(auto sysIt = systems.begin(); sysIt != systems.end(); sysIt++)
{
std::vector<FileData*> files = (*sysIt)->getRootFolder()->getFilesRecursive(true);
std::vector<FileData*> files = (*sysIt)->getRootFolder()->getFilesRecursive(GAME);
ScraperSearchParams params;
params.system = (*sysIt);
@ -149,15 +149,15 @@ int run_scraper_cmdline()
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
{
params.nameOverride = "";
params.game = (GameData*)(*gameIt);
params.game = *gameIt;
//print original search term
out << params.game->getCleanName() << "...\n";
out << getCleanFileName(params.game->getPath()) << "...\n";
//need to take into account filter_choice
if(filter_choice == FILTER_MISSING_IMAGES)
{
if(!params.game->metadata()->get("image").empty()) //maybe should also check if the image file exists/is a URL
if(!params.game->metadata.get("image").empty()) //maybe should also check if the image file exists/is a URL
{
out << " Skipping, metadata \"image\" entry is not empty.\n";
continue;
@ -212,7 +212,7 @@ int run_scraper_cmdline()
if(choice >= 0 && choice < (int)mdls.size())
{
*params.game->metadata() = mdls.at(choice);
params.game->metadata = mdls.at(choice);
break;
}else{
out << "Invalid choice.\n";
@ -223,7 +223,7 @@ int run_scraper_cmdline()
//automatic mode
//always choose the first choice
out << " name -> " << mdls.at(0).get("name") << "\n";
*params.game->metadata() = mdls.at(0);
params.game->metadata = mdls.at(0);
break;
}
@ -238,32 +238,32 @@ int run_scraper_cmdline()
for(auto sysIt = systems.begin(); sysIt != systems.end(); sysIt++)
{
std::vector<FileData*> files = (*sysIt)->getRootFolder()->getFilesRecursive(true);
std::vector<FileData*> files = (*sysIt)->getRootFolder()->getFilesRecursive(GAME);
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
{
GameData* game = (GameData*)(*gameIt);
const std::vector<MetaDataDecl>& mdd = game->metadata()->getMDD();
FileData* game = *gameIt;
const std::vector<MetaDataDecl>& mdd = game->metadata.getMDD();
for(auto i = mdd.begin(); i != mdd.end(); i++)
{
std::string key = i->key;
std::string url = game->metadata()->get(key);
std::string url = game->metadata.get(key);
if(i->type == MD_IMAGE_PATH && HttpReq::isUrl(url))
{
std::string urlShort = url.substr(0, url.length() > 35 ? 35 : url.length());
if(url.length() != urlShort.length()) urlShort += "...";
out << " " << game->metadata()->get("name") << " [from: " << urlShort << "]...\n";
out << " " << game->metadata.get("name") << " [from: " << urlShort << "]...\n";
ScraperSearchParams p;
p.game = game;
p.system = *sysIt;
game->metadata()->set(key, downloadImage(url, getSaveAsPath(p, key, url)));
if(game->metadata()->get(key).empty())
game->metadata.set(key, downloadImage(url, getSaveAsPath(p, key, url)));
if(game->metadata.get(key).empty())
{
out << " FAILED! Skipping.\n";
game->metadata()->set(key, url); //result URL to what it was if download failed, retry some other time
game->metadata.set(key, url); //result URL to what it was if download failed, retry some other time
}
}
}

View file

@ -1,5 +1,4 @@
#include "SystemData.h"
#include "GameData.h"
#include "XMLReader.h"
#include <boost/filesystem.hpp>
#include <fstream>
@ -12,14 +11,12 @@
#include "InputManager.h"
#include <iostream>
#include "Settings.h"
#include "FileSorts.h"
std::vector<SystemData*> SystemData::sSystemVector;
namespace fs = boost::filesystem;
std::string SystemData::getStartPath() { return mStartPath; }
std::vector<std::string> SystemData::getExtensions() { return mSearchExtensions; }
SystemData::SystemData(const std::string& name, const std::string& fullName, const std::string& startPath, const std::vector<std::string>& extensions,
const std::string& command, PlatformIds::PlatformId platformId)
{
@ -38,7 +35,8 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, con
mLaunchCommand = command;
mPlatformId = platformId;
mRootFolder = new FolderData(this, mStartPath, "Search Root");
mRootFolder = new FileData(FOLDER, mStartPath);
mRootFolder->metadata.set("name", "Search Root");
if(!Settings::getInstance()->getBool("PARSEGAMELISTONLY"))
populateFolder(mRootFolder);
@ -46,15 +44,17 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, con
if(!Settings::getInstance()->getBool("IGNOREGAMELIST"))
parseGamelist(this);
mRootFolder->sort();
mRootFolder->sort(FileSorts::SortTypes.at(0));
}
SystemData::~SystemData()
{
//save changed game data back to xml
if(!Settings::getInstance()->getBool("IGNOREGAMELIST")) {
if(!Settings::getInstance()->getBool("IGNOREGAMELIST"))
{
updateGamelist(this);
}
delete mRootFolder;
}
@ -68,7 +68,33 @@ std::string strreplace(std::string& str, std::string replace, std::string with)
return str;
}
void SystemData::launchGame(Window* window, GameData* game)
std::string escapePath(const boost::filesystem::path& path)
{
// a quick and dirty way to insert a backslash before most characters that would mess up a bash path;
// someone with regex knowledge should make this into a one-liner
std::string pathStr = path.generic_string();
const char* invalidChars = " '\"\\!$^&*(){}[]?;<>";
for(unsigned int i = 0; i < pathStr.length(); i++)
{
char c;
unsigned int charNum = 0;
do {
c = invalidChars[charNum];
if(pathStr[i] == c)
{
pathStr.insert(i, "\\");
i++;
break;
}
charNum++;
} while(c != '\0');
}
return pathStr;
}
void SystemData::launchGame(Window* window, FileData* game)
{
LOG(LogInfo) << "Attempting to launch game...";
@ -78,9 +104,13 @@ void SystemData::launchGame(Window* window, GameData* game)
std::string command = mLaunchCommand;
command = strreplace(command, "%ROM%", game->getBashPath());
command = strreplace(command, "%BASENAME%", game->getBaseName());
command = strreplace(command, "%ROM_RAW%", game->getPath());
const std::string rom = escapePath(game->getPath());
const std::string basename = game->getPath().stem().string();
const std::string rom_raw = game->getPath().string();
command = strreplace(command, "%ROM%", rom);
command = strreplace(command, "%BASENAME%", basename);
command = strreplace(command, "%ROM_RAW%", rom_raw);
LOG(LogInfo) << " " << command;
std::cout << "==============================================\n";
@ -97,25 +127,31 @@ void SystemData::launchGame(Window* window, GameData* game)
AudioManager::getInstance()->init();
window->normalizeNextUpdate();
//update number of times the game has been launched and the time
game->incTimesPlayed();
game->lastPlayedNow();
//update number of times the game has been launched
int timesPlayed = game->metadata.getInt("playcount") + 1;
game->metadata.set("playcount", std::to_string(static_cast<long long>(timesPlayed)));
//update last played time
boost::posix_time::ptime time = boost::posix_time::second_clock::universal_time();
game->metadata.setTime("lastplayed", time);
}
void SystemData::populateFolder(FolderData* folder)
void SystemData::populateFolder(FileData* folder)
{
std::string folderPath = folder->getPath();
const fs::path& folderPath = folder->getPath();
if(!fs::is_directory(folderPath))
{
LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!";
return;
}
const std::string folderStr = folderPath.generic_string();
//make sure that this isn't a symlink to a thing we already have
if(fs::is_symlink(folderPath))
{
//if this symlink resolves to somewhere that's at the beginning of our path, it's gonna recurse
if(folderPath.find(fs::canonical(folderPath).string()) == 0)
if(folderStr.find(fs::canonical(folderPath).generic_string()) == 0)
{
LOG(LogWarning) << "Skipping infinitely recursive symlink \"" << folderPath << "\"";
return;
@ -142,39 +178,26 @@ void SystemData::populateFolder(FolderData* folder)
isGame = false;
if(std::find(mSearchExtensions.begin(), mSearchExtensions.end(), extension) != mSearchExtensions.end())
{
GameData* newGame = new GameData(filePath.generic_string(), MetaDataList(GAME_METADATA));
folder->pushFileData(newGame);
FileData* newGame = new FileData(GAME, filePath.generic_string());
folder->addChild(newGame);
isGame = true;
}
//add directories that also do not match an extension as folders
if(!isGame && fs::is_directory(filePath))
{
FolderData* newFolder = new FolderData(this, filePath.generic_string(), filePath.stem().string());
FileData* newFolder = new FileData(FOLDER, filePath.generic_string());
populateFolder(newFolder);
//ignore folders that do not contain games
if(newFolder->getFileCount() == 0)
if(newFolder->getChildren().size() == 0)
delete newFolder;
else
folder->pushFileData(newFolder);
folder->addChild(newFolder);
}
}
}
std::string SystemData::getName()
{
return mName;
}
std::string SystemData::getFullName()
{
if(mFullName.empty())
return mName;
else
return mFullName;
}
//creates systems from information located in a config file
bool SystemData::loadConfig(const std::string& path, bool writeExample)
{
@ -241,7 +264,7 @@ bool SystemData::loadConfig(const std::string& path, bool writeExample)
path = genericPath.generic_string();
SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformId);
if(newSys->getRootFolder()->getFileCount() == 0)
if(newSys->getRootFolder()->getChildren().size() == 0)
{
LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it.";
delete newSys;
@ -312,22 +335,16 @@ std::string SystemData::getConfigPath()
return(home + "/.emulationstation/es_systems.cfg");
}
FolderData* SystemData::getRootFolder()
std::string SystemData::getGamelistPath() const
{
return mRootFolder;
}
fs::path filePath;
std::string SystemData::getGamelistPath()
{
std::string filePath;
filePath = mRootFolder->getPath() + "/gamelist.xml";
filePath = mRootFolder->getPath() / "gamelist.xml";
if(fs::exists(filePath))
return filePath;
return filePath.generic_string();
filePath = getHomePath();
filePath += "/.emulationstation/"+ getName() + "/gamelist.xml";
return filePath;
filePath = getHomePath() + "/.emulationstation/"+ getName() + "/gamelist.xml";
return filePath.generic_string();
}
bool SystemData::hasGamelist()
@ -335,12 +352,7 @@ bool SystemData::hasGamelist()
return (fs::exists(getGamelistPath()));
}
PlatformIds::PlatformId SystemData::getPlatformId()
unsigned int SystemData::getGameCount() const
{
return mPlatformId;
}
unsigned int SystemData::getGameCount()
{
return mRootFolder->getFilesRecursive(true).size();
return mRootFolder->getFilesRecursive(GAME).size();
}

View file

@ -3,13 +3,11 @@
#include <vector>
#include <string>
#include "FolderData.h"
#include "FileData.h"
#include "Window.h"
#include "MetaData.h"
#include "PlatformId.h"
class GameData;
class SystemData
{
public:
@ -17,20 +15,19 @@ public:
const std::string& command, PlatformIds::PlatformId platformId = PlatformIds::PLATFORM_UNKNOWN);
~SystemData();
FolderData* getRootFolder();
inline FileData* getRootFolder() const { return mRootFolder; };
inline const std::string& getName() const { return mName; }
inline const std::string& getFullName() const { return mFullName; }
inline const std::string& getStartPath() const { return mStartPath; }
inline const std::vector<std::string>& getExtensions() const { return mSearchExtensions; }
inline PlatformIds::PlatformId getPlatformId() const { return mPlatformId; }
std::string getName();
std::string getFullName();
std::string getStartPath();
std::vector<std::string> getExtensions();
PlatformIds::PlatformId getPlatformId();
std::string getGamelistPath();
std::string getGamelistPath() const;
bool hasGamelist();
unsigned int getGameCount();
unsigned int getGameCount() const;
void launchGame(Window* window, GameData* game);
void launchGame(Window* window, FileData* game);
static void deleteSystems();
static bool loadConfig(const std::string& path, bool writeExampleIfNonexistant = true); //Load the system config file at getConfigPath(). Returns true if no errors were encountered. An example can be written if the file doesn't exist.
@ -38,6 +35,7 @@ public:
static std::string getConfigPath();
static std::vector<SystemData*> sSystemVector;
private:
std::string mName;
std::string mFullName;
@ -46,10 +44,9 @@ private:
std::string mLaunchCommand;
PlatformIds::PlatformId mPlatformId;
void populateFolder(FolderData* folder);
void populateFolder(FileData* folder);
FolderData* mRootFolder;
FileData* mRootFolder;
};
#endif

View file

@ -1,6 +1,5 @@
#include "XMLReader.h"
#include "SystemData.h"
#include "GameData.h"
#include "pugiXML/pugixml.hpp"
#include <boost/filesystem.hpp>
#include "Log.h"
@ -8,27 +7,25 @@
//this is obviously an incredibly inefficient way to go about searching
//but I don't think it'll matter too much with the size of most collections
GameData* searchFolderByPath(FolderData* folder, std::string const& path)
FileData* searchFolderByPath(FileData* folder, std::string const& path)
{
for(unsigned int i = 0; i < folder->getFileCount(); i++)
for(auto it = folder->getChildren().begin(); it != folder->getChildren().end(); it++)
{
FileData* file = folder->getFile(i);
if(file->isFolder())
if((*it)->getType() == FOLDER)
{
GameData* result = searchFolderByPath((FolderData*)file, path);
FileData* result = searchFolderByPath(*it, path);
if(result)
return (GameData*)result;
return result;
}else{
if(file->getPath() == path)
return (GameData*)file;
if((*it)->getPath().generic_string() == path)
return *it;
}
}
return NULL;
}
GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
FileData* createGameFromPath(std::string gameAbsPath, SystemData* system)
{
std::string gamePath = gameAbsPath;
std::string sysPath = system->getStartPath();
@ -46,11 +43,10 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
//make our way through the directory tree finding each folder in our path or creating it if it doesn't exist
FolderData* folder = system->getRootFolder();
FileData* folder = system->getRootFolder();
size_t separator = 0;
size_t nextSeparator = 0;
unsigned int loops = 0;
while(nextSeparator != std::string::npos)
{
//determine which chunk of the path we're testing right now
@ -63,12 +59,11 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
//see if the folder already exists
bool foundFolder = false;
for(unsigned int i = 0; i < folder->getFileCount(); i++)
for(auto it = folder->getChildren().begin(); it != folder->getChildren().end(); it++)
{
FileData* checkFolder = folder->getFile(i);
if(checkFolder->isFolder() && checkFolder->getName() == checkName)
if((*it)->getType() == FOLDER && (*it)->getName() == checkName)
{
folder = (FolderData*)checkFolder;
folder = *it;
foundFolder = true;
break;
}
@ -77,22 +72,14 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
//the folder didn't already exist, so create it
if(!foundFolder)
{
FolderData* newFolder = new FolderData(system, folder->getPath() + "/" + checkName, checkName);
folder->pushFileData(newFolder);
FileData* newFolder = new FileData(FOLDER, folder->getPath() / checkName);
folder->addChild(newFolder);
folder = newFolder;
}
//if for some reason this function is broken, break out of this while instead of freezing
if(loops > gamePath.length() * 2)
{
LOG(LogError) << "createGameFromPath breaking out of loop for path \"" << gamePath << "\" to prevent infinite loop (please report this)";
break;
}
loops++;
}
GameData* game = new GameData(gameAbsPath, MetaDataList(GAME_METADATA));
folder->pushFileData(game);
FileData* game = new FileData(GAME, gameAbsPath);
folder->addChild(game);
return game;
}
@ -150,40 +137,41 @@ void parseGamelist(SystemData* system)
if(boost::filesystem::exists(path))
{
GameData* game = searchFolderByPath(system->getRootFolder(), path);
FileData* game = searchFolderByPath(system->getRootFolder(), path);
if(game == NULL)
game = createGameFromPath(path, system);
//load the metadata
*(game->metadata()) = MetaDataList::createFromXML(GAME_METADATA, gameNode);
std::string defaultName = game->metadata.get("name");
game->metadata = MetaDataList::createFromXML(GAME_METADATA, gameNode);
//make sure name gets set if one didn't exist
if(game->metadata()->get("name").empty())
game->metadata()->set("name", game->getBaseName());
if(game->metadata.get("name").empty())
game->metadata.set("name", defaultName);
}else{
LOG(LogWarning) << "Game at \"" << path << "\" does not exist!";
}
}
}
void addGameDataNode(pugi::xml_node& parent, const GameData* game, SystemData* system)
void addGameDataNode(pugi::xml_node& parent, const FileData* game, SystemData* system)
{
//create game and add to parent node
pugi::xml_node newGame = parent.append_child("game");
//write metadata
const_cast<GameData*>(game)->metadata()->appendToXML(newGame, true);
game->metadata.appendToXML(newGame, true);
if(newGame.children().begin() == newGame.child("name") //first element is name
&& ++newGame.children().begin() == newGame.children().end() //theres only one element
&& newGame.child("name").text().get() == game->getBaseName()) //the name is the default
&& newGame.child("name").text().get() == getCleanFileName(game->getPath())) //the name is the default
{
//if the only info is the default name, don't bother with this node
parent.remove_child(newGame);
}else{
//there's something useful in there so we'll keep the node, add the path
newGame.prepend_child("path").text().set(game->getPath().c_str());
newGame.prepend_child("path").text().set(game->getPath().generic_string().c_str());
}
}
@ -230,18 +218,16 @@ void updateGamelist(SystemData* system)
}
//now we have all the information from the XML. now iterate through all our games and add information from there
FolderData * rootFolder = system->getRootFolder();
FileData* rootFolder = system->getRootFolder();
if (rootFolder != nullptr)
{
//get only files, no folders
std::vector<FileData*> files = rootFolder->getFilesRecursive(true);
std::vector<FileData*> files = rootFolder->getFilesRecursive(GAME);
//iterate through all files, checking if they're already in the XML
std::vector<FileData*>::const_iterator fit = files.cbegin();
while(fit != files.cend())
{
//try to cast to gamedata
const GameData * game = dynamic_cast<const GameData*>(*fit);
if (game != nullptr)
if((*fit)->getType() == GAME)
{
//worked. check if this games' path can be found somewhere in the XML
for(pugi::xml_node gameNode = root.child("game"); gameNode; gameNode = gameNode.next_sibling("game"))
@ -256,7 +242,7 @@ void updateGamelist(SystemData* system)
//check paths. use the same directory separators
boost::filesystem::path nodePath(pathNode.text().get());
boost::filesystem::path gamePath(game->getPath());
boost::filesystem::path gamePath((*fit)->getPath());
if (nodePath.generic_string() == gamePath.generic_string())
{
//found the game. remove it. it will be added again later with updated values
@ -268,7 +254,7 @@ void updateGamelist(SystemData* system)
//either the game content was removed, because it needs to be updated,
//or didn't exist in the first place, so just add it
addGameDataNode(root, game, system);
addGameDataNode(root, *fit, system);
}
++fit;
}

View file

@ -2,6 +2,7 @@
#include "../Renderer.h"
#include <iostream>
#include "GuiGameList.h"
#include "../FileSorts.h"
#define DEFAULT_FS_IMAGE ":/frame.png"
@ -9,6 +10,8 @@ const std::string GuiFastSelect::LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const int GuiFastSelect::SCROLLSPEED = 100;
const int GuiFastSelect::SCROLLDELAY = 507;
int GuiFastSelect::sortTypeId = 0;
GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent<FileData*>* list, char startLetter, ThemeComponent * theme)
: GuiComponent(window), mParent(parent), mList(list), mTheme(theme), mBox(mWindow, "")
{
@ -60,7 +63,7 @@ void GuiFastSelect::render(const Eigen::Affine3f& parentTrans)
letterFont->drawCenteredText(LETTERS.substr(mLetterID, 1), 0, sh * 0.5f - (letterFont->getHeight() * 0.5f), mTextColor);
subtextFont->drawCenteredText("Sort order:", 0, sh * 0.6f - (subtextFont->getHeight() * 0.5f), mTextColor);
std::string sortString = "<- " + mParent->getSortState().description + " ->";
std::string sortString = "<- " + FileSorts::SortTypes.at(sortTypeId).description + " ->";
subtextFont->drawCenteredText(sortString, 0, sh * 0.6f + (subtextFont->getHeight() * 0.5f), mTextColor);
}
@ -82,13 +85,16 @@ bool GuiFastSelect::input(InputConfig* config, Input input)
if(config->isMappedTo("left", input) && input.value != 0)
{
mParent->setPreviousSortIndex();
sortTypeId--;
if(sortTypeId < 0)
sortTypeId = FileSorts::SortTypes.size() - 1;
mScrollSound->play();
return true;
}
else if(config->isMappedTo("right", input) && input.value != 0)
{
mParent->setNextSortIndex();
sortTypeId = (sortTypeId + 1) % FileSorts::SortTypes.size();
mScrollSound->play();
return true;
}
@ -104,6 +110,7 @@ bool GuiFastSelect::input(InputConfig* config, Input input)
if(config->isMappedTo("select", input) && input.value == 0)
{
setListPos();
mParent->sort(FileSorts::SortTypes.at(sortTypeId));
delete this;
return true;
}

View file

@ -3,7 +3,6 @@
#include "../GuiComponent.h"
#include "../SystemData.h"
#include "../FolderData.h"
#include "../Sound.h"
#include "ThemeComponent.h"
#include "TextListComponent.h"
@ -11,6 +10,7 @@
class GuiGameList;
class GuiFastSelect : public GuiComponent
{
public:
@ -26,6 +26,8 @@ private:
static const int SCROLLSPEED;
static const int SCROLLDELAY;
static int sortTypeId;
void setListPos();
void scroll();
void setLetterID(int id);

View file

@ -10,8 +10,6 @@
#include "GuiMetaDataEd.h"
#include "GuiScraperStart.h"
std::vector<FolderData::SortState> GuiGameList::sortStates;
Eigen::Vector3f GuiGameList::getImagePos()
{
return Eigen::Vector3f(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX"), Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"), 0.0f);
@ -23,15 +21,11 @@ bool GuiGameList::isDetailed() const
return false;
//return true if any game has an image specified
for(unsigned int i = 0; i < mFolder->getFileCount(); i++)
for(auto it = mFolder->getChildren().begin(); it != mFolder->getChildren().end(); it++)
{
if(!mFolder->getFile(i)->isFolder())
{
GameData* game = (GameData*)(mFolder->getFile(i));
if(!game->metadata()->get("image").empty())
if(!(*it)->getThumbnailPath().empty())
return true;
}
}
return false;
}
@ -47,22 +41,9 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
mDescContainer(window),
mTransitionImage(window, 0.0f, 0.0f, "", (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), true),
mHeaderText(mWindow),
sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")),
mLockInput(false),
mEffectFunc(NULL), mEffectTime(0), mGameLaunchEffectLength(700)
{
//first object initializes the vector
if (sortStates.empty()) {
sortStates.push_back(FolderData::SortState(FolderData::compareFileName, true, "file name, ascending"));
sortStates.push_back(FolderData::SortState(FolderData::compareFileName, false, "file name, descending"));
sortStates.push_back(FolderData::SortState(FolderData::compareRating, true, "rating, ascending"));
sortStates.push_back(FolderData::SortState(FolderData::compareRating, false, "rating, descending"));
sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, true, "played least often"));
sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, false, "played most often"));
sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, true, "played least recently"));
sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, false, "played most recently"));
}
mImageAnimation.addChild(&mScreenshot);
mDescContainer.addChild(&mReleaseDateLabel);
mDescContainer.addChild(&mReleaseDate);
@ -142,18 +123,18 @@ bool GuiGameList::input(InputConfig* config, Input input)
if(input.id == SDLK_F3)
{
GameData* game = dynamic_cast<GameData*>(mList.getSelectedObject());
if(game)
FileData* game = mList.getSelectedObject();
if(game->getType() == GAME)
{
FolderData* root = mSystem->getRootFolder();
FileData* root = mSystem->getRootFolder();
ScraperSearchParams searchParams;
searchParams.game = game;
searchParams.system = mSystem;
mWindow->pushGui(new GuiMetaDataEd(mWindow, game->metadata(), game->metadata()->getMDD(), searchParams, game->getBaseName(),
mWindow->pushGui(new GuiMetaDataEd(mWindow, &game->metadata, game->metadata.getMDD(), searchParams, game->getPath().stem().string(),
[&] { updateDetailData(); },
[game, root, this] {
boost::filesystem::remove(game->getPath());
root->removeFileRecursive(game);
root->removeChild(game);
updateList();
}));
}
@ -166,16 +147,16 @@ bool GuiGameList::input(InputConfig* config, Input input)
return true;
}
if(config->isMappedTo("a", input) && mFolder->getFileCount() > 0 && input.value != 0)
if(config->isMappedTo("a", input) && input.value != 0)
{
//play select sound
mTheme->getSound("menuSelect")->play();
FileData* file = mList.getSelectedObject();
if(file->isFolder()) //if you selected a folder, add this directory to the stack, and use the selected one
if(file->getType() == FOLDER) //if you selected a folder, add this directory to the stack, and use the selected one
{
mFolderStack.push(mFolder);
mFolder = (FolderData*)file;
mFolder = file;
updateList();
updateDetailData();
return true;
@ -225,16 +206,6 @@ bool GuiGameList::input(InputConfig* config, Input input)
}
}
//change sort order
if(config->isMappedTo("sortordernext", input) && input.value != 0) {
setNextSortIndex();
//std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl;
}
else if(config->isMappedTo("sortorderprevious", input) && input.value != 0) {
setPreviousSortIndex();
//std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl;
}
//open the "start menu"
if(config->isMappedTo("menu", input) && input.value != 0)
{
@ -264,48 +235,10 @@ bool GuiGameList::input(InputConfig* config, Input input)
return false;
}
const FolderData::SortState & GuiGameList::getSortState() const
{
return sortStates.at(sortStateIndex);
}
void GuiGameList::setSortIndex(size_t index)
{
//make the index valid
if (index >= sortStates.size()) {
index = 0;
}
if (index != sortStateIndex) {
//get sort state from vector and sort list
sortStateIndex = index;
sort(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending);
}
//save new index to settings
Settings::getInstance()->setInt("GameListSortIndex", sortStateIndex);
}
void GuiGameList::setNextSortIndex()
{
//make the index wrap around
if ((sortStateIndex - 1) >= sortStates.size()) {
setSortIndex(0);
}
setSortIndex(sortStateIndex + 1);
}
void GuiGameList::setPreviousSortIndex()
{
//make the index wrap around
if (((int)sortStateIndex - 1) < 0) {
setSortIndex(sortStates.size() - 1);
}
setSortIndex(sortStateIndex - 1);
}
void GuiGameList::sort(FolderData::ComparisonFunction & comparisonFunction, bool ascending)
void GuiGameList::sort(const FileData::SortType& type)
{
//resort list and update it
mFolder->sort(comparisonFunction, ascending);
mFolder->sort(type);
updateList();
updateDetailData();
}
@ -314,14 +247,12 @@ void GuiGameList::updateList()
{
mList.clear();
for(unsigned int i = 0; i < mFolder->getFileCount(); i++)
for(auto it = mFolder->getChildren().begin(); it != mFolder->getChildren().end(); it++)
{
FileData* file = mFolder->getFile(i);
if(file->isFolder())
mList.addObject(file->getName(), file, mTheme->getColor("secondary"));
if((*it)->getType() == FOLDER)
mList.addObject((*it)->getName(), *it, mTheme->getColor("secondary"));
else
mList.addObject(file->getName(), file, mTheme->getColor("primary"));
mList.addObject((*it)->getName(), *it, mTheme->getColor("primary"));
}
}
@ -391,17 +322,17 @@ void GuiGameList::updateTheme()
void GuiGameList::updateDetailData()
{
if(!isDetailed() || !mList.getSelectedObject() || mList.getSelectedObject()->isFolder())
if(!isDetailed() || !mList.getSelectedObject() || mList.getSelectedObject()->getType() == FOLDER)
{
hideDetailData();
}else{
if(mDescContainer.getParent() != this)
addChild(&mDescContainer);
GameData* game = (GameData*)mList.getSelectedObject();
FileData* game = mList.getSelectedObject();
//set image to either "not found" image or metadata image
if(!boost::filesystem::exists(game->metadata()->get("image")))
if(!boost::filesystem::exists(game->metadata.get("image")))
{
//image doesn't exist
if(mTheme->getString("imageNotFoundPath").empty())
@ -413,7 +344,7 @@ void GuiGameList::updateDetailData()
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
}
}else{
mScreenshot.setImage(game->metadata()->get("image"));
mScreenshot.setImage(game->metadata.get("image"));
}
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
@ -434,14 +365,14 @@ void GuiGameList::updateDetailData()
mReleaseDateLabel.setPosition(0, 0);
mReleaseDateLabel.setText("Released: ");
mReleaseDate.setPosition(mReleaseDateLabel.getPosition().x() + mReleaseDateLabel.getSize().x(), mReleaseDateLabel.getPosition().y());
mReleaseDate.setValue(game->metadata()->get("releasedate"));
mReleaseDate.setValue(game->metadata.get("releasedate"));
mRating.setPosition(colwidth - mRating.getSize().x() - 12, 0);
mRating.setValue(game->metadata()->get("rating"));
mRating.setValue(game->metadata.get("rating"));
mDescription.setPosition(0, mRating.getSize().y());
mDescription.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), 0));
mDescription.setText(game->metadata()->get("desc"));
mDescription.setText(game->metadata.get("desc"));
}
}
@ -557,7 +488,7 @@ void GuiGameList::updateGameLaunchEffect(int t)
{
//effect done
mTransitionImage.setImage(""); //fixes "tried to bind uninitialized texture!" since copyScreen()'d textures don't reinit
mSystem->launchGame(mWindow, (GameData*)mList.getSelectedObject());
mSystem->launchGame(mWindow, mList.getSelectedObject());
mEffectFunc = &GuiGameList::updateGameReturnEffect;
mEffectTime = 0;
mGameLaunchEffectLength = 700;

View file

@ -10,8 +10,6 @@
#include <string>
#include <stack>
#include "../SystemData.h"
#include "../GameData.h"
#include "../FolderData.h"
#include "ScrollableContainer.h"
#include "RatingComponent.h"
#include "DateTimeComponent.h"
@ -20,9 +18,6 @@
//It has a TextListComponent child that handles the game list, a ThemeComponent that handles the theming system, and an ImageComponent for game images.
class GuiGameList : public GuiComponent
{
static std::vector<FolderData::SortState> sortStates;
size_t sortStateIndex;
public:
GuiGameList(Window* window);
virtual ~GuiGameList();
@ -35,11 +30,7 @@ public:
void updateDetailData();
const FolderData::SortState & getSortState() const;
void setSortIndex(size_t index);
void setNextSortIndex();
void setPreviousSortIndex();
void sort(FolderData::ComparisonFunction & comparisonFunction = FolderData::compareFileName, bool ascending = true);
void sort(const FileData::SortType& type);
static GuiGameList* create(Window* window);
@ -55,8 +46,8 @@ private:
std::string getThemeFile();
SystemData* mSystem;
FolderData* mFolder;
std::stack<FolderData*> mFolderStack;
FileData* mFolder;
std::stack<FileData*> mFolderStack;
int mSystemId;
TextListComponent<FileData*> mList;

View file

@ -7,7 +7,7 @@
GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::function<void(MetaDataList)> doneFunc, std::function<void()> skipFunc) : GuiComponent(window),
mList(window, Eigen::Vector2i(2, 7 + MAX_SCRAPER_RESULTS)),
mBox(window, ":/frame.png"),
mHeader(window, params.game->getBaseName(), Font::get(FONT_SIZE_MEDIUM)),
mHeader(window, getCleanFileName(params.game->getPath()), Font::get(FONT_SIZE_MEDIUM)),
mResultName(window, "", Font::get(FONT_SIZE_MEDIUM)),
mResultInfo(window),
mResultDesc(window, "", Font::get(FONT_SIZE_SMALL)),
@ -56,7 +56,7 @@ GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::
mResultName.setColor(0x3B56CCFF);
mList.setEntry(Vector2i(0, 1), Vector2i(1, 1), &mResultName, false, ComponentListComponent::AlignLeft);
mResultDesc.setText(params.game->metadata()->get("desc"));
mResultDesc.setText(params.game->metadata.get("desc"));
mResultDesc.setSize(colWidth, 0);
mResultInfo.addChild(&mResultDesc);
mResultInfo.setSize(mResultDesc.getSize().x(), mResultDesc.getFont()->getHeight() * 3.0f);
@ -69,7 +69,7 @@ GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::
//y = 3 is a spacer row
mList.setEntry(Vector2i(0, 4), Vector2i(1, 1), &mSearchLabel, false, ComponentListComponent::AlignLeft);
mSearchText.setValue(!params.nameOverride.empty() ? params.nameOverride : params.game->getCleanName());
mSearchText.setValue(!params.nameOverride.empty() ? params.nameOverride : getCleanFileName(params.game->getPath()));
mSearchText.setSize(colWidth * 2 - mSearchLabel.getSize().x() - 20, mSearchText.getSize().y());
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mSearchText, true, ComponentListComponent::AlignRight);

View file

@ -4,7 +4,6 @@
#include "ComponentListComponent.h"
#include "../MetaData.h"
#include "TextComponent.h"
#include "../GameData.h"
#include "NinePatchComponent.h"
#include "ButtonComponent.h"
#include <functional>

View file

@ -52,7 +52,7 @@ void GuiScraperLog::next()
ScraperSearchParams search = mSearches.front();
mSearches.pop();
writeLine(search.game->getCleanName(), 0x0000FFFF);
writeLine(getCleanFileName(search.game->getPath()), 0x0000FFFF);
if(mManualMode)
{
@ -87,7 +87,7 @@ void GuiScraperLog::resultFetched(ScraperSearchParams params, MetaDataList mdl)
void GuiScraperLog::resultResolved(ScraperSearchParams params, MetaDataList mdl)
{
//apply new metadata
*params.game->metadata() = mdl;
params.game->metadata = mdl;
writeLine(" Success!", 0x00FF00FF);
@ -106,7 +106,7 @@ void GuiScraperLog::resultEmpty(ScraperSearchParams search)
else
writeLine(" NO RESULTS, skipping", 0xFF0000FF);
LOG(LogInfo) << "Scraper skipping [" << search.game->getCleanName() << "]";
LOG(LogInfo) << "Scraper skipping [" << getCleanFileName(search.game->getPath()) << "]";
mSkippedCount++;

View file

@ -24,9 +24,9 @@ GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window),
//add filters (with first one selected)
mFiltersOpt.addEntry(mFiltersOpt.makeEntry("All Games",
[](SystemData*, GameData*) -> bool { return true; }, true));
[](SystemData*, FileData*) -> bool { return true; }, true));
mFiltersOpt.addEntry(mFiltersOpt.makeEntry("Missing Image",
[](SystemData*, GameData* g) -> bool { return g->metadata()->get("image").empty(); }));
[](SystemData*, FileData* g) -> bool { return g->metadata.get("image").empty(); }));
mList.setEntry(Vector2i(0, 0), Vector2i(1, 1), &mFilterLabel, false, ComponentListComponent::AlignRight);
mList.setEntry(Vector2i(1, 0), Vector2i(1, 1), &mFiltersOpt, true, ComponentListComponent::AlignLeft);
@ -85,13 +85,13 @@ std::queue<ScraperSearchParams> GuiScraperStart::getSearches(std::vector<SystemD
std::queue<ScraperSearchParams> queue;
for(auto sys = systems.begin(); sys != systems.end(); sys++)
{
std::vector<FileData*> games = (*sys)->getRootFolder()->getFilesRecursive(true);
std::vector<FileData*> games = (*sys)->getRootFolder()->getFilesRecursive(GAME);
for(auto game = games.begin(); game != games.end(); game++)
{
if(selector((*sys), (GameData*)(*game)))
if(selector((*sys), (*game)))
{
ScraperSearchParams search;
search.game = (GameData*)(*game);
search.game = *game;
search.system = *sys;
queue.push(search);

View file

@ -10,7 +10,7 @@
#include "../scrapers/Scraper.h"
#include <queue>
typedef std::function<bool(SystemData*, GameData*)> GameFilterFunc;
typedef std::function<bool(SystemData*, FileData*)> GameFilterFunc;
//The starting point for a multi-game scrape.
//Allows the user to set various parameters (to set filters, to set which systems to scrape, to enable manual mode).

View file

@ -60,7 +60,7 @@ std::shared_ptr<HttpReq> GamesDBScraper::makeHttpReq(ScraperSearchParams params)
std::string cleanName = params.nameOverride;
if(cleanName.empty())
cleanName = params.game->getCleanName();
cleanName = getCleanFileName(params.game->getPath());
path += "name=" + HttpReq::urlEncode(cleanName);

View file

@ -143,7 +143,7 @@ std::string downloadImage(const std::string& url, const std::string& saveAs)
std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url)
{
const std::string subdirectory = params.system->getName();
const std::string name = params.game->getCleanName() + "-" + suffix;
const std::string name = getCleanFileName(params.game->getPath()) + "-" + suffix;
std::string path = getHomePath() + "/.emulationstation/downloaded_images/";
@ -177,7 +177,7 @@ std::shared_ptr<Scraper> createScraperByName(const std::string& name)
void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& params, MetaDataList mdl, std::function<void(MetaDataList)> returnFunc)
{
const std::vector<MetaDataDecl>& mdd = params.game->metadata()->getMDD();
const std::vector<MetaDataDecl>& mdd = params.game->metadata.getMDD();
for(auto it = mdd.begin(); it != mdd.end(); it++)
{
std::string key = it->key;
@ -190,7 +190,7 @@ void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& param
if(savedAs.empty())
{
//error
LOG(LogError) << "Could not resolve image for [" << params.game->getCleanName() << "]! Skipping.";
LOG(LogError) << "Could not resolve image for [" << getCleanFileName(params.game->getPath()) << "]! Skipping.";
}
mdl.set(key, savedAs);

View file

@ -2,7 +2,6 @@
#include "../MetaData.h"
#include "../SystemData.h"
#include "../GameData.h"
#include "../HttpReq.h"
#include <vector>
#include <functional>
@ -12,7 +11,7 @@ class Window;
struct ScraperSearchParams
{
SystemData* system;
GameData* game;
FileData* game;
std::string nameOverride;
};

View file

@ -12,7 +12,7 @@ std::shared_ptr<HttpReq> TheArchiveScraper::makeHttpReq(ScraperSearchParams para
std::string cleanName = params.nameOverride;
if(cleanName.empty())
cleanName = params.game->getCleanName();
cleanName = getCleanFileName(params.game->getPath());
path += HttpReq::urlEncode(cleanName);
//platform TODO, should use some params.system get method