diff --git a/src/media_library.cpp b/src/media_library.cpp index a5ec5f2b..678926ab 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -67,18 +67,18 @@ bool SongEntryMatcher(const Regex &rx, const MPD::Song &s); void DisplayAlbums(NC::Menu &menu); void DisplayPrimaryTags(NC::Menu &menu); -bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b); - -struct SortAllTracks { +struct SortSongs { static const std::array GetFuns; LocaleStringComparison m_cmp; + std::ptrdiff_t m_offset; public: - SortAllTracks() : m_cmp(std::locale(), Config.ignore_leading_the) { } + SortSongs(bool disc_only) + : m_cmp(std::locale(), Config.ignore_leading_the), m_offset(disc_only ? 2 : 0) { } bool operator()(const MPD::Song &a, const MPD::Song &b) { - for (auto get = GetFuns.begin(); get != GetFuns.end(); ++get) { + for (auto get = GetFuns.begin()+m_offset; get != GetFuns.end(); ++get) { int ret = m_cmp(a.getTags(*get, Config.tags_separator), b.getTags(*get, Config.tags_separator)); if (ret != 0) @@ -88,7 +88,7 @@ public: } }; -const std::array SortAllTracks::GetFuns = {{ +const std::array SortSongs::GetFuns = {{ &MPD::Song::getDate, &MPD::Song::getAlbum, &MPD::Song::getDisc @@ -242,9 +242,10 @@ void MediaLibrary::update() if (hasTwoColumns) { - if (Albums.reallyEmpty()) + if (Albums.reallyEmpty() || m_albums_update_request) { - Songs.clear(); + Albums.clearSearchResults(); + m_albums_update_request = false; std::map, time_t> albums; Mpd.GetDirectoryRecursive("/", [&albums](MPD::Song &&s) { unsigned idx = 0; @@ -260,22 +261,33 @@ void MediaLibrary::update() } while (!(tag = s.get(Config.media_lib_primary_tag, ++idx)).empty()); }); - for (auto it = albums.begin(); it != albums.end(); ++it) - Albums.addItem(AlbumEntry(Album( - std::move(std::get<0>(it->first)), - std::move(std::get<1>(it->first)), - std::move(std::get<2>(it->first)), - it->second))); + withUnfilteredMenuReapplyFilter(Albums, [this, &albums]() { + size_t idx = 0; + for (auto it = albums.begin(); it != albums.end(); ++it, ++idx) + { + auto &&entry = AlbumEntry(Album( + std::move(std::get<0>(it->first)), + std::move(std::get<1>(it->first)), + std::move(std::get<2>(it->first)), + it->second)); + if (idx < Albums.size()) + Albums[idx].value() = entry; + else + Albums.addItem(entry); + } + if (idx < Albums.size()) + Albums.resizeList(idx); std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries()); + }); Albums.refresh(); } } else { - if (Tags.reallyEmpty()) + if (Tags.reallyEmpty() || m_tags_update_request) { - Albums.clear(); - Songs.clear(); + Tags.clearSearchResults(); + m_tags_update_request = false; std::map tags; Mpd.GetDirectoryRecursive("/", [&tags](MPD::Song &&s) { unsigned idx = 0; @@ -290,13 +302,26 @@ void MediaLibrary::update() } while (!(tag = s.get(Config.media_lib_primary_tag, ++idx)).empty()); }); - for (auto it = tags.begin(); it != tags.end(); ++it) - Tags.addItem(PrimaryTag(std::move(it->first), it->second)); + withUnfilteredMenuReapplyFilter(Tags, [this, &tags]() { + size_t idx = 0; + for (auto it = tags.begin(); it != tags.end(); ++it, ++idx) + { + auto &&tag = PrimaryTag(std::move(it->first), it->second); + if (idx < Tags.size()) + Tags[idx].value() = tag; + else + Tags.addItem(tag); + } + if (idx < Tags.size()) + Tags.resizeList(idx); + }); Tags.refresh(); } - if (!Tags.empty() && Albums.reallyEmpty()) + if ((!Tags.empty() && Albums.reallyEmpty()) || m_albums_update_request) { + Albums.clearSearchResults(); + m_albums_update_request = false; auto &primary_tag = Tags.current().value().tag(); Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, primary_tag); @@ -309,25 +334,40 @@ void MediaLibrary::update() else it->second = s.getMTime(); }); - for (auto it = albums.begin(); it != albums.end(); ++it) - Albums.addItem(AlbumEntry(Album( - primary_tag, - std::move(std::get<0>(it->first)), - std::move(std::get<1>(it->first)), - it->second))); - std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries()); - if (albums.size() > 1) - { - Albums.addSeparator(); - Albums.addItem(AlbumEntry::mkAllTracksEntry(primary_tag)); - } + withUnfilteredMenuReapplyFilter(Albums, [this, &albums, &primary_tag]() { + size_t idx = 0; + for (auto it = albums.begin(); it != albums.end(); ++it, ++idx) + { + auto &&entry = AlbumEntry(Album( + primary_tag, + std::move(std::get<0>(it->first)), + std::move(std::get<1>(it->first)), + it->second)); + if (idx < Albums.size()) + { + Albums[idx].value() = entry; + Albums[idx].setSeparator(false); + } + else + Albums.addItem(entry); + } + if (idx < Albums.size()) + Albums.resizeList(idx); + std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries()); + if (albums.size() > 1) + { + Albums.addSeparator(); + Albums.addItem(AlbumEntry::mkAllTracksEntry(primary_tag)); + } + }); Albums.refresh(); } } - if (!Albums.empty() && Songs.reallyEmpty()) + if ((!Albums.empty() && Songs.reallyEmpty()) || m_songs_update_request) { - Songs.reset(); + Songs.clearSearchResults(); + m_songs_update_request = false; auto &album = Albums.current().value(); Mpd.StartSearch(true); Mpd.AddSearch(Config.media_lib_primary_tag, album.entry().tag()); @@ -336,15 +376,23 @@ void MediaLibrary::update() Mpd.AddSearch(MPD_TAG_ALBUM, album.entry().album()); Mpd.AddSearch(MPD_TAG_DATE, album.entry().date()); } - Mpd.CommitSearchSongs([this](MPD::Song &&s) { - Songs.addItem(s, myPlaylist->checkForSong(s)); + withUnfilteredMenuReapplyFilter(Songs, [this, &album]() { + size_t idx = 0; + Mpd.CommitSearchSongs([this, &idx](MPD::Song &&s) { + bool is_playlist = myPlaylist->checkForSong(s); + if (idx < Songs.size()) + { + Songs[idx].value() = s; + Songs[idx].setBold(is_playlist); + } + else + Songs.addItem(s, is_playlist); + ++idx; + }); + if (idx < Songs.size()) + Songs.resizeList(idx); + std::sort(Songs.beginV(), Songs.endV(), SortSongs(!album.isAllTracksEntry())); }); - - if (album.isAllTracksEntry()) - std::sort(Songs.beginV(), Songs.endV(), SortAllTracks()); - else - std::sort(Songs.beginV(), Songs.endV(), SortSongsByTrack); - Songs.refresh(); } @@ -640,7 +688,7 @@ MPD::SongList MediaLibrary::getSelectedSongs() Mpd.CommitSearchSongs([&result](MPD::Song &&s) { result.push_back(s); }); - std::sort(result.begin()+begin, result.end(), SortSongsByTrack); + std::sort(result.begin()+begin, result.end(), SortSongs(false)); } } // if no item is selected, add songs from right column @@ -998,14 +1046,4 @@ void DisplayPrimaryTags(NC::Menu &menu) menu << tag; } -/***********************************************************************/ - -bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b) -{ - int cmp = a.getDisc().compare(b.getDisc()); - if (cmp != 0) - return cmp < 0; - return a.getTrack() < b.getTrack(); -} - } diff --git a/src/media_library.h b/src/media_library.h index 591ee7ed..4ea5cfdc 100644 --- a/src/media_library.h +++ b/src/media_library.h @@ -74,9 +74,14 @@ struct MediaLibrary: Screen, Filterable, HasColumns, HasSongs, Sea void LocateSong(const MPD::Song &); ProxySongList songsProxyList(); void toggleSortMode(); - + + void requestTagsUpdate() { m_tags_update_request = true; } + void requestAlbumsUpdate() { m_albums_update_request = true; } + void requestSongsUpdate() { m_songs_update_request = true; } + struct PrimaryTag { + PrimaryTag() : m_mtime(0) { } PrimaryTag(std::string tag_, time_t mtime_) : m_tag(std::move(tag_)), m_mtime(mtime_) { } @@ -134,6 +139,10 @@ protected: private: void AddToPlaylist(bool); + + bool m_tags_update_request; + bool m_albums_update_request; + bool m_songs_update_request; }; extern MediaLibrary *myLibrary; diff --git a/src/status.cpp b/src/status.cpp index db81dfec..2420f0e4 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -193,10 +193,9 @@ void Status::Changes::database() # ifdef HAVE_TAGLIB_H myTagEditor->Dirs->clear(); # endif // HAVE_TAGLIB_H - if (myLibrary->Columns() == 2) - myLibrary->Albums.clear(); - else - myLibrary->Tags.clear(); + myLibrary->requestTagsUpdate(); + myLibrary->requestAlbumsUpdate(); + myLibrary->requestSongsUpdate(); } void Status::Changes::playerState()