menu: remove search related methods
This commit is contained in:
@@ -70,10 +70,25 @@
|
||||
|
||||
using Global::myScreen;
|
||||
|
||||
namespace {//
|
||||
namespace {
|
||||
|
||||
enum class Find { Forward, Backward };
|
||||
|
||||
std::string findToString(Find find)
|
||||
{
|
||||
std::string result;
|
||||
switch (find)
|
||||
{
|
||||
case Find::Forward:
|
||||
result = "forward";
|
||||
break;
|
||||
case Find::Backward:
|
||||
result = "backward";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boost::array<
|
||||
Actions::BaseAction *, static_cast<size_t>(Actions::Type::_numberOfActions)
|
||||
> AvailableActions;
|
||||
@@ -1942,7 +1957,8 @@ bool NextFoundItem::canBeRun() const
|
||||
void NextFoundItem::run()
|
||||
{
|
||||
Searchable *w = dynamic_cast<Searchable *>(myScreen);
|
||||
w->nextFound(Config.wrapped_search);
|
||||
assert(w != nullptr);
|
||||
w->findForward(Config.wrapped_search);
|
||||
listsChangeFinisher();
|
||||
}
|
||||
|
||||
@@ -1954,7 +1970,8 @@ bool PreviousFoundItem::canBeRun() const
|
||||
void PreviousFoundItem::run()
|
||||
{
|
||||
Searchable *w = dynamic_cast<Searchable *>(myScreen);
|
||||
w->prevFound(Config.wrapped_search);
|
||||
assert(w != nullptr);
|
||||
w->findBackward(Config.wrapped_search);
|
||||
listsChangeFinisher();
|
||||
}
|
||||
|
||||
@@ -2798,28 +2815,38 @@ void findItem(const Find direction)
|
||||
using Global::wFooter;
|
||||
|
||||
Searchable *w = dynamic_cast<Searchable *>(myScreen);
|
||||
assert(w);
|
||||
assert(w != nullptr);
|
||||
assert(w->allowsSearching());
|
||||
|
||||
std::string token;
|
||||
std::string constraint;
|
||||
{
|
||||
Statusbar::ScopedLock slock;
|
||||
Statusbar::put() << "Find " << (direction == Find::Forward ? "forward" : "backward") << ": ";
|
||||
token = wFooter->prompt();
|
||||
Statusbar::put() << "Find " << findToString(direction) << ": ";
|
||||
constraint = wFooter->prompt();
|
||||
}
|
||||
|
||||
Statusbar::print("Searching...");
|
||||
bool success = w->search(token);
|
||||
|
||||
if (success)
|
||||
Statusbar::print("Searching finished");
|
||||
else
|
||||
Statusbar::printf("Unable to find \"%1%\"", token);
|
||||
|
||||
if (direction == Find::Forward)
|
||||
w->nextFound(Config.wrapped_search);
|
||||
else
|
||||
w->prevFound(Config.wrapped_search);
|
||||
try
|
||||
{
|
||||
bool success = w->setSearchConstraint(constraint);
|
||||
if (success)
|
||||
Statusbar::printf("Using constraint \"%1%\"", constraint);
|
||||
else
|
||||
Statusbar::printf("Constraint unset");
|
||||
}
|
||||
catch (boost::bad_expression &e)
|
||||
{
|
||||
Statusbar::printf("%1%", e.what());
|
||||
}
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case Find::Forward:
|
||||
w->findForward(Config.wrapped_search);
|
||||
break;
|
||||
case Find::Backward:
|
||||
w->findBackward(Config.wrapped_search);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void listsChangeFinisher()
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "global.h"
|
||||
#include "helpers.h"
|
||||
#include "playlist.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen_switcher.h"
|
||||
#include "settings.h"
|
||||
#include "status.h"
|
||||
@@ -285,34 +284,31 @@ bool Browser::allowsSearching()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Browser::search(const std::string &constraint)
|
||||
bool Browser::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
w.clearSearchResults();
|
||||
m_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
auto fun = boost::bind(browserEntryMatcher, _1, _2, false);
|
||||
auto rx = RegexFilter<MPD::Item>(
|
||||
boost::regex(constraint, Config.regex_type), fun);
|
||||
return w.search(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
m_search_predicate = RegexFilter<MPD::Item>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
boost::bind(browserEntryMatcher, _1, _2, false)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Browser::nextFound(bool wrap)
|
||||
void Browser::findForward(bool wrap)
|
||||
{
|
||||
w.nextFound(wrap);
|
||||
searchForward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void Browser::prevFound(bool wrap)
|
||||
void Browser::findBackward(bool wrap)
|
||||
{
|
||||
w.prevFound(wrap);
|
||||
searchBackward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "mpdpp.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct Browser: Screen<NC::Menu<MPD::Item>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
@@ -51,9 +52,9 @@ struct Browser: Screen<NC::Menu<MPD::Item>>, Filterable, HasSongs, Searchable, T
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -82,6 +83,7 @@ private:
|
||||
bool m_local_browser;
|
||||
size_t m_scroll_beginning;
|
||||
std::string m_current_directory;
|
||||
RegexFilter<MPD::Item> m_search_predicate;
|
||||
};
|
||||
|
||||
extern Browser *myBrowser;
|
||||
|
||||
@@ -29,6 +29,41 @@
|
||||
#include "utility/string.h"
|
||||
#include "utility/wide_string.h"
|
||||
|
||||
template <typename Iterator, typename PredicateT>
|
||||
Iterator wrappedSearch(Iterator begin, Iterator current, Iterator end,
|
||||
const PredicateT &pred, bool wrap)
|
||||
{
|
||||
++current;
|
||||
auto it = std::find_if(current, end, pred);
|
||||
if (it == end && wrap)
|
||||
{
|
||||
it = std::find_if(begin, current, pred);
|
||||
if (it == current)
|
||||
it = end;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
template <typename ItemT, typename PredicateT>
|
||||
void searchForward(NC::Menu<ItemT> &m, const PredicateT &pred, bool wrap)
|
||||
{
|
||||
if (!pred.defined())
|
||||
return;
|
||||
auto it = wrappedSearch(m.begin(), m.currentI(), m.end(), pred, wrap);
|
||||
if (it != m.end())
|
||||
m.highlight(it-m.begin());
|
||||
}
|
||||
|
||||
template <typename ItemT, typename PredicateT>
|
||||
void searchBackward(NC::Menu<ItemT> &m, const PredicateT &pred, bool wrap)
|
||||
{
|
||||
if (!pred.defined())
|
||||
return;
|
||||
auto it = wrappedSearch(m.rbegin(), m.currentRI(), m.rend(), pred, wrap);
|
||||
if (it != m.rend())
|
||||
m.highlight(m.size()-1-(it-m.rbegin()));
|
||||
}
|
||||
|
||||
inline HasColumns *hasColumns(BaseScreen *screen)
|
||||
{
|
||||
return dynamic_cast<HasColumns *>(screen);
|
||||
|
||||
@@ -37,9 +37,9 @@ struct Filterable
|
||||
struct Searchable
|
||||
{
|
||||
virtual bool allowsSearching() = 0;
|
||||
virtual bool search(const std::string &constraint) = 0;
|
||||
virtual void nextFound(bool wrap) = 0;
|
||||
virtual void prevFound(bool wrap) = 0;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) = 0;
|
||||
virtual void findForward(bool wrap) = 0;
|
||||
virtual void findBackward(bool wrap) = 0;
|
||||
};
|
||||
|
||||
struct HasSongs
|
||||
|
||||
@@ -29,10 +29,9 @@
|
||||
#include "display.h"
|
||||
#include "helpers.h"
|
||||
#include "global.h"
|
||||
#include "media_library.h"
|
||||
#include "mpdpp.h"
|
||||
#include "playlist.h"
|
||||
#include "regex_filter.h"
|
||||
#include "media_library.h"
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "utility/comparators.h"
|
||||
@@ -256,7 +255,6 @@ void MediaLibrary::update()
|
||||
{
|
||||
if (Albums.reallyEmpty() || m_albums_update_request)
|
||||
{
|
||||
Albums.clearSearchResults();
|
||||
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)
|
||||
@@ -299,7 +297,6 @@ void MediaLibrary::update()
|
||||
{
|
||||
if (Tags.reallyEmpty() || m_tags_update_request)
|
||||
{
|
||||
Tags.clearSearchResults();
|
||||
m_tags_update_request = false;
|
||||
std::map<std::string, time_t> tags;
|
||||
if (Config.media_library_sort_by_mtime)
|
||||
@@ -346,7 +343,6 @@ void MediaLibrary::update()
|
||||
&& ((Albums.reallyEmpty() && Global::Timer - m_timer > m_fetching_delay) || m_albums_update_request)
|
||||
)
|
||||
{
|
||||
Albums.clearSearchResults();
|
||||
m_albums_update_request = false;
|
||||
auto &primary_tag = Tags.current().value().tag();
|
||||
Mpd.StartSearch(true);
|
||||
@@ -395,7 +391,6 @@ void MediaLibrary::update()
|
||||
&& ((Songs.reallyEmpty() && Global::Timer - m_timer > m_fetching_delay) || m_songs_update_request)
|
||||
)
|
||||
{
|
||||
Songs.clearSearchResults();
|
||||
m_songs_update_request = false;
|
||||
auto &album = Albums.current().value();
|
||||
Mpd.StartSearch(true);
|
||||
@@ -640,66 +635,63 @@ bool MediaLibrary::allowsSearching()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MediaLibrary::search(const std::string &constraint)
|
||||
bool MediaLibrary::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
Tags.clearSearchResults();
|
||||
m_tags_search_predicate.clear();
|
||||
else if (isActiveWindow(Albums))
|
||||
Albums.clearSearchResults();
|
||||
m_albums_search_predicate.clear();
|
||||
else if (isActiveWindow(Songs))
|
||||
Songs.clearSearchResults();
|
||||
m_songs_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
bool result = false;
|
||||
if (isActiveWindow(Tags))
|
||||
{
|
||||
auto rx = RegexFilter<PrimaryTag>(
|
||||
boost::regex(constraint, Config.regex_type), TagEntryMatcher);
|
||||
result = Tags.search(Tags.begin(), Tags.end(), rx);
|
||||
m_tags_search_predicate = RegexFilter<PrimaryTag>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
TagEntryMatcher
|
||||
);
|
||||
}
|
||||
else if (isActiveWindow(Albums))
|
||||
{
|
||||
auto fun = boost::bind(AlbumEntryMatcher, _1, _2, false);
|
||||
auto rx = RegexItemFilter<AlbumEntry>(
|
||||
boost::regex(constraint, Config.regex_type), fun);
|
||||
result = Albums.search(Albums.begin(), Albums.end(), rx);
|
||||
m_albums_search_predicate = RegexItemFilter<AlbumEntry>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
boost::bind(AlbumEntryMatcher, _1, _2, false)
|
||||
);
|
||||
}
|
||||
else if (isActiveWindow(Songs))
|
||||
{
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type), SongEntryMatcher);
|
||||
result = Songs.search(Songs.begin(), Songs.end(), rx);
|
||||
m_songs_search_predicate = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
SongEntryMatcher
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaLibrary::nextFound(bool wrap)
|
||||
void MediaLibrary::findForward(bool wrap)
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
Tags.nextFound(wrap);
|
||||
searchForward(Tags, m_tags_search_predicate, wrap);
|
||||
else if (isActiveWindow(Albums))
|
||||
Albums.nextFound(wrap);
|
||||
searchForward(Albums, m_albums_search_predicate, wrap);
|
||||
else if (isActiveWindow(Songs))
|
||||
Songs.nextFound(wrap);
|
||||
searchForward(Songs, m_songs_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void MediaLibrary::prevFound(bool wrap)
|
||||
void MediaLibrary::findBackward(bool wrap)
|
||||
{
|
||||
if (isActiveWindow(Tags))
|
||||
Tags.prevFound(wrap);
|
||||
searchBackward(Tags, m_tags_search_predicate, wrap);
|
||||
else if (isActiveWindow(Albums))
|
||||
Albums.prevFound(wrap);
|
||||
searchBackward(Albums, m_albums_search_predicate, wrap);
|
||||
else if (isActiveWindow(Songs))
|
||||
Songs.prevFound(wrap);
|
||||
searchBackward(Songs, m_songs_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct MediaLibrary: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Searchable, Tabbable
|
||||
@@ -54,9 +55,9 @@ struct MediaLibrary: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Sea
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -153,6 +154,11 @@ private:
|
||||
|
||||
const int m_window_timeout;
|
||||
const boost::posix_time::time_duration m_fetching_delay;
|
||||
|
||||
RegexFilter<PrimaryTag> m_tags_search_predicate;
|
||||
RegexItemFilter<AlbumEntry> m_albums_search_predicate;
|
||||
RegexFilter<MPD::Song> m_songs_search_predicate;
|
||||
|
||||
};
|
||||
|
||||
extern MediaLibrary *myLibrary;
|
||||
|
||||
71
src/menu.h
71
src/menu.h
@@ -176,26 +176,11 @@ public:
|
||||
|
||||
void applyCurrentFilter(ConstIterator first, ConstIterator last);
|
||||
|
||||
bool search(ConstIterator first, ConstIterator last, const FilterFunction &f);
|
||||
|
||||
/// Clears filter results
|
||||
void clearFilterResults();
|
||||
|
||||
void clearFilter();
|
||||
|
||||
/// Clears search results
|
||||
void clearSearchResults();
|
||||
|
||||
/// Moves current position in the list to the next found one
|
||||
/// @param wrap if true, this function will go to the first
|
||||
/// found pos after the last one, otherwise it'll do nothing.
|
||||
void nextFound(bool wrap);
|
||||
|
||||
/// Moves current position in the list to the previous found one
|
||||
/// @param wrap if true, this function will go to the last
|
||||
/// found pos after the first one, otherwise it'll do nothing.
|
||||
void prevFound(bool wrap);
|
||||
|
||||
/// @return const reference to currently used filter function
|
||||
const FilterFunction &getFilter() { return m_filter; }
|
||||
|
||||
@@ -306,8 +291,13 @@ public:
|
||||
|
||||
Iterator currentI() { return Iterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstIterator currentI() const { return ConstIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ReverseIterator currentRI() { return ReverseIterator(++currentI()); }
|
||||
ConstReverseIterator currentRI() const { return ReverseIterator(++currentI()); }
|
||||
|
||||
ValueIterator currentVI() { return ValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ConstValueIterator currentVI() const { return ConstValueIterator(m_options_ptr->begin() + m_highlight); }
|
||||
ReverseValueIterator currentRVI() { return ReverseValueIterator(++currentVI()); }
|
||||
ConstReverseValueIterator currentRVI() const { return ConstReverseValueIterator(++currentVI()); }
|
||||
|
||||
Iterator begin() { return Iterator(m_options_ptr->begin()); }
|
||||
ConstIterator begin() const { return ConstIterator(m_options_ptr->begin()); }
|
||||
@@ -360,7 +350,6 @@ private:
|
||||
std::vector<ItemProxy> *m_options_ptr;
|
||||
std::vector<ItemProxy> m_options;
|
||||
std::vector<ItemProxy> m_filtered_options;
|
||||
std::set<size_t> m_found_positions;
|
||||
|
||||
size_t m_beginning;
|
||||
size_t m_highlight;
|
||||
@@ -403,7 +392,6 @@ Menu<ItemT>::Menu(const Menu &rhs)
|
||||
, m_item_displayer(rhs.m_item_displayer)
|
||||
, m_filter(rhs.m_filter)
|
||||
, m_searcher(rhs.m_searcher)
|
||||
, m_found_positions(rhs.m_found_positions)
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
@@ -430,7 +418,6 @@ Menu<ItemT>::Menu(Menu &&rhs)
|
||||
, m_searcher(rhs.m_searcher)
|
||||
, m_options(std::move(rhs.m_options))
|
||||
, m_filtered_options(std::move(rhs.m_filtered_options))
|
||||
, m_found_positions(std::move(rhs.m_found_positions))
|
||||
, m_beginning(rhs.m_beginning)
|
||||
, m_highlight(rhs.m_highlight)
|
||||
, m_highlight_color(rhs.m_highlight_color)
|
||||
@@ -456,7 +443,6 @@ Menu<ItemT> &Menu<ItemT>::operator=(Menu rhs)
|
||||
std::swap(m_searcher, rhs.m_searcher);
|
||||
std::swap(m_options, rhs.m_options);
|
||||
std::swap(m_filtered_options, rhs.m_filtered_options);
|
||||
std::swap(m_found_positions, rhs.m_found_positions);
|
||||
std::swap(m_beginning, rhs.m_beginning);
|
||||
std::swap(m_highlight, rhs.m_highlight);
|
||||
std::swap(m_highlight_color, rhs.m_highlight_color);
|
||||
@@ -705,7 +691,6 @@ void Menu<ItemT>::clear()
|
||||
{
|
||||
clearFilterResults();
|
||||
m_options.clear();
|
||||
m_found_positions.clear();
|
||||
m_options_ptr = &m_options;
|
||||
}
|
||||
|
||||
@@ -764,52 +749,6 @@ void Menu<ItemT>::clearFilter()
|
||||
m_filter = 0;
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
bool Menu<ItemT>::search(ConstIterator first, ConstIterator last, const FilterFunction &f)
|
||||
{
|
||||
m_found_positions.clear();
|
||||
m_searcher = f;
|
||||
for (auto it = first; it != last; ++it)
|
||||
{
|
||||
if (m_searcher(*it))
|
||||
{
|
||||
size_t pos = it-begin();
|
||||
m_found_positions.insert(pos);
|
||||
}
|
||||
}
|
||||
return !m_found_positions.empty();
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::clearSearchResults()
|
||||
{
|
||||
m_found_positions.clear();
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::nextFound(bool wrap)
|
||||
{
|
||||
if (m_found_positions.empty())
|
||||
return;
|
||||
auto next = m_found_positions.upper_bound(m_highlight);
|
||||
if (next != m_found_positions.end())
|
||||
highlight(*next);
|
||||
else if (wrap)
|
||||
highlight(*m_found_positions.begin());
|
||||
}
|
||||
|
||||
template <typename ItemT>
|
||||
void Menu<ItemT>::prevFound(bool wrap)
|
||||
{
|
||||
if (m_found_positions.empty())
|
||||
return;
|
||||
auto prev = m_found_positions.lower_bound(m_highlight);
|
||||
if (prev != m_found_positions.begin())
|
||||
highlight(*--prev);
|
||||
else if (wrap)
|
||||
highlight(*m_found_positions.rbegin());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_MENU_H
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "helpers.h"
|
||||
#include "menu.h"
|
||||
#include "playlist.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen_switcher.h"
|
||||
#include "song.h"
|
||||
#include "status.h"
|
||||
@@ -184,33 +183,30 @@ bool Playlist::allowsSearching()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Playlist::search(const std::string &constraint)
|
||||
bool Playlist::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
w.clearSearchResults();
|
||||
m_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type), playlistEntryMatcher);
|
||||
return w.search(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
m_search_predicate = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type), playlistEntryMatcher
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void Playlist::nextFound(bool wrap)
|
||||
void Playlist::findForward(bool wrap)
|
||||
{
|
||||
w.nextFound(wrap);
|
||||
searchForward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void Playlist::prevFound(bool wrap)
|
||||
void Playlist::findBackward(bool wrap)
|
||||
{
|
||||
w.prevFound(wrap);
|
||||
searchBackward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
#include "song.h"
|
||||
|
||||
@@ -54,9 +55,9 @@ struct Playlist: Screen<NC::Menu<MPD::Song>>, Filterable, HasSongs, Searchable,
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching();
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -100,6 +101,8 @@ private:
|
||||
|
||||
bool m_reload_total_length;
|
||||
bool m_reload_remaining;
|
||||
|
||||
RegexFilter<MPD::Song> m_search_predicate;
|
||||
};
|
||||
|
||||
extern Playlist *myPlaylist;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "playlist.h"
|
||||
#include "playlist_editor.h"
|
||||
#include "mpdpp.h"
|
||||
#include "regex_filter.h"
|
||||
#include "status.h"
|
||||
#include "statusbar.h"
|
||||
#include "tag_editor.h"
|
||||
@@ -138,7 +137,6 @@ void PlaylistEditor::update()
|
||||
if (Playlists.reallyEmpty() || m_playlists_update_requested)
|
||||
{
|
||||
m_playlists_update_requested = false;
|
||||
Playlists.clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(Playlists, [this]() {
|
||||
size_t idx = 0;
|
||||
for (MPD::PlaylistIterator it = Mpd.GetPlaylists(), end; it != end; ++it, ++idx)
|
||||
@@ -164,7 +162,6 @@ void PlaylistEditor::update()
|
||||
Content.clear();
|
||||
else
|
||||
{
|
||||
Content.clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(Content, [this]() {
|
||||
size_t idx = 0;
|
||||
MPD::SongIterator s = Mpd.GetPlaylistContent(Playlists.current().value().path()), end;
|
||||
@@ -403,53 +400,50 @@ bool PlaylistEditor::allowsSearching()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlaylistEditor::search(const std::string &constraint)
|
||||
bool PlaylistEditor::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
Playlists.clearSearchResults();
|
||||
m_playlists_search_predicate.clear();
|
||||
else if (isActiveWindow(Content))
|
||||
Content.clearSearchResults();
|
||||
m_content_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
bool result = false;
|
||||
if (isActiveWindow(Playlists))
|
||||
{
|
||||
auto rx = RegexFilter<MPD::Playlist>(
|
||||
boost::regex(constraint, Config.regex_type), PlaylistEntryMatcher);
|
||||
result = Playlists.search(Playlists.begin(), Playlists.end(), rx);
|
||||
m_playlists_search_predicate = RegexFilter<MPD::Playlist>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
PlaylistEntryMatcher
|
||||
);
|
||||
}
|
||||
else if (isActiveWindow(Content))
|
||||
{
|
||||
auto rx = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type), SongEntryMatcher);
|
||||
result = Content.search(Content.begin(), Content.end(), rx);
|
||||
m_content_search_predicate = RegexFilter<MPD::Song>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
SongEntryMatcher
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void PlaylistEditor::nextFound(bool wrap)
|
||||
void PlaylistEditor::findForward(bool wrap)
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
Playlists.nextFound(wrap);
|
||||
searchForward(Playlists, m_playlists_search_predicate, wrap);
|
||||
else if (isActiveWindow(Content))
|
||||
Content.nextFound(wrap);
|
||||
searchForward(Content, m_content_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void PlaylistEditor::prevFound(bool wrap)
|
||||
void PlaylistEditor::findBackward(bool wrap)
|
||||
{
|
||||
if (isActiveWindow(Playlists))
|
||||
Playlists.prevFound(wrap);
|
||||
searchBackward(Playlists, m_playlists_search_predicate, wrap);
|
||||
else if (isActiveWindow(Content))
|
||||
Content.prevFound(wrap);
|
||||
searchBackward(Content, m_content_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct PlaylistEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Searchable, Tabbable
|
||||
@@ -54,9 +55,9 @@ struct PlaylistEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, S
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -98,6 +99,9 @@ private:
|
||||
|
||||
const int m_window_timeout;
|
||||
const boost::posix_time::time_duration m_fetching_delay;
|
||||
|
||||
RegexFilter<MPD::Playlist> m_playlists_search_predicate;
|
||||
RegexFilter<MPD::Song> m_content_search_predicate;
|
||||
};
|
||||
|
||||
extern PlaylistEditor *myPlaylistEditor;
|
||||
|
||||
@@ -22,21 +22,35 @@
|
||||
#define NCMPCPP_REGEX_FILTER_H
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <cassert>
|
||||
#include "menu.h"
|
||||
|
||||
template <typename T> struct RegexFilter
|
||||
template <typename T>
|
||||
struct RegexFilter
|
||||
{
|
||||
typedef NC::Menu<T> MenuT;
|
||||
typedef typename NC::Menu<T>::Item Item;
|
||||
typedef std::function<bool(const boost::regex &, const T &)> FilterFunction;
|
||||
|
||||
RegexFilter() { }
|
||||
RegexFilter(boost::regex rx, FilterFunction filter)
|
||||
: m_rx(rx), m_filter(filter) { }
|
||||
|
||||
bool operator()(const Item &item) {
|
||||
: m_rx(std::move(rx)), m_filter(std::move(filter)) { }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_filter = nullptr;
|
||||
}
|
||||
|
||||
bool operator()(const Item &item) const {
|
||||
assert(defined());
|
||||
return m_filter(m_rx, item.value());
|
||||
}
|
||||
|
||||
|
||||
bool defined() const
|
||||
{
|
||||
return m_filter.operator bool();
|
||||
}
|
||||
|
||||
static std::string currentFilter(MenuT &menu)
|
||||
{
|
||||
std::string filter;
|
||||
@@ -57,13 +71,24 @@ template <typename T> struct RegexItemFilter
|
||||
typedef typename NC::Menu<T>::Item Item;
|
||||
typedef std::function<bool(const boost::regex &, const Item &)> FilterFunction;
|
||||
|
||||
RegexItemFilter() { }
|
||||
RegexItemFilter(boost::regex rx, FilterFunction filter)
|
||||
: m_rx(rx), m_filter(filter) { }
|
||||
: m_rx(std::move(rx)), m_filter(std::move(filter)) { }
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_filter = nullptr;
|
||||
}
|
||||
|
||||
bool operator()(const Item &item) {
|
||||
return m_filter(m_rx, item);
|
||||
}
|
||||
|
||||
bool defined() const
|
||||
{
|
||||
return m_filter.operator bool();
|
||||
}
|
||||
|
||||
static std::string currentFilter(MenuT &menu)
|
||||
{
|
||||
std::string filter;
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "global.h"
|
||||
#include "helpers.h"
|
||||
#include "playlist.h"
|
||||
#include "regex_filter.h"
|
||||
#include "search_engine.h"
|
||||
#include "settings.h"
|
||||
#include "status.h"
|
||||
@@ -293,34 +292,31 @@ bool SearchEngine::allowsSearching()
|
||||
return w.back().value().isSong();
|
||||
}
|
||||
|
||||
bool SearchEngine::search(const std::string &constraint)
|
||||
bool SearchEngine::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
w.clearSearchResults();
|
||||
m_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
auto fun = boost::bind(SEItemEntryMatcher, _1, _2, false);
|
||||
auto rx = RegexItemFilter<SEItem>(
|
||||
boost::regex(constraint, Config.regex_type), fun);
|
||||
return w.search(w.begin(), w.end(), rx);
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
m_search_predicate = RegexItemFilter<SEItem>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
boost::bind(SEItemEntryMatcher, _1, _2, false)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void SearchEngine::nextFound(bool wrap)
|
||||
void SearchEngine::findForward(bool wrap)
|
||||
{
|
||||
w.nextFound(wrap);
|
||||
searchForward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void SearchEngine::prevFound(bool wrap)
|
||||
void SearchEngine::findBackward(bool wrap)
|
||||
{
|
||||
w.prevFound(wrap);
|
||||
searchBackward(w, m_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -25,9 +25,56 @@
|
||||
|
||||
#include "interfaces.h"
|
||||
#include "mpdpp.h"
|
||||
#include "regex_filter.h"
|
||||
#include "screen.h"
|
||||
|
||||
struct SearchEngine: Screen<NC::Menu<struct SEItem>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
struct SEItem
|
||||
{
|
||||
SEItem() : m_is_song(false), m_buffer(0) { }
|
||||
SEItem(NC::Buffer *buf) : m_is_song(false), m_buffer(buf) { }
|
||||
SEItem(const MPD::Song &s) : m_is_song(true), m_song(s) { }
|
||||
SEItem(const SEItem &ei) { *this = ei; }
|
||||
~SEItem() {
|
||||
if (!m_is_song)
|
||||
delete m_buffer;
|
||||
}
|
||||
|
||||
NC::Buffer &mkBuffer() {
|
||||
assert(!m_is_song);
|
||||
delete m_buffer;
|
||||
m_buffer = new NC::Buffer();
|
||||
return *m_buffer;
|
||||
}
|
||||
|
||||
bool isSong() const { return m_is_song; }
|
||||
|
||||
NC::Buffer &buffer() { assert(!m_is_song && m_buffer); return *m_buffer; }
|
||||
MPD::Song &song() { assert(m_is_song); return m_song; }
|
||||
|
||||
const NC::Buffer &buffer() const { assert(!m_is_song && m_buffer); return *m_buffer; }
|
||||
const MPD::Song &song() const { assert(m_is_song); return m_song; }
|
||||
|
||||
SEItem &operator=(const SEItem &se) {
|
||||
if (this == &se)
|
||||
return *this;
|
||||
m_is_song = se.m_is_song;
|
||||
if (se.m_is_song)
|
||||
m_song = se.m_song;
|
||||
else if (se.m_buffer)
|
||||
m_buffer = new NC::Buffer(*se.m_buffer);
|
||||
else
|
||||
m_buffer = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_is_song;
|
||||
|
||||
NC::Buffer *m_buffer;
|
||||
MPD::Song m_song;
|
||||
};
|
||||
|
||||
struct SearchEngine: Screen<NC::Menu<SEItem>>, Filterable, HasSongs, Searchable, Tabbable
|
||||
{
|
||||
SearchEngine();
|
||||
|
||||
@@ -53,9 +100,9 @@ struct SearchEngine: Screen<NC::Menu<struct SEItem>>, Filterable, HasSongs, Sear
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -77,6 +124,8 @@ protected:
|
||||
private:
|
||||
void Prepare();
|
||||
void Search();
|
||||
|
||||
RegexItemFilter<SEItem> m_search_predicate;
|
||||
|
||||
const char **SearchMode;
|
||||
|
||||
@@ -89,52 +138,6 @@ private:
|
||||
static bool MatchToPattern;
|
||||
};
|
||||
|
||||
struct SEItem
|
||||
{
|
||||
SEItem() : m_is_song(false), m_buffer(0) { }
|
||||
SEItem(NC::Buffer *buf) : m_is_song(false), m_buffer(buf) { }
|
||||
SEItem(const MPD::Song &s) : m_is_song(true), m_song(s) { }
|
||||
SEItem(const SEItem &ei) { *this = ei; }
|
||||
~SEItem() {
|
||||
if (!m_is_song)
|
||||
delete m_buffer;
|
||||
}
|
||||
|
||||
NC::Buffer &mkBuffer() {
|
||||
assert(!m_is_song);
|
||||
delete m_buffer;
|
||||
m_buffer = new NC::Buffer();
|
||||
return *m_buffer;
|
||||
}
|
||||
|
||||
bool isSong() const { return m_is_song; }
|
||||
|
||||
NC::Buffer &buffer() { assert(!m_is_song && m_buffer); return *m_buffer; }
|
||||
MPD::Song &song() { assert(m_is_song); return m_song; }
|
||||
|
||||
const NC::Buffer &buffer() const { assert(!m_is_song && m_buffer); return *m_buffer; }
|
||||
const MPD::Song &song() const { assert(m_is_song); return m_song; }
|
||||
|
||||
SEItem &operator=(const SEItem &se) {
|
||||
if (this == &se)
|
||||
return *this;
|
||||
m_is_song = se.m_is_song;
|
||||
if (se.m_is_song)
|
||||
m_song = se.m_song;
|
||||
else if (se.m_buffer)
|
||||
m_buffer = new NC::Buffer(*se.m_buffer);
|
||||
else
|
||||
m_buffer = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_is_song;
|
||||
|
||||
NC::Buffer *m_buffer;
|
||||
MPD::Song m_song;
|
||||
};
|
||||
|
||||
extern SearchEngine *mySearcher;
|
||||
|
||||
#endif // NCMPCPP_SEARCH_ENGINE_H
|
||||
|
||||
@@ -387,7 +387,6 @@ int Status::State::volume()
|
||||
|
||||
void Status::Changes::playlist(unsigned previous_version)
|
||||
{
|
||||
myPlaylist->main().clearSearchResults();
|
||||
withUnfilteredMenuReapplyFilter(myPlaylist->main(), [previous_version]() {
|
||||
if (m_playlist_length < myPlaylist->main().size())
|
||||
{
|
||||
|
||||
@@ -775,54 +775,50 @@ bool TagEditor::allowsSearching()
|
||||
return w == Dirs || w == Tags;
|
||||
}
|
||||
|
||||
bool TagEditor::search(const std::string &constraint)
|
||||
bool TagEditor::setSearchConstraint(const std::string &constraint)
|
||||
{
|
||||
if (constraint.empty())
|
||||
{
|
||||
if (w == Dirs)
|
||||
Dirs->clearSearchResults();
|
||||
m_directories_search_predicate.clear();
|
||||
else if (w == Tags)
|
||||
Tags->clearSearchResults();
|
||||
m_songs_search_predicate.clear();
|
||||
return false;
|
||||
}
|
||||
try
|
||||
else
|
||||
{
|
||||
bool result = false;
|
||||
if (w == Dirs)
|
||||
{
|
||||
auto fun = boost::bind(DirEntryMatcher, _1, _2, false);
|
||||
auto rx = RegexFilter< std::pair<std::string, std::string> >(
|
||||
boost::regex(constraint, Config.regex_type), fun);
|
||||
result = Dirs->search(Dirs->begin(), Dirs->end(), rx);
|
||||
m_directories_search_predicate = RegexFilter<std::pair<std::string, std::string>>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
boost::bind(DirEntryMatcher, _1, _2, false)
|
||||
);
|
||||
}
|
||||
else if (w == Tags)
|
||||
{
|
||||
auto rx = RegexFilter<MPD::MutableSong>(
|
||||
boost::regex(constraint, Config.regex_type), SongEntryMatcher);
|
||||
result = Tags->search(Tags->begin(), Tags->end(), rx);
|
||||
m_songs_search_predicate = RegexFilter<MPD::MutableSong>(
|
||||
boost::regex(constraint, Config.regex_type),
|
||||
SongEntryMatcher
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (boost::bad_expression &)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void TagEditor::nextFound(bool wrap)
|
||||
void TagEditor::findForward(bool wrap)
|
||||
{
|
||||
if (w == Dirs)
|
||||
Dirs->nextFound(wrap);
|
||||
searchForward(*Dirs, m_directories_search_predicate, wrap);
|
||||
else if (w == Tags)
|
||||
Tags->nextFound(wrap);
|
||||
searchForward(*Tags, m_songs_search_predicate, wrap);
|
||||
}
|
||||
|
||||
void TagEditor::prevFound(bool wrap)
|
||||
void TagEditor::findBackward(bool wrap)
|
||||
{
|
||||
if (w == Dirs)
|
||||
Dirs->prevFound(wrap);
|
||||
searchBackward(*Dirs, m_directories_search_predicate, wrap);
|
||||
else if (w == Tags)
|
||||
Tags->prevFound(wrap);
|
||||
searchBackward(*Tags, m_songs_search_predicate, wrap);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
@@ -58,9 +58,9 @@ struct TagEditor: Screen<NC::Window *>, Filterable, HasColumns, HasSongs, Search
|
||||
|
||||
// Searchable implementation
|
||||
virtual bool allowsSearching() OVERRIDE;
|
||||
virtual bool search(const std::string &constraint) OVERRIDE;
|
||||
virtual void nextFound(bool wrap) OVERRIDE;
|
||||
virtual void prevFound(bool wrap) OVERRIDE;
|
||||
virtual bool setSearchConstraint(const std::string &constraint) OVERRIDE;
|
||||
virtual void findForward(bool wrap) OVERRIDE;
|
||||
virtual void findBackward(bool wrap) OVERRIDE;
|
||||
|
||||
// HasSongs implementation
|
||||
virtual ProxySongList proxySongList() OVERRIDE;
|
||||
@@ -100,6 +100,9 @@ private:
|
||||
|
||||
std::string itsBrowsedDir;
|
||||
std::string itsHighlightedDir;
|
||||
|
||||
RegexFilter<std::pair<std::string, std::string>> m_directories_search_predicate;
|
||||
RegexFilter<MPD::MutableSong> m_songs_search_predicate;
|
||||
};
|
||||
|
||||
extern TagEditor *myTagEditor;
|
||||
|
||||
Reference in New Issue
Block a user