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
|
|
|
// FileFilterIndex.cpp
|
|
|
|
//
|
|
|
|
// Gamelist filters.
|
|
|
|
//
|
|
|
|
|
2017-03-18 17:54:39 +00:00
|
|
|
#include "FileFilterIndex.h"
|
|
|
|
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "FileData.h"
|
|
|
|
#include "Log.h"
|
2017-11-18 22:23:56 +00:00
|
|
|
#include "Settings.h"
|
2021-07-07 18:03:42 +00:00
|
|
|
#include "utils/StringUtil.h"
|
|
|
|
#include "views/UIModeController.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2020-12-28 10:29:32 +00:00
|
|
|
#include <cmath>
|
|
|
|
|
2017-03-18 17:54:39 +00:00
|
|
|
#define UNKNOWN_LABEL "UNKNOWN"
|
|
|
|
#define INCLUDE_UNKNOWN false;
|
|
|
|
|
2017-05-18 10:16:57 +00:00
|
|
|
FileFilterIndex::FileFilterIndex()
|
2021-07-07 18:03:42 +00:00
|
|
|
: mFilterByText(false)
|
2021-09-23 15:42:04 +00:00
|
|
|
, mTextRemoveSystem(false)
|
2021-07-07 18:03:42 +00:00
|
|
|
, mFilterByFavorites(false)
|
|
|
|
, mFilterByGenre(false)
|
|
|
|
, mFilterByPlayers(false)
|
|
|
|
, mFilterByPubDev(false)
|
|
|
|
, mFilterByRatings(false)
|
|
|
|
, mFilterByKidGame(false)
|
|
|
|
, mFilterByCompleted(false)
|
|
|
|
, mFilterByBroken(false)
|
|
|
|
, mFilterByHidden(false)
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
clearAllFilters();
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
// clang-format off
|
2020-06-22 15:27:53 +00:00
|
|
|
FilterDataDecl filterDecls[] = {
|
2021-09-23 15:42:04 +00:00
|
|
|
//type //allKeys //filteredBy //filteredKeys //primaryKey //hasSecondaryKey //secondaryKey //menuLabel
|
2021-08-17 16:41:45 +00:00
|
|
|
{FAVORITES_FILTER, &mFavoritesIndexAllKeys, &mFilterByFavorites, &mFavoritesIndexFilteredKeys, "favorite", false, "", "FAVORITES"},
|
|
|
|
{GENRE_FILTER, &mGenreIndexAllKeys, &mFilterByGenre, &mGenreIndexFilteredKeys, "genre", true, "genre", "GENRE"},
|
|
|
|
{PLAYER_FILTER, &mPlayersIndexAllKeys, &mFilterByPlayers, &mPlayersIndexFilteredKeys, "players", false, "", "PLAYERS"},
|
|
|
|
{PUBDEV_FILTER, &mPubDevIndexAllKeys, &mFilterByPubDev, &mPubDevIndexFilteredKeys, "developer", true, "publisher", "PUBLISHER / DEVELOPER"},
|
|
|
|
{RATINGS_FILTER, &mRatingsIndexAllKeys, &mFilterByRatings, &mRatingsIndexFilteredKeys, "rating", false, "", "RATING"},
|
|
|
|
{KIDGAME_FILTER, &mKidGameIndexAllKeys, &mFilterByKidGame, &mKidGameIndexFilteredKeys, "kidgame", false, "", "KIDGAME"},
|
|
|
|
{COMPLETED_FILTER, &mCompletedIndexAllKeys, &mFilterByCompleted, &mCompletedIndexFilteredKeys, "completed", false, "", "COMPLETED"},
|
|
|
|
{BROKEN_FILTER, &mBrokenIndexAllKeys, &mFilterByBroken, &mBrokenIndexFilteredKeys, "broken", false, "", "BROKEN"},
|
|
|
|
{HIDDEN_FILTER, &mHiddenIndexAllKeys, &mFilterByHidden, &mHiddenIndexFilteredKeys, "hidden", false, "", "HIDDEN"}
|
2020-06-22 15:27:53 +00:00
|
|
|
};
|
2021-07-07 18:03:42 +00:00
|
|
|
// clang-format on
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
filterDataDecl = std::vector<FilterDataDecl>(
|
|
|
|
filterDecls, filterDecls + sizeof(filterDecls) / sizeof(filterDecls[0]));
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FileFilterIndex::~FileFilterIndex()
|
|
|
|
{
|
2021-07-07 18:03:42 +00:00
|
|
|
// Reset the index when destroyed.
|
2020-06-22 15:27:53 +00:00
|
|
|
resetIndex();
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 09:45:50 +00:00
|
|
|
void FileFilterIndex::importIndex(FileFilterIndex* indexToImport)
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
struct IndexImportStructure {
|
|
|
|
std::map<std::string, int>* destinationIndex;
|
|
|
|
std::map<std::string, int>* sourceIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
IndexImportStructure indexStructDecls[] = {
|
2021-08-17 16:41:45 +00:00
|
|
|
{&mFavoritesIndexAllKeys, &(indexToImport->mFavoritesIndexAllKeys)},
|
|
|
|
{&mGenreIndexAllKeys, &(indexToImport->mGenreIndexAllKeys)},
|
|
|
|
{&mPlayersIndexAllKeys, &(indexToImport->mPlayersIndexAllKeys)},
|
|
|
|
{&mPubDevIndexAllKeys, &(indexToImport->mPubDevIndexAllKeys)},
|
|
|
|
{&mRatingsIndexAllKeys, &(indexToImport->mRatingsIndexAllKeys)},
|
|
|
|
{&mKidGameIndexAllKeys, &(indexToImport->mKidGameIndexAllKeys)},
|
|
|
|
{&mCompletedIndexAllKeys, &(indexToImport->mCompletedIndexAllKeys)},
|
|
|
|
{&mBrokenIndexAllKeys, &(indexToImport->mBrokenIndexAllKeys)},
|
|
|
|
{&mHiddenIndexAllKeys, &(indexToImport->mHiddenIndexAllKeys)},
|
2020-06-22 15:27:53 +00:00
|
|
|
};
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
std::vector<IndexImportStructure> indexImportDecl = std::vector<IndexImportStructure>(
|
|
|
|
indexStructDecls,
|
|
|
|
indexStructDecls + sizeof(indexStructDecls) / sizeof(indexStructDecls[0]));
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
for (std::vector<IndexImportStructure>::const_iterator indexesIt = indexImportDecl.cbegin();
|
|
|
|
indexesIt != indexImportDecl.cend(); indexesIt++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
for (std::map<std::string, int>::const_iterator sourceIt =
|
2021-07-07 18:03:42 +00:00
|
|
|
(*indexesIt).sourceIndex->cbegin();
|
|
|
|
sourceIt != (*indexesIt).sourceIndex->cend(); sourceIt++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
if ((*indexesIt).destinationIndex->find((*sourceIt).first) ==
|
2021-07-07 18:03:42 +00:00
|
|
|
(*indexesIt).destinationIndex->cend()) {
|
2020-06-22 15:27:53 +00:00
|
|
|
// Entry doesn't exist.
|
|
|
|
(*((*indexesIt).destinationIndex))[(*sourceIt).first] = (*sourceIt).second;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-06-22 15:27:53 +00:00
|
|
|
(*((*indexesIt).destinationIndex))[(*sourceIt).first] += (*sourceIt).second;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-18 09:45:50 +00:00
|
|
|
}
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2017-07-18 09:45:50 +00:00
|
|
|
void FileFilterIndex::resetIndex()
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
clearAllFilters();
|
2020-11-08 15:47:51 +00:00
|
|
|
clearIndex(mFavoritesIndexAllKeys);
|
|
|
|
clearIndex(mGenreIndexAllKeys);
|
|
|
|
clearIndex(mPlayersIndexAllKeys);
|
|
|
|
clearIndex(mPubDevIndexAllKeys);
|
|
|
|
clearIndex(mRatingsIndexAllKeys);
|
|
|
|
clearIndex(mKidGameIndexAllKeys);
|
|
|
|
clearIndex(mCompletedIndexAllKeys);
|
|
|
|
clearIndex(mBrokenIndexAllKeys);
|
|
|
|
clearIndex(mHiddenIndexAllKeys);
|
2017-07-18 09:45:50 +00:00
|
|
|
}
|
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
std::string FileFilterIndex::getIndexableKey(FileData* game,
|
2021-07-07 18:03:42 +00:00
|
|
|
FilterIndexType type,
|
|
|
|
bool getSecondary)
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
std::string key = "";
|
|
|
|
switch (type) {
|
2020-10-27 19:58:42 +00:00
|
|
|
case FAVORITES_FILTER: {
|
|
|
|
if (game->getType() != GAME)
|
|
|
|
return "FALSE";
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("favorite"));
|
|
|
|
break;
|
|
|
|
}
|
2020-06-22 15:27:53 +00:00
|
|
|
case GENRE_FILTER: {
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("genre"));
|
|
|
|
key = Utils::String::trim(key);
|
|
|
|
if (getSecondary && !key.empty()) {
|
|
|
|
std::istringstream f(key);
|
|
|
|
std::string newKey;
|
|
|
|
getline(f, newKey, '/');
|
|
|
|
if (!newKey.empty() && newKey != key)
|
|
|
|
key = newKey;
|
|
|
|
else
|
|
|
|
key = std::string();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PLAYER_FILTER: {
|
|
|
|
if (getSecondary)
|
|
|
|
break;
|
|
|
|
|
2020-10-18 17:11:19 +00:00
|
|
|
key = Utils::String::toUpper(game->metadata.get("players"));
|
2020-06-22 15:27:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PUBDEV_FILTER: {
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("publisher"));
|
|
|
|
key = Utils::String::trim(key);
|
|
|
|
|
|
|
|
if ((getSecondary && !key.empty()) || (!getSecondary && key.empty()))
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("developer"));
|
|
|
|
else
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("publisher"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case RATINGS_FILTER: {
|
|
|
|
int ratingNumber = 0;
|
|
|
|
if (!getSecondary) {
|
|
|
|
std::string ratingString = game->metadata.get("rating");
|
|
|
|
if (!ratingString.empty()) {
|
|
|
|
try {
|
2020-10-27 19:58:42 +00:00
|
|
|
// Round up fractional values such as 0.75 to 0.8.
|
|
|
|
// These values should only exist if a third party application has
|
|
|
|
// been used for scraping the ratings, or if the gamelist.xml file
|
|
|
|
// has been manually edited.
|
2021-07-07 18:03:42 +00:00
|
|
|
ratingNumber =
|
|
|
|
static_cast<int>((ceilf(stof(ratingString) / 0.1f) / 10.0f) * 5.0f);
|
2020-10-27 19:58:42 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
if (ratingNumber < 0)
|
|
|
|
ratingNumber = 0;
|
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
if (ratingNumber == 5)
|
|
|
|
key = "5 STARS";
|
|
|
|
else
|
|
|
|
key = std::to_string(ratingNumber) + " - " +
|
2021-07-07 18:03:42 +00:00
|
|
|
std::to_string(ratingNumber) + ".5 STARS";
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
catch (int e) {
|
2021-07-07 18:03:42 +00:00
|
|
|
LOG(LogError) << "Error parsing Rating (invalid value, exception nr.): "
|
|
|
|
<< ratingString << ", " << e;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-10-27 19:58:42 +00:00
|
|
|
case KIDGAME_FILTER: {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (game->getType() != GAME)
|
|
|
|
return "FALSE";
|
2020-10-27 19:58:42 +00:00
|
|
|
key = Utils::String::toUpper(game->metadata.get("kidgame"));
|
2020-06-22 15:27:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 19:58:42 +00:00
|
|
|
case COMPLETED_FILTER: {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (game->getType() != GAME)
|
|
|
|
return "FALSE";
|
2020-10-27 19:58:42 +00:00
|
|
|
key = Utils::String::toUpper(game->metadata.get("completed"));
|
2020-06-22 15:27:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-10-27 19:58:42 +00:00
|
|
|
case BROKEN_FILTER: {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (game->getType() != GAME)
|
|
|
|
return "FALSE";
|
2020-10-27 19:58:42 +00:00
|
|
|
key = Utils::String::toUpper(game->metadata.get("broken"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case HIDDEN_FILTER: {
|
|
|
|
if (game->getType() != GAME)
|
|
|
|
return "FALSE";
|
|
|
|
key = Utils::String::toUpper(game->metadata.get("hidden"));
|
2020-06-22 15:27:53 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-06-25 17:52:38 +00:00
|
|
|
default:
|
|
|
|
break;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
key = Utils::String::trim(key);
|
|
|
|
if (key.empty() || (type == RATINGS_FILTER && key == "0 STARS")) {
|
|
|
|
key = UNKNOWN_LABEL;
|
|
|
|
}
|
|
|
|
return key;
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::addToIndex(FileData* game)
|
|
|
|
{
|
2020-10-27 19:58:42 +00:00
|
|
|
manageFavoritesEntryInIndex(game);
|
2020-06-22 15:27:53 +00:00
|
|
|
manageGenreEntryInIndex(game);
|
|
|
|
managePlayerEntryInIndex(game);
|
|
|
|
managePubDevEntryInIndex(game);
|
|
|
|
manageRatingsEntryInIndex(game);
|
|
|
|
manageKidGameEntryInIndex(game);
|
2020-10-27 19:58:42 +00:00
|
|
|
manageCompletedEntryInIndex(game);
|
|
|
|
manageBrokenEntryInIndex(game);
|
|
|
|
manageHiddenEntryInIndex(game);
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::removeFromIndex(FileData* game)
|
|
|
|
{
|
2020-10-27 19:58:42 +00:00
|
|
|
manageFavoritesEntryInIndex(game, true);
|
2020-06-22 15:27:53 +00:00
|
|
|
manageGenreEntryInIndex(game, true);
|
|
|
|
managePlayerEntryInIndex(game, true);
|
|
|
|
managePubDevEntryInIndex(game, true);
|
|
|
|
manageRatingsEntryInIndex(game, true);
|
|
|
|
manageKidGameEntryInIndex(game, true);
|
2020-10-27 19:58:42 +00:00
|
|
|
manageCompletedEntryInIndex(game, true);
|
|
|
|
manageBrokenEntryInIndex(game, true);
|
|
|
|
manageHiddenEntryInIndex(game, true);
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 10:16:57 +00:00
|
|
|
void FileFilterIndex::setFilter(FilterIndexType type, std::vector<std::string>* values)
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// Test if it exists before setting.
|
|
|
|
if (type == NONE) {
|
|
|
|
clearAllFilters();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
2021-07-07 18:03:42 +00:00
|
|
|
it != filterDataDecl.cend(); it++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
if ((*it).type == type) {
|
|
|
|
FilterDataDecl filterData = (*it);
|
|
|
|
*(filterData.filteredByRef) = values->size() > 0;
|
|
|
|
filterData.currentFilteredKeys->clear();
|
2021-07-07 18:03:42 +00:00
|
|
|
for (std::vector<std::string>::const_iterator vit = values->cbegin();
|
|
|
|
vit != values->cend(); vit++) {
|
2020-10-27 19:58:42 +00:00
|
|
|
// Check if it exists.
|
2020-06-22 15:27:53 +00:00
|
|
|
if (filterData.allIndexKeys->find(*vit) != filterData.allIndexKeys->cend()) {
|
|
|
|
filterData.currentFilteredKeys->push_back(std::string(*vit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
void FileFilterIndex::setTextFilter(std::string textFilter)
|
|
|
|
{
|
2020-11-08 15:34:33 +00:00
|
|
|
mTextFilter = textFilter;
|
|
|
|
|
|
|
|
if (textFilter == "")
|
|
|
|
mFilterByText = false;
|
|
|
|
else
|
|
|
|
mFilterByText = true;
|
2021-09-18 07:53:26 +00:00
|
|
|
}
|
2020-11-08 15:34:33 +00:00
|
|
|
|
2017-05-18 10:16:57 +00:00
|
|
|
void FileFilterIndex::clearAllFilters()
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
2021-07-07 18:03:42 +00:00
|
|
|
it != filterDataDecl.cend(); it++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
FilterDataDecl filterData = (*it);
|
|
|
|
*(filterData.filteredByRef) = false;
|
|
|
|
filterData.currentFilteredKeys->clear();
|
|
|
|
}
|
2021-01-05 09:45:32 +00:00
|
|
|
setTextFilter("");
|
2020-06-22 15:27:53 +00:00
|
|
|
return;
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2017-09-08 13:20:07 +00:00
|
|
|
void FileFilterIndex::resetFilters()
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
clearAllFilters();
|
2021-01-05 09:45:32 +00:00
|
|
|
setKidModeFilters();
|
2017-09-08 13:20:07 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 09:45:32 +00:00
|
|
|
void FileFilterIndex::setKidModeFilters()
|
2017-09-08 13:20:07 +00:00
|
|
|
{
|
2021-01-05 09:45:32 +00:00
|
|
|
if (UIModeController::getInstance()->isUIModeKid()) {
|
|
|
|
mFilterByKidGame = true;
|
2021-08-17 16:41:45 +00:00
|
|
|
std::vector<std::string> val = {"TRUE"};
|
2021-01-05 09:45:32 +00:00
|
|
|
setFilter(KIDGAME_FILTER, &val);
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
2017-09-08 13:20:07 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 10:16:57 +00:00
|
|
|
void FileFilterIndex::debugPrintIndexes()
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
LOG(LogInfo) << "Printing Indexes...";
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto x : mFavoritesIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Favorites Index: " << x.first << ": " << x.second;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto x : mGenreIndexAllKeys) {
|
2020-06-22 15:27:53 +00:00
|
|
|
LOG(LogInfo) << "Genre Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto x : mPlayersIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Multiplayer Index: " << x.first << ": " << x.second;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto x : mPubDevIndexAllKeys) {
|
2020-06-22 15:27:53 +00:00
|
|
|
LOG(LogInfo) << "PubDev Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto x : mRatingsIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Ratings Index: " << x.first << ": " << x.second;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
2020-11-08 15:47:51 +00:00
|
|
|
for (auto x : mKidGameIndexAllKeys) {
|
2020-06-22 15:27:53 +00:00
|
|
|
LOG(LogInfo) << "KidGames Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2020-11-08 15:47:51 +00:00
|
|
|
for (auto x : mCompletedIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Completed Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2020-11-08 15:47:51 +00:00
|
|
|
for (auto x : mBrokenIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Broken Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2020-11-08 15:47:51 +00:00
|
|
|
for (auto x : mHiddenIndexAllKeys) {
|
2020-10-27 19:58:42 +00:00
|
|
|
LOG(LogInfo) << "Hidden Index: " << x.first << ": " << x.second;
|
|
|
|
}
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool FileFilterIndex::showFile(FileData* game)
|
2017-05-18 10:16:57 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// If folder, needs further inspection - i.e. see if folder contains at least one element
|
|
|
|
// that should be shown.
|
|
|
|
if (game->getType() == FOLDER) {
|
|
|
|
std::vector<FileData*> children = game->getChildren();
|
|
|
|
// Iterate through all of the children, until there's a match.
|
2021-07-07 18:03:42 +00:00
|
|
|
for (std::vector<FileData*>::const_iterator it = children.cbegin(); it != children.cend();
|
|
|
|
it++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (showFile(*it))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-08 15:34:33 +00:00
|
|
|
bool nameMatch = false;
|
2020-06-22 15:27:53 +00:00
|
|
|
bool keepGoing = false;
|
|
|
|
|
2020-11-08 15:34:33 +00:00
|
|
|
// Name filters take precedence over all other filters, so if there is no match for
|
2021-09-23 15:42:04 +00:00
|
|
|
// the game name, then always return false. If we're in a collection system and the option
|
|
|
|
// to show the system name has been enabled, then exclude the system name that is encapsulated
|
|
|
|
// in [] from the search string.
|
|
|
|
if (mTextFilter != "" && mTextRemoveSystem &&
|
|
|
|
!(Utils::String::toUpper(game->getName().substr(0, game->getName().find_last_of("[")))
|
|
|
|
.find(mTextFilter) != std::string::npos)) {
|
2020-11-08 15:34:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-09-23 15:42:04 +00:00
|
|
|
else if (mTextFilter != "" &&
|
|
|
|
!(Utils::String::toUpper(game->getName()).find(mTextFilter) != std::string::npos)) {
|
|
|
|
return false;
|
2020-11-08 15:34:33 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 15:42:04 +00:00
|
|
|
if (mTextFilter != "")
|
|
|
|
nameMatch = true;
|
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
for (std::vector<FilterDataDecl>::const_iterator it = filterDataDecl.cbegin();
|
2021-07-07 18:03:42 +00:00
|
|
|
it != filterDataDecl.cend(); it++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
FilterDataDecl filterData = (*it);
|
2021-01-05 09:45:32 +00:00
|
|
|
if (filterData.primaryKey == "kidgame" && UIModeController::getInstance()->isUIModeKid()) {
|
|
|
|
return (getIndexableKey(game, filterData.type, false) != "FALSE");
|
|
|
|
}
|
|
|
|
else if (*(filterData.filteredByRef)) {
|
2020-06-22 15:27:53 +00:00
|
|
|
// Try to find a match.
|
|
|
|
std::string key = getIndexableKey(game, filterData.type, false);
|
|
|
|
keepGoing = isKeyBeingFilteredBy(key, filterData.type);
|
|
|
|
|
|
|
|
// If we didn't find a match, try for secondary keys - i.e.
|
|
|
|
// publisher and dev, or first genre.
|
|
|
|
if (!keepGoing) {
|
|
|
|
if (!filterData.hasSecondaryKey)
|
|
|
|
return false;
|
|
|
|
std::string secKey = getIndexableKey(game, filterData.type, true);
|
|
|
|
if (secKey != UNKNOWN_LABEL)
|
|
|
|
keepGoing = isKeyBeingFilteredBy(secKey, filterData.type);
|
|
|
|
}
|
|
|
|
// If still nothing, then it's not a match.
|
|
|
|
if (!keepGoing)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-11-08 15:34:33 +00:00
|
|
|
|
|
|
|
// If there is a match for the game name, but not for any other filters, then return
|
|
|
|
// true as it means that the name filter is the only applied filter.
|
|
|
|
if (!keepGoing && nameMatch)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return keepGoing;
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2021-01-05 09:45:32 +00:00
|
|
|
bool FileFilterIndex::isFiltered()
|
|
|
|
{
|
|
|
|
if (UIModeController::getInstance()->isUIModeKid()) {
|
|
|
|
return (mFilterByText || mFilterByFavorites || mFilterByGenre || mFilterByPlayers ||
|
|
|
|
mFilterByPubDev || mFilterByRatings || mFilterByCompleted || mFilterByBroken ||
|
|
|
|
mFilterByHidden);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return (mFilterByText || mFilterByFavorites || mFilterByGenre || mFilterByPlayers ||
|
|
|
|
mFilterByPubDev || mFilterByRatings || mFilterByKidGame || mFilterByCompleted ||
|
|
|
|
mFilterByBroken || mFilterByHidden);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-18 10:16:57 +00:00
|
|
|
bool FileFilterIndex::isKeyBeingFilteredBy(std::string key, FilterIndexType type)
|
|
|
|
{
|
2021-08-17 16:41:45 +00:00
|
|
|
const FilterIndexType filterTypes[9] = {FAVORITES_FILTER, GENRE_FILTER, PLAYER_FILTER,
|
|
|
|
PUBDEV_FILTER, RATINGS_FILTER, KIDGAME_FILTER,
|
|
|
|
COMPLETED_FILTER, BROKEN_FILTER, HIDDEN_FILTER};
|
2021-07-07 18:03:42 +00:00
|
|
|
std::vector<std::string> filterKeysList[9] = {
|
|
|
|
mFavoritesIndexFilteredKeys, mGenreIndexFilteredKeys, mPlayersIndexFilteredKeys,
|
|
|
|
mPubDevIndexFilteredKeys, mRatingsIndexFilteredKeys, mKidGameIndexFilteredKeys,
|
2021-08-17 16:41:45 +00:00
|
|
|
mCompletedIndexFilteredKeys, mBrokenIndexFilteredKeys, mHiddenIndexFilteredKeys};
|
2020-06-22 15:27:53 +00:00
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
for (int i = 0; i < 9; i++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (filterTypes[i] == type) {
|
|
|
|
for (std::vector<std::string>::const_iterator it = filterKeysList[i].cbegin();
|
2021-07-07 18:03:42 +00:00
|
|
|
it != filterKeysList[i].cend(); it++) {
|
2020-06-22 15:27:53 +00:00
|
|
|
if (key == (*it))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
void FileFilterIndex::manageFavoritesEntryInIndex(FileData* game, bool remove)
|
2017-03-18 17:54:39 +00:00
|
|
|
{
|
2020-10-27 19:58:42 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
|
|
|
std::string key = getIndexableKey(game, FAVORITES_FILTER, false);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
|
|
|
// No valid favorites info found.
|
|
|
|
return;
|
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mFavoritesIndexAllKeys, key, remove);
|
2020-10-27 19:58:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::manageGenreEntryInIndex(FileData* game, bool remove)
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
std::string key = getIndexableKey(game, GENRE_FILTER, false);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
// Only add unknown in pubdev IF both dev and pub are empty.
|
|
|
|
if (!includeUnknown && (key == UNKNOWN_LABEL || key == "BIOS"))
|
|
|
|
// No valid genre info found.
|
|
|
|
return;
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mGenreIndexAllKeys, key, remove);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
key = getIndexableKey(game, GENRE_FILTER, true);
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mGenreIndexAllKeys, key, remove);
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::managePlayerEntryInIndex(FileData* game, bool remove)
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
|
|
|
std::string key = getIndexableKey(game, PLAYER_FILTER, false);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
// Only add unknown in pubdev IF both dev and pub are empty.
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
|
|
|
// No valid player info found.
|
|
|
|
return;
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mPlayersIndexAllKeys, key, remove);
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::managePubDevEntryInIndex(FileData* game, bool remove)
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
std::string pub = getIndexableKey(game, PUBDEV_FILTER, false);
|
|
|
|
std::string dev = getIndexableKey(game, PUBDEV_FILTER, true);
|
|
|
|
|
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
|
|
|
bool unknownPub = false;
|
|
|
|
bool unknownDev = false;
|
|
|
|
|
|
|
|
if (pub == UNKNOWN_LABEL)
|
|
|
|
unknownPub = true;
|
|
|
|
|
|
|
|
if (dev == UNKNOWN_LABEL)
|
|
|
|
unknownDev = true;
|
|
|
|
|
|
|
|
if (!includeUnknown && unknownDev && unknownPub)
|
|
|
|
// No valid rating info found.
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (unknownDev && unknownPub) {
|
|
|
|
// If no info at all.
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mPubDevIndexAllKeys, pub, remove);
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (!unknownDev) {
|
|
|
|
// If no info at all.
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mPubDevIndexAllKeys, dev, remove);
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
if (!unknownPub) {
|
|
|
|
// If no info at all.
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mPubDevIndexAllKeys, pub, remove);
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
}
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::manageRatingsEntryInIndex(FileData* game, bool remove)
|
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
std::string key = getIndexableKey(game, RATINGS_FILTER, false);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
|
|
|
// No valid rating info found.
|
|
|
|
return;
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mRatingsIndexAllKeys, key, remove);
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
void FileFilterIndex::manageKidGameEntryInIndex(FileData* game, bool remove)
|
2017-06-12 16:38:59 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
2020-10-27 19:58:42 +00:00
|
|
|
std::string key = getIndexableKey(game, KIDGAME_FILTER, false);
|
2020-06-22 15:27:53 +00:00
|
|
|
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
2020-10-27 19:58:42 +00:00
|
|
|
// No valid kidgame info found.
|
2020-06-22 15:27:53 +00:00
|
|
|
return;
|
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mKidGameIndexAllKeys, key, remove);
|
2017-06-12 16:38:59 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
void FileFilterIndex::manageCompletedEntryInIndex(FileData* game, bool remove)
|
2017-09-08 13:20:07 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
2020-10-27 19:58:42 +00:00
|
|
|
std::string key = getIndexableKey(game, COMPLETED_FILTER, false);
|
2020-06-22 15:27:53 +00:00
|
|
|
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
2020-10-27 19:58:42 +00:00
|
|
|
// No valid completed info found.
|
2020-06-22 15:27:53 +00:00
|
|
|
return;
|
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mCompletedIndexAllKeys, key, remove);
|
2017-09-08 13:20:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 19:58:42 +00:00
|
|
|
void FileFilterIndex::manageBrokenEntryInIndex(FileData* game, bool remove)
|
2017-09-08 13:20:07 +00:00
|
|
|
{
|
2020-06-22 15:27:53 +00:00
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
2020-10-27 19:58:42 +00:00
|
|
|
std::string key = getIndexableKey(game, BROKEN_FILTER, false);
|
2020-06-22 15:27:53 +00:00
|
|
|
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
2020-10-27 19:58:42 +00:00
|
|
|
// No valid broken info found.
|
2020-06-22 15:27:53 +00:00
|
|
|
return;
|
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mBrokenIndexAllKeys, key, remove);
|
2020-10-27 19:58:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileFilterIndex::manageHiddenEntryInIndex(FileData* game, bool remove)
|
|
|
|
{
|
|
|
|
// Flag for including unknowns.
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
|
|
|
std::string key = getIndexableKey(game, HIDDEN_FILTER, false);
|
|
|
|
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
|
|
|
// No valid hidden info found.
|
|
|
|
return;
|
|
|
|
|
2020-11-08 15:47:51 +00:00
|
|
|
manageIndexEntry(&mHiddenIndexAllKeys, key, remove);
|
2017-09-08 13:20:07 +00:00
|
|
|
}
|
|
|
|
|
2020-06-22 15:27:53 +00:00
|
|
|
void FileFilterIndex::manageIndexEntry(std::map<std::string, int>* index,
|
2021-07-07 18:03:42 +00:00
|
|
|
std::string key,
|
|
|
|
bool remove)
|
2020-06-22 15:27:53 +00:00
|
|
|
{
|
|
|
|
bool includeUnknown = INCLUDE_UNKNOWN;
|
|
|
|
if (!includeUnknown && key == UNKNOWN_LABEL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (remove) {
|
|
|
|
// Removing entry.
|
|
|
|
if (index->find(key) == index->cend()) {
|
2020-10-27 19:58:42 +00:00
|
|
|
// Disabled for now as this could happen because default values are assigned as
|
|
|
|
// filters, for example 'FALSE' for favorites and kidgames for non-game entries.
|
2021-07-07 18:03:42 +00:00
|
|
|
// LOG(LogDebug) << "Couldn't find entry in index! " << key;
|
2020-06-22 15:27:53 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
(index->at(key))--;
|
|
|
|
if (index->at(key) <= 0) {
|
|
|
|
index->erase(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Adding entry.
|
|
|
|
if (index->find(key) == index->cend())
|
|
|
|
(*index)[key] = 1;
|
|
|
|
else
|
|
|
|
(index->at(key))++;
|
|
|
|
}
|
2017-03-18 17:54:39 +00:00
|
|
|
}
|