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