From ba15707b292d827bdce732e7713b26fae3f75c74 Mon Sep 17 00:00:00 2001 From: Alex Bennee Date: Wed, 14 Jul 2010 15:57:06 +0100 Subject: EasyTag 2.1.1 --- src/misc.c | 3392 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3392 insertions(+) create mode 100755 src/misc.c (limited to 'src/misc.c') diff --git a/src/misc.c b/src/misc.c new file mode 100755 index 0000000..41f12ec --- /dev/null +++ b/src/misc.c @@ -0,0 +1,3392 @@ +/* misc.c - 2000/06/28 */ +/* + * EasyTAG - Tag editor for MP3 and Ogg Vorbis files + * Copyright (C) 2000-2003 Jerome Couderc + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "misc.h" +#include "easytag.h" +#include "msgbox.h" +#include "id3_tag.h" +#include "browser.h" +#include "setting.h" +#include "bar.h" +#include "prefs.h" +#include "scan.h" +#include "genres.h" +#include "log.h" +#include "charset.h" + +#ifdef WIN32 +# include +#endif + + +/*************** + * Declaration * + ***************/ +// Playlist window defined in misc.h + +// Search file window +GtkWidget *SearchFileWindow = NULL; +GtkWidget *SearchStringCombo; +GtkListStore *SearchStringModel = NULL; +GtkWidget *SearchInFilename; +GtkWidget *SearchInTag; +GtkWidget *SearchCaseSensitive; +GtkWidget *SearchResultList; +GtkListStore *SearchResultListModel; +GtkWidget *SearchStatusBar; +guint SearchStatusBarContext; + +// Load filename window +GtkWidget *LoadFilenameWindow = NULL; +GtkWidget *FileToLoadCombo; +GtkListStore *FileToLoadModel = NULL; +GtkWidget *LoadFileContentList; +GtkListStore* LoadFileContentListModel; +GtkWidget *LoadFileNameList; +GtkListStore* LoadFileNameListModel; + + +enum +{ + // Columns for titles + SEARCH_RESULT_FILENAME = 0, + SEARCH_RESULT_TITLE, + SEARCH_RESULT_ARTIST, + SEARCH_RESULT_ALBUM, + SEARCH_RESULT_DISC_NUMBER, + SEARCH_RESULT_YEAR, + SEARCH_RESULT_TRACK, + SEARCH_RESULT_GENRE, + SEARCH_RESULT_COMMENT, + SEARCH_RESULT_COMPOSER, + SEARCH_RESULT_ORIG_ARTIST, + SEARCH_RESULT_COPYRIGHT, + SEARCH_RESULT_URL, + SEARCH_RESULT_ENCODED_BY, + + // Columns for pango style (normal/bold) + SEARCH_RESULT_FILENAME_WEIGHT, + SEARCH_RESULT_TITLE_WEIGHT, + SEARCH_RESULT_ARTIST_WEIGHT, + SEARCH_RESULT_ALBUM_WEIGHT, + SEARCH_RESULT_DISC_NUMBER_WEIGHT, + SEARCH_RESULT_YEAR_WEIGHT, + SEARCH_RESULT_TRACK_WEIGHT, + SEARCH_RESULT_GENRE_WEIGHT, + SEARCH_RESULT_COMMENT_WEIGHT, + SEARCH_RESULT_COMPOSER_WEIGHT, + SEARCH_RESULT_ORIG_ARTIST_WEIGHT, + SEARCH_RESULT_COPYRIGHT_WEIGHT, + SEARCH_RESULT_URL_WEIGHT, + SEARCH_RESULT_ENCODED_BY_WEIGHT, + + // Columns for color (normal/red) + SEARCH_RESULT_FILENAME_FOREGROUND, + SEARCH_RESULT_TITLE_FOREGROUND, + SEARCH_RESULT_ARTIST_FOREGROUND, + SEARCH_RESULT_ALBUM_FOREGROUND, + SEARCH_RESULT_DISC_NUMBER_FOREGROUND, + SEARCH_RESULT_YEAR_FOREGROUND, + SEARCH_RESULT_TRACK_FOREGROUND, + SEARCH_RESULT_GENRE_FOREGROUND, + SEARCH_RESULT_COMMENT_FOREGROUND, + SEARCH_RESULT_COMPOSER_FOREGROUND, + SEARCH_RESULT_ORIG_ARTIST_FOREGROUND, + SEARCH_RESULT_COPYRIGHT_FOREGROUND, + SEARCH_RESULT_URL_FOREGROUND, + SEARCH_RESULT_ENCODED_BY_FOREGROUND, + + SEARCH_RESULT_POINTER, + SEARCH_COLUMN_COUNT +}; + +enum +{ + LOAD_FILE_CONTENT_TEXT, + LOAD_FILE_CONTENT_COUNT +}; + +enum +{ + LOAD_FILE_NAME_TEXT, + LOAD_FILE_NAME_POINTER, + LOAD_FILE_NAME_COUNT +}; + +/************** + * Prototypes * + **************/ +void Open_Write_Playlist_Window (void); +gboolean Write_Playlist_Window_Key_Press (GtkWidget *window, GdkEvent *event); +void Destroy_Write_Playlist_Window (void); +void Playlist_Write_Button_Pressed (void); +gboolean Write_Playlist (gchar *play_list_name); +gboolean Playlist_Check_Content_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source); +void Playlist_Convert_Forwardslash_Into_Backslash (gchar *string); + +void Open_Search_File_Window (void); +void Destroy_Search_File_Window (void); +gboolean Search_File_Window_Key_Press (GtkWidget *window, GdkEvent *event); +void Search_File (GtkWidget *search_button); +void Add_Row_To_Search_Result_List (ET_File *ETFile,const gchar *string_to_search); +void Search_Result_List_Row_Selected (GtkTreeSelection* selection, gpointer data); + +void Open_Load_Filename_Window (void); +void Destroy_Load_Filename_Window (void); +gboolean Load_Filename_Window_Key_Press (GtkWidget *window, GdkEvent *event); +void Load_Filename_List_Key_Press (GtkWidget *clist, GdkEvent *event); +void Load_File_Content (GtkWidget *file_entry); +void Load_File_List (void); +void Load_Filename_Select_Row_In_Other_List (GtkWidget *target, gpointer selection_emit); +void Load_Filename_Set_Filenames (void); +void Button_Load_Set_Sensivity (GtkWidget *button, GtkWidget *entry); +GtkWidget *Create_Load_Filename_Popup_Menu (GtkWidget *list); +void Load_Filename_List_Insert_Blank_Line (GtkWidget *list); +void Load_Filename_List_Delete_Line (GtkWidget *list); +void Load_Filename_List_Delete_All_Blank_Lines (GtkWidget *list); +void Load_Filename_List_Reload (GtkWidget *list); +void Load_Filename_Update_Text_Line (GtkWidget *entry, GtkWidget *list); +void Load_Filename_Edit_Text_Line (GtkTreeSelection *selection, gpointer data); + +void Create_Xpm_Icon_Factory (const char **xpmdata, const char *name); + +/* Browser */ +static void Open_File_Selection_Window (GtkWidget *entry, gchar *title, GtkFileChooserAction action); +void File_Selection_Window_For_File (GtkWidget *entry); +void File_Selection_Window_For_Directory (GtkWidget *entry); + + +/************* + * Functions * + *************/ + +/****************************** + * Functions managing pixmaps * + ******************************/ +/* + * Buttons creation with pixmap + */ + +GtkWidget *Create_Button_With_Pixmap(guint button_type) +{ + GtkWidget *Button; + GtkWidget *HBox; + GtkWidget *Label; + GtkWidget *Pixmap; + + gtk_widget_realize(MainWindow); + switch (button_type) + { + case BUTTON_OK: + Label = gtk_label_new(_(" OK ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_OK, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_YES: + Label = gtk_label_new(_(" Yes ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_YES, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_NO: + Label = gtk_label_new(_(" No ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_NO, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_APPLY: + Label = gtk_label_new(_(" Apply ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_SAVE: + Label = gtk_label_new(_(" Save ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_CANCEL: + Label = gtk_label_new(_(" Cancel ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_CANCEL, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_CLOSE: + Label = gtk_label_new(_(" Close ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_WRITE: + Label = gtk_label_new(_(" Write ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_SAVE_AS, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_EXECUTE: + Label = gtk_label_new(_(" Execute ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_SEARCH: + Label = gtk_label_new(_(" Search ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_FIND, GTK_ICON_SIZE_BUTTON); + break; + + case BUTTON_BROWSE: + Label = gtk_label_new(_(" Browse... ")); + Pixmap = gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_BUTTON); + break; + + default: + Button = gtk_button_new_with_label("Unknown button"); + return Button; + break; + } + + Button = gtk_button_new(); + HBox = gtk_hbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(Button),HBox); + /* Add items in button */ + gtk_container_add(GTK_CONTAINER(HBox),Pixmap); + gtk_container_add(GTK_CONTAINER(HBox),Label); + /* Alignment of items */ + gtk_misc_set_alignment(GTK_MISC(Pixmap),1,0.5); + gtk_misc_set_alignment(GTK_MISC(Label),0,0.5); + + return Button; +} + +/* + * Create an icon into an event box to allow some events (as to display tooltips). + */ +GtkWidget *Create_Pixmap_Icon_With_Event_Box (const gchar *pixmap_name) +{ + GtkWidget *icon; + GtkWidget *EventBox; + + EventBox = gtk_event_box_new(); + if (pixmap_name) + { + icon = gtk_image_new_from_stock(pixmap_name, GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(EventBox),icon); + } + + return EventBox; +} + +/* + * Return a button with an icon and a label + */ +GtkWidget *Create_Button_With_Icon_And_Label (const gchar *pixmap_name, gchar *label) +{ + GtkWidget *Button; + GtkWidget *HBox; + GtkWidget *Label; + GtkWidget *Pixmap; + + Button = gtk_button_new(); + HBox = gtk_hbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(Button),HBox); + + /* Add a pixmap if not null */ + if (pixmap_name != NULL) + { + gtk_widget_realize(MainWindow); + Pixmap = gtk_image_new_from_stock(pixmap_name, GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(HBox),Pixmap); + } + + /* Add a label if not null */ + if (label != NULL) + { + Label = gtk_label_new(label); + gtk_container_add(GTK_CONTAINER(HBox),Label); + } + + /* Display a warning message if the both parameters are NULL */ + if (pixmap_name==NULL && label==NULL) + g_warning("Empty button created 'adr=%p' (no icon and no label)!",Button); + + return Button; +} + +/* + * Add the 'string' passed in parameter to the list store + * If this string already exists in the list store, it doesn't add it. + * Returns TRUE if string was added. + */ +gboolean Add_String_To_Combo_List (GtkListStore *liststore, gchar *str) +{ + GtkTreeIter iter; + gchar *text; + guint HISTORY_MAX_LENGTH = 15; + //gboolean found = FALSE; + gchar *string = g_strdup(str); + + if (!string || g_utf8_strlen(string, -1) <= 0) + return FALSE; + +#if 0 + // We add the string to the beginning of the list store + // So we will start to parse from the second line below + gtk_list_store_prepend(liststore, &iter); + gtk_list_store_set(liststore, &iter, MISC_COMBO_TEXT, string, -1); + + // Search in the list store if string already exists and remove other same strings in the list + found = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter); + //gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, MISC_COMBO_TEXT, &text, -1); + while (found && gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter)) + { + gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, MISC_COMBO_TEXT, &text, -1); + //g_print(">0>%s\n>1>%s\n",string,text); + if (g_utf8_collate(text, string) == 0) + { + g_free(text); + // FIX ME : it seems that after it selects the next item for the + // combo (changes 'string')???? + // So should select the first item? + gtk_list_store_remove(liststore, &iter); + // Must be rewinded? + found = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter); + //gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, MISC_COMBO_TEXT, &text, -1); + continue; + } + g_free(text); + } + + // Limit list size to HISTORY_MAX_LENGTH + while (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore),NULL) > HISTORY_MAX_LENGTH) + { + if ( gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(liststore), + &iter,NULL,HISTORY_MAX_LENGTH) ) + { + gtk_list_store_remove(liststore, &iter); + } + } + + g_free(string); + // Place again to the beginning of the list, to select the right value? + //gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter); + + return TRUE; + +#else + + // Search in the list store if string already exists. + // FIXME : insert string at the beginning of the list (if already exists), + // and remove other same strings in the list + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(liststore), &iter)) + { + do + { + gtk_tree_model_get(GTK_TREE_MODEL(liststore), &iter, MISC_COMBO_TEXT, &text, -1); + if (g_utf8_collate(text, string) == 0) + { + g_free(text); + return FALSE; + } + + g_free(text); + } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(liststore), &iter)); + } + + // We add the string to the beginning of the list store + gtk_list_store_prepend(liststore, &iter); + gtk_list_store_set(liststore, &iter, MISC_COMBO_TEXT, string, -1); + + // Limit list size to HISTORY_MAX_LENGTH + while (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(liststore),NULL) > HISTORY_MAX_LENGTH) + { + if ( gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(liststore), + &iter,NULL,HISTORY_MAX_LENGTH) ) + { + gtk_list_store_remove(liststore, &iter); + } + } + + g_free(string); + return TRUE; +#endif +} + +/* + * Returns the text of the selected item in a combo box + * Remember to free the returned value... + */ +gchar *Get_Active_Combo_Box_Item (GtkComboBox *combo) +{ + gchar *text; + GtkTreeIter iter; + GtkTreeModel *model; + + if (!combo) + return NULL; + + model = gtk_combo_box_get_model(combo); + if (!gtk_combo_box_get_active_iter(combo, &iter)) + return NULL; + + gtk_tree_model_get(model, &iter, MISC_COMBO_TEXT, &text, -1); + return text; +} + +/* + * Event attached to an entry to disable an other widget (for example: a button) + * when the entry is empty + */ +void Entry_Changed_Disable_Object(GtkObject *widget_to_disable, GtkEditable *source_widget) +{ + gchar *text = NULL; + + if (!widget_to_disable || !source_widget) return; + + text = gtk_editable_get_chars(GTK_EDITABLE(source_widget),0,-1); + if (!text || strlen(text)<1) + gtk_widget_set_sensitive(GTK_WIDGET(widget_to_disable),FALSE); + else + gtk_widget_set_sensitive(GTK_WIDGET(widget_to_disable),TRUE); + + g_free(text); +} + +/* + * To insert only digits in an entry. If the text contains only digits: returns it, + * else only first digits. + */ +void Insert_Only_Digit (GtkEditable *editable, const gchar *inserted_text, gint length, + gint *position, gpointer data) +{ + int i = 1; // Ignore first character + int j = 1; + gchar *result; + + if (length<=0 || !inserted_text) + return; + + if (!isdigit((guchar)inserted_text[0]) && inserted_text[0] != '-') + { + g_signal_stop_emission_by_name(G_OBJECT(editable),"insert_text"); + return; + } else if (length == 1) + { + // We already checked the first digit... + return; + } + + g_signal_stop_emission_by_name(G_OBJECT(editable),"insert_text"); + result = g_malloc0(length); + result[0] = inserted_text[0]; + + // Check the rest, if any... + for (i = 1; i < length; i++) + { + if (isdigit((guchar)inserted_text[i])) + { + result[j++] = inserted_text[i]; + } + } + + if (result[0] == (gchar)NULL) + { + g_free(result); + return; + } + + g_signal_handlers_block_by_func(G_OBJECT(editable),G_CALLBACK(Insert_Only_Digit),data); + gtk_editable_insert_text(editable, result, j, position); + g_signal_handlers_unblock_by_func(G_OBJECT(editable),G_CALLBACK(Insert_Only_Digit),data); + g_free(result); +} + +/* + * Parse and auto complete date entry if you don't type the 4 digits. + */ +#include +#include +gboolean Parse_Date (void) +{ + const gchar *year; + gchar *tmp, *tmp1; + gchar current_year[5]; + time_t t; + struct tm t0; + + if (!DATE_AUTO_COMPLETION) return FALSE; + + /* Get the info entered by user */ + year = gtk_entry_get_text(GTK_ENTRY(YearEntry)); + + if ( strcmp(year,"")!=0 && strlen(year)<4 ) + { + t = time(NULL); + /* Get the current date */ + memcpy(&t0, localtime(&t), sizeof(struct tm)); + /* Put the current year in 'current_year' tab */ + sprintf(current_year,"%d",1900+t0.tm_year); + + tmp = ¤t_year[4-strlen(year)]; + if ( atoi(year) <= atoi(tmp) ) + { + sprintf(current_year,"%d",atoi(current_year)-atoi(tmp)); + tmp1 = g_strdup_printf("%d",atoi(current_year)+atoi(year)); + gtk_entry_set_text(GTK_ENTRY(YearEntry),tmp1); + g_free(tmp1); + + }else + { + sprintf(current_year,"%d",atoi(current_year)-atoi(tmp) + -(strlen(year)<=0 ? 1 : strlen(year)<=1 ? 10 : // pow(10,strlen(year)) returns 99 instead of 100 under Win32... + strlen(year)<=2 ? 100 : strlen(year)<=3 ? 1000 : 0)); + tmp1 = g_strdup_printf("%d",atoi(current_year)+atoi(year)); + gtk_entry_set_text(GTK_ENTRY(YearEntry),tmp1); + g_free(tmp1); + } + } + return FALSE; +} + +/* + * Load the genres list to the combo, and sorts it + */ +int Compare_Two_Genres (gchar *genre1,gchar *genre2) +{ + return strcmp(genre1,genre2); +} + +void Load_Genres_List_To_UI (void) +{ + guint i; + GtkTreeIter iter; + + if (!GenreComboModel) return; + + gtk_list_store_append(GTK_LIST_STORE(GenreComboModel), &iter); + gtk_list_store_set(GTK_LIST_STORE(GenreComboModel), &iter, MISC_COMBO_TEXT, "", -1); + + gtk_list_store_append(GTK_LIST_STORE(GenreComboModel), &iter); + gtk_list_store_set(GTK_LIST_STORE(GenreComboModel), &iter, MISC_COMBO_TEXT, "Unknown", -1); + + for (i=0; i<=GENRE_MAX; i++) + { + gtk_list_store_append(GTK_LIST_STORE(GenreComboModel), &iter); + gtk_list_store_set(GTK_LIST_STORE(GenreComboModel), &iter, MISC_COMBO_TEXT, id3_genres[i], -1); + } +} + +/* + * Load the track numbers into the track combo list + * We limit the preloaded values to 30 to avoid lost of time with lot of files... + */ +void Load_Track_List_To_UI (void) +{ + guint len; + guint i; + GtkTreeIter iter; + gchar *text; + + if (!ETCore->ETFileDisplayedList || !TrackEntryComboModel) return; + + // Number mini of items + //if ((len=ETCore->ETFileDisplayedList_Length) < 30) + // Length limited to 30 (instead to the number of files)! + len = 30; + + // Create list of tracks + for (i=1; i<=len; i++) + { + + if (NUMBER_TRACK_FORMATED) + { + text = g_strdup_printf("%.*d",NUMBER_TRACK_FORMATED_SPIN_BUTTON,i); + } else + { + text = g_strdup_printf("%.2d",i); + } + + gtk_list_store_append(GTK_LIST_STORE(TrackEntryComboModel), &iter); + gtk_list_store_set(GTK_LIST_STORE(TrackEntryComboModel), &iter, MISC_COMBO_TEXT, text, -1); + g_free(text); + } + +} + +/* + * Change mouse cursor + */ +void Init_Mouse_Cursor (void) +{ + MouseCursor = NULL; +} + +void Destroy_Mouse_Cursor (void) +{ + if (MouseCursor) + { + gdk_cursor_unref(MouseCursor); + MouseCursor = NULL; + } +} + +void Set_Busy_Cursor (void) +{ + /* If still built, destroy it to avoid memory leak */ + Destroy_Mouse_Cursor(); + /* Create the new cursor */ + MouseCursor = gdk_cursor_new(GDK_WATCH); + gdk_window_set_cursor(MainWindow->window,MouseCursor); +} + +void Set_Unbusy_Cursor (void) +{ + /* Back to standard cursor */ + gdk_window_set_cursor(MainWindow->window,NULL); + Destroy_Mouse_Cursor(); +} + + + +/* + * Add easytag specific icons to GTK stock set + */ +#include "../pixmaps/scan.xpm" +#include "../pixmaps/select_all.xpm" +#include "../pixmaps/invert_selection.xpm" +#include "../pixmaps/add.xpm" +#include "../pixmaps/unselect_all.xpm" +#include "../pixmaps/grab.xpm" +#include "../pixmaps/mask.xpm" +//#include "../pixmaps/blackwhite.xpm" +#include "../pixmaps/forbidden.xpm" +#include "../pixmaps/read_only.xpm" +//#include "../pixmaps/sequence_track.xpm" +#include "../pixmaps/red_lines.xpm" +#include "../pixmaps/artist_album.xpm" +#include "../pixmaps/add_folder.xpm" +#include "../pixmaps/parent_folder.xpm" +#include "../pixmaps/sound.xpm" +#include "../pixmaps/all_uppercase.xpm" +#include "../pixmaps/all_downcase.xpm" +#include "../pixmaps/first_letter_uppercase.xpm" +#include "../pixmaps/first_letter_uppercase_word.xpm" +void Init_Custom_Icons (void) +{ + Create_Xpm_Icon_Factory((const char**)select_all_xpm, "easytag-select-all"); + Create_Xpm_Icon_Factory((const char**)scan_xpm, "easytag-scan"); + Create_Xpm_Icon_Factory((const char**)invert_selection_xpm, "easytag-invert-selection"); + Create_Xpm_Icon_Factory((const char**)add_xpm, "easytag-add"); + Create_Xpm_Icon_Factory((const char**)unselect_all_xpm, "easytag-unselect-all"); + Create_Xpm_Icon_Factory((const char**)grab_xpm, "easytag-grab"); + Create_Xpm_Icon_Factory((const char**)mask_xpm, "easytag-mask"); + //Create_Xpm_Icon_Factory((const char**)blackwhite_xpm, "easytag-blackwhite"); + Create_Xpm_Icon_Factory((const char**)forbidden_xpm, "easytag-forbidden"); + Create_Xpm_Icon_Factory((const char**)read_only_xpm, "easytag-read-only"); + //Create_Xpm_Icon_Factory((const char**)sequence_track_xpm, "easytag-sequence-track"); + Create_Xpm_Icon_Factory((const char**)red_lines_xpm, "easytag-red-lines"); + Create_Xpm_Icon_Factory((const char**)artist_album_xpm, "easytag-artist-album"); + Create_Xpm_Icon_Factory((const char**)parent_folder_xpm, "easytag-parent-folder"); + Create_Xpm_Icon_Factory((const char**)add_folder_xpm, "easytag-add-folder"); + Create_Xpm_Icon_Factory((const char**)sound_xpm, "easytag-sound"); + Create_Xpm_Icon_Factory((const char**)all_uppercase_xpm, "easytag-all-uppercase"); + Create_Xpm_Icon_Factory((const char**)all_downcase_xpm, "easytag-all-downcase"); + Create_Xpm_Icon_Factory((const char**)first_letter_uppercase_xpm, "easytag-first-letter-uppercase"); + Create_Xpm_Icon_Factory((const char**)first_letter_uppercase_word_xpm, "easytag-first-letter-uppercase-word"); +} + + +/* + * Create an icon factory from the specified pixmap + * Also add it to the GTK stock images + */ +void Create_Xpm_Icon_Factory (const char **xpmdata, const char *xpmname) +{ + GtkIconSet *set; + GtkIconFactory *factory; + GdkPixbuf *pixbuf; + + if (!*xpmdata || !xpmname) + return; + + pixbuf = gdk_pixbuf_new_from_xpm_data(xpmdata); + + set = gtk_icon_set_new_from_pixbuf(pixbuf); + factory = gtk_icon_factory_new(); + gtk_icon_factory_add(factory, xpmname, set); + gtk_icon_set_unref(set); + gtk_icon_factory_add_default(factory); +} + +/* + * Return a widget with a pixmap + * Note: for pixmap 'pixmap.xpm', pixmap_name is 'pixmap_xpm' + */ +GtkWidget *Create_Xpm_Image (const char **xpm_name) +{ + GdkPixbuf *pixbuf; + GtkWidget *image; + + if (!*xpm_name) + return NULL; + + pixbuf = gdk_pixbuf_new_from_xpm_data(xpm_name); + image = gtk_image_new_from_pixbuf(GDK_PIXBUF(pixbuf)); + + return image; +} + + + +/* + * Iter compare func: Sort alphabetically + */ +gint Combo_Alphabetic_Sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer data) +{ + gchar *text1, *text1_folded; + gchar *text2, *text2_folded; + gint ret; + + gtk_tree_model_get(model, a, MISC_COMBO_TEXT, &text1, -1); + gtk_tree_model_get(model, b, MISC_COMBO_TEXT, &text2, -1); + + if (text1 == text2) + { + g_free(text1); + g_free(text2); + return 0; + } + + if (text1 == NULL) + { + g_free(text2); + return -1; + } + + if (text2 == NULL) + { + g_free(text1); + return 1; + } + + text1_folded = g_utf8_casefold(text1, -1); + text2_folded = g_utf8_casefold(text2, -1); + ret = g_utf8_collate(text1_folded, text2_folded); + + g_free(text1); + g_free(text2); + g_free(text1_folded); + g_free(text2_folded); + return ret; +} + + +/************************* + * File selection window * + *************************/ +void File_Selection_Window_For_File (GtkWidget *entry) +{ + Open_File_Selection_Window(entry, _("Select directory..."), GTK_FILE_CHOOSER_ACTION_OPEN); +} + +void File_Selection_Window_For_Directory (GtkWidget *entry) +{ + Open_File_Selection_Window(entry, _("Select file..."), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); +} + +/* + * Open the file selection window and saves the selected file path into entry + */ +static void Open_File_Selection_Window (GtkWidget *entry, gchar *title, GtkFileChooserAction action) +{ + gchar *tmp; + gchar *filename, *filename_utf8; + GtkWidget *FileSelectionWindow; + GtkWindow *parent_window = NULL; + + parent_window = (GtkWindow*) gtk_widget_get_toplevel(entry); + if (!GTK_WIDGET_TOPLEVEL(parent_window)) + { + g_warning("Could not get parent window\n"); + return; + } + + FileSelectionWindow = gtk_file_chooser_dialog_new(title, parent_window, action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + // Set initial directory + tmp = (gchar*) gtk_entry_get_text(GTK_ENTRY(entry)); + if (tmp && *tmp) + { + if (!gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(FileSelectionWindow),tmp)) + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(FileSelectionWindow),tmp); + } + + + if (gtk_dialog_run(GTK_DIALOG(FileSelectionWindow)) == GTK_RESPONSE_ACCEPT) + { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(FileSelectionWindow)); + filename_utf8 = filename_to_display(filename); + gtk_entry_set_text(GTK_ENTRY(entry),filename_utf8); + g_free(filename); + g_free(filename_utf8); + } + gtk_widget_destroy(FileSelectionWindow); +} + + + +/* + * Run the audio player and load files of the current dir + */ +void Run_Audio_Player_Using_File_List (GList *etfilelist_init) +{ + gchar **argv; + gint argv_index = 0; + GList *etfilelist; + ET_File *etfile; + gchar *filename; + gchar *program_path; +#ifdef WIN32 + gchar *argv_join; + STARTUPINFO siStartupInfo; + PROCESS_INFORMATION piProcessInfo; +#else + pid_t pid; + gchar **argv_user; + gint argv_user_number; +#endif + + // Exit if no program selected... + if (!AUDIO_FILE_PLAYER || strlen(g_strstrip(AUDIO_FILE_PLAYER))<1) + { + GtkWidget *msgbox = msg_box_new(_("Warning..."),_("No audio player defined!"),GTK_STOCK_DIALOG_WARNING,BUTTON_OK,0); + msg_box_hide_check_button(MSG_BOX(msgbox)); + //gtk_window_set_transient_for(GTK_WINDOW(msgbox),GTK_WINDOW(OptionsWindow)); + msg_box_run(MSG_BOX(msgbox)); + gtk_widget_destroy(msgbox); + + return; + } + + if ( !(program_path = Check_If_Executable_Exists(AUDIO_FILE_PLAYER)) ) + { + gchar *msg = g_strdup_printf(_("The program '%s' can't be found!"),AUDIO_FILE_PLAYER); + Log_Print(msg); + g_free(msg); + return; + } + g_free(program_path); + + // The list of files to play + etfilelist = etfilelist_init; + +#ifdef WIN32 + + // See documentation : http://c.developpez.com/faq/vc/?page=ProcessThread and http://www.answers.com/topic/createprocess + ZeroMemory(&siStartupInfo, sizeof(siStartupInfo)); + siStartupInfo.cb = sizeof(siStartupInfo); + ZeroMemory(&piProcessInfo, sizeof(piProcessInfo)); + + argv = g_new0(gchar *,g_list_length(etfilelist) + 2); // "+2" for 1rst arg 'foo' and last arg 'NULL' + argv[argv_index++] = "foo"; + + // Load files as arguments + while (etfilelist) + { + etfile = (ET_File *)etfilelist->data; + filename = ((File_Name *)etfile->FileNameCur->data)->value; + //filename_utf8 = ((File_Name *)etfile->FileNameCur->data)->value_utf8; + // We must enclose filename between quotes, because of possible (probable!) spaces in filenames" + argv[argv_index++] = g_strconcat("\"", filename, "\"", NULL); + etfilelist = etfilelist->next; + } + argv[argv_index] = NULL; // Ends the list of arguments + + // Make a command line with all arguments (joins strings together to form one long string separated by a space) + argv_join = g_strjoinv(" ", argv); + + if (CreateProcess(AUDIO_FILE_PLAYER, + argv_join, + NULL, + NULL, + FALSE, + CREATE_DEFAULT_ERROR_MODE, + NULL, + NULL, + &siStartupInfo, + &piProcessInfo) == FALSE) + { + Log_Print(_("Can't execute %s (error %d)!\n"), AUDIO_FILE_PLAYER, GetLastError()); + } + + // Free allocated parameters (for each filename) + for (argv_index = 1; argv[argv_index]; argv_index++) + g_free(argv[argv_index]); + + g_free(argv_join); + +#else + + argv_user = g_strsplit(AUDIO_FILE_PLAYER," ",0); // the string may contains arguments, space is the delimiter + // Number of arguments into 'argv_user' + for (argv_user_number=0;argv_user[argv_user_number];argv_user_number++); + + argv = g_new0(gchar *,argv_user_number + g_list_length(etfilelist) + 1); // +1 for NULL + + // Load 'user' arguments (program name and more...) + while (argv_user[argv_index]) + { + argv[argv_index] = argv_user[argv_index]; + argv_index++; + } + + // Load files as arguments + while (etfilelist) + { + etfile = (ET_File *)etfilelist->data; + filename = ((File_Name *)etfile->FileNameCur->data)->value; + //filename_utf8 = ((File_Name *)etfile->FileNameCur->data)->value_utf8; + argv[argv_index++] = filename; + etfilelist = etfilelist->next; + } + argv[argv_index] = NULL; // Ends the list of arguments + + pid = fork(); + switch (pid) + { + case -1: + Log_Print(_("Can't fork another process!\n")); + break; + case 0: + { + if (execvp(argv[0],argv) == -1) + { + Log_Print(_("Can't execute %s (%s)!\n"),argv[0],g_strerror(errno)); + } + g_strfreev(argv_user); + _exit(1); + break; + } + default: + break; + } + +#endif + + g_free(argv); +} + +void Run_Audio_Player_Using_Directory (void) +{ + GList *etfilelist = g_list_first(ETCore->ETFileList); + + Run_Audio_Player_Using_File_List(etfilelist); +} + +void Run_Audio_Player_Using_Selection (void) +{ + GList *etfilelist = NULL; + GList *selfilelist = NULL; + ET_File *etfile; + GtkTreeSelection *selection; + + if (!BrowserList) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserList)); + selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL); + while (selfilelist) + { + etfile = Browser_List_Get_ETFile_From_Path(selfilelist->data); + etfilelist = g_list_append(etfilelist, etfile); + + if (!selfilelist->next) break; + selfilelist = selfilelist->next; + } + + g_list_foreach(selfilelist, (GFunc) gtk_tree_path_free, NULL); + g_list_free(selfilelist); + + Run_Audio_Player_Using_File_List(etfilelist); + + g_list_free(etfilelist); +} + +void Run_Audio_Player_Using_Browser_Artist_List (void) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *artistListModel; + GList *AlbumList, *etfilelist; + GList *concatenated_list = NULL; + + if (!BrowserArtistList) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserArtistList)); + if (!gtk_tree_selection_get_selected(selection, &artistListModel, &iter)) + return; + + gtk_tree_model_get(artistListModel, &iter, + ARTIST_ALBUM_LIST_POINTER, &AlbumList, + -1); + + while (AlbumList) + { + etfilelist = g_list_copy((GList *)AlbumList->data); + if (!concatenated_list) + concatenated_list = etfilelist; + else + concatenated_list = g_list_concat(concatenated_list,etfilelist); + AlbumList = AlbumList->next; + } + + Run_Audio_Player_Using_File_List(concatenated_list); + + if (concatenated_list) + g_list_free(concatenated_list); +} + +void Run_Audio_Player_Using_Browser_Album_List (void) +{ + GtkTreeIter iter; + GtkTreeSelection *selection; + GtkTreeModel *albumListModel; + GList *etfilelist; + + if (!BrowserAlbumList) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserAlbumList)); + if (!gtk_tree_selection_get_selected(selection, &albumListModel, &iter)) + return; + + gtk_tree_model_get(albumListModel, &iter, + ALBUM_ETFILE_LIST_POINTER, &etfilelist, + -1); + + Run_Audio_Player_Using_File_List(etfilelist); +} + + +/* + * Check if the executable passed in parameter can be launched + * Returns the full path of the file (must be freed if not used) + */ +gchar *Check_If_Executable_Exists (const gchar *program) +{ + gchar *program_tmp; + gchar *tmp; + + if (!program) + return NULL; + + program_tmp = g_strdup(program); + g_strstrip(program_tmp); + +#ifdef WIN32 + // Remove arguments if found, after '.exe' + if ( (tmp=strstr(program_tmp,".exe")) ) + *(tmp + 4) = 0; +#else + // Remove arguments if found + if ( (tmp=strchr(program_tmp,' ')) ) + *tmp = 0; +#endif + + if (g_path_is_absolute(program_tmp)) + { + if (access(program_tmp, X_OK) == 0) + { + return program_tmp; + } else + { + g_free(program_tmp); + return NULL; + } + } else + { + tmp = g_find_program_in_path(program_tmp); + if (tmp) + { + g_free(program_tmp); + return tmp; + }else + { + g_free(program_tmp); + return NULL; + } + } + +} + + + +/* + * The returned string must be freed after used + */ +gchar *Convert_Size (gfloat size) +{ + gchar *data = NULL; + /* Units Tab of file size (bytes,kilobytes,...) */ + gchar *Units_Tab[] = { N_("B"), N_("KB"), N_("MB"), N_("GB"), N_("TB")}; + gint i = 0; + + while ( (gint)size/1024 && i<(gint)(sizeof(Units_Tab)/sizeof(Units_Tab[0])-1) ) + { + size = size/1024; + i++; + } + return data = g_strdup_printf("%.1f %s",size,_(Units_Tab[i])); +} + +/* + * Same that before except that if value in MB, we display 3 numbers after the coma + * The returned string must be freed after used + */ +gchar *Convert_Size_1 (gfloat size) +{ + gchar *data = NULL; + /* Units Tab of file size (bytes,kilobytes,...) */ + gchar *Units_Tab[] = { N_("B"), N_("KB"), N_("MB"), N_("GB"), N_("TB")}; + guint i = 0; + + while ( (gint)size/1024 && i<(sizeof(Units_Tab)/sizeof(Units_Tab[0])-1) ) + { + size = size/1024; + i++; + } + if (i >= 2) // For big values : display 3 number afer the separator (coma or point) + return data = g_strdup_printf("%.3f %s",size,_(Units_Tab[i])); + else + return data = g_strdup_printf("%.1f %s",size,_(Units_Tab[i])); +} + +/* + * Convert a series of seconds into a readable duration + * Remember to free the string that is returned + */ +gchar *Convert_Duration (gulong duration) +{ + guint hour=0; + guint minute=0; + guint second=0; + gchar *data = NULL; + + if (duration<=0) + return g_strdup_printf("%d:%.2d",minute,second); + + hour = duration/3600; + minute = (duration%3600)/60; + second = (duration%3600)%60; + + if (hour) + data = g_strdup_printf("%d:%.2d:%.2d",hour,minute,second); + else + data = g_strdup_printf("%d:%.2d",minute,second); + + return data; +} + +/* + * Returns the size of a file in bytes + */ +gulong Get_File_Size(gchar *filename) +{ + struct stat statbuf; + + if (filename) + { + stat(filename,&statbuf); + return statbuf.st_size; + }else + { + return 0; + } +} + +/* + * Delete spaces at the end and the beginning of the string + */ +void Strip_String (gchar *string) +{ + if (!string) return; + string = g_strstrip(string); +} + + + +/******************************* + * Writting playlist functions * + *******************************/ +/* + * The window to write playlists. + */ +void Open_Write_Playlist_Window (void) +{ + GtkWidget *Frame; + GtkWidget *VBox; + GtkWidget *vbox, *hbox; + GtkWidget *ButtonBox; + GtkWidget *Button; + GtkWidget *Separator; + GtkWidget *Icon; + GtkWidget *MaskStatusIconBox, *MaskStatusIconBox1; + GtkTooltips *Tips; + + if (WritePlaylistWindow != NULL) + { + gdk_window_raise(WritePlaylistWindow->window); + return; + } + + Tips = gtk_tooltips_new(); + + WritePlaylistWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(WritePlaylistWindow),_("Generate a playlist")); + gtk_window_set_transient_for(GTK_WINDOW(WritePlaylistWindow),GTK_WINDOW(MainWindow)); + g_signal_connect(G_OBJECT(WritePlaylistWindow),"destroy", G_CALLBACK(Destroy_Write_Playlist_Window),NULL); + g_signal_connect(G_OBJECT(WritePlaylistWindow),"delete_event", G_CALLBACK(Destroy_Write_Playlist_Window),NULL); + g_signal_connect(G_OBJECT(WritePlaylistWindow),"key_press_event", G_CALLBACK(Write_Playlist_Window_Key_Press),NULL); + + // Just center on mainwindow + gtk_window_set_position(GTK_WINDOW(WritePlaylistWindow), GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_set_default_size(GTK_WINDOW(WritePlaylistWindow),PLAYLIST_WINDOW_WIDTH,PLAYLIST_WINDOW_HEIGHT); + + Frame = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(WritePlaylistWindow),Frame); + gtk_container_set_border_width(GTK_CONTAINER(Frame),4); + + VBox = gtk_vbox_new(FALSE,2); + gtk_container_add(GTK_CONTAINER(Frame),VBox); + gtk_container_set_border_width(GTK_CONTAINER(VBox), 4); + + /* Playlist name */ + if (!PlayListNameMaskModel) + PlayListNameMaskModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING); + else + gtk_list_store_clear(PlayListNameMaskModel); + + Frame = gtk_frame_new(_("M3U Playlist Name")); + gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0); + vbox = gtk_vbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(Frame),vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + + playlist_use_mask_name = gtk_radio_button_new_with_label(NULL, _("Use mask :")); + hbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0); + gtk_box_pack_start(GTK_BOX(hbox),playlist_use_mask_name,FALSE,FALSE,0); + PlayListNameMaskCombo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(PlayListNameMaskModel), MISC_COMBO_TEXT); + gtk_box_pack_start(GTK_BOX(hbox),PlayListNameMaskCombo,FALSE,FALSE,4); + playlist_use_dir_name = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(playlist_use_mask_name),_("Use directory name")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dir_name,FALSE,FALSE,0); + // History list + Load_Play_List_Name_List(PlayListNameMaskModel, MISC_COMBO_TEXT); + Add_String_To_Combo_List(PlayListNameMaskModel, PLAYLIST_NAME); + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(PlayListNameMaskCombo)->child), PLAYLIST_NAME); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name),PLAYLIST_USE_MASK_NAME); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),PLAYLIST_USE_DIR_NAME); + + // Mask status icon + MaskStatusIconBox = Create_Pixmap_Icon_With_Event_Box("easytag-forbidden"); + gtk_box_pack_start(GTK_BOX(hbox),MaskStatusIconBox,FALSE,FALSE,0); + gtk_tooltips_set_tip(Tips,MaskStatusIconBox,_("Invalid Scanner Mask"),NULL); + // Signal connection to check if mask is correct into the mask entry + g_signal_connect_swapped(G_OBJECT(GTK_BIN(PlayListNameMaskCombo)->child),"changed", + G_CALLBACK(Playlist_Check_Content_Mask),G_OBJECT(MaskStatusIconBox)); + + // Button for Mask editor + Button = gtk_button_new(); + Icon = gtk_image_new_from_stock("easytag-mask", GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(Button),Icon); + gtk_box_pack_start(GTK_BOX(hbox),Button,FALSE,FALSE,0); + gtk_button_set_relief(GTK_BUTTON(Button),GTK_RELIEF_NONE); + gtk_tooltips_set_tip(Tips,Button,_("Edit Masks"),NULL); + // The masks will be edited into a tab of the preferences window. In the future... + //g_signal_connect(G_OBJECT(Button),"clicked",(GtkSignalFunc)???,NULL); + // FIX ME : edit the masks + gtk_widget_set_sensitive(GTK_WIDGET(Button),FALSE); + + + /* Playlist options */ + Frame = gtk_frame_new(_("Playlist Options")); + gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0); + vbox = gtk_vbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(Frame),vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + + playlist_only_selected_files = gtk_check_button_new_with_label(_("Include only the selected files")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_only_selected_files,FALSE,FALSE,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files),PLAYLIST_ONLY_SELECTED_FILES); + gtk_tooltips_set_tip(Tips,playlist_only_selected_files,_("If activated, only the selected files will be " + "written in the playlist file. Else, all the files will be written."),NULL); + + // Separator line + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox),Separator,FALSE,FALSE,0); + + playlist_full_path = gtk_radio_button_new_with_label(NULL,_("Use full path for files in playlist")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_full_path,FALSE,FALSE,0); + playlist_relative_path = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_full_path), + _("Use relative path for files in playlist")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_relative_path,FALSE,FALSE,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_full_path),PLAYLIST_FULL_PATH); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_relative_path),PLAYLIST_RELATIVE_PATH); + + // Separator line + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox),Separator,FALSE,FALSE,0); + + // Create playlist in parent directory + playlist_create_in_parent_dir = gtk_check_button_new_with_label(_("Create playlist in the parent directory")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_create_in_parent_dir,FALSE,FALSE,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir),PLAYLIST_CREATE_IN_PARENT_DIR); + gtk_tooltips_set_tip(Tips,playlist_create_in_parent_dir,_("If activated, the playlist will be created " + "in the parent directory."),NULL); + + // DOS Separator + playlist_use_dos_separator = gtk_check_button_new_with_label(_("Use DOS directory separator")); +#ifndef WIN32 // This has no sense under Win32, so we don't display it + gtk_box_pack_start(GTK_BOX(vbox),playlist_use_dos_separator,FALSE,FALSE,0); +#endif + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator),PLAYLIST_USE_DOS_SEPARATOR); + gtk_tooltips_set_tip(Tips,playlist_use_dos_separator,_("This option replaces the UNIX directory " + "separator '/' into DOS separator '\\'."),NULL); + + /* Playlist content */ + if (!PlayListContentMaskModel) + PlayListContentMaskModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING); + else + gtk_list_store_clear(PlayListContentMaskModel); + + Frame = gtk_frame_new(_("Playlist Content")); + gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0); + vbox = gtk_vbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(Frame),vbox); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + + playlist_content_none = gtk_radio_button_new_with_label(NULL,_("Write only list of files")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_content_none,FALSE,FALSE,0); + + playlist_content_filename = gtk_radio_button_new_with_label_from_widget( + GTK_RADIO_BUTTON(playlist_content_none),_("Write info using filename")); + gtk_box_pack_start(GTK_BOX(vbox),playlist_content_filename,FALSE,FALSE,0); + + playlist_content_mask = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(playlist_content_none), _("Write info using :")); + hbox = gtk_hbox_new(FALSE,0); + gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0); + gtk_box_pack_start(GTK_BOX(hbox),playlist_content_mask,FALSE,FALSE,0); + // Set a label, a combobox and un editor button in the 3rd radio button + PlayListContentMaskCombo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(PlayListContentMaskModel), MISC_COMBO_TEXT); + gtk_box_pack_start(GTK_BOX(hbox),PlayListContentMaskCombo,FALSE,FALSE,0); + // History list + Load_Playlist_Content_Mask_List(PlayListContentMaskModel, MISC_COMBO_TEXT); + Add_String_To_Combo_List(PlayListContentMaskModel, PLAYLIST_CONTENT_MASK_VALUE); + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child), PLAYLIST_CONTENT_MASK_VALUE); + + // Mask status icon + MaskStatusIconBox1 = Create_Pixmap_Icon_With_Event_Box("easytag-forbidden"); + gtk_box_pack_start(GTK_BOX(hbox),MaskStatusIconBox1,FALSE,FALSE,0); + gtk_tooltips_set_tip(Tips,MaskStatusIconBox1,_("Invalid Scanner Mask"),NULL); + // Signal connection to check if mask is correct into the mask entry + g_signal_connect_swapped(G_OBJECT(GTK_BIN(PlayListContentMaskCombo)->child),"changed", + G_CALLBACK(Playlist_Check_Content_Mask),G_OBJECT(MaskStatusIconBox1)); + + // Button for Mask editor + Button = gtk_button_new(); + Icon = gtk_image_new_from_stock("easytag-mask", GTK_ICON_SIZE_BUTTON); + gtk_container_add(GTK_CONTAINER(Button),Icon); + gtk_box_pack_start(GTK_BOX(hbox),Button,FALSE,FALSE,0); + gtk_button_set_relief(GTK_BUTTON(Button),GTK_RELIEF_NONE); + gtk_tooltips_set_tip(Tips,Button,_("Edit Masks"),NULL); + // The masks will be edited into a tab of the preferences window. In the future... + //g_signal_connect(G_OBJECT(Button),"clicked",(GtkSignalFunc)???,NULL); + // FIX ME : edit the masks + gtk_widget_set_sensitive(GTK_WIDGET(Button),FALSE); + + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_none), PLAYLIST_CONTENT_NONE); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_filename),PLAYLIST_CONTENT_FILENAME); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_content_mask), PLAYLIST_CONTENT_MASK); + + + /* Separator line */ + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0); + + ButtonBox = gtk_hbutton_box_new (); + gtk_box_pack_start(GTK_BOX(VBox),ButtonBox,FALSE,FALSE,0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(ButtonBox),GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(ButtonBox), 10); + + /* Button to Cancel */ + Button = Create_Button_With_Pixmap(BUTTON_CLOSE); + gtk_container_add(GTK_CONTAINER(ButtonBox),Button); + GTK_WIDGET_SET_FLAGS(Button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(Button); + g_signal_connect(G_OBJECT(Button),"clicked", G_CALLBACK(Destroy_Write_Playlist_Window),NULL); + + /* Button to Write the playlist */ + Button = Create_Button_With_Pixmap(BUTTON_WRITE); + gtk_container_add(GTK_CONTAINER(ButtonBox),Button); + GTK_WIDGET_SET_FLAGS(Button,GTK_CAN_DEFAULT); + g_signal_connect_swapped(G_OBJECT(Button),"clicked",G_CALLBACK(Playlist_Write_Button_Pressed),NULL); + + gtk_widget_show_all(WritePlaylistWindow); + if (PLAYLIST_WINDOW_X > 0 && PLAYLIST_WINDOW_Y > 0) + gdk_window_move(WritePlaylistWindow->window,PLAYLIST_WINDOW_X,PLAYLIST_WINDOW_Y); + + /* To initialize the mask status icon and visibility */ + g_signal_emit_by_name(G_OBJECT(GTK_BIN(PlayListNameMaskCombo)->child),"changed"); + g_signal_emit_by_name(G_OBJECT(GTK_BIN(PlayListContentMaskCombo)->child),"changed"); +} + +void Destroy_Write_Playlist_Window (void) +{ + if (WritePlaylistWindow) + { + /* Save combobox history lists before exit */ + Save_Play_List_Name_List(PlayListNameMaskModel, MISC_COMBO_TEXT); + Save_Playlist_Content_Mask_List(PlayListContentMaskModel, MISC_COMBO_TEXT); + + Write_Playlist_Window_Apply_Changes(); + + gtk_widget_destroy(WritePlaylistWindow); + WritePlaylistWindow = (GtkWidget *)NULL; + } +} + +/* + * For the configuration file... + */ +void Write_Playlist_Window_Apply_Changes (void) +{ + if (WritePlaylistWindow) + { + gint x, y, width, height; + + if ( WritePlaylistWindow->window && gdk_window_is_visible(WritePlaylistWindow->window) + && gdk_window_get_state(WritePlaylistWindow->window)!=GDK_WINDOW_STATE_MAXIMIZED ) + { + // Position and Origin of the window + gdk_window_get_root_origin(WritePlaylistWindow->window,&x,&y); + PLAYLIST_WINDOW_X = x; + PLAYLIST_WINDOW_Y = y; + gdk_window_get_size(WritePlaylistWindow->window,&width,&height); + PLAYLIST_WINDOW_WIDTH = width; + PLAYLIST_WINDOW_HEIGHT = height; + } + + /* List of variables also set in the function 'Playlist_Write_Button_Pressed' */ + if (PLAYLIST_NAME) g_free(PLAYLIST_NAME); + PLAYLIST_NAME = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListNameMaskCombo)->child))); + PLAYLIST_USE_MASK_NAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name)); + PLAYLIST_USE_DIR_NAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name)); + + PLAYLIST_ONLY_SELECTED_FILES = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files)); + PLAYLIST_FULL_PATH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path)); + PLAYLIST_RELATIVE_PATH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path)); + PLAYLIST_CREATE_IN_PARENT_DIR = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir)); + PLAYLIST_USE_DOS_SEPARATOR = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator)); + + PLAYLIST_CONTENT_NONE = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none)); + PLAYLIST_CONTENT_FILENAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename)); + PLAYLIST_CONTENT_MASK = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask)); + if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE); + PLAYLIST_CONTENT_MASK_VALUE = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child))); + } +} + +gboolean Write_Playlist_Window_Key_Press (GtkWidget *window, GdkEvent *event) +{ + GdkEventKey *kevent; + + if (event && event->type == GDK_KEY_PRESS) + { + kevent = (GdkEventKey *)event; + switch(kevent->keyval) + { + case GDK_Escape: + Destroy_Write_Playlist_Window(); + break; + } + } + return FALSE; +} + +void Playlist_Write_Button_Pressed (void) +{ + gchar *playlist_name = NULL; + gchar *playlist_path_utf8; // Path + gchar *playlist_basename_utf8; // Filename + gchar *playlist_name_utf8; // Path + filename + gchar *temp; + FILE *file; + gchar *msg; + GtkWidget *msgbox; + gint msgbox_button = 0; + + + // Check if playlist name was filled + if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name)) + && g_utf8_strlen(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListNameMaskCombo)->child)), -1)<=0 ) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name),TRUE); + + /* List of variables also set in the function 'Write_Playlist_Window_Apply_Changes' */ + /***if (PLAYLIST_NAME) g_free(PLAYLIST_NAME); + PLAYLIST_NAME = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListNameMaskCombo)->child))); + PLAYLIST_USE_MASK_NAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_mask_name)); + PLAYLIST_USE_DIR_NAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dir_name)); + + PLAYLIST_ONLY_SELECTED_FILES = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_only_selected_files)); + PLAYLIST_FULL_PATH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_full_path)); + PLAYLIST_RELATIVE_PATH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_relative_path)); + PLAYLIST_CREATE_IN_PARENT_DIR = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_create_in_parent_dir)); + PLAYLIST_USE_DOS_SEPARATOR = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_use_dos_separator)); + + PLAYLIST_CONTENT_NONE = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_none)); + PLAYLIST_CONTENT_FILENAME = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_filename)); + PLAYLIST_CONTENT_MASK = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_content_mask)); + if (PLAYLIST_CONTENT_MASK_VALUE) g_free(PLAYLIST_CONTENT_MASK_VALUE); + PLAYLIST_CONTENT_MASK_VALUE = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child)));***/ + Write_Playlist_Window_Apply_Changes(); + + // Path of the playlist file (may be truncated later if PLAYLIST_CREATE_IN_PARENT_DIR is TRUE) + playlist_path_utf8 = filename_to_display(Browser_Get_Current_Path()); + + // Build the playlist file name + if (PLAYLIST_USE_MASK_NAME) + { + + if (!ETCore->ETFileList) + return; + + Add_String_To_Combo_List(PlayListNameMaskModel, PLAYLIST_NAME); + + // Generate filename from tag of the current selected file (hummm FIX ME) + temp = filename_from_display(PLAYLIST_NAME); + playlist_basename_utf8 = Scan_Generate_New_Filename_From_Mask(ETCore->ETFileDisplayed,temp,FALSE); + g_free(temp); + + // Replace Characters (with scanner) + if (RFS_CONVERT_UNDERSCORE_AND_P20_INTO_SPACE) + { + Scan_Convert_Underscore_Into_Space(playlist_basename_utf8); + Scan_Convert_P20_Into_Space(playlist_basename_utf8); + } + if (RFS_CONVERT_SPACE_INTO_UNDERSCORE) + { + Scan_Convert_Space_Into_Undescore(playlist_basename_utf8); + } + + }else // PLAYLIST_USE_DIR_NAME + { + + if ( strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S)==0 ) + { + playlist_basename_utf8 = g_strdup("playlist"); + }else + { + gchar *tmp_string = g_strdup(playlist_path_utf8); + // Remove last '/' + if (tmp_string[strlen(tmp_string)-1]==G_DIR_SEPARATOR) + tmp_string[strlen(tmp_string)-1] = '\0'; + // Get directory name + temp = g_path_get_basename(tmp_string); + playlist_basename_utf8 = g_strdup(temp); + g_free(tmp_string); + g_free(temp); + } + + } + + // Must be placed after "Build the playlist file name", as we can truncate the path! + if (PLAYLIST_CREATE_IN_PARENT_DIR) + { + if ( (strcmp(playlist_path_utf8,G_DIR_SEPARATOR_S) != 0) ) + { + gchar *tmp; + // Remove last '/' + if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR) + playlist_path_utf8[strlen(playlist_path_utf8)-1] = '\0'; + // Get parent directory + if ( (tmp=strrchr(playlist_path_utf8,G_DIR_SEPARATOR)) != NULL ) + *(tmp + 1) = '\0'; + } + } + + // Generate path + filename of playlist + if (playlist_path_utf8[strlen(playlist_path_utf8)-1]==G_DIR_SEPARATOR) + playlist_name_utf8 = g_strconcat(playlist_path_utf8,playlist_basename_utf8,".m3u",NULL); + else + playlist_name_utf8 = g_strconcat(playlist_path_utf8,G_DIR_SEPARATOR_S,playlist_basename_utf8,".m3u",NULL); + + g_free(playlist_path_utf8); + g_free(playlist_basename_utf8); + + playlist_name = filename_from_display(playlist_name_utf8); + + // Check if file exists + if (CONFIRM_WRITE_PLAYLIST) + { + if ( (file=fopen(playlist_name,"r")) != NULL ) + { + fclose(file); + msg = g_strdup_printf(_("Playlist file '%s' already exists!\nOverwrite?"),playlist_name_utf8); + msgbox = msg_box_new(_("Write Playlist..."),msg,GTK_STOCK_DIALOG_QUESTION,BUTTON_NO,BUTTON_YES,0); + msg_box_hide_check_button(MSG_BOX(msgbox)); + msgbox_button = msg_box_run(MSG_BOX(msgbox)); + gtk_widget_destroy(msgbox); + g_free(msg); + } + } + + // Writing playlist if ok + if (msgbox_button==0 || msgbox_button==BUTTON_YES ) + { + if ( Write_Playlist(playlist_name) == FALSE ) + { + // Writing fails... + msg = g_strdup_printf(_("Can't write playlist file '%s'!\n(%s)"),playlist_name_utf8,g_strerror(errno)); + msgbox = msg_box_new(_("Error..."),msg,GTK_STOCK_DIALOG_ERROR,BUTTON_OK,0); + msg_box_hide_check_button(MSG_BOX(msgbox)); + msg_box_run(MSG_BOX(msgbox)); + gtk_widget_destroy(msgbox); + }else + { + msg = g_strdup_printf(_("Written playlist file '%s'"),playlist_name_utf8); + //msgbox = msg_box_new(_("Information..."),msg,GTK_STOCK_DIALOG_INFO,BUTTON_OK,0); + Statusbar_Message(msg,TRUE); + } + g_free(msg); + } + g_free(playlist_name_utf8); + g_free(playlist_name); +} + +gboolean Playlist_Check_Content_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source) +{ + gchar *tmp = NULL; + gchar *mask = NULL; + + + if (!widget_to_show_hide || !widget_source) + goto Bad_Mask; + + mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget_source))); + if (!mask || strlen(mask)<1) + goto Bad_Mask; + + while (mask) + { + if ( (tmp=strrchr(mask,'%'))==NULL ) + { + /* There is no more code. */ + /* No code in mask is accepted. */ + goto Good_Mask; + } + if (strlen(tmp)>1 && (tmp[1]=='t' || tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='y' || + tmp[1]=='g' || tmp[1]=='n' || tmp[1]=='l' || tmp[1]=='c' || tmp[1]=='i')) + { + /* The code is valid. */ + /* No separator is accepted. */ + *(mask+strlen(mask)-strlen(tmp)) = '\0'; + }else + { + goto Bad_Mask; + } + } + + Bad_Mask: + g_free(mask); + gtk_widget_show(GTK_WIDGET(widget_to_show_hide)); + return FALSE; + + Good_Mask: + g_free(mask); + gtk_widget_hide(GTK_WIDGET(widget_to_show_hide)); + return TRUE; +} + +/* + * Function to replace UNIX ForwardSlash with a DOS BackSlash + */ +void Playlist_Convert_Forwardslash_Into_Backslash (gchar *string) +{ + gchar *tmp; + + while ((tmp=strchr(string,'/'))!=NULL) + *tmp = '\\'; +} + + +/* + * Write a playlist + * - 'playlist_name' in file system encoding (not UTF-8) + */ +gboolean Write_Playlist (gchar *playlist_name) +{ + FILE *file; + ET_File *etfile; + GList *etfilelist = NULL; + gchar *filename; + gchar *playlist_name_utf8 = filename_to_display(playlist_name); + gchar *basedir; + gchar *temp; + gint duration; + + if ((file = fopen(playlist_name,"wb")) == NULL) + { + Log_Print(_("ERROR while opening file: '%s' (%s)."),playlist_name_utf8,g_strerror(errno)); + g_free(playlist_name_utf8); + return FALSE; + } + + /* 'base directory' where is located the playlist. Used also to write file with a + * relative path for file located in this directory and sub-directories + */ + basedir = g_path_get_dirname(playlist_name); + + // 1) First line of the file (if playlist content is not set to "write only list of files") + if (!PLAYLIST_CONTENT_NONE) + { + fprintf(file,"#EXTM3U\r\n"); + } + + if (PLAYLIST_ONLY_SELECTED_FILES) + { + GList *selfilelist = NULL; + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(BrowserList)); + + selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL); + while (selfilelist) + { + etfile = Browser_List_Get_ETFile_From_Path(selfilelist->data); + etfilelist = g_list_append(etfilelist, etfile); + + if (!selfilelist->next) break; + selfilelist = selfilelist->next; + } + + g_list_foreach(selfilelist, (GFunc) gtk_tree_path_free, NULL); + g_list_free(selfilelist); + }else + { + etfilelist = g_list_first(ETCore->ETFileList); + } + while (etfilelist) + { + etfile = (ET_File *)etfilelist->data; + filename = ((File_Name *)etfile->FileNameCur->data)->value; + duration = ((ET_File_Info *)etfile->ETFileInfo)->duration; + + if (PLAYLIST_RELATIVE_PATH) + { + // Keep only files in this directory and sub-dirs + if ( strncmp(filename,basedir,strlen(basedir))==0 ) + { + // 2) Write the header + if (PLAYLIST_CONTENT_NONE) + { + // No header written + }else if (PLAYLIST_CONTENT_FILENAME) + { + // Header uses only filename + temp = g_path_get_basename(filename); + fprintf(file,"#EXTINF:%d,%s\r\n",duration,temp); // Must be written in system encoding (not UTF-8) + g_free(temp); + }else if (PLAYLIST_CONTENT_MASK) + { + // Header uses generated filename from a mask + gchar *mask = filename_from_display(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child))); + // Special case : we don't replace illegal characters and don't check if there is a directory separator in the mask. + gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE); + gchar *filename_generated = filename_from_display(filename_generated_utf8); + fprintf(file,"#EXTINF:%d,%s\r\n",duration,filename_generated); // Must be written in system encoding (not UTF-8) + g_free(mask); + g_free(filename_generated_utf8); + } + + // 3) Write the file path + if (PLAYLIST_USE_DOS_SEPARATOR) + { + gchar *filename_conv = g_strdup(filename+strlen(basedir)+1); + Playlist_Convert_Forwardslash_Into_Backslash(filename_conv); + fprintf(file,"%s\r\n",filename_conv); // Must be written in system encoding (not UTF-8) + g_free(filename_conv); + }else + { + fprintf(file,"%s\r\n",filename+strlen(basedir)+1); // Must be written in system encoding (not UTF-8) + } + } + }else // PLAYLIST_FULL_PATH + { + // 2) Write the header + if (PLAYLIST_CONTENT_NONE) + { + // No header written + }else if (PLAYLIST_CONTENT_FILENAME) + { + // Header uses only filename + temp = g_path_get_basename(filename); + fprintf(file,"#EXTINF:%d,%s\r\n",duration,temp); // Must be written in system encoding (not UTF-8) + g_free(temp); + }else if (PLAYLIST_CONTENT_MASK) + { + // Header uses generated filename from a mask + gchar *mask = filename_from_display(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(PlayListContentMaskCombo)->child))); + gchar *filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(etfile,mask,TRUE); + gchar *filename_generated = filename_from_display(filename_generated_utf8); + fprintf(file,"#EXTINF:%d,%s\r\n",duration,filename_generated); // Must be written in system encoding (not UTF-8) + g_free(mask); + g_free(filename_generated_utf8); + } + + // 3) Write the file path + if (PLAYLIST_USE_DOS_SEPARATOR) + { + gchar *filename_conv = g_strdup(filename); + Playlist_Convert_Forwardslash_Into_Backslash(filename_conv); + fprintf(file,"%s\r\n",filename_conv); // Must be written in system encoding (not UTF-8) + g_free(filename_conv); + }else + { + fprintf(file,"%s\r\n",filename); // Must be written in system encoding (not UTF-8) + } + } + etfilelist = etfilelist->next; + } + fclose(file); + + if (PLAYLIST_ONLY_SELECTED_FILES) + g_list_free(etfilelist); + g_free(playlist_name_utf8); + g_free(basedir); + return TRUE; +} + + + + +/***************************** + * Searching files functions * + *****************************/ +/* + * The window to search keywords in the list of files. + */ +void Open_Search_File_Window (void) +{ + GtkWidget *VBox; + GtkWidget *Frame; + GtkWidget *Table; + GtkWidget *Label; + GtkWidget *Button; + GtkWidget *Separator; + GtkTooltips *Tips; + GtkWidget *ScrollWindow; + GtkTreeViewColumn* column; + GtkCellRenderer* renderer; + gchar *SearchResultList_Titles[] = { N_("File Name"), + N_("Title"), + N_("Artist"), + N_("Album"), + N_("CD"), + N_("Year"), + N_("Track"), + N_("Genre"), + N_("Comment"), + N_("Composer"), + N_("Orig. Artist"), + N_("Copyright"), + N_("URL"), + N_("Encoded by") + }; + + + if (SearchFileWindow != NULL) + { + gdk_window_raise(SearchFileWindow->window); + return; + } + + SearchFileWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(SearchFileWindow),_("Search a file")); + g_signal_connect(G_OBJECT(SearchFileWindow),"destroy", G_CALLBACK(Destroy_Search_File_Window),NULL); + g_signal_connect(G_OBJECT(SearchFileWindow),"delete_event", G_CALLBACK(Destroy_Search_File_Window),NULL); + g_signal_connect(G_OBJECT(SearchFileWindow),"key_press_event", G_CALLBACK(Search_File_Window_Key_Press),NULL); + gtk_window_set_default_size(GTK_WINDOW(SearchFileWindow),SEARCH_WINDOW_WIDTH,SEARCH_WINDOW_HEIGHT); + + // The tooltips + Tips = gtk_tooltips_new(); + + VBox = gtk_vbox_new(FALSE,0); + gtk_container_add(GTK_CONTAINER(SearchFileWindow),VBox); + gtk_container_set_border_width(GTK_CONTAINER(VBox), 1); + + Frame = gtk_frame_new(NULL); + //gtk_container_add(GTK_CONTAINER(SearchFileWindow),Frame); + gtk_box_pack_start(GTK_BOX(VBox),Frame,TRUE,TRUE,0); + gtk_container_set_border_width(GTK_CONTAINER(Frame),2); + + Table = gtk_table_new(3,6,FALSE); + gtk_container_add(GTK_CONTAINER(Frame),Table); + gtk_container_set_border_width(GTK_CONTAINER(Table), 2); + gtk_table_set_row_spacings(GTK_TABLE(Table),4); + gtk_table_set_col_spacings(GTK_TABLE(Table),4); + + // Words to search + if (!SearchStringModel) + SearchStringModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING); + else + gtk_list_store_clear(SearchStringModel); + + Label = gtk_label_new(_("Search :")); + gtk_misc_set_alignment(GTK_MISC(Label),1.0,0.5); + gtk_table_attach(GTK_TABLE(Table),Label,0,1,0,1,GTK_FILL,GTK_FILL,0,0); + SearchStringCombo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(SearchStringModel), MISC_COMBO_TEXT); + gtk_widget_set_size_request(GTK_WIDGET(SearchStringCombo),200,-1); + gtk_table_attach(GTK_TABLE(Table),SearchStringCombo,1,5,0,1,GTK_EXPAND|GTK_FILL,GTK_FILL,0,0); + // History List + Load_Search_File_List(SearchStringModel, MISC_COMBO_TEXT); + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(SearchStringCombo)->child),""); + gtk_tooltips_set_tip(Tips,GTK_WIDGET(GTK_ENTRY(GTK_BIN(SearchStringCombo)->child)), + _("Type the word to search into files. Or type nothing to display all files."),NULL); + + // Set content of the clipboard if available + gtk_editable_paste_clipboard(GTK_EDITABLE(GTK_BIN(SearchStringCombo)->child)); + + // Where... + Label = gtk_label_new(_("In :")); + gtk_misc_set_alignment(GTK_MISC(Label),1.0,0.5); + gtk_table_attach(GTK_TABLE(Table),Label,0,1,1,2,GTK_FILL,GTK_FILL,0,0); + SearchInFilename = gtk_check_button_new_with_label(_("the File Name")); + // Note : label changed to "the Tag" (to be the only one) to fix a Hungarian grammatical problem (which uses one word to say "in the tag" like here) + SearchInTag = gtk_check_button_new_with_label(_("the Tag")); + gtk_table_attach(GTK_TABLE(Table),SearchInFilename,1,2,1,2,GTK_FILL,GTK_FILL,0,0); + gtk_table_attach(GTK_TABLE(Table),SearchInTag,2,3,1,2,GTK_FILL,GTK_FILL,0,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(SearchInFilename),SEARCH_IN_FILENAME); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(SearchInTag),SEARCH_IN_TAG); + + Separator = gtk_vseparator_new(); + gtk_table_attach(GTK_TABLE(Table),Separator,3,4,1,2,GTK_FILL,GTK_FILL,4,0); + + // Property of the search + SearchCaseSensitive = gtk_check_button_new_with_label(_("Case sensitive")); + gtk_table_attach(GTK_TABLE(Table),SearchCaseSensitive,4,5,1,2,GTK_EXPAND|GTK_FILL,GTK_FILL,0,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(SearchCaseSensitive),SEARCH_CASE_SENSITIVE); + + // Results list + ScrollWindow = gtk_scrolled_window_new(NULL,NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWindow),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); + gtk_widget_set_size_request(GTK_WIDGET(ScrollWindow), -1, 130); + gtk_table_attach(GTK_TABLE(Table),ScrollWindow,0,6,2,3,GTK_EXPAND|GTK_FILL,GTK_EXPAND|GTK_FILL,0,0); + + SearchResultListModel = gtk_list_store_new(SEARCH_COLUMN_COUNT, + G_TYPE_STRING, /* Filename */ + G_TYPE_STRING, /* Title */ + G_TYPE_STRING, /* Artist */ + G_TYPE_STRING, /* Album */ + G_TYPE_STRING, /* Disc Number */ + G_TYPE_STRING, /* Year */ + G_TYPE_STRING, /* Track + Track Total */ + G_TYPE_STRING, /* Genre */ + G_TYPE_STRING, /* Comment */ + G_TYPE_STRING, /* Composer */ + G_TYPE_STRING, /* Orig. Artist */ + G_TYPE_STRING, /* Copyright */ + G_TYPE_STRING, /* URL */ + G_TYPE_STRING, /* Encoded by */ + + G_TYPE_INT, /* Font Weight for Filename */ + G_TYPE_INT, /* Font Weight for Title */ + G_TYPE_INT, /* Font Weight for Artist */ + G_TYPE_INT, /* Font Weight for Album */ + G_TYPE_INT, /* Font Weight for Disc Number */ + G_TYPE_INT, /* Font Weight for Year */ + G_TYPE_INT, /* Font Weight for Track + Track Total */ + G_TYPE_INT, /* Font Weight for Genre */ + G_TYPE_INT, /* Font Weight for Comment */ + G_TYPE_INT, /* Font Weight for Composer */ + G_TYPE_INT, /* Font Weight for Orig. Artist */ + G_TYPE_INT, /* Font Weight for Copyright */ + G_TYPE_INT, /* Font Weight for URL */ + G_TYPE_INT, /* Font Weight for Encoded by */ + + GDK_TYPE_COLOR, /* Color Weight for Filename */ + GDK_TYPE_COLOR, /* Color Weight for Title */ + GDK_TYPE_COLOR, /* Color Weight for Artist */ + GDK_TYPE_COLOR, /* Color Weight for Album */ + GDK_TYPE_COLOR, /* Color Weight for Disc Number */ + GDK_TYPE_COLOR, /* Color Weight for Year */ + GDK_TYPE_COLOR, /* Color Weight for Track + Track Total */ + GDK_TYPE_COLOR, /* Color Weight for Genre */ + GDK_TYPE_COLOR, /* Color Weight for Comment */ + GDK_TYPE_COLOR, /* Color Weight for Composer */ + GDK_TYPE_COLOR, /* Color Weight for Orig. Artist */ + GDK_TYPE_COLOR, /* Color Weight for Copyright */ + GDK_TYPE_COLOR, /* Color Weight for URL */ + GDK_TYPE_COLOR, /* Color Weight for Encoded by */ + + G_TYPE_POINTER); + SearchResultList = gtk_tree_view_new_with_model(GTK_TREE_MODEL(SearchResultListModel)); + + renderer = gtk_cell_renderer_text_new(); /* Filename */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[0]), renderer, + "text", SEARCH_RESULT_FILENAME, + "weight", SEARCH_RESULT_FILENAME_WEIGHT, + "foreground-gdk", SEARCH_RESULT_FILENAME_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Title */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[1]), renderer, + "text", SEARCH_RESULT_TITLE, + "weight", SEARCH_RESULT_TITLE_WEIGHT, + "foreground-gdk", SEARCH_RESULT_TITLE_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Artist */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[2]), renderer, + "text", SEARCH_RESULT_ARTIST, + "weight", SEARCH_RESULT_ARTIST_WEIGHT, + "foreground-gdk", SEARCH_RESULT_ARTIST_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Album */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[3]), renderer, + "text", SEARCH_RESULT_ALBUM, + "weight", SEARCH_RESULT_ALBUM_WEIGHT, + "foreground-gdk", SEARCH_RESULT_ALBUM_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Disc Number */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[4]), renderer, + "text", SEARCH_RESULT_DISC_NUMBER, + "weight", SEARCH_RESULT_DISC_NUMBER_WEIGHT, + "foreground-gdk", SEARCH_RESULT_DISC_NUMBER_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Year */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[5]), renderer, + "text", SEARCH_RESULT_YEAR, + "weight", SEARCH_RESULT_YEAR_WEIGHT, + "foreground-gdk", SEARCH_RESULT_YEAR_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Track */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[6]), renderer, + "text", SEARCH_RESULT_TRACK, + "weight", SEARCH_RESULT_TRACK_WEIGHT, + "foreground-gdk", SEARCH_RESULT_TRACK_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Genre */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[7]), renderer, + "text", SEARCH_RESULT_GENRE, + "weight", SEARCH_RESULT_GENRE_WEIGHT, + "foreground-gdk", SEARCH_RESULT_GENRE_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Comment */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[8]), renderer, + "text", SEARCH_RESULT_COMMENT, + "weight", SEARCH_RESULT_COMMENT_WEIGHT, + "foreground-gdk", SEARCH_RESULT_COMMENT_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Composer */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[9]), renderer, + "text", SEARCH_RESULT_COMPOSER, + "weight", SEARCH_RESULT_COMPOSER_WEIGHT, + "foreground-gdk", SEARCH_RESULT_COMPOSER_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Orig. Artist */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[10]), renderer, + "text", SEARCH_RESULT_ORIG_ARTIST, + "weight", SEARCH_RESULT_ORIG_ARTIST_WEIGHT, + "foreground-gdk", SEARCH_RESULT_ORIG_ARTIST_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Copyright */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[11]), renderer, + "text", SEARCH_RESULT_COPYRIGHT, + "weight", SEARCH_RESULT_COPYRIGHT_WEIGHT, + "foreground-gdk", SEARCH_RESULT_COPYRIGHT_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* URL */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[12]), renderer, + "text", SEARCH_RESULT_URL, + "weight", SEARCH_RESULT_URL_WEIGHT, + "foreground-gdk", SEARCH_RESULT_URL_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + renderer = gtk_cell_renderer_text_new(); /* Encoded by */ + column = gtk_tree_view_column_new_with_attributes(_(SearchResultList_Titles[13]), renderer, + "text", SEARCH_RESULT_ENCODED_BY, + "weight", SEARCH_RESULT_ENCODED_BY_WEIGHT, + "foreground-gdk", SEARCH_RESULT_ENCODED_BY_FOREGROUND, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(SearchResultList), column); + gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); + + gtk_container_add(GTK_CONTAINER(ScrollWindow),SearchResultList); + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(SearchResultList)), + GTK_SELECTION_MULTIPLE); + //gtk_tree_view_columns_autosize(GTK_TREE_VIEW(SearchResultList)); // Doesn't seem to work... + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(SearchResultList), FALSE); + gtk_widget_set_sensitive(GTK_WIDGET(SearchResultList), FALSE); + g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(SearchResultList))), + "changed", G_CALLBACK(Search_Result_List_Row_Selected), NULL); + + // Button to run the search + Button = Create_Button_With_Pixmap(BUTTON_SEARCH); + gtk_table_attach(GTK_TABLE(Table),Button,5,6,0,1,GTK_FILL,GTK_FILL,0,0); + GTK_WIDGET_SET_FLAGS(Button,GTK_CAN_DEFAULT); + gtk_widget_grab_default(Button); + g_signal_connect(G_OBJECT(Button),"clicked", G_CALLBACK(Search_File),NULL); + g_signal_connect(G_OBJECT(GTK_BIN(SearchStringCombo)->child),"activate", G_CALLBACK(Search_File),NULL); + + // Button to cancel + Button = Create_Button_With_Pixmap(BUTTON_CLOSE); + gtk_table_attach(GTK_TABLE(Table),Button,5,6,1,2,GTK_FILL,GTK_FILL,0,0); + g_signal_connect(G_OBJECT(Button),"clicked", G_CALLBACK(Destroy_Search_File_Window),NULL); + + // Status bar + SearchStatusBar = gtk_statusbar_new(); + //gtk_table_attach(GTK_TABLE(Table),SearchStatusBar,0,6,3,4,GTK_FILL,GTK_FILL,0,0); + gtk_box_pack_start(GTK_BOX(VBox),SearchStatusBar,FALSE,TRUE,0); + SearchStatusBarContext = gtk_statusbar_get_context_id(GTK_STATUSBAR(SearchStatusBar),"Messages"); + gtk_statusbar_push(GTK_STATUSBAR(SearchStatusBar),SearchStatusBarContext,_("Ready to search...")); + + gtk_widget_show_all(SearchFileWindow); + + if (SET_SEARCH_WINDOW_POSITION) + gdk_window_move(SearchFileWindow->window, SEARCH_WINDOW_X, SEARCH_WINDOW_Y); + //else + // gtk_window_set_position(GTK_WINDOW(SearchFileWindow), GTK_WIN_POS_CENTER_ON_PARENT); // Must use gtk_window_set_transient_for to work +} + +void Destroy_Search_File_Window (void) +{ + if (SearchFileWindow) + { + /* Save combobox history lists before exit */ + Save_Search_File_List(SearchStringModel, MISC_COMBO_TEXT); + + Search_File_Window_Apply_Changes(); + + gtk_widget_destroy(SearchFileWindow); + SearchFileWindow = (GtkWidget *)NULL; + } +} + +/* + * For the configuration file... + */ +void Search_File_Window_Apply_Changes (void) +{ + if (SearchFileWindow) + { + gint x, y, width, height; + + if ( SearchFileWindow->window!=NULL && gdk_window_is_visible(SearchFileWindow->window) + && gdk_window_get_state(SearchFileWindow->window)!=GDK_WINDOW_STATE_MAXIMIZED ) + { + // Position and Origin of the scanner window + gdk_window_get_root_origin(SearchFileWindow->window,&x,&y); + SEARCH_WINDOW_X = x; + SEARCH_WINDOW_Y = y; + gdk_window_get_size(SearchFileWindow->window,&width,&height); + SEARCH_WINDOW_WIDTH = width; + SEARCH_WINDOW_HEIGHT = height; + } + + SEARCH_IN_FILENAME = GTK_TOGGLE_BUTTON(SearchInFilename)->active; + SEARCH_IN_TAG = GTK_TOGGLE_BUTTON(SearchInTag)->active; + SEARCH_CASE_SENSITIVE = GTK_TOGGLE_BUTTON(SearchCaseSensitive)->active; + } +} + +gboolean Search_File_Window_Key_Press (GtkWidget *window, GdkEvent *event) +{ + GdkEventKey *kevent; + + if (event && event->type == GDK_KEY_PRESS) + { + kevent = (GdkEventKey *)event; + switch(kevent->keyval) + { + case GDK_Escape: + Destroy_Search_File_Window(); + break; + } + } + return FALSE; +} + +/* + * This function and the one below could do with improving + * as we are looking up tag data twice (once when searching, once when adding to list) + */ +void Search_File (GtkWidget *search_button) +{ + const gchar *string_to_search = NULL; + GList *etfilelist; + ET_File *ETFile; + gchar *msg; + gchar *temp = NULL; + gchar *title2, *artist2, *album2, *disc_number2, *year2, *track2, + *track_total2, *genre2, *comment2, *composer2, *orig_artist2, + *copyright2, *url2, *encoded_by2, *string_to_search2; + gint resultCount = 0; + + + if (!SearchStringCombo || !SearchInFilename || !SearchInTag || !SearchResultList) + return; + + string_to_search = gtk_entry_get_text(GTK_ENTRY(GTK_BIN(SearchStringCombo)->child)); + if (!string_to_search) + return; + + Add_String_To_Combo_List(SearchStringModel, (gchar*)string_to_search); + + gtk_widget_set_sensitive(GTK_WIDGET(search_button),FALSE); + gtk_list_store_clear(SearchResultListModel); + gtk_statusbar_push(GTK_STATUSBAR(SearchStatusBar),SearchStatusBarContext,""); + + etfilelist = g_list_first(ETCore->ETFileList); + while (etfilelist) + { + ETFile = (ET_File *)etfilelist->data; + + // Search in the filename + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(SearchInFilename))) + { + gchar *filename_utf8 = ((File_Name *)ETFile->FileNameNew->data)->value_utf8; + gchar *basename_utf8; + + // To search without case sensivity + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(SearchCaseSensitive))) + { + temp = g_path_get_basename(filename_utf8); + basename_utf8 = g_utf8_casefold(temp, -1); + g_free(temp); + string_to_search2 = g_utf8_casefold(string_to_search, -1); + } else + { + basename_utf8 = g_path_get_basename(filename_utf8); + string_to_search2 = g_strdup(string_to_search); + } + + if ( basename_utf8 && strstr(basename_utf8,string_to_search2) ) + { + Add_Row_To_Search_Result_List(ETFile, string_to_search2); + etfilelist = etfilelist->next; + g_free(basename_utf8); + g_free(string_to_search2); + continue; + } + g_free(basename_utf8); + g_free(string_to_search2); + } + + // Search in the tag + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(SearchInTag))) + { + File_Tag *FileTag = (File_Tag *)ETFile->FileTag->data; + + // To search with or without case sensivity + if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(SearchCaseSensitive))) + { + // To search without case sensivity... + // Duplicate and convert the strings into UTF-8 in loxer case + if (FileTag->title) title2 = g_utf8_casefold(FileTag->title, -1); else title2 = NULL; + if (FileTag->artist) artist2 = g_utf8_casefold(FileTag->artist, -1); else artist2 = NULL; + if (FileTag->album) album2 = g_utf8_casefold(FileTag->album, -1); else album2 = NULL; + if (FileTag->disc_number) disc_number2 = g_utf8_casefold(FileTag->disc_number, -1); else disc_number2 = NULL; + if (FileTag->year) year2 = g_utf8_casefold(FileTag->year, -1); else year2 = NULL; + if (FileTag->track) track2 = g_utf8_casefold(FileTag->track, -1); else track2 = NULL; + if (FileTag->track_total) track_total2 = g_utf8_casefold(FileTag->track_total, -1); else track_total2 = NULL; + if (FileTag->genre) genre2 = g_utf8_casefold(FileTag->genre, -1); else genre2 = NULL; + if (FileTag->comment) comment2 = g_utf8_casefold(FileTag->comment, -1); else comment2 = NULL; + if (FileTag->composer) composer2 = g_utf8_casefold(FileTag->composer, -1); else composer2 = NULL; + if (FileTag->orig_artist) orig_artist2 = g_utf8_casefold(FileTag->orig_artist, -1); else orig_artist2 = NULL; + if (FileTag->copyright) copyright2 = g_utf8_casefold(FileTag->copyright, -1); else copyright2 = NULL; + if (FileTag->url) url2 = g_utf8_casefold(FileTag->url, -1); else url2 = NULL; + if (FileTag->encoded_by) encoded_by2 = g_utf8_casefold(FileTag->encoded_by, -1); else encoded_by2 = NULL; + string_to_search2 = g_utf8_strdown(string_to_search, -1); + }else + { + // To search with case sensivity... + // Duplicate and convert the strings into UTF-8 + title2 = g_strdup(FileTag->title); + artist2 = g_strdup(FileTag->artist); + album2 = g_strdup(FileTag->album); + disc_number2 = g_strdup(FileTag->disc_number); + year2 = g_strdup(FileTag->year); + track2 = g_strdup(FileTag->track); + track_total2 = g_strdup(FileTag->track_total); + genre2 = g_strdup(FileTag->genre); + comment2 = g_strdup(FileTag->comment); + composer2 = g_strdup(FileTag->composer); + orig_artist2 = g_strdup(FileTag->orig_artist); + copyright2 = g_strdup(FileTag->copyright); + url2 = g_strdup(FileTag->url); + encoded_by2 = g_strdup(FileTag->encoded_by); + string_to_search2 = g_strdup(string_to_search); + } + + // FIX ME : should use UTF-8 functions? + if ( (title2 && strstr(title2, string_to_search2) ) + || (artist2 && strstr(artist2, string_to_search2) ) + || (album2 && strstr(album2, string_to_search2) ) + || (disc_number2 && strstr(disc_number2, string_to_search2) ) + || (year2 && strstr(year2, string_to_search2) ) + || (track2 && strstr(track2, string_to_search2) ) + || (track_total2 && strstr(track_total2, string_to_search2) ) + || (genre2 && strstr(genre2, string_to_search2) ) + || (comment2 && strstr(comment2, string_to_search2) ) + || (composer2 && strstr(composer2, string_to_search2) ) + || (orig_artist2 && strstr(orig_artist2, string_to_search2) ) + || (copyright2 && strstr(copyright2, string_to_search2) ) + || (url2 && strstr(url2, string_to_search2) ) + || (encoded_by2 && strstr(encoded_by2, string_to_search2) ) ) + { + Add_Row_To_Search_Result_List(ETFile, string_to_search); + } + g_free(title2); + g_free(artist2); + g_free(album2); + g_free(disc_number2); + g_free(year2); + g_free(track2); + g_free(track_total2); + g_free(genre2); + g_free(comment2); + g_free(composer2); + g_free(orig_artist2); + g_free(copyright2); + g_free(url2); + g_free(encoded_by2); + g_free(string_to_search2); + } + etfilelist = etfilelist->next; + } + + gtk_widget_set_sensitive(GTK_WIDGET(search_button),TRUE); + + // Display the number of files in the statusbar + resultCount = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(SearchResultListModel), NULL); + msg = g_strdup_printf(_("Found : %d file(s)"), resultCount); + gtk_statusbar_push(GTK_STATUSBAR(SearchStatusBar),SearchStatusBarContext,msg); + g_free(msg); + + // Disable result list if no row inserted + if (resultCount > 0 ) + { + gtk_widget_set_sensitive(GTK_WIDGET(SearchResultList), TRUE); + } else + { + gtk_widget_set_sensitive(GTK_WIDGET(SearchResultList), FALSE); + } +} + +void Add_Row_To_Search_Result_List(ET_File *ETFile,const gchar *string_to_search) +{ + gchar *SearchResultList_Text[14]; // Because : 14 columns to display + gint SearchResultList_Weight[14] = {PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL, + PANGO_WEIGHT_NORMAL, PANGO_WEIGHT_NORMAL}; + GdkColor *SearchResultList_Color[14] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + gchar *track, *track_total; + gboolean case_sensitive; + gint column; + GtkTreeIter iter; + + if (!ETFile || !string_to_search) + return; + + case_sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(SearchCaseSensitive)); + + // Filename + SearchResultList_Text[SEARCH_RESULT_FILENAME] = g_path_get_basename( ((File_Name *)ETFile->FileNameNew->data)->value_utf8 ); + // Title + SearchResultList_Text[SEARCH_RESULT_TITLE] = g_strdup(((File_Tag *)ETFile->FileTag->data)->title); + // Artist + SearchResultList_Text[SEARCH_RESULT_ARTIST] = g_strdup(((File_Tag *)ETFile->FileTag->data)->artist); + // Album + SearchResultList_Text[SEARCH_RESULT_ALBUM] = g_strdup(((File_Tag *)ETFile->FileTag->data)->album); + // Disc Number + SearchResultList_Text[SEARCH_RESULT_DISC_NUMBER] = g_strdup(((File_Tag *)ETFile->FileTag->data)->disc_number); + // Year + SearchResultList_Text[SEARCH_RESULT_YEAR] = g_strdup(((File_Tag *)ETFile->FileTag->data)->year); + //Genre + SearchResultList_Text[SEARCH_RESULT_GENRE] = g_strdup(((File_Tag *)ETFile->FileTag->data)->genre); + // Comment + SearchResultList_Text[SEARCH_RESULT_COMMENT] = g_strdup(((File_Tag *)ETFile->FileTag->data)->comment); + // Composer + SearchResultList_Text[SEARCH_RESULT_COMPOSER] = g_strdup(((File_Tag *)ETFile->FileTag->data)->composer); + // Orig. Artist + SearchResultList_Text[SEARCH_RESULT_ORIG_ARTIST] = g_strdup(((File_Tag *)ETFile->FileTag->data)->orig_artist); + // Copyright + SearchResultList_Text[SEARCH_RESULT_COPYRIGHT] = g_strdup(((File_Tag *)ETFile->FileTag->data)->copyright); + // URL + SearchResultList_Text[SEARCH_RESULT_URL] = g_strdup(((File_Tag *)ETFile->FileTag->data)->url); + // Encoded by + SearchResultList_Text[SEARCH_RESULT_ENCODED_BY] = g_strdup(((File_Tag *)ETFile->FileTag->data)->encoded_by); + + // Track + track = ((File_Tag *)ETFile->FileTag->data)->track; + track_total = ((File_Tag *)ETFile->FileTag->data)->track_total; + if (track) + { + if (track_total) + SearchResultList_Text[SEARCH_RESULT_TRACK] = g_strconcat(track,"/",track_total,NULL); + else + SearchResultList_Text[SEARCH_RESULT_TRACK] = g_strdup(track); + } else + { + SearchResultList_Text[SEARCH_RESULT_TRACK] = NULL; + } + + + + // Highlight the keywords in the result list + // Don't display files to red if the searched string is '' (to display all files) + for (column=0;column<14;column++) + { + if (case_sensitive) + { + if ( SearchResultList_Text[column] && strlen(string_to_search) && strstr(SearchResultList_Text[column],string_to_search) ) + { + if (CHANGED_FILES_DISPLAYED_TO_BOLD) + SearchResultList_Weight[column] = PANGO_WEIGHT_BOLD; + else + SearchResultList_Color[column] = &RED; + } + + } else + { + // Search wasn't case sensitive + gchar *list_text = NULL; + gchar *string_to_search2 = g_utf8_casefold(string_to_search, -1); + + if (!SearchResultList_Text[column]) + { + g_free(string_to_search2); + continue; + } + + list_text = g_utf8_casefold(SearchResultList_Text[column], -1); + + if ( list_text && strlen(string_to_search2) && strstr(list_text,string_to_search2) ) + { + if (CHANGED_FILES_DISPLAYED_TO_BOLD) + SearchResultList_Weight[column] = PANGO_WEIGHT_BOLD; + else + SearchResultList_Color[column] = &RED; + } + + g_free(list_text); + g_free(string_to_search2); + } + } + + // Load the row in the list + gtk_list_store_append(SearchResultListModel, &iter); + gtk_list_store_set(SearchResultListModel, &iter, + SEARCH_RESULT_FILENAME, SearchResultList_Text[SEARCH_RESULT_FILENAME], + SEARCH_RESULT_TITLE, SearchResultList_Text[SEARCH_RESULT_TITLE], + SEARCH_RESULT_ARTIST, SearchResultList_Text[SEARCH_RESULT_ARTIST], + SEARCH_RESULT_ALBUM, SearchResultList_Text[SEARCH_RESULT_ALBUM], + SEARCH_RESULT_DISC_NUMBER, SearchResultList_Text[SEARCH_RESULT_DISC_NUMBER], + SEARCH_RESULT_YEAR, SearchResultList_Text[SEARCH_RESULT_YEAR], + SEARCH_RESULT_TRACK, SearchResultList_Text[SEARCH_RESULT_TRACK], + SEARCH_RESULT_GENRE, SearchResultList_Text[SEARCH_RESULT_GENRE], + SEARCH_RESULT_COMMENT, SearchResultList_Text[SEARCH_RESULT_COMMENT], + SEARCH_RESULT_COMPOSER, SearchResultList_Text[SEARCH_RESULT_COMPOSER], + SEARCH_RESULT_ORIG_ARTIST, SearchResultList_Text[SEARCH_RESULT_ORIG_ARTIST], + SEARCH_RESULT_COPYRIGHT, SearchResultList_Text[SEARCH_RESULT_COPYRIGHT], + SEARCH_RESULT_URL, SearchResultList_Text[SEARCH_RESULT_URL], + SEARCH_RESULT_ENCODED_BY, SearchResultList_Text[SEARCH_RESULT_ENCODED_BY], + + SEARCH_RESULT_FILENAME_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_FILENAME], + SEARCH_RESULT_TITLE_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_TITLE], + SEARCH_RESULT_ARTIST_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_ARTIST], + SEARCH_RESULT_ALBUM_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_ALBUM], + SEARCH_RESULT_DISC_NUMBER_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_DISC_NUMBER], + SEARCH_RESULT_YEAR_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_YEAR], + SEARCH_RESULT_TRACK_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_TRACK], + SEARCH_RESULT_GENRE_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_GENRE], + SEARCH_RESULT_COMMENT_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_COMMENT], + SEARCH_RESULT_COMPOSER_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_COMPOSER], + SEARCH_RESULT_ORIG_ARTIST_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_ORIG_ARTIST], + SEARCH_RESULT_COPYRIGHT_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_COPYRIGHT], + SEARCH_RESULT_URL_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_URL], + SEARCH_RESULT_ENCODED_BY_WEIGHT, SearchResultList_Weight[SEARCH_RESULT_ENCODED_BY], + + SEARCH_RESULT_FILENAME_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_FILENAME], + SEARCH_RESULT_TITLE_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_TITLE], + SEARCH_RESULT_ARTIST_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_ARTIST], + SEARCH_RESULT_ALBUM_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_ALBUM], + SEARCH_RESULT_DISC_NUMBER_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_DISC_NUMBER], + SEARCH_RESULT_YEAR_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_YEAR], + SEARCH_RESULT_TRACK_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_TRACK], + SEARCH_RESULT_GENRE_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_GENRE], + SEARCH_RESULT_COMMENT_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_COMMENT], + SEARCH_RESULT_COMPOSER_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_COMPOSER], + SEARCH_RESULT_ORIG_ARTIST_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_ORIG_ARTIST], + SEARCH_RESULT_COPYRIGHT_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_COPYRIGHT], + SEARCH_RESULT_URL_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_URL], + SEARCH_RESULT_ENCODED_BY_FOREGROUND, SearchResultList_Color[SEARCH_RESULT_ENCODED_BY], + + SEARCH_RESULT_POINTER, ETFile, + -1); + + // Frees allocated data + g_free(SearchResultList_Text[SEARCH_RESULT_FILENAME]); + g_free(SearchResultList_Text[SEARCH_RESULT_TITLE]); + g_free(SearchResultList_Text[SEARCH_RESULT_ARTIST]); + g_free(SearchResultList_Text[SEARCH_RESULT_ALBUM]); + g_free(SearchResultList_Text[SEARCH_RESULT_DISC_NUMBER]); + g_free(SearchResultList_Text[SEARCH_RESULT_YEAR]); + g_free(SearchResultList_Text[SEARCH_RESULT_TRACK]); + g_free(SearchResultList_Text[SEARCH_RESULT_GENRE]); + g_free(SearchResultList_Text[SEARCH_RESULT_COMMENT]); + g_free(SearchResultList_Text[SEARCH_RESULT_COMPOSER]); + g_free(SearchResultList_Text[SEARCH_RESULT_ORIG_ARTIST]); + g_free(SearchResultList_Text[SEARCH_RESULT_COPYRIGHT]); + g_free(SearchResultList_Text[SEARCH_RESULT_URL]); + g_free(SearchResultList_Text[SEARCH_RESULT_ENCODED_BY]); +} + +/* + * Callback to select-row event + * Select all results that are selected in the search result list also in the browser list + */ +void Search_Result_List_Row_Selected(GtkTreeSelection *selection, gpointer data) +{ + GList *selectedRows; + GList *selectedRowsCopy; + ET_File *ETFile; + GtkTreeIter currentFile; + gboolean found; + + selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL); + selectedRowsCopy = selectedRows; + + /* We might be called with no rows selected */ + if (g_list_length(selectedRows) == 0) + { + g_list_foreach(selectedRowsCopy, (GFunc) gtk_tree_path_free, NULL); + g_list_free(selectedRowsCopy); + return; + } + + Browser_List_Unselect_All_Files(); + + while (selectedRows) + { + found = gtk_tree_model_get_iter(GTK_TREE_MODEL(SearchResultListModel), ¤tFile, (GtkTreePath*)selectedRows->data); + if (found) + { + gtk_tree_model_get(GTK_TREE_MODEL(SearchResultListModel), ¤tFile, SEARCH_RESULT_POINTER, &ETFile, -1); + Browser_List_Select_File_By_Etfile(ETFile, TRUE); + Action_Select_Nth_File_By_Etfile(ETFile); + } + selectedRows = selectedRows->next; + } + + g_list_foreach(selectedRowsCopy, (GFunc) gtk_tree_path_free, NULL); + g_list_free(selectedRowsCopy); +} + + +/******************************************** + * Load Filenames from a TXT file functions * + ********************************************/ +/* + * The window to load the filenames from a txt. + */ +void Open_Load_Filename_Window (void) +{ + GtkWidget *VBox, *hbox; + GtkWidget *Frame; + GtkWidget *Label; + GtkWidget *ButtonBox; + GtkWidget *Button; + GtkWidget *Entry; + GtkWidget *ButtonLoad; + GtkWidget *Separator; + GtkWidget *ScrollWindow; + GtkWidget *loadedvbox; + GtkWidget *filelistvbox; + GtkWidget *vboxpaned; + GtkTooltips *Tips; + gchar *path; + GtkCellRenderer* renderer; + GtkTreeViewColumn* column; + + if (LoadFilenameWindow != NULL) + { + gdk_window_raise(LoadFilenameWindow->window); + return; + } + + LoadFilenameWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(LoadFilenameWindow),_("Load the filenames from a TXT file")); + gtk_window_set_transient_for(GTK_WINDOW(LoadFilenameWindow),GTK_WINDOW(MainWindow)); + g_signal_connect(G_OBJECT(LoadFilenameWindow),"destroy",G_CALLBACK(Destroy_Load_Filename_Window),NULL); + g_signal_connect(G_OBJECT(LoadFilenameWindow),"delete_event", G_CALLBACK(Destroy_Load_Filename_Window),NULL); + g_signal_connect(G_OBJECT(LoadFilenameWindow),"key_press_event", G_CALLBACK(Load_Filename_Window_Key_Press),NULL); + + // Just center on mainwindow + gtk_window_set_position(GTK_WINDOW(LoadFilenameWindow), GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_set_default_size(GTK_WINDOW(LoadFilenameWindow),LOAD_FILE_WINDOW_WIDTH,LOAD_FILE_WINDOW_HEIGHT); + + Tips = gtk_tooltips_new(); + + Frame = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(LoadFilenameWindow),Frame); + gtk_container_set_border_width(GTK_CONTAINER(Frame),2); + + VBox = gtk_vbox_new(FALSE,4); + gtk_container_add(GTK_CONTAINER(Frame),VBox); + gtk_container_set_border_width(GTK_CONTAINER(VBox), 2); + + // Hbox for file entry and browser/load buttons + hbox = gtk_hbox_new(FALSE,4); + gtk_box_pack_start(GTK_BOX(VBox),hbox,FALSE,TRUE,0); + + // File to load + if (!FileToLoadModel) + FileToLoadModel = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING); + else + gtk_list_store_clear(FileToLoadModel); + + Label = gtk_label_new(_("File :")); + gtk_misc_set_alignment(GTK_MISC(Label),1.0,0.5); + gtk_box_pack_start(GTK_BOX(hbox),Label,FALSE,FALSE,0); + FileToLoadCombo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(FileToLoadModel), MISC_COMBO_TEXT); + gtk_widget_set_size_request(GTK_WIDGET(FileToLoadCombo), 200, -1); + gtk_box_pack_start(GTK_BOX(hbox),FileToLoadCombo,TRUE,TRUE,0); + // History List + Load_File_To_Load_List(FileToLoadModel, MISC_COMBO_TEXT); + // Initial value + if ((path=Browser_Get_Current_Path())!=NULL) + gtk_entry_set_text(GTK_ENTRY(GTK_BIN(FileToLoadCombo)->child),path); + // the 'changed' signal is attached below to enable/disable the button to load + // Button 'browse' + Button = Create_Button_With_Pixmap(BUTTON_BROWSE); + gtk_box_pack_start(GTK_BOX(hbox),Button,FALSE,FALSE,0); + g_signal_connect_swapped(G_OBJECT(Button),"clicked", G_CALLBACK(File_Selection_Window_For_File), G_OBJECT(GTK_BIN(FileToLoadCombo)->child)); + // Button 'load' + // the signal attached to this button, to load the file, is placed after the LoadFileContentList definition + ButtonLoad = Create_Button_With_Icon_And_Label("easytag-add",_(" Load ")); + //ButtonLoad = gtk_button_new_with_label(_(" Load ")); + gtk_box_pack_start(GTK_BOX(hbox),ButtonLoad,FALSE,FALSE,0); + g_signal_connect_swapped(G_OBJECT(GTK_BIN(FileToLoadCombo)->child),"changed", G_CALLBACK(Button_Load_Set_Sensivity), G_OBJECT(ButtonLoad)); + + // Separator line + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0); + + loadedvbox = gtk_vbox_new(FALSE, 4); + + // Label of file content + Label = gtk_label_new(_("Loaded File Content :")); + gtk_box_pack_start(GTK_BOX(loadedvbox), Label, FALSE, FALSE, 0); + + // Content of the loaded file + ScrollWindow = gtk_scrolled_window_new(NULL,NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWindow),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); + gtk_widget_set_size_request(GTK_WIDGET(ScrollWindow), 250, 200); + LoadFileContentListModel = gtk_list_store_new(LOAD_FILE_CONTENT_COUNT, G_TYPE_STRING); + LoadFileContentList = gtk_tree_view_new_with_model(GTK_TREE_MODEL(LoadFileContentListModel)); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("", + renderer, "text", LOAD_FILE_CONTENT_TEXT, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(LoadFileContentList), column); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(LoadFileContentList), FALSE); + gtk_container_add(GTK_CONTAINER(ScrollWindow),LoadFileContentList); + gtk_box_pack_start(GTK_BOX(loadedvbox), ScrollWindow, TRUE, TRUE, 0); + + // Signal to automatically load the file + g_signal_connect_swapped(G_OBJECT(ButtonLoad),"clicked", G_CALLBACK(Load_File_Content), G_OBJECT(GTK_BIN(FileToLoadCombo)->child)); + g_signal_connect(G_OBJECT(LoadFileContentList),"key-press-event", G_CALLBACK(Load_Filename_List_Key_Press),NULL); + + gtk_widget_show_all(loadedvbox); + + filelistvbox = gtk_vbox_new(FALSE, 4); + + // Label of current list + Label = gtk_label_new(_("Files Name List :")); + gtk_box_pack_start(GTK_BOX(filelistvbox), Label, FALSE, FALSE, 0); + + // List of current filenames + ScrollWindow = gtk_scrolled_window_new(NULL,NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ScrollWindow),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); + gtk_widget_set_size_request(GTK_WIDGET(ScrollWindow), 250, 200); + gtk_box_pack_start(GTK_BOX(filelistvbox), ScrollWindow, TRUE, TRUE, 0); + LoadFileNameListModel = gtk_list_store_new(LOAD_FILE_NAME_COUNT, G_TYPE_STRING,G_TYPE_POINTER); + LoadFileNameList = gtk_tree_view_new_with_model(GTK_TREE_MODEL(LoadFileNameListModel)); + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("", renderer, "text", LOAD_FILE_NAME_TEXT, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(LoadFileNameList), column); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(LoadFileNameList), FALSE); + g_signal_connect(G_OBJECT(LoadFileNameList),"key-press-event", G_CALLBACK(Load_Filename_List_Key_Press),NULL); + gtk_container_add(GTK_CONTAINER(ScrollWindow),LoadFileNameList); + + // Signals to 'select' the same row into the other list (to show the corresponding filenames) + g_signal_connect_swapped(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(LoadFileContentList))),"changed", G_CALLBACK(Load_Filename_Select_Row_In_Other_List), G_OBJECT(LoadFileNameList)); + g_signal_connect_swapped(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(LoadFileNameList))),"changed", G_CALLBACK(Load_Filename_Select_Row_In_Other_List), G_OBJECT(LoadFileContentList)); + + gtk_widget_show_all(filelistvbox); + + // Load the list of files in the list widget + Load_File_List(); + + vboxpaned = gtk_hpaned_new(); + gtk_paned_pack1(GTK_PANED(vboxpaned),loadedvbox, TRUE,FALSE); + gtk_paned_pack2(GTK_PANED(vboxpaned),filelistvbox,TRUE,FALSE); + gtk_box_pack_start(GTK_BOX(VBox),vboxpaned,TRUE,TRUE,0); + + // Create popup menus + Create_Load_Filename_Popup_Menu(LoadFileContentList); + Create_Load_Filename_Popup_Menu(LoadFileNameList); + + // Entry to edit a line into the list + Entry = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(VBox),Entry,FALSE,TRUE,0); + g_signal_connect(G_OBJECT(Entry),"changed",G_CALLBACK(Load_Filename_Update_Text_Line),G_OBJECT(LoadFileContentList)); + + // Signal to load the line text in the editing entry + g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(LoadFileContentList))),"changed", G_CALLBACK(Load_Filename_Edit_Text_Line), G_OBJECT(Entry)); + + // Separator line + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0); + + LoadFileRunScanner = gtk_check_button_new_with_label(_("Run the current scanner for each file")); + gtk_box_pack_start(GTK_BOX(VBox),LoadFileRunScanner,FALSE,TRUE,0); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(LoadFileRunScanner),LOAD_FILE_RUN_SCANNER); + gtk_tooltips_set_tip(Tips,LoadFileRunScanner,_("When activating this option, after loading the " + "filenames, the current selected scanner will be ran (the scanner window must be opened)."),NULL); + + // Separator line + Separator = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0); + + ButtonBox = gtk_hbutton_box_new (); + gtk_box_pack_start(GTK_BOX(VBox),ButtonBox,FALSE,FALSE,0); + gtk_button_box_set_layout(GTK_BUTTON_BOX(ButtonBox),GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(ButtonBox), 10); + + // Button to cancel + Button = Create_Button_With_Pixmap(BUTTON_CLOSE); + gtk_container_add(GTK_CONTAINER(ButtonBox),Button); + GTK_WIDGET_SET_FLAGS(Button, GTK_CAN_DEFAULT); + gtk_widget_grab_default(Button); + g_signal_connect(G_OBJECT(Button),"clicked", G_CALLBACK(Destroy_Load_Filename_Window),NULL); + + // Button to load filenames + Button = Create_Button_With_Pixmap(BUTTON_APPLY); + gtk_container_add(GTK_CONTAINER(ButtonBox),Button); + GTK_WIDGET_SET_FLAGS(Button,GTK_CAN_DEFAULT); + g_signal_connect(G_OBJECT(Button),"clicked", G_CALLBACK(Load_Filename_Set_Filenames),NULL); + + + // To initialize 'ButtonLoad' sensivity + g_signal_emit_by_name(G_OBJECT(GTK_BIN(FileToLoadCombo)->child),"changed"); + + gtk_widget_show_all(LoadFilenameWindow); + if (LOAD_FILE_WINDOW_X > 0 && LOAD_FILE_WINDOW_Y > 0) + gdk_window_move(LoadFilenameWindow->window,LOAD_FILE_WINDOW_X,LOAD_FILE_WINDOW_Y); +} + +void Destroy_Load_Filename_Window (void) +{ + if (LoadFilenameWindow) + { + /* Save combobox history lists before exit */ + Save_File_To_Load_List(FileToLoadModel, MISC_COMBO_TEXT); + + Load_Filename_Window_Apply_Changes(); + + gtk_widget_destroy(LoadFilenameWindow); + LoadFilenameWindow = (GtkWidget *)NULL; + } +} + +/* + * For the configuration file... + */ +void Load_Filename_Window_Apply_Changes (void) +{ + if (LoadFilenameWindow) + { + gint x, y, width, height; + + if ( LoadFilenameWindow->window && gdk_window_is_visible(LoadFilenameWindow->window) + && gdk_window_get_state(LoadFilenameWindow->window)!=GDK_WINDOW_STATE_MAXIMIZED ) + { + // Position and Origin of the window + gdk_window_get_root_origin(LoadFilenameWindow->window,&x,&y); + LOAD_FILE_WINDOW_X = x; + LOAD_FILE_WINDOW_Y = y; + gdk_window_get_size(LoadFilenameWindow->window,&width,&height); + LOAD_FILE_WINDOW_WIDTH = width; + LOAD_FILE_WINDOW_HEIGHT = height; + } + + LOAD_FILE_RUN_SCANNER = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(LoadFileRunScanner)); + } +} + +gboolean Load_Filename_Window_Key_Press (GtkWidget *window, GdkEvent *event) +{ + GdkEventKey *kevent; + + if (event && event->type == GDK_KEY_PRESS) + { + kevent = (GdkEventKey *)event; + switch(kevent->keyval) + { + case GDK_Escape: + Destroy_Load_Filename_Window(); + break; + } + } + return FALSE; +} + +/* + * To enable/disable sensivity of the button 'Load' + */ +void Button_Load_Set_Sensivity (GtkWidget *button, GtkWidget *entry) +{ + struct stat statbuf; + gchar *path; + + if (!entry || !button) + return; + + path = filename_from_display(gtk_entry_get_text(GTK_ENTRY(entry))); + if ( path && stat(path,&statbuf)==0 && S_ISREG(statbuf.st_mode)) + gtk_widget_set_sensitive(GTK_WIDGET(button),TRUE); + else + gtk_widget_set_sensitive(GTK_WIDGET(button),FALSE); + + g_free(path); +} + +void Load_Filename_List_Key_Press (GtkWidget *treeview, GdkEvent *event) +{ + if (event && event->type == GDK_KEY_PRESS) + { + GdkEventKey *kevent = (GdkEventKey *)event; + + switch(kevent->keyval) + { + case GDK_Delete: + Load_Filename_List_Delete_Line(treeview); + break; + case GDK_I: + case GDK_i: + Load_Filename_List_Insert_Blank_Line(treeview); + break; + } + } +} + +/* + * Load content of the file into the LoadFileContentList list + */ +void Load_File_Content (GtkWidget *entry) +{ + FILE *file; + gchar *filename; + const gchar *filename_utf8; + gchar buffer[MAX_STRING_LEN]; + gchar *text; + gchar *valid; + GtkTreeIter iter; + + if (!entry) + return; + + // The file to read + filename_utf8 = gtk_entry_get_text(GTK_ENTRY(entry)); // Don't free me! + Add_String_To_Combo_List(FileToLoadModel, (gchar*)filename_utf8); + filename = filename_from_display(filename_utf8); + + if ( (file=fopen(filename,"r"))==0 ) + { + Log_Print(_("Can't open file '%s' (%s)"),filename_utf8,g_strerror(errno)); + g_free(filename); + return; + } + + gtk_list_store_clear(LoadFileContentListModel); + while (fgets(buffer, sizeof(buffer), file)) + { + if (buffer[strlen(buffer)-1]=='\n') + buffer[strlen(buffer)-1]='\0'; + if (buffer[strlen(buffer)-1]=='\r') + buffer[strlen(buffer)-1]='\0'; + text = &buffer[0]; + + if (g_utf8_validate(text, -1, NULL)) + { + valid = g_strdup(buffer); + } else + { + valid = convert_to_utf8(text); + } + + gtk_list_store_append(LoadFileContentListModel, &iter); + gtk_list_store_set(LoadFileContentListModel, &iter, + LOAD_FILE_CONTENT_TEXT, valid, + -1); + g_free(valid); + } + + fclose(file); + g_free(filename); +} + +/* + * Load the names of the current list of files + */ +void Load_File_List (void) +{ + GList *etfilelist; + ET_File *etfile; + gchar *filename_utf8; + gchar *pos; + GtkTreeIter iter; + + gtk_list_store_clear(LoadFileNameListModel); + etfilelist = g_list_first(ETCore->ETFileList); + while (etfilelist) + { + etfile = (ET_File *)etfilelist->data; + filename_utf8 = g_path_get_basename(((File_Name *)etfile->FileNameNew->data)->value_utf8); + // Remove the extension ('filename' must be allocated to don't affect the initial value) + if ((pos=strrchr(filename_utf8,'.'))!=NULL) + *pos = 0; + gtk_list_store_append(LoadFileNameListModel, &iter); + gtk_list_store_set(LoadFileNameListModel, &iter, + LOAD_FILE_NAME_TEXT, filename_utf8, + LOAD_FILE_NAME_POINTER, etfilelist->data, + -1); + g_free(filename_utf8); + etfilelist = etfilelist->next; + } +} +/* + * To select the corresponding row in the other list + */ +void Load_Filename_Select_Row_In_Other_List(GtkWidget* treeview_target, gpointer origselection) +{ + GtkAdjustment *ct_adj, *ce_adj; + GtkTreeSelection *selection_orig; + GtkTreeSelection *selection_target; + GtkTreeView *treeview_orig; + GtkTreeModel *treemodel_orig; + GtkTreeModel *treemodel_target; + GtkTreeIter iter_orig; + GtkTreeIter iter_target; + GtkTreePath *path_orig; + gint *indices_orig; + gchar *stringiter; + + if (!treeview_target || !origselection) + return; + + selection_orig = (GtkTreeSelection*) origselection; + selection_target = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview_target)); + treemodel_target = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview_target)); + + if (!gtk_tree_selection_get_selected(selection_orig, &treemodel_orig, &iter_orig)) + return; /* Might be called with no selection */ + + treeview_orig = gtk_tree_selection_get_tree_view(selection_orig); + path_orig = gtk_tree_model_get_path(treemodel_orig, &iter_orig); + gtk_tree_selection_unselect_all(selection_target); + + // Synchronize the two lists + ce_adj = gtk_tree_view_get_vadjustment(treeview_orig); + ct_adj = gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(treeview_target)); + + if (GTK_ADJUSTMENT(ct_adj)->upper >= GTK_ADJUSTMENT(ct_adj)->page_size + && GTK_ADJUSTMENT(ce_adj)->upper >= GTK_ADJUSTMENT(ce_adj)->page_size) + { + // Rules are displayed in the both clist + if (GTK_ADJUSTMENT(ce_adj)->value <= GTK_ADJUSTMENT(ct_adj)->upper - GTK_ADJUSTMENT(ct_adj)->page_size) + { + gtk_adjustment_set_value(GTK_ADJUSTMENT(ct_adj),GTK_ADJUSTMENT(ce_adj)->value); + } else + { + gtk_adjustment_set_value(GTK_ADJUSTMENT(ct_adj),GTK_ADJUSTMENT(ct_adj)->upper - GTK_ADJUSTMENT(ct_adj)->page_size); + indices_orig = gtk_tree_path_get_indices(path_orig); + + if (indices_orig[0] <= (gtk_tree_model_iter_n_children(treemodel_target, NULL) - 1)) + gtk_adjustment_set_value(GTK_ADJUSTMENT(ce_adj),GTK_ADJUSTMENT(ct_adj)->value); + + } + }else if (GTK_ADJUSTMENT(ct_adj)->upper < GTK_ADJUSTMENT(ct_adj)->page_size) // Target Clist rule not visible + { + indices_orig = gtk_tree_path_get_indices(path_orig); + + if (indices_orig[0] <= (gtk_tree_model_iter_n_children(treemodel_target, NULL) - 1)) + gtk_adjustment_set_value(GTK_ADJUSTMENT(ce_adj),GTK_ADJUSTMENT(ct_adj)->value); + } + + // Must block the select signal of the target to avoid looping + g_signal_handlers_block_by_func(G_OBJECT(selection_target), G_CALLBACK(Load_Filename_Select_Row_In_Other_List), G_OBJECT(treeview_orig)); + + stringiter = gtk_tree_model_get_string_from_iter(treemodel_orig, &iter_orig); + if (gtk_tree_model_get_iter_from_string(treemodel_target, &iter_target, stringiter)) + { + gtk_tree_selection_select_iter(selection_target, &iter_target); + } + + g_free(stringiter); + g_signal_handlers_unblock_by_func(G_OBJECT(selection_target), G_CALLBACK(Load_Filename_Select_Row_In_Other_List), G_OBJECT(treeview_orig)); +} + +/* + * Set the new file name of each file. + * Associate lines from LoadFileContentList with LoadFileNameList + */ +void Load_Filename_Set_Filenames (void) +{ + gint row; + ET_File *ETFile; + File_Name *FileName; + gchar *list_text; + gint rowcount; + gboolean found; + + GtkTreePath *currentPath = NULL; + GtkTreeIter iter_name; + GtkTreeIter iter_content; + + if ( !ETCore->ETFileList || !LoadFileContentList || !LoadFileNameList) + return; + + /* Save current file */ + ET_Save_File_Data_From_UI(ETCore->ETFileDisplayed); + + rowcount = MIN(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(LoadFileNameListModel), NULL), + gtk_tree_model_iter_n_children(GTK_TREE_MODEL(LoadFileContentListModel), NULL)); + + for (row=0; row < rowcount; row++) + { + if (row == 0) + currentPath = gtk_tree_path_new_first(); + else + gtk_tree_path_next(currentPath); + + found = gtk_tree_model_get_iter(GTK_TREE_MODEL(LoadFileNameListModel), &iter_name, currentPath); + if (found) + gtk_tree_model_get(GTK_TREE_MODEL(LoadFileNameListModel), &iter_name, LOAD_FILE_NAME_POINTER, &ETFile, -1); + + found = gtk_tree_model_get_iter(GTK_TREE_MODEL(LoadFileContentListModel), &iter_content, currentPath); + if (found) + gtk_tree_model_get(GTK_TREE_MODEL(LoadFileContentListModel), &iter_content, LOAD_FILE_CONTENT_TEXT, &list_text, -1); + + if (ETFile && list_text && g_utf8_strlen(list_text, -1)>0) + { + gchar *list_text_tmp; + gchar *filename_new_utf8; + + list_text_tmp = g_strdup(list_text); + ET_File_Name_Convert_Character(list_text_tmp); // Replace invalid characters + + /* Build the filename with the path */ + filename_new_utf8 = ET_File_Name_Generate(ETFile,list_text_tmp); + g_free(list_text_tmp); + + /* Set the new filename */ + // Create a new 'File_Name' item + FileName = ET_File_Name_Item_New(); + // Save changes of the 'File_Name' item + ET_Set_Filename_File_Name_Item(FileName,filename_new_utf8,NULL); + ET_Manage_Changes_Of_File_Data(ETFile,FileName,NULL); + + g_free(filename_new_utf8); + + // Then run current scanner if asked... + if (ScannerWindow && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(LoadFileRunScanner)) ) + Scan_Select_Mode_And_Run_Scanner(ETFile); + } + g_free(list_text); + } + + g_free(currentPath); + + Browser_List_Refresh_Whole_List(); + ET_Display_File_Data_To_UI(ETCore->ETFileDisplayed); +} + +/* + * Create and attach a popup menu on the two clist of the LoadFileWindow + */ +gboolean Load_Filename_Popup_Menu_Handler (GtkMenu *menu, GdkEventButton *event) +{ + if (event && (event->type==GDK_BUTTON_PRESS) && (event->button==3)) + { + gtk_menu_popup(menu,NULL,NULL,NULL,NULL,event->button,event->time); + return TRUE; + } + return FALSE; +} + +GtkWidget *Create_Load_Filename_Popup_Menu(GtkWidget *list) +{ + GtkWidget *BrowserPopupMenu; + GtkWidget *Image; + GtkWidget *MenuItem; + + + BrowserPopupMenu = gtk_menu_new(); + g_signal_connect_swapped(G_OBJECT(list),"button_press_event", G_CALLBACK(Load_Filename_Popup_Menu_Handler), G_OBJECT(BrowserPopupMenu)); + + MenuItem = gtk_image_menu_item_new_with_label(_("Insert a blank line")); + Image = gtk_image_new_from_stock(GTK_STOCK_ADD,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(MenuItem),Image); + gtk_menu_shell_append(GTK_MENU_SHELL(BrowserPopupMenu), MenuItem); + g_signal_connect_swapped(G_OBJECT(MenuItem),"activate", G_CALLBACK(Load_Filename_List_Insert_Blank_Line), G_OBJECT(list)); + + MenuItem = gtk_image_menu_item_new_with_label(_("Delete this line")); + Image = gtk_image_new_from_stock(GTK_STOCK_REMOVE,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(MenuItem),Image); + gtk_menu_shell_append(GTK_MENU_SHELL(BrowserPopupMenu),MenuItem); + g_signal_connect_swapped(G_OBJECT(MenuItem),"activate", G_CALLBACK(Load_Filename_List_Delete_Line), G_OBJECT(list)); + + MenuItem = gtk_image_menu_item_new_with_label(_("Delete all blank lines")); + Image = gtk_image_new_from_stock(GTK_STOCK_REMOVE,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(MenuItem),Image); + gtk_menu_shell_append(GTK_MENU_SHELL(BrowserPopupMenu),MenuItem); + g_signal_connect_swapped(G_OBJECT(MenuItem),"activate", G_CALLBACK(Load_Filename_List_Delete_All_Blank_Lines),G_OBJECT(list)); + + MenuItem = gtk_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(BrowserPopupMenu),MenuItem); + + MenuItem = gtk_image_menu_item_new_with_label(_("Reload")); + Image = gtk_image_new_from_stock(GTK_STOCK_REFRESH,GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(MenuItem),Image); + gtk_menu_shell_append(GTK_MENU_SHELL(BrowserPopupMenu),MenuItem); + g_signal_connect_swapped(G_OBJECT(MenuItem),"activate", G_CALLBACK(Load_Filename_List_Reload), G_OBJECT(list)); + + gtk_widget_show_all(BrowserPopupMenu); + return BrowserPopupMenu; +} + +/* + * Insert a blank line before the selected line in the treeview passed as parameter + */ +void Load_Filename_List_Insert_Blank_Line(GtkWidget *treeview) +{ + GtkTreeSelection *selection; + GtkTreeIter selectedIter; + GtkTreeIter *temp; + GtkTreeModel *model; + + if (!treeview) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + + if (gtk_tree_selection_get_selected(selection, &model, &selectedIter) != TRUE) + return; + + temp = &selectedIter; /* Not used here, but it must be non-NULL to keep GTK+ happy! */ + gtk_list_store_insert_before(GTK_LIST_STORE(model), temp, &selectedIter); +} + +/* + * Delete all blank lines in the treeview passed in as parameter + */ +void Load_Filename_List_Delete_All_Blank_Lines (GtkWidget *treeview) +{ + gchar *text = NULL; + GtkTreeIter iter; + GtkTreeModel *model; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview)); + + if (!gtk_tree_model_get_iter_first(model, &iter)) + return; + + while (TRUE) + { + gtk_tree_model_get(model, &iter, LOAD_FILE_NAME_TEXT, &text, -1); + + /* Check for blank entry */ + if (!text || g_utf8_strlen(text, -1) == 0) + { + g_free(text); + + if (!gtk_list_store_remove(GTK_LIST_STORE(model), &iter)) + break; + else + continue; + } + g_free(text); + + if (!gtk_tree_model_iter_next(model, &iter)) + break; + } +} + +/* + * Delete the selected line in the treeview passed in as parameter + */ +void Load_Filename_List_Delete_Line(GtkWidget *treeview) +{ + GtkTreeSelection *selection; + GtkTreeIter selectedIter, itercopy; + GtkTreeModel *model; + gboolean rowafter; + + if (!treeview) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); + + if (gtk_tree_selection_get_selected(selection, &model, &selectedIter) != TRUE) + { + return; + } + + // If there is a line following the one about to be removed, select it for convenience + itercopy = selectedIter; + rowafter = gtk_tree_model_iter_next(model, &itercopy); + + // Remove the line to be deleted + gtk_list_store_remove(GTK_LIST_STORE(model), &selectedIter); + + if (rowafter) + gtk_tree_selection_select_iter(selection, &itercopy); +} + +/* + * Reload a list of choice + * The list parameter refers to a GtkTreeView (LoadFileNameList or LoadFileContentList) + */ +void Load_Filename_List_Reload (GtkWidget *treeview) +{ + if (!treeview) return; + + if (GTK_TREE_VIEW(treeview) == (GtkTreeView *)LoadFileContentList) + { + Load_File_Content(GTK_BIN(FileToLoadCombo)->child); + } else if (GTK_TREE_VIEW(treeview) == (GtkTreeView *)LoadFileNameList) + { + Load_File_List(); + } +} + +/* + * Update the text of the selected line into the list, with the text entered into the entry + */ +void Load_Filename_Update_Text_Line(GtkWidget *entry, GtkWidget *list) +{ + GtkTreeIter SelectedRow; + GtkTreeSelection *selection; + GtkTreeModel *model; + gboolean hasSelectedRows = FALSE; + + if (!list || !entry) return; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list)); + hasSelectedRows = gtk_tree_selection_get_selected(selection, &model, &SelectedRow); + if (hasSelectedRows) + { + const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry)); + gtk_list_store_set(GTK_LIST_STORE(model), &SelectedRow, LOAD_FILE_CONTENT_TEXT, text, -1); + } +} + +/* + * Set the text of the selected line of the list into the entry + */ +void Load_Filename_Edit_Text_Line(GtkTreeSelection *selection, gpointer data) +{ + gchar *text; + GtkTreeIter selectedIter; + GtkEntry *entry = (GtkEntry*)data; + gulong handler; + + if (gtk_tree_selection_get_selected(selection, NULL, &selectedIter) != TRUE) + return; + + gtk_tree_model_get(GTK_TREE_MODEL(LoadFileContentListModel), &selectedIter, LOAD_FILE_NAME_TEXT, &text, -1); + + handler = g_signal_handler_find(entry, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, Load_Filename_Update_Text_Line, NULL); + g_signal_handler_block(entry, handler); + if (text) + { + gtk_entry_set_text(entry, text); + g_free(text); + } else + gtk_entry_set_text(entry, ""); + + g_signal_handler_unblock(entry, handler); +} -- cgit v1.2.3