2020-09-21 17:17:34 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-22 15:27:53 +00:00
|
|
|
//
|
2020-09-21 17:17:34 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-22 15:27:53 +00:00
|
|
|
// FileSorts.cpp
|
|
|
|
//
|
|
|
|
// Gamelist sorting functions.
|
|
|
|
// Actual sorting takes place in FileData.
|
|
|
|
//
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "FileSorts.h"
|
|
|
|
|
2018-01-09 21:59:23 +00:00
|
|
|
#include "utils/StringUtil.h"
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <string>
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
namespace FileSorts
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
const FileData::SortType typesArr[] = {
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareName, "filename, ascending"),
|
|
|
|
FileData::SortType(&compareNameDescending, "filename, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareRating, "rating, ascending"),
|
|
|
|
FileData::SortType(&compareRatingDescending, "rating, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareReleaseDate, "release date, ascending"),
|
|
|
|
FileData::SortType(&compareReleaseDateDescending, "release date, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareDeveloper, "developer, ascending"),
|
|
|
|
FileData::SortType(&compareDeveloperDescending, "developer, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&comparePublisher, "publisher, ascending"),
|
|
|
|
FileData::SortType(&comparePublisherDescending, "publisher, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareGenre, "genre, ascending"),
|
|
|
|
FileData::SortType(&compareGenreDescending, "genre, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareNumPlayers, "players, ascending"),
|
|
|
|
FileData::SortType(&compareNumPlayersDescending, "players, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareLastPlayed, "last played, ascending"),
|
|
|
|
FileData::SortType(&compareLastPlayedDescending, "last played, descending"),
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-01-08 20:36:43 +00:00
|
|
|
FileData::SortType(&compareTimesPlayed, "times played, ascending"),
|
|
|
|
FileData::SortType(&compareTimesPlayedDescending, "times played, descending"),
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
FileData::SortType(&compareSystem, "system, ascending"),
|
|
|
|
FileData::SortType(&compareSystemDescending, "system, descending")
|
2020-06-22 15:27:53 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const std::vector<FileData::SortType> SortTypes(typesArr, typesArr +
|
|
|
|
sizeof(typesArr)/sizeof(typesArr[0]));
|
|
|
|
|
|
|
|
bool compareName(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
// We compare the actual metadata name, as collection files have the system
|
|
|
|
// appended which messes up the order.
|
|
|
|
std::string name1 = Utils::String::toUpper(file1->metadata.get("sortname"));
|
|
|
|
std::string name2 = Utils::String::toUpper(file2->metadata.get("sortname"));
|
2021-01-08 19:30:21 +00:00
|
|
|
if (name1.empty())
|
2020-06-22 15:27:53 +00:00
|
|
|
name1 = Utils::String::toUpper(file1->metadata.get("name"));
|
2021-01-08 19:30:21 +00:00
|
|
|
if (name2.empty())
|
2020-06-22 15:27:53 +00:00
|
|
|
name2 = Utils::String::toUpper(file2->metadata.get("name"));
|
|
|
|
return name1.compare(name2) < 0;
|
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool compareNameDescending(const FileData* file1, const FileData* file2)
|
2020-06-22 15:27:53 +00:00
|
|
|
{
|
2021-01-08 19:30:21 +00:00
|
|
|
std::string name1 = Utils::String::toUpper(file1->metadata.get("sortname"));
|
|
|
|
std::string name2 = Utils::String::toUpper(file2->metadata.get("sortname"));
|
|
|
|
if (name1.empty())
|
|
|
|
name1 = Utils::String::toUpper(file1->metadata.get("name"));
|
|
|
|
if (name2.empty())
|
|
|
|
name2 = Utils::String::toUpper(file2->metadata.get("name"));
|
|
|
|
return name1.compare(name2) > 0;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool compareRating(const FileData* file1, const FileData* file2)
|
2020-06-22 15:27:53 +00:00
|
|
|
{
|
2021-01-08 19:30:21 +00:00
|
|
|
return file1->metadata.getFloat("rating") < file2->metadata.getFloat("rating");
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool compareRatingDescending(const FileData* file1, const FileData* file2)
|
2020-06-22 15:27:53 +00:00
|
|
|
{
|
2021-01-08 19:30:21 +00:00
|
|
|
return file1->metadata.getFloat("rating") > file2->metadata.getFloat("rating");
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool compareReleaseDate(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
// Since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
|
|
|
// which is a lot faster than the time casts and the time comparisons.
|
|
|
|
return (file1)->metadata.get("releasedate") < (file2)->metadata.get("releasedate");
|
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool compareReleaseDateDescending(const FileData* file1, const FileData* file2)
|
2020-06-22 15:27:53 +00:00
|
|
|
{
|
2021-01-08 19:30:21 +00:00
|
|
|
return (file1)->metadata.get("releasedate") > (file2)->metadata.get("releasedate");
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool compareDeveloper(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string developer1 = Utils::String::toUpper(file1->metadata.get("developer"));
|
|
|
|
std::string developer2 = Utils::String::toUpper(file2->metadata.get("developer"));
|
|
|
|
return developer1.compare(developer2) < 0;
|
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool compareDeveloperDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string developer1 = Utils::String::toUpper(file1->metadata.get("developer"));
|
|
|
|
std::string developer2 = Utils::String::toUpper(file2->metadata.get("developer"));
|
|
|
|
return developer1.compare(developer2) > 0;
|
|
|
|
}
|
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
bool comparePublisher(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string publisher1 = Utils::String::toUpper(file1->metadata.get("publisher"));
|
|
|
|
std::string publisher2 = Utils::String::toUpper(file2->metadata.get("publisher"));
|
|
|
|
return publisher1.compare(publisher2) < 0;
|
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
bool comparePublisherDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string publisher1 = Utils::String::toUpper(file1->metadata.get("publisher"));
|
|
|
|
std::string publisher2 = Utils::String::toUpper(file2->metadata.get("publisher"));
|
|
|
|
return publisher1.compare(publisher2) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compareGenre(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string genre1 = Utils::String::toUpper(file1->metadata.get("genre"));
|
|
|
|
std::string genre2 = Utils::String::toUpper(file2->metadata.get("genre"));
|
|
|
|
return genre1.compare(genre2) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compareGenreDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string genre1 = Utils::String::toUpper(file1->metadata.get("genre"));
|
|
|
|
std::string genre2 = Utils::String::toUpper(file2->metadata.get("genre"));
|
|
|
|
return genre1.compare(genre2) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compareNumPlayers(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string file1Players = (file1)->metadata.get("players");
|
|
|
|
std::string file2Players = (file2)->metadata.get("players");
|
|
|
|
unsigned int file1Int = 0;
|
|
|
|
unsigned int file2Int = 0;
|
|
|
|
size_t dashPos;
|
|
|
|
// If there is a range of players such as '1-4' then capture the number after the dash.
|
|
|
|
dashPos = file1Players.find("-");
|
|
|
|
if (dashPos != std::string::npos)
|
|
|
|
file1Players = file1Players.substr(dashPos + 1, file1Players.size() - dashPos - 1);
|
|
|
|
dashPos = file2Players.find("-");
|
|
|
|
if (dashPos != std::string::npos)
|
|
|
|
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
|
|
|
// Any non-numeric value will end up as zero.
|
|
|
|
if (!file1Players.empty() &&
|
|
|
|
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
|
|
|
file1Int = stoi(file1Players);
|
|
|
|
if (!file2Players.empty() &&
|
|
|
|
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
|
|
|
file2Int = stoi(file2Players);
|
|
|
|
return file1Int < file2Int;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compareNumPlayersDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string file1Players = (file1)->metadata.get("players");
|
|
|
|
std::string file2Players = (file2)->metadata.get("players");
|
|
|
|
unsigned int file1Int = 0;
|
|
|
|
unsigned int file2Int = 0;
|
|
|
|
size_t dashPos;
|
|
|
|
dashPos = file1Players.find("-");
|
|
|
|
if (dashPos != std::string::npos)
|
|
|
|
file1Players = file1Players.substr(dashPos + 1, file1Players.size() - dashPos - 1);
|
|
|
|
dashPos = file2Players.find("-");
|
|
|
|
if (dashPos != std::string::npos)
|
|
|
|
file2Players = file2Players.substr(dashPos + 1, file2Players.size() - dashPos - 1);
|
|
|
|
if (!file1Players.empty() &&
|
|
|
|
std::all_of(file1Players.begin(), file1Players.end(), ::isdigit))
|
|
|
|
file1Int = stoi(file1Players);
|
|
|
|
if (!file2Players.empty() &&
|
|
|
|
std::all_of(file2Players.begin(), file2Players.end(), ::isdigit))
|
|
|
|
file2Int = stoi(file2Players);
|
|
|
|
return file1Int > file2Int;
|
|
|
|
}
|
|
|
|
|
2021-01-08 20:36:43 +00:00
|
|
|
bool compareLastPlayed(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
// Since it's stored as an ISO string (YYYYMMDDTHHMMSS), we can compare as a string
|
|
|
|
// which is a lot faster than the time casts and the time comparisons.
|
|
|
|
return (file1)->metadata.get("lastplayed") > (file2)->metadata.get("lastplayed");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compareLastPlayedDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
return (file1)->metadata.get("lastplayed") < (file2)->metadata.get("lastplayed");
|
|
|
|
}
|
|
|
|
|
2021-01-08 19:30:21 +00:00
|
|
|
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 compareTimesPlayedDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
if (file1->metadata.getType() == GAME_METADATA &&
|
|
|
|
file2->metadata.getType() == GAME_METADATA)
|
|
|
|
return (file1)->metadata.getInt("playcount") > (file2)->metadata.getInt("playcount");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
bool compareSystem(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string system1 = Utils::String::toUpper(file1->getSystemName());
|
|
|
|
std::string system2 = Utils::String::toUpper(file2->getSystemName());
|
|
|
|
return system1.compare(system2) < 0;
|
|
|
|
}
|
2021-01-08 19:30:21 +00:00
|
|
|
|
|
|
|
bool compareSystemDescending(const FileData* file1, const FileData* file2)
|
|
|
|
{
|
|
|
|
std::string system1 = Utils::String::toUpper(file1->getSystemName());
|
|
|
|
std::string system2 = Utils::String::toUpper(file2->getSystemName());
|
|
|
|
return system1.compare(system2) > 0;
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
};
|