remove filtering
This commit is contained in:
@@ -142,7 +142,6 @@
|
||||
## The following actions are not bound to any key/command:
|
||||
##
|
||||
## - set_volume
|
||||
## - filter_playlist_on_priorities
|
||||
##
|
||||
#
|
||||
#def_key "mouse"
|
||||
@@ -352,9 +351,6 @@
|
||||
#def_key "ctrl_r"
|
||||
# reverse_playlist
|
||||
#
|
||||
#def_key "ctrl_f"
|
||||
# apply_filter
|
||||
#
|
||||
#def_key "/"
|
||||
# find
|
||||
#
|
||||
|
||||
166
src/actions.cpp
166
src/actions.cpp
@@ -800,35 +800,24 @@ void SavePlaylist::run()
|
||||
Statusbar::put() << "Save playlist as: ";
|
||||
playlist_name = wFooter->prompt();
|
||||
}
|
||||
if (myPlaylist->main().isFiltered())
|
||||
try
|
||||
{
|
||||
Mpd.StartCommandsList();
|
||||
for (const auto &item : myPlaylist->main())
|
||||
Mpd.AddToPlaylist(playlist_name, item.value());
|
||||
Mpd.CommitCommandsList();
|
||||
Statusbar::printf("Filtered items added to playlist \"%1%\"", playlist_name);
|
||||
Mpd.SavePlaylist(playlist_name);
|
||||
Statusbar::printf("Playlist saved as \"%1%\"", playlist_name);
|
||||
}
|
||||
else
|
||||
catch (MPD::ServerError &e)
|
||||
{
|
||||
try
|
||||
if (e.code() == MPD_SERVER_ERROR_EXIST)
|
||||
{
|
||||
confirmAction(
|
||||
boost::format("Playlist \"%1%\" already exists, overwrite?") % playlist_name
|
||||
);
|
||||
Mpd.DeletePlaylist(playlist_name);
|
||||
Mpd.SavePlaylist(playlist_name);
|
||||
Statusbar::printf("Playlist saved as \"%1%\"", playlist_name);
|
||||
}
|
||||
catch (MPD::ServerError &e)
|
||||
{
|
||||
if (e.code() == MPD_SERVER_ERROR_EXIST)
|
||||
{
|
||||
confirmAction(
|
||||
boost::format("Playlist \"%1%\" already exists, overwrite?") % playlist_name
|
||||
);
|
||||
Mpd.DeletePlaylist(playlist_name);
|
||||
Mpd.SavePlaylist(playlist_name);
|
||||
Statusbar::print("Playlist overwritten");
|
||||
}
|
||||
else
|
||||
throw e;
|
||||
Statusbar::print("Playlist overwritten");
|
||||
}
|
||||
else
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,11 +876,9 @@ void MoveSortOrderDown::run()
|
||||
bool MoveSelectedItemsUp::canBeRun() const
|
||||
{
|
||||
return ((myScreen == myPlaylist
|
||||
&& !myPlaylist->main().empty()
|
||||
&& !myPlaylist->isFiltered())
|
||||
&& !myPlaylist->main().empty())
|
||||
|| (myScreen->isActiveWindow(myPlaylistEditor->Content)
|
||||
&& !myPlaylistEditor->Content.empty()
|
||||
&& !myPlaylistEditor->isContentFiltered()));
|
||||
&& !myPlaylistEditor->Content.empty()));
|
||||
}
|
||||
|
||||
void MoveSelectedItemsUp::run()
|
||||
@@ -912,11 +899,9 @@ void MoveSelectedItemsUp::run()
|
||||
bool MoveSelectedItemsDown::canBeRun() const
|
||||
{
|
||||
return ((myScreen == myPlaylist
|
||||
&& !myPlaylist->main().empty()
|
||||
&& !myPlaylist->isFiltered())
|
||||
&& !myPlaylist->main().empty())
|
||||
|| (myScreen->isActiveWindow(myPlaylistEditor->Content)
|
||||
&& !myPlaylistEditor->Content.empty()
|
||||
&& !myPlaylistEditor->isContentFiltered()));
|
||||
&& !myPlaylistEditor->Content.empty()));
|
||||
}
|
||||
|
||||
void MoveSelectedItemsDown::run()
|
||||
@@ -1154,7 +1139,7 @@ void TogglePlayingSongCentering::run()
|
||||
Statusbar::printf("Centering playing song: %1%",
|
||||
Config.autocenter_mode ? "on" : "off"
|
||||
);
|
||||
if (Config.autocenter_mode && !myPlaylist->main().isFiltered())
|
||||
if (Config.autocenter_mode)
|
||||
{
|
||||
auto s = myPlaylist->nowPlayingSong();
|
||||
if (!s.empty())
|
||||
@@ -1176,9 +1161,9 @@ void UpdateDatabase::run()
|
||||
|
||||
bool JumpToPlayingSong::canBeRun() const
|
||||
{
|
||||
return (myScreen == myPlaylist && !myPlaylist->isFiltered())
|
||||
|| myScreen == myBrowser
|
||||
|| myScreen == myLibrary;
|
||||
return myScreen == myPlaylist
|
||||
|| myScreen == myBrowser
|
||||
|| myScreen == myLibrary;
|
||||
}
|
||||
|
||||
void JumpToPlayingSong::run()
|
||||
@@ -1791,11 +1776,8 @@ void ClearMainPlaylist::run()
|
||||
{
|
||||
if (Config.ask_before_clearing_playlists)
|
||||
confirmAction("Do you really want to clear main playlist?");
|
||||
auto delete_fun = boost::bind(&MPD::Connection::Delete, _1, _2);
|
||||
auto clear_fun = boost::bind(&MPD::Connection::ClearMainPlaylist, _1);
|
||||
Statusbar::printf("Deleting items...");
|
||||
clearPlaylist(myPlaylist->main(), delete_fun, clear_fun);
|
||||
Statusbar::printf("Items deleted");
|
||||
Mpd.ClearMainPlaylist();
|
||||
Statusbar::print("Playlist cleared");
|
||||
myPlaylist->main().reset();
|
||||
}
|
||||
|
||||
@@ -1811,11 +1793,8 @@ void ClearPlaylist::run()
|
||||
std::string playlist = myPlaylistEditor->Playlists.current()->value().path();
|
||||
if (Config.ask_before_clearing_playlists)
|
||||
confirmAction(boost::format("Do you really want to clear playlist \"%1%\"?") % playlist);
|
||||
auto delete_fun = boost::bind(&MPD::Connection::PlaylistDelete, _1, playlist, _2);
|
||||
auto clear_fun = boost::bind(&MPD::Connection::ClearPlaylist, _1, playlist);
|
||||
Statusbar::printf("Deleting items from \"%1%\"...", playlist);
|
||||
clearPlaylist(myPlaylistEditor->Content, delete_fun, clear_fun);
|
||||
Statusbar::printf("Items deleted from \"%1%\"", playlist);
|
||||
Mpd.ClearPlaylist(playlist);
|
||||
Statusbar::printf("Playlist \"%1%\" cleared", playlist);
|
||||
}
|
||||
|
||||
bool SortPlaylist::canBeRun() const
|
||||
@@ -1838,62 +1817,6 @@ void ReversePlaylist::run()
|
||||
myPlaylist->Reverse();
|
||||
}
|
||||
|
||||
bool ApplyFilter::canBeRun() const
|
||||
{
|
||||
auto w = dynamic_cast<Filterable *>(myScreen);
|
||||
return w && w->allowsFiltering();
|
||||
}
|
||||
|
||||
void ApplyFilter::run()
|
||||
{
|
||||
using Global::wFooter;
|
||||
|
||||
Filterable *f = dynamic_cast<Filterable *>(myScreen);
|
||||
std::string filter = f->currentFilter();
|
||||
// if filter is already here, apply it
|
||||
if (!filter.empty())
|
||||
{
|
||||
f->applyFilter(filter);
|
||||
myScreen->refreshWindow();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Statusbar::ScopedLock slock;
|
||||
NC::Window::ScopedPromptHook helper(*wFooter,
|
||||
Statusbar::Helpers::ApplyFilterImmediately(f, filter)
|
||||
);
|
||||
Statusbar::put() << NC::Format::Bold << "Apply filter: " << NC::Format::NoBold;
|
||||
wFooter->prompt(filter);
|
||||
}
|
||||
catch (NC::PromptAborted &)
|
||||
{
|
||||
// restore previous filter
|
||||
f->applyFilter(filter);
|
||||
throw;
|
||||
}
|
||||
|
||||
filter = f->currentFilter();
|
||||
if (filter.empty())
|
||||
{
|
||||
myPlaylist->main().clearFilterResults();
|
||||
Statusbar::printf("Filtering disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
// apply filter here so even if old one wasn't modified
|
||||
// (and callback wasn't invoked), it still gets applied.
|
||||
f->applyFilter(filter);
|
||||
Statusbar::printf("Using filter \"%1%\"", filter);
|
||||
}
|
||||
|
||||
// recalculate total length of songs in playlist as it probably changed.
|
||||
// TODO: check where drawHeader is invoked.
|
||||
if (myScreen == myPlaylist)
|
||||
myPlaylist->reloadTotalLength();
|
||||
listsChangeFinisher();
|
||||
}
|
||||
|
||||
bool Find::canBeRun() const
|
||||
{
|
||||
return myScreen == myHelp
|
||||
@@ -2119,15 +2042,13 @@ void ToggleBrowserSortMode::run()
|
||||
Config.browser_sort_mode = SortMode::Name;
|
||||
Statusbar::print("Sort songs by: name");
|
||||
}
|
||||
withUnfilteredMenuReapplyFilter(myBrowser->main(), [] {
|
||||
if (Config.browser_sort_mode != SortMode::NoOp)
|
||||
{
|
||||
size_t sort_offset = myBrowser->inRootDirectory() ? 0 : 1;
|
||||
std::sort(myBrowser->main().begin()+sort_offset, myBrowser->main().end(),
|
||||
LocaleBasedItemSorting(std::locale(), Config.ignore_leading_the, Config.browser_sort_mode)
|
||||
);
|
||||
}
|
||||
});
|
||||
if (Config.browser_sort_mode != SortMode::NoOp)
|
||||
{
|
||||
size_t sort_offset = myBrowser->inRootDirectory() ? 0 : 1;
|
||||
std::sort(myBrowser->main().begin()+sort_offset, myBrowser->main().end(),
|
||||
LocaleBasedItemSorting(std::locale(), Config.ignore_leading_the, Config.browser_sort_mode)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool ToggleLibraryTagType::canBeRun() const
|
||||
@@ -2257,29 +2178,6 @@ void SetVisualizerSampleMultiplier::run()
|
||||
# endif // ENABLE_VISUALIZER
|
||||
}
|
||||
|
||||
bool FilterPlaylistOnPriorities::canBeRun() const
|
||||
{
|
||||
return myScreen == myPlaylist;
|
||||
}
|
||||
|
||||
void FilterPlaylistOnPriorities::run()
|
||||
{
|
||||
using Global::wFooter;
|
||||
|
||||
unsigned prio;
|
||||
{
|
||||
Statusbar::ScopedLock slock;
|
||||
Statusbar::put() << "Show songs with priority higher than: ";
|
||||
prio = fromString<unsigned>(wFooter->prompt());
|
||||
boundsCheck(prio, 0u, 255u);
|
||||
myPlaylist->main().filter(myPlaylist->main().begin(), myPlaylist->main().end(),
|
||||
[prio](const NC::Menu<MPD::Song>::Item &s) {
|
||||
return s.value().getPrio() > prio;
|
||||
});
|
||||
}
|
||||
Statusbar::printf("Playlist filtered (songs with priority higher than %1%)", prio);
|
||||
}
|
||||
|
||||
void ShowSongInfo::run()
|
||||
{
|
||||
mySongInfo->switchTo();
|
||||
@@ -2668,7 +2566,6 @@ void populateActions()
|
||||
insert_action(new Actions::ClearPlaylist());
|
||||
insert_action(new Actions::SortPlaylist());
|
||||
insert_action(new Actions::ReversePlaylist());
|
||||
insert_action(new Actions::ApplyFilter());
|
||||
insert_action(new Actions::Find());
|
||||
insert_action(new Actions::FindItemForward());
|
||||
insert_action(new Actions::FindItemBackward());
|
||||
@@ -2687,7 +2584,6 @@ void populateActions()
|
||||
insert_action(new Actions::RefetchLyrics());
|
||||
insert_action(new Actions::SetSelectedItemsPriority());
|
||||
insert_action(new Actions::SetVisualizerSampleMultiplier());
|
||||
insert_action(new Actions::FilterPlaylistOnPriorities());
|
||||
insert_action(new Actions::ShowSongInfo());
|
||||
insert_action(new Actions::ShowArtistInfo());
|
||||
insert_action(new Actions::ShowLyrics());
|
||||
|
||||
@@ -47,12 +47,12 @@ enum class Type
|
||||
JumpToPlaylistEditor, ToggleScreenLock, JumpToTagEditor, JumpToPositionInSong,
|
||||
ReverseSelection, RemoveSelection, SelectAlbum, AddSelectedItems,
|
||||
CropMainPlaylist, CropPlaylist, ClearMainPlaylist, ClearPlaylist, SortPlaylist,
|
||||
ReversePlaylist, ApplyFilter, Find, FindItemForward, FindItemBackward,
|
||||
ReversePlaylist, Find, FindItemForward, FindItemBackward,
|
||||
NextFoundItem, PreviousFoundItem, ToggleFindMode, ToggleReplayGainMode,
|
||||
ToggleSpaceMode, ToggleAddMode, ToggleMouse, ToggleBitrateVisibility,
|
||||
AddRandomItems, ToggleBrowserSortMode, ToggleLibraryTagType,
|
||||
ToggleMediaLibrarySortMode, RefetchLyrics,
|
||||
SetSelectedItemsPriority, SetVisualizerSampleMultiplier, FilterPlaylistOnPriorities,
|
||||
SetSelectedItemsPriority, SetVisualizerSampleMultiplier,
|
||||
ShowSongInfo, ShowArtistInfo, ShowLyrics, Quit, NextScreen, PreviousScreen,
|
||||
ShowHelp, ShowPlaylist, ShowBrowser, ChangeBrowseMode, ShowSearchEngine,
|
||||
ResetSearchEngine, ShowMediaLibrary, ToggleMediaLibraryColumnsMode,
|
||||
@@ -802,15 +802,6 @@ protected:
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct ApplyFilter : public BaseAction
|
||||
{
|
||||
ApplyFilter() : BaseAction(Type::ApplyFilter, "apply_filter") { }
|
||||
|
||||
protected:
|
||||
virtual bool canBeRun() const;
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct Find : public BaseAction
|
||||
{
|
||||
Find() : BaseAction(Type::Find, "find") { }
|
||||
@@ -969,16 +960,6 @@ protected:
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct FilterPlaylistOnPriorities : public BaseAction
|
||||
{
|
||||
FilterPlaylistOnPriorities()
|
||||
: BaseAction(Type::FilterPlaylistOnPriorities, "filter_playlist_on_priorities") { }
|
||||
|
||||
protected:
|
||||
virtual bool canBeRun() const;
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
struct ShowSongInfo : public BaseAction
|
||||
{
|
||||
ShowSongInfo() : BaseAction(Type::ShowSongInfo, "show_song_info") { }
|
||||
|
||||
@@ -482,8 +482,6 @@ void BindingsConfiguration::generateDefaults()
|
||||
bind(k, Actions::Type::SortPlaylist);
|
||||
if (notBound(k = stringToKey("ctrl_r")))
|
||||
bind(k, Actions::Type::ReversePlaylist);
|
||||
if (notBound(k = stringToKey("ctrl_f")))
|
||||
bind(k, Actions::Type::ApplyFilter);
|
||||
if (notBound(k = stringToKey("/")))
|
||||
{
|
||||
bind(k, Actions::Type::Find);
|
||||
|
||||
@@ -248,37 +248,6 @@ void Browser::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool Browser::allowsFiltering()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Browser::currentFilter()
|
||||
{
|
||||
return RegexFilter<MPD::Item>::currentFilter(w);
|
||||
}
|
||||
|
||||
void Browser::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
w.clearFilter();
|
||||
w.clearFilterResults();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
w.showAll();
|
||||
auto fun = boost::bind(browserEntryMatcher, _1, _2, true);
|
||||
auto rx = RegexFilter<MPD::Item>(
|
||||
boost::regex(filter, Config.regex_type), fun);
|
||||
w.filter(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool Browser::allowsSearching()
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct Browser: Screen<NC::Menu<MPD::Item>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
struct Browser: Screen<NC::Menu<MPD::Item>>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
Browser();
|
||||
|
||||
@@ -45,11 +45,6 @@ struct Browser: Screen<NC::Menu<MPD::Item>>, Filterable, HasSongs, Searchable, T
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
|
||||
@@ -96,7 +96,7 @@ void setProperties(NC::Menu<T> &menu, const MPD::Song &s, const ProxySongList &p
|
||||
is_selected = menu.drawn()->isSelected();
|
||||
discard_colors = Config.discard_colors_if_item_is_selected && is_selected;
|
||||
|
||||
int song_pos = menu.isFiltered() ? s.getPosition() : drawn_pos;
|
||||
int song_pos = drawn_pos;
|
||||
is_now_playing = Status::State::player() != MPD::psStop && myPlaylist->isActiveWindow(menu)
|
||||
&& song_pos == Status::State::currentSongPosition();
|
||||
if (is_now_playing)
|
||||
|
||||
@@ -245,7 +245,6 @@ void write_bindings(NC::Scrollpad &w)
|
||||
key(w, Type::UpdateDatabase, "Start music database update");
|
||||
w << '\n';
|
||||
key(w, Type::ExecuteCommand, "Execute command");
|
||||
key(w, Type::ApplyFilter, "Apply filter");
|
||||
key(w, Type::FindItemForward, "Find item forward");
|
||||
key(w, Type::FindItemBackward, "Find item backward");
|
||||
key(w, Type::PreviousFoundItem, "Jump to previous found item");
|
||||
@@ -289,7 +288,6 @@ void write_bindings(NC::Scrollpad &w)
|
||||
key(w, Type::SavePlaylist, "Save playlist");
|
||||
key(w, Type::SortPlaylist, "Sort playlist");
|
||||
key(w, Type::ReversePlaylist, "Reverse playlist");
|
||||
key(w, Type::FilterPlaylistOnPriorities, "Filter playlist on priorities");
|
||||
key(w, Type::JumpToPlayingSong, "Jump to current song");
|
||||
key(w, Type::TogglePlayingSongCentering, "Toggle playing song centering");
|
||||
|
||||
|
||||
170
src/helpers.h
170
src/helpers.h
@@ -61,7 +61,7 @@ void searchBackward(NC::Menu<ItemT> &m, const PredicateT &pred, bool wrap)
|
||||
return;
|
||||
auto it = wrappedSearch(m.rbegin(), m.rcurrent(), m.rend(), pred, wrap);
|
||||
if (it != m.rend())
|
||||
m.highlight(m.size()-1-(it-m.rbegin()));
|
||||
m.highlight(it.base()-m.begin()-1);
|
||||
}
|
||||
|
||||
inline HasColumns *hasColumns(BaseScreen *screen)
|
||||
@@ -149,54 +149,6 @@ void reverseSelectionHelper(Iterator first, Iterator last)
|
||||
first->setSelected(!first->isSelected());
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void withUnfilteredMenu(NC::Menu<T> &m, F action)
|
||||
{
|
||||
bool is_filtered = m.isFiltered();
|
||||
auto cleanup = [&]() {
|
||||
if (is_filtered)
|
||||
m.showFiltered();
|
||||
};
|
||||
m.showAll();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cleanup();
|
||||
throw;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
void withUnfilteredMenuReapplyFilter(NC::Menu<T> &m, F action)
|
||||
{
|
||||
auto cleanup = [&]() {
|
||||
if (m.getFilter())
|
||||
{
|
||||
m.applyCurrentFilter(m.begin(), m.end());
|
||||
if (m.empty())
|
||||
{
|
||||
m.clearFilter();
|
||||
m.clearFilterResults();
|
||||
}
|
||||
}
|
||||
};
|
||||
m.showAll();
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
cleanup();
|
||||
throw;
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void moveSelectedItemsUp(NC::Menu<MPD::Song> &m, F swap_fun)
|
||||
{
|
||||
@@ -264,53 +216,52 @@ void moveSelectedItemsDown(NC::Menu<MPD::Song> &m, F swap_fun)
|
||||
template <typename F>
|
||||
void moveSelectedItemsTo(NC::Menu<MPD::Song> &m, F move_fun)
|
||||
{
|
||||
// FIXME: make it not look like shit
|
||||
auto cur_ptr = &m.current()->value();
|
||||
withUnfilteredMenu(m, [&]() {
|
||||
// this is kinda shitty, but there is no other way to know
|
||||
// what position current item has in unfiltered menu.
|
||||
ptrdiff_t pos = 0;
|
||||
for (auto it = m.begin(); it != m.end(); ++it, ++pos)
|
||||
if (&it->value() == cur_ptr)
|
||||
break;
|
||||
auto begin = m.begin();
|
||||
auto list = getSelected(m.begin(), m.end());
|
||||
// we move only truly selected items
|
||||
if (list.empty())
|
||||
return;
|
||||
// we can't move to the middle of selected items
|
||||
//(this also handles case when list.size() == 1)
|
||||
if (pos >= (list.front() - begin) && pos <= (list.back() - begin))
|
||||
return;
|
||||
int diff = pos - (list.front() - begin);
|
||||
Mpd.StartCommandsList();
|
||||
if (diff > 0) // move down
|
||||
// this is kinda shitty, but there is no other way to know
|
||||
// what position current item has in unfiltered menu.
|
||||
ptrdiff_t pos = 0;
|
||||
for (auto it = m.begin(); it != m.end(); ++it, ++pos)
|
||||
if (&it->value() == cur_ptr)
|
||||
break;
|
||||
auto begin = m.begin();
|
||||
auto list = getSelected(m.begin(), m.end());
|
||||
// we move only truly selected items
|
||||
if (list.empty())
|
||||
return;
|
||||
// we can't move to the middle of selected items
|
||||
//(this also handles case when list.size() == 1)
|
||||
if (pos >= (list.front() - begin) && pos <= (list.back() - begin))
|
||||
return;
|
||||
int diff = pos - (list.front() - begin);
|
||||
Mpd.StartCommandsList();
|
||||
if (diff > 0) // move down
|
||||
{
|
||||
pos -= list.size();
|
||||
size_t i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
move_fun(&Mpd, *it - begin, pos+i);
|
||||
Mpd.CommitCommandsList();
|
||||
i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
{
|
||||
pos -= list.size();
|
||||
size_t i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
move_fun(&Mpd, *it - begin, pos+i);
|
||||
Mpd.CommitCommandsList();
|
||||
i = list.size()-1;
|
||||
for (auto it = list.rbegin(); it != list.rend(); ++it, --i)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
else if (diff < 0) // move up
|
||||
}
|
||||
else if (diff < 0) // move up
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
move_fun(&Mpd, *it - begin, pos+i);
|
||||
Mpd.CommitCommandsList();
|
||||
i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
{
|
||||
size_t i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
move_fun(&Mpd, *it - begin, pos+i);
|
||||
Mpd.CommitCommandsList();
|
||||
i = 0;
|
||||
for (auto it = list.begin(); it != list.end(); ++it, ++i)
|
||||
{
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
(*it)->setSelected(false);
|
||||
m[pos+i].setSelected(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
@@ -322,28 +273,14 @@ void deleteSelectedSongs(NC::Menu<MPD::Song> &m, F delete_fun)
|
||||
// ignore all songs that are not filtered. we use the fact
|
||||
// that both ranges share the same values, ie. we can compare
|
||||
// pointers to check whether an item belongs to filtered range.
|
||||
NC::Menu<MPD::Song>::Iterator begin;
|
||||
NC::Menu<MPD::Song>::ReverseIterator real_begin, real_end;
|
||||
withUnfilteredMenu(m, [&]() {
|
||||
// obtain iterators for unfiltered range
|
||||
begin = m.begin() + 1; // cancel reverse iterator's offset
|
||||
real_begin = m.rbegin();
|
||||
real_end = m.rend();
|
||||
});
|
||||
// get iterator to filtered range
|
||||
auto cur_filtered = m.rbegin();
|
||||
auto begin = ++m.begin();
|
||||
Mpd.StartCommandsList();
|
||||
for (auto it = real_begin; it != real_end; ++it)
|
||||
for (auto it = m.rbegin(); it != m.rend(); ++it)
|
||||
{
|
||||
// current iterator belongs to filtered range, proceed
|
||||
if (&*it == &*cur_filtered)
|
||||
if (it->isSelected())
|
||||
{
|
||||
if (it->isSelected())
|
||||
{
|
||||
it->setSelected(false);
|
||||
delete_fun(Mpd, it.base() - begin);
|
||||
}
|
||||
++cur_filtered;
|
||||
it->setSelected(false);
|
||||
delete_fun(Mpd, it.base() - begin);
|
||||
}
|
||||
}
|
||||
Mpd.CommitCommandsList();
|
||||
@@ -356,19 +293,6 @@ void cropPlaylist(NC::Menu<MPD::Song> &m, F delete_fun)
|
||||
deleteSelectedSongs(m, delete_fun);
|
||||
}
|
||||
|
||||
template <typename F, typename G>
|
||||
void clearPlaylist(NC::Menu<MPD::Song> &m, F delete_fun, G clear_fun)
|
||||
{
|
||||
if (m.isFiltered())
|
||||
{
|
||||
for (auto it = m.begin(); it != m.end(); ++it)
|
||||
it->setSelected(true);
|
||||
deleteSelectedSongs(m, delete_fun);
|
||||
}
|
||||
else
|
||||
clear_fun(Mpd);
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
std::function<void (ItemT)> vectorMoveInserter(std::vector<ItemT> &v)
|
||||
{
|
||||
|
||||
@@ -27,13 +27,6 @@
|
||||
#include "song.h"
|
||||
#include "proxy_song_list.h"
|
||||
|
||||
struct Filterable
|
||||
{
|
||||
virtual bool allowsFiltering() = 0;
|
||||
virtual std::string currentFilter() = 0;
|
||||
virtual void applyFilter(const std::string &filter) = 0;
|
||||
};
|
||||
|
||||
struct Searchable
|
||||
{
|
||||
virtual bool allowsSearching() = 0;
|
||||
|
||||
@@ -253,49 +253,48 @@ void MediaLibrary::update()
|
||||
{
|
||||
if (hasTwoColumns)
|
||||
{
|
||||
if (Albums.reallyEmpty() || m_albums_update_request)
|
||||
if (Albums.empty() || m_albums_update_request)
|
||||
{
|
||||
m_albums_update_request = false;
|
||||
std::map<std::tuple<std::string, std::string, std::string>, time_t> albums;
|
||||
for (MPD::SongIterator s = Mpd.GetDirectoryRecursive("/"), end; s != end; ++s)
|
||||
{
|
||||
std::string tag;
|
||||
unsigned idx = 0;
|
||||
std::string tag = s->get(Config.media_lib_primary_tag, idx);
|
||||
do
|
||||
while (!(tag = s->get(Config.media_lib_primary_tag, idx++)).empty())
|
||||
{
|
||||
auto key = std::make_tuple(tag, s->getAlbum(), s->getDate());
|
||||
auto key = std::make_tuple(std::move(tag), s->getAlbum(), s->getDate());
|
||||
auto it = albums.find(key);
|
||||
if (it == albums.end())
|
||||
albums[key] = s->getMTime();
|
||||
albums[std::move(key)] = s->getMTime();
|
||||
else
|
||||
it->second = s->getMTime();
|
||||
}
|
||||
while (!(tag = s->get(Config.media_lib_primary_tag, ++idx)).empty());
|
||||
}
|
||||
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);
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (const auto &album : albums)
|
||||
{
|
||||
auto entry = AlbumEntry(Album(
|
||||
std::move(std::get<0>(album.first)),
|
||||
std::move(std::get<1>(album.first)),
|
||||
std::move(std::get<2>(album.first)),
|
||||
album.second)
|
||||
);
|
||||
if (idx < Albums.size())
|
||||
Albums.resizeList(idx);
|
||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||
});
|
||||
Albums[idx].value() = std::move(entry);
|
||||
else
|
||||
Albums.addItem(std::move(entry));
|
||||
++idx;
|
||||
}
|
||||
if (idx < Albums.size())
|
||||
Albums.resizeList(idx);
|
||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||
Albums.refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Tags.reallyEmpty() || m_tags_update_request)
|
||||
if (Tags.empty() || m_tags_update_request)
|
||||
{
|
||||
m_tags_update_request = false;
|
||||
std::map<std::string, time_t> tags;
|
||||
@@ -303,17 +302,16 @@ void MediaLibrary::update()
|
||||
{
|
||||
for (MPD::SongIterator s = Mpd.GetDirectoryRecursive("/"), end; s != end; ++s)
|
||||
{
|
||||
std::string tag;
|
||||
unsigned idx = 0;
|
||||
std::string tag = s->get(Config.media_lib_primary_tag, idx);
|
||||
do
|
||||
while (!(tag = s->get(Config.media_lib_primary_tag, idx++)).empty())
|
||||
{
|
||||
auto it = tags.find(tag);
|
||||
if (it == tags.end())
|
||||
tags[tag] = s->getMTime();
|
||||
tags[std::move(tag)] = s->getMTime();
|
||||
else
|
||||
it->second = std::max(it->second, s->getMTime());
|
||||
}
|
||||
while (!(tag = s->get(Config.media_lib_primary_tag, ++idx)).empty());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -322,25 +320,24 @@ void MediaLibrary::update()
|
||||
for (; tag != end; ++tag)
|
||||
tags[std::move(*tag)] = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (const auto &tag : tags)
|
||||
{
|
||||
auto ptag = PrimaryTag(std::move(tag.first), tag.second);
|
||||
if (idx < Tags.size())
|
||||
Tags.resizeList(idx);
|
||||
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
||||
});
|
||||
Tags[idx].value() = std::move(ptag);
|
||||
else
|
||||
Tags.addItem(std::move(ptag));
|
||||
++idx;
|
||||
}
|
||||
if (idx < Tags.size())
|
||||
Tags.resizeList(idx);
|
||||
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
||||
Tags.refresh();
|
||||
}
|
||||
|
||||
if (!Tags.empty()
|
||||
&& ((Albums.reallyEmpty() && Global::Timer - m_timer > m_fetching_delay) || m_albums_update_request)
|
||||
&& ((Albums.empty() && Global::Timer - m_timer > m_fetching_delay) || m_albums_update_request)
|
||||
)
|
||||
{
|
||||
m_albums_update_request = false;
|
||||
@@ -353,42 +350,42 @@ void MediaLibrary::update()
|
||||
auto key = std::make_tuple(s->getAlbum(), s->getDate());
|
||||
auto it = albums.find(key);
|
||||
if (it == albums.end())
|
||||
albums[key] = s->getMTime();
|
||||
albums[std::move(key)] = s->getMTime();
|
||||
else
|
||||
it->second = s->getMTime();
|
||||
it->second = std::max(it->second, s->getMTime());
|
||||
};
|
||||
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);
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (const auto &album : albums)
|
||||
{
|
||||
auto entry = AlbumEntry(Album(
|
||||
primary_tag,
|
||||
std::move(std::get<0>(album.first)),
|
||||
std::move(std::get<1>(album.first)),
|
||||
album.second)
|
||||
);
|
||||
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[idx].value() = std::move(entry);
|
||||
Albums[idx].setSeparator(false);
|
||||
}
|
||||
});
|
||||
else
|
||||
Albums.addItem(std::move(entry));
|
||||
++idx;
|
||||
}
|
||||
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() && Global::Timer - m_timer > m_fetching_delay) || m_songs_update_request)
|
||||
&& ((Songs.empty() && Global::Timer - m_timer > m_fetching_delay) || m_songs_update_request)
|
||||
)
|
||||
{
|
||||
m_songs_update_request = false;
|
||||
@@ -400,30 +397,28 @@ void MediaLibrary::update()
|
||||
Mpd.AddSearch(MPD_TAG_ALBUM, album.entry().album());
|
||||
Mpd.AddSearch(MPD_TAG_DATE, album.entry().date());
|
||||
}
|
||||
withUnfilteredMenuReapplyFilter(Songs, [this, &album]() {
|
||||
size_t idx = 0;
|
||||
for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_playlist = myPlaylist->checkForSong(*s);
|
||||
if (idx < Songs.size())
|
||||
{
|
||||
Songs[idx].value() = std::move(*s);
|
||||
Songs[idx].setBold(is_playlist);
|
||||
}
|
||||
else
|
||||
Songs.addItem(std::move(*s), is_playlist);
|
||||
};
|
||||
size_t idx = 0;
|
||||
for (MPD::SongIterator s = Mpd.CommitSearchSongs(), end; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_playlist = myPlaylist->checkForSong(*s);
|
||||
if (idx < Songs.size())
|
||||
Songs.resizeList(idx);
|
||||
std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry()));
|
||||
});
|
||||
{
|
||||
Songs[idx].value() = std::move(*s);
|
||||
Songs[idx].setBold(is_playlist);
|
||||
}
|
||||
else
|
||||
Songs.addItem(std::move(*s), is_playlist);
|
||||
};
|
||||
if (idx < Songs.size())
|
||||
Songs.resizeList(idx);
|
||||
std::sort(Songs.begin(), Songs.end(), SortSongs(!album.isAllTracksEntry()));
|
||||
Songs.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
int MediaLibrary::windowTimeout()
|
||||
{
|
||||
if (Albums.reallyEmpty() || Songs.reallyEmpty())
|
||||
if (Albums.empty() || Songs.empty())
|
||||
return m_window_timeout;
|
||||
else
|
||||
return Screen<WindowType>::windowTimeout();
|
||||
@@ -562,74 +557,6 @@ void MediaLibrary::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool MediaLibrary::allowsFiltering()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MediaLibrary::currentFilter()
|
||||
{
|
||||
std::string filter;
|
||||
if (isActiveWindow(Tags))
|
||||
filter = RegexFilter<PrimaryTag>::currentFilter(Tags);
|
||||
else if (isActiveWindow(Albums))
|
||||
filter = RegexItemFilter<AlbumEntry>::currentFilter(Albums);
|
||||
else if (isActiveWindow(Songs))
|
||||
filter = RegexFilter<MPD::Song>::currentFilter(Songs);
|
||||
return filter;
|
||||
}
|
||||
|
||||
void MediaLibrary::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
{
|
||||
Tags.clearFilter();
|
||||
Tags.clearFilterResults();
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
Albums.clearFilter();
|
||||
Albums.clearFilterResults();
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
Songs.clearFilter();
|
||||
Songs.clearFilterResults();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
{
|
||||
Tags.showAll();
|
||||
auto rx = RegexFilter<PrimaryTag>(
|
||||
boost::regex(filter, Config.regex_type), TagEntryMatcher);
|
||||
Tags.filter(Tags.begin(), Tags.end(), rx);
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
Albums.showAll();
|
||||
auto fun = boost::bind(AlbumEntryMatcher, _1, _2, true);
|
||||
auto rx = RegexItemFilter<AlbumEntry>(
|
||||
boost::regex(filter, Config.regex_type), fun);
|
||||
Albums.filter(Albums.begin(), Albums.end(), rx);
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
Songs.showAll();
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(filter, Config.regex_type), SongEntryMatcher);
|
||||
Songs.filter(Songs.begin(), Songs.end(), rx);
|
||||
}
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool MediaLibrary::allowsSearching()
|
||||
{
|
||||
return true;
|
||||
@@ -780,17 +707,13 @@ std::vector<MPD::Song> MediaLibrary::getSelectedSongs()
|
||||
}
|
||||
// if no item is selected, add songs from right column
|
||||
if (!any_selected && !Albums.empty())
|
||||
{
|
||||
withUnfilteredMenu(Songs, [this, &result]() {
|
||||
result.insert(result.end(), Songs.beginV(), Songs.endV());
|
||||
});
|
||||
}
|
||||
result.insert(result.end(), Songs.beginV(), Songs.endV());
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
for (auto it = Songs.begin(); it != Songs.end(); ++it)
|
||||
if (it->isSelected())
|
||||
result.push_back(it->value());
|
||||
for (const auto &s : Songs)
|
||||
if (s.isSelected())
|
||||
result.push_back(s.value());
|
||||
// if no item is selected, add current one
|
||||
if (result.empty() && !Songs.empty())
|
||||
result.push_back(Songs.current()->value());
|
||||
@@ -805,12 +728,12 @@ bool MediaLibrary::previousColumnAvailable()
|
||||
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
||||
if (isActiveWindow(Songs))
|
||||
{
|
||||
if (!Albums.reallyEmpty() && (hasTwoColumns || !Tags.reallyEmpty()))
|
||||
if (!Albums.empty() && (hasTwoColumns || !Tags.empty()))
|
||||
return true;
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
if (!hasTwoColumns && !Tags.reallyEmpty())
|
||||
if (!hasTwoColumns && !Tags.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -839,12 +762,12 @@ bool MediaLibrary::nextColumnAvailable()
|
||||
assert(!hasTwoColumns || !isActiveWindow(Tags));
|
||||
if (isActiveWindow(Tags))
|
||||
{
|
||||
if (!Albums.reallyEmpty() && !Songs.reallyEmpty())
|
||||
if (!Albums.empty() && !Songs.empty())
|
||||
return true;
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
if (!Songs.reallyEmpty())
|
||||
if (!Songs.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -921,9 +844,7 @@ void MediaLibrary::toggleSortMode()
|
||||
Config.media_library_sort_by_mtime ? "modification time" : "name");
|
||||
if (hasTwoColumns)
|
||||
{
|
||||
withUnfilteredMenuReapplyFilter(Albums, [this]() {
|
||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||
});
|
||||
std::sort(Albums.beginV(), Albums.endV(), SortAlbumEntries());
|
||||
Albums.refresh();
|
||||
Songs.clear();
|
||||
if (Config.titles_visibility)
|
||||
@@ -936,17 +857,14 @@ void MediaLibrary::toggleSortMode()
|
||||
}
|
||||
else
|
||||
{
|
||||
withUnfilteredMenuReapplyFilter(Tags, [this]() {
|
||||
// if we already have modification times,
|
||||
// just resort. otherwise refetch the list.
|
||||
if (!Tags.empty() && Tags[0].value().mtime() > 0)
|
||||
{
|
||||
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
||||
Tags.refresh();
|
||||
}
|
||||
else
|
||||
Tags.clear();
|
||||
});
|
||||
// if we already have modification times, just resort. otherwise refetch the list.
|
||||
if (!Tags.empty() && Tags[0].value().mtime() > 0)
|
||||
{
|
||||
std::sort(Tags.beginV(), Tags.endV(), SortPrimaryTags());
|
||||
Tags.refresh();
|
||||
}
|
||||
else
|
||||
Tags.clear();
|
||||
Albums.clear();
|
||||
Songs.clear();
|
||||
}
|
||||
@@ -973,10 +891,9 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
||||
switchTo();
|
||||
Statusbar::put() << "Jumping to song...";
|
||||
Global::wFooter->refresh();
|
||||
|
||||
// FIXME: use std::find
|
||||
if (!hasTwoColumns)
|
||||
{
|
||||
Tags.showAll();
|
||||
if (Tags.empty())
|
||||
update();
|
||||
if (primary_tag != Tags.current()->value().tag())
|
||||
@@ -994,7 +911,6 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
||||
}
|
||||
}
|
||||
|
||||
Albums.showAll();
|
||||
if (Albums.empty())
|
||||
update();
|
||||
|
||||
@@ -1017,7 +933,6 @@ void MediaLibrary::LocateSong(const MPD::Song &s)
|
||||
}
|
||||
}
|
||||
|
||||
Songs.showAll();
|
||||
if (Songs.empty())
|
||||
update();
|
||||
|
||||
@@ -1064,10 +979,7 @@ void MediaLibrary::AddToPlaylist(bool add_n_play)
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
bool success;
|
||||
withUnfilteredMenu(Songs, [&]() {
|
||||
success = addSongsToPlaylist(Songs.beginV(), Songs.endV(), add_n_play, -1);
|
||||
});
|
||||
bool success = addSongsToPlaylist(Songs.beginV(), Songs.endV(), add_n_play, -1);
|
||||
Statusbar::printf("Songs from album \"%1%\" added%2%",
|
||||
Albums.current()->value().entry().album(), withErrors(success)
|
||||
);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct MediaLibrary: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Searchable, Tabbable
|
||||
struct MediaLibrary: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
MediaLibrary();
|
||||
|
||||
@@ -48,11 +48,6 @@ struct MediaLibrary: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Sea
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
|
||||
187
src/menu.h
187
src/menu.h
@@ -130,13 +130,13 @@ public:
|
||||
|
||||
/// Resizes the list to given size (adequate to std::vector::resize())
|
||||
/// @param size requested size
|
||||
void resizeList(size_t size);
|
||||
void resizeList(size_t new_size);
|
||||
|
||||
/// Adds new option to list
|
||||
/// @param item object that has to be added
|
||||
/// @param is_bold defines the initial state of bold attribute
|
||||
/// @param is_inactive defines the initial state of static attribute
|
||||
void addItem(ItemT item, bool is_bold = 0, bool is_inactive = 0);
|
||||
void addItem(ItemT item, bool is_bold = false, bool is_inactive = false);
|
||||
|
||||
/// Adds separator to list
|
||||
void addSeparator();
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
/// @param item object that has to be inserted
|
||||
/// @param is_bold defines the initial state of bold attribute
|
||||
/// @param is_inactive defines the initial state of static attribute
|
||||
void insertItem(size_t pos, const ItemT &Item, bool is_bold = 0, bool is_inactive = 0);
|
||||
void insertItem(size_t pos, const ItemT &Item, bool is_bold = false, bool is_inactive = false);
|
||||
|
||||
/// Inserts separator to list at given position
|
||||
/// @param pos initial position of inserted separator
|
||||
@@ -168,27 +168,6 @@ public:
|
||||
/// @return currently highlighted position
|
||||
size_t choice() const;
|
||||
|
||||
void filter(ConstIterator first, ConstIterator last, const FilterFunction &f);
|
||||
|
||||
void applyCurrentFilter(ConstIterator first, ConstIterator last);
|
||||
|
||||
/// Clears filter results
|
||||
void clearFilterResults();
|
||||
|
||||
void clearFilter();
|
||||
|
||||
/// @return const reference to currently used filter function
|
||||
const FilterFunction &getFilter() { return m_filter; }
|
||||
|
||||
/// @return true if list is currently filtered, false otherwise
|
||||
bool isFiltered() { return m_options_ptr == &m_filtered_options; }
|
||||
|
||||
/// Turns off filtering
|
||||
void showAll() { m_options_ptr = &m_options; }
|
||||
|
||||
/// Turns on filtering
|
||||
void showFiltered() { m_options_ptr = &m_filtered_options; }
|
||||
|
||||
/// Refreshes the menu window
|
||||
/// @see Window::refresh()
|
||||
virtual void refresh() OVERRIDE;
|
||||
@@ -236,17 +215,10 @@ public:
|
||||
|
||||
/// Checks if list is empty
|
||||
/// @return true if list is empty, false otherwise
|
||||
/// @see reallyEmpty()
|
||||
bool empty() const { return m_options_ptr->empty(); }
|
||||
|
||||
/// Checks if list is really empty since Empty() may not
|
||||
/// be accurate if filter is set)
|
||||
/// @return true if list is empty, false otherwise
|
||||
/// @see Empty()
|
||||
bool reallyEmpty() const { return m_options.empty(); }
|
||||
bool empty() const { return m_items.empty(); }
|
||||
|
||||
/// @return size of the list
|
||||
size_t size() const { return m_options_ptr->size(); }
|
||||
size_t size() const { return m_items.size(); }
|
||||
|
||||
/// @return currently drawn item. The result is defined only within
|
||||
/// drawing function that is called by refresh()
|
||||
@@ -256,35 +228,35 @@ public:
|
||||
/// @param pos requested position
|
||||
/// @return reference to item at given position
|
||||
/// @throw std::out_of_range if given position is out of range
|
||||
Menu<ItemT>::Item &at(size_t pos) { return *m_options_ptr->at(pos); }
|
||||
Menu<ItemT>::Item &at(size_t pos) { return *m_items.at(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
|
||||
const Menu<ItemT>::Item &at(size_t pos) const { return *m_options_ptr->at(pos); }
|
||||
const Menu<ItemT>::Item &at(size_t pos) const { return *m_items.at(pos); }
|
||||
|
||||
/// @param pos requested position
|
||||
/// @return const reference to item at given position
|
||||
const Menu<ItemT>::Item &operator[](size_t pos) const { return *(*m_options_ptr)[pos]; }
|
||||
const Menu<ItemT>::Item &operator[](size_t pos) const { return *m_items[pos]; }
|
||||
|
||||
/// @param pos requested position
|
||||
/// @return const reference to item at given position
|
||||
Menu<ItemT>::Item &operator[](size_t pos) { return *(*m_options_ptr)[pos]; }
|
||||
Menu<ItemT>::Item &operator[](size_t pos) { return *m_items[pos]; }
|
||||
|
||||
Iterator current() { return Iterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstIterator current() const { return ConstIterator(m_options_ptr->begin() + m_highlight); }
|
||||
Iterator current() { return Iterator(m_items.begin() + m_highlight); }
|
||||
ConstIterator current() const { return ConstIterator(m_items.begin() + m_highlight); }
|
||||
ReverseIterator rcurrent() { return ReverseIterator(++current()); }
|
||||
ConstReverseIterator rcurrent() const { return ReverseIterator(++current()); }
|
||||
|
||||
ValueIterator currentV() { return ValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstValueIterator currentV() const { return ConstValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ValueIterator currentV() { return ValueIterator(m_items.begin() + m_highlight); }
|
||||
ConstValueIterator currentV() const { return ConstValueIterator(m_items.begin() + m_highlight); }
|
||||
ReverseValueIterator rcurrentV() { return ReverseValueIterator(++currentV()); }
|
||||
ConstReverseValueIterator rcurrentV() const { return ConstReverseValueIterator(++currentV()); }
|
||||
|
||||
Iterator begin() { return Iterator(m_options_ptr->begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_options_ptr->begin()); }
|
||||
Iterator end() { return Iterator(m_options_ptr->end()); }
|
||||
ConstIterator end() const { return ConstIterator(m_options_ptr->end()); }
|
||||
Iterator begin() { return Iterator(m_items.begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_items.begin()); }
|
||||
Iterator end() { return Iterator(m_items.end()); }
|
||||
ConstIterator end() const { return ConstIterator(m_items.end()); }
|
||||
|
||||
ReverseIterator rbegin() { return ReverseIterator(end()); }
|
||||
ConstReverseIterator rbegin() const { return ConstReverseIterator(end()); }
|
||||
@@ -320,17 +292,13 @@ private:
|
||||
|
||||
bool isHighlightable(size_t pos)
|
||||
{
|
||||
return !(*m_options_ptr)[pos]->isSeparator()
|
||||
&& !(*m_options_ptr)[pos]->isInactive();
|
||||
return !m_items[pos]->isSeparator()
|
||||
&& !m_items[pos]->isInactive();
|
||||
}
|
||||
|
||||
ItemDisplayer m_item_displayer;
|
||||
|
||||
FilterFunction m_filter;
|
||||
|
||||
std::vector<ItemProxy> *m_options_ptr;
|
||||
std::vector<ItemProxy> m_options;
|
||||
std::vector<ItemProxy> m_filtered_options;
|
||||
std::vector<ItemProxy> m_items;
|
||||
|
||||
size_t m_beginning;
|
||||
size_t m_highlight;
|
||||
@@ -357,7 +325,6 @@ Menu<ItemT>::Menu(size_t startx,
|
||||
Border border)
|
||||
: Window(startx, starty, width, height, title, color, border),
|
||||
m_item_displayer(0),
|
||||
m_options_ptr(&m_options),
|
||||
m_beginning(0),
|
||||
m_highlight(0),
|
||||
m_highlight_color(m_base_color),
|
||||
@@ -371,7 +338,6 @@ template <typename ItemT>
|
||||
Menu<ItemT>::Menu(const Menu &rhs)
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_filter(rhs.m_filter)
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
@@ -384,19 +350,15 @@ Menu<ItemT>::Menu(const Menu &rhs)
|
||||
{
|
||||
// there is no way to properly fill m_filtered_options
|
||||
// (if rhs is filtered), so we just don't do it.
|
||||
m_options.reserve(rhs.m_options.size());
|
||||
for (auto it = rhs.m_options.begin(); it != rhs.m_options.end(); ++it)
|
||||
m_options.push_back(ItemProxy(**it));
|
||||
m_options_ptr = &m_options;
|
||||
m_items.reserve(rhs.m_items.size());
|
||||
std::copy(rhs.begin(), rhs.end(), std::back_inserter(m_items));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
Menu<ItemT>::Menu(Menu &&rhs)
|
||||
: Window(rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_filter(rhs.m_filter)
|
||||
, m_options(std::move(rhs.m_options))
|
||||
, m_filtered_options(std::move(rhs.m_filtered_options))
|
||||
, m_items(std::move(rhs.m_items))
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
@@ -407,10 +369,6 @@ Menu<ItemT>::Menu(Menu &&rhs)
|
||||
, m_selected_prefix(std::move(rhs.m_selected_prefix))
|
||||
, m_selected_suffix(std::move(rhs.m_selected_suffix))
|
||||
{
|
||||
if (rhs.m_options_ptr == &rhs.m_options)
|
||||
m_options_ptr = &m_options;
|
||||
else
|
||||
m_options_ptr = &m_filtered_options;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -418,9 +376,7 @@ Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
|
||||
{
|
||||
std::swap(static_cast<Window &>(*this), static_cast<Window &>(rhs));
|
||||
std::swap(m_item_displayer, rhs.m_item_displayer);
|
||||
std::swap(m_filter, rhs.m_filter);
|
||||
std::swap(m_options, rhs.m_options);
|
||||
std::swap(m_filtered_options, rhs.m_filtered_options);
|
||||
std::swap(m_items, rhs.m_items);
|
||||
std::swap(m_beginning, rhs.m_beginning);
|
||||
std::swap(m_highlight, rhs.m_highlight);
|
||||
std::swap(m_highlight_color, rhs.m_highlight_color);
|
||||
@@ -430,57 +386,52 @@ Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
|
||||
std::swap(m_drawn_position, rhs.m_drawn_position);
|
||||
std::swap(m_selected_prefix, rhs.m_selected_prefix);
|
||||
std::swap(m_selected_suffix, rhs.m_selected_suffix);
|
||||
if (rhs.m_options_ptr == &rhs.m_options)
|
||||
m_options_ptr = &m_options;
|
||||
else
|
||||
m_options_ptr = &m_filtered_options;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::resizeList(size_t new_size)
|
||||
{
|
||||
if (new_size > m_options.size())
|
||||
if (new_size > m_items.size())
|
||||
{
|
||||
size_t old_size = m_options.size();
|
||||
m_options.resize(new_size);
|
||||
size_t old_size = m_items.size();
|
||||
m_items.resize(new_size);
|
||||
for (size_t i = old_size; i < new_size; ++i)
|
||||
m_options[i] = Item();
|
||||
m_items[i] = Item();
|
||||
}
|
||||
else
|
||||
m_options.resize(new_size);
|
||||
m_items.resize(new_size);
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::addItem(ItemT item, bool is_bold, bool is_inactive)
|
||||
{
|
||||
m_options.push_back(Item(std::move(item), is_bold, is_inactive));
|
||||
m_items.push_back(Item(std::move(item), is_bold, is_inactive));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::addSeparator()
|
||||
{
|
||||
m_options.push_back(Item::mkSeparator());
|
||||
m_items.push_back(Item::mkSeparator());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::insertItem(size_t pos, const ItemT &item, bool is_bold, bool is_inactive)
|
||||
{
|
||||
m_options.insert(m_options.begin()+pos, Item(item, is_bold, is_inactive));
|
||||
m_items.insert(m_items.begin()+pos, Item(item, is_bold, is_inactive));
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::insertSeparator(size_t pos)
|
||||
{
|
||||
m_options.insert(m_options.begin()+pos, Item::mkSeparator());
|
||||
m_items.insert(m_items.begin()+pos, Item::mkSeparator());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::deleteItem(size_t pos)
|
||||
{
|
||||
assert(m_options_ptr != &m_filtered_options);
|
||||
assert(pos < m_options.size());
|
||||
m_options.erase(m_options.begin()+pos);
|
||||
assert(pos < m_items.size());
|
||||
m_items.erase(m_items.begin()+pos);
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
@@ -495,7 +446,7 @@ bool Menu<ItemT>::Goto(size_t y)
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::refresh()
|
||||
{
|
||||
if (m_options_ptr->empty())
|
||||
if (m_items.empty())
|
||||
{
|
||||
Window::clear();
|
||||
Window::refresh();
|
||||
@@ -503,14 +454,14 @@ void Menu<ItemT>::refresh()
|
||||
}
|
||||
|
||||
size_t max_beginning = 0;
|
||||
if (m_options_ptr->size() > m_height)
|
||||
max_beginning = m_options_ptr->size() - m_height;
|
||||
if (m_items.size() > m_height)
|
||||
max_beginning = m_items.size() - m_height;
|
||||
m_beginning = std::min(m_beginning, max_beginning);
|
||||
|
||||
// if highlighted position is off the screen, make it visible
|
||||
m_highlight = std::min(m_highlight, m_beginning+m_height-1);
|
||||
// if highlighted position is invalid, correct it
|
||||
m_highlight = std::min(m_highlight, m_options_ptr->size()-1);
|
||||
m_highlight = std::min(m_highlight, m_items.size()-1);
|
||||
|
||||
if (!isHighlightable(m_highlight))
|
||||
{
|
||||
@@ -524,18 +475,18 @@ void Menu<ItemT>::refresh()
|
||||
for (size_t &i = m_drawn_position; i < m_beginning+m_height; ++i, ++line)
|
||||
{
|
||||
goToXY(0, line);
|
||||
if (i >= m_options_ptr->size())
|
||||
if (i >= m_items.size())
|
||||
{
|
||||
for (; line < m_height; ++line)
|
||||
mvwhline(m_window, line, 0, KEY_SPACE, m_width);
|
||||
break;
|
||||
}
|
||||
if ((*m_options_ptr)[i]->isSeparator())
|
||||
if (m_items[i]->isSeparator())
|
||||
{
|
||||
mvwhline(m_window, line, 0, 0, m_width);
|
||||
continue;
|
||||
}
|
||||
if ((*m_options_ptr)[i]->isBold())
|
||||
if (m_items[i]->isBold())
|
||||
*this << Format::Bold;
|
||||
if (m_highlight_enabled && i == m_highlight)
|
||||
{
|
||||
@@ -543,18 +494,18 @@ void Menu<ItemT>::refresh()
|
||||
*this << m_highlight_color;
|
||||
}
|
||||
mvwhline(m_window, line, 0, KEY_SPACE, m_width);
|
||||
if ((*m_options_ptr)[i]->isSelected())
|
||||
if (m_items[i]->isSelected())
|
||||
*this << m_selected_prefix;
|
||||
if (m_item_displayer)
|
||||
m_item_displayer(*this);
|
||||
if ((*m_options_ptr)[i]->isSelected())
|
||||
if (m_items[i]->isSelected())
|
||||
*this << m_selected_suffix;
|
||||
if (m_highlight_enabled && i == m_highlight)
|
||||
{
|
||||
*this << Color::End;
|
||||
*this << Format::NoReverse;
|
||||
}
|
||||
if ((*m_options_ptr)[i]->isBold())
|
||||
if (m_items[i]->isBold())
|
||||
*this << Format::NoBold;
|
||||
}
|
||||
Window::refresh();
|
||||
@@ -563,10 +514,10 @@ void Menu<ItemT>::refresh()
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::scroll(Scroll where)
|
||||
{
|
||||
if (m_options_ptr->empty())
|
||||
if (m_items.empty())
|
||||
return;
|
||||
size_t max_highlight = m_options_ptr->size()-1;
|
||||
size_t max_beginning = m_options_ptr->size() < m_height ? 0 : m_options_ptr->size()-m_height;
|
||||
size_t max_highlight = m_items.size()-1;
|
||||
size_t max_beginning = m_items.size() < m_height ? 0 : m_items.size()-m_height;
|
||||
size_t max_visible_highlight = m_beginning+m_height-1;
|
||||
switch (where)
|
||||
{
|
||||
@@ -661,15 +612,13 @@ void Menu<ItemT>::reset()
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clear()
|
||||
{
|
||||
clearFilterResults();
|
||||
m_options.clear();
|
||||
m_options_ptr = &m_options;
|
||||
m_items.clear();
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::highlight(size_t pos)
|
||||
{
|
||||
assert(pos < m_options_ptr->size());
|
||||
assert(pos < m_items.size());
|
||||
m_highlight = pos;
|
||||
size_t half_height = m_height/2;
|
||||
if (pos < half_height)
|
||||
@@ -685,42 +634,6 @@ size_t Menu<ItemT>::choice() const
|
||||
return m_highlight;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::filter(ConstIterator first, ConstIterator last, const FilterFunction &f)
|
||||
{
|
||||
assert(m_options_ptr != &m_filtered_options);
|
||||
clearFilterResults();
|
||||
m_filter = f;
|
||||
for (auto it = first; it != last; ++it)
|
||||
if (m_filter(*it))
|
||||
m_filtered_options.push_back(*it.base());
|
||||
if (m_filtered_options == m_options)
|
||||
m_filtered_options.clear();
|
||||
else
|
||||
m_options_ptr = &m_filtered_options;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::applyCurrentFilter(ConstIterator first, ConstIterator last)
|
||||
{
|
||||
assert(m_filter);
|
||||
filter(first, last, m_filter);
|
||||
}
|
||||
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clearFilterResults()
|
||||
{
|
||||
m_filtered_options.clear();
|
||||
m_options_ptr = &m_options;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clearFilter()
|
||||
{
|
||||
m_filter = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_MENU_H
|
||||
|
||||
@@ -148,36 +148,6 @@ void Playlist::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool Playlist::allowsFiltering()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Playlist::currentFilter()
|
||||
{
|
||||
return RegexFilter<MPD::Song>::currentFilter(w);
|
||||
}
|
||||
|
||||
void Playlist::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
w.clearFilter();
|
||||
w.clearFilterResults();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
w.showAll();
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(filter, Config.regex_type), playlistEntryMatcher);
|
||||
w.filter(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool Playlist::allowsSearching()
|
||||
{
|
||||
return true;
|
||||
@@ -245,22 +215,12 @@ MPD::Song Playlist::nowPlayingSong()
|
||||
{
|
||||
MPD::Song s;
|
||||
if (Status::State::player() != MPD::psUnknown)
|
||||
withUnfilteredMenu(w, [this, &s]() {
|
||||
auto sp = Status::State::currentSongPosition();
|
||||
if (sp >= 0 && size_t(sp) < w.size())
|
||||
s = w.at(sp).value();
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
bool Playlist::isFiltered()
|
||||
{
|
||||
if (w.isFiltered())
|
||||
{
|
||||
Statusbar::print("Function currently unavailable due to filtered playlist");
|
||||
return true;
|
||||
auto sp = Status::State::currentSongPosition();
|
||||
if (sp >= 0 && size_t(sp) < w.size())
|
||||
s = w.at(sp).value();
|
||||
}
|
||||
return false;
|
||||
return s;
|
||||
}
|
||||
|
||||
void Playlist::Reverse()
|
||||
@@ -292,7 +252,7 @@ std::string Playlist::getTotalLength()
|
||||
m_total_length += s.value().getDuration();
|
||||
m_reload_total_length = false;
|
||||
}
|
||||
if (Config.playlist_show_remaining_time && m_reload_remaining && !w.isFiltered())
|
||||
if (Config.playlist_show_remaining_time && m_reload_remaining)
|
||||
{
|
||||
m_remaining_time = 0;
|
||||
for (size_t i = Status::State::currentSongPosition(); i < w.size(); ++i)
|
||||
@@ -302,21 +262,12 @@ std::string Playlist::getTotalLength()
|
||||
|
||||
result << '(' << w.size() << (w.size() == 1 ? " item" : " items");
|
||||
|
||||
if (w.isFiltered())
|
||||
{
|
||||
w.showAll();
|
||||
size_t real_size = w.size();
|
||||
w.showFiltered();
|
||||
if (w.size() != real_size)
|
||||
result << " (out of " << real_size << ")";
|
||||
}
|
||||
|
||||
if (m_total_length)
|
||||
{
|
||||
result << ", length: ";
|
||||
ShowTime(result, m_total_length, Config.playlist_shorten_total_times);
|
||||
}
|
||||
if (Config.playlist_show_remaining_time && m_remaining_time && !w.isFiltered() && w.size() > 1)
|
||||
if (Config.playlist_show_remaining_time && m_remaining_time && w.size() > 1)
|
||||
{
|
||||
result << " :: remaining: ";
|
||||
ShowTime(result, m_remaining_time, Config.playlist_shorten_total_times);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
|
||||
struct Playlist: Screen<NC::Menu<MPD::Song>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
struct Playlist: Screen<NC::Menu<MPD::Song>>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
Playlist();
|
||||
|
||||
@@ -48,11 +48,6 @@ struct Playlist: Screen<NC::Menu<MPD::Song>>, Filterable, HasSongs, Searchable,
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching();
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
@@ -69,7 +64,6 @@ struct Playlist: Screen<NC::Menu<MPD::Song>>, Filterable, HasSongs, Searchable,
|
||||
// private members
|
||||
MPD::Song nowPlayingSong();
|
||||
|
||||
bool isFiltered();
|
||||
void Reverse();
|
||||
|
||||
void EnableHighlighting();
|
||||
|
||||
@@ -134,27 +134,25 @@ void PlaylistEditor::switchTo()
|
||||
|
||||
void PlaylistEditor::update()
|
||||
{
|
||||
if (Playlists.reallyEmpty() || m_playlists_update_requested)
|
||||
if (Playlists.empty() || m_playlists_update_requested)
|
||||
{
|
||||
m_playlists_update_requested = false;
|
||||
withUnfilteredMenuReapplyFilter(Playlists, [this]() {
|
||||
size_t idx = 0;
|
||||
for (MPD::PlaylistIterator it = Mpd.GetPlaylists(), end; it != end; ++it, ++idx)
|
||||
{
|
||||
if (idx < Playlists.size())
|
||||
Playlists[idx].value() = std::move(*it);
|
||||
else
|
||||
Playlists.addItem(std::move(*it));
|
||||
};
|
||||
size_t idx = 0;
|
||||
for (MPD::PlaylistIterator it = Mpd.GetPlaylists(), end; it != end; ++it, ++idx)
|
||||
{
|
||||
if (idx < Playlists.size())
|
||||
Playlists.resizeList(idx);
|
||||
std::sort(Playlists.beginV(), Playlists.endV(),
|
||||
LocaleBasedSorting(std::locale(), Config.ignore_leading_the));
|
||||
});
|
||||
Playlists[idx].value() = std::move(*it);
|
||||
else
|
||||
Playlists.addItem(std::move(*it));
|
||||
};
|
||||
if (idx < Playlists.size())
|
||||
Playlists.resizeList(idx);
|
||||
std::sort(Playlists.beginV(), Playlists.endV(),
|
||||
LocaleBasedSorting(std::locale(), Config.ignore_leading_the));
|
||||
Playlists.refresh();
|
||||
}
|
||||
|
||||
if ((Content.reallyEmpty() && Global::Timer - m_timer > m_fetching_delay)
|
||||
if ((Content.empty() && Global::Timer - m_timer > m_fetching_delay)
|
||||
|| m_content_update_requested)
|
||||
{
|
||||
m_content_update_requested = false;
|
||||
@@ -162,49 +160,43 @@ void PlaylistEditor::update()
|
||||
Content.clear();
|
||||
else
|
||||
{
|
||||
withUnfilteredMenuReapplyFilter(Content, [this]() {
|
||||
size_t idx = 0;
|
||||
MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current()->value().path()), end;
|
||||
for (; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_bold = myPlaylist->checkForSong(*s);
|
||||
if (idx < Content.size())
|
||||
{
|
||||
Content[idx].setBold(is_bold);
|
||||
Content[idx].value() = std::move(*s);
|
||||
}
|
||||
else
|
||||
Content.addItem(std::move(*s), is_bold);
|
||||
}
|
||||
size_t idx = 0;
|
||||
MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current()->value().path()), end;
|
||||
for (; s != end; ++s, ++idx)
|
||||
{
|
||||
bool is_bold = myPlaylist->checkForSong(*s);
|
||||
if (idx < Content.size())
|
||||
Content.resizeList(idx);
|
||||
std::string title;
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
title = "Playlist content";
|
||||
title += " (";
|
||||
title += boost::lexical_cast<std::string>(Content.size());
|
||||
title += " item";
|
||||
if (Content.size() == 1)
|
||||
title += ")";
|
||||
else
|
||||
title += "s)";
|
||||
title.resize(Content.getWidth());
|
||||
Content[idx].setBold(is_bold);
|
||||
Content[idx].value() = std::move(*s);
|
||||
}
|
||||
Content.setTitle(title);
|
||||
});
|
||||
else
|
||||
Content.addItem(std::move(*s), is_bold);
|
||||
}
|
||||
if (idx < Content.size())
|
||||
Content.resizeList(idx);
|
||||
std::string title;
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
title = (boost::format("Playlist content (%1%) %2%")
|
||||
% boost::lexical_cast<std::string>(Content.size())
|
||||
% (Content.size() == 1 ? "item" : "items")
|
||||
).str();
|
||||
title.resize(Content.getWidth());
|
||||
}
|
||||
Content.setTitle(title);
|
||||
}
|
||||
Content.display();
|
||||
}
|
||||
|
||||
if (isActiveWindow(Content) && Content.reallyEmpty())
|
||||
if (isActiveWindow(Content) && Content.empty())
|
||||
{
|
||||
Content.setHighlightColor(Config.main_highlight_color);
|
||||
Playlists.setHighlightColor(Config.active_column_color);
|
||||
w = &Playlists;
|
||||
}
|
||||
|
||||
if (Playlists.empty() && Content.reallyEmpty())
|
||||
if (Playlists.empty() && Content.empty())
|
||||
{
|
||||
Content.Window::clear();
|
||||
Content.Window::display();
|
||||
@@ -213,22 +205,12 @@ void PlaylistEditor::update()
|
||||
|
||||
int PlaylistEditor::windowTimeout()
|
||||
{
|
||||
if (Content.reallyEmpty())
|
||||
if (Content.empty())
|
||||
return m_window_timeout;
|
||||
else
|
||||
return Screen<WindowType>::windowTimeout();
|
||||
}
|
||||
|
||||
bool PlaylistEditor::isContentFiltered()
|
||||
{
|
||||
if (Content.isFiltered())
|
||||
{
|
||||
Statusbar::print("Function currently unavailable due to filtered playlist content");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ProxySongList PlaylistEditor::contentProxyList()
|
||||
{
|
||||
return ProxySongList(Content, [](NC::Menu<MPD::Song>::Item &item) {
|
||||
@@ -242,10 +224,7 @@ void PlaylistEditor::AddToPlaylist(bool add_n_play)
|
||||
|
||||
if (isActiveWindow(Playlists) && !Playlists.empty())
|
||||
{
|
||||
bool success;
|
||||
withUnfilteredMenu(Content, [&]() {
|
||||
success = addSongsToPlaylist(Content.beginV(), Content.endV(), add_n_play, -1);
|
||||
});
|
||||
bool success = addSongsToPlaylist(Content.beginV(), Content.endV(), add_n_play, -1);
|
||||
Statusbar::printf("Playlist \"%1%\" loaded%2%",
|
||||
Playlists.current()->value().path(), withErrors(success)
|
||||
);
|
||||
@@ -342,59 +321,6 @@ void PlaylistEditor::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool PlaylistEditor::allowsFiltering()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string PlaylistEditor::currentFilter()
|
||||
{
|
||||
std::string filter;
|
||||
if (isActiveWindow(Playlists))
|
||||
filter = RegexFilter<MPD::Playlist>::currentFilter(Playlists);
|
||||
else if (isActiveWindow(Content))
|
||||
filter = RegexFilter<MPD::Song>::currentFilter(Content);
|
||||
return filter;
|
||||
}
|
||||
|
||||
void PlaylistEditor::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
{
|
||||
Playlists.clearFilter();
|
||||
Playlists.clearFilterResults();
|
||||
}
|
||||
else if (isActiveWindow(Content))
|
||||
{
|
||||
Content.clearFilter();
|
||||
Content.clearFilterResults();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
{
|
||||
Playlists.showAll();
|
||||
auto rx = RegexFilter<MPD::Playlist>(
|
||||
boost::regex(filter, Config.regex_type), PlaylistEntryMatcher);
|
||||
Playlists.filter(Playlists.begin(), Playlists.end(), rx);
|
||||
}
|
||||
else if (isActiveWindow(Content))
|
||||
{
|
||||
Content.showAll();
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(filter, Config.regex_type), SongEntryMatcher);
|
||||
Content.filter(Content.begin(), Content.end(), rx);
|
||||
}
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool PlaylistEditor::allowsSearching()
|
||||
{
|
||||
return true;
|
||||
@@ -489,11 +415,7 @@ std::vector<MPD::Song> PlaylistEditor::getSelectedSongs()
|
||||
}
|
||||
// if no item is selected, add songs from right column
|
||||
if (!any_selected && !Content.empty())
|
||||
{
|
||||
withUnfilteredMenu(Content, [this, &result]() {
|
||||
std::copy(Content.beginV(), Content.endV(), std::back_inserter(result));
|
||||
});
|
||||
}
|
||||
std::copy(Content.beginV(), Content.endV(), std::back_inserter(result));
|
||||
}
|
||||
else if (isActiveWindow(Content))
|
||||
{
|
||||
@@ -513,7 +435,7 @@ bool PlaylistEditor::previousColumnAvailable()
|
||||
{
|
||||
if (isActiveWindow(Content))
|
||||
{
|
||||
if (!Playlists.reallyEmpty())
|
||||
if (!Playlists.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -534,7 +456,7 @@ bool PlaylistEditor::nextColumnAvailable()
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
{
|
||||
if (!Content.reallyEmpty())
|
||||
if (!Content.empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct PlaylistEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Searchable, Tabbable
|
||||
struct PlaylistEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
PlaylistEditor();
|
||||
|
||||
@@ -48,11 +48,6 @@ struct PlaylistEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, S
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
@@ -80,7 +75,6 @@ struct PlaylistEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, S
|
||||
void requestContentsUpdate() { m_content_update_requested = true; }
|
||||
|
||||
virtual void Locate(const MPD::Playlist &playlist);
|
||||
bool isContentFiltered();
|
||||
ProxySongList contentProxyList();
|
||||
|
||||
NC::Menu<MPD::Playlist> Playlists;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <cassert>
|
||||
#include "menu.h"
|
||||
|
||||
template <typename T>
|
||||
struct RegexFilter
|
||||
@@ -51,15 +50,6 @@ struct RegexFilter
|
||||
return m_filter.operator bool();
|
||||
}
|
||||
|
||||
static std::string currentFilter(MenuT &menu)
|
||||
{
|
||||
std::string filter;
|
||||
auto rf = menu.getFilter().template target< RegexFilter<T> >();
|
||||
if (rf)
|
||||
filter = rf->m_rx.str();
|
||||
return filter;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::regex m_rx;
|
||||
FilterFunction m_filter;
|
||||
@@ -89,15 +79,6 @@ template <typename T> struct RegexItemFilter
|
||||
return m_filter.operator bool();
|
||||
}
|
||||
|
||||
static std::string currentFilter(MenuT &menu)
|
||||
{
|
||||
std::string filter;
|
||||
auto rf = menu.getFilter().template target< RegexItemFilter<T> >();
|
||||
if (rf)
|
||||
filter = rf->m_rx.str();
|
||||
return filter;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::regex m_rx;
|
||||
FilterFunction m_filter;
|
||||
|
||||
@@ -176,7 +176,6 @@ void SearchEngine::enterPressed()
|
||||
}
|
||||
else if (option == SearchButton)
|
||||
{
|
||||
w.showAll();
|
||||
Statusbar::print("Searching...");
|
||||
if (w.size() > StaticOptions)
|
||||
Prepare();
|
||||
@@ -256,37 +255,6 @@ void SearchEngine::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool SearchEngine::allowsFiltering()
|
||||
{
|
||||
return w.rbegin()->value().isSong();
|
||||
}
|
||||
|
||||
std::string SearchEngine::currentFilter()
|
||||
{
|
||||
return RegexItemFilter<SEItem>::currentFilter(w);
|
||||
}
|
||||
|
||||
void SearchEngine::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
w.clearFilter();
|
||||
w.clearFilterResults();
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
w.showAll();
|
||||
auto fun = boost::bind(SEItemEntryMatcher, _1, _2, true);
|
||||
auto rx = RegexItemFilter<SEItem>(
|
||||
boost::regex(filter, Config.regex_type), fun);
|
||||
w.filter(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool SearchEngine::allowsSearching()
|
||||
{
|
||||
return w.rbegin()->value().isSong();
|
||||
|
||||
@@ -74,7 +74,7 @@ private:
|
||||
MPD::Song m_song;
|
||||
};
|
||||
|
||||
struct SearchEngine: Screen<NC::Menu<SEItem>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
struct SearchEngine: Screen<NC::Menu<SEItem>>, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
SearchEngine();
|
||||
|
||||
@@ -93,11 +93,6 @@ struct SearchEngine: Screen<NC::Menu<SEItem>>, Filterable, HasSongs, Searchable,
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
|
||||
@@ -271,11 +271,9 @@ void SelectedItemsAdder::addAfterCurrentAlbum() const
|
||||
return;
|
||||
auto &pl = myPlaylist->main();
|
||||
size_t pos = Status::State::currentSongPosition();
|
||||
withUnfilteredMenu(pl, [&pos, &pl]() {
|
||||
std::string album = pl[pos].value().getAlbum();
|
||||
while (pos < pl.size() && pl[pos].value().getAlbum() == album)
|
||||
++pos;
|
||||
});
|
||||
std::string album = pl[pos].value().getAlbum();
|
||||
while (pos < pl.size() && pl[pos].value().getAlbum() == album)
|
||||
++pos;
|
||||
bool success = addSongsToPlaylist(m_selected_items.begin(), m_selected_items.end(), false, pos);
|
||||
exitSuccessfully(success);
|
||||
}
|
||||
|
||||
@@ -387,32 +387,30 @@ int Status::State::volume()
|
||||
|
||||
void Status::Changes::playlist(unsigned previous_version)
|
||||
{
|
||||
withUnfilteredMenuReapplyFilter(myPlaylist->main(), [previous_version]() {
|
||||
if (m_playlist_length < myPlaylist->main().size())
|
||||
if (m_playlist_length < myPlaylist->main().size())
|
||||
{
|
||||
auto it = myPlaylist->main().begin()+m_playlist_length;
|
||||
auto end = myPlaylist->main().end();
|
||||
for (; it != end; ++it)
|
||||
myPlaylist->unregisterSong(it->value());
|
||||
myPlaylist->main().resizeList(m_playlist_length);
|
||||
}
|
||||
|
||||
MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end;
|
||||
for (; s != end; ++s)
|
||||
{
|
||||
size_t pos = s->getPosition();
|
||||
myPlaylist->registerSong(*s);
|
||||
if (pos < myPlaylist->main().size())
|
||||
{
|
||||
auto it = myPlaylist->main().begin()+m_playlist_length;
|
||||
auto end = myPlaylist->main().end();
|
||||
for (; it != end; ++it)
|
||||
myPlaylist->unregisterSong(it->value());
|
||||
myPlaylist->main().resizeList(m_playlist_length);
|
||||
// if song's already in playlist, replace it with a new one
|
||||
MPD::Song &old_s = myPlaylist->main()[pos].value();
|
||||
myPlaylist->unregisterSong(old_s);
|
||||
old_s = std::move(*s);
|
||||
}
|
||||
|
||||
MPD::SongIterator s = Mpd.GetPlaylistChanges(previous_version), end;
|
||||
for (; s != end; ++s)
|
||||
{
|
||||
size_t pos = s->getPosition();
|
||||
myPlaylist->registerSong(*s);
|
||||
if (pos < myPlaylist->main().size())
|
||||
{
|
||||
// if song's already in playlist, replace it with a new one
|
||||
MPD::Song &old_s = myPlaylist->main()[pos].value();
|
||||
myPlaylist->unregisterSong(old_s);
|
||||
old_s = std::move(*s);
|
||||
}
|
||||
else // otherwise just add it to playlist
|
||||
myPlaylist->main().addItem(std::move(*s));
|
||||
}
|
||||
});
|
||||
else // otherwise just add it to playlist
|
||||
myPlaylist->main().addItem(std::move(*s));
|
||||
}
|
||||
|
||||
myPlaylist->reloadTotalLength();
|
||||
myPlaylist->reloadRemaining();
|
||||
@@ -536,7 +534,7 @@ void Status::Changes::songID(int song_id)
|
||||
|
||||
drawTitle(s);
|
||||
|
||||
if (Config.autocenter_mode && !pl.isFiltered())
|
||||
if (Config.autocenter_mode)
|
||||
pl.highlight(Status::State::currentSongPosition());
|
||||
|
||||
if (Config.now_playing_lyrics && isVisible(myLyrics) && myLyrics->previousScreen() == myPlaylist)
|
||||
|
||||
@@ -220,27 +220,6 @@ bool Statusbar::Helpers::ImmediatelyReturnOneOf::operator()(const char *s) const
|
||||
return !isOneOf(s);
|
||||
}
|
||||
|
||||
bool Statusbar::Helpers::ApplyFilterImmediately::operator()(const char *s)
|
||||
{
|
||||
using Global::myScreen;
|
||||
// if input queue is not empty, we don't want to update filter since next
|
||||
// character will be taken from queue immediately, trigering this function
|
||||
// again and thus making it inefficient, so let's apply filter only if
|
||||
// "real" user input arrived. however, we want to apply filter if ENTER
|
||||
// is next in queue, so its effects will be seen.
|
||||
if (wFooter->inputQueue().empty() || wFooter->inputQueue().front() == KEY_ENTER)
|
||||
{
|
||||
if (m_s != s)
|
||||
{
|
||||
m_s = s;
|
||||
m_f->applyFilter(m_s);
|
||||
myScreen->refreshWindow();
|
||||
}
|
||||
Status::trace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Statusbar::Helpers::TryExecuteImmediateCommand::operator()(const char *s)
|
||||
{
|
||||
bool continue_ = true;
|
||||
|
||||
@@ -89,20 +89,6 @@ private:
|
||||
std::vector<std::string> m_values;
|
||||
};
|
||||
|
||||
/// called each time user changes current filter (while being inside Window::getString)
|
||||
struct ApplyFilterImmediately
|
||||
{
|
||||
template <typename StringT>
|
||||
ApplyFilterImmediately(Filterable *f, StringT &&filter)
|
||||
: m_f(f), m_s(std::forward<StringT>(filter)) { }
|
||||
|
||||
bool operator()(const char *s);
|
||||
|
||||
private:
|
||||
Filterable *m_f;
|
||||
std::string m_s;
|
||||
};
|
||||
|
||||
struct TryExecuteImmediateCommand
|
||||
{
|
||||
bool operator()(const char *s);
|
||||
|
||||
@@ -230,7 +230,7 @@ void TagEditor::refresh()
|
||||
|
||||
void TagEditor::update()
|
||||
{
|
||||
if (Dirs->reallyEmpty())
|
||||
if (Dirs->empty())
|
||||
{
|
||||
Dirs->Window::clear();
|
||||
Tags->clear();
|
||||
@@ -251,7 +251,7 @@ void TagEditor::update()
|
||||
Dirs->display();
|
||||
}
|
||||
|
||||
if (Tags->reallyEmpty())
|
||||
if (Tags->empty())
|
||||
{
|
||||
Tags->reset();
|
||||
MPD::SongIterator s = Mpd.GetSongs(Dirs->current()->value().second), end;
|
||||
@@ -716,60 +716,6 @@ void TagEditor::mouseButtonPressed(MEVENT me)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool TagEditor::allowsFiltering()
|
||||
{
|
||||
return w == Dirs || w == Tags;
|
||||
}
|
||||
|
||||
std::string TagEditor::currentFilter()
|
||||
{
|
||||
std::string filter;
|
||||
if (w == Dirs)
|
||||
filter = RegexFilter< std::pair<std::string, std::string> >::currentFilter(*Dirs);
|
||||
else if (w == Tags)
|
||||
filter = RegexFilter<MPD::MutableSong>::currentFilter(*Tags);
|
||||
return filter;
|
||||
}
|
||||
|
||||
void TagEditor::applyFilter(const std::string &filter)
|
||||
{
|
||||
if (filter.empty())
|
||||
{
|
||||
if (w == Dirs)
|
||||
{
|
||||
Dirs->clearFilter();
|
||||
Dirs->clearFilterResults();
|
||||
}
|
||||
else if (w == Tags)
|
||||
{
|
||||
Tags->clearFilter();
|
||||
Tags->clearFilterResults();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (w == Dirs)
|
||||
{
|
||||
Dirs->showAll();
|
||||
auto fun = boost::bind(DirEntryMatcher, _1, _2, true);
|
||||
auto rx = RegexFilter< std::pair<std::string, std::string> >(
|
||||
boost::regex(filter, Config.regex_type), fun);
|
||||
Dirs->filter(Dirs->begin(), Dirs->end(), rx);
|
||||
}
|
||||
else if (w == Tags)
|
||||
{
|
||||
Tags->showAll();
|
||||
auto rx = RegexFilter<MPD::MutableSong>(
|
||||
boost::regex(filter, Config.regex_type), SongEntryMatcher);
|
||||
Tags->filter(Tags->begin(), Tags->end(), rx);
|
||||
}
|
||||
}
|
||||
catch (boost::bad_expression &) { }
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
bool TagEditor::allowsSearching()
|
||||
{
|
||||
return w == Dirs || w == Tags;
|
||||
@@ -866,12 +812,12 @@ bool TagEditor::previousColumnAvailable()
|
||||
bool result = false;
|
||||
if (w == Tags)
|
||||
{
|
||||
if (!TagTypes->reallyEmpty() && !Dirs->reallyEmpty())
|
||||
if (!TagTypes->empty() && !Dirs->empty())
|
||||
result = true;
|
||||
}
|
||||
else if (w == TagTypes)
|
||||
{
|
||||
if (!Dirs->reallyEmpty() && isAnyModified(*Tags))
|
||||
if (!Dirs->empty() && isAnyModified(*Tags))
|
||||
Actions::confirmAction("There are pending changes, are you sure?");
|
||||
result = true;
|
||||
}
|
||||
@@ -911,12 +857,12 @@ bool TagEditor::nextColumnAvailable()
|
||||
bool result = false;
|
||||
if (w == Dirs)
|
||||
{
|
||||
if (!TagTypes->reallyEmpty() && !Tags->reallyEmpty())
|
||||
if (!TagTypes->empty() && !Tags->empty())
|
||||
result = true;
|
||||
}
|
||||
else if (w == TagTypes)
|
||||
{
|
||||
if (!Tags->reallyEmpty())
|
||||
if (!Tags->empty())
|
||||
result = true;
|
||||
}
|
||||
else if (w == FParser)
|
||||
@@ -933,7 +879,7 @@ void TagEditor::nextColumn()
|
||||
w = TagTypes;
|
||||
TagTypes->setHighlightColor(Config.active_column_color);
|
||||
}
|
||||
else if (w == TagTypes && TagTypes->choice() < 13 && !Tags->reallyEmpty())
|
||||
else if (w == TagTypes && TagTypes->choice() < 13 && !Tags->empty())
|
||||
{
|
||||
TagTypes->setHighlightColor(Config.main_highlight_color);
|
||||
w->refresh();
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct TagEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Searchable, Tabbable
|
||||
struct TagEditor: Screen<NC::Window *>, HasColumns, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
TagEditor();
|
||||
|
||||
@@ -51,11 +51,6 @@ struct TagEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Search
|
||||
|
||||
virtual bool isMergable() OVERRIDE { return true; }
|
||||
|
||||
// Filterable implementation
|
||||
virtual bool allowsFiltering() OVERRIDE;
|
||||
virtual std::string currentFilter() OVERRIDE;
|
||||
virtual void applyFilter(const std::string &filter) OVERRIDE;
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
|
||||
Reference in New Issue
Block a user