Added metadata editor button to delete media files from games and folders.

This commit is contained in:
Leon Styhre 2020-07-30 20:05:57 +02:00
parent 3887bfff3d
commit 8233e2704e
9 changed files with 166 additions and 48 deletions

View file

@ -41,6 +41,7 @@ Many bugs have been fixed, and numerous features that were only partially implem
* Speed improvements and optimizations, the application now starts faster and feels more responsive * Speed improvements and optimizations, the application now starts faster and feels more responsive
* Added metadata entry to mark games as broken/not working * Added metadata entry to mark games as broken/not working
* Added metadata entry to indicate whether the file should be counted as a game (for example useful to exclude setup files and similar for DOS games) * Added metadata entry to indicate whether the file should be counted as a game (for example useful to exclude setup files and similar for DOS games)
* Added a button to the metadata editor to delete the media files for a game while retaining the game itself and the gamelist.xml entry
* Moved all resources to a subdirectory structure and enabled the CMake install prefix variable to generate the resources search path * Moved all resources to a subdirectory structure and enabled the CMake install prefix variable to generate the resources search path
* Changed theme directory to the install prefix (e.g. /usr/local/share/emulationstation/themes) with themes in the home directory taking precedence * Changed theme directory to the install prefix (e.g. /usr/local/share/emulationstation/themes) with themes in the home directory taking precedence
* No more attempts to open files directly under /etc, instead only the install prefix directory and the home directory are used * No more attempts to open files directly under /etc, instead only the install prefix directory and the home directory are used

View file

@ -252,15 +252,47 @@ void GuiGamelistOptions::openMetaDataEd()
p.game = file; p.game = file;
p.system = file->getSystem(); p.system = file->getSystem();
std::function<void()> deleteBtnFunc; std::function<void()> deleteGameBtnFunc;
std::function<void()> deleteMediaBtnFunc;
deleteMediaBtnFunc = [this, file] {
LOG(LogInfo) << "Deleting all game media files for '" << file->getFullPath() << "'.";
ViewController::get()->getGameListView(
file->getSystem()).get()->removeMedia(file);
};
if (file->getType() == FOLDER) { if (file->getType() == FOLDER) {
deleteBtnFunc = nullptr; deleteGameBtnFunc = [this, file] {
LOG(LogInfo) << "Deleting the media files and gamelist.xml entry for the folder '" <<
file->getFullPath() << "'";
ViewController::get()->getGameListView(
file->getSystem()).get()->removeMedia(file);
// Manually reset all the metadata values, set the name to the actual folder name.
const std::vector<MetaDataDecl>& mdd = file->metadata.getMDD();
for (auto it = mdd.cbegin(); it != mdd.cend(); it++) {
if (it->key == "name") {
file->metadata.set(it->key, file->getDisplayName());
continue;
}
file->metadata.set(it->key, it->defaultValue);
}
ViewController::get()->reloadGameListView(file->getParent()->getSystem());
// Remove the folder entry from the gamelist.xml file.
file->setDeletionFlag();
file->getParent()->getSystem()->writeMetaData();
};
} }
else { else {
deleteBtnFunc = [this, file] { deleteGameBtnFunc = [this, file] {
LOG(LogInfo) << "Deleting the game file '" << file->getFullPath() <<
"', all its media files and its gamelist.xml entry.";
CollectionSystemManager::get()->deleteCollectionFiles(file); CollectionSystemManager::get()->deleteCollectionFiles(file);
ViewController::get()->getGameListView(file->getSystem()).get()->remove(file, true); ViewController::get()->getGameListView(
file->getSystem()).get()->removeMedia(file);
ViewController::get()->getGameListView(
file->getSystem()).get()->remove(file, true);
}; };
} }
@ -269,14 +301,16 @@ void GuiGamelistOptions::openMetaDataEd()
file->metadata.getMDD(FOLDER_METADATA), p, file->metadata.getMDD(FOLDER_METADATA), p,
Utils::FileSystem::getFileName(file->getPath()), std::bind( Utils::FileSystem::getFileName(file->getPath()), std::bind(
&IGameListView::onFileChanged, ViewController::get()->getGameListView( &IGameListView::onFileChanged, ViewController::get()->getGameListView(
file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc)); file->getSystem()).get(), file, FILE_METADATA_CHANGED),
deleteGameBtnFunc, deleteMediaBtnFunc));
} }
else { else {
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata,
file->metadata.getMDD(GAME_METADATA), p, file->metadata.getMDD(GAME_METADATA), p,
Utils::FileSystem::getFileName(file->getPath()), std::bind( Utils::FileSystem::getFileName(file->getPath()), std::bind(
&IGameListView::onFileChanged, ViewController::get()->getGameListView( &IGameListView::onFileChanged, ViewController::get()->getGameListView(
file->getSystem()).get(), file, FILE_METADATA_CHANGED), deleteBtnFunc)); file->getSystem()).get(), file, FILE_METADATA_CHANGED),
deleteGameBtnFunc, deleteMediaBtnFunc));
} }
} }

