Code

Test new search functionality with qball's version of libmpdclient
authorKalle Wallin <kaw@linux.se>
Thu, 16 Jun 2005 21:08:59 +0000 (21:08 +0000)
committerKalle Wallin <kaw@linux.se>
Thu, 16 Jun 2005 21:08:59 +0000 (21:08 +0000)
git-svn-id: https://svn.musicpd.org/ncmpc/trunk@3360 09075e82-0dd4-0310-85a5-a0d7c8717e4f

src/libmpdclient.c
src/libmpdclient.h
src/screen_search.c

index bc1c1d6e709817eabe932b17672a8a0ff1c5c60a..a8bbabef7bd046a2b3bf0de1992c64e3764c9511 100644 (file)
@@ -31,6 +31,7 @@
 
 */
 
+
 #include "libmpdclient.h"
 
 #include <errno.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <sys/param.h>
+
+
 #include <string.h>
+#include <strings.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <fcntl.h>
+#include <stdarg.h>
 
 #ifndef MPD_NO_IPV6
 #ifdef AF_INET6
 #define COMMAND_LIST   1
 #define COMMAND_LIST_OK        2
 
+char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES] =
+{
+       "Artist",
+       "Album",
+       "Title",
+       "Track",
+       "Name",
+       "Genre",
+       "Date",
+       "Composer",
+       "Performer",
+       "Comment",
+       "filename"
+};
+
+
 #ifdef MPD_HAVE_IPV6        
 int mpd_ipv6Supported() {
         int s;          
@@ -105,8 +126,8 @@ mpd_ReturnElement * mpd_newReturnElement(const char * name, const char * value)
 {
        mpd_ReturnElement * ret = malloc(sizeof(mpd_ReturnElement));
 
-       ret->name = strdup(name);
-       ret->value = strdup(value);
+       ret->name = (char *)strdup(name);
+       ret->value = (char *)strdup(value);
 
        return ret;
 }
@@ -1073,6 +1094,13 @@ char * mpd_getNextReturnElementNamed(mpd_Connection * connection,
        return NULL;
 }
 
+char * mpd_getNextTag(mpd_Connection * connection,int table) {
+       if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
+       {
+               return mpd_getNextReturnElementNamed(connection,mpdTagItemKeys[table]);
+       }
+       return NULL;
+}
 char * mpd_getNextArtist(mpd_Connection * connection) {
        return mpd_getNextReturnElementNamed(connection,"Artist");
 }
@@ -1154,6 +1182,89 @@ void mpd_sendSearchCommand(mpd_Connection * connection, int table,
        free(string);
        free(sanitStr);
 }
+void mpd_sendSearchTagCommand(mpd_Connection *connection, ...)
+{
+       va_list arglist;
+       va_start(arglist, connection);
+       mpd_sendVSearchTagCommand(connection, arglist);
+       va_end(arglist);
+}
+
+void mpd_sendVSearchTagCommand(mpd_Connection * connection, va_list arglist) 
+{
+       char *st, *str;
+       char * string=NULL;
+       int table;
+       char * sanitStr;
+       string = realloc(string,strlen("search")+1);
+       strcpy(string, "search");
+       while((table = va_arg(arglist, int)) != -1)
+       {
+               if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
+               {
+                       st = mpdTagItemKeys[table];
+                       str = va_arg(arglist,char *);
+                       sanitStr = mpd_sanitizeArg(str);
+                       string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
+                       sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
+                       free(sanitStr);
+               }       
+               else {
+                       connection->error = 1;
+                       sprintf(connection->errorStr,"unknown table for search %i",table);
+                       va_end(arglist);
+                       return;
+               }
+       }
+       /* set the last to '\n', should be sufficient space in the string for this */
+       sprintf(string, "%s\n", string);
+       mpd_sendInfoCommand(connection,string);
+       free(string);
+}
+
+
+void mpd_sendFindTagCommand(mpd_Connection *connection, ...)
+{
+       va_list arglist;
+       va_start(arglist, connection);
+       mpd_sendVFindTagCommand(connection, arglist);
+       va_end(arglist);
+}
+
+
+
+
+void mpd_sendVFindTagCommand(mpd_Connection * connection, va_list arglist) 
+{
+       char *st, *str;
+       char * string=NULL;
+       int table;
+       char * sanitStr;
+       string = realloc(string,strlen("find")+1);
+       strcpy(string, "find");
+       while((table = va_arg(arglist, int)) != -1)
+       {
+               if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
+               {
+                       st = mpdTagItemKeys[table];
+                       str = va_arg(arglist,char *);
+                       sanitStr = mpd_sanitizeArg(str);
+                       string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+6);
+                       sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
+                       free(sanitStr);
+               }       
+               else {
+                       connection->error = 1;
+                       sprintf(connection->errorStr,"unknown table for find %i",table);
+                       va_end(arglist);
+                       return;
+               }
+       }
+       /* set the last to '\n', should be sufficient space in the string for this */
+       sprintf(string, "%s\n", string);
+       mpd_sendInfoCommand(connection,string);
+       free(string);
+}
 
 void mpd_sendFindCommand(mpd_Connection * connection, int table, 
                const char * str) 
@@ -1202,6 +1313,53 @@ void mpd_sendListCommand(mpd_Connection * connection, int table,
        free(string);
 }
 
+void mpd_sendListTagCommand(mpd_Connection *connection, int ret_table, ...)
+{
+       va_list arglist;
+       va_start(arglist, ret_table);
+       mpd_sendVListTagCommand(connection, ret_table, arglist);
+       va_end(arglist);
+}
+void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist) 
+{
+       char *st, *str;
+       char * string=NULL;
+       int table;
+       char * sanitStr;
+       if(ret_table < 0 && ret_table >= MPD_TAG_NUM_OF_ITEM_TYPES)
+       {
+               connection->error = 1;
+               sprintf(connection->errorStr,"unknown ret_table for search %i",ret_table);
+               return;
+       }
+
+       string = realloc(string,strlen("list")+3+strlen(mpdTagItemKeys[ret_table]));
+       sprintf(string, "list %s",mpdTagItemKeys[ret_table]);
+       while((table = va_arg(arglist, int)) != -1)
+       {
+               if(table >= 0 && table < MPD_TAG_NUM_OF_ITEM_TYPES)
+               {
+                       st = mpdTagItemKeys[table];
+                       str = va_arg(arglist,char *);
+                       sanitStr = mpd_sanitizeArg(str);
+                       string = realloc(string, strlen(string)+strlen(st)+strlen(sanitStr)+7);
+                       sprintf(string, "%s %s \"%s\"",string,st,sanitStr);
+                       free(sanitStr);
+               }       
+               else {
+                       connection->error = 1;
+                       sprintf(connection->errorStr,"unknown table for search %i",table);
+                       va_end(arglist);
+                       return;
+               }
+       }
+       /* set the last to '\n', should be sufficient space in the string for this */
+       sprintf(string,"%s\n", string);
+       mpd_sendInfoCommand(connection,string);
+       free(string);
+}
+
+
 void mpd_sendAddCommand(mpd_Connection * connection, const char * file) {
        char * sFile = mpd_sanitizeArg(file);
        char * string = malloc(strlen("add")+strlen(sFile)+5);
@@ -1440,7 +1598,7 @@ mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
        mpd_OutputEntity * output = NULL;
 
        if(connection->doneProcessing || (connection->listOks &&
-                       connection->doneListOk))
+                               connection->doneListOk))
        {
                return NULL;
        }
@@ -1472,7 +1630,7 @@ mpd_OutputEntity * mpd_getNextOutput(mpd_Connection * connection) {
                        free(output);
                        return NULL;
                }
-               
+
        }
 
        return output;
index 79a94d8ee3ea5ab35945bc56324de332cd5aa46e..dbbd1019ea19abe60369730d907e9222ea79f8e2 100644 (file)
@@ -35,7 +35,7 @@
 #define LIBMPDCLIENT_H
 
 #include <sys/time.h>
-
+#include <stdarg.h>
 #define MPD_BUFFER_MAX_LENGTH  50000
 #define MPD_WELCOME_MESSAGE    "OK MPD "
 
 extern "C" {
 #endif
 
+
+enum 
+{
+       MPD_TAG_ITEM_ARTIST,
+       MPD_TAG_ITEM_ALBUM,
+       MPD_TAG_ITEM_TITLE,
+       MPD_TAG_ITEM_TRACK,
+       MPD_TAG_ITEM_NAME,
+       MPD_TAG_ITEM_GENRE,
+       MPD_TAG_ITEM_DATE,
+       MPD_TAG_ITEM_COMPOSER,
+       MPD_TAG_ITEM_PERFORMER,
+       MPD_TAG_ITEM_COMMENT,
+       MPD_TAG_ITEM_FILENAME,
+       MPD_TAG_NUM_OF_ITEM_TYPES
+}mpd_TagItems;
+
+
+extern char * mpdTagItemKeys[MPD_TAG_NUM_OF_ITEM_TYPES];
+
 /* internal stuff don't touch this struct */
 typedef struct _mpd_ReturnElement {
        char * name;
@@ -388,21 +408,32 @@ void mpd_sendSearchCommand(mpd_Connection * connection, int table,
 void mpd_sendFindCommand(mpd_Connection * connection, int table, 
                const char * str);
 
+
+void mpd_sendSearchTagCommand(mpd_Connection *connection, ...);
+void mpd_sendFindTagCommand(mpd_Connection *connection, ...);
+void mpd_sendVSearchTagCommand(mpd_Connection *connection, va_list arglist);
+void mpd_sendVFindTagCommand(mpd_Connection *connection, va_list arglist);
 /* LIST TAG COMMANDS */
 
 /* use this function fetch next artist entry, be sure to free the returned 
  * string.  NULL means there are no more.  Best used with sendListArtists
  */
+
 char * mpd_getNextArtist(mpd_Connection * connection);
 
 char * mpd_getNextAlbum(mpd_Connection * connection);
 
+char * mpd_getNextTag(mpd_Connection *connection, int table);
+
 /* list artist or albums by artist, arg1 should be set to the artist if
  * listing albums by a artist, otherwise NULL for listing all artists or albums
  */
 void mpd_sendListCommand(mpd_Connection * connection, int table, 
                const char * arg1);
 
+void mpd_sendListTagCommand(mpd_Connection * connection, int table,...);
+void mpd_sendVListTagCommand(mpd_Connection * connection,int ret_table, va_list arglist);
+
 /* SIMPLE COMMANDS */
 
 void mpd_sendAddCommand(mpd_Connection * connection, const char * file);
index 03ce11ad6370e7d8b83f01cacf31f1886862b966..ebeb2559224c0f808775d1703e2920ffc4edf0d5 100644 (file)
 #include "strfsong.h"
 #include "command.h"
 #include "screen.h"
+#include "utils.h"
 #include "screen_utils.h"
 #include "screen_browse.h"
 
-#define SEARCH_TITLE  0
-#define SEARCH_ARTIST 1
-#define SEARCH_ALBUM  2
-#define SEARCH_FILE   3
+/* new search stuff with qball's libmpdclient */
+#define FUTURE
+
+
+#ifdef FUTURE
+
+typedef struct
+{
+  int id;
+  char *name;
+  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 }
+};
+
+static int
+search_get_tag_id(char *name)
+{
+  int i;
+
+  i=0;
+  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++;
+    }
+  return -1;
+}
+
+#endif
+
+
+#define SEARCH_TITLE    0
+#define SEARCH_ARTIST   1
+#define SEARCH_ALBUM    2
+#define SEARCH_FILE     3
 
 typedef struct {
   int table;
@@ -56,7 +104,44 @@ static search_type_t mode[] = {
 
 static list_window_t *lw = NULL;
 static mpdclient_filelist_t *filelist = NULL;
+static GList *search_history = NULL;
 static gchar *pattern = NULL;
+static gboolean advanced_search_mode = FALSE;
+
+
+/* search info */
+static char *
+lw_search_help_callback(int index, int *highlight, void *data)
+{
+  int text_rows;
+  static char *text[] = {
+    "Welcome to ncmpc's search screen - SVN version.",
+    "",
+    "Quick search - just enter a string and ncmcp will search according",
+    "               to the current search mode (displayed above).",
+    "",
+    "Advanced - bla bla bla.... syntax below",
+    ""
+    " <tag>:<search term> [<tag>:<search term>...]",
+    "",
+    "Example: artist:radiohead album:pablo honey",
+    "",
+    "##### SOMEONE - Write a proper help text, please! #####",
+    "",
+    "avalible tags: artist, album, title, track, name, genre, date",
+    "               composer, performer, comment, file",
+    "",
+    NULL
+  };
+
+  text_rows=0;
+  while( text[text_rows] )
+    text_rows++;
+  
+  if( index < text_rows )
+    return text[index];
+  return NULL;
+}
 
 /* the playlist have been updated -> fix highlights */
 static void 
@@ -105,6 +190,130 @@ search_clear(screen_t *screen, mpdclient_t *c, gboolean clear_pattern)
     }
 }
 
+#ifdef FUTURE
+/*-----------------------------------------------------------------------
+ * NOTE: This code exists to test a new search ui,
+ *       Its ugly and MUST be redesigned before the next release!
+ *-----------------------------------------------------------------------
+ */
+static mpdclient_filelist_t *
+search_advanced_query(char *query, mpdclient_t *c)
+{
+  int i,j;
+  char **strv;
+  int table[10];
+  char *arg[10];
+  mpdclient_filelist_t *filelist = NULL;
+
+  advanced_search_mode = FALSE;
+  if( g_strrstr(query, ":") == NULL )
+    return NULL;
+  
+  strv = g_strsplit_set(query, ": ", 0);
+
+  i=0;
+  while( strv[i] )
+    {
+      D("strv[%d] = \"%s\"\n", i, strv[i]);
+      i++;
+    }
+
+  memset(table, 0, 10*sizeof(int));
+  memset(arg,   0, 10*sizeof(char *));
+
+  i=0;
+  j=0;
+  while( strv[i] && i<9 )
+    {
+      D("strv[%d] = \"%s\"\n", i, strv[i]);
+
+      int id = search_get_tag_id(strv[i]);
+      if( id==-1 )
+       {
+         if( table[j] )
+           {
+             char *tmp = arg[j];
+             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 )
+       {
+         D("No argument for search tag %s\n", strv[i]);
+         screen_status_printf(_("No argument for search tag %s"), strv[i]);
+         i++;
+       }
+      else
+       {
+         table[j] = id;
+         arg[j] = locale_to_utf8(strv[i+1]); // FREE ME
+         j++;
+         table[j] = -1;
+         arg[j] = NULL;
+         i = i + 2;
+         advanced_search_mode = TRUE;
+       }     
+    }
+
+  g_strfreev(strv);
+
+
+  if( advanced_search_mode )
+    {
+      /*-----------------------------------------------------------------------
+       * 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
+       *-----------------------------------------------------------------------
+       */
+      mpd_InfoEntity *entity;
+
+      /** stupid - but this is just a test...... (fulhack)  */
+      mpd_sendSearchTagCommand(c->connection, 
+                              table[0], arg[0],
+                              table[1], arg[1],
+                              table[2], arg[2],
+                              table[3], arg[3],
+                              table[4], arg[4],
+                              table[5], arg[5],
+                              table[6], arg[6],
+                              table[7], arg[7],
+                              table[8], arg[8],
+                              table[9], arg[9]);
+
+      filelist = g_malloc0(sizeof(mpdclient_filelist_t));
+
+      while( (entity=mpd_getNextInfoEntity(c->connection)) ) 
+       {
+         filelist_entry_t *entry = g_malloc0(sizeof(filelist_entry_t));
+      
+         entry->entity = entity;
+         filelist->list = g_list_append(filelist->list, (gpointer) entry);
+         filelist->length++;
+       }
+  
+      if( mpdclient_finish_command(c) )
+       filelist = mpdclient_filelist_free(filelist);
+
+      filelist->updated = TRUE;
+    } 
+  
+  i=0;
+  while( arg[i] )
+    g_free(arg[i++]);
+
+  return filelist;
+}
+#else
+#define search_advanced_query(pattern,c) (NULL)
+#endif
+
 static void
 search_new(screen_t *screen, mpdclient_t *c)
 {
@@ -113,7 +322,7 @@ search_new(screen_t *screen, mpdclient_t *c)
   pattern = screen_readln(screen->status_window.w, 
                          _("Search: "),
                          NULL,
-                         NULL,
+                         &search_history,
                          NULL);
 
   if( pattern && strcmp(pattern,"")==0 )
@@ -128,15 +337,20 @@ search_new(screen_t *screen, mpdclient_t *c)
       return;
     }
 
-  filelist = mpdclient_filelist_search(c, 
-                                      FALSE,
-                                      mode[options.search_mode].table,
-                                      pattern);
+  if( !MPD_VERSION_LT(c, 0, 12, 0) )
+    filelist = search_advanced_query(pattern, c);
+  if( !advanced_search_mode && filelist==NULL )
+    filelist = mpdclient_filelist_search(c, 
+                                        FALSE,
+                                        mode[options.search_mode].table,
+                                        pattern);
   sync_highlights(c, filelist);
   mpdclient_install_playlist_callback(c, playlist_changed_callback);
   list_window_check_selected(lw, filelist->length);
 }
 
+
+
 static void
 init(WINDOW *w, int cols, int rows)
 {
@@ -146,6 +360,8 @@ init(WINDOW *w, int cols, int rows)
 static void
 quit(void)
 {
+  if( search_history )
+    string_list_free(search_history);
   if( filelist )
     filelist = mpdclient_filelist_free(filelist);
   list_window_free(lw);
@@ -157,10 +373,10 @@ quit(void)
 static void
 open(screen_t *screen, mpdclient_t *c)
 {
-  if( pattern==NULL )
-    search_new(screen, c);
-  else
-    screen_status_printf(_("Press %s for a new search"),
+  //  if( pattern==NULL )
+  //    search_new(screen, c);
+  // else
+  screen_status_printf(_("Press %s for a new search"),
                         get_key_names(CMD_SCREEN_SEARCH,0));
   search_check_mode();
 }
@@ -184,13 +400,18 @@ paint(screen_t *screen, mpdclient_t *c)
   
   if( filelist )
     {
+      lw->flags = 0;
       list_window_paint(lw, browse_lw_callback, (void *) filelist);
       filelist->updated = FALSE;
     }
   else
     {
-      wmove(lw->w, 0, 0);
-      wclrtobot(lw->w);
+      lw->flags = LW_HIDE_CURSOR;
+      list_window_paint(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(lw->w);
 }
@@ -210,7 +431,9 @@ update(screen_t *screen, mpdclient_t *c)
 static char *
 get_title(char *str, size_t size)
 {
-  if( pattern )
+  if( advanced_search_mode && pattern )
+    g_snprintf(str, size, _("Search: %s"), pattern);
+  else if( pattern )
     g_snprintf(str, size, 
               _("Search: Results for %s [%s]"), 
               pattern,