remove filtering

This commit is contained in:
Andrzej Rybczak
2014-11-05 00:19:44 +01:00
parent 413fe866de
commit 309a4989c9
26 changed files with 317 additions and 1040 deletions

View File

@@ -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
#

View File

@@ -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());

View File

@@ -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") { }

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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");

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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)
);

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;