View file

@ -37,17 +37,17 @@ GuiMetaDataEd::GuiMetaDataEd(
ScraperSearchParams scraperParams, ScraperSearchParams scraperParams,
const std::string& /*header*/, const std::string& /*header*/,
std::function<void()> saveCallback, std::function<void()> saveCallback,
std::function<void()> deleteFunc) std::function<void()> deleteGameFunc,
std::function<void()> deleteMediaFunc)
: GuiComponent(window), : GuiComponent(window),
mScraperParams(scraperParams), mScraperParams(scraperParams),
mBackground(window, ":/graphics/frame.png"), mBackground(window, ":/graphics/frame.png"),
mGrid(window, Vector2i(1, 3)), mGrid(window, Vector2i(1, 3)),
mMetaDataDecl(mdd), mMetaDataDecl(mdd),
mMetaData(md), mMetaData(md),
mSavedCallback(saveCallback), mSavedCallback(saveCallback),
mDeleteFunc(deleteFunc) mDeleteGameFunc(deleteGameFunc),
mDeleteMediaFunc(deleteMediaFunc)
{ {
addChild(&mBackground); addChild(&mBackground);
addChild(&mGrid); addChild(&mGrid);
@ -237,14 +237,61 @@ GuiMetaDataEd::GuiMetaDataEd(
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes", buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes",
[&] { delete this; })); [&] { delete this; }));
if (mDeleteFunc) { if (scraperParams.game->getType() == FOLDER) {
auto deleteFileAndSelf = [&] { mDeleteFunc(); delete this; }; if (mDeleteGameFunc) {
auto deleteBtnFunc = [this, deleteFileAndSelf] { auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"THIS WILL DELETE THE ACTUAL GAME FILE(S)!\nARE YOU SURE?", "THIS WILL DELETE THE MEDIA FILES AND\n"
"YES", deleteFileAndSelf, "NO", nullptr)); }; "THE GAMELIST.XML ENTRY FOR THIS FOLDER.\n"
"HOWEVER NEITHER THE FOLDER ITSELF OR\n"
"ANY DATA FOR THE FILES INSIDE THE FOLDER\n"
"WILL BE DELETED. ARE YOU SURE?",
"YES", deleteFilesAndSelf, "NO", nullptr)); };
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE", buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
"delete game", deleteBtnFunc)); "delete game", deleteGameBtnFunc));
}
if (mDeleteMediaFunc) {
auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; };
auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] {
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"THIS WILL DELETE ALL THE MEDIA FILES\n"
"FOR THE ACTUAL FOLDER, BUT NO MEDIA\n"
"FOR ANY FILES INSIDE THE FOLDER WILL\n"
"BE DELETED. ARE YOU SURE?",
"YES", deleteFilesAndSelf, "NO", nullptr)); };
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE MEDIA",
"delete game", deleteMediaBtnFunc));
}
}
else {
if (mDeleteGameFunc) {
auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"THIS WILL DELETE THE GAME\n"
"FILE, ANY MEDIA FILES AND\n"
"THE GAMELIST.XML ENTRY.\n"
"ARE YOU SURE?",
"YES", deleteFilesAndSelf, "NO", nullptr)); };
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
"delete game", deleteGameBtnFunc));
}
if (mDeleteMediaFunc) {
auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; };
auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] {
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"THIS WILL DELETE ALL GAME\n"
"MEDIA FILES, BUT WILL KEEP\n"
"THE ACTUAL GAME FILE AND\n"
"THE GAMELIST.XML ENTRY.\n"
"ARE YOU SURE?",
"YES", deleteFilesAndSelf, "NO", nullptr)); };
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE MEDIA",
"delete game", deleteMediaBtnFunc));
}
} }
mButtons = makeButtonGrid(mWindow, buttons); mButtons = makeButtonGrid(mWindow, buttons);

