Moved metadata type declarations more behind-the-scenes.

The original plan was to allow each system to have customizable lists of
metadata, which made constructing metadata really painful (the declaration
list isn't stored on the metadata instance because that's pretty wasteful
for 2,000 games).  Now they're constructed by passing a MetaDataListType
enum in the constructor.
Declaration lists are now managed by const globals passed by reference
through getMDDByType(MetaDataListType).
This commit is contained in:
Aloshi 2013-11-03 19:54:13 -06:00
parent 626a2692e5
commit 5c65747551
10 changed files with 82 additions and 54 deletions

View file

@ -6,36 +6,57 @@
#include "components/RatingComponent.h" #include "components/RatingComponent.h"
#include "components/DateTimeComponent.h" #include "components/DateTimeComponent.h"
MetaDataList::MetaDataList()
MetaDataDecl gameDecls[] = {
{"name", MD_STRING, "", false},
{"desc", MD_MULTILINE_STRING, "", false},
{"image", MD_IMAGE_PATH, "", false},
{"thumbnail", MD_IMAGE_PATH, "", false},
{"rating", MD_RATING, "0", false},
{"releasedate", MD_DATE, "0", false},
{"playcount", MD_INT, "0", true},
{"lastplayed", MD_TIME, "0", true}
};
const std::vector<MetaDataDecl> gameMDD(gameDecls, gameDecls + sizeof(gameDecls) / sizeof(gameDecls[0]));
MetaDataDecl folderDecls[] = {
{"name", MD_STRING, "", false},
{"desc", MD_MULTILINE_STRING, "", false},
{"image", MD_IMAGE_PATH, "", false},
{"thumbnail", MD_IMAGE_PATH, "", false},
};
const std::vector<MetaDataDecl> folderMDD(folderDecls, folderDecls + sizeof(folderDecls) / sizeof(folderDecls[0]));
const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type)
{ {
switch(type)
{
case GAME_METADATA:
return gameMDD;
case FOLDER_METADATA:
return folderMDD;
}
LOG(LogError) << "Invalid MDD type";
return gameMDD;
} }
MetaDataList::MetaDataList(const std::vector<MetaDataDecl>& mdd)
MetaDataList::MetaDataList(MetaDataListType type)
: mType(type)
{ {
const std::vector<MetaDataDecl>& mdd = getMDD();
for(auto iter = mdd.begin(); iter != mdd.end(); iter++) for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
set(iter->key, iter->defaultValue); set(iter->key, iter->defaultValue);
} }
std::vector<MetaDataDecl> MetaDataList::getDefaultGameMDD()
{
MetaDataDecl decls[] = {
{"name", MD_STRING, "", false},
{"desc", MD_MULTILINE_STRING, "", false},
{"image", MD_IMAGE_PATH, "", false},
{"thumbnail", MD_IMAGE_PATH, "", false},
{"rating", MD_RATING, "0", false},
{"releasedate", MD_DATE, "0", false},
{"playcount", MD_INT, "0", true},
{"lastplayed", MD_TIME, "0", true}
};
std::vector<MetaDataDecl> mdd(decls, decls + sizeof(decls) / sizeof(decls[0])); MetaDataList MetaDataList::createFromXML(MetaDataListType type, pugi::xml_node node)
return mdd;
}
MetaDataList MetaDataList::createFromXML(const std::vector<MetaDataDecl>& mdd, pugi::xml_node node)
{ {
MetaDataList mdl; MetaDataList mdl(type);
const std::vector<MetaDataDecl>& mdd = mdl.getMDD();
for(auto iter = mdd.begin(); iter != mdd.end(); iter++) for(auto iter = mdd.begin(); iter != mdd.end(); iter++)
{ {
@ -51,19 +72,25 @@ MetaDataList MetaDataList::createFromXML(const std::vector<MetaDataDecl>& mdd, p
return mdl; return mdl;
} }
void MetaDataList::appendToXML(pugi::xml_node parent, const std::vector<MetaDataDecl>& ignoreDefaults) const void MetaDataList::appendToXML(pugi::xml_node parent, bool ignoreDefaults) const
{ {
const std::vector<MetaDataDecl>& mdd = getMDD();
for(auto iter = mMap.begin(); iter != mMap.end(); iter++) for(auto iter = mMap.begin(); iter != mMap.end(); iter++)
{ {
bool write = true; bool write = true;
for(auto mddIter = ignoreDefaults.begin(); mddIter != ignoreDefaults.end(); mddIter++)
{
if(mddIter->key == iter->first)
{
if(iter->second == mddIter->defaultValue)
write = false;
break; if(ignoreDefaults)
{
for(auto mddIter = mdd.begin(); mddIter != mdd.end(); mddIter++)
{
if(mddIter->key == iter->first)
{
if(iter->second == mddIter->defaultValue)
write = false;
break;
}
} }
} }

View file

@ -31,16 +31,22 @@ struct MetaDataDecl
boost::posix_time::ptime string_to_ptime(const std::string& str, const std::string& fmt = "%Y%m%dT%H%M%S%F%q"); boost::posix_time::ptime string_to_ptime(const std::string& str, const std::string& fmt = "%Y%m%dT%H%M%S%F%q");
enum MetaDataListType
{
GAME_METADATA,
FOLDER_METADATA
};
const std::vector<MetaDataDecl>& getMDDByType(MetaDataListType type);
class MetaDataList class MetaDataList
{ {
public: public:
static std::vector<MetaDataDecl> getDefaultGameMDD(); static MetaDataList createFromXML(MetaDataListType type, pugi::xml_node node);
void appendToXML(pugi::xml_node parent, bool ignoreDefaults = false) const;
static MetaDataList createFromXML(const std::vector<MetaDataDecl>& mdd, pugi::xml_node node);
//MetaDataDecl required to set our defaults.
MetaDataList(const std::vector<MetaDataDecl>& mdd);
MetaDataList(MetaDataListType type);
void set(const std::string& key, const std::string& value); void set(const std::string& key, const std::string& value);
void setTime(const std::string& key, const boost::posix_time::ptime& time); //times are internally stored as ISO strings (e.g. boost::posix_time::to_iso_string(ptime)) void setTime(const std::string& key, const boost::posix_time::ptime& time); //times are internally stored as ISO strings (e.g. boost::posix_time::to_iso_string(ptime))
@ -52,11 +58,11 @@ public:
static GuiComponent* makeDisplay(Window* window, MetaDataType as); static GuiComponent* makeDisplay(Window* window, MetaDataType as);
static GuiComponent* makeEditor(Window* window, MetaDataType as); static GuiComponent* makeEditor(Window* window, MetaDataType as);
void appendToXML(pugi::xml_node parent, const std::vector<MetaDataDecl>& ignoreDefaults = std::vector<MetaDataDecl>()) const; inline MetaDataListType getType() const { return mType; }
inline const std::vector<MetaDataDecl>& getMDD() const { return getMDDByType(getType()); }
private: private:
MetaDataList(); MetaDataListType mType;
std::map<std::string, std::string> mMap; std::map<std::string, std::string> mMap;
}; };
@ -64,7 +70,8 @@ private:
//options for storing metadata... //options for storing metadata...
//store internally everything as a string - this is all going to be read to/from XML anyway, after all //store internally everything as a string - this is all going to be read to/from XML anyway, after all
//store using individual get/set functions ala Settings - this is a fair amount of work but the most explicit, for better or worse // - problem: this does not play nice with lists of values
//store using individual get/set functions ala Settings - this is a fair amount of work but the most explicit and type-safe, for better or worse
//let's think about some of the special types we would like to support... //let's think about some of the special types we would like to support...
//image paths, sound paths, ratings, play counts //image paths, sound paths, ratings, play counts

View file

@ -243,7 +243,7 @@ int run_scraper_cmdline()
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++) for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
{ {
GameData* game = (GameData*)(*gameIt); GameData* game = (GameData*)(*gameIt);
std::vector<MetaDataDecl> mdd = (*sysIt)->getGameMDD(); const std::vector<MetaDataDecl>& mdd = game->metadata()->getMDD();
for(auto i = mdd.begin(); i != mdd.end(); i++) for(auto i = mdd.begin(); i != mdd.end(); i++)
{ {
std::string key = i->key; std::string key = i->key;

View file

@ -142,7 +142,7 @@ void SystemData::populateFolder(FolderData* folder)
isGame = false; isGame = false;
if(std::find(mSearchExtensions.begin(), mSearchExtensions.end(), extension) != mSearchExtensions.end()) if(std::find(mSearchExtensions.begin(), mSearchExtensions.end(), extension) != mSearchExtensions.end())
{ {
GameData* newGame = new GameData(filePath.generic_string(), MetaDataList(getGameMDD())); GameData* newGame = new GameData(filePath.generic_string(), MetaDataList(GAME_METADATA));
folder->pushFileData(newGame); folder->pushFileData(newGame);
isGame = true; isGame = true;
} }
@ -335,11 +335,6 @@ bool SystemData::hasGamelist()
return (fs::exists(getGamelistPath())); return (fs::exists(getGamelistPath()));
} }
std::vector<MetaDataDecl> SystemData::getGameMDD()
{
return MetaDataList::getDefaultGameMDD();
}
PlatformIds::PlatformId SystemData::getPlatformId() PlatformIds::PlatformId SystemData::getPlatformId()
{ {
return mPlatformId; return mPlatformId;

View file

@ -27,8 +27,7 @@ public:
std::string getGamelistPath(); std::string getGamelistPath();
bool hasGamelist(); bool hasGamelist();
std::vector<MetaDataDecl> getGameMDD();
unsigned int getGameCount(); unsigned int getGameCount();
void launchGame(Window* window, GameData* game); void launchGame(Window* window, GameData* game);

View file

@ -91,7 +91,7 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
loops++; loops++;
} }
GameData* game = new GameData(gameAbsPath, MetaDataList(system->getGameMDD())); GameData* game = new GameData(gameAbsPath, MetaDataList(GAME_METADATA));
folder->pushFileData(game); folder->pushFileData(game);
return game; return game;
} }
@ -156,7 +156,7 @@ void parseGamelist(SystemData* system)
game = createGameFromPath(path, system); game = createGameFromPath(path, system);
//load the metadata //load the metadata
*(game->metadata()) = MetaDataList::createFromXML(system->getGameMDD(), gameNode); *(game->metadata()) = MetaDataList::createFromXML(GAME_METADATA, gameNode);
//make sure name gets set if one didn't exist //make sure name gets set if one didn't exist
if(game->metadata()->get("name").empty()) if(game->metadata()->get("name").empty())
@ -173,7 +173,7 @@ void addGameDataNode(pugi::xml_node& parent, const GameData* game, SystemData* s
pugi::xml_node newGame = parent.append_child("game"); pugi::xml_node newGame = parent.append_child("game");
//write metadata //write metadata
const_cast<GameData*>(game)->metadata()->appendToXML(newGame, system->getGameMDD()); const_cast<GameData*>(game)->metadata()->appendToXML(newGame, true);
if(newGame.children().begin() == newGame.child("name") //first element is name if(newGame.children().begin() == newGame.child("name") //first element is name
&& ++newGame.children().begin() == newGame.children().end() //theres only one element && ++newGame.children().begin() == newGame.children().end() //theres only one element

View file

@ -149,7 +149,7 @@ bool GuiGameList::input(InputConfig* config, Input input)
ScraperSearchParams searchParams; ScraperSearchParams searchParams;
searchParams.game = game; searchParams.game = game;
searchParams.system = mSystem; searchParams.system = mSystem;
mWindow->pushGui(new GuiMetaDataEd(mWindow, game->metadata(), mSystem->getGameMDD(), searchParams, game->getBaseName(), mWindow->pushGui(new GuiMetaDataEd(mWindow, game->metadata(), game->metadata()->getMDD(), searchParams, game->getBaseName(),
[&] { updateDetailData(); }, [&] { updateDetailData(); },
[game, root, this] { [game, root, this] {
boost::filesystem::remove(game->getPath()); boost::filesystem::remove(game->getPath());

View file

@ -99,7 +99,7 @@ std::vector<MetaDataList> GamesDBScraper::parseReq(ScraperSearchParams params, s
pugi::xml_node game = data.child("Game"); pugi::xml_node game = data.child("Game");
while(game && resultNum < MAX_SCRAPER_RESULTS) while(game && resultNum < MAX_SCRAPER_RESULTS)
{ {
mdl.push_back(MetaDataList(params.system->getGameMDD())); mdl.push_back(MetaDataList(GAME_METADATA));
mdl.back().set("name", game.child("GameTitle").text().get()); mdl.back().set("name", game.child("GameTitle").text().get());
mdl.back().set("desc", game.child("Overview").text().get()); mdl.back().set("desc", game.child("Overview").text().get());

View file

@ -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) void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& params, MetaDataList mdl, std::function<void(MetaDataList)> returnFunc)
{ {
std::vector<MetaDataDecl> mdd = params.system->getGameMDD(); const std::vector<MetaDataDecl>& mdd = params.game->metadata()->getMDD();
for(auto it = mdd.begin(); it != mdd.end(); it++) for(auto it = mdd.begin(); it != mdd.end(); it++)
{ {
std::string key = it->key; std::string key = it->key;

View file

@ -44,7 +44,7 @@ std::vector<MetaDataList> TheArchiveScraper::parseReq(ScraperSearchParams params
pugi::xml_node game = data.child("game"); pugi::xml_node game = data.child("game");
while(game && resultNum < MAX_SCRAPER_RESULTS) while(game && resultNum < MAX_SCRAPER_RESULTS)
{ {
mdl.push_back(MetaDataList(params.system->getGameMDD())); mdl.push_back(MetaDataList(GAME_METADATA));
mdl.back().set("name", game.child("title").text().get()); mdl.back().set("name", game.child("title").text().get());
mdl.back().set("desc", game.child("description").text().get()); mdl.back().set("desc", game.child("description").text().get());