menu: remove search related methods

This commit is contained in:
Andrzej Rybczak
2014-11-04 20:53:03 +01:00
parent c01e734e6e
commit 12772c47f9
18 changed files with 306 additions and 290 deletions

View File

@@ -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);
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());
}
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);
switch (direction)
{
case Find::Forward:
w->findForward(Config.wrapped_search);
break;
case Find::Backward:
w->findBackward(Config.wrapped_search);
break;
}
}
void listsChangeFinisher()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) { }
: m_rx(std::move(rx)), m_filter(std::move(filter)) { }
bool operator()(const Item &item) {
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;

View File

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

View File

@@ -25,70 +25,9 @@
#include "interfaces.h"
#include "mpdpp.h"
#include "regex_filter.h"
#include "screen.h"
struct SearchEngine: Screen<NC::Menu<struct SEItem>>, Filterable, HasSongs, Searchable, Tabbable
{
SearchEngine();
// Screen< NC::Menu<SEItem> > implementation
virtual void resize() OVERRIDE;
virtual void switchTo() OVERRIDE;
virtual std::wstring title() OVERRIDE;
virtual ScreenType type() OVERRIDE { return ScreenType::SearchEngine; }
virtual void update() OVERRIDE { }
virtual void enterPressed() OVERRIDE;
virtual void spacePressed() OVERRIDE;
virtual void mouseButtonPressed(MEVENT me) OVERRIDE;
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 search(const std::string &constraint) OVERRIDE;
virtual void nextFound(bool wrap) OVERRIDE;
virtual void prevFound(bool wrap) OVERRIDE;
// HasSongs implementation
virtual ProxySongList proxySongList() OVERRIDE;
virtual bool allowsSelection() OVERRIDE;
virtual void reverseSelection() OVERRIDE;
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
// private members
void reset();
static size_t StaticOptions;
static size_t SearchButton;
static size_t ResetButton;
protected:
virtual bool isLockable() OVERRIDE { return true; }
private:
void Prepare();
void Search();
const char **SearchMode;
static const char *SearchModes[];
static const size_t ConstraintsNumber = 11;
static const char *ConstraintsNames[];
std::string itsConstraints[ConstraintsNumber];
static bool MatchToPattern;
};
struct SEItem
{
SEItem() : m_is_song(false), m_buffer(0) { }
@@ -135,6 +74,70 @@ private:
MPD::Song m_song;
};
struct SearchEngine: Screen<NC::Menu<SEItem>>, Filterable, HasSongs, Searchable, Tabbable
{
SearchEngine();
// Screen< NC::Menu<SEItem> > implementation
virtual void resize() OVERRIDE;
virtual void switchTo() OVERRIDE;
virtual std::wstring title() OVERRIDE;
virtual ScreenType type() OVERRIDE { return ScreenType::SearchEngine; }
virtual void update() OVERRIDE { }
virtual void enterPressed() OVERRIDE;
virtual void spacePressed() OVERRIDE;
virtual void mouseButtonPressed(MEVENT me) OVERRIDE;
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;
virtual void findForward(bool wrap) OVERRIDE;
virtual void findBackward(bool wrap) OVERRIDE;
// HasSongs implementation
virtual ProxySongList proxySongList() OVERRIDE;
virtual bool allowsSelection() OVERRIDE;
virtual void reverseSelection() OVERRIDE;
virtual std::vector<MPD::Song> getSelectedSongs() OVERRIDE;
// private members
void reset();
static size_t StaticOptions;
static size_t SearchButton;
static size_t ResetButton;
protected:
virtual bool isLockable() OVERRIDE { return true; }
private:
void Prepare();
void Search();
RegexItemFilter<SEItem> m_search_predicate;
const char **SearchMode;
static const char *SearchModes[];
static const size_t ConstraintsNumber = 11;
static const char *ConstraintsNames[];
std::string itsConstraints[ConstraintsNumber];
static bool MatchToPattern;
};
extern SearchEngine *mySearcher;
#endif // NCMPCPP_SEARCH_ENGINE_H

View File

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

View File

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

View File

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