View file

@ -29,7 +29,8 @@ public:
ScraperSearchParams params, ScraperSearchParams params,
const std::string& header, const std::string& header,
std::function<void()> savedCallback, std::function<void()> savedCallback,
std::function<void()> deleteFunc); std::function<void()> deleteGameFunc,
std::function<void()> deleteMediaFunc);
bool input(InputConfig* config, Input input) override; bool input(InputConfig* config, Input input) override;
void onSizeChanged() override; void onSizeChanged() override;
@ -59,7 +60,8 @@ private:
std::vector<MetaDataDecl> mMetaDataDecl; std::vector<MetaDataDecl> mMetaDataDecl;
MetaDataList* mMetaData; MetaDataList* mMetaData;
std::function<void()> mSavedCallback; std::function<void()> mSavedCallback;
std::function<void()> mDeleteFunc; std::function<void()> mDeleteGameFunc;
std::function<void()> mDeleteMediaFunc;
bool mMediaFilesUpdated; bool mMediaFilesUpdated;
}; };

View file

@ -135,33 +135,10 @@ void BasicGameListView::launch(FileData* game)
void BasicGameListView::remove(FileData *game, bool deleteFile) void BasicGameListView::remove(FileData *game, bool deleteFile)
{ {
// Actually delete the file on the filesystem. // Delete the game file on the filesystem.
if (deleteFile) { if (deleteFile)
Utils::FileSystem::removeFile(game->getPath()); Utils::FileSystem::removeFile(game->getPath());
// Remove all game media files as well.
if (Utils::FileSystem::exists(game->getVideoPath()))
Utils::FileSystem::removeFile(game->getVideoPath());
if (Utils::FileSystem::exists(game->getMiximagePath()))
Utils::FileSystem::removeFile(game->getMiximagePath());
if (Utils::FileSystem::exists(game->getScreenshotPath()))
Utils::FileSystem::removeFile(game->getScreenshotPath());
if (Utils::FileSystem::exists(game->getCoverPath()))
Utils::FileSystem::removeFile(game->getCoverPath());
if (Utils::FileSystem::exists(game->getMarqueePath()))
Utils::FileSystem::removeFile(game->getMarqueePath());
if (Utils::FileSystem::exists(game->get3DBoxPath()))
Utils::FileSystem::removeFile(game->get3DBoxPath());
if (Utils::FileSystem::exists(game->getThumbnailPath()))
Utils::FileSystem::removeFile(game->getThumbnailPath());
}
FileData* parent = game->getParent(); FileData* parent = game->getParent();
// Select next element in list, or previous if none. // Select next element in list, or previous if none.
if (getCursor() == game) { if (getCursor() == game) {
@ -190,6 +167,31 @@ void BasicGameListView::remove(FileData *game, bool deleteFile)
onFileChanged(parent, FILE_REMOVED); onFileChanged(parent, FILE_REMOVED);
} }
void BasicGameListView::removeMedia(FileData *game)
{
// Remove all game media files on the filesystem.
if (Utils::FileSystem::exists(game->getVideoPath()))
Utils::FileSystem::removeFile(game->getVideoPath());
if (Utils::FileSystem::exists(game->getMiximagePath()))
Utils::FileSystem::removeFile(game->getMiximagePath());
if (Utils::FileSystem::exists(game->getScreenshotPath()))
Utils::FileSystem::removeFile(game->getScreenshotPath());
if (Utils::FileSystem::exists(game->getCoverPath()))
Utils::FileSystem::removeFile(game->getCoverPath());
if (Utils::FileSystem::exists(game->getMarqueePath()))
Utils::FileSystem::removeFile(game->getMarqueePath());
if (Utils::FileSystem::exists(game->get3DBoxPath()))
Utils::FileSystem::removeFile(game->get3DBoxPath());
if (Utils::FileSystem::exists(game->getThumbnailPath()))
Utils::FileSystem::removeFile(game->getThumbnailPath());
}
std::vector<HelpPrompt> BasicGameListView::getHelpPrompts() std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
{ {
std::vector<HelpPrompt> prompts; std::vector<HelpPrompt> prompts;

View file

@ -36,6 +36,7 @@ protected:
virtual std::string getQuickSystemSelectLeftButton() override; virtual std::string getQuickSystemSelectLeftButton() override;
virtual void populateList(const std::vector<FileData*>& files) override; virtual void populateList(const std::vector<FileData*>& files) override;
virtual void remove(FileData* game, bool deleteFile) override; virtual void remove(FileData* game, bool deleteFile) override;
virtual void removeMedia(FileData* game) override;
virtual void addPlaceholder(); virtual void addPlaceholder();
TextListComponent<FileData*> mList; TextListComponent<FileData*> mList;

View file

@ -450,7 +450,7 @@ void GridGameListView::launch(FileData* game)
void GridGameListView::remove(FileData *game, bool deleteFile) void GridGameListView::remove(FileData *game, bool deleteFile)
{ {
// Actually delete the file on the filesystem. // Delete the game file on the filesystem.
if (deleteFile) if (deleteFile)
Utils::FileSystem::removeFile(game->getPath()); Utils::FileSystem::removeFile(game->getPath());
@ -472,12 +472,41 @@ void GridGameListView::remove(FileData *game, bool deleteFile)
if (mGrid.size() == 0) if (mGrid.size() == 0)
addPlaceholder(); addPlaceholder();
// Remove before repopulating (removes from parent). // If a game has been deleted, immediately remove the entry from gamelist.xml
// Update the view, with game removed. // regardless of the value of the setting SaveGamelistsMode.
game->setDeletionFlag();
parent->getSystem()->writeMetaData();
// Remove before repopulating (removes from parent), then update the view.
delete game; delete game;
onFileChanged(parent, FILE_REMOVED); onFileChanged(parent, FILE_REMOVED);
} }
void GridGameListView::removeMedia(FileData *game)
{
// Remove all game media files on the filesystem.
if (Utils::FileSystem::exists(game->getVideoPath()))
Utils::FileSystem::removeFile(game->getVideoPath());
if (Utils::FileSystem::exists(game->getMiximagePath()))
Utils::FileSystem::removeFile(game->getMiximagePath());
if (Utils::FileSystem::exists(game->getScreenshotPath()))
Utils::FileSystem::removeFile(game->getScreenshotPath());
if (Utils::FileSystem::exists(game->getCoverPath()))
Utils::FileSystem::removeFile(game->getCoverPath());
if (Utils::FileSystem::exists(game->getMarqueePath()))
Utils::FileSystem::removeFile(game->getMarqueePath());
if (Utils::FileSystem::exists(game->get3DBoxPath()))
Utils::FileSystem::removeFile(game->get3DBoxPath());
if (Utils::FileSystem::exists(game->getThumbnailPath()))
Utils::FileSystem::removeFile(game->getThumbnailPath());
}
std::vector<TextComponent*> GridGameListView::getMDLabels() std::vector<TextComponent*> GridGameListView::getMDLabels()
{ {
std::vector<TextComponent*> ret; std::vector<TextComponent*> ret;

View file

@ -43,6 +43,7 @@ protected:
virtual std::string getQuickSystemSelectLeftButton() override; virtual std::string getQuickSystemSelectLeftButton() override;
virtual void populateList(const std::vector<FileData*>& files) override; virtual void populateList(const std::vector<FileData*>& files) override;
virtual void remove(FileData* game, bool deleteFile) override; virtual void remove(FileData* game, bool deleteFile) override;
virtual void removeMedia(FileData* game) override;
virtual void addPlaceholder(); virtual void addPlaceholder();
ImageGridComponent<FileData*> mGrid; ImageGridComponent<FileData*> mGrid;

View file

@ -48,6 +48,7 @@ public:
virtual bool input(InputConfig* config, Input input) override; virtual bool input(InputConfig* config, Input input) override;
virtual void remove(FileData* game, bool deleteFile) = 0; virtual void remove(FileData* game, bool deleteFile) = 0;
virtual void removeMedia(FileData* game) = 0;
virtual const char* getName() const = 0; virtual const char* getName() const = 0;
virtual void launch(FileData* game) = 0; virtual void launch(FileData* game) = 0;