X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fscreen_search.c;h=1465602ed2537fe49178acebb64cf99f2504c2ca;hb=e52df3dd5be37471c4fceceb683479bd81bdec27;hp=365a23c6f77413520b2383ba50e183c400e72d84;hpb=cde030e211b3d9ea517403b5d5547b6d374fc470;p=ncmpc.git diff --git a/src/screen_search.c b/src/screen_search.c index 365a23c..1465602 100644 --- a/src/screen_search.c +++ b/src/screen_search.c @@ -1,7 +1,6 @@ -/* - * $Id$ - * - * (c) 2004 by Kalle Wallin +/* ncmpc (Ncurses MPD Client) + * (c) 2004-2017 The Music Player Daemon Project + * Project homepage: http://musicpd.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -12,95 +11,76 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "config.h" - -#ifndef DISABLE_SEARCH_SCREEN -#include "ncmpc.h" +#include "screen_search.h" +#include "screen_interface.h" +#include "screen_status.h" +#include "screen.h" +#include "i18n.h" #include "options.h" -#include "support.h" +#include "charset.h" #include "mpdclient.h" #include "strfsong.h" -#include "command.h" -#include "screen.h" #include "utils.h" #include "screen_utils.h" #include "screen_browser.h" -#include "gcc.h" +#include "filelist.h" -#include -#include #include #include -#include -/* new search stuff with qball's libmpdclient */ -#define FUTURE - -#ifdef FUTURE - -extern gint mpdclient_finish_command(mpdclient_t *c); +enum { + SEARCH_URI = MPD_TAG_COUNT + 100, + SEARCH_ARTIST_TITLE +}; -typedef struct { - int id; +static const struct { const char *name; const char *localname; -} search_tag_t; - -static search_tag_t search_tag[] = { - { MPD_TAG_ITEM_ARTIST, "artist", N_("artist") }, - { MPD_TAG_ITEM_ALBUM, "album", N_("album") }, - { MPD_TAG_ITEM_TITLE, "title", N_("title") }, - { MPD_TAG_ITEM_TRACK, "track", N_("track") }, - { MPD_TAG_ITEM_NAME, "name", N_("name") }, - { MPD_TAG_ITEM_GENRE, "genre", N_("genre") }, - { MPD_TAG_ITEM_DATE, "date", N_("date") }, - { MPD_TAG_ITEM_COMPOSER, "composer", N_("composer") }, - { MPD_TAG_ITEM_PERFORMER, "performer", N_("performer") }, - { MPD_TAG_ITEM_COMMENT, "comment", N_("comment") }, - { MPD_TAG_ITEM_FILENAME, "filename", N_("file") }, - { -1, NULL, NULL } +} search_tag[MPD_TAG_COUNT] = { + [MPD_TAG_ARTIST] = { "artist", N_("artist") }, + [MPD_TAG_ALBUM] = { "album", N_("album") }, + [MPD_TAG_TITLE] = { "title", N_("title") }, + [MPD_TAG_TRACK] = { "track", N_("track") }, + [MPD_TAG_NAME] = { "name", N_("name") }, + [MPD_TAG_GENRE] = { "genre", N_("genre") }, + [MPD_TAG_DATE] = { "date", N_("date") }, + [MPD_TAG_COMPOSER] = { "composer", N_("composer") }, + [MPD_TAG_PERFORMER] = { "performer", N_("performer") }, + [MPD_TAG_COMMENT] = { "comment", N_("comment") }, }; static int -search_get_tag_id(char *name) +search_get_tag_id(const char *name) { - int i = 0; + if (g_ascii_strcasecmp(name, "file") == 0 || + strcasecmp(name, _("file")) == 0) + return SEARCH_URI; - while (search_tag[i].name) { - if (strcasecmp(search_tag[i].name, name) == 0 || - strcasecmp(search_tag[i].localname, name) == 0) - return search_tag[i].id; - i++; - } + for (unsigned i = 0; i < MPD_TAG_COUNT; ++i) + if (search_tag[i].name != NULL && + (strcasecmp(search_tag[i].name, name) == 0 || + strcasecmp(search_tag[i].localname, name) == 0)) + return i; return -1; } -#endif - -#define SEARCH_TITLE 0 -#define SEARCH_ARTIST 1 -#define SEARCH_ALBUM 2 -#define SEARCH_FILE 3 - -#define SEARCH_ARTIST_TITLE 999 - typedef struct { - int table; + enum mpd_tag_type table; const char *label; } search_type_t; static search_type_t mode[] = { - { MPD_TABLE_TITLE, N_("Title") }, - { MPD_TABLE_ARTIST, N_("Artist") }, - { MPD_TABLE_ALBUM, N_("Album") }, - { MPD_TABLE_FILENAME, N_("Filename") }, + { MPD_TAG_TITLE, N_("Title") }, + { MPD_TAG_ARTIST, N_("Artist") }, + { MPD_TAG_ALBUM, N_("Album") }, + { SEARCH_URI, N_("Filename") }, { SEARCH_ARTIST_TITLE, N_("Artist + Title") }, { 0, NULL } }; @@ -111,50 +91,25 @@ static gboolean advanced_search_mode = FALSE; static struct screen_browser browser; +static const char *const help_text[] = { + "Quick - Enter a string and ncmpc will search according", + " to the current search mode (displayed above).", + "", + "Advanced - : [:...]", + " Example: artist:radiohead album:pablo honey", + "", + " Available tags: artist, album, title, track,", + " name, genre, date composer, performer, comment, file", + "", +}; /* search info */ static const char * -lw_search_help_callback(unsigned idx, mpd_unused int *highlight, - mpd_unused void *data) +lw_search_help_callback(unsigned idx, gcc_unused void *data) { - unsigned text_rows; - static const char *text[] = { - "Quick - just enter a string and ncmpc will search according", - " to the current search mode (displayed above).", - "", - "Advanced - : [:...]", - " Example: artist:radiohead album:pablo honey", - "", - " avalible tags: artist, album, title, track,", - " name, genre, date composer, performer, comment, file", - "", - NULL - }; - - text_rows=0; - while (text[text_rows]) - text_rows++; - - if (idx < text_rows) - return text[idx]; - return NULL; -} + assert(idx < G_N_ELEMENTS(help_text)); -/* the playlist have been updated -> fix highlights */ -static void -playlist_changed_callback(mpdclient_t *c, int event, mpd_unused gpointer data) -{ - if (browser.filelist == NULL) - return; - D("screen_search.c> playlist_callback() [%d]\n", event); - switch(event) { - case PLAYLIST_EVENT_CLEAR: - clear_highlights(browser.filelist); - break; - default: - sync_highlights(c, browser.filelist); - break; - } + return help_text[idx]; } /* sanity check search mode value */ @@ -172,13 +127,12 @@ search_check_mode(void) } static void -search_clear(mpd_unused screen_t *screen, mpdclient_t *c, - gboolean clear_pattern) +search_clear(bool clear_pattern) { if (browser.filelist) { - mpdclient_remove_playlist_callback(c, playlist_changed_callback); - mpdclient_filelist_free(browser.filelist); - browser.filelist = NULL; + filelist_free(browser.filelist); + browser.filelist = filelist_new(); + list_window_set_length(browser.lw, 0); } if (clear_pattern && pattern) { g_free(pattern); @@ -186,26 +140,47 @@ search_clear(mpd_unused screen_t *screen, mpdclient_t *c, } } -#ifdef FUTURE -static mpdclient_filelist_t * -filelist_search(mpdclient_t *c, mpd_unused int exact_match, int table, - gchar *local_pattern) +static struct filelist * +search_simple_query(struct mpd_connection *connection, bool exact_match, + int table, gchar *local_pattern) { - mpdclient_filelist_t *list, *list2; + struct filelist *list; + gchar *filter_utf8 = locale_to_utf8(local_pattern); if (table == SEARCH_ARTIST_TITLE) { - list = mpdclient_filelist_search(c, FALSE, MPD_TABLE_ARTIST, - local_pattern); - list2 = mpdclient_filelist_search(c, FALSE, MPD_TABLE_TITLE, - local_pattern); - - list->length += list2->length; - list->list = g_list_concat(list->list, list2->list); - list->list = g_list_sort(list->list, compare_filelistentry_format); - list->updated = TRUE; - } else - list = mpdclient_filelist_search(c, FALSE, table, local_pattern); + mpd_command_list_begin(connection, false); + + mpd_search_db_songs(connection, exact_match); + mpd_search_add_tag_constraint(connection, MPD_OPERATOR_DEFAULT, + MPD_TAG_ARTIST, filter_utf8); + mpd_search_commit(connection); + + mpd_search_db_songs(connection, exact_match); + mpd_search_add_tag_constraint(connection, MPD_OPERATOR_DEFAULT, + MPD_TAG_TITLE, filter_utf8); + mpd_search_commit(connection); + mpd_command_list_end(connection); + + list = filelist_new_recv(connection); + filelist_no_duplicates(list); + } else if (table == SEARCH_URI) { + mpd_search_db_songs(connection, exact_match); + mpd_search_add_uri_constraint(connection, MPD_OPERATOR_DEFAULT, + filter_utf8); + mpd_search_commit(connection); + + list = filelist_new_recv(connection); + } else { + mpd_search_db_songs(connection, exact_match); + mpd_search_add_tag_constraint(connection, MPD_OPERATOR_DEFAULT, + table, filter_utf8); + mpd_search_commit(connection); + + list = filelist_new_recv(connection); + } + + g_free(filter_utf8); return list; } @@ -214,32 +189,22 @@ filelist_search(mpdclient_t *c, mpd_unused int exact_match, int table, * Its ugly and MUST be redesigned before the next release! *----------------------------------------------------------------------- */ -static mpdclient_filelist_t * -search_advanced_query(char *query, mpdclient_t *c) +static struct filelist * +search_advanced_query(struct mpd_connection *connection, char *query) { - int i,j; - char **strv; - int table[10]; - char *arg[10]; - mpdclient_filelist_t *fl = NULL; - advanced_search_mode = FALSE; - if( g_strrstr(query, ":") == NULL ) + if (strchr(query, ':') == NULL) return NULL; - strv = g_strsplit_set(query, ": ", 0); - - i=0; - while (strv[i]) { - D("strv[%d] = \"%s\"\n", i, strv[i]); - i++; - } + char **strv = g_strsplit_set(query, ": ", 0); + int table[10]; memset(table, 0, 10*sizeof(int)); + + char *arg[10]; memset(arg, 0, 10*sizeof(char *)); - i=0; - j=0; + int i = 0, j = 0; while (strv[i] && strlen(strv[i]) > 0 && i < 9) { int id = search_get_tag_id(strv[i]); if (id == -1) { @@ -248,12 +213,10 @@ search_advanced_query(char *query, mpdclient_t *c) arg[j] = g_strdup_printf("%s %s", arg[j], strv[i]); g_free(tmp); } else { - D("Bad search tag %s\n", strv[i]); screen_status_printf(_("Bad search tag %s"), strv[i]); } i++; } else if (strv[i+1] == NULL || strlen(strv[i+1]) == 0) { - D("No argument for search tag %s\n", strv[i]); screen_status_printf(_("No argument for search tag %s"), strv[i]); i++; // j--; @@ -271,101 +234,129 @@ search_advanced_query(char *query, mpdclient_t *c) g_strfreev(strv); + if (!advanced_search_mode || j == 0) { + for (i = 0; arg[i] != NULL; ++i) + g_free(arg[i]); + return NULL; + } - if (advanced_search_mode && j > 0) { - int iter; - mpd_InfoEntity *entity; + /*----------------------------------------------------------------------- + * NOTE (again): This code exists to test a new search ui, + * Its ugly and MUST be redesigned before the next release! + * + the code below should live in mpdclient.c + *----------------------------------------------------------------------- + */ + /** stupid - but this is just a test...... (fulhack) */ + mpd_search_db_songs(connection, false); + + for (i = 0; i < 10 && arg[i] != NULL; i++) { + if (table[i] == SEARCH_URI) + mpd_search_add_uri_constraint(connection, + MPD_OPERATOR_DEFAULT, + arg[i]); + else + mpd_search_add_tag_constraint(connection, + MPD_OPERATOR_DEFAULT, + table[i], arg[i]); + } - /*----------------------------------------------------------------------- - * NOTE (again): This code exists to test a new search ui, - * Its ugly and MUST be redesigned before the next release! - * + the code below should live in mpdclient.c - *----------------------------------------------------------------------- - */ - /** stupid - but this is just a test...... (fulhack) */ - mpd_startSearch(c->connection, FALSE); + mpd_search_commit(connection); + struct filelist *fl = filelist_new_recv(connection); + if (!mpd_response_finish(connection)) { + filelist_free(fl); + fl = NULL; + } - for(iter = 0; iter < 10; iter++) { - mpd_addConstraintSearch(c->connection, table[iter], arg[iter]); - } + for (i = 0; arg[i] != NULL; ++i) + g_free(arg[i]); - mpd_commitSearch(c->connection); + return fl; +} - fl = g_malloc0(sizeof(mpdclient_filelist_t)); +static struct filelist * +do_search(struct mpdclient *c, char *query) +{ + struct mpd_connection *connection = mpdclient_get_connection(c); + if (connection == NULL) + return NULL; - while ((entity=mpd_getNextInfoEntity(c->connection))) { - filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t)); + struct filelist *fl = search_advanced_query(connection, query); + if (fl != NULL) + return fl; - entry->entity = entity; - fl->list = g_list_append(fl->list, (gpointer) entry); - fl->length++; - } + if (mpd_connection_get_error(connection) != MPD_ERROR_SUCCESS) { + mpdclient_handle_error(c); + return NULL; + } + + fl = search_simple_query(connection, FALSE, + mode[options.search_mode].table, + query); + if (fl == NULL) + mpdclient_handle_error(c); + return fl; +} - if (mpdclient_finish_command(c) && fl) - mpdclient_filelist_free(fl); +static void +screen_search_reload(struct mpdclient *c) +{ + if (pattern == NULL) + return; - fl->updated = TRUE; + if (browser.filelist != NULL) { + filelist_free(browser.filelist); + browser.filelist = NULL; } - i=0; - while( arg[i] ) - g_free(arg[i++]); + browser.filelist = do_search(c, pattern); + if (browser.filelist == NULL) + browser.filelist = filelist_new(); + list_window_set_length(browser.lw, filelist_length(browser.filelist)); - return fl; + screen_browser_sync_highlights(browser.filelist, &c->playlist); } -#else -#define search_advanced_query(pattern,c) (NULL) -#endif static void -search_new(screen_t *screen, mpdclient_t *c) +search_new(struct mpdclient *c) { - search_clear(screen, c, TRUE); + if (!mpdclient_is_connected(c)) + return; + + search_clear(true); - pattern = screen_readln(screen->status_window.w, - _("Search: "), + g_free(pattern); + pattern = screen_readln(_("Search"), NULL, &search_history, NULL); - if (pattern && strcmp(pattern,"") == 0) { - g_free(pattern); - pattern=NULL; - } - if (pattern == NULL) { list_window_reset(browser.lw); return; } - if (!MPD_VERSION_LT(c, 0, 12, 0)) - browser.filelist = search_advanced_query(pattern, c); - - if (!advanced_search_mode && browser.filelist == NULL) - browser.filelist = filelist_search(c, FALSE, - mode[options.search_mode].table, - pattern); - - sync_highlights(c, browser.filelist); - mpdclient_install_playlist_callback(c, playlist_changed_callback); - list_window_check_selected(browser.lw, browser.filelist->length); + screen_search_reload(c); } - - static void -init(WINDOW *w, int cols, int rows) +screen_search_init(WINDOW *w, int cols, int rows) { browser.lw = list_window_init(w, cols, rows); + if (options.search_format != NULL) { + browser.song_format = options.search_format; + } else { + browser.song_format = options.list_format; + } + list_window_set_length(browser.lw, G_N_ELEMENTS(help_text)); } static void -quit(void) +screen_search_quit(void) { if (search_history) string_list_free(search_history); if (browser.filelist) - mpdclient_filelist_free(browser.filelist); + filelist_free(browser.filelist); list_window_free(browser.lw); if (pattern) { @@ -375,58 +366,36 @@ quit(void) } static void -open(mpd_unused screen_t *screen, mpd_unused mpdclient_t *c) +screen_search_open(gcc_unused struct mpdclient *c) { // if( pattern==NULL ) // search_new(screen, c); // else screen_status_printf(_("Press %s for a new search"), - get_key_names(CMD_SCREEN_SEARCH,0)); + get_key_names(CMD_SCREEN_SEARCH, false)); search_check_mode(); } static void -resize(int cols, int rows) +screen_search_resize(int cols, int rows) { - browser.lw->cols = cols; - browser.lw->rows = rows; + list_window_resize(browser.lw, cols, rows); } static void -paint(mpd_unused screen_t *screen, mpdclient_t *c) +screen_search_paint(void) { - browser.lw->clear = 1; - if (browser.filelist) { - browser.lw->flags = 0; - list_window_paint(browser.lw, browser_lw_callback, browser.filelist); - browser.filelist->updated = FALSE; + browser.lw->hide_cursor = false; + screen_browser_paint(&browser); } else { - browser.lw->flags = LW_HIDE_CURSOR; + browser.lw->hide_cursor = true; list_window_paint(browser.lw, lw_search_help_callback, NULL); - if( !MPD_VERSION_LT(c, 0, 12, 0) ) - g_strdup_printf("Advanced search disabled (MPD version < 0.12.0"); - // wmove(lw->w, 0, 0); - //wclrtobot(lw->w); } - - wnoutrefresh(browser.lw->w); -} - -static void -update(screen_t *screen, mpdclient_t *c) -{ - if (browser.filelist == NULL || browser.filelist->updated) { - paint(screen, c); - return; - } - - list_window_paint(browser.lw, browser_lw_callback, browser.filelist); - wnoutrefresh(browser.lw->w); } static const char * -get_title(char *str, size_t size) +screen_search_get_title(char *str, size_t size) { if (advanced_search_mode && pattern) g_snprintf(str, size, _("Search: %s"), pattern); @@ -437,93 +406,69 @@ get_title(char *str, size_t size) _(mode[options.search_mode].label)); else g_snprintf(str, size, _("Search: Press %s for a new search [%s]"), - get_key_names(CMD_SCREEN_SEARCH,0), + get_key_names(CMD_SCREEN_SEARCH, false), _(mode[options.search_mode].label)); return str; } -static int -search_cmd(screen_t *screen, mpdclient_t *c, command_t cmd) +static void +screen_search_update(struct mpdclient *c) { - switch (cmd) { - case CMD_PLAY: - browser_handle_enter(&browser, c); - return 1; - - case CMD_SELECT: - if (browser_handle_select(&browser, c) == 0) { - /* continue and select next item... */ - cmd = CMD_LIST_NEXT; - } - /* call list_window_cmd to go to the next item */ - return list_window_cmd(browser.lw, browser.filelist->length, cmd); - - case CMD_SELECT_ALL: - browser_handle_select_all(&browser, c); - paint (screen, c); - return 0; + if (browser.filelist != NULL && c->events & MPD_IDLE_QUEUE) { + screen_browser_sync_highlights(browser.filelist, &c->playlist); + screen_search_paint(); + } +} +static bool +screen_search_cmd(struct mpdclient *c, command_t cmd) +{ + switch (cmd) { case CMD_SEARCH_MODE: options.search_mode++; if (mode[options.search_mode].label == NULL) options.search_mode = 0; screen_status_printf(_("Search mode: %s"), _(mode[options.search_mode].label)); - /* continue and update... */ + /* fall through */ case CMD_SCREEN_UPDATE: - if (pattern) { - search_clear(screen, c, FALSE); - browser.filelist = filelist_search(c, - FALSE, - mode[options.search_mode].table, - pattern); - sync_highlights(c, browser.filelist); - } - return 1; + screen_search_reload(c); + screen_search_paint(); + return true; case CMD_SCREEN_SEARCH: - search_new(screen, c); - return 1; + search_new(c); + screen_search_paint(); + return true; case CMD_CLEAR: - search_clear(screen, c, TRUE); + search_clear(true); list_window_reset(browser.lw); - return 1; - - case CMD_LIST_FIND: - case CMD_LIST_RFIND: - case CMD_LIST_FIND_NEXT: - case CMD_LIST_RFIND_NEXT: - if (browser.filelist) - return screen_find(screen, - browser.lw, browser.filelist->length, - cmd, browser_lw_callback, - browser.filelist); - else - return 1; - - case CMD_MOUSE_EVENT: - return browser_handle_mouse_event(&browser, c); + screen_search_paint(); + return true; default: - if (browser.filelist) - return list_window_cmd(browser.lw, - browser.filelist->length, cmd); + break; } - return 0; + if (browser.filelist != NULL && + browser_cmd(&browser, c, cmd)) { + if (screen_is_visible(&screen_search)) + screen_search_paint(); + return true; + } + + return false; } const struct screen_functions screen_search = { - .init = init, - .exit = quit, - .open = open, - .resize = resize, - .paint = paint, - .update = update, - .cmd = search_cmd, - .get_title = get_title, + .init = screen_search_init, + .exit = screen_search_quit, + .open = screen_search_open, + .resize = screen_search_resize, + .paint = screen_search_paint, + .update = screen_search_update, + .cmd = screen_search_cmd, + .get_title = screen_search_get_title, }; - -#endif /* ENABLE_SEARCH_SCREEN */