Improved handling and sorting of folders.

This commit is contained in:
Leon Styhre 2020-09-20 20:25:32 +02:00
parent 2b82770e43
commit e56fdf3df6
4 changed files with 99 additions and 23 deletions

View file

@ -151,6 +151,17 @@ const std::vector<FileData*> FileData::getChildrenRecursive() const
return childrenRecursive;
}
bool FileData::viewHasOnlyFolders()
{
bool onlyFolders = true;
std::vector<FileData*> entrySiblings = this->getParent()->getChildren();
for (auto it = entrySiblings.cbegin(); it != entrySiblings.cend(); it++) {
if ((*it)->getType() != FOLDER)
onlyFolders = false;
}
return onlyFolders;
}
const std::string FileData::getROMDirectory()
{
std::string romDirSetting = Settings::getInstance()->getString("ROMDirectory");
@ -463,6 +474,13 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending)
}
}
// If descending sorting is requested, always perform a ascending sort by filename first.
// This adds a slight (probably negligible) overhead but it will avoid strange sorting
// issues where the secondary sorting is reversed for some sort types.
if (!ascending)
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
if (foldersOnTop && mOnlyFolders)
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator);
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
@ -479,6 +497,10 @@ void FileData::sort(ComparisonFunction& comparator, bool ascending)
mChildren.insert(mChildren.end(), mChildrenOthers.begin(), mChildrenOthers.end());
}
else {
if (!ascending)
std::stable_sort(mChildren.begin(), mChildren.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
std::stable_sort(mChildren.begin(), mChildren.end(), comparator);
if (!ascending)
std::reverse(mChildren.begin(), mChildren.end());
@ -523,6 +545,7 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending
mFirstLetterIndex.clear();
mOnlyFolders = true;
std::vector<FileData*> mChildrenFolders;
std::vector<FileData*> mChildrenFavoritesFolders;
std::vector<FileData*> mChildrenFavorites;
std::vector<FileData*> mChildrenOthers;
bool showHiddenGames = Settings::getInstance()->getBool("ShowHiddenGames");
@ -538,7 +561,11 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending
}
if (foldersOnTop && mChildren[i]->getType() == FOLDER) {
if (!mChildren[i]->getFavorite())
mChildrenFolders.push_back(mChildren[i]);
else
mChildrenFavoritesFolders.push_back(mChildren[i]);
hasFolders = true;
}
else if (mChildren[i]->getFavorite()) {
@ -555,6 +582,19 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending
mOnlyFolders = false;
}
// If there are favorite folders and this is a mixed list, then don't handle these
// separately but instead merge them into the same vector. This is a quite wasteful
// approach but the scenario where a user has a mixed folder and files list and marks
// some folders as favorites is probably a rare situation.
if (!mOnlyFolders && mChildrenFavoritesFolders.size() > 0) {
mChildrenFolders.insert(mChildrenFolders.end(), mChildrenFavoritesFolders.begin(),
mChildrenFavoritesFolders.end());
mChildrenFavoritesFolders.erase(mChildrenFavoritesFolders.begin(),
mChildrenFavoritesFolders.end());
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
}
// If there are only favorites in the gamelist, it makes sense to still generate
// a letter index. For instance to be able to quick jump in the 'favorites'
// collection. Doing this additional work here only for the applicable gamelists is
@ -584,49 +624,70 @@ void FileData::sortFavoritesOnTop(ComparisonFunction& comparator, bool ascending
auto last = std::unique(mFirstLetterIndex.begin(), mFirstLetterIndex.end());
mFirstLetterIndex.erase(last, mFirstLetterIndex.end());
// If there were at least one favorite folder in the gamelist, insert the favorite
// unicode character in the first position.
if (foldersOnTop && mOnlyFolders && mChildrenFavoritesFolders.size() > 0)
mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FAVORITE_CHAR);
// If there were at least one favorite in the gamelist, insert the favorite
// unicode character in the first position.
if (mChildrenOthers.size() > 0 && mChildrenFavorites.size() > 0)
else if (mChildrenOthers.size() > 0 && mChildrenFavorites.size() > 0)
mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FAVORITE_CHAR);
// If it's a mixed list and folders are sorted on top, add a folder icon to the index.
if (foldersOnTop && hasFolders && !mOnlyFolders)
mFirstLetterIndex.insert(mFirstLetterIndex.begin(), FOLDER_CHAR);
// If descending sorting is requested, always perform a ascending sort by filename first.
// This adds a slight (probably negligible) overhead but it will avoid strange sorting
// issues where the secondary sorting is reversed for some sort types.
if (!ascending) {
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
std::stable_sort(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(),
getSortTypeFromString("filename, ascending").comparisonFunction);
}
// Sort favorite games and the other games separately.
if (foldersOnTop && mOnlyFolders)
if (foldersOnTop && mOnlyFolders) {
std::stable_sort(mChildrenFavoritesFolders.begin(),
mChildrenFavoritesFolders.end(), comparator);
std::stable_sort(mChildrenFolders.begin(), mChildrenFolders.end(), comparator);
}
std::stable_sort(mChildrenFavorites.begin(), mChildrenFavorites.end(), comparator);
std::stable_sort(mChildrenOthers.begin(), mChildrenOthers.end(), comparator);
// Iterate through any child favorite folders.
for (auto it = mChildrenFavoritesFolders.cbegin(); it !=
mChildrenFavoritesFolders.cend(); it++) {
if ((*it)->getChildren().size() > 0)
(*it)->sortFavoritesOnTop(comparator, ascending);
}
// Iterate through any child folders.
for (auto it = mChildrenFolders.cbegin(); it != mChildrenFolders.cend(); it++) {
if ((*it)->getChildren().size() > 0)
(*it)->sortFavoritesOnTop(comparator, ascending);
}
// Iterate through any child folders.
for (auto it = mChildrenFavorites.cbegin(); it != mChildrenFavorites.cend(); it++) {
if ((*it)->getChildren().size() > 0)
(*it)->sortFavoritesOnTop(comparator, ascending);
}
// Iterate through any child folders.
for (auto it = mChildrenOthers.cbegin(); it != mChildrenOthers.cend(); it++) {
if ((*it)->getChildren().size() > 0)
(*it)->sortFavoritesOnTop(comparator, ascending);
}
if (!ascending) {
if (foldersOnTop && mOnlyFolders)
if (foldersOnTop && mOnlyFolders) {
std::reverse(mChildrenFavoritesFolders.begin(), mChildrenFavoritesFolders.end());
std::reverse(mChildrenFolders.begin(), mChildrenFolders.end());
}
std::reverse(mChildrenFavorites.begin(), mChildrenFavorites.end());
std::reverse(mChildrenOthers.begin(), mChildrenOthers.end());
}
// Combine the individually sorted favorite games and other games vectors.
mChildren.erase(mChildren.begin(), mChildren.end());
mChildren.reserve(mChildrenFolders.size() + mChildrenFavorites.size() + mChildrenOthers.size());
mChildren.reserve(mChildrenFavoritesFolders.size() + mChildrenFolders.size() +
mChildrenFavorites.size() + mChildrenOthers.size());
mChildren.insert(mChildren.end(), mChildrenFavoritesFolders.begin(),
mChildrenFavoritesFolders.end());
mChildren.insert(mChildren.end(), mChildrenFolders.begin(), mChildrenFolders.end());
mChildren.insert(mChildren.end(), mChildrenFavorites.begin(), mChildrenFavorites.end());
mChildren.insert(mChildren.end(), mChildrenOthers.begin(), mChildrenOthers.end());

View file

@ -64,6 +64,7 @@ public:
const std::vector<std::string>& getFirstLetterIndex() const
{ return mFirstLetterIndex; };
const bool getOnlyFoldersFlag() { return mOnlyFolders; }
bool viewHasOnlyFolders();
static const std::string getROMDirectory();
static const std::string getMediaDirectory();
const std::string getMediafilePath(std::string subdirectory, std::string mediatype) const;

View file

@ -339,7 +339,7 @@ void GuiGamelistOptions::jumpToLetter()
if (mFavoritesSorting && mFirstLetterIndex.front() == FAVORITE_CHAR) {
if ((char)toupper(files.at(i)->getSortName().front()) ==
letter && !files.at(i)->getFavorite()) {
if (mFoldersOnTop && files.at(i)->getType() == FOLDER) {
if (!mOnlyHasFolders && mFoldersOnTop && files.at(i)->getType() == FOLDER) {
continue;
}
else {
@ -368,9 +368,13 @@ void GuiGamelistOptions::jumpToFirstRow()
// Get the gamelist.
const std::vector<FileData*>& files = getGamelist()->getCursor()->
getParent()->getChildrenListToDisplay();
// Select the first game that is not a folder.
// Select the first game that is not a folder, unless it's a folder-only list in
// which case the first line overall is selected.
for (auto it = files.cbegin(); it != files.cend(); it++) {
if ((*it)->getType() == GAME) {
if (!mOnlyHasFolders && mFoldersOnTop && (*it)->getType() == FOLDER) {
continue;
}
else {
getGamelist()->setCursor(*it);
break;
}

View file

@ -189,6 +189,11 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
bool favoritesSorting;
bool removedLastFavorite = false;
bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop");
// If the current list only contains folders, then treat it as if the folders
// are not sorted on top, this way the logic should work exactly as for mixed
// lists or files-only lists.
if (getCursor()->getType() == FOLDER && foldersOnTop == true)
foldersOnTop = !getCursor()->viewHasOnlyFolders();
if (CollectionSystemManager::get()->getIsCustomCollection(mRoot->getSystem()))
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
@ -208,6 +213,11 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
// If we are on the favorite marking boundary, select the next entry.
else if (getCursor()->getFavorite() != getPreviousEntry()->getFavorite())
entryToSelect = getNextEntry();
// If we mark the second entry as favorite and the first entry is not a
// favorite, then select this entry if they are of the same type.
else if (getPreviousEntry() == getFirstEntry() &&
getCursor()->getType() == getPreviousEntry()->getType())
entryToSelect = getPreviousEntry();
// For all other scenarios try to select the next entry, and if it doesn't
// exist, select the previous entry.
else
@ -271,8 +281,8 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
mWindow->setInfoPopup(s);
entryToUpdate->getSourceFileData()->getSystem()->onMetaDataSavePoint();
if (!Settings::getInstance()->getBool("FoldersOnTop"))
mRoot->sort(mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
getCursor()->getParent()->sort(
mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
Settings::getInstance()->getBool("FavoritesFirst"));
ViewController::get()->onFileChanged(getCursor(), FILE_METADATA_CHANGED);