mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
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:
parent
5c65747551
commit
3a3471cfe8
|
@ -138,8 +138,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/EmulationStation.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FolderData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GameData.h
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.h
|
||||||
|
@ -198,8 +197,8 @@ set(ES_HEADERS
|
||||||
)
|
)
|
||||||
set(ES_SOURCES
|
set(ES_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/AudioManager.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/FolderData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GameData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/FileSorts.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/GuiComponent.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/HttpReq.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.cpp
|
||||||
|
|
98
src/FileData.cpp
Normal file
98
src/FileData.cpp
Normal 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);
|
||||||
|
}
|
|
@ -1,17 +1,62 @@
|
||||||
#ifndef _FILEDATA_H_
|
#pragma once
|
||||||
#define _FILEDATA_H_
|
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include "MetaData.h"
|
||||||
|
|
||||||
//This is a really basic class that the GameData and FolderData subclass from.
|
enum FileType
|
||||||
//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.
|
{
|
||||||
|
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
|
class FileData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~FileData() { };
|
FileData(FileType type, const boost::filesystem::path& path);
|
||||||
virtual bool isFolder() const = 0;
|
virtual ~FileData();
|
||||||
virtual const std::string& getName() const = 0;
|
|
||||||
virtual const std::string& getPath() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
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) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
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
62
src/FileSorts.cpp
Normal 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
14
src/FileSorts.h
Normal 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;
|
||||||
|
};
|
|
@ -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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -141,7 +141,7 @@ int run_scraper_cmdline()
|
||||||
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
|
std::shared_ptr<Scraper> scraper = Settings::getInstance()->getScraper();
|
||||||
for(auto sysIt = systems.begin(); sysIt != systems.end(); sysIt++)
|
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;
|
ScraperSearchParams params;
|
||||||
params.system = (*sysIt);
|
params.system = (*sysIt);
|
||||||
|
@ -149,15 +149,15 @@ int run_scraper_cmdline()
|
||||||
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
|
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
|
||||||
{
|
{
|
||||||
params.nameOverride = "";
|
params.nameOverride = "";
|
||||||
params.game = (GameData*)(*gameIt);
|
params.game = *gameIt;
|
||||||
|
|
||||||
//print original search term
|
//print original search term
|
||||||
out << params.game->getCleanName() << "...\n";
|
out << getCleanFileName(params.game->getPath()) << "...\n";
|
||||||
|
|
||||||
//need to take into account filter_choice
|
//need to take into account filter_choice
|
||||||
if(filter_choice == FILTER_MISSING_IMAGES)
|
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";
|
out << " Skipping, metadata \"image\" entry is not empty.\n";
|
||||||
continue;
|
continue;
|
||||||
|
@ -212,7 +212,7 @@ int run_scraper_cmdline()
|
||||||
|
|
||||||
if(choice >= 0 && choice < (int)mdls.size())
|
if(choice >= 0 && choice < (int)mdls.size())
|
||||||
{
|
{
|
||||||
*params.game->metadata() = mdls.at(choice);
|
params.game->metadata = mdls.at(choice);
|
||||||
break;
|
break;
|
||||||
}else{
|
}else{
|
||||||
out << "Invalid choice.\n";
|
out << "Invalid choice.\n";
|
||||||
|
@ -223,7 +223,7 @@ int run_scraper_cmdline()
|
||||||
//automatic mode
|
//automatic mode
|
||||||
//always choose the first choice
|
//always choose the first choice
|
||||||
out << " name -> " << mdls.at(0).get("name") << "\n";
|
out << " name -> " << mdls.at(0).get("name") << "\n";
|
||||||
*params.game->metadata() = mdls.at(0);
|
params.game->metadata = mdls.at(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,32 +238,32 @@ int run_scraper_cmdline()
|
||||||
|
|
||||||
for(auto sysIt = systems.begin(); sysIt != systems.end(); sysIt++)
|
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++)
|
for(auto gameIt = files.begin(); gameIt != files.end(); gameIt++)
|
||||||
{
|
{
|
||||||
GameData* game = (GameData*)(*gameIt);
|
FileData* game = *gameIt;
|
||||||
const std::vector<MetaDataDecl>& mdd = game->metadata()->getMDD();
|
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;
|
||||||
std::string url = game->metadata()->get(key);
|
std::string url = game->metadata.get(key);
|
||||||
|
|
||||||
if(i->type == MD_IMAGE_PATH && HttpReq::isUrl(url))
|
if(i->type == MD_IMAGE_PATH && HttpReq::isUrl(url))
|
||||||
{
|
{
|
||||||
std::string urlShort = url.substr(0, url.length() > 35 ? 35 : url.length());
|
std::string urlShort = url.substr(0, url.length() > 35 ? 35 : url.length());
|
||||||
if(url.length() != urlShort.length()) urlShort += "...";
|
if(url.length() != urlShort.length()) urlShort += "...";
|
||||||
|
|
||||||
out << " " << game->metadata()->get("name") << " [from: " << urlShort << "]...\n";
|
out << " " << game->metadata.get("name") << " [from: " << urlShort << "]...\n";
|
||||||
|
|
||||||
ScraperSearchParams p;
|
ScraperSearchParams p;
|
||||||
p.game = game;
|
p.game = game;
|
||||||
p.system = *sysIt;
|
p.system = *sysIt;
|
||||||
game->metadata()->set(key, downloadImage(url, getSaveAsPath(p, key, url)));
|
game->metadata.set(key, downloadImage(url, getSaveAsPath(p, key, url)));
|
||||||
if(game->metadata()->get(key).empty())
|
if(game->metadata.get(key).empty())
|
||||||
{
|
{
|
||||||
out << " FAILED! Skipping.\n";
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "GameData.h"
|
|
||||||
#include "XMLReader.h"
|
#include "XMLReader.h"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -12,14 +11,12 @@
|
||||||
#include "InputManager.h"
|
#include "InputManager.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#include "FileSorts.h"
|
||||||
|
|
||||||
std::vector<SystemData*> SystemData::sSystemVector;
|
std::vector<SystemData*> SystemData::sSystemVector;
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
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,
|
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)
|
const std::string& command, PlatformIds::PlatformId platformId)
|
||||||
{
|
{
|
||||||
|
@ -38,7 +35,8 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, con
|
||||||
mLaunchCommand = command;
|
mLaunchCommand = command;
|
||||||
mPlatformId = platformId;
|
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"))
|
if(!Settings::getInstance()->getBool("PARSEGAMELISTONLY"))
|
||||||
populateFolder(mRootFolder);
|
populateFolder(mRootFolder);
|
||||||
|
@ -46,15 +44,17 @@ SystemData::SystemData(const std::string& name, const std::string& fullName, con
|
||||||
if(!Settings::getInstance()->getBool("IGNOREGAMELIST"))
|
if(!Settings::getInstance()->getBool("IGNOREGAMELIST"))
|
||||||
parseGamelist(this);
|
parseGamelist(this);
|
||||||
|
|
||||||
mRootFolder->sort();
|
mRootFolder->sort(FileSorts::SortTypes.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemData::~SystemData()
|
SystemData::~SystemData()
|
||||||
{
|
{
|
||||||
//save changed game data back to xml
|
//save changed game data back to xml
|
||||||
if(!Settings::getInstance()->getBool("IGNOREGAMELIST")) {
|
if(!Settings::getInstance()->getBool("IGNOREGAMELIST"))
|
||||||
|
{
|
||||||
updateGamelist(this);
|
updateGamelist(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete mRootFolder;
|
delete mRootFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +68,33 @@ std::string strreplace(std::string& str, std::string replace, std::string with)
|
||||||
return str;
|
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...";
|
LOG(LogInfo) << "Attempting to launch game...";
|
||||||
|
|
||||||
|
@ -78,9 +104,13 @@ void SystemData::launchGame(Window* window, GameData* game)
|
||||||
|
|
||||||
std::string command = mLaunchCommand;
|
std::string command = mLaunchCommand;
|
||||||
|
|
||||||
command = strreplace(command, "%ROM%", game->getBashPath());
|
const std::string rom = escapePath(game->getPath());
|
||||||
command = strreplace(command, "%BASENAME%", game->getBaseName());
|
const std::string basename = game->getPath().stem().string();
|
||||||
command = strreplace(command, "%ROM_RAW%", game->getPath());
|
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;
|
LOG(LogInfo) << " " << command;
|
||||||
std::cout << "==============================================\n";
|
std::cout << "==============================================\n";
|
||||||
|
@ -97,25 +127,31 @@ void SystemData::launchGame(Window* window, GameData* game)
|
||||||
AudioManager::getInstance()->init();
|
AudioManager::getInstance()->init();
|
||||||
window->normalizeNextUpdate();
|
window->normalizeNextUpdate();
|
||||||
|
|
||||||
//update number of times the game has been launched and the time
|
//update number of times the game has been launched
|
||||||
game->incTimesPlayed();
|
int timesPlayed = game->metadata.getInt("playcount") + 1;
|
||||||
game->lastPlayedNow();
|
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))
|
if(!fs::is_directory(folderPath))
|
||||||
{
|
{
|
||||||
LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!";
|
LOG(LogWarning) << "Error - folder with path \"" << folderPath << "\" is not a directory!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string folderStr = folderPath.generic_string();
|
||||||
|
|
||||||
//make sure that this isn't a symlink to a thing we already have
|
//make sure that this isn't a symlink to a thing we already have
|
||||||
if(fs::is_symlink(folderPath))
|
if(fs::is_symlink(folderPath))
|
||||||
{
|
{
|
||||||
//if this symlink resolves to somewhere that's at the beginning of our path, it's gonna recurse
|
//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 << "\"";
|
LOG(LogWarning) << "Skipping infinitely recursive symlink \"" << folderPath << "\"";
|
||||||
return;
|
return;
|
||||||
|
@ -142,39 +178,26 @@ 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(GAME_METADATA));
|
FileData* newGame = new FileData(GAME, filePath.generic_string());
|
||||||
folder->pushFileData(newGame);
|
folder->addChild(newGame);
|
||||||
isGame = true;
|
isGame = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//add directories that also do not match an extension as folders
|
//add directories that also do not match an extension as folders
|
||||||
if(!isGame && fs::is_directory(filePath))
|
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);
|
populateFolder(newFolder);
|
||||||
|
|
||||||
//ignore folders that do not contain games
|
//ignore folders that do not contain games
|
||||||
if(newFolder->getFileCount() == 0)
|
if(newFolder->getChildren().size() == 0)
|
||||||
delete newFolder;
|
delete newFolder;
|
||||||
else
|
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
|
//creates systems from information located in a config file
|
||||||
bool SystemData::loadConfig(const std::string& path, bool writeExample)
|
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();
|
path = genericPath.generic_string();
|
||||||
|
|
||||||
SystemData* newSys = new SystemData(name, fullname, path, extensions, cmd, platformId);
|
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.";
|
LOG(LogWarning) << "System \"" << name << "\" has no games! Ignoring it.";
|
||||||
delete newSys;
|
delete newSys;
|
||||||
|
@ -312,22 +335,16 @@ std::string SystemData::getConfigPath()
|
||||||
return(home + "/.emulationstation/es_systems.cfg");
|
return(home + "/.emulationstation/es_systems.cfg");
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderData* SystemData::getRootFolder()
|
std::string SystemData::getGamelistPath() const
|
||||||
{
|
{
|
||||||
return mRootFolder;
|
fs::path filePath;
|
||||||
}
|
|
||||||
|
|
||||||
std::string SystemData::getGamelistPath()
|
filePath = mRootFolder->getPath() / "gamelist.xml";
|
||||||
{
|
|
||||||
std::string filePath;
|
|
||||||
|
|
||||||
filePath = mRootFolder->getPath() + "/gamelist.xml";
|
|
||||||
if(fs::exists(filePath))
|
if(fs::exists(filePath))
|
||||||
return filePath;
|
return filePath.generic_string();
|
||||||
|
|
||||||
filePath = getHomePath();
|
filePath = getHomePath() + "/.emulationstation/"+ getName() + "/gamelist.xml";
|
||||||
filePath += "/.emulationstation/"+ getName() + "/gamelist.xml";
|
return filePath.generic_string();
|
||||||
return filePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemData::hasGamelist()
|
bool SystemData::hasGamelist()
|
||||||
|
@ -335,12 +352,7 @@ bool SystemData::hasGamelist()
|
||||||
return (fs::exists(getGamelistPath()));
|
return (fs::exists(getGamelistPath()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PlatformIds::PlatformId SystemData::getPlatformId()
|
unsigned int SystemData::getGameCount() const
|
||||||
{
|
{
|
||||||
return mPlatformId;
|
return mRootFolder->getFilesRecursive(GAME).size();
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int SystemData::getGameCount()
|
|
||||||
{
|
|
||||||
return mRootFolder->getFilesRecursive(true).size();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "FolderData.h"
|
#include "FileData.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "MetaData.h"
|
#include "MetaData.h"
|
||||||
#include "PlatformId.h"
|
#include "PlatformId.h"
|
||||||
|
|
||||||
class GameData;
|
|
||||||
|
|
||||||
class SystemData
|
class SystemData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -17,20 +15,19 @@ public:
|
||||||
const std::string& command, PlatformIds::PlatformId platformId = PlatformIds::PLATFORM_UNKNOWN);
|
const std::string& command, PlatformIds::PlatformId platformId = PlatformIds::PLATFORM_UNKNOWN);
|
||||||
~SystemData();
|
~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 getGamelistPath() const;
|
||||||
std::string getFullName();
|
|
||||||
std::string getStartPath();
|
|
||||||
std::vector<std::string> getExtensions();
|
|
||||||
PlatformIds::PlatformId getPlatformId();
|
|
||||||
|
|
||||||
std::string getGamelistPath();
|
|
||||||
bool hasGamelist();
|
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 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.
|
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::string getConfigPath();
|
||||||
|
|
||||||
static std::vector<SystemData*> sSystemVector;
|
static std::vector<SystemData*> sSystemVector;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mFullName;
|
std::string mFullName;
|
||||||
|
@ -46,10 +44,9 @@ private:
|
||||||
std::string mLaunchCommand;
|
std::string mLaunchCommand;
|
||||||
PlatformIds::PlatformId mPlatformId;
|
PlatformIds::PlatformId mPlatformId;
|
||||||
|
|
||||||
void populateFolder(FolderData* folder);
|
void populateFolder(FileData* folder);
|
||||||
|
|
||||||
FolderData* mRootFolder;
|
FileData* mRootFolder;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include "XMLReader.h"
|
#include "XMLReader.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
#include "GameData.h"
|
|
||||||
#include "pugiXML/pugixml.hpp"
|
#include "pugiXML/pugixml.hpp"
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
@ -8,27 +7,25 @@
|
||||||
|
|
||||||
//this is obviously an incredibly inefficient way to go about searching
|
//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
|
//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((*it)->getType() == FOLDER)
|
||||||
|
|
||||||
if(file->isFolder())
|
|
||||||
{
|
{
|
||||||
GameData* result = searchFolderByPath((FolderData*)file, path);
|
FileData* result = searchFolderByPath(*it, path);
|
||||||
if(result)
|
if(result)
|
||||||
return (GameData*)result;
|
return result;
|
||||||
}else{
|
}else{
|
||||||
if(file->getPath() == path)
|
if((*it)->getPath().generic_string() == path)
|
||||||
return (GameData*)file;
|
return *it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
|
FileData* createGameFromPath(std::string gameAbsPath, SystemData* system)
|
||||||
{
|
{
|
||||||
std::string gamePath = gameAbsPath;
|
std::string gamePath = gameAbsPath;
|
||||||
std::string sysPath = system->getStartPath();
|
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
|
//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 separator = 0;
|
||||||
size_t nextSeparator = 0;
|
size_t nextSeparator = 0;
|
||||||
unsigned int loops = 0;
|
|
||||||
while(nextSeparator != std::string::npos)
|
while(nextSeparator != std::string::npos)
|
||||||
{
|
{
|
||||||
//determine which chunk of the path we're testing right now
|
//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
|
//see if the folder already exists
|
||||||
bool foundFolder = false;
|
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((*it)->getType() == FOLDER && (*it)->getName() == checkName)
|
||||||
if(checkFolder->isFolder() && checkFolder->getName() == checkName)
|
|
||||||
{
|
{
|
||||||
folder = (FolderData*)checkFolder;
|
folder = *it;
|
||||||
foundFolder = true;
|
foundFolder = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -77,22 +72,14 @@ GameData* createGameFromPath(std::string gameAbsPath, SystemData* system)
|
||||||
//the folder didn't already exist, so create it
|
//the folder didn't already exist, so create it
|
||||||
if(!foundFolder)
|
if(!foundFolder)
|
||||||
{
|
{
|
||||||
FolderData* newFolder = new FolderData(system, folder->getPath() + "/" + checkName, checkName);
|
FileData* newFolder = new FileData(FOLDER, folder->getPath() / checkName);
|
||||||
folder->pushFileData(newFolder);
|
folder->addChild(newFolder);
|
||||||
folder = 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));
|
FileData* game = new FileData(GAME, gameAbsPath);
|
||||||
folder->pushFileData(game);
|
folder->addChild(game);
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,40 +137,41 @@ void parseGamelist(SystemData* system)
|
||||||
|
|
||||||
if(boost::filesystem::exists(path))
|
if(boost::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
GameData* game = searchFolderByPath(system->getRootFolder(), path);
|
FileData* game = searchFolderByPath(system->getRootFolder(), path);
|
||||||
|
|
||||||
if(game == NULL)
|
if(game == NULL)
|
||||||
game = createGameFromPath(path, system);
|
game = createGameFromPath(path, system);
|
||||||
|
|
||||||
//load the metadata
|
//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
|
//make sure name gets set if one didn't exist
|
||||||
if(game->metadata()->get("name").empty())
|
if(game->metadata.get("name").empty())
|
||||||
game->metadata()->set("name", game->getBaseName());
|
game->metadata.set("name", defaultName);
|
||||||
}else{
|
}else{
|
||||||
LOG(LogWarning) << "Game at \"" << path << "\" does not exist!";
|
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
|
//create game and add to parent node
|
||||||
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, true);
|
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
|
||||||
&& 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
|
//if the only info is the default name, don't bother with this node
|
||||||
parent.remove_child(newGame);
|
parent.remove_child(newGame);
|
||||||
}else{
|
}else{
|
||||||
//there's something useful in there so we'll keep the node, add the path
|
//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
|
//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)
|
if (rootFolder != nullptr)
|
||||||
{
|
{
|
||||||
//get only files, no folders
|
//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
|
//iterate through all files, checking if they're already in the XML
|
||||||
std::vector<FileData*>::const_iterator fit = files.cbegin();
|
std::vector<FileData*>::const_iterator fit = files.cbegin();
|
||||||
while(fit != files.cend())
|
while(fit != files.cend())
|
||||||
{
|
{
|
||||||
//try to cast to gamedata
|
if((*fit)->getType() == GAME)
|
||||||
const GameData * game = dynamic_cast<const GameData*>(*fit);
|
|
||||||
if (game != nullptr)
|
|
||||||
{
|
{
|
||||||
//worked. check if this games' path can be found somewhere in the XML
|
//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"))
|
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
|
//check paths. use the same directory separators
|
||||||
boost::filesystem::path nodePath(pathNode.text().get());
|
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())
|
if (nodePath.generic_string() == gamePath.generic_string())
|
||||||
{
|
{
|
||||||
//found the game. remove it. it will be added again later with updated values
|
//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,
|
//either the game content was removed, because it needs to be updated,
|
||||||
//or didn't exist in the first place, so just add it
|
//or didn't exist in the first place, so just add it
|
||||||
addGameDataNode(root, game, system);
|
addGameDataNode(root, *fit, system);
|
||||||
}
|
}
|
||||||
++fit;
|
++fit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "../Renderer.h"
|
#include "../Renderer.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "GuiGameList.h"
|
#include "GuiGameList.h"
|
||||||
|
#include "../FileSorts.h"
|
||||||
|
|
||||||
#define DEFAULT_FS_IMAGE ":/frame.png"
|
#define DEFAULT_FS_IMAGE ":/frame.png"
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ const std::string GuiFastSelect::LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
const int GuiFastSelect::SCROLLSPEED = 100;
|
const int GuiFastSelect::SCROLLSPEED = 100;
|
||||||
const int GuiFastSelect::SCROLLDELAY = 507;
|
const int GuiFastSelect::SCROLLDELAY = 507;
|
||||||
|
|
||||||
|
int GuiFastSelect::sortTypeId = 0;
|
||||||
|
|
||||||
GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent<FileData*>* list, char startLetter, ThemeComponent * theme)
|
GuiFastSelect::GuiFastSelect(Window* window, GuiGameList* parent, TextListComponent<FileData*>* list, char startLetter, ThemeComponent * theme)
|
||||||
: GuiComponent(window), mParent(parent), mList(list), mTheme(theme), mBox(mWindow, "")
|
: 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);
|
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);
|
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);
|
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)
|
if(config->isMappedTo("left", input) && input.value != 0)
|
||||||
{
|
{
|
||||||
mParent->setPreviousSortIndex();
|
sortTypeId--;
|
||||||
|
if(sortTypeId < 0)
|
||||||
|
sortTypeId = FileSorts::SortTypes.size() - 1;
|
||||||
|
|
||||||
mScrollSound->play();
|
mScrollSound->play();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if(config->isMappedTo("right", input) && input.value != 0)
|
else if(config->isMappedTo("right", input) && input.value != 0)
|
||||||
{
|
{
|
||||||
mParent->setNextSortIndex();
|
sortTypeId = (sortTypeId + 1) % FileSorts::SortTypes.size();
|
||||||
mScrollSound->play();
|
mScrollSound->play();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -104,6 +110,7 @@ bool GuiFastSelect::input(InputConfig* config, Input input)
|
||||||
if(config->isMappedTo("select", input) && input.value == 0)
|
if(config->isMappedTo("select", input) && input.value == 0)
|
||||||
{
|
{
|
||||||
setListPos();
|
setListPos();
|
||||||
|
mParent->sort(FileSorts::SortTypes.at(sortTypeId));
|
||||||
delete this;
|
delete this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
#include "../GuiComponent.h"
|
#include "../GuiComponent.h"
|
||||||
#include "../SystemData.h"
|
#include "../SystemData.h"
|
||||||
#include "../FolderData.h"
|
|
||||||
#include "../Sound.h"
|
#include "../Sound.h"
|
||||||
#include "ThemeComponent.h"
|
#include "ThemeComponent.h"
|
||||||
#include "TextListComponent.h"
|
#include "TextListComponent.h"
|
||||||
|
@ -11,6 +10,7 @@
|
||||||
|
|
||||||
class GuiGameList;
|
class GuiGameList;
|
||||||
|
|
||||||
|
|
||||||
class GuiFastSelect : public GuiComponent
|
class GuiFastSelect : public GuiComponent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -26,6 +26,8 @@ private:
|
||||||
static const int SCROLLSPEED;
|
static const int SCROLLSPEED;
|
||||||
static const int SCROLLDELAY;
|
static const int SCROLLDELAY;
|
||||||
|
|
||||||
|
static int sortTypeId;
|
||||||
|
|
||||||
void setListPos();
|
void setListPos();
|
||||||
void scroll();
|
void scroll();
|
||||||
void setLetterID(int id);
|
void setLetterID(int id);
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#include "GuiMetaDataEd.h"
|
#include "GuiMetaDataEd.h"
|
||||||
#include "GuiScraperStart.h"
|
#include "GuiScraperStart.h"
|
||||||
|
|
||||||
std::vector<FolderData::SortState> GuiGameList::sortStates;
|
|
||||||
|
|
||||||
Eigen::Vector3f GuiGameList::getImagePos()
|
Eigen::Vector3f GuiGameList::getImagePos()
|
||||||
{
|
{
|
||||||
return Eigen::Vector3f(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX"), Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"), 0.0f);
|
return Eigen::Vector3f(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX"), Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"), 0.0f);
|
||||||
|
@ -23,16 +21,12 @@ bool GuiGameList::isDetailed() const
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//return true if any game has an image specified
|
//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())
|
if(!(*it)->getThumbnailPath().empty())
|
||||||
{
|
return true;
|
||||||
GameData* game = (GameData*)(mFolder->getFile(i));
|
|
||||||
if(!game->metadata()->get("image").empty())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,22 +41,9 @@ GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
|
||||||
mDescContainer(window),
|
mDescContainer(window),
|
||||||
mTransitionImage(window, 0.0f, 0.0f, "", (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), true),
|
mTransitionImage(window, 0.0f, 0.0f, "", (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), true),
|
||||||
mHeaderText(mWindow),
|
mHeaderText(mWindow),
|
||||||
sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")),
|
|
||||||
mLockInput(false),
|
mLockInput(false),
|
||||||
mEffectFunc(NULL), mEffectTime(0), mGameLaunchEffectLength(700)
|
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);
|
mImageAnimation.addChild(&mScreenshot);
|
||||||
mDescContainer.addChild(&mReleaseDateLabel);
|
mDescContainer.addChild(&mReleaseDateLabel);
|
||||||
mDescContainer.addChild(&mReleaseDate);
|
mDescContainer.addChild(&mReleaseDate);
|
||||||
|
@ -142,18 +123,18 @@ bool GuiGameList::input(InputConfig* config, Input input)
|
||||||
|
|
||||||
if(input.id == SDLK_F3)
|
if(input.id == SDLK_F3)
|
||||||
{
|
{
|
||||||
GameData* game = dynamic_cast<GameData*>(mList.getSelectedObject());
|
FileData* game = mList.getSelectedObject();
|
||||||
if(game)
|
if(game->getType() == GAME)
|
||||||
{
|
{
|
||||||
FolderData* root = mSystem->getRootFolder();
|
FileData* root = mSystem->getRootFolder();
|
||||||
ScraperSearchParams searchParams;
|
ScraperSearchParams searchParams;
|
||||||
searchParams.game = game;
|
searchParams.game = game;
|
||||||
searchParams.system = mSystem;
|
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(); },
|
[&] { updateDetailData(); },
|
||||||
[game, root, this] {
|
[game, root, this] {
|
||||||
boost::filesystem::remove(game->getPath());
|
boost::filesystem::remove(game->getPath());
|
||||||
root->removeFileRecursive(game);
|
root->removeChild(game);
|
||||||
updateList();
|
updateList();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -166,16 +147,16 @@ bool GuiGameList::input(InputConfig* config, Input input)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config->isMappedTo("a", input) && mFolder->getFileCount() > 0 && input.value != 0)
|
if(config->isMappedTo("a", input) && input.value != 0)
|
||||||
{
|
{
|
||||||
//play select sound
|
//play select sound
|
||||||
mTheme->getSound("menuSelect")->play();
|
mTheme->getSound("menuSelect")->play();
|
||||||
|
|
||||||
FileData* file = mList.getSelectedObject();
|
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);
|
mFolderStack.push(mFolder);
|
||||||
mFolder = (FolderData*)file;
|
mFolder = file;
|
||||||
updateList();
|
updateList();
|
||||||
updateDetailData();
|
updateDetailData();
|
||||||
return true;
|
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"
|
//open the "start menu"
|
||||||
if(config->isMappedTo("menu", input) && input.value != 0)
|
if(config->isMappedTo("menu", input) && input.value != 0)
|
||||||
{
|
{
|
||||||
|
@ -264,48 +235,10 @@ bool GuiGameList::input(InputConfig* config, Input input)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FolderData::SortState & GuiGameList::getSortState() const
|
void GuiGameList::sort(const FileData::SortType& type)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
//resort list and update it
|
//resort list and update it
|
||||||
mFolder->sort(comparisonFunction, ascending);
|
mFolder->sort(type);
|
||||||
updateList();
|
updateList();
|
||||||
updateDetailData();
|
updateDetailData();
|
||||||
}
|
}
|
||||||
|
@ -314,14 +247,12 @@ void GuiGameList::updateList()
|
||||||
{
|
{
|
||||||
mList.clear();
|
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((*it)->getType() == FOLDER)
|
||||||
|
mList.addObject((*it)->getName(), *it, mTheme->getColor("secondary"));
|
||||||
if(file->isFolder())
|
|
||||||
mList.addObject(file->getName(), file, mTheme->getColor("secondary"));
|
|
||||||
else
|
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()
|
void GuiGameList::updateDetailData()
|
||||||
{
|
{
|
||||||
if(!isDetailed() || !mList.getSelectedObject() || mList.getSelectedObject()->isFolder())
|
if(!isDetailed() || !mList.getSelectedObject() || mList.getSelectedObject()->getType() == FOLDER)
|
||||||
{
|
{
|
||||||
hideDetailData();
|
hideDetailData();
|
||||||
}else{
|
}else{
|
||||||
if(mDescContainer.getParent() != this)
|
if(mDescContainer.getParent() != this)
|
||||||
addChild(&mDescContainer);
|
addChild(&mDescContainer);
|
||||||
|
|
||||||
GameData* game = (GameData*)mList.getSelectedObject();
|
FileData* game = mList.getSelectedObject();
|
||||||
|
|
||||||
//set image to either "not found" image or metadata image
|
//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
|
//image doesn't exist
|
||||||
if(mTheme->getString("imageNotFoundPath").empty())
|
if(mTheme->getString("imageNotFoundPath").empty())
|
||||||
|
@ -413,7 +344,7 @@ void GuiGameList::updateDetailData()
|
||||||
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
|
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
mScreenshot.setImage(game->metadata()->get("image"));
|
mScreenshot.setImage(game->metadata.get("image"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
|
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
|
||||||
|
@ -434,14 +365,14 @@ void GuiGameList::updateDetailData()
|
||||||
mReleaseDateLabel.setPosition(0, 0);
|
mReleaseDateLabel.setPosition(0, 0);
|
||||||
mReleaseDateLabel.setText("Released: ");
|
mReleaseDateLabel.setText("Released: ");
|
||||||
mReleaseDate.setPosition(mReleaseDateLabel.getPosition().x() + mReleaseDateLabel.getSize().x(), mReleaseDateLabel.getPosition().y());
|
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.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.setPosition(0, mRating.getSize().y());
|
||||||
mDescription.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), 0));
|
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
|
//effect done
|
||||||
mTransitionImage.setImage(""); //fixes "tried to bind uninitialized texture!" since copyScreen()'d textures don't reinit
|
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;
|
mEffectFunc = &GuiGameList::updateGameReturnEffect;
|
||||||
mEffectTime = 0;
|
mEffectTime = 0;
|
||||||
mGameLaunchEffectLength = 700;
|
mGameLaunchEffectLength = 700;
|
||||||
|
|
|
@ -10,8 +10,6 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include "../SystemData.h"
|
#include "../SystemData.h"
|
||||||
#include "../GameData.h"
|
|
||||||
#include "../FolderData.h"
|
|
||||||
#include "ScrollableContainer.h"
|
#include "ScrollableContainer.h"
|
||||||
#include "RatingComponent.h"
|
#include "RatingComponent.h"
|
||||||
#include "DateTimeComponent.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.
|
//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
|
class GuiGameList : public GuiComponent
|
||||||
{
|
{
|
||||||
static std::vector<FolderData::SortState> sortStates;
|
|
||||||
size_t sortStateIndex;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GuiGameList(Window* window);
|
GuiGameList(Window* window);
|
||||||
virtual ~GuiGameList();
|
virtual ~GuiGameList();
|
||||||
|
@ -35,11 +30,7 @@ public:
|
||||||
|
|
||||||
void updateDetailData();
|
void updateDetailData();
|
||||||
|
|
||||||
const FolderData::SortState & getSortState() const;
|
void sort(const FileData::SortType& type);
|
||||||
void setSortIndex(size_t index);
|
|
||||||
void setNextSortIndex();
|
|
||||||
void setPreviousSortIndex();
|
|
||||||
void sort(FolderData::ComparisonFunction & comparisonFunction = FolderData::compareFileName, bool ascending = true);
|
|
||||||
|
|
||||||
static GuiGameList* create(Window* window);
|
static GuiGameList* create(Window* window);
|
||||||
|
|
||||||
|
@ -55,8 +46,8 @@ private:
|
||||||
std::string getThemeFile();
|
std::string getThemeFile();
|
||||||
|
|
||||||
SystemData* mSystem;
|
SystemData* mSystem;
|
||||||
FolderData* mFolder;
|
FileData* mFolder;
|
||||||
std::stack<FolderData*> mFolderStack;
|
std::stack<FileData*> mFolderStack;
|
||||||
int mSystemId;
|
int mSystemId;
|
||||||
|
|
||||||
TextListComponent<FileData*> mList;
|
TextListComponent<FileData*> mList;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::function<void(MetaDataList)> doneFunc, std::function<void()> skipFunc) : GuiComponent(window),
|
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)),
|
mList(window, Eigen::Vector2i(2, 7 + MAX_SCRAPER_RESULTS)),
|
||||||
mBox(window, ":/frame.png"),
|
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)),
|
mResultName(window, "", Font::get(FONT_SIZE_MEDIUM)),
|
||||||
mResultInfo(window),
|
mResultInfo(window),
|
||||||
mResultDesc(window, "", Font::get(FONT_SIZE_SMALL)),
|
mResultDesc(window, "", Font::get(FONT_SIZE_SMALL)),
|
||||||
|
@ -56,7 +56,7 @@ GuiGameScraper::GuiGameScraper(Window* window, ScraperSearchParams params, std::
|
||||||
mResultName.setColor(0x3B56CCFF);
|
mResultName.setColor(0x3B56CCFF);
|
||||||
mList.setEntry(Vector2i(0, 1), Vector2i(1, 1), &mResultName, false, ComponentListComponent::AlignLeft);
|
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);
|
mResultDesc.setSize(colWidth, 0);
|
||||||
mResultInfo.addChild(&mResultDesc);
|
mResultInfo.addChild(&mResultDesc);
|
||||||
mResultInfo.setSize(mResultDesc.getSize().x(), mResultDesc.getFont()->getHeight() * 3.0f);
|
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
|
//y = 3 is a spacer row
|
||||||
|
|
||||||
mList.setEntry(Vector2i(0, 4), Vector2i(1, 1), &mSearchLabel, false, ComponentListComponent::AlignLeft);
|
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());
|
mSearchText.setSize(colWidth * 2 - mSearchLabel.getSize().x() - 20, mSearchText.getSize().y());
|
||||||
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mSearchText, true, ComponentListComponent::AlignRight);
|
mList.setEntry(Vector2i(1, 4), Vector2i(1, 1), &mSearchText, true, ComponentListComponent::AlignRight);
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "ComponentListComponent.h"
|
#include "ComponentListComponent.h"
|
||||||
#include "../MetaData.h"
|
#include "../MetaData.h"
|
||||||
#include "TextComponent.h"
|
#include "TextComponent.h"
|
||||||
#include "../GameData.h"
|
|
||||||
#include "NinePatchComponent.h"
|
#include "NinePatchComponent.h"
|
||||||
#include "ButtonComponent.h"
|
#include "ButtonComponent.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
|
@ -52,7 +52,7 @@ void GuiScraperLog::next()
|
||||||
ScraperSearchParams search = mSearches.front();
|
ScraperSearchParams search = mSearches.front();
|
||||||
mSearches.pop();
|
mSearches.pop();
|
||||||
|
|
||||||
writeLine(search.game->getCleanName(), 0x0000FFFF);
|
writeLine(getCleanFileName(search.game->getPath()), 0x0000FFFF);
|
||||||
|
|
||||||
if(mManualMode)
|
if(mManualMode)
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ void GuiScraperLog::resultFetched(ScraperSearchParams params, MetaDataList mdl)
|
||||||
void GuiScraperLog::resultResolved(ScraperSearchParams params, MetaDataList mdl)
|
void GuiScraperLog::resultResolved(ScraperSearchParams params, MetaDataList mdl)
|
||||||
{
|
{
|
||||||
//apply new metadata
|
//apply new metadata
|
||||||
*params.game->metadata() = mdl;
|
params.game->metadata = mdl;
|
||||||
|
|
||||||
writeLine(" Success!", 0x00FF00FF);
|
writeLine(" Success!", 0x00FF00FF);
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ void GuiScraperLog::resultEmpty(ScraperSearchParams search)
|
||||||
else
|
else
|
||||||
writeLine(" NO RESULTS, skipping", 0xFF0000FF);
|
writeLine(" NO RESULTS, skipping", 0xFF0000FF);
|
||||||
|
|
||||||
LOG(LogInfo) << "Scraper skipping [" << search.game->getCleanName() << "]";
|
LOG(LogInfo) << "Scraper skipping [" << getCleanFileName(search.game->getPath()) << "]";
|
||||||
|
|
||||||
mSkippedCount++;
|
mSkippedCount++;
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ GuiScraperStart::GuiScraperStart(Window* window) : GuiComponent(window),
|
||||||
|
|
||||||
//add filters (with first one selected)
|
//add filters (with first one selected)
|
||||||
mFiltersOpt.addEntry(mFiltersOpt.makeEntry("All Games",
|
mFiltersOpt.addEntry(mFiltersOpt.makeEntry("All Games",
|
||||||
[](SystemData*, GameData*) -> bool { return true; }, true));
|
[](SystemData*, FileData*) -> bool { return true; }, true));
|
||||||
mFiltersOpt.addEntry(mFiltersOpt.makeEntry("Missing Image",
|
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(0, 0), Vector2i(1, 1), &mFilterLabel, false, ComponentListComponent::AlignRight);
|
||||||
mList.setEntry(Vector2i(1, 0), Vector2i(1, 1), &mFiltersOpt, true, ComponentListComponent::AlignLeft);
|
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;
|
std::queue<ScraperSearchParams> queue;
|
||||||
for(auto sys = systems.begin(); sys != systems.end(); sys++)
|
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++)
|
for(auto game = games.begin(); game != games.end(); game++)
|
||||||
{
|
{
|
||||||
if(selector((*sys), (GameData*)(*game)))
|
if(selector((*sys), (*game)))
|
||||||
{
|
{
|
||||||
ScraperSearchParams search;
|
ScraperSearchParams search;
|
||||||
search.game = (GameData*)(*game);
|
search.game = *game;
|
||||||
search.system = *sys;
|
search.system = *sys;
|
||||||
|
|
||||||
queue.push(search);
|
queue.push(search);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "../scrapers/Scraper.h"
|
#include "../scrapers/Scraper.h"
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
typedef std::function<bool(SystemData*, GameData*)> GameFilterFunc;
|
typedef std::function<bool(SystemData*, FileData*)> GameFilterFunc;
|
||||||
|
|
||||||
//The starting point for a multi-game scrape.
|
//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).
|
//Allows the user to set various parameters (to set filters, to set which systems to scrape, to enable manual mode).
|
||||||
|
|
|
@ -60,7 +60,7 @@ std::shared_ptr<HttpReq> GamesDBScraper::makeHttpReq(ScraperSearchParams params)
|
||||||
|
|
||||||
std::string cleanName = params.nameOverride;
|
std::string cleanName = params.nameOverride;
|
||||||
if(cleanName.empty())
|
if(cleanName.empty())
|
||||||
cleanName = params.game->getCleanName();
|
cleanName = getCleanFileName(params.game->getPath());
|
||||||
|
|
||||||
path += "name=" + HttpReq::urlEncode(cleanName);
|
path += "name=" + HttpReq::urlEncode(cleanName);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
std::string getSaveAsPath(const ScraperSearchParams& params, const std::string& suffix, const std::string& url)
|
||||||
{
|
{
|
||||||
const std::string subdirectory = params.system->getName();
|
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/";
|
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)
|
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++)
|
for(auto it = mdd.begin(); it != mdd.end(); it++)
|
||||||
{
|
{
|
||||||
std::string key = it->key;
|
std::string key = it->key;
|
||||||
|
@ -190,7 +190,7 @@ void resolveMetaDataAssetsAsync(Window* window, const ScraperSearchParams& param
|
||||||
if(savedAs.empty())
|
if(savedAs.empty())
|
||||||
{
|
{
|
||||||
//error
|
//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);
|
mdl.set(key, savedAs);
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "../MetaData.h"
|
#include "../MetaData.h"
|
||||||
#include "../SystemData.h"
|
#include "../SystemData.h"
|
||||||
#include "../GameData.h"
|
|
||||||
#include "../HttpReq.h"
|
#include "../HttpReq.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -12,7 +11,7 @@ class Window;
|
||||||
struct ScraperSearchParams
|
struct ScraperSearchParams
|
||||||
{
|
{
|
||||||
SystemData* system;
|
SystemData* system;
|
||||||
GameData* game;
|
FileData* game;
|
||||||
|
|
||||||
std::string nameOverride;
|
std::string nameOverride;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ std::shared_ptr<HttpReq> TheArchiveScraper::makeHttpReq(ScraperSearchParams para
|
||||||
|
|
||||||
std::string cleanName = params.nameOverride;
|
std::string cleanName = params.nameOverride;
|
||||||
if(cleanName.empty())
|
if(cleanName.empty())
|
||||||
cleanName = params.game->getCleanName();
|
cleanName = getCleanFileName(params.game->getPath());
|
||||||
|
|
||||||
path += HttpReq::urlEncode(cleanName);
|
path += HttpReq::urlEncode(cleanName);
|
||||||
//platform TODO, should use some params.system get method
|
//platform TODO, should use some params.system get method
|
||||||
|
|
Loading…
Reference in a new issue