diff --git a/src/Makefile.am b/src/Makefile.am index 3262219d..43b12355 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,7 +19,6 @@ ncmpcpp_SOURCES = \ lyrics.cpp \ lyrics_fetcher.cpp \ media_library.cpp \ - menu.cpp \ mpdpp.cpp \ mutable_song.cpp \ ncmpcpp.cpp \ diff --git a/src/actions.cpp b/src/actions.cpp index a4cacb4c..4a585fcd 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -503,7 +503,8 @@ void ScrollDown::Run() void ScrollUpArtist::Run() { - List *mList = myScreen->GetList(); + // FIXME + /*List *mList = myScreen->GetList(); if (!mList || mList->Empty()) return; size_t pos = mList->Choice(); @@ -517,12 +518,13 @@ void ScrollUpArtist::Run() if (!s || s->getArtist() != artist) break; } - } + }*/ } void ScrollUpAlbum::Run() { - List *mList = myScreen->GetList(); + // FIXME + /*List *mList = myScreen->GetList(); if (!mList || mList->Empty()) return; size_t pos = mList->Choice(); @@ -536,12 +538,13 @@ void ScrollUpAlbum::Run() if (!s || s->getAlbum() != album) break; } - } + }*/ } void ScrollDownArtist::Run() { - List *mList = myScreen->GetList(); + // FIXME + /*List *mList = myScreen->GetList(); if (!mList || mList->Empty()) return; size_t pos = mList->Choice(); @@ -555,12 +558,13 @@ void ScrollDownArtist::Run() if (!s || s->getArtist() != artist) break; } - } + }*/ } void ScrollDownAlbum::Run() { - List *mList = myScreen->GetList(); + // FIXME + /*List *mList = myScreen->GetList(); if (!mList || mList->Empty()) return; size_t pos = mList->Choice(); @@ -574,7 +578,7 @@ void ScrollDownAlbum::Run() if (!s || s->getAlbum() != album) break; } - } + }*/ } void PageUp::Run() @@ -769,7 +773,7 @@ void Delete::Run() } } else - Mpd.DeleteID(myPlaylist->CurrentSong()->getID()); + Mpd.DeleteID(myPlaylist->currentSong()->getID()); } else if ( (myScreen == myBrowser && !myBrowser->Main()->Empty() && myBrowser->CurrentDir() == "/" && myBrowser->Main()->Current().value().type == itPlaylist) @@ -1184,13 +1188,9 @@ void ToggleDisplayMode::Run() Config.columns_in_playlist_editor = !Config.columns_in_playlist_editor; ShowMessage("Playlist editor display mode: %s", Config.columns_in_playlist_editor ? "Columns" : "Classic"); if (Config.columns_in_playlist_editor) - { myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::SongsInColumns, _1, *myPlaylistEditor)); - } else - { myPlaylistEditor->Content->setItemDisplayer(std::bind(Display::Songs, _1, *myPlaylistEditor, Config.song_list_format)); - } } } @@ -1377,7 +1377,8 @@ void SetCrossfade::Run() bool EditSong::canBeRun() const { # ifdef HAVE_TAGLIB_H - return myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + return w && w->currentSong(); # else return false; # endif // HAVE_TAGLIB_H @@ -1388,7 +1389,9 @@ void EditSong::Run() # ifdef HAVE_TAGLIB_H if (!isMPDMusicDirSet()) return; - const MPD::Song *s = myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + assert(w); + auto s = w->currentSong(); assert(s); myTinyTagEditor->SetEdited(*s); myTinyTagEditor->SwitchTo(); @@ -1424,11 +1427,10 @@ void EditLibraryTag::Run() MPD::MutableSong::SetFunction set = tagTypeToSetFunction(Config.media_lib_primary_tag); assert(set); bool success = true; - std::string dir_to_update; - Mpd.CommitSearchSongs([set, &new_tag, &success, &dir_to_update](MPD::Song &&s) { - if (!success) - return; - MPD::MutableSong es = s; + MPD::SongList songs = Mpd.CommitSearchSongs(); + for (auto s = songs.begin(); s != songs.end(); ++s) + { + MPD::MutableSong es = *s; es.setTag(set, new_tag); ShowMessage("Updating tags in \"%s\"...", es.getName().c_str()); std::string path = Config.mpd_music_dir + es.getURI(); @@ -1437,15 +1439,12 @@ void EditLibraryTag::Run() const char msg[] = "Error while updating tags in \"%s\""; ShowMessage(msg, Shorten(TO_WSTRING(es.getURI()), COLS-const_strlen(msg)).c_str()); success = false; + break; } - if (dir_to_update.empty()) - dir_to_update = es.getDirectory(); - else - getSharedDirectory(es.getDirectory(), dir_to_update); - }); + } if (success) { - Mpd.UpdateDirectory(dir_to_update); + Mpd.UpdateDirectory(getSharedDirectory(songs.begin(), songs.end())); ShowMessage("Tags updated successfully"); } } @@ -1500,7 +1499,7 @@ void EditLibraryAlbum::Run() } if (success) { - Mpd.UpdateDirectory(getSharedDirectory(myLibrary->Songs)); + Mpd.UpdateDirectory(getSharedDirectory(myLibrary->Songs->BeginV(), myLibrary->Songs->EndV())); ShowMessage("Tags updated successfully"); } } @@ -1635,24 +1634,29 @@ void EditLyrics::Run() bool JumpToBrowser::canBeRun() const { - return myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + return w && w->currentSong(); } void JumpToBrowser::Run() { - MPD::Song *s = myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + auto s = w->currentSong(); assert(s); myBrowser->LocateSong(*s); } bool JumpToMediaLibrary::canBeRun() const { - return myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + return w && w->currentSong(); } void JumpToMediaLibrary::Run() { - MPD::Song *s = myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + assert(w); + auto s = w->currentSong(); assert(s); myLibrary->LocateSong(*s); } @@ -1708,7 +1712,8 @@ void ToggleScreenLock::Run() bool JumpToTagEditor::canBeRun() const { # ifdef HAVE_TAGLIB_H - return myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + return w && w->currentSong(); # else return false; # endif // HAVE_TAGLIB_H @@ -1719,7 +1724,9 @@ void JumpToTagEditor::Run() # ifdef HAVE_TAGLIB_H if (!isMPDMusicDirSet()) return; - MPD::Song *s = myScreen->CurrentSong(); + auto w = dynamic_cast(myScreen); + assert(w); + auto s = w->currentSong(); assert(s); myTagEditor->LocateSong(*s); # endif // HAVE_TAGLIB_H @@ -1780,32 +1787,35 @@ void JumpToPositionInSong::Run() bool ReverseSelection::canBeRun() const { - return myScreen->allowsSelection(); + auto w = dynamic_cast(myScreen); + return w && w->allowsSelection(); } void ReverseSelection::Run() { - myScreen->ReverseSelection(); + auto w = dynamic_cast(myScreen); + assert(w); + w->reverseSelection(); ShowMessage("Selection reversed"); } bool DeselectItems::canBeRun() const { - return myScreen->allowsSelection(); + auto w = dynamic_cast(myScreen); + return w && w->allowsSelection(); } void DeselectItems::Run() { - // FIXME - /*List *mList = myScreen->GetList(); - for (size_t i = 0; i < mList->Size(); ++i) - mList->Select(i, 0); - ShowMessage("Items deselected");*/ + auto w = dynamic_cast(myScreen); + assert(w); + w->removeSelection(); } bool SelectAlbum::canBeRun() const { - return myScreen->allowsSelection() + auto w = dynamic_cast(myScreen); + return w && w->allowsSelection() && myScreen->GetList(); } @@ -2334,12 +2344,14 @@ void ShowSongInfo::Run() mySongInfo->SwitchTo(); } -#ifndef HAVE_CURL_CURL_H bool ShowArtistInfo::canBeRun() const { + #ifdef HAVE_CURL_CURL_H + return myScreen == myLastfm || dynamic_cast(myScreen); +# else return false; +# endif // NOT HAVE_CURL_CURL_H } -#endif // NOT HAVE_CURL_CURL_H void ShowArtistInfo::Run() { @@ -2351,7 +2363,9 @@ void ShowArtistInfo::Run() } std::string artist; - MPD::Song *s = myScreen->CurrentSong(); + auto hs = dynamic_cast(myScreen); + assert(hs); + auto s = hs->currentSong(); if (s) artist = s->getArtist(); diff --git a/src/actions.h b/src/actions.h index bc920c7a..f51878d3 100644 --- a/src/actions.h +++ b/src/actions.h @@ -766,9 +766,7 @@ struct ShowSongInfo : public Action struct ShowArtistInfo : public Action { ShowArtistInfo() : Action(aShowArtistInfo, "show_artist_info") { } -# ifndef HAVE_CURL_CURL_H virtual bool canBeRun() const; -# endif // NOT HAVE_CURL_CURL_H virtual void Run(); }; diff --git a/src/browser.cpp b/src/browser.cpp index 82cba855..28b1e054 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -263,68 +263,6 @@ void Browser::MouseButtonPressed(MEVENT me) Screen< Menu >::MouseButtonPressed(me); } -MPD::Song *Browser::CurrentSong() -{ - const MPD::Item &item = w->Current().value(); - if (!w->Empty() && item.type == itSong) - return item.song.get(); - else - return 0; -} - -void Browser::ReverseSelection() -{ - w->ReverseSelection(itsBrowsedDir == "/" ? 0 : 1); -} - -void Browser::GetSelectedSongs(MPD::SongList &v) -{ - if (w->Empty()) - return; - std::vector selected; - w->GetSelected(selected); - if (selected.empty()) - selected.push_back(w->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - { - const MPD::Item &item = w->at(*it).value(); - switch (item.type) - { - case itDirectory: - { -# ifndef WIN32 - if (isLocal()) - { - MPD::ItemList list; - GetLocalDirectory(list, item.name, 1); - for (auto j = list.begin(); j != list.end(); ++j) - v.push_back(*j->song); - } - else -# endif // !WIN32 - { - Mpd.GetDirectoryRecursive(locale_to_utf_cpy(item.name), [&v](MPD::Song &&s) { - v.push_back(s); - }); - } - break; - } - case itSong: - { - v.push_back(*item.song); - break; - } - case itPlaylist: - { - Mpd.GetPlaylistContent(locale_to_utf_cpy(item.name), [&v](MPD::Song &&s) { - v.push_back(s); - }); - break; - } - } - } -} - /***********************************************************************/ std::string Browser::currentFilter() @@ -361,6 +299,75 @@ void Browser::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *Browser::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + if ((*w)[pos].value().type == itSong) + ptr = (*w)[pos].value().song.get(); + return ptr; +} + +MPD::Song *Browser::currentSong() +{ + if (w->Empty()) + return 0; + else + return getSong(w->Choice()); +} + +bool Browser::allowsSelection() +{ + return true; +} + +void Browser::removeSelection() +{ + removeSelectionHelper(w->Begin(), w->End()); +} + +void Browser::reverseSelection() +{ + reverseSelectionHelper(w->Begin()+(itsBrowsedDir == "/" ? 0 : 1), w->End()); +} + +MPD::SongList Browser::getSelectedSongs() +{ + MPD::SongList result; + auto item_handler = [this, &result](const MPD::Item &item) { + if (item.type == itDirectory) + { +# ifndef WIN32 + if (isLocal()) + { + MPD::ItemList list; + GetLocalDirectory(list, item.name, true); + for (auto it = list.begin(); it != list.end(); ++it) + result.push_back(*it->song); + } + else +# endif // !WIN32 + { + auto list = Mpd.GetDirectoryRecursive(item.name); + result.insert(result.end(), list.begin(), list.end()); + } + } + else if (item.type == itSong) + result.push_back(*item.song); + else if (item.type == itPlaylist) + { + auto list = Mpd.GetPlaylistContent(item.name); + result.insert(result.end(), list.begin(), list.end()); + } + }; + for (auto it = w->Begin(); it != w->End(); ++it) + if (it->isSelected()) + item_handler(it->value()); + // if no item is selected, add current one + if (result.empty() && !w->Empty()) + item_handler(w->Current().value()); + return result; +} + void Browser::LocateSong(const MPD::Song &s) { if (s.getDirectory().empty()) @@ -411,15 +418,9 @@ void Browser::GetDirectory(std::string dir, std::string subdir) if (isLocal()) GetLocalDirectory(list); else - { - Mpd.GetDirectory(dir, [&list](MPD::Item &&i) { - list.push_back(i); - }); - } + list = Mpd.GetDirectory(dir); # else - Mpd.GetDirectory(dir, [&list](MPD::Item &&i) { - list.push_back(i); - }); + list = Mpd.GetDirectory(dir); # endif // !WIN32 if (!isLocal()) // local directory is already sorted std::sort(list.begin(), list.end(), CaseInsensitiveSorting()); diff --git a/src/browser.h b/src/browser.h index 1663d39f..ac4fba86 100644 --- a/src/browser.h +++ b/src/browser.h @@ -26,7 +26,7 @@ #include "regex_filter.h" #include "screen.h" -class Browser : public Screen< Menu >, public Filterable, public Searchable +class Browser : public Screen< Menu >, public Filterable, public HasSongs, public Searchable { public: Browser() : itsBrowseLocally(0), itsScrollBeginning(0), itsBrowsedDir("/") { } @@ -41,13 +41,6 @@ class Browser : public Screen< Menu >, public Filterable, public Sear virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return w->at(pos).value().type == MPD::itSong ? (*w)[pos].value().song.get() : 0; } - - virtual bool allowsSelection() { return true; } - virtual void ReverseSelection(); - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -57,6 +50,15 @@ class Browser : public Screen< Menu >, public Filterable, public Sear virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual List *GetList() { return w; } virtual bool isMergable() { return true; } diff --git a/src/display.cpp b/src/display.cpp index abff372c..cb17ab66 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -73,13 +73,13 @@ const my_char_t *toColumnName(char c) } template -void setProperties(Menu &menu, const MPD::Song &s, BasicScreen &screen, bool &separate_albums, +void setProperties(Menu &menu, const MPD::Song &s, HasSongs &screen, bool &separate_albums, bool &is_now_playing, bool &is_selected, bool &discard_colors) { separate_albums = false; if (Config.playlist_separate_albums) { - MPD::Song *next = screen.GetSong(menu.DrawnPosition()+1); + auto next = screen.getSong(menu.DrawnPosition()+1); if (next && next->getAlbum() != s.getAlbum()) separate_albums = true; } @@ -87,13 +87,14 @@ void setProperties(Menu &menu, const MPD::Song &s, BasicScreen &screen, bool menu << fmtUnderline; int song_pos = menu.isFiltered() ? s.getPosition() : menu.DrawnPosition(); - is_now_playing = song_pos == myPlaylist->NowPlaying && s.getID() > 0; // playlist + is_now_playing = static_cast(&menu) == myPlaylist->Items + && song_pos == myPlaylist->NowPlaying; is_selected = menu.Drawn().isSelected(); discard_colors = Config.discard_colors_if_item_is_selected && is_selected; } template -void showSongs(Menu &menu, const MPD::Song &s, BasicScreen &screen, const std::string &format) +void showSongs(Menu &menu, const MPD::Song &s, HasSongs &screen, const std::string &format) { bool separate_albums, is_now_playing, is_selected, discard_colors; setProperties(menu, s, screen, separate_albums, is_now_playing, is_selected, discard_colors); @@ -147,7 +148,7 @@ void showSongs(Menu &menu, const MPD::Song &s, BasicScreen &screen, const std } template -void showSongsInColumns(Menu &menu, const MPD::Song &s, BasicScreen &screen) +void showSongsInColumns(Menu &menu, const MPD::Song &s, HasSongs &screen) { if (Config.columns.empty()) return; @@ -332,12 +333,12 @@ std::string Display::Columns(size_t list_width) return result; } -void Display::SongsInColumns(Menu &menu, BasicScreen &screen) +void Display::SongsInColumns(Menu &menu, HasSongs &screen) { showSongsInColumns(menu, menu.Drawn().value(), screen); } -void Display::Songs(Menu &menu, BasicScreen &screen, const std::string &format) +void Display::Songs(Menu &menu, HasSongs &screen, const std::string &format) { showSongs(menu, menu.Drawn().value(), screen, format); } diff --git a/src/display.h b/src/display.h index efd0c41c..83b2976b 100644 --- a/src/display.h +++ b/src/display.h @@ -21,11 +21,11 @@ #ifndef _DISPLAY_H #define _DISPLAY_H +#include "interfaces.h" #include "ncmpcpp.h" #include "menu.h" #include "mpdpp.h" #include "mutable_song.h" -#include "screen.h" #include "search_engine.h" namespace Display @@ -42,9 +42,9 @@ namespace Display menu << menu.Drawn().value().first; } - void SongsInColumns(Menu &menu, BasicScreen &screen); + void SongsInColumns(Menu &menu, HasSongs &screen); - void Songs(Menu &menu, BasicScreen &screen, const std::string &format); + void Songs(Menu &menu, HasSongs &screen, const std::string &format); void Tags(Menu &menu); diff --git a/src/helpers.cpp b/src/helpers.cpp index 52bbcf4c..ce946a92 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -270,11 +270,6 @@ void ParseArgv(int argc, char **argv) exit(0); } -std::string StringPairToString(const std::pair &pair) -{ - return pair.first; -} - std::string Timestamp(time_t t) { char result[32]; @@ -306,26 +301,6 @@ void UpdateSongList(Menu *menu) menu->Refresh(); } -#ifdef HAVE_TAGLIB_H -std::string getSharedDirectory(const MPD::SongList &v) -{ - if (v.empty()) // this should never happen, but in case... - FatalError("empty SongList passed to getSharedDirectory(const SongList &)!"); - size_t i = -1; - std::string first = v.front().getDirectory(); - for (MPD::SongList::const_iterator it = ++v.begin(); it != v.end(); ++it) - { - size_t j = 0; - std::string dir = it->getDirectory(); - size_t length = std::min(first.length(), dir.length()); - while (!first.compare(j, 1, dir, j, 1) && j < length && j < i) - ++j; - i = j; - } - return i ? first.substr(0, i) : "/"; -} -#endif // HAVE_TAGLIB_H - std::basic_string Scroller(const std::basic_string &str, size_t &pos, size_t width) { std::basic_string s(str); diff --git a/src/helpers.h b/src/helpers.h index b037063f..783b01a5 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -26,9 +26,41 @@ #include "settings.h" #include "status.h" -void ParseArgv(int, char **); +template void removeSelectionHelper(Iterator first, Iterator last) +{ + for (; first != last; ++first) + first->setSelected(false); +} -std::string StringPairToString(const std::pair &pair); +template void reverseSelectionHelper(Iterator first, Iterator last) +{ + for (; first != last; ++first) + first->setSelected(!first->isSelected()); +} + +template std::string getSharedDirectory(Iterator first, Iterator last) +{ + assert(first != last); + std::string result = first->getDirectory(); + while (++first != last) + { + result = getSharedDirectory(result, first->getDirectory()); + if (result == "/") + break; + } + return result; +} + +template void withUnfilteredMenu(Menu &menu, std::function action) +{ + bool is_filtered = menu.isFiltered(); + menu.ShowAll(); + action(); + if (is_filtered) + menu.ShowFiltered(); +} + +void ParseArgv(int, char **); template struct StringConverter { const char *operator()(const char *s) { return s; } @@ -172,22 +204,6 @@ std::string Timestamp(time_t t); void UpdateSongList(Menu *); -#ifdef HAVE_TAGLIB_H -template std::string getSharedDirectory(Menu *menu) -{ - assert(!menu->Empty()); - std::string dir; -// dir = (*menu)[0].value().getDirectory(); - for (size_t i = 1; i < menu->Size(); ++i) - { - dir = getSharedDirectory(dir, (*menu)[i].value().getDirectory()); - if (dir == "/") - break; - } - return dir; -} -#endif // HAVE_TAGLIB_H - std::basic_string Scroller(const std::basic_string &str, size_t &pos, size_t width); std::string Shorten(const std::basic_string &s, size_t max_length); diff --git a/src/interfaces.h b/src/interfaces.h index e99e6591..2aa9c44f 100644 --- a/src/interfaces.h +++ b/src/interfaces.h @@ -22,6 +22,7 @@ #define _INTERFACES_H #include +#include "mpdpp.h" #include "gcc.h" struct Filterable @@ -37,4 +38,15 @@ struct Searchable virtual void prevFound(bool wrap) = 0; }; +struct HasSongs +{ + virtual MPD::Song *getSong(size_t pos) = 0; + virtual MPD::Song *currentSong() = 0; + + virtual bool allowsSelection() = 0; + virtual void reverseSelection() = 0; + virtual void removeSelection() = 0; + virtual MPD::SongList getSelectedSongs() = 0; +}; + #endif // _INTERFACES_H diff --git a/src/lyrics.cpp b/src/lyrics.cpp index 1e4e4f5e..0a021df0 100644 --- a/src/lyrics.cpp +++ b/src/lyrics.cpp @@ -116,7 +116,11 @@ void Lyrics::SwitchTo() } # endif // HAVE_CURL_CURL_H - if (const MPD::Song *s = myScreen->CurrentSong()) + auto hs = dynamic_cast(myScreen); + if (!hs) + return; + + if (const MPD::Song *s = hs->currentSong()) { if (!s->getArtist().empty() && !s->getTitle().empty()) { @@ -137,7 +141,7 @@ void Lyrics::SwitchTo() // if we resize for locked screen, we have to do that in the end since // fetching lyrics may fail (eg. if tags are missing) and we don't want // to adjust screen size then. - if (myLockedScreen) + if (myLockedScreen) // BUG { UpdateInactiveScreen(this); Resize(); diff --git a/src/media_library.cpp b/src/media_library.cpp index bffb10a0..97b18f9c 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -19,6 +19,7 @@ ***************************************************************************/ #include +#include #include #include "charset.h" @@ -216,19 +217,16 @@ void MediaLibrary::Update() { if (!hasTwoColumns && Tags->ReallyEmpty()) { - MPD::TagList list; Albums->Clear(); Songs->Clear(); - Mpd.GetList(list, Config.media_lib_primary_tag); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it) + auto list = Mpd.GetList(Config.media_lib_primary_tag); + std::sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (auto it = list.begin(); it != list.end(); ++it) { if (it->empty() && !Config.media_library_display_empty_tag) continue; - utf_to_locale(*it); Tags->AddItem(*it); } - Tags->Window::Clear(); Tags->Refresh(); } @@ -237,35 +235,25 @@ void MediaLibrary::Update() // idle has to be blocked for now since it would be enabled and // disabled a few times by each mpd command, which makes no sense // and slows down the whole process. - Mpd.BlockIdle(1); + Mpd.BlockIdle(true); Albums->Reset(); - MPD::TagList list; - locale_to_utf(Tags->Current().value()); Mpd.StartFieldSearch(MPD_TAG_ALBUM); Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value()); - Mpd.CommitSearchTags([&list](std::string &&album) { - list.push_back(album); - }); - for (auto album = list.begin(); album != list.end(); ++album) + auto albums = Mpd.CommitSearchTags(); + for (auto album = albums.begin(); album != albums.end(); ++album) { if (Config.media_library_display_date) { Mpd.StartFieldSearch(MPD_TAG_DATE); Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value()); Mpd.AddSearch(MPD_TAG_ALBUM, *album); - utf_to_locale(*album); - Mpd.CommitSearchTags([this, &album](std::string &&date) { - utf_to_locale(date); - Albums->AddItem(SearchConstraints(*album, date)); - }); + auto dates = Mpd.CommitSearchTags(); + for (auto date = dates.begin(); date != dates.end(); ++date) + Albums->AddItem(SearchConstraints(*album, *date)); } else - { - utf_to_locale(*album); Albums->AddItem(SearchConstraints(*album, "")); - } } - utf_to_locale(Tags->Current().value()); if (!Albums->Empty()) std::sort(Albums->BeginV(), Albums->EndV(), SortSearchConstraints); if (Albums->Size() > 1) @@ -274,24 +262,20 @@ void MediaLibrary::Update() Albums->AddItem(SearchConstraints("", AllTracksMarker)); } Albums->Refresh(); - Mpd.BlockIdle(0); + Mpd.BlockIdle(false); } else if (hasTwoColumns && Albums->ReallyEmpty()) { Songs->Clear(); - MPD::TagList artists; *Albums << XY(0, 0) << "Fetching albums..."; Albums->Window::Refresh(); - Mpd.BlockIdle(1); - Mpd.GetList(artists, Config.media_lib_primary_tag); + Mpd.BlockIdle(true); + auto artists = Mpd.GetList(Config.media_lib_primary_tag); for (auto artist = artists.begin(); artist != artists.end(); ++artist) { - MPD::TagList albums; Mpd.StartFieldSearch(MPD_TAG_ALBUM); Mpd.AddSearch(Config.media_lib_primary_tag, *artist); - Mpd.CommitSearchTags([&albums](std::string &&album) { - albums.push_back(album); - }); + auto albums = Mpd.CommitSearchTags(); for (auto album = albums.begin(); album != albums.end(); ++album) { if (Config.media_library_display_date) @@ -301,26 +285,15 @@ void MediaLibrary::Update() Mpd.StartFieldSearch(MPD_TAG_DATE); Mpd.AddSearch(Config.media_lib_primary_tag, *artist); Mpd.AddSearch(MPD_TAG_ALBUM, *album); - utf_to_locale(*artist); - utf_to_locale(*album); - Mpd.CommitSearchTags([this, &artist, &album](std::string &&tag) { - utf_to_locale(tag); - Albums->AddItem(SearchConstraints(*artist, *album, tag)); - }); + auto dates = Mpd.CommitSearchTags(); + for (auto date = dates.begin(); date != dates.end(); ++date) + Albums->AddItem(SearchConstraints(*artist, *album, *date)); } else - { - utf_to_locale(*artist); - utf_to_locale(*album); Albums->AddItem(SearchConstraints(*artist, *album, *artist)); - } } else - { - utf_to_locale(*artist); - utf_to_locale(*album); Albums->AddItem(SearchConstraints(*artist, *album, "")); - } } } Mpd.BlockIdle(0); @@ -348,16 +321,15 @@ void MediaLibrary::Update() if (Config.media_library_display_date) Mpd.AddSearch(MPD_TAG_DATE, locale_to_utf_cpy(Albums->Current().value().Date)); } - Mpd.CommitSearchSongs([this](MPD::Song &&s) { - Songs->AddItem(s, myPlaylist->checkForSong(s)); - }); + auto songs = Mpd.CommitSearchSongs(); + for (auto s = songs.begin(); s != songs.end(); ++s) + Songs->AddItem(*s, myPlaylist->checkForSong(*s)); if (Albums->Current().value().Date == AllTracksMarker) std::sort(Songs->BeginV(), Songs->EndV(), SortAllTracks); else std::sort(Songs->BeginV(), Songs->EndV(), SortSongsByTrack); - Songs->Window::Clear(); Songs->Refresh(); } } @@ -462,11 +434,6 @@ void MediaLibrary::MouseButtonPressed(MEVENT me) } } -MPD::Song *MediaLibrary::CurrentSong() -{ - return w == Songs && !Songs->Empty() ? &Songs->Current().value() : 0; -} - List *MediaLibrary::GetList() { if (w == Tags) @@ -479,73 +446,6 @@ List *MediaLibrary::GetList() return 0; } -void MediaLibrary::ReverseSelection() -{ - if (w == Tags) - Tags->ReverseSelection(); - else if (w == Albums) - Albums->ReverseSelection(); - else if (w == Songs) - Songs->ReverseSelection(); -} - -void MediaLibrary::GetSelectedSongs(MPD::SongList &v) -{ - std::vector selected; - if (w == Tags && !Tags->Empty()) - { - Tags->GetSelected(selected); - if (selected.empty()) - selected.push_back(Tags->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - { - MPD::SongList list; - Mpd.StartSearch(1); - Mpd.AddSearch(Config.media_lib_primary_tag, locale_to_utf_cpy(Tags->at(*it).value())); - Mpd.CommitSearchSongs([&list](MPD::Song &&s) { - list.push_back(s); - }); - std::sort(list.begin(), list.end(), SortAllTracks); - std::copy(list.begin(), list.end(), std::back_inserter(v)); - } - } - else if (w == Albums && !Albums->Empty()) - { - Albums->GetSelected(selected); - if (selected.empty()) - { - // shortcut via the existing song list in right column - if (v.empty()) - v.reserve(Songs->Size()); - for (size_t i = 0; i < Songs->Size(); ++i) - v.push_back((*Songs)[i].value()); - } - else - { - for (auto it = selected.begin(); it != selected.end(); ++it) - { - Mpd.StartSearch(1); - Mpd.AddSearch(Config.media_lib_primary_tag, hasTwoColumns - ? Albums->at(*it).value().PrimaryTag - : locale_to_utf_cpy(Tags->Current().value())); - Mpd.AddSearch(MPD_TAG_ALBUM, Albums->at(*it).value().Album); - Mpd.AddSearch(MPD_TAG_DATE, Albums->at(*it).value().Date); - Mpd.CommitSearchSongs([&v](MPD::Song &&s) { - v.push_back(s); - }); - } - } - } - else if (w == Songs && !Songs->Empty()) - { - Songs->GetSelected(selected); - if (selected.empty()) - selected.push_back(Songs->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - v.push_back(Songs->at(*it).value()); - } -} - /***********************************************************************/ std::string MediaLibrary::currentFilter() @@ -629,6 +529,113 @@ void MediaLibrary::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *MediaLibrary::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + if (w == Songs) + ptr = &(*Songs)[pos].value(); + return ptr; +} + +MPD::Song *MediaLibrary::currentSong() +{ + if (w == Songs && !Songs->Empty()) + return getSong(Songs->Choice()); + else + return 0; +} + +bool MediaLibrary::allowsSelection() +{ + return true; +} + +void MediaLibrary::removeSelection() +{ + if (w == Tags) + removeSelectionHelper(Tags->Begin(), Tags->End()); + else if (w == Albums) + removeSelectionHelper(Albums->Begin(), Albums->End()); + else if (w == Songs) + removeSelectionHelper(Songs->Begin(), Songs->End()); +} + +void MediaLibrary::reverseSelection() +{ + if (w == Tags) + reverseSelectionHelper(Tags->Begin(), Tags->End()); + else if (w == Albums) + { + // omit "All tracks" + if (Albums->Size() > 1) + reverseSelectionHelper(Albums->Begin(), Albums->End()-2); + else + reverseSelectionHelper(Albums->Begin(), Albums->End()); + } + else if (w == Songs) + reverseSelectionHelper(Songs->Begin(), Songs->End()); +} + +MPD::SongList MediaLibrary::getSelectedSongs() +{ + MPD::SongList result; + if (w == Tags) + { + auto tag_handler = [&result](const std::string &tag) { + Mpd.StartSearch(true); + Mpd.AddSearch(Config.media_lib_primary_tag, tag); + auto songs = Mpd.CommitSearchSongs(); + std::sort(songs.begin(), songs.end(), SortAllTracks); + result.insert(result.end(), songs.begin(), songs.end()); + }; + for (auto it = Tags->Begin(); it != Tags->End(); ++it) + if (it->isSelected()) + tag_handler(it->value()); + // if no item is selected, add current one + if (result.empty() && !Tags->Empty()) + tag_handler(Tags->Current().value()); + } + else if (w == Albums) + { + for (auto it = Albums->Begin(); it != Albums->End() && !it->isSeparator(); ++it) + { + if (it->isSelected()) + { + auto &sc = it->value(); + Mpd.StartSearch(true); + if (hasTwoColumns) + Mpd.AddSearch(Config.media_lib_primary_tag, sc.PrimaryTag); + else + Mpd.AddSearch(Config.media_lib_primary_tag, Tags->Current().value()); + Mpd.AddSearch(MPD_TAG_ALBUM, sc.Album); + Mpd.AddSearch(MPD_TAG_DATE, sc.Date); + auto songs = Mpd.CommitSearchSongs(); + std::sort(songs.begin(), songs.end(), SortSongsByTrack); + result.insert(result.end(), songs.begin(), songs.end()); + } + } + // if no item is selected, add songs from right column + if (result.empty() && !Albums->Empty()) + { + withUnfilteredMenu(*Songs, [this, &result]() { + result.insert(result.end(), Songs->BeginV(), Songs->EndV()); + }); + } + } + else if (w == Songs) + { + for (auto it = Songs->Begin(); it != Songs->End(); ++it) + if (it->isSelected()) + result.push_back(it->value()); + // if no item is selected, add current one + if (result.empty() && !Songs->Empty()) + result.push_back(Songs->Current().value()); + } + return result; +} + +/***********************************************************************/ + int MediaLibrary::Columns() { if (hasTwoColumns) @@ -817,9 +824,7 @@ void MediaLibrary::AddToPlaylist(bool add_n_play) } else { - MPD::SongList list; - GetSelectedSongs(list); - + auto list = getSelectedSongs(); if (myPlaylist->Add(list, add_n_play)) { if ((!Tags->Empty() && w == Tags) @@ -915,20 +920,27 @@ void DisplayPrimaryTags(Menu &menu) bool SortSongsByTrack(const MPD::Song &a, const MPD::Song &b) { - if (a.getDisc() == b.getDisc()) - return stringToInt(a.getTrack()) < stringToInt(b.getTrack()); - else - return stringToInt(a.getDisc()) < stringToInt(b.getDisc()); + int cmp = a.getDisc().compare(a.getDisc()); + if (cmp != 0) + return cmp; + return a.getTrack() < b.getTrack(); } bool SortAllTracks(const MPD::Song &a, const MPD::Song &b) { - static MPD::Song::GetFunction gets[] = { &MPD::Song::getDate, &MPD::Song::getAlbum, &MPD::Song::getDisc, 0 }; + const std::array gets = {{ + &MPD::Song::getDate, + &MPD::Song::getAlbum, + &MPD::Song::getDisc + }}; CaseInsensitiveStringComparison cmp; - for (MPD::Song::GetFunction *get = gets; *get; ++get) - if (int ret = cmp(a.getTags(*get), b.getTags(*get))) + for (auto get = gets.begin(); get != gets.end(); ++get) + { + int ret = cmp(a.getTags(*get), b.getTags(*get)); + if (ret != 0) return ret < 0; - return a.getTrack() < b.getTrack(); + } + return a.getTrack() < b.getTrack(); } bool SortSearchConstraints(const SearchConstraints &a, const SearchConstraints &b) diff --git a/src/media_library.h b/src/media_library.h index 48c2e1a0..c6f51634 100644 --- a/src/media_library.h +++ b/src/media_library.h @@ -25,7 +25,7 @@ #include "ncmpcpp.h" #include "screen.h" -class MediaLibrary : public Screen, public Filterable, public Searchable +class MediaLibrary : public Screen, public Filterable, public HasSongs, public Searchable { public: virtual void SwitchTo(); @@ -41,13 +41,6 @@ class MediaLibrary : public Screen, public Filterable, public Searchable virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return w == Songs ? &Songs->at(pos).value() : 0; } - - virtual bool allowsSelection() { return true; } - virtual void ReverseSelection(); - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -57,6 +50,15 @@ class MediaLibrary : public Screen, public Filterable, public Searchable virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual List *GetList(); virtual bool isMergable() { return true; } diff --git a/src/menu.cpp b/src/menu.cpp deleted file mode 100644 index 033ca847..00000000 --- a/src/menu.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008-2012 by Andrzej Rybczak * - * electricityispower@gmail.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ diff --git a/src/menu.h b/src/menu.h index 5664504a..a086789a 100644 --- a/src/menu.h +++ b/src/menu.h @@ -153,7 +153,7 @@ template struct Menu : public Window, public List return ItemIterator::type, Iterator>(m_it); } - const BaseIterator &base() { return m_it; } + const BaseIterator &base() const { return m_it; } }; typedef ItemIterator< @@ -251,10 +251,6 @@ template struct Menu : public Window, public List /// @param v vector to be filled with selected positions numbers void GetSelected(std::vector &v) const; - /// Reverses selection of all items in list - /// @param beginning beginning of range that has to be reversed - void ReverseSelection(size_t beginning = 0); - /// Highlights given position /// @param pos position to be highlighted void Highlight(size_t pos); @@ -372,33 +368,27 @@ template struct Menu : public Window, public List const Menu::Item &Back() const; /// @return reference to curently highlighted object - /// @throw List::InvalidItem if requested item is separator Menu::Item &Current(); /// @return const reference to curently highlighted object - /// @throw List::InvalidItem if requested item is separator const Menu::Item &Current() const; /// @param pos requested position /// @return reference to item at given position /// @throw std::out_of_range if given position is out of range - /// @throw List::InvalidItem if requested item is separator Menu::Item &at(size_t pos); /// @param pos requested position /// @return const reference to item at given position /// @throw std::out_of_range if given position is out of range - /// @throw List::InvalidItem if requested item is separator const Menu::Item &at(size_t pos) const; /// @param pos requested position /// @return const reference to item at given position - /// @throw List::InvalidItem if requested item is separator const Menu::Item &operator[](size_t pos) const; /// @param pos requested position /// @return const reference to item at given position - /// @throw List::InvalidItem if requested item is separator Menu::Item &operator[](size_t pos); Iterator Begin() { return Iterator(m_options_ptr->begin()); } @@ -744,6 +734,7 @@ template size_t Menu::Size() const template size_t Menu::Choice() const { + assert(!Empty()); return m_highlight; } @@ -793,13 +784,6 @@ template void Menu::clearSearchResults() m_found_positions.clear(); } -template void Menu::ReverseSelection(size_t beginning) -{ - auto it = m_options_ptr->begin()+beginning; - for (size_t i = beginning; i < Size(); ++i, ++it) - (*it)->setSelected(!(*it)->isSelected() && !(*it)->isInactive()); -} - template void Menu::NextFound(bool wrap) { if (m_found_positions.empty()) diff --git a/src/mpdpp.cpp b/src/mpdpp.cpp index 3b46c792..a4340d50 100644 --- a/src/mpdpp.cpp +++ b/src/mpdpp.cpp @@ -621,17 +621,19 @@ bool MPD::Connection::Rename(const std::string &from, const std::string &to) } } -void MPD::Connection::GetPlaylistChanges(unsigned version, std::function f) +MPD::SongList MPD::Connection::GetPlaylistChanges(unsigned version) { + SongList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_queue_changes_meta(itsConnection, version); while (mpd_song *s = mpd_recv_song(itsConnection)) - f(Song(s)); + result.push_back(Song(s)); mpd_response_finish(itsConnection); GoIdle(); + return result; } MPD::Song MPD::Connection::GetSong(const std::string &path) @@ -667,17 +669,19 @@ MPD::Song MPD::Connection::GetCurrentlyPlayingSong() return result; } -void MPD::Connection::GetPlaylistContent(const std::string &path, std::function f) +MPD::SongList MPD::Connection::GetPlaylistContent(const std::string &path) { + SongList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_playlist_meta(itsConnection, path.c_str()); while (mpd_song *s = mpd_recv_song(itsConnection)) - f(Song(s)); + result.push_back(Song(s)); mpd_response_finish(itsConnection); GoIdle(); + return result; } void MPD::Connection::GetSupportedExtensions(std::set &acc) @@ -903,9 +907,7 @@ bool MPD::Connection::AddRandomTag(mpd_tag_type tag, size_t number) return false; assert(!isCommandsListEnabled); - TagList tags; - GetList(tags, tag); - + auto tags = GetList(tag); if (number > tags.size()) { if (itsErrorHandler) @@ -915,18 +917,15 @@ bool MPD::Connection::AddRandomTag(mpd_tag_type tag, size_t number) else { std::random_shuffle(tags.begin(), tags.end()); - TagList::const_iterator it = tags.begin()+rand()%(tags.size()-number); + auto it = tags.begin()+rand()%(tags.size()-number); for (size_t i = 0; i < number && it != tags.end(); ++i) { StartSearch(1); AddSearch(tag, *it++); - SongList list; - CommitSearchSongs([&list](MPD::Song &&s) { - list.push_back(s); - }); + auto songs = CommitSearchSongs(); StartCommandsList(); - for (auto j = list.begin(); j != list.end(); ++j) - AddSong(*j); + for (auto s = songs.begin(); s != songs.end(); ++s) + AddSong(*s); CommitCommandsList(); } } @@ -939,7 +938,7 @@ bool MPD::Connection::AddRandomSongs(size_t number) return false; assert(!isCommandsListEnabled); - TagList files; + StringList files; GoBusy(); mpd_send_list_all(itsConnection, "/"); @@ -958,12 +957,11 @@ bool MPD::Connection::AddRandomSongs(size_t number) } else { - srand(time(0)); std::random_shuffle(files.begin(), files.end()); StartCommandsList(); - TagList::const_iterator it = files.begin()+rand()%(std::max(size_t(1), files.size()-number)); - for (size_t i = 0; i < number && it != files.end(); ++i) - AddSong(*it++); + auto it = files.begin()+rand()%(std::max(size_t(1), files.size()-number)); + for (size_t i = 0; i < number && it != files.end(); ++i, ++it) + AddSong(*it); CommitCommandsList(); } return true; @@ -1075,31 +1073,35 @@ int MPD::Connection::SavePlaylist(const std::string &name) return CheckForErrors(); } -void MPD::Connection::GetPlaylists(TagList &v) +MPD::StringList MPD::Connection::GetPlaylists() { + StringList result; if (!itsConnection) - return; - GetDirectory("/", [&v](Item &&it) { - if (it.type == itPlaylist) - v.push_back(it.name); - }); + return result; + auto items = GetDirectory("/"); + for (auto it = items.begin(); it != items.end(); ++it) + if (it->type == itPlaylist) + result.push_back(it->name); + return result; } -void MPD::Connection::GetList(TagList &v, mpd_tag_type type) +MPD::StringList MPD::Connection::GetList(mpd_tag_type type) { + StringList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_search_db_tags(itsConnection, type); mpd_search_commit(itsConnection); while (mpd_pair *item = mpd_recv_pair_tag(itsConnection, type)) { - v.push_back(item->value); + result.push_back(item->value); mpd_return_pair(itsConnection, item); } mpd_response_finish(itsConnection); GoIdle(); + return result; } void MPD::Connection::StartSearch(bool exact_match) @@ -1140,39 +1142,44 @@ void MPD::Connection::AddSearchURI(const std::string &str) const mpd_search_add_uri_constraint(itsConnection, MPD_OPERATOR_DEFAULT, str.c_str()); } -void MPD::Connection::CommitSearchSongs(std::function f) +MPD::SongList MPD::Connection::CommitSearchSongs() { + SongList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_search_commit(itsConnection); while (mpd_song *s = mpd_recv_song(itsConnection)) - f(Song(s)); + result.push_back(Song(s)); mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::CommitSearchTags(std::function f) +MPD::StringList MPD::Connection::CommitSearchTags() { + StringList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_search_commit(itsConnection); while (mpd_pair *tag = mpd_recv_pair_tag(itsConnection, itsSearchedField)) { - f(tag->value); + result.push_back(tag->value); mpd_return_pair(itsConnection, tag); } mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::GetDirectory(const std::string &path, std::function f) +MPD::ItemList MPD::Connection::GetDirectory(const std::string &path) { + ItemList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_meta(itsConnection, path.c_str()); @@ -1197,68 +1204,77 @@ void MPD::Connection::GetDirectory(const std::string &path, std::function f) +MPD::SongList MPD::Connection::GetDirectoryRecursive(const std::string &path) { + SongList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_all_meta(itsConnection, path.c_str()); while (mpd_song *s = mpd_recv_song(itsConnection)) - f(Song(s)); + result.push_back(Song(s)); mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::GetDirectories(const std::string &path, TagList &v) +MPD::StringList MPD::Connection::GetDirectories(const std::string &path) { + StringList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_meta(itsConnection, path.c_str()); while (mpd_directory *dir = mpd_recv_directory(itsConnection)) { - v.push_back(mpd_directory_get_path(dir)); + result.push_back(mpd_directory_get_path(dir)); mpd_directory_free(dir); } mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::GetSongs(const std::string &path, SongList &v) +MPD::SongList MPD::Connection::GetSongs(const std::string &path) { + SongList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_meta(itsConnection, path.c_str()); while (mpd_song *s = mpd_recv_song(itsConnection)) - v.push_back(Song(s)); + result.push_back(Song(s)); mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::GetOutputs(std::function f) +MPD::OutputList MPD::Connection::GetOutputs() { + OutputList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_outputs(itsConnection); while (mpd_output *output = mpd_recv_output(itsConnection)) { - f(Output(mpd_output_get_name(output), mpd_output_get_enabled(output))); + result.push_back(Output(mpd_output_get_name(output), mpd_output_get_enabled(output))); mpd_output_free(output); } mpd_response_finish(itsConnection); GoIdle(); + return result; } bool MPD::Connection::EnableOutput(int id) @@ -1293,36 +1309,40 @@ bool MPD::Connection::DisableOutput(int id) } } -void MPD::Connection::GetURLHandlers(std::function f) +MPD::StringList MPD::Connection::GetURLHandlers() { + StringList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_url_schemes(itsConnection); while (mpd_pair *handler = mpd_recv_pair_named(itsConnection, "handler")) { - f(handler->value); + result.push_back(handler->value); mpd_return_pair(itsConnection, handler); } mpd_response_finish(itsConnection); GoIdle(); + return result; } -void MPD::Connection::GetTagTypes(std::function f) +MPD::StringList MPD::Connection::GetTagTypes() { + StringList result; if (!itsConnection) - return; + return result; assert(!isCommandsListEnabled); GoBusy(); mpd_send_list_tag_types(itsConnection); while (mpd_pair *tag_type = mpd_recv_pair_named(itsConnection, "tagtype")) { - f(tag_type->value); + result.push_back(tag_type->value); mpd_return_pair(itsConnection, tag_type); } mpd_response_finish(itsConnection); GoIdle(); + return result; } int MPD::Connection::CheckForErrors() diff --git a/src/mpdpp.h b/src/mpdpp.h index 02252694..1ce62f39 100644 --- a/src/mpdpp.h +++ b/src/mpdpp.h @@ -74,7 +74,7 @@ namespace MPD typedef std::vector ItemList; typedef std::vector SongList; - typedef std::vector TagList; + typedef std::vector StringList; typedef std::vector OutputList; class Connection @@ -153,15 +153,15 @@ namespace MPD unsigned long DBPlayTime() const { return itsStats ? mpd_stats_get_db_play_time(itsStats) : 0; } size_t GetPlaylistLength() const { return itsCurrentStatus ? mpd_status_get_queue_length(itsCurrentStatus) : 0; } - void GetPlaylistChanges(unsigned, std::function f); + SongList GetPlaylistChanges(unsigned); - const std::string & GetErrorMessage() const { return itsErrorMessage; } + const std::string &GetErrorMessage() const { return itsErrorMessage; } Song GetCurrentlyPlayingSong(); int GetCurrentlyPlayingSongPos() const; int GetCurrentSongPos() const; Song GetSong(const std::string &); - void GetPlaylistContent(const std::string &, std::function f); + SongList GetPlaylistContent(const std::string &); void GetSupportedExtensions(std::set &); @@ -202,22 +202,22 @@ namespace MPD void AddSearch(mpd_tag_type, const std::string &) const; void AddSearchAny(const std::string &str) const; void AddSearchURI(const std::string &str) const; - void CommitSearchSongs(std::function f); - void CommitSearchTags(std::function f); + SongList CommitSearchSongs(); + StringList CommitSearchTags(); - void GetPlaylists(TagList &); - void GetList(TagList &, mpd_tag_type); - void GetDirectory(const std::string &, std::function f); - void GetDirectoryRecursive(const std::string &, std::function f); - void GetSongs(const std::string &, SongList &); - void GetDirectories(const std::string &, TagList &); + StringList GetPlaylists(); + StringList GetList(mpd_tag_type); + ItemList GetDirectory(const std::string &); + SongList GetDirectoryRecursive(const std::string &); + SongList GetSongs(const std::string &); + StringList GetDirectories(const std::string &); - void GetOutputs(std::function f); + OutputList GetOutputs(); bool EnableOutput(int); bool DisableOutput(int); - void GetURLHandlers(std::function f); - void GetTagTypes(std::function f); + StringList GetURLHandlers(); + StringList GetTagTypes(); private: void GoIdle(); diff --git a/src/outputs.cpp b/src/outputs.cpp index 1df0ab26..e5a82b4e 100644 --- a/src/outputs.cpp +++ b/src/outputs.cpp @@ -116,9 +116,9 @@ void Outputs::FetchList() if (!isInitialized) return; w->Clear(); - Mpd.GetOutputs([this](MPD::Output &&o) { - w->AddItem(o, o.isEnabled()); - }); + auto outputs = Mpd.GetOutputs(); + for (auto o = outputs.begin(); o != outputs.end(); ++o) + w->AddItem(*o, o->isEnabled()); if (myScreen == this) w->Refresh(); } diff --git a/src/playlist.cpp b/src/playlist.cpp index add812ed..03da74bf 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -269,23 +269,6 @@ void Playlist::MouseButtonPressed(MEVENT me) } } -MPD::Song *Playlist::CurrentSong() -{ - return w == Items && !Items->Empty() ? &Items->Current().value() : 0; -} - -void Playlist::GetSelectedSongs(MPD::SongList &v) -{ - if (Items->Empty()) - return; - std::vector selected; - Items->GetSelected(selected); - if (selected.empty()) - selected.push_back(Items->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - v.push_back(Items->at(*it).value()); -} - /***********************************************************************/ std::string Playlist::currentFilter() @@ -333,6 +316,54 @@ void Playlist::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *Playlist::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + if (w == Items) + ptr = &(*Items)[pos].value(); + return ptr; +} + +MPD::Song *Playlist::currentSong() +{ + if (Items->Empty()) + return 0; + else + return getSong(Items->Choice()); +} + +bool Playlist::allowsSelection() +{ + return w == Items; +} + +void Playlist::removeSelection() +{ + removeSelectionHelper(Items->Begin(), Items->End()); +} + +void Playlist::reverseSelection() +{ + reverseSelectionHelper(Items->Begin(), Items->End()); +} + +MPD::SongList Playlist::getSelectedSongs() +{ + MPD::SongList result; + if (w == Items) + { + for (auto it = Items->Begin(); it != Items->End(); ++it) + if (it->isSelected()) + result.push_back(it->value()); + if (result.empty() && !Items->Empty()) + result.push_back(Items->Current().value()); + } + return result; +} + +/***********************************************************************/ + + bool Playlist::isFiltered() { if (Items->isFiltered()) diff --git a/src/playlist.h b/src/playlist.h index 4610721b..f9769813 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -26,7 +26,7 @@ #include "screen.h" #include "song.h" -class Playlist : public Screen, public Filterable, public Searchable +class Playlist : public Screen, public Filterable, public HasSongs, public Searchable { public: enum Movement { mUp, mDown }; @@ -44,13 +44,6 @@ class Playlist : public Screen, public Filterable, public Searchable virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return w == Items ? &Items->at(pos).value() : 0; } - - virtual bool allowsSelection() { return w == Items; } - virtual void ReverseSelection() { Items->ReverseSelection(); } - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -60,6 +53,15 @@ class Playlist : public Screen, public Filterable, public Searchable virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual List *GetList() { return w == Items ? Items : 0; } virtual bool isMergable() { return true; } diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index 380e36a4..9f42cb4e 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -60,9 +60,11 @@ void PlaylistEditor::Init() Playlists->HighlightColor(Config.active_column_color); Playlists->CyclicScrolling(Config.use_cyclic_scrolling); Playlists->CenteredCursor(Config.centered_cursor); + Playlists->SetSelectPrefix(Config.selected_item_prefix); + Playlists->SetSelectSuffix(Config.selected_item_suffix); Playlists->setItemDisplayer(Display::Default); - Content = new Menu(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Playlist's content" : "", Config.main_color, brNone); + Content = new Menu(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, Config.titles_visibility ? "Playlist content" : "", Config.main_color, brNone); Content->HighlightColor(Config.main_highlight_color); Content->CyclicScrolling(Config.use_cyclic_scrolling); Content->CenteredCursor(Config.centered_cursor); @@ -138,15 +140,10 @@ void PlaylistEditor::Update() if (Playlists->ReallyEmpty()) { Content->Clear(); - MPD::TagList list; - Mpd.GetPlaylists(list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (MPD::TagList::iterator it = list.begin(); it != list.end(); ++it) - { - utf_to_locale(*it); + auto list = Mpd.GetPlaylists(); + std::sort(list.begin(), list.end(), CaseInsensitiveSorting()); + for (auto it = list.begin(); it != list.end(); ++it) Playlists->AddItem(*it); - } - Playlists->Window::Clear(); Playlists->Refresh(); } @@ -154,20 +151,26 @@ void PlaylistEditor::Update() { Content->Reset(); size_t plsize = 0; - Mpd.GetPlaylistContent(locale_to_utf_cpy(Playlists->Current().value()), [this, &plsize](MPD::Song &&s) { - Content->AddItem(s, myPlaylist->checkForSong(s)); - ++plsize; - }); - if (plsize > 0) + auto songs = Mpd.GetPlaylistContent(Playlists->Current().value()); + for (auto s = songs.begin(); s != songs.end(); ++s, ++plsize) + Content->AddItem(*s, myPlaylist->checkForSong(*s)); + std::string title; + if (Config.titles_visibility) { - std::string title = Config.titles_visibility ? "Playlist content (" + unsignedLongIntTo::apply(plsize) + " item" + (plsize == 1 ? ")" : "s)") : ""; + title = "Playlist content"; + if (plsize > 0) + { + title += " ("; + title += unsignedLongIntTo::apply(plsize); + title += " item"; + if (plsize == 1) + title += ")"; + else + title += "s)"; + } title.resize(Content->GetWidth()); - Content->SetTitle(title); } - else - Content->SetTitle(Config.titles_visibility ? "Playlist content" : ""); - - Content->Window::Clear(); + Content->SetTitle(title); Content->Display(); } @@ -351,13 +354,27 @@ void PlaylistEditor::AddToPlaylist(bool add_n_play) void PlaylistEditor::SpacePressed() { - if (Config.space_selects && w == Content) + if (Config.space_selects) { - Content->Current().setSelected(!Content->Current().isSelected()); - w->Scroll(wDown); + if (w == Playlists) + { + if (!Playlists->Empty()) + { + Playlists->Current().setSelected(!Playlists->Current().isSelected()); + Playlists->Scroll(wDown); + } + } + else if (w == Content) + { + if (!Content->Empty()) + { + Content->Current().setSelected(!Content->Current().isSelected()); + Content->Scroll(wDown); + } + } } else - AddToPlaylist(0); + AddToPlaylist(false); } void PlaylistEditor::MouseButtonPressed(MEVENT me) @@ -403,21 +420,6 @@ void PlaylistEditor::MouseButtonPressed(MEVENT me) } } -MPD::Song *PlaylistEditor::CurrentSong() -{ - return w == Content && !Content->Empty() ? &Content->Current().value() : 0; -} - -void PlaylistEditor::GetSelectedSongs(MPD::SongList &v) -{ - std::vector selected; - Content->GetSelected(selected); - if (selected.empty()) - selected.push_back(Content->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - v.push_back(Content->at(*it).value()); -} - /***********************************************************************/ std::string PlaylistEditor::currentFilter() @@ -482,6 +484,81 @@ void PlaylistEditor::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *PlaylistEditor::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + if (w == Content) + ptr = &(*Content)[pos].value(); + return ptr; +} + +MPD::Song *PlaylistEditor::currentSong() +{ + if (w == Content && !Content->Empty()) + return getSong(Content->Choice()); + else + return 0; +} + +bool PlaylistEditor::allowsSelection() +{ + return true; +} + +void PlaylistEditor::removeSelection() +{ + if (w == Playlists) + removeSelectionHelper(Playlists->Begin(), Playlists->End()); + else if (w == Content) + removeSelectionHelper(Content->Begin(), Content->End()); +} + +void PlaylistEditor::reverseSelection() +{ + if (w == Playlists) + reverseSelectionHelper(Playlists->Begin(), Playlists->End()); + else if (w == Content) + reverseSelectionHelper(Content->Begin(), Content->End()); +} + +MPD::SongList PlaylistEditor::getSelectedSongs() +{ + MPD::SongList result; + if (w == Playlists) + { + bool any_selected = false; + for (auto it = Playlists->Begin(); it != Playlists->End(); ++it) + { + if (it->isSelected()) + { + any_selected = true; + auto songs = Mpd.GetPlaylistContent(it->value()); + result.insert(result.end(), songs.begin(), songs.end()); + } + } + // we don't check for empty result here as it's possible that + // all selected playlists are empty. + if (!any_selected && !Content->Empty()) + { + withUnfilteredMenu(*Content, [this, &result]() { + result.insert(result.end(), Content->BeginV(), Content->EndV()); + }); + } + } + else if (w == Content) + { + for (auto it = Content->Begin(); it != Content->End(); ++it) + if (it->isSelected()) + result.push_back(it->value()); + // if no item is selected, add current one + if (result.empty() && !Content->Empty()) + result.push_back(Content->Current().value()); + } + return result; +} + +/***********************************************************************/ + void PlaylistEditor::Locate(const std::string &name) { if (!isInitialized) diff --git a/src/playlist_editor.h b/src/playlist_editor.h index 98d2dc62..ced4c713 100644 --- a/src/playlist_editor.h +++ b/src/playlist_editor.h @@ -24,7 +24,7 @@ #include "playlist.h" #include "ncmpcpp.h" -class PlaylistEditor : public Screen, public Filterable, public Searchable +class PlaylistEditor : public Screen, public Filterable, public HasSongs, public Searchable { public: virtual void SwitchTo(); @@ -40,13 +40,6 @@ class PlaylistEditor : public Screen, public Filterable, public Searchab virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return w == Content ? &Content->at(pos).value() : 0; } - - virtual bool allowsSelection() { return w == Content; } - virtual void ReverseSelection() { Content->ReverseSelection(); } - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -56,6 +49,15 @@ class PlaylistEditor : public Screen, public Filterable, public Searchab virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual void Locate(const std::string &); virtual List *GetList(); diff --git a/src/regexes.cpp b/src/regexes.cpp index 69150026..02ed476c 100644 --- a/src/regexes.cpp +++ b/src/regexes.cpp @@ -42,6 +42,16 @@ Regex::~Regex() regfree(&m_rx); } +const std::string &Regex::regex() const +{ + return m_regex; +} + +const std::string &Regex::error() const +{ + return m_error; +} + bool Regex::compile() { if (m_compiled) diff --git a/src/regexes.h b/src/regexes.h index bca86ca8..94ac68ac 100644 --- a/src/regexes.h +++ b/src/regexes.h @@ -32,10 +32,10 @@ struct Regex virtual ~Regex(); /// @return regular expression - const std::string ®ex() const { return m_regex; } + const std::string ®ex() const; /// @return compilation error (if there was any) - const std::string &error() const { return m_error; } + const std::string &error() const; /// compiles regular expression /// @result true if compilation was successful, false otherwise @@ -59,4 +59,4 @@ private: bool m_compiled; }; -#endif // _REGEXES_H \ No newline at end of file +#endif // _REGEXES_H diff --git a/src/screen.h b/src/screen.h index 74bbd4f2..a76bf267 100644 --- a/src/screen.h +++ b/src/screen.h @@ -46,84 +46,46 @@ class BasicScreen virtual ~BasicScreen() { } /// @see Screen::ActiveWindow() - /// virtual Window *ActiveWindow() = 0; /// Method used for switching to screen - /// virtual void SwitchTo() = 0; /// Method that should resize screen /// if requested by hasToBeResized - /// virtual void Resize() = 0; /// @return title of the screen - /// virtual std::basic_string Title() = 0; /// If the screen contantly has to update itself /// somehow, it should be called by this function. - /// virtual void Update() { } /// @see Screen::Refresh() - /// virtual void Refresh() = 0; /// @see Screen::RefreshWindow() - /// virtual void RefreshWindow() = 0; /// @see Screen::Scroll() - /// virtual void Scroll(Where where) = 0; /// Invoked after Enter was pressed - /// virtual void EnterPressed() = 0; /// Invoked after Space was pressed - /// virtual void SpacePressed() = 0; /// @see Screen::MouseButtonPressed() - /// virtual void MouseButtonPressed(MEVENT) { } - /// @return pointer to currently selected song in the screen - /// (if screen provides one) or null pointer otherwise. - /// - virtual MPD::Song *CurrentSong() { return 0; } - - /// @return pointer to song at given position in the screen - /// (if screen is provides one) or null pointer otherwise. - /// - virtual MPD::Song *GetSong(GNUC_UNUSED size_t pos) { return 0; } - - /// @return true if the screen allows selecting items, false otherwise - /// - virtual bool allowsSelection() = 0; - - /// Reverses selection. Does nothing by default since pure - /// virtual allowsSelection() should remind of this function - /// to be defined - /// - virtual void ReverseSelection() { } - - /// Gets selected songs' positions from the screen - /// @param v vector to be filled with positions - /// - virtual void GetSelectedSongs(GNUC_UNUSED MPD::SongList &v) { } - /// @return pointer to instantiation of Menu template class /// cast to List if available or null pointer otherwise - /// virtual List *GetList() = 0; /// When this is overwritten with a function returning true, the /// screen will be used in tab switching. - /// virtual bool isTabbable() { return false; } /// @return true if screen is mergable, ie. can be "proper" subwindow @@ -137,7 +99,6 @@ class BasicScreen bool Lock(); /// Should be set to true each time screen needs resize - /// bool hasToBeResized; /// Unlocks a screen, ie. hides merged window (if there is one set). @@ -182,33 +143,26 @@ template class Screen : public BasicScreen /// it's useful to determine the one that is being /// active /// @return address to window object cast to void * - /// virtual Window *ActiveWindow(); /// @return pointer to currently active window - /// WindowType *Main(); /// Refreshes whole screen - /// virtual void Refresh(); /// Refreshes active window of the screen - /// virtual void RefreshWindow(); - /// Scrolls the screen by given amount of lines and /// if fancy scrolling feature is disabled, enters the /// loop that holds main loop until user releases the key /// @param where indicates where one wants to scroll - /// virtual void Scroll(Where where); /// Invoked after there was one of mouse buttons pressed /// @param me struct that contains coords of where the click /// had its place and button actions - /// virtual void MouseButtonPressed(MEVENT me); protected: @@ -216,7 +170,6 @@ template class Screen : public BasicScreen /// of window used by the screen. What is more, it should /// always be assigned to the currently active window (if /// acreen contains more that one) - /// WindowType *w; }; @@ -268,7 +221,6 @@ template void Screen::MouseButtonPressed(MEVEN /// Specialization for Screen::MouseButtonPressed, that should /// not scroll whole page, but rather a few lines (the number of them is /// defined in the config) -/// template <> inline void Screen::MouseButtonPressed(MEVENT me) { if (me.bstate & BUTTON2_PRESSED) diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 3b29ab61..7adcdf17 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -276,26 +276,6 @@ void SearchEngine::MouseButtonPressed(MEVENT me) Screen< Menu >::MouseButtonPressed(me); } -MPD::Song *SearchEngine::CurrentSong() -{ - return !w->Empty() && w->Current().value().isSong() ? &w->Current().value().song() : 0; -} - -void SearchEngine::GetSelectedSongs(MPD::SongList &v) -{ - if (w->Empty()) - return; - std::vector selected; - w->GetSelected(selected); - if (selected.empty() && w->Choice() >= StaticOptions) - selected.push_back(w->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - { - assert(w->at(*it).value().isSong()); - v.push_back(w->at(*it).value().song()); - } -} - /***********************************************************************/ std::string SearchEngine::currentFilter() @@ -332,22 +312,65 @@ void SearchEngine::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *SearchEngine::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + auto &item = (*w)[pos]; + if (!item.isSeparator() && item.value().isSong()) + ptr = &item.value().song(); + return ptr; +} + +MPD::Song *SearchEngine::currentSong() +{ + if (w->Empty()) + return 0; + else + return getSong(w->Choice()); +} + +bool SearchEngine::allowsSelection() +{ + return w->Current().value().isSong(); +} + +void SearchEngine::removeSelection() +{ + removeSelectionHelper(w->Begin(), w->End()); +} + +void SearchEngine::reverseSelection() +{ + reverseSelectionHelper(w->Begin()+std::min(StaticOptions, w->Size()), w->End()); +} + +MPD::SongList SearchEngine::getSelectedSongs() +{ + MPD::SongList result; + for (auto it = w->Begin(); it != w->End(); ++it) + { + if (it->isSelected()) + { + assert(it->value().isSong()); + result.push_back(it->value().song()); + } + } + // if no item is selected, add current one + if (result.empty() && !w->Empty()) + { + assert(w->Current().value().isSong()); + result.push_back(w->Current().value().song()); + } + return result; +} + +/***********************************************************************/ + void SearchEngine::UpdateFoundList() { - bool bold = 0; - for (size_t i = StaticOptions; i < w->Size(); ++i) - { - for (size_t j = 0; j < myPlaylist->Items->Size(); ++j) - { - if (myPlaylist->Items->at(j).value().getHash() == w->at(i).value().song().getHash()) - { - bold = 1; - break; - } - } - w->at(i).setBold(bold); - bold = 0; - } + for (auto it = w->Begin(); it != w->End(); ++it) + if (it->value().isSong()) + it->setBold(myPlaylist->checkForSong(it->value().song())); } void SearchEngine::Prepare() @@ -422,30 +445,26 @@ void SearchEngine::Search() Mpd.AddSearch(MPD_TAG_DATE, itsConstraints[9]); if (!itsConstraints[10].empty()) Mpd.AddSearch(MPD_TAG_COMMENT, itsConstraints[10]); - Mpd.CommitSearchSongs([this](MPD::Song &&s) { - w->AddItem(s); - }); + auto songs = Mpd.CommitSearchSongs(); + for (auto s = songs.begin(); s != songs.end(); ++s) + w->AddItem(*s); return; } MPD::SongList list; if (Config.search_in_db) - { - Mpd.GetDirectoryRecursive("/", [&list](MPD::Song &&s) { - list.push_back(s); - }); - } + list = Mpd.GetDirectoryRecursive("/"); else { list.reserve(myPlaylist->Items->Size()); - for (size_t i = 0; i < myPlaylist->Items->Size(); ++i) - list.push_back((*myPlaylist->Items)[i].value()); + for (auto s = myPlaylist->Items->BeginV(); s != myPlaylist->Items->EndV(); ++s) + list.push_back(*s); } bool any_found = 1; bool found = 1; - for (MPD::SongList::const_iterator it = list.begin(); it != list.end(); ++it) + for (auto it = list.begin(); it != list.end(); ++it) { if (SearchMode != &SearchModes[2]) // match to pattern { diff --git a/src/search_engine.h b/src/search_engine.h index 7b9ed8f9..a4c3b5af 100644 --- a/src/search_engine.h +++ b/src/search_engine.h @@ -26,6 +26,7 @@ #include "interfaces.h" #include "mpdpp.h" #include "ncmpcpp.h" +#include "screen.h" struct SEItem { @@ -73,7 +74,7 @@ struct SEItem MPD::Song itsSong; }; -class SearchEngine : public Screen< Menu >, public Filterable, public Searchable +class SearchEngine : public Screen< Menu >, public Filterable, public HasSongs, public Searchable { public: virtual void Resize(); @@ -86,13 +87,6 @@ class SearchEngine : public Screen< Menu >, public Filterable, public Se virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return !(*w)[pos].isSeparator() && w->at(pos).value().isSong() ? &w->at(pos).value().song() : 0; } - - virtual bool allowsSelection() { return w->Choice() >= StaticOptions; } - virtual void ReverseSelection() { w->ReverseSelection(StaticOptions); } - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -102,6 +96,15 @@ class SearchEngine : public Screen< Menu >, public Filterable, public Se virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual List *GetList() { return w->Size() >= StaticOptions ? w : 0; } virtual bool isMergable() { return true; } diff --git a/src/sel_items_adder.cpp b/src/sel_items_adder.cpp index ff118f64..d83d0aa6 100644 --- a/src/sel_items_adder.cpp +++ b/src/sel_items_adder.cpp @@ -69,7 +69,8 @@ void SelectedItemsAdder::SwitchTo() myOldScreen->SwitchTo(); return; } - if (!myScreen->allowsSelection()) + auto hs = dynamic_cast(myScreen); + if (!hs || !hs->allowsSelection()) return; if (MainHeight < 5) @@ -101,19 +102,14 @@ void SelectedItemsAdder::SwitchTo() w->AddItem("New playlist", 0, playlists_not_active); w->AddSeparator(); - MPD::TagList playlists; - Mpd.GetPlaylists(playlists); + auto playlists = Mpd.GetPlaylists(); std::sort(playlists.begin(), playlists.end(), CaseInsensitiveSorting()); - for (MPD::TagList::iterator it = playlists.begin(); it != playlists.end(); ++it) - { - utf_to_locale(*it); + for (auto it = playlists.begin(); it != playlists.end(); ++it) w->AddItem(*it, 0, playlists_not_active); - } w->AddSeparator(); w->AddItem("Cancel"); myScreen = this; - w->Window::Clear(); } void SelectedItemsAdder::Resize() @@ -161,7 +157,7 @@ void SelectedItemsAdder::EnterPressed() MPD::SongList list; if ((w != itsPlaylistSelector || pos != 0) && pos != w->Size()-1) - myOldScreen->GetSelectedSongs(list); + list = dynamic_cast(*myOldScreen).getSelectedSongs(); if (w == itsPlaylistSelector) { diff --git a/src/server_info.cpp b/src/server_info.cpp index a4d5eb8d..3ecae657 100644 --- a/src/server_info.cpp +++ b/src/server_info.cpp @@ -35,12 +35,8 @@ void ServerInfo::Init() SetDimensions(); w = new Scrollpad((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "MPD server info", Config.main_color, Config.window_border); - Mpd.GetURLHandlers([this](std::string &&handler) { - itsURLHandlers.push_back(handler); - }); - Mpd.GetTagTypes([this](std::string &&tag_type) { - itsTagTypes.push_back(tag_type); - }); + itsURLHandlers = Mpd.GetURLHandlers(); + itsTagTypes = Mpd.GetTagTypes(); isInitialized = 1; } @@ -119,11 +115,11 @@ void ServerInfo::Update() *w << fmtBold << U("Last DB update: ") << fmtBoldEnd << Timestamp(Mpd.DBUpdateTime()) << '\n'; *w << '\n'; *w << fmtBold << U("URL Handlers:") << fmtBoldEnd; - for (MPD::TagList::const_iterator it = itsURLHandlers.begin(); it != itsURLHandlers.end(); ++it) + for (auto it = itsURLHandlers.begin(); it != itsURLHandlers.end(); ++it) *w << (it != itsURLHandlers.begin() ? U(", ") : U(" ")) << *it; *w << U("\n\n"); *w << fmtBold << U("Tag Types:") << fmtBoldEnd; - for (MPD::TagList::const_iterator it = itsTagTypes.begin(); it != itsTagTypes.end(); ++it) + for (auto it = itsTagTypes.begin(); it != itsTagTypes.end(); ++it) *w << (it != itsTagTypes.begin() ? U(", ") : U(" ")) << *it; w->Flush(); diff --git a/src/server_info.h b/src/server_info.h index 00a25d6b..b65c5f21 100644 --- a/src/server_info.h +++ b/src/server_info.h @@ -49,8 +49,8 @@ class ServerInfo : public Screen private: void SetDimensions(); - MPD::TagList itsURLHandlers; - MPD::TagList itsTagTypes; + MPD::StringList itsURLHandlers; + MPD::StringList itsTagTypes; size_t itsWidth; size_t itsHeight; diff --git a/src/song.cpp b/src/song.cpp index a0e864e5..1c2c2e09 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -30,9 +30,9 @@ namespace {// -unsigned calc_hash(const char* s, unsigned seed = 0) +size_t calc_hash(const char* s, unsigned seed = 0) { - unsigned hash = seed; + size_t hash = seed; while (*s) hash = hash * 101 + *s++; return hash; diff --git a/src/song.h b/src/song.h index f8a2241b..b23fe584 100644 --- a/src/song.h +++ b/src/song.h @@ -82,7 +82,7 @@ struct Song const std::string &escape_chars) const; std::shared_ptr m_song; - unsigned m_hash; + size_t m_hash; }; } diff --git a/src/song_info.cpp b/src/song_info.cpp index b065b157..f7f5625b 100644 --- a/src/song_info.cpp +++ b/src/song_info.cpp @@ -78,8 +78,10 @@ void SongInfo::SwitchTo() if (myLockedScreen) UpdateInactiveScreen(this); - MPD::Song *s = myScreen->CurrentSong(); - + auto hs = dynamic_cast(myScreen); + if (!hs) + return; + auto s = hs->currentSong(); if (!s) return; diff --git a/src/status.cpp b/src/status.cpp index 0847c9a0..51256eb9 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -236,19 +236,21 @@ void NcmpcppStatusChanged(MPD::Connection *, MPD::StatusChanges changed, void *) if (playlist_length < myPlaylist->Items->Size()) myPlaylist->Items->ResizeList(playlist_length); - Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID(), [](MPD::Song &&s) { - int pos = s.getPosition(); - if (pos < int(myPlaylist->Items->Size())) + auto songs = Mpd.GetPlaylistChanges(Mpd.GetOldPlaylistID()); + for (auto s = songs.begin(); s != songs.end(); ++s) + { + size_t pos = s->getPosition(); + if (pos < myPlaylist->Items->Size()) { // if song's already in playlist, replace it with a new one - myPlaylist->Items->at(pos).value() = s; + myPlaylist->Items->at(pos).value() = *s; } else { // otherwise just add it to playlist - myPlaylist->Items->AddItem(s); + myPlaylist->Items->AddItem(*s); } - }); + } if (is_filtered) { diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index fa2cd43e..43309fcd 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -259,32 +259,28 @@ void TagEditor::Update() { LeftColumn->Window::Clear(); Tags->Clear(); - MPD::TagList list; if (Config.albums_in_tag_editor) { *Albums << XY(0, 0) << "Fetching albums..."; Albums->Window::Refresh(); - Mpd.BlockIdle(1); // for the same reason as in media library - Mpd.GetList(list, MPD_TAG_ALBUM); - for (MPD::TagList::const_iterator it = list.begin(); it != list.end(); ++it) + Mpd.BlockIdle(true); // for the same reason as in media library + auto albums = Mpd.GetList(MPD_TAG_ALBUM); + for (auto album = albums.begin(); album != albums.end(); ++album) { - MPD::SongList l; Mpd.StartSearch(1); - Mpd.AddSearch(MPD_TAG_ALBUM, *it); - Mpd.CommitSearchSongs([&l](MPD::Song &&s) { - l.push_back(s); - }); - if (!l.empty()) - Albums->AddItem(std::make_pair(l[0].toString(Config.tag_editor_album_format), *it)); + Mpd.AddSearch(MPD_TAG_ALBUM, *album); + auto songs = Mpd.CommitSearchSongs(); + if (!songs.empty()) + Albums->AddItem(std::make_pair(songs[0].toString(Config.tag_editor_album_format), *album)); } - Mpd.BlockIdle(0); + Mpd.BlockIdle(false); std::sort(Albums->BeginV(), Albums->EndV(), CaseInsensitiveSorting()); } else { int highlightme = -1; - Mpd.GetDirectories(itsBrowsedDir, list); - sort(list.begin(), list.end(), CaseInsensitiveSorting()); + auto dirs = Mpd.GetDirectories(itsBrowsedDir); + std::sort(dirs.begin(), dirs.end(), CaseInsensitiveSorting()); if (itsBrowsedDir != "/") { size_t slash = itsBrowsedDir.rfind("/"); @@ -292,16 +288,13 @@ void TagEditor::Update() Dirs->AddItem(make_pair("..", parent)); } else - { Dirs->AddItem(std::make_pair(".", "/")); - } - for (MPD::TagList::const_iterator it = list.begin(); it != list.end(); ++it) + for (auto dir = dirs.begin(); dir != dirs.end(); ++dir) { - size_t slash = it->rfind("/"); - std::string to_display = slash != std::string::npos ? it->substr(slash+1) : *it; - utf_to_locale(to_display); - Dirs->AddItem(make_pair(to_display, *it)); - if (*it == itsHighlightedDir) + size_t slash = dir->rfind("/"); + std::string to_display = slash != std::string::npos ? dir->substr(slash+1) : *dir; + Dirs->AddItem(make_pair(to_display, *dir)); + if (*dir == itsHighlightedDir) highlightme = Dirs->Size()-1; } if (highlightme != -1) @@ -314,29 +307,25 @@ void TagEditor::Update() if (Tags->ReallyEmpty()) { Tags->Reset(); - MPD::SongList list; if (Config.albums_in_tag_editor) { if (!Albums->Empty()) { Mpd.StartSearch(1); Mpd.AddSearch(MPD_TAG_ALBUM, Albums->Current().value().second); - Mpd.CommitSearchSongs([&list](MPD::Song &&s) { - list.push_back(s); - }); - std::sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (auto it = list.begin(); it != list.end(); ++it) - Tags->AddItem(*it); + auto albums = Mpd.CommitSearchSongs(); + std::sort(albums.begin(), albums.end(), CaseInsensitiveSorting()); + for (auto album = albums.begin(); album != albums.end(); ++album) + Tags->AddItem(*album); } } else { - Mpd.GetSongs(Dirs->Current().value().second, list); - std::sort(list.begin(), list.end(), CaseInsensitiveSorting()); - for (auto it = list.begin(); it != list.end(); ++it) - Tags->AddItem(*it); + auto songs = Mpd.GetSongs(Dirs->Current().value().second); + std::sort(songs.begin(), songs.end(), CaseInsensitiveSorting()); + for (auto s = songs.begin(); s != songs.end(); ++s) + Tags->AddItem(*s); } - Tags->Window::Clear(); Tags->Refresh(); } @@ -357,9 +346,8 @@ void TagEditor::EnterPressed() if (w == Dirs) { - MPD::TagList test; - Mpd.GetDirectories(LeftColumn->Current().value().second, test); - if (!test.empty()) + auto dirs = Mpd.GetDirectories(LeftColumn->Current().value().second); + if (!dirs.empty()) { itsHighlightedDir = itsBrowsedDir; itsBrowsedDir = LeftColumn->Current().value().second; @@ -659,7 +647,7 @@ void TagEditor::EnterPressed() w->Refresh(); w = LeftColumn; LeftColumn->HighlightColor(Config.active_column_color); - Mpd.UpdateDirectory(getSharedDirectory(Tags)); + Mpd.UpdateDirectory(getSharedDirectory(Tags->BeginV(), Tags->EndV())); } else Tags->Clear(); @@ -777,23 +765,6 @@ void TagEditor::MouseButtonPressed(MEVENT me) } } -MPD::Song *TagEditor::CurrentSong() -{ - return w == Tags && !Tags->Empty() ? &Tags->Current().value() : 0; -} - -void TagEditor::GetSelectedSongs(MPD::SongList &v) -{ - if (w != Tags || Tags->Empty()) - return; - std::vector selected; - Tags->GetSelected(selected); - if (selected.empty()) - selected.push_back(Tags->Choice()); - for (auto it = selected.begin(); it != selected.end(); ++it) - v.push_back(static_cast((*Tags)[*it].value())); -} - /***********************************************************************/ std::string TagEditor::currentFilter() @@ -877,6 +848,56 @@ void TagEditor::prevFound(bool wrap) /***********************************************************************/ +MPD::Song *TagEditor::getSong(size_t pos) +{ + MPD::Song *ptr = 0; + if (w == Tags) + ptr = &(*Tags)[pos].value(); + return ptr; +} + +MPD::Song *TagEditor::currentSong() +{ + if (w == Tags && !Tags->Empty()) + return getSong(Tags->Choice()); + else + return 0; +} + +bool TagEditor::allowsSelection() +{ + return w == Tags; +} + +void TagEditor::removeSelection() +{ + if (w == Tags) + removeSelectionHelper(Tags->Begin(), Tags->End()); +} + +void TagEditor::reverseSelection() +{ + if (w == Tags) + reverseSelectionHelper(Tags->Begin(), Tags->End()); +} + +MPD::SongList TagEditor::getSelectedSongs() +{ + MPD::SongList result; + if (w == Tags) + { + for (auto it = Tags->Begin(); it != Tags->End(); ++it) + if (it->isSelected()) + result.push_back(it->value()); + // if no song was selected, add current one + if (result.empty() && !Tags->Empty()) + result.push_back(Tags->Current().value()); + } + return result; +} + +/***********************************************************************/ + List *TagEditor::GetList() { if (w == LeftColumn) diff --git a/src/tag_editor.h b/src/tag_editor.h index 2e9d26e7..af89dff1 100644 --- a/src/tag_editor.h +++ b/src/tag_editor.h @@ -37,7 +37,7 @@ #include "regex_filter.h" #include "screen.h" -class TagEditor : public Screen, public Filterable, public Searchable +class TagEditor : public Screen, public Filterable, public HasSongs, public Searchable { public: TagEditor() : FParser(0), FParserHelper(0), FParserLegend(0), FParserPreview(0), itsBrowsedDir("/") { } @@ -55,13 +55,6 @@ class TagEditor : public Screen, public Filterable, public Searchable virtual void MouseButtonPressed(MEVENT); virtual bool isTabbable() { return true; } - virtual MPD::Song *CurrentSong(); - virtual MPD::Song *GetSong(size_t pos) { return w == Tags ? &Tags->at(pos).value() : 0; } - - virtual bool allowsSelection() { return w == Tags; } - virtual void ReverseSelection() { Tags->ReverseSelection(); } - virtual void GetSelectedSongs(MPD::SongList &); - /// Filterable implementation virtual std::string currentFilter(); virtual void applyFilter(const std::string &filter); @@ -71,6 +64,15 @@ class TagEditor : public Screen, public Filterable, public Searchable virtual void nextFound(bool wrap); virtual void prevFound(bool wrap); + /// HasSongs implementation + virtual MPD::Song *getSong(size_t pos); + virtual MPD::Song *currentSong(); + + virtual bool allowsSelection(); + virtual void reverseSelection(); + virtual void removeSelection(); + virtual MPD::SongList getSelectedSongs(); + virtual List *GetList(); virtual bool isMergable() { return true; } diff --git a/src/visualizer.cpp b/src/visualizer.cpp index 52612cd5..4124b434 100644 --- a/src/visualizer.cpp +++ b/src/visualizer.cpp @@ -237,11 +237,10 @@ void Visualizer::FindOutputID() if (!Config.visualizer_output_name.empty()) { size_t i = 0; - Mpd.GetOutputs([this, &i](MPD::Output &&o) { - if (o.name() == Config.visualizer_output_name) + auto outputs = Mpd.GetOutputs(); + for (auto o = outputs.begin(); o != outputs.end(); ++o, ++i) + if (o->name() == Config.visualizer_output_name) itsOutputID = i; - ++i; - }); if (itsOutputID == -1) ShowMessage("There is no output named \"%s\"", Config.visualizer_output_name.c_str()); }