# HG changeset patch # User giacomo # Date 1166210086 28800 # Node ID 0d845907c0b99b3aebc2d3ddf2271c403d0cb24d # Parent a414866b32bc23f40dd786d85a462964729be084 [svn] added a regex-based search option in playlist that allows to select playlist entries using multiple match criteria diff -r a414866b32bc -r 0d845907c0b9 ChangeLog --- a/ChangeLog Fri Dec 15 10:48:13 2006 -0800 +++ b/ChangeLog Fri Dec 15 11:14:46 2006 -0800 @@ -1,3 +1,11 @@ +2006-12-15 18:48:13 +0000 William Pitcock + revision [3261] + - bail after 15 failures to find an acceptable playback candidate + + trunk/audacious/playback.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + + 2006-12-15 16:23:51 +0000 William Pitcock revision [3259] - add playlist_select_playlist() to select a literal playlist diff -r a414866b32bc -r 0d845907c0b9 audacious/playlist.c --- a/audacious/playlist.c Fri Dec 15 10:48:13 2006 -0800 +++ b/audacious/playlist.c Fri Dec 15 11:14:46 2006 -0800 @@ -38,6 +38,7 @@ #include #include #include +#include #include "input.h" #include "main.h" @@ -2706,6 +2707,136 @@ PLAYLIST_UNLOCK(); } +gint +playlist_select_search( Playlist *playlist , TitleInput *tuple , gint action ) +{ + GList *entry_list = NULL, *found_list = NULL, *sel_list = NULL; + gboolean is_first_search = TRUE; + gint num_of_entries_found = 0; + + PLAYLIST_LOCK(); + + if ( tuple->track_name != NULL ) + { + /* match by track_name */ + const gchar *regex_pattern = tuple->track_name; + regex_t regex; + if ( regcomp( ®ex , regex_pattern , REG_NOSUB | REG_ICASE ) == 0 ) + { + GList *tfound_list = NULL; + if ( is_first_search == TRUE ) entry_list = playlist->entries; + else entry_list = found_list; /* use found_list */ + for ( ; entry_list ; entry_list = g_list_next(entry_list) ) + { + PlaylistEntry *entry = entry_list->data; + if ( ( entry->tuple != NULL ) && + ( regexec( ®ex , entry->tuple->track_name , 0 , NULL , 0 ) == 0 ) ) + { + tfound_list = g_list_append( tfound_list , entry ); + } + } + g_list_free( found_list ); /* wipe old found_list */ + found_list = tfound_list; /* move tfound_list in found_list */ + regfree( ®ex ); + } + is_first_search = FALSE; + } + + if ( tuple->album_name != NULL ) + { + /* match by album_name */ + const gchar *regex_pattern = tuple->album_name; + regex_t regex; + if ( regcomp( ®ex , regex_pattern , REG_NOSUB | REG_ICASE ) == 0 ) + { + GList *tfound_list = NULL; + if ( is_first_search == TRUE ) entry_list = playlist->entries; + else entry_list = found_list; /* use found_list */ + for ( ; entry_list ; entry_list = g_list_next(entry_list) ) + { + PlaylistEntry *entry = entry_list->data; + if ( ( entry->tuple != NULL ) && + ( regexec( ®ex , entry->tuple->album_name , 0 , NULL , 0 ) == 0 ) ) + { + tfound_list = g_list_append( tfound_list , entry ); + } + } + g_list_free( found_list ); /* wipe old found_list */ + found_list = tfound_list; /* move tfound_list in found_list */ + regfree( ®ex ); + } + is_first_search = FALSE; + } + + if ( tuple->performer != NULL ) + { + /* match by performer */ + const gchar *regex_pattern = tuple->performer; + regex_t regex; + if ( regcomp( ®ex , regex_pattern , REG_NOSUB | REG_ICASE ) == 0 ) + { + GList *tfound_list = NULL; + if ( is_first_search == TRUE ) entry_list = playlist->entries; + else entry_list = found_list; /* use found_list */ + for ( ; entry_list ; entry_list = g_list_next(entry_list) ) + { + PlaylistEntry *entry = entry_list->data; + if ( ( entry->tuple != NULL ) && + ( regexec( ®ex , entry->tuple->performer , 0 , NULL , 0 ) == 0 ) ) + { + tfound_list = g_list_append( tfound_list , entry ); + } + } + g_list_free( found_list ); /* wipe old found_list */ + found_list = tfound_list; /* move tfound_list in found_list */ + regfree( ®ex ); + } + is_first_search = FALSE; + } + + if ( tuple->file_name != NULL ) + { + /* match by file_name */ + const gchar *regex_pattern = tuple->file_name; + regex_t regex; + if ( regcomp( ®ex , regex_pattern , REG_NOSUB | REG_ICASE ) == 0 ) + { + GList *tfound_list = NULL; + if ( is_first_search == TRUE ) entry_list = playlist->entries; + else entry_list = found_list; /* use found_list */ + for ( ; entry_list ; entry_list = g_list_next(entry_list) ) + { + PlaylistEntry *entry = entry_list->data; + if ( ( entry->tuple != NULL ) && + ( regexec( ®ex , entry->tuple->file_name , 0 , NULL , 0 ) == 0 ) ) + { + tfound_list = g_list_append( tfound_list , entry ); + } + } + g_list_free( found_list ); /* wipe old found_list */ + found_list = tfound_list; /* move tfound_list in found_list */ + regfree( ®ex ); + } + is_first_search = FALSE; + } + + /* NOTE: action = 0 -> default behaviour, select all matching entries */ + /* if some entries are still in found_list, those + are what the user is searching for; select them */ + for ( sel_list = found_list ; sel_list ; sel_list = g_list_next(sel_list) ) + { + PlaylistEntry *entry = sel_list->data; + entry->selected = TRUE; + num_of_entries_found++; + } + + g_list_free( found_list ); + + PLAYLIST_UNLOCK(); + playlist_recalc_total_time(playlist); + + return num_of_entries_found; +} void playlist_select_all(Playlist *playlist, gboolean set) diff -r a414866b32bc -r 0d845907c0b9 audacious/playlist.h --- a/audacious/playlist.h Fri Dec 15 10:48:13 2006 -0800 +++ b/audacious/playlist.h Fri Dec 15 11:14:46 2006 -0800 @@ -179,6 +179,7 @@ gboolean * total_more, gboolean * selection_more); +gint playlist_select_search(Playlist *playlist, TitleInput *tuple, gint action); void playlist_select_all(Playlist *playlist, gboolean set); void playlist_select_range(Playlist *playlist, gint min, gint max, gboolean sel); void playlist_select_invert_all(Playlist *playlist); diff -r a414866b32bc -r 0d845907c0b9 audacious/ui_playlist.c --- a/audacious/ui_playlist.c Fri Dec 15 10:48:13 2006 -0800 +++ b/audacious/ui_playlist.c Fri Dec 15 11:14:46 2006 -0800 @@ -60,7 +60,7 @@ ADD_URL, ADD_DIR, ADD_FILES, SUB_MISC, SUB_ALL, SUB_CROP, SUB_SELECTED, SUB_DUPLICATE_BYTITLE, SUB_DUPLICATE_BYFILENAME, SUB_DUPLICATE_BYPATH, - SEL_INV, SEL_ZERO, SEL_ALL, + SEL_SEARCH, SEL_INV, SEL_ZERO, SEL_ALL, MISC_SORT, MISC_FILEINFO, MISC_MISCOPTS, PLIST_NEW, PLIST_SAVE_AS, PLIST_LOAD, SEL_LOOKUP, CLOSE_PL_WINDOW, MOVE_UP, PLIST_SAVE, @@ -225,10 +225,16 @@ }; static GtkItemFactoryEntry plsel_menu_entries[] = { + {N_("/Search and Select"), NULL, + playlistwin_sub_menu_callback, + SEL_SEARCH, "", GTK_STOCK_FIND}, + + ITEM_SEPARATOR, + {N_("/Invert Selection"), NULL, playlistwin_sub_menu_callback, SEL_INV, "", selectinvert_pixbuf}, - + ITEM_SEPARATOR, {N_("/Select None"),"A", @@ -654,6 +660,107 @@ } static void +playlistwin_select_search(void) +{ + Playlist *playlist = playlist_get_active(); + GtkWidget *searchdlg_win, *searchdlg_table; + GtkWidget *searchdlg_hbox, *searchdlg_logo, *searchdlg_helptext; + GtkWidget *searchdlg_entry_track_name, *searchdlg_label_track_name; + GtkWidget *searchdlg_entry_album_name, *searchdlg_label_album_name; + GtkWidget *searchdlg_entry_file_name, *searchdlg_label_file_name; + GtkWidget *searchdlg_entry_performer, *searchdlg_label_performer; + gint result; + + /* create dialog */ + searchdlg_win = gtk_dialog_new_with_buttons( + "Search entries in active playlist" , GTK_WINDOW(mainwin) , + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT , + GTK_STOCK_CANCEL , GTK_RESPONSE_REJECT , GTK_STOCK_OK , GTK_RESPONSE_ACCEPT , NULL ); + /* help text and logo */ + searchdlg_hbox = gtk_hbox_new( FALSE , 4 ); + searchdlg_logo = gtk_image_new_from_stock( GTK_STOCK_FIND , GTK_ICON_SIZE_DIALOG ); + searchdlg_helptext = gtk_label_new( _("Select entries in playlist by filling one or more " + "fields. Fields use regular expressions syntax, case-insensitive. If you don't know how " + "regular expressions work, simply insert a literal portion of what you're searching for.") ); + gtk_label_set_line_wrap( GTK_LABEL(searchdlg_helptext) , TRUE ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_logo , FALSE , FALSE , 0 ); + gtk_box_pack_start( GTK_BOX(searchdlg_hbox) , searchdlg_helptext , FALSE , FALSE , 0 ); + /* track name */ + searchdlg_label_track_name = gtk_label_new( _("Track name: ") ); + searchdlg_entry_track_name = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_track_name) , 0 , 0.5 ); + /* album name */ + searchdlg_label_album_name = gtk_label_new( _("Album name: ") ); + searchdlg_entry_album_name = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_album_name) , 0 , 0.5 ); + /* artist */ + searchdlg_label_performer = gtk_label_new( _("Artist: ") ); + searchdlg_entry_performer = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_performer) , 0 , 0.5 ); + /* file name */ + searchdlg_label_file_name = gtk_label_new( _("Filename: ") ); + searchdlg_entry_file_name = gtk_entry_new(); + gtk_misc_set_alignment( GTK_MISC(searchdlg_label_file_name) , 0 , 0.5 ); + /* place fields in searchdlg_table */ + searchdlg_table = gtk_table_new( 5 , 2 , FALSE ); + gtk_table_set_row_spacing( GTK_TABLE(searchdlg_table) , 0 , 8 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_hbox , + 0 , 2 , 0 , 1 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_track_name , + 0 , 1 , 1 , 2 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_track_name , + 1 , 2 , 1 , 2 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_album_name , + 0 , 1 , 2 , 3 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_album_name , + 1 , 2 , 2 , 3 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_performer , + 0 , 1 , 3 , 4 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_performer , + 1 , 2 , 3 , 4 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_label_file_name , + 0 , 1 , 4 , 5 , GTK_FILL , GTK_FILL | GTK_EXPAND , 0 , 2 ); + gtk_table_attach( GTK_TABLE(searchdlg_table) , searchdlg_entry_file_name , + 1 , 2 , 4 , 5 , GTK_FILL | GTK_EXPAND , GTK_FILL | GTK_EXPAND , 0 , 2 ); + + gtk_container_set_border_width( GTK_CONTAINER(searchdlg_table) , 5 ); + gtk_container_add( GTK_CONTAINER(GTK_DIALOG(searchdlg_win)->vbox) , searchdlg_table ); + gtk_widget_show_all( searchdlg_win ); + result = gtk_dialog_run( GTK_DIALOG(searchdlg_win) ); + switch(result) + { + case GTK_RESPONSE_ACCEPT: + { + /* create a TitleInput tuple with user search data */ + TitleInput *tuple = g_malloc(sizeof(TitleInput)); + gchar *searchdata = NULL; + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_track_name) ); + tuple->track_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL; + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_album_name) ); + tuple->album_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL; + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_performer) ); + tuple->performer = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL; + searchdata = (gchar*)gtk_entry_get_text( GTK_ENTRY(searchdlg_entry_file_name) ); + tuple->file_name = ( strcmp(searchdata,"") ) ? g_strdup(searchdata) : NULL; + /* now send this tuple to the real search function */ + playlist_select_search( playlist , tuple , 0 ); + /* we do not need the tuple and its data anymore */ + if ( tuple->track_name != NULL ) g_free( tuple->track_name ); + if ( tuple->album_name != NULL ) g_free( tuple->album_name ); + if ( tuple->performer != NULL ) g_free( tuple->performer ); + if ( tuple->file_name != NULL ) g_free( tuple->file_name ); + g_free( tuple ); + playlistwin_update_list(); + break; + } + default: + break; + } + /* done here :) */ + gtk_widget_destroy( searchdlg_win ); +} + +static void playlistwin_select_all(void) { Playlist *playlist = playlist_get_active(); @@ -2050,6 +2157,9 @@ case PLIST_LOAD: playlistwin_select_playlist_to_load(playlist_get_current_name(playlist)); break; + case SEL_SEARCH: + playlistwin_select_search(); + break; case SEL_INV: playlistwin_inverse_selection(); break;