aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/scan.c')
-rwxr-xr-xsrc/scan.c3455
1 files changed, 3455 insertions, 0 deletions
diff --git a/src/scan.c b/src/scan.c
new file mode 100755
index 0000000..2f7be4a
--- /dev/null
+++ b/src/scan.c
@@ -0,0 +1,3455 @@
+/* scan.c - 2000/06/16 */
+/*
+ * EasyTAG - Tag editor for MP3 and Ogg Vorbis files
+ * Copyright (C) 2000-2003 Jerome Couderc <easytag@gmail.com>
+ *
+ * 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 <config.h>
+
+#include <gtk/gtk.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <gdk/gdkkeysyms.h>
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include "scan.h"
+#include "easytag.h"
+#include "prefs.h"
+#include "setting.h"
+#include "id3_tag.h"
+#include "bar.h"
+#include "browser.h"
+#include "log.h"
+#include "misc.h"
+#include "et_core.h"
+#include "crc32.h"
+#include "msgbox.h"
+#include "charset.h"
+
+
+#define step(a,b) (b-a)+1
+
+
+/****************
+ * Declarations *
+ ****************/
+GtkWidget *DummyEntry = NULL; /* Used to simulate a gtkentry widget for mask code '%i' */
+GtkWidget *ScanTagMaskCombo = NULL;
+GtkWidget *RenameFileMaskCombo = NULL;
+GtkWidget *ScannerOptionCombo = NULL;
+GtkWidget *RenameFilePrefixPathButton = NULL;
+
+GtkWidget *ScanTagFrame;
+GtkWidget *RenameFileFrame;
+GtkWidget *ProcessFieldsFrame;
+GtkWidget *FillTagPreviewLabel = NULL;
+GtkWidget *RenameFilePreviewLabel = NULL;
+
+GtkListStore *RenameFileListModel;
+GtkListStore *ScanTagListModel;
+
+GtkWidget *ProcessFileNameField;
+GtkWidget *ProcessTitleField;
+GtkWidget *ProcessArtistField;
+GtkWidget *ProcessAlbumField;
+GtkWidget *ProcessGenreField;
+GtkWidget *ProcessCommentField;
+GtkWidget *ProcessComposerField;
+GtkWidget *ProcessOrigArtistField;
+GtkWidget *ProcessCopyrightField;
+GtkWidget *ProcessURLField;
+GtkWidget *ProcessEncodedByField;
+GtkWidget *ProcessFieldsConvertIntoSpace = NULL;
+GtkWidget *ProcessFieldsConvertSpace = NULL;
+GtkWidget *ProcessFieldsConvert = NULL;
+GtkWidget *ProcessFieldsConvertLabelTo;
+GtkWidget *ProcessFieldsConvertTo = NULL;
+GtkWidget *ProcessFieldsConvertFrom = NULL;
+GtkWidget *ProcessFieldsAllUppercase = NULL;
+GtkWidget *ProcessFieldsAllDowncase = NULL;
+GtkWidget *ProcessFieldsFirstLetterUppercase = NULL;
+GtkWidget *ProcessFieldsFirstLettersUppercase = NULL;
+GtkWidget *ProcessFieldsRemoveSpace = NULL;
+GtkWidget *ProcessFieldsInsertSpace = NULL;
+GtkWidget *ProcessFieldsOnlyOneSpace = NULL;
+
+GtkWidget *LegendFrame = NULL;
+GtkWidget *LegendButton = NULL;
+
+GtkWidget *MaskEditorButton = NULL;
+GtkWidget *MaskEditorFrame = NULL;
+GtkWidget *MaskEditorVBox;
+GtkWidget *MaskEditorHBox;
+GtkWidget *MaskEditorScrollWindow;
+GtkWidget *MaskEditorList;
+GtkWidget *MaskEditorEntry;
+GtkWidget *MaskEditorNewButton;
+GtkWidget *MaskEditorCopyButton;
+GtkWidget *MaskEditorAddButton;
+GtkWidget *MaskEditorRemoveButton;
+GtkWidget *MaskEditorUpButton;
+GtkWidget *MaskEditorDownButton;
+GtkWidget *MaskEditorSaveButton;
+
+/* Some predefined masks -- IMPORTANT: Null-terminate me! */
+gchar *Scan_Masks [] =
+{
+ "%a - %b"G_DIR_SEPARATOR_S"%n - %t",
+ "%a_-_%b"G_DIR_SEPARATOR_S"%n_-_%t",
+ "%a - %b (%y)"G_DIR_SEPARATOR_S"%n - %a - %t",
+ "%a_-_%b_(%y)"G_DIR_SEPARATOR_S"%n_-_%a_-_%t",
+ "%a - %b (%y) - %g"G_DIR_SEPARATOR_S"%n - %a - %t",
+ "%a_-_%b_(%y)_-_%g"G_DIR_SEPARATOR_S"%n_-_%a_-_%t",
+ "%a - %b"G_DIR_SEPARATOR_S"%n. %t",
+ "%a_-_%b"G_DIR_SEPARATOR_S"%n._%t",
+ "%a-%b"G_DIR_SEPARATOR_S"%n-%t",
+ "%b"G_DIR_SEPARATOR_S"%n. %a - %t",
+ "%b"G_DIR_SEPARATOR_S"%n._%a_-_%t",
+ "%b"G_DIR_SEPARATOR_S"%n - %a - %t",
+ "%b"G_DIR_SEPARATOR_S"%n_-_%a_-_%t",
+ "%b"G_DIR_SEPARATOR_S"%n-%a-%t",
+ "%a-%b"G_DIR_SEPARATOR_S"%n-%t",
+ "%a"G_DIR_SEPARATOR_S"%b"G_DIR_SEPARATOR_S"%n. %t",
+ "%g"G_DIR_SEPARATOR_S"%a"G_DIR_SEPARATOR_S"%b"G_DIR_SEPARATOR_S"%t",
+ "%a_-_%b-%n-%t-%y",
+ "%a - %b"G_DIR_SEPARATOR_S"%n. %t(%c)",
+ "%t",
+ "Track%n",
+ "Track%i %n",
+ NULL
+};
+
+gchar *Rename_File_Masks [] =
+{
+ "%n - %a - %t",
+ "%n_-_%a_-_%t",
+ "%n. %a - %t",
+ "%n._%a_-_%t",
+ "%n - %t",
+ "%n_-_%t",
+ "%n. %t",
+ "%n._%t",
+ "%n - %a - %b - %t",
+ "%n_-_%a_-_%b_-_%t",
+ "%a - %b - %t",
+ "%a_-_%b_-_%t",
+ "%a - %b - %n - %t",
+ "%a_-_%b_-_%n_-_%t",
+ "%a - %t",
+ "%a_-_%t",
+ "Track %n",
+ NULL
+};
+
+/**gchar *Rename_Directory_Masks [] =
+{
+ "%a - %b",
+ "%a_-_%b",
+ "%a - %b (%y) - %g",
+ "%a_-_%b_(%y)_-_%g",
+ "VA - %b (%y)",
+ "VA_-_%b_(%y)",
+ NULL
+};**/
+
+
+gchar *Scanner_Option_Menu_Items [] =
+{
+ N_("Fill Tag"),
+ N_("Rename File and Directory"),
+ N_("Process Fields")
+};
+
+typedef enum
+{
+ UNKNOWN = 0, /* Default value when initialized */
+ LEADING_SEPARATOR, /* characters before the first code */
+ TRAILING_SEPARATOR, /* characters after the last code */
+ SEPARATOR, /* item is a separator between two codes */
+ DIRECTORY_SEPARATOR, /* item is a separator between two codes with character '/' (G_DIR_SEPARATOR) */
+ FIELD, /* item contains text (not empty) of entry */
+ EMPTY_FIELD /* item when entry contains no text */
+} Mask_Item_Type;
+
+
+
+/*
+ * Used into Rename File Scanner
+ */
+typedef struct _File_Mask_Item File_Mask_Item;
+struct _File_Mask_Item
+{
+ Mask_Item_Type type;
+ gchar *string;
+};
+
+/*
+ * Used into Scan Tag Scanner
+ */
+typedef struct _Scan_Mask_Item Scan_Mask_Item;
+struct _Scan_Mask_Item
+{
+ gchar code; // The code of the mask without % (ex: %a => a)
+ gchar *string; // The string found by the scanner for the code defined the line above
+};
+
+
+
+/**************
+ * Prototypes *
+ **************/
+void ScannerWindow_Quit (void);
+gboolean ScannerWindow_Key_Press (GtkWidget *window, GdkEvent *event);
+void Scan_Toggle_Legend_Button (void);
+void Scan_Toggle_Mask_Editor_Button (void);
+gchar *Scan_Replace_String (gchar *string, gchar *last, gchar *new);
+void Scan_Option_Button (void);
+gboolean Scan_Check_Scan_Tag_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source);
+gboolean Scan_Check_Rename_File_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source);
+gboolean Scan_Check_Editor_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source);
+
+gchar *Scan_Generate_New_Filename_From_Mask (ET_File *ETFile, gchar *mask, gboolean no_dir_check_or_conversion);
+GList *Scan_Generate_New_Tag_From_Mask (ET_File *ETFile, gchar *mask);
+void Scan_Rename_File_Generate_Preview (void);
+void Scan_Rename_File_Prefix_Path (void);
+void Scan_Fill_Tag_Generate_Preview (void);
+void Scan_Free_File_Rename_List (GList *list);
+void Scan_Free_File_Fill_Tag_List (GList *list);
+void Scan_Rename_Directory_Generate_Preview (void);
+
+gchar **Scan_Return_File_Tag_Field_From_Mask_Code (File_Tag *FileTag, gchar code);
+void Scan_Process_Fields_Functions (gchar *string);
+
+void Process_Fields_Check_Button_Toggled (GtkObject *object, GList *list);
+void Process_Fields_Convert_Check_Button_Toggled (GtkObject *object);
+void Select_Fields_Invert_Selection (void);
+void Select_Fields_Select_Unselect_All (void);
+void Select_Fields_Set_Sensitive (void);
+
+void Mask_Editor_List_Row_Selected (GtkTreeSelection* selection, gpointer data);
+void Mask_Editor_List_New (void);
+void Mask_Editor_List_Duplicate (void);
+void Mask_Editor_List_Add (void);
+void Mask_Editor_List_Remove (void);
+void Mask_Editor_List_Move_Up (void);
+void Mask_Editor_List_Move_Down (void);
+void Mask_Editor_List_Save_Button (void);
+void Mask_Editor_Entry_Changed (void);
+gboolean Mask_Editor_List_Key_Press (GtkWidget *widget, GdkEvent *event);
+
+void Mask_Editor_Clean_Up_Masks_List (void);
+
+void Scanner_Option_Menu_Activate_Item (GtkWidget *widget, gpointer data);
+
+void Populate_Scan_Tag_Masks();
+void Populate_Rename_File_Masks();
+
+
+/*************
+ * *
+ * Functions *
+ * *
+ *************/
+
+void Init_ScannerWindow (void)
+{
+ ScannerWindow = (GtkWidget *)NULL;
+ ScannerOptionCombo= (GtkWidget *)NULL;
+ SWScanButton = (GtkWidget *)NULL;
+}
+
+
+/*
+ * Uses the filename and path to fill tag informations
+ * Note: mask and source are read from the right to the left
+ */
+void Scan_Tag_With_Mask (ET_File *ETFile)
+{
+ GList *fill_tag_list = NULL;
+ gchar **dest = NULL;
+ gchar *mask; // The 'mask' in the entry
+ gchar *filename_utf8;
+ File_Tag *FileTag;
+
+ if (!ScannerWindow || !ScanTagMaskCombo || !ETFile) return;
+ mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)));
+ if (!mask) return;
+
+ // Create a new File_Tag item
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+
+ // Process this mask with file
+ fill_tag_list = Scan_Generate_New_Tag_From_Mask(ETFile,mask);
+ while (fill_tag_list)
+ {
+ Scan_Mask_Item *mask_item = fill_tag_list->data;
+
+ // Get the target entry for this code
+ dest = Scan_Return_File_Tag_Field_From_Mask_Code(FileTag,mask_item->code);
+
+ // We display the text affected to the code
+ if ( dest && ( OVERWRITE_TAG_FIELD || *dest==NULL || strlen(*dest)==0 ) )
+ ET_Set_Field_File_Tag_Item(dest,mask_item->string);
+
+ if (!fill_tag_list->next) break;
+ fill_tag_list = fill_tag_list->next;
+ }
+ Scan_Free_File_Fill_Tag_List(fill_tag_list);
+
+ // Set the default text to comment
+ if (SET_DEFAULT_COMMENT && (OVERWRITE_TAG_FIELD || FileTag->comment==NULL || strlen(FileTag->comment)==0 ) )
+ ET_Set_Field_File_Tag_Item((void *)&FileTag->comment,DEFAULT_COMMENT);
+
+ // Set CRC-32 value as default comment (for files with ID3 tag only ;-)
+ if (SET_CRC32_COMMENT && (OVERWRITE_TAG_FIELD || FileTag->comment==NULL || strlen(FileTag->comment)==0 ) )
+ {
+ gulong crc32_value = 0;
+ gchar *buffer;
+ ET_File_Description *ETFileDescription;
+
+ ETFileDescription = ETFile->ETFileDescription;
+ switch (ETFileDescription->TagType)
+ {
+ case ID3_TAG:
+ crc32_file_with_ID3_tag( ((File_Name *)((GList *)ETFile->FileNameNew)->data)->value, &crc32_value);
+
+ if (crc32_value > 0)
+ {
+ buffer = g_strdup_printf("%.8lx",crc32_value);
+ ET_Set_Field_File_Tag_Item((void *)&FileTag->comment,buffer);
+ g_free(buffer);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ // Save changes of the 'File_Tag' item
+ ET_Manage_Changes_Of_File_Data(ETFile,NULL,FileTag);
+
+ g_free(mask);
+ Statusbar_Message(_("Tag successfully scanned..."),TRUE);
+ filename_utf8 = g_path_get_basename( ((File_Name *)ETFile->FileNameNew->data)->value_utf8 );
+ Log_Print(_("Tag successfully scanned...(%s)"),filename_utf8);
+ g_free(filename_utf8);
+}
+
+GList *Scan_Generate_New_Tag_From_Mask (ET_File *ETFile, gchar *mask)
+{
+ GList *fill_tag_list = NULL;
+ gchar *filename_utf8;
+ gchar *tmp;
+ gchar *buf;
+ gchar *separator;
+ gchar *string;
+ gint len, i, loop=0;
+ gchar **mask_splitted;
+ gchar **file_splitted;
+ guint mask_splitted_number;
+ guint file_splitted_number;
+ guint mask_splitted_index;
+ guint file_splitted_index;
+ Scan_Mask_Item *mask_item;
+
+ if (!ETFile || !mask) return NULL;
+
+ filename_utf8 = g_strdup(((File_Name *)((GList *)ETFile->FileNameNew)->data)->value_utf8);
+ if (!filename_utf8) return NULL;
+
+ // Remove extension of file (if found)
+ tmp = strrchr(filename_utf8,'.');
+ for (i=0; i<=(gint)ET_FILE_DESCRIPTION_SIZE; i++)
+ {
+ if ( strcasecmp(tmp,ETFileDescription[i].Extension)==0 )
+ {
+ *tmp = 0; //strrchr(source,'.') = 0;
+ break;
+ }
+ }
+
+ if (i==ET_FILE_DESCRIPTION_SIZE)
+ {
+ gchar *tmp1 = g_path_get_basename(filename_utf8);
+ Log_Print(_("Tag scanner: strange..., the extension '%s' was not found into filename '%s'!"),tmp,tmp1);
+ g_free(tmp1);
+ }
+
+ // Replace characters into mask and filename before parsing
+ if (FTS_CONVERT_UNDERSCORE_AND_P20_INTO_SPACE)
+ {
+ Scan_Convert_Underscore_Into_Space(mask);
+ Scan_Convert_Underscore_Into_Space(filename_utf8);
+ Scan_Convert_P20_Into_Space(mask);
+ Scan_Convert_P20_Into_Space(filename_utf8);
+ }
+ if (FTS_CONVERT_SPACE_INTO_UNDERSCORE)
+ {
+ Scan_Convert_Space_Into_Undescore(mask);
+ Scan_Convert_Space_Into_Undescore(filename_utf8);
+ }
+
+
+ // Split the Scanner mask
+ mask_splitted = g_strsplit(mask,G_DIR_SEPARATOR_S,0);
+ // Get number of arguments into 'mask_splitted'
+ for (mask_splitted_number=0;mask_splitted[mask_splitted_number];mask_splitted_number++);
+
+ // Split the File Path
+ file_splitted = g_strsplit(filename_utf8,G_DIR_SEPARATOR_S,0);
+ // Get number of arguments into 'file_splitted'
+ for (file_splitted_number=0;file_splitted[file_splitted_number];file_splitted_number++);
+
+ // Set the starting position for each tab
+ if (mask_splitted_number <= file_splitted_number)
+ {
+ mask_splitted_index = 0;
+ file_splitted_index = file_splitted_number - mask_splitted_number;
+ }else
+ {
+ mask_splitted_index = mask_splitted_number - file_splitted_number;
+ file_splitted_index = 0;
+ }
+
+ loop = 0;
+ while ( mask_splitted[mask_splitted_index]!= NULL && file_splitted[file_splitted_index]!=NULL )
+ {
+ gchar *mask_seq = mask_splitted[mask_splitted_index];
+ gchar *file_seq = file_splitted[file_splitted_index];
+ gchar *file_seq_utf8 = filename_to_display(file_seq);
+
+ //g_print(">%d> seq '%s' '%s'\n",loop,mask_seq,file_seq);
+ while ( mask_seq && strlen(mask_seq)>0 )
+ {
+
+ /*
+ * Determine (first) code and destination
+ */
+ if ( (tmp=strchr(mask_seq,'%')) == NULL || strlen(tmp) < 2 )
+ {
+ break;
+ }
+
+ /*
+ * Allocate a new iten for the fill_tag_list
+ */
+ mask_item = g_malloc0(sizeof(Scan_Mask_Item));
+
+ // Get the code (used to determine the corresponding target entry)
+ mask_item->code = tmp[1];
+
+ /*
+ * Delete text before the code
+ */
+ if ( (len = strlen(mask_seq) - strlen(tmp)) > 0 )
+ {
+ // Get this text in 'mask_seq'
+ buf = g_strndup(mask_seq,len);
+ // We remove it in 'mask_seq'
+ mask_seq = mask_seq + len;
+ // Find the same text at the begining of 'file_seq' ?
+ if ( (strstr(file_seq,buf)) == file_seq )
+ {
+ file_seq = file_seq + len; // We remove it
+ }else
+ {
+ Log_Print(_("Scan Error: can't find separator '%s' within '%s'"),buf,file_seq_utf8);
+ }
+ g_free(buf);
+ }
+
+ // Remove the current code into 'mask_seq'
+ mask_seq = mask_seq + 2;
+
+ /*
+ * Determine separator between two code or trailing text (after code)
+ */
+ if ( mask_seq && strlen(mask_seq)>0 )
+ {
+ if ( (tmp=strchr(mask_seq,'%')) == NULL || strlen(tmp) < 2 )
+ {
+ // No more code found
+ len = strlen(mask_seq);
+ }else
+ {
+ len = strlen(mask_seq) - strlen(tmp);
+ }
+ separator = g_strndup(mask_seq,len);
+
+ // Remove the current separator in 'mask_seq'
+ mask_seq = mask_seq + len;
+
+ // Try to find the separator in 'file_seq'
+ if ( (tmp=strstr(file_seq,separator)) == NULL )
+ {
+ Log_Print(_("Scan Error: can't find separator '%s' within '%s'"),separator,file_seq_utf8);
+ separator[0] = 0; // Needed to avoid error when calculting 'len' below
+ }
+
+ // Get the string affected to the code (or the corresponding entry field)
+ len = strlen(file_seq) - (tmp!=NULL?strlen(tmp):0);
+ string = g_strndup(file_seq,len);
+
+ // Remove the current separator in 'file_seq'
+ file_seq = file_seq + strlen(string) + strlen(separator);
+ g_free(separator);
+
+ // We get the text affected to the code
+ mask_item->string = string;
+ }else
+ {
+ // We display the remaining text, affected to the code (no more data in 'mask_seq')
+ mask_item->string = g_strdup(file_seq);
+ }
+
+ // Add the filled mask_iten to the list
+ fill_tag_list = g_list_append(fill_tag_list,mask_item);
+ }
+
+ g_free(file_seq_utf8);
+
+ // Next sequences
+ mask_splitted_index++;
+ file_splitted_index++;
+ loop++;
+ }
+
+ g_free(filename_utf8);
+ g_strfreev(mask_splitted);
+ g_strfreev(file_splitted);
+
+ // The 'fill_tag_list' must be freed after use
+ return fill_tag_list;
+}
+
+void Scan_Fill_Tag_Generate_Preview (void)
+{
+ gchar *mask = NULL;
+ gchar *preview_text = NULL;
+ GList *fill_tag_list = NULL;
+
+ if (!ETCore->ETFileDisplayedList
+ || !ScannerWindow || !RenameFileMaskCombo || !FillTagPreviewLabel
+ || gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) != SCANNER_FILL_TAG)
+ return;
+
+ mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)));
+ if (!mask)
+ return;
+
+ preview_text = g_strdup("");
+ fill_tag_list = Scan_Generate_New_Tag_From_Mask(ETCore->ETFileDisplayed,mask);
+ while (fill_tag_list)
+ {
+ Scan_Mask_Item *mask_item = fill_tag_list->data;
+ gchar *tmp_code = g_strdup_printf("%c",mask_item->code);
+ gchar *tmp_string = g_markup_printf_escaped("%s",mask_item->string); // To avoid problem with strings containing characters like '&'
+ gchar *tmp_preview_text = preview_text;
+
+ preview_text = g_strconcat(tmp_preview_text,"<b>","%",tmp_code," = ",
+ "</b>","<i>",tmp_string,"</i>",NULL);
+ g_free(tmp_code);
+ g_free(tmp_string);
+ g_free(tmp_preview_text);
+
+ if (!fill_tag_list->next) break;
+ fill_tag_list = fill_tag_list->next;
+
+ tmp_preview_text = preview_text;
+ preview_text = g_strconcat(tmp_preview_text," || ",NULL);
+ g_free(tmp_preview_text);
+ }
+ Scan_Free_File_Fill_Tag_List(fill_tag_list);
+
+ if (GTK_IS_LABEL(FillTagPreviewLabel))
+ {
+ if (preview_text)
+ {
+ //gtk_label_set_text(GTK_LABEL(FillTagPreviewLabel),preview_text);
+ gtk_label_set_markup(GTK_LABEL(FillTagPreviewLabel),preview_text);
+ } else
+ {
+ gtk_label_set_text(GTK_LABEL(FillTagPreviewLabel),"");
+ }
+
+ // Force the window to be redrawed
+ gtk_widget_queue_resize(ScannerWindow);
+ }
+
+ g_free(mask);
+ g_free(preview_text);
+}
+
+void Scan_Free_File_Fill_Tag_List (GList *list)
+{
+ // Free the list
+ list = g_list_first(list);
+ while (list)
+ {
+ if (list->data)
+ {
+ g_free(((Scan_Mask_Item *)list->data)->string);
+ g_free( (Scan_Mask_Item *)list->data );
+ }
+ if (!list->next) break;
+ list = list->next;
+ }
+ g_list_free(list);
+ list = (GList *)NULL;
+}
+
+
+
+/**************************
+ * Scanner To Rename File *
+ **************************/
+/*
+ * Uses tag informations (displayed into tag entries) to rename file
+ * Note: mask and source are read from the right to the left.
+ * Note1: a mask code may be used severals times...
+ */
+void Scan_Rename_File_With_Mask (ET_File *ETFile)
+{
+ gchar *filename_generated_utf8 = NULL;
+ gchar *filename_generated = NULL;
+ gchar *filename_new_utf8 = NULL;
+ gchar *mask = NULL;
+ File_Name *FileName;
+
+ if (!ScannerWindow || !RenameFileMaskCombo || !ETFile) return;
+
+ mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)));
+ if (!mask) return;
+
+ // Note : if the first character is '/', we have a path with the filename,
+ // else we have only the filename. The both are in UTF-8.
+ filename_generated_utf8 = Scan_Generate_New_Filename_From_Mask(ETFile,mask,FALSE);
+ g_free(mask);
+
+ if (!filename_generated_utf8)
+ return;
+ if (g_utf8_strlen(filename_generated_utf8,-1)<1)
+ {
+ g_free(filename_generated_utf8);
+ return;
+ }
+
+ // Convert filename to file-system encoding
+ filename_generated = filename_from_display(filename_generated_utf8);
+ if (!filename_generated)
+ {
+ GtkWidget *msgbox;
+ gchar *msg = g_strdup_printf(_("Could not convert filename '%s' into system filename encoding."), filename_generated_utf8);
+ msgbox = msg_box_new(_("Filename translation"),msg,GTK_STOCK_DIALOG_ERROR,BUTTON_OK,0);
+ msg_box_run(MSG_BOX(msgbox));
+ gtk_widget_destroy(msgbox);
+ g_free(msg);
+ g_free(filename_generated_utf8);
+ return;
+ }
+
+ /* Build the filename with the full path or relative to old path */
+ filename_new_utf8 = ET_File_Name_Generate(ETFile,filename_generated_utf8);
+ g_free(filename_generated);
+ g_free(filename_generated_utf8);
+
+ /* 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);
+
+ Statusbar_Message(_("New file name successfully scanned..."),TRUE);
+
+ filename_new_utf8 = g_path_get_basename(((File_Name *)ETFile->FileNameNew->data)->value_utf8);
+ Log_Print(_("New file name successfully scanned...(%s)"),filename_new_utf8);
+ g_free(filename_new_utf8);
+
+ return;
+}
+
+/*
+ * Build the new filename using tag + mask
+ * Used also to rename the directory (from the browser)
+ * @param ETFile : the etfile to process
+ * @param mask : the pattern to parse
+ * @param no_dir_check_or_conversion : if FALSE, disable checking of a directory
+ * in the mask, and don't convert "illegal" characters. This is used in the
+ * function "Write_Playlist" for the content of the playlist.
+ * Returns filename in UTF-8
+ */
+gchar *Scan_Generate_New_Filename_From_Mask (ET_File *ETFile, gchar *mask, gboolean no_dir_check_or_conversion)
+{
+ gchar *tmp;
+ gchar **source = NULL;
+ gchar *path_utf8_cur = NULL;
+ gchar *filename_new_utf8 = NULL;
+ gchar *filename_tmp = NULL;
+ GList *rename_file_list = NULL;
+ File_Mask_Item *mask_item;
+ File_Mask_Item *mask_item_prev;
+ File_Mask_Item *mask_item_next;
+ gint counter = 0;
+
+
+ if (!ETFile || !mask) return NULL;
+
+ /*
+ * Check for a directory in the mask
+ */
+ if (!no_dir_check_or_conversion)
+ {
+ if (g_path_is_absolute(mask))
+ {
+ // Absolute directory
+ }else if (strrchr(mask,G_DIR_SEPARATOR)!=NULL) // This is '/' on UNIX machines and '\' under Windows
+ {
+ // Relative path => set beginning of the path
+ path_utf8_cur = g_path_get_dirname( ((File_Name *)ETFile->FileNameCur->data)->value_utf8 );
+ }
+ }
+
+
+ /*
+ * Parse the codes to generate a list (1rst item = 1rst code)
+ */
+ while ( mask!=NULL && (tmp=strrchr(mask,'%'))!=NULL && strlen(tmp)>1 )
+ {
+ // Mask contains some characters after the code ('%b__')
+ if (strlen(tmp)>2)
+ {
+ mask_item = g_malloc0(sizeof(File_Mask_Item));
+ if (counter)
+ {
+ if (strchr(tmp+2,G_DIR_SEPARATOR))
+ mask_item->type = DIRECTORY_SEPARATOR;
+ else
+ mask_item->type = SEPARATOR;
+ } else
+ {
+ mask_item->type = TRAILING_SEPARATOR;
+ }
+ mask_item->string = g_strdup(tmp+2);
+ rename_file_list = g_list_prepend(rename_file_list,mask_item);
+ }
+
+ // Now, parses the code to get the corresponding string (from tag)
+ source = Scan_Return_File_Tag_Field_From_Mask_Code((File_Tag *)ETFile->FileTag->data,tmp[1]);
+ mask_item = g_malloc0(sizeof(File_Mask_Item));
+ if (source && *source && strlen(*source)>0)
+ {
+ mask_item->type = FIELD;
+ mask_item->string = g_strdup(*source);
+
+ // Replace invalid characters for this field
+ // Note : shouldn't be done always as for the content of a playlist, we don't need to replace...
+ if (!no_dir_check_or_conversion)
+ {
+ ET_File_Name_Convert_Character(mask_item->string);
+ }
+
+ // Replace characters (rules) (!! don't convert in directory path_utf8_cur)
+ if (RFS_CONVERT_UNDERSCORE_AND_P20_INTO_SPACE)
+ {
+ Scan_Convert_Underscore_Into_Space(mask_item->string);
+ Scan_Convert_P20_Into_Space(mask_item->string);
+ }
+ if (RFS_CONVERT_SPACE_INTO_UNDERSCORE)
+ Scan_Convert_Space_Into_Undescore(mask_item->string);
+ }else
+ {
+ mask_item->type = EMPTY_FIELD;
+ mask_item->string = NULL;
+ }
+ rename_file_list = g_list_prepend(rename_file_list,mask_item);
+ *tmp = '\0'; // Cut parsed data of mask
+ counter++; // To indicate that we made at least one loop to identifiate 'separator' or 'trailing_separator'
+ }
+
+ // It may have some characters before the last remaining code ('__%a')
+ if (mask!=NULL && strlen(mask)>0)
+ {
+ mask_item = g_malloc0(sizeof(File_Mask_Item));
+ mask_item->type = LEADING_SEPARATOR;
+ mask_item->string = g_strdup(mask);
+ rename_file_list = g_list_prepend(rename_file_list,mask_item);
+ }
+
+ if (!rename_file_list) return NULL;
+
+ /*
+ * For Debugging : display the "rename_file_list" list
+ */
+ /***{
+ GList *list = g_list_first(rename_file_list);
+ gint i = 0;
+ g_print("## rename_file_list - start\n");
+ while (list)
+ {
+ File_Mask_Item *mask_item = (File_Mask_Item *)list->data;
+ Mask_Item_Type type = mask_item->type;
+ gchar *string = mask_item->string;
+
+ //g_print("item %d : \n",i++);
+ //g_print(" - type : '%s'\n",type==UNKNOWN?"UNKNOWN":type==LEADING_SEPARATOR?"LEADING_SEPARATOR":type==TRAILING_SEPARATOR?"TRAILING_SEPARATOR":type==SEPARATOR?"SEPARATOR":type==DIRECTORY_SEPARATOR?"DIRECTORY_SEPARATOR":type==FIELD?"FIELD":type==EMPTY_FIELD?"EMPTY_FIELD":"???");
+ //g_print(" - string : '%s'\n",string);
+ g_print("%d -> %s (%s) | ",i++,type==UNKNOWN?"UNKNOWN":type==LEADING_SEPARATOR?"LEADING_SEPARATOR":type==TRAILING_SEPARATOR?"TRAILING_SEPARATOR":type==SEPARATOR?"SEPARATOR":type==DIRECTORY_SEPARATOR?"DIRECTORY_SEPARATOR":type==FIELD?"FIELD":type==EMPTY_FIELD?"EMPTY_FIELD":"???",string);
+
+ list = list->next;
+ }
+ g_print("\n## rename_file_list - end\n\n");
+ }***/
+
+ /*
+ * Build the new filename with items placed into the list
+ * (read the list from the end to the beginning)
+ */
+ rename_file_list = g_list_last(rename_file_list);
+ filename_new_utf8 = g_strdup("");
+
+ while (rename_file_list)
+ {
+ File_Mask_Item *mask_item = rename_file_list->data;
+
+ if ( mask_item->type==TRAILING_SEPARATOR ) // Trailing characters of mask
+ {
+ // Doesn't write it if previous field is empty
+ if (rename_file_list->prev && ((File_Mask_Item *)rename_file_list->prev->data)->type!=EMPTY_FIELD)
+ {
+ filename_tmp = filename_new_utf8;
+ filename_new_utf8 = g_strconcat(mask_item->string,filename_new_utf8,NULL);
+ g_free(filename_tmp);
+ }
+ }else
+ if ( mask_item->type==EMPTY_FIELD )
+ // We don't concatenate the field value (empty) and the previous
+ // separator (except leading separator) to the filename.
+ // If the empty field is the 'first', we don't concatenate it, and the
+ // next separator too.
+ {
+ if (rename_file_list->prev)
+ {
+ // The empty field isn't the first.
+ // If previous string is a separator, we don't use it, except if the next
+ // string is a FIELD (not empty)
+ mask_item_prev = rename_file_list->prev->data;
+ if ( mask_item_prev->type==SEPARATOR )
+ {
+ if ( !(rename_file_list->next && (mask_item_next=rename_file_list->next->data)
+ && mask_item_next->type==FIELD) )
+ {
+ rename_file_list = rename_file_list->prev;
+ }
+ }
+ }else
+ if (rename_file_list->next && (mask_item_next=rename_file_list->next->data)
+ && mask_item_next->type==SEPARATOR)
+ // We are at the 'beginning' of the mask (so empty field is the first)
+ // and next field is a separator. As the separator may have been already added, we remove it
+ {
+ if ( filename_new_utf8 && mask_item_next->string && (strncmp(filename_new_utf8,mask_item_next->string,strlen(mask_item_next->string))==0) ) // To avoid crash if filename_new_utf8 is 'empty'
+ {
+ filename_tmp = filename_new_utf8;
+ filename_new_utf8 = g_strdup(filename_new_utf8+strlen(mask_item_next->string));
+ g_free(filename_tmp);
+ }
+ }
+
+ }else // SEPARATOR, FIELD, LEADING_SEPARATOR, DIRECTORY_SEPARATOR
+ {
+ filename_tmp = filename_new_utf8;
+ filename_new_utf8 = g_strconcat(mask_item->string,filename_new_utf8,NULL);
+ g_free(filename_tmp);
+ }
+
+ if (!rename_file_list->prev) break;
+ rename_file_list = rename_file_list->prev;
+ }
+
+ // Free the list
+ Scan_Free_File_Rename_List(rename_file_list);
+
+
+ // Add current path if relative path entered
+ if (path_utf8_cur)
+ {
+ filename_tmp = filename_new_utf8; // in UTF-8!
+ filename_new_utf8 = g_strconcat(path_utf8_cur,G_DIR_SEPARATOR_S,filename_new_utf8,NULL);
+ g_free(filename_tmp);
+ g_free(path_utf8_cur);
+ }
+
+ return filename_new_utf8; // in UTF-8!
+}
+
+void Scan_Rename_File_Generate_Preview (void)
+{
+ gchar *preview_text = NULL;
+ gchar *mask = NULL;
+
+ if (!ETCore->ETFileDisplayed
+ || !ScannerWindow || !RenameFileMaskCombo || !RenameFilePreviewLabel)
+ return;
+
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) != SCANNER_RENAME_FILE)
+ return;
+
+ mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)));
+ if (!mask)
+ return;
+
+ preview_text = Scan_Generate_New_Filename_From_Mask(ETCore->ETFileDisplayed,mask,FALSE);
+
+ if (GTK_IS_LABEL(RenameFilePreviewLabel))
+ {
+ if (preview_text)
+ {
+ //gtk_label_set_text(GTK_LABEL(RenameFilePreviewLabel),preview_text);
+ gchar *tmp_string = g_markup_printf_escaped("%s",preview_text); // To avoid problem with strings containing characters like '&'
+ gchar *str = g_strdup_printf("<i>%s</i>",tmp_string);
+ gtk_label_set_markup(GTK_LABEL(RenameFilePreviewLabel),str);
+ g_free(tmp_string);
+ g_free(str);
+ } else
+ {
+ gtk_label_set_text(GTK_LABEL(RenameFilePreviewLabel),"");
+ }
+
+ // Force the window to be redrawed
+ gtk_widget_queue_resize(ScannerWindow);
+ }
+
+ g_free(mask);
+ g_free(preview_text);
+}
+
+
+void Scan_Free_File_Rename_List (GList *list)
+{
+ // Free the list
+ list = g_list_last(list);
+ while (list)
+ {
+ if (list->data)
+ {
+ g_free(((File_Mask_Item *)list->data)->string);
+ g_free( (File_Mask_Item *)list->data );
+ }
+ if (!list->prev) break;
+ list = list->prev;
+ }
+ g_list_free(list);
+ list = (GList *)NULL;
+}
+
+/*
+ * Adds the current path of the file to the mask on the "Rename File Scanner" entry
+ */
+void Scan_Rename_File_Prefix_Path (void)
+{
+ gchar *path_tmp;
+ gchar *combo_text = NULL;
+ gchar *combo_tmp;
+ ET_File *ETFile = ETCore->ETFileDisplayed;
+ gchar *filename_utf8_cur = ((File_Name *)ETFile->FileNameCur->data)->value_utf8;
+ gchar *path_utf8_cur;
+
+
+ // The path to prefix
+ path_utf8_cur = g_path_get_dirname(filename_utf8_cur);
+
+ // The current text in the combobox
+ combo_text = (gchar *)gtk_entry_get_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child));
+ if (!g_utf8_validate(combo_text, -1, NULL))
+ {
+ combo_tmp = convert_to_utf8(combo_text);
+ }else
+ {
+ combo_tmp = g_strdup(combo_text);
+ }
+
+ // If the path already exists we don't add it again
+ // Use g_utf8_collate_key instead of strncmp
+ if (combo_tmp && path_utf8_cur && strncmp(combo_tmp,path_utf8_cur,strlen(path_utf8_cur))!=0)
+ {
+ if (g_path_is_absolute(combo_tmp))
+ {
+ path_tmp = g_strdup(path_utf8_cur);
+ } else
+ {
+ path_tmp = g_strconcat(path_utf8_cur,G_DIR_SEPARATOR_S,NULL);
+ }
+ gtk_entry_prepend_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child),path_tmp);
+ g_free(path_tmp);
+ }
+
+ g_free(path_utf8_cur);
+}
+
+
+/*******************************
+ * Scanner To Rename Directory *
+ *******************************/
+void Scan_Rename_Directory_Generate_Preview (void)
+{
+ gchar *preview_text = NULL;
+ gchar *mask = NULL;
+
+ if (!ETCore->ETFileDisplayed
+ || !RenameDirectoryWindow || !RenameDirectoryMaskCombo || !RenameDirectoryPreviewLabel)
+ return;
+
+ mask = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(RenameDirectoryMaskCombo)->child)));
+ if (!mask)
+ return;
+
+ preview_text = Scan_Generate_New_Filename_From_Mask(ETCore->ETFileDisplayed,mask,FALSE);
+
+ if (GTK_IS_LABEL(RenameDirectoryPreviewLabel))
+ {
+ if (preview_text)
+ {
+ //gtk_label_set_text(GTK_LABEL(RenameFilePreviewLabel),preview_text);
+ gchar *tmp_string = g_markup_printf_escaped("%s",preview_text); // To avoid problem with strings containing characters like '&'
+ gchar *str = g_strdup_printf("<i>%s</i>",tmp_string);
+ gtk_label_set_markup(GTK_LABEL(RenameDirectoryPreviewLabel),str);
+ g_free(tmp_string);
+ g_free(str);
+ } else
+ {
+ gtk_label_set_text(GTK_LABEL(RenameDirectoryPreviewLabel),"");
+ }
+
+ // Force the window to be redrawed else the preview label may be not placed correctly
+ gtk_widget_queue_resize(RenameDirectoryWindow);
+ }
+
+ g_free(mask);
+ g_free(preview_text);
+}
+
+gchar *Scan_Generate_New_Directory_Name_From_Mask (ET_File *ETFile, gchar *mask, gboolean no_dir_check_or_conversion)
+{
+ return Scan_Generate_New_Filename_From_Mask(ETFile,mask,no_dir_check_or_conversion);
+}
+
+
+
+/*****************************
+ * Scanner To Process Fields *
+ *****************************/
+/* See also functions : Convert_P20_And_Undescore_Into_Spaces, ... in easytag.c */
+void Scan_Process_Fields (ET_File *ETFile)
+{
+ File_Name *FileName = NULL;
+ File_Tag *FileTag = NULL;
+ File_Name *st_filename;
+ File_Tag *st_filetag;
+ gchar *filename_utf8;
+ //GString *string2process;
+ guint string_length;
+ gchar *string;
+ gchar *temp;
+
+
+ if (!ScannerWindow || !ETFile) return;
+
+ st_filename = (File_Name *)ETFile->FileNameNew->data;
+ st_filetag = (File_Tag *)ETFile->FileTag->data;
+ //string2process = g_string_sized_new(512);
+
+ /* Process the filename */
+ if (st_filename != NULL)
+ {
+ if (st_filename->value_utf8 && GTK_TOGGLE_BUTTON(ProcessFileNameField)->active) // File name field
+ {
+ gchar *string_utf8;
+ gchar *pos;
+
+ filename_utf8 = st_filename->value_utf8;
+
+ if (!FileName)
+ FileName = ET_File_Name_Item_New();
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ temp = g_path_get_basename(filename_utf8);
+ string_length = 2 * g_utf8_strlen(temp,-1);
+ string = g_malloc(string_length+1);
+ strncpy(string,temp,string_length);
+ g_free(temp);
+ string[string_length]='\0';
+ // Remove the extension to set it to lower case (to avoid problem with undo)
+ if ((pos=strrchr(string,'.'))!=NULL) *pos = 0;
+
+ Scan_Process_Fields_Functions(string);
+
+ string_utf8 = ET_File_Name_Generate(ETFile,string);
+ ET_Set_Filename_File_Name_Item(FileName,string_utf8,NULL);
+ g_free(string_utf8);
+ g_free(string);
+ }
+ }
+
+ /* Process data of the tag */
+ if (st_filetag != NULL)
+ {
+ // Title field
+ if (st_filetag->title && GTK_TOGGLE_BUTTON(ProcessTitleField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->title);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->title,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->title,string);
+
+ g_free(string);
+ }
+
+ // Artist field
+ if (st_filetag->artist && GTK_TOGGLE_BUTTON(ProcessArtistField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->artist);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->artist,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->artist,string);
+
+ g_free(string);
+ }
+
+ // Album field
+ if (st_filetag->album && GTK_TOGGLE_BUTTON(ProcessAlbumField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->album);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->album,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->album,string);
+
+ g_free(string);
+ }
+
+ // Genre field
+ if (st_filetag->genre && GTK_TOGGLE_BUTTON(ProcessGenreField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->genre);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->genre,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->genre,string);
+
+ g_free(string);
+ }
+
+ // Comment field
+ if (st_filetag->comment && GTK_TOGGLE_BUTTON(ProcessCommentField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->comment);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->comment,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->comment,string);
+
+ g_free(string);
+ }
+
+ // Composer field
+ if (st_filetag->composer && GTK_TOGGLE_BUTTON(ProcessComposerField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->composer);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->composer,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->composer,string);
+
+ g_free(string);
+ }
+
+ // Original artist field
+ if (st_filetag->orig_artist && GTK_TOGGLE_BUTTON(ProcessOrigArtistField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->orig_artist);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->orig_artist,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->orig_artist,string);
+
+ g_free(string);
+ }
+
+ // Copyright field
+ if (st_filetag->copyright && GTK_TOGGLE_BUTTON(ProcessCopyrightField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->copyright);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->copyright,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->copyright,string);
+
+ g_free(string);
+ }
+
+ // URL field
+ if (st_filetag->url && GTK_TOGGLE_BUTTON(ProcessURLField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->url);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->url,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->url,string);
+
+ g_free(string);
+ }
+
+ // 'Encoded by' field
+ if (st_filetag->encoded_by && GTK_TOGGLE_BUTTON(ProcessEncodedByField)->active)
+ {
+ if (!FileTag)
+ {
+ FileTag = ET_File_Tag_Item_New();
+ ET_Copy_File_Tag_Item(ETFile,FileTag);
+ }
+
+ // FIX ME : we suppose that it will not grow more than 2 times its size...
+ string_length = 2 * strlen(st_filetag->encoded_by);
+ string = g_malloc(string_length+1);
+ strncpy(string,st_filetag->encoded_by,string_length);
+ string[string_length]='\0';
+
+ Scan_Process_Fields_Functions(string);
+
+ ET_Set_Field_File_Tag_Item(&FileTag->encoded_by,string);
+
+ g_free(string);
+ }
+ }
+
+ if (FileName && FileTag)
+ {
+ // Synchronize undo key of the both structures (used for the
+ // undo functions, as they are generated as the same time)
+ FileName->key = FileTag->key;
+ }
+ ET_Manage_Changes_Of_File_Data(ETFile,FileName,FileTag);
+
+}
+
+
+void Scan_Process_Fields_Functions (gchar *string)
+{
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsConvertIntoSpace)->active)
+ {
+ Scan_Convert_Underscore_Into_Space(string);
+ Scan_Convert_P20_Into_Space(string);
+ }
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsConvertSpace)->active)
+ Scan_Convert_Space_Into_Undescore(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsInsertSpace)->active)
+ Scan_Process_Fields_Insert_Space(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsOnlyOneSpace)->active)
+ Scan_Process_Fields_Keep_One_Space(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsConvert)->active)
+ Scan_Convert(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsAllUppercase)->active)
+ Scan_Process_Fields_All_Uppercase(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsAllDowncase)->active)
+ Scan_Process_Fields_All_Downcase(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsFirstLetterUppercase)->active)
+ Scan_Process_Fields_Letter_Uppercase(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsFirstLettersUppercase)->active)
+ Scan_Process_Fields_First_Letters_Uppercase(string);
+
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsRemoveSpace)->active)
+ Scan_Process_Fields_Remove_Space(string);
+
+}
+
+void Scan_Process_Fields_All_Uppercase (gchar *text)
+{
+ gchar *temp;
+ gchar temp2[6]; // Must have at least 6 bytes of space
+ gunichar c;
+
+ for (temp = text; *temp; temp = g_utf8_next_char(temp))
+ {
+ c = g_utf8_get_char(temp);
+ if (g_unichar_islower(c))
+ strncpy(temp, temp2, g_unichar_to_utf8(g_unichar_toupper(c), temp2));
+ }
+}
+
+void Scan_Process_Fields_All_Downcase (gchar *text)
+{
+ gchar *temp;
+ gchar temp2[6];
+ gunichar c;
+
+ for (temp = text; *temp; temp = g_utf8_next_char(temp))
+ {
+ c = g_utf8_get_char(temp);
+ if (g_unichar_isupper(c))
+ strncpy(temp, temp2, g_unichar_to_utf8(g_unichar_tolower(c), temp2));
+ }
+}
+
+void Scan_Process_Fields_Letter_Uppercase (gchar *text)
+{
+ gchar *temp;
+ gchar temp2[6];
+ gboolean set_to_upper_case = TRUE;
+ gunichar c;
+ gchar utf8_character[6];
+ gchar *word, *word1, *word2;
+
+ for (temp = text; *temp; temp = g_utf8_next_char(temp))
+ {
+ c = g_utf8_get_char(temp);
+ if (set_to_upper_case && g_unichar_islower(c))
+ strncpy(temp, temp2, g_unichar_to_utf8(g_unichar_toupper(c), temp2));
+ else if (!set_to_upper_case && g_unichar_isupper(c))
+ strncpy(temp, temp2, g_unichar_to_utf8(g_unichar_tolower(c), temp2));
+ set_to_upper_case = FALSE; // After the first time, all will be down case
+ }
+
+ temp = text;
+
+ // Uppercase again the word 'I' in english
+ while ( temp )
+ {
+ word1 = g_utf8_strchr(temp,-1,' ');
+ word2 = g_utf8_strchr(temp,-1,'_');
+
+ // Take the first string found (near beginning of string)
+ if (word1 && word2)
+ word = MIN(word1,word2);
+ else if (word1)
+ word = word1;
+ else if (word2)
+ word = word2;
+ else
+ break;
+
+ // Go to first character of the word (char. after ' ' or '_')
+ word = word+1;
+
+ // Set uppercase word 'I'
+ if (g_ascii_strncasecmp("I ", word, strlen("I ")) == 0)
+ {
+ c = g_utf8_get_char(word);
+ strncpy(word, utf8_character, g_unichar_to_utf8(g_unichar_toupper(c), utf8_character));
+ }
+
+ temp = word;
+ }
+}
+
+void Scan_Process_Fields_First_Letters_Uppercase (gchar *text)
+{
+/**** DANIEL TEST *****
+ gchar *iter;
+ gchar utf8_character[6];
+ gboolean set_to_upper_case = TRUE;
+ gunichar c;
+
+ for (iter = text; *iter; iter = g_utf8_next_char(iter))
+ {
+ c = g_utf8_get_char(iter);
+ if (set_to_upper_case && g_unichar_islower(c))
+ strncpy(iter, utf8_character, g_unichar_to_utf8(g_unichar_toupper(c), utf8_character));
+ else if (!set_to_upper_case && g_unichar_isupper(c))
+ strncpy(iter, utf8_character, g_unichar_to_utf8(g_unichar_tolower(c), utf8_character));
+
+ set_to_upper_case = (g_unichar_isalpha(c)
+ || c == (gunichar)'.'
+ || c == (gunichar)'\''
+ || c == (gunichar)'`') ? FALSE : TRUE;
+ }
+****/
+/**** Barış Çiçek version ****/
+ gchar *word, *word1, *word2, *temp;
+ gint i;
+ gchar utf8_character[6];
+ gunichar c;
+ gboolean set_to_upper_case, set_to_upper_case_tmp;
+ // There have to be space at the end of words to seperate them from prefix
+ gchar *exempt[] =
+ {
+ "a ", "a_",
+ "an ", "an_",
+ "and ", "and_",
+ "at ", "at_",
+ "but ", "but_",
+ "feat. ", "feat._",
+ "for ", "for_",
+ "in ", "in_",
+ "nor ", "nor_",
+ "of ", "of_",
+ "off ", "off_",
+ "on ", "on_",
+ "or ", "or_",
+ "over ", "over_",
+ "so ", "so_",
+ "the ", "the_",
+ "to ", "to_",
+ "with ", "with_",
+ NULL
+ };
+
+ if (!PFS_DONT_UPPER_SOME_WORDS)
+ {
+ exempt[0] = NULL;
+ }
+ Scan_Process_Fields_All_Downcase(text);
+
+ if (!g_utf8_validate(text,-1,NULL))
+ {
+ Log_Print("Scan_Process_Fields_First_Letters_Uppercase: Not a valid utf8! quiting");
+ return;
+ }
+ // Removes trailing whitespace
+ text = g_strchomp(text);
+
+ temp = text;
+
+ // Set first character to uppercase
+ c = g_utf8_get_char(temp);
+ strncpy(text, utf8_character, g_unichar_to_utf8(g_unichar_toupper(c), utf8_character));
+
+ // Uppercase first character of each word, except for 'exempt[]' words lists
+ while ( temp )
+ {
+ word1 = g_utf8_strchr(temp,-1,' ');
+ word2 = g_utf8_strchr(temp,-1,'_');
+
+ // Take the first string found (near beginning of string)
+ if (word1 && word2)
+ word = MIN(word1,word2);
+ else if (word1)
+ word = word1;
+ else if (word2)
+ word = word2;
+ else
+ break;
+
+ // Go to first character of the word (char. after ' ' or '_')
+ word = word+1;
+
+ // Set uppercase the first character of this word
+ c = g_utf8_get_char(word);
+ strncpy(word, utf8_character, g_unichar_to_utf8(g_unichar_toupper(c), utf8_character));
+
+ // Set lowercase the first character of this word if found in the exempt words list
+ for (i=0; exempt[i]!=NULL; i++)
+ {
+ if (g_ascii_strncasecmp(exempt[i], word, strlen(exempt[i])) == 0)
+ {
+ c = g_utf8_get_char(word);
+ strncpy(word, utf8_character, g_unichar_to_utf8(g_unichar_tolower(c), utf8_character));
+ break;
+ }
+ }
+
+ temp = word;
+ }
+
+ // Uppercase letter placed after some characters like '(', '[', '{'
+ set_to_upper_case = FALSE;
+ for (temp = text; *temp; temp = g_utf8_next_char(temp))
+ {
+ c = g_utf8_get_char(temp);
+ set_to_upper_case_tmp = ( c == (gunichar)'('
+ || c == (gunichar)'['
+ || c == (gunichar)'{'
+ || c == (gunichar)'"'
+ ) ? TRUE : FALSE;
+
+ if (set_to_upper_case && g_unichar_islower(c))
+ strncpy(temp, utf8_character, g_unichar_to_utf8(g_unichar_toupper(c), utf8_character));
+
+ set_to_upper_case = set_to_upper_case_tmp;
+ }
+
+}
+
+void Scan_Process_Fields_Remove_Space (gchar *text)
+{
+ gchar *tmp, *tmp1;
+
+ tmp = tmp1 = text;
+ while (*tmp)
+ {
+ while (*tmp == ' ')
+ tmp++;
+ if (*tmp)
+ *(tmp1++) = *(tmp++);
+ }
+ *tmp1 = '\0';
+}
+
+void Scan_Process_Fields_Insert_Space (gchar *text)
+{
+ gchar *iter;
+ gunichar c;
+ gint j;
+
+ // FIXME: try to use realloc
+ for (iter = g_utf8_next_char(text); *iter; iter = g_utf8_next_char(iter)) // i=1 to not consider first "uppercase" letter
+ {
+ c = g_utf8_get_char(iter);
+
+ if (g_unichar_isupper(c))
+ {
+ for (j = strlen(iter); j > 0; j--)
+ *(iter + j) = *(iter + j - 1);
+ *iter = ' ';
+ iter++;
+ }
+ }
+}
+void Scan_Process_Fields_Keep_One_Space (gchar *text)
+{
+ gchar *tmp, *tmp1;
+ tmp = tmp1 = text;
+
+ // Remove multiple consecutive underscores and spaces.
+ while (*tmp1)
+ {
+ while (*tmp1 && *tmp1 != ' ' && *tmp1 != '_')
+ *(tmp++) = *(tmp1++);
+ if (!*tmp1)
+ break;
+ *(tmp++) = *(tmp1++);
+ while (*tmp1 == ' ' || *tmp1 == '_')
+ *tmp1++;
+ }
+ *tmp = '\0';
+}
+
+/*
+ * Function to replace underscore '_' by a space
+ */
+void Scan_Convert_Underscore_Into_Space (gchar *string)
+{
+ gchar *tmp;
+
+ while ((tmp=strchr(string,'_'))!=NULL)
+ *tmp = ' ';
+}
+
+/*
+ * Function to replace %20 by a space
+ */
+void Scan_Convert_P20_Into_Space (gchar *string)
+{
+ gchar *tmp, *tmp1;
+
+ while ((tmp=strstr(string,"%20"))!=NULL)
+ {
+ tmp1 = tmp + 3;
+ *(tmp++) = ' ';
+ while (*tmp1)
+ *(tmp++) = *(tmp1++);
+ *tmp = '\0';
+ }
+}
+
+/*
+ * Function to replace space by '_'
+ */
+void Scan_Convert_Space_Into_Undescore (gchar *string)
+{
+ gchar *tmp;
+
+ while ((tmp=strchr(string,' '))!=NULL)
+ *tmp = '_';
+}
+
+/*
+ * Replace something with something else ;)
+ * Currently this only works with one character for each
+ */
+void Scan_Convert (gchar *string)
+{
+ gchar *tmp;
+ gchar *from = gtk_editable_get_chars(GTK_EDITABLE(ProcessFieldsConvertFrom),0,-1 );
+ gchar *to = gtk_editable_get_chars(GTK_EDITABLE(ProcessFieldsConvertTo),0,-1 );
+
+ if ( from && to && strlen(from)>0 && strlen(to)>0 )
+ while ((tmp=strchr(string,*from))!=NULL)
+ *tmp = *to;
+}
+
+
+
+/*
+ * Return the field of a 'File_Tag' structure corresponding to the mask code
+ */
+gchar **Scan_Return_File_Tag_Field_From_Mask_Code (File_Tag *FileTag, gchar code)
+{
+ switch (code)
+ {
+ case 't': /* Title */
+ return &FileTag->title;
+ case 'a': /* Artist */
+ return &FileTag->artist;
+ case 'b': /* Album */
+ return &FileTag->album;
+ case 'd': /* Disc Number */
+ return &FileTag->disc_number;
+ case 'y': /* Year */
+ return &FileTag->year;
+ case 'n': /* Track */
+ return &FileTag->track;
+ case 'l': /* Track Total */
+ return &FileTag->track_total;
+ case 'g': /* Genre */
+ return &FileTag->genre;
+ case 'c': /* Comment */
+ return &FileTag->comment;
+ case 'p': /* Composer */
+ return &FileTag->composer;
+ case 'o': /* Orig. Artist */
+ return &FileTag->orig_artist;
+ case 'r': /* Copyright */
+ return &FileTag->copyright;
+ case 'u': /* URL */
+ return &FileTag->url;
+ case 'e': /* Encoded by */
+ return &FileTag->encoded_by;
+ case 'i': /* Ignored */
+ return NULL;
+ default:
+ Log_Print("Scanner: Invalid code '%%%c' found!",code);
+ return NULL;
+ }
+}
+
+
+
+/******************
+ * Scanner Window *
+ ******************/
+#include "../pixmaps/black.xpm"
+#include "../pixmaps/blackwhite.xpm"
+void Open_ScannerWindow (gint scanner_type)
+{
+ GtkWidget *ScanVBox;
+ GtkWidget *HBox1, *HBox2, *HBox4, *VBox, *hbox, *vbox;
+ GtkWidget *Table;
+ GtkWidget *Label;
+ GtkWidget *Button;
+ GtkWidget *Separator;
+ GtkWidget *Icon;
+ GtkWidget *EventBox;
+ GtkTooltips *Tips;
+ GtkWidget *MaskStatusIconBox;
+ GList *pf_cb_group1 = NULL;
+ GList *pf_cb_group2 = NULL;
+ GList *pf_cb_group3 = NULL;
+ GtkTreeViewColumn * column;
+ GtkCellRenderer *renderer;
+
+ /* Check if already opened */
+ if (ScannerWindow)
+ {
+ //gdk_window_show(ScannerWindow->window);
+ gdk_window_raise(ScannerWindow->window);
+ if (ScannerOptionCombo)
+ {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(ScannerOptionCombo), scanner_type);
+ }
+ return;
+ }
+
+ if ( scanner_type < SCANNER_FILL_TAG
+ || scanner_type > SCANNER_PROCESS_FIELDS)
+ scanner_type = SCANNER_FILL_TAG;
+
+ /* The window */
+ ScannerWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ /* Config */
+ gtk_container_set_border_width(GTK_CONTAINER(ScannerWindow), 5);
+ gtk_window_set_resizable(GTK_WINDOW(ScannerWindow), FALSE);
+ gtk_window_set_wmclass(GTK_WINDOW(ScannerWindow),"EasyTag_Scanner","easytag"); // Patch from Nikolai Prokoschenko (Debian)
+ if (SCANNER_WINDOW_ON_TOP)
+ gtk_window_set_transient_for(GTK_WINDOW(ScannerWindow),GTK_WINDOW(MainWindow));
+
+ /* The init position is define below, cause the scanner window must be showed before
+ * to be able to move it. */
+
+ /* Title */
+ gtk_window_set_title(GTK_WINDOW(ScannerWindow),_("Tag and File Name scan"));
+
+ /* Signals connection */
+ g_signal_connect(G_OBJECT(ScannerWindow),"destroy",G_CALLBACK(ScannerWindow_Quit),NULL);
+ g_signal_connect(G_OBJECT(ScannerWindow),"delete_event",G_CALLBACK(ScannerWindow_Quit),NULL);
+ g_signal_connect(G_OBJECT(ScannerWindow),"key_press_event",G_CALLBACK(ScannerWindow_Key_Press),NULL);
+
+ /* The tooltips */
+ Tips = gtk_tooltips_new();
+
+ /* The main vbox */
+ ScanVBox = gtk_vbox_new(FALSE,2);
+ gtk_container_add(GTK_CONTAINER(ScannerWindow),ScanVBox);
+
+
+ /*
+ * The hbox for mode buttons + buttons + what to scan
+ */
+ HBox1 = gtk_hbox_new(FALSE,0);
+ gtk_box_pack_start(GTK_BOX(ScanVBox),HBox1,FALSE,FALSE,0);
+
+ /* Option Menu */
+ Label = gtk_label_new(_("Scanner:"));
+ gtk_box_pack_start(GTK_BOX(HBox1),Label,FALSE,FALSE,0);
+
+ EventBox = gtk_event_box_new();
+ ScannerOptionCombo = gtk_combo_box_new_text();
+ gtk_container_add(GTK_CONTAINER(EventBox),ScannerOptionCombo);
+ gtk_box_pack_start(GTK_BOX(HBox1),EventBox,TRUE,TRUE,2);
+ gtk_widget_set_size_request(ScannerOptionCombo, 160, -1);
+
+ /* Option for Tag */
+ gtk_combo_box_append_text(GTK_COMBO_BOX(ScannerOptionCombo), _(Scanner_Option_Menu_Items[SCANNER_FILL_TAG]));
+
+ /* Option for FileName */
+ gtk_combo_box_append_text(GTK_COMBO_BOX(ScannerOptionCombo), _(Scanner_Option_Menu_Items[SCANNER_RENAME_FILE]));
+
+ /* Option for ProcessFields */
+ gtk_combo_box_append_text(GTK_COMBO_BOX(ScannerOptionCombo), _(Scanner_Option_Menu_Items[SCANNER_PROCESS_FIELDS]));
+
+ // Selection of the item made at the end of the function
+ gtk_tooltips_set_tip(Tips, EventBox, _("Select the type of scanner to use"), NULL);
+ g_signal_connect(G_OBJECT(ScannerOptionCombo), "changed", G_CALLBACK(Scanner_Option_Menu_Activate_Item), NULL);
+
+ /* 'Scan selected files' button */
+ SWScanButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock("easytag-scan", GTK_ICON_SIZE_BUTTON);
+ gtk_container_add(GTK_CONTAINER(SWScanButton),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox1),SWScanButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(SWScanButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,SWScanButton,_("Open scanner window / Scan selected files"),NULL);
+ g_signal_connect(G_OBJECT(SWScanButton),"clicked",G_CALLBACK(Action_Scan_Selected_Files),NULL);
+
+ /* Separator line */
+ Separator = gtk_vseparator_new();
+ gtk_box_pack_start(GTK_BOX(HBox1),Separator,FALSE,FALSE,2);
+
+ /* Options button */
+ Button = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add(GTK_CONTAINER(Button),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox1),Button,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(Button),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,Button,_("Scanner Options"),NULL);
+ g_signal_connect(G_OBJECT(Button),"clicked",G_CALLBACK(Scan_Option_Button),NULL);
+
+ /* Mask Editor button */
+ MaskEditorButton = gtk_toggle_button_new();
+ Icon = gtk_image_new_from_stock("easytag-mask", GTK_ICON_SIZE_BUTTON);
+ gtk_container_add(GTK_CONTAINER(MaskEditorButton),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox1),MaskEditorButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorButton,_("Show / Hide Masks Editor"),NULL);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(MaskEditorButton),SCAN_MASK_EDITOR_BUTTON);
+ g_signal_connect(G_OBJECT(MaskEditorButton),"toggled",G_CALLBACK(Scan_Toggle_Mask_Editor_Button),NULL);
+
+ /* Legend button */
+ LegendButton = gtk_toggle_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_HELP, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add(GTK_CONTAINER(LegendButton),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox1),LegendButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(LegendButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,LegendButton,_("Show / Hide Legend"),NULL);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(LegendButton),SCAN_LEGEND_BUTTON);
+ g_signal_connect(G_OBJECT(LegendButton),"toggled",G_CALLBACK(Scan_Toggle_Legend_Button),NULL);
+
+ /* Close button */
+ Button = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_QUIT, GTK_ICON_SIZE_BUTTON);
+ gtk_container_add(GTK_CONTAINER(Button),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox1),Button,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(Button),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,Button,_("Close this window"),NULL);
+ g_signal_connect(G_OBJECT(Button),"clicked",G_CALLBACK(ScannerWindow_Quit),NULL);
+
+ /*
+ * Frame for Scan Tag
+ */
+ ScanTagFrame = gtk_frame_new (_(Scanner_Option_Menu_Items[0]));
+ gtk_box_pack_start(GTK_BOX(ScanVBox),ScanTagFrame,FALSE,FALSE,0);
+
+ vbox = gtk_vbox_new(FALSE,4);
+ gtk_container_add(GTK_CONTAINER(ScanTagFrame),vbox);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+ gtk_widget_show(vbox);
+
+ /* The combo box + Status icon */
+ HBox2 = gtk_hbox_new(FALSE,2);
+ gtk_box_pack_start(GTK_BOX(vbox),HBox2,TRUE,TRUE,0);
+
+ // Set up list model which is used both by the combobox and the editor
+ ScanTagListModel = gtk_list_store_new(MASK_EDITOR_COUNT, G_TYPE_STRING);
+
+ // The combo box to select the mask to apply
+ ScanTagMaskCombo = gtk_combo_box_entry_new();
+ gtk_combo_box_set_model(GTK_COMBO_BOX(ScanTagMaskCombo), GTK_TREE_MODEL(ScanTagListModel));
+ gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(ScanTagMaskCombo), MASK_EDITOR_TEXT);
+
+ gtk_box_pack_start(GTK_BOX(HBox2),ScanTagMaskCombo,TRUE,TRUE,2);
+ gtk_tooltips_set_tip(Tips,GTK_WIDGET(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)),
+ _("Select or type in a mask using codes (see Legend) to parse file name and "
+ "path. Used to fill in tag fields."),NULL);
+ // Signal to generate preview (preview of the new tag values)
+ g_signal_connect_swapped(G_OBJECT(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)),"changed",
+ G_CALLBACK(Scan_Fill_Tag_Generate_Preview),NULL);
+
+ // Load masks into the combobox from a file
+ Load_Scan_Tag_Masks_List(ScanTagListModel, MASK_EDITOR_TEXT, Scan_Masks);
+ if (SCAN_TAG_DEFAULT_MASK)
+ {
+ Add_String_To_Combo_List(ScanTagListModel, SCAN_TAG_DEFAULT_MASK);
+ gtk_entry_set_text(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child), SCAN_TAG_DEFAULT_MASK);
+ }else
+ {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(ScanTagMaskCombo), 0);
+ }
+
+ // Mask status icon
+ MaskStatusIconBox = Create_Pixmap_Icon_With_Event_Box("easytag-forbidden");
+ gtk_box_pack_start(GTK_BOX(HBox2),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(ScanTagMaskCombo)->child),"changed",
+ G_CALLBACK(Scan_Check_Scan_Tag_Mask),GTK_OBJECT(MaskStatusIconBox));
+
+ // Preview label
+ FillTagPreviewLabel = gtk_label_new(_("Fill tag preview..."));
+ gtk_label_set_line_wrap(GTK_LABEL(FillTagPreviewLabel),TRUE);
+ gtk_widget_show(FillTagPreviewLabel);
+ gtk_box_pack_start(GTK_BOX(vbox),FillTagPreviewLabel,TRUE,TRUE,0);
+
+ /*
+ * Frame for Rename File
+ */
+ RenameFileFrame = gtk_frame_new (_(Scanner_Option_Menu_Items[1]));
+ gtk_box_pack_start(GTK_BOX(ScanVBox),RenameFileFrame,FALSE,FALSE,0);
+
+ vbox = gtk_vbox_new(FALSE,4);
+ gtk_container_add(GTK_CONTAINER(RenameFileFrame),vbox);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+ gtk_widget_show(vbox);
+
+ /* The button to prefix path + combo box + Status icon */
+ HBox4 = gtk_hbox_new(FALSE,2);
+ gtk_box_pack_start(GTK_BOX(vbox),HBox4,TRUE,TRUE,0);
+
+ // Button to prefix path
+ RenameFilePrefixPathButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock("easytag-add-folder", GTK_ICON_SIZE_SMALL_TOOLBAR); // On Win32, GTK_ICON_SIZE_BUTTON enlarge the combobox...
+ gtk_container_add(GTK_CONTAINER(RenameFilePrefixPathButton),Icon);
+ gtk_box_pack_start(GTK_BOX(HBox4),RenameFilePrefixPathButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(RenameFilePrefixPathButton),GTK_RELIEF_NONE);
+ g_signal_connect(G_OBJECT(RenameFilePrefixPathButton),"clicked",G_CALLBACK(Scan_Rename_File_Prefix_Path),NULL);
+ gtk_tooltips_set_tip(Tips,RenameFilePrefixPathButton,_("Prefix mask with current path"),NULL);
+
+ // Set up list model which is used both by the combobox and the editor
+ RenameFileListModel = gtk_list_store_new(MASK_EDITOR_COUNT, G_TYPE_STRING);
+
+ // The combo box to select the mask to apply
+ RenameFileMaskCombo = gtk_combo_box_entry_new();
+ gtk_combo_box_set_model(GTK_COMBO_BOX(RenameFileMaskCombo), GTK_TREE_MODEL(RenameFileListModel));
+ gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(RenameFileMaskCombo), MASK_EDITOR_TEXT);
+
+ gtk_box_pack_start(GTK_BOX(HBox4),RenameFileMaskCombo,TRUE,TRUE,2);
+ gtk_container_set_border_width(GTK_CONTAINER(HBox4), 2);
+ gtk_tooltips_set_tip(Tips,GTK_WIDGET(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)),
+ _("Select or type in a mask using codes (see Legend) to parse tag fields. "
+ "Used to rename the file.\nUse / to make directories. If the first character "
+ "is /, it's a absolute path, otherwise is relative to the old path."),NULL);
+ // Signal to generate preview (preview of the new filename)
+ g_signal_connect_swapped(G_OBJECT(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)),"changed",
+ G_CALLBACK(Scan_Rename_File_Generate_Preview),NULL);
+
+ // Load masks into the combobox from a file
+ Load_Rename_File_Masks_List(RenameFileListModel, MASK_EDITOR_TEXT, Rename_File_Masks);
+ if (RENAME_FILE_DEFAULT_MASK)
+ {
+ Add_String_To_Combo_List(RenameFileListModel, RENAME_FILE_DEFAULT_MASK);
+ gtk_entry_set_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child), RENAME_FILE_DEFAULT_MASK);
+ }else
+ {
+ gtk_combo_box_set_active(GTK_COMBO_BOX(RenameFileMaskCombo), 0);
+ }
+
+ // Mask status icon
+ MaskStatusIconBox = Create_Pixmap_Icon_With_Event_Box("easytag-forbidden");
+ gtk_box_pack_start(GTK_BOX(HBox4),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_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)),"changed",
+ G_CALLBACK(Scan_Check_Rename_File_Mask),G_OBJECT(MaskStatusIconBox));
+
+ /* Preview label */
+ RenameFilePreviewLabel = gtk_label_new(_("Rename file preview..."));
+ gtk_label_set_line_wrap(GTK_LABEL(RenameFilePreviewLabel),TRUE);
+ gtk_widget_show(RenameFilePreviewLabel);
+ gtk_box_pack_start(GTK_BOX(vbox),RenameFilePreviewLabel,TRUE,TRUE,0);
+
+ /*
+ * Frame for Processing Fields
+ */
+ ProcessFieldsFrame = gtk_frame_new (_(Scanner_Option_Menu_Items[2]));
+ gtk_box_pack_start(GTK_BOX(ScanVBox),ProcessFieldsFrame,FALSE,FALSE,0);
+
+ VBox = gtk_vbox_new(FALSE,0);
+ gtk_container_add(GTK_CONTAINER(ProcessFieldsFrame),VBox);
+ gtk_container_set_border_width(GTK_CONTAINER(VBox), 4);
+ gtk_widget_show(VBox);
+
+ /* Group: select entry fields to process */
+ hbox = gtk_hbox_new(FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),hbox,FALSE,FALSE,2);
+ EventBox = gtk_event_box_new();
+ Label = gtk_label_new(_("Select fields:"));
+ gtk_box_pack_start(GTK_BOX(hbox),EventBox,FALSE,FALSE,2);
+ gtk_container_add(GTK_CONTAINER(EventBox),Label);
+ gtk_tooltips_set_tip(Tips,EventBox,_("The buttons on the right represent the fields which can "
+ "be processed. Select those who interest you."),NULL);
+ // Advice for Translators : set the first letter of filename translated
+ ProcessFileNameField = gtk_toggle_button_new_with_label( _("F"));
+ gtk_tooltips_set_tip(Tips,ProcessFileNameField, _("Process file name field"),NULL);
+ // Advice for Translators : set the first letter of title translated
+ ProcessTitleField = gtk_toggle_button_new_with_label( _("T"));
+ gtk_tooltips_set_tip(Tips,ProcessTitleField, _("Process title field"),NULL);
+ // Advice for Translators : set the first letter of artist translated
+ ProcessArtistField = gtk_toggle_button_new_with_label( _("Ar"));
+ gtk_tooltips_set_tip(Tips,ProcessArtistField, _("Process file artist field"),NULL);
+ // Advice for Translators : set the first letter of album translated
+ ProcessAlbumField = gtk_toggle_button_new_with_label( _("Al"));
+ gtk_tooltips_set_tip(Tips,ProcessAlbumField, _("Process album field"),NULL);
+ // Advice for Translators : set the first letter of genre translated
+ ProcessGenreField = gtk_toggle_button_new_with_label( _("G"));
+ gtk_tooltips_set_tip(Tips,ProcessGenreField, _("Process genre field"),NULL);
+ // Advice for Translators : set the first letter of comment translated
+ ProcessCommentField = gtk_toggle_button_new_with_label( _("Cm"));
+ gtk_tooltips_set_tip(Tips,ProcessCommentField, _("Process comment field"),NULL);
+ // Advice for Translators : set the first letter of composer translated
+ ProcessComposerField = gtk_toggle_button_new_with_label( _("Cp"));
+ gtk_tooltips_set_tip(Tips,ProcessComposerField, _("Process composer field"),NULL);
+ // Advice for Translators : set the first letter of orig artist translated
+ ProcessOrigArtistField = gtk_toggle_button_new_with_label( _("O"));
+ gtk_tooltips_set_tip(Tips,ProcessOrigArtistField, _("Process original artist field"),NULL);
+ // Advice for Translators : set the first letter of copyright translated
+ ProcessCopyrightField = gtk_toggle_button_new_with_label( _("Cr"));
+ gtk_tooltips_set_tip(Tips,ProcessCopyrightField, _("Process copyright field"),NULL);
+ // Advice for Translators : set the first letter of URL translated
+ ProcessURLField = gtk_toggle_button_new_with_label( _("U"));
+ gtk_tooltips_set_tip(Tips,ProcessURLField, _("Process URL field"),NULL);
+ // Advice for Translators : set the first letter of encoder name translated
+ ProcessEncodedByField = gtk_toggle_button_new_with_label( _("E"));
+ gtk_tooltips_set_tip(Tips,ProcessEncodedByField, _("Process encoder name field"),NULL);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessFileNameField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessTitleField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessArtistField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessAlbumField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessGenreField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessCommentField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessComposerField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessOrigArtistField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessCopyrightField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessURLField, TRUE,TRUE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessEncodedByField, TRUE,TRUE,2);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFileNameField), PROCESS_FILENAME_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessTitleField), PROCESS_TITLE_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessArtistField), PROCESS_ARTIST_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessAlbumField), PROCESS_ALBUM_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessGenreField), PROCESS_GENRE_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCommentField), PROCESS_COMMENT_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessComposerField), PROCESS_COMPOSER_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessOrigArtistField), PROCESS_ORIG_ARTIST_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCopyrightField), PROCESS_COPYRIGHT_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessURLField), PROCESS_URL_FIELD);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessEncodedByField), PROCESS_ENCODED_BY_FIELD);
+ g_signal_connect(G_OBJECT(ProcessFileNameField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessTitleField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessArtistField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessAlbumField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessGenreField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessCommentField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessComposerField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessOrigArtistField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessCopyrightField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessURLField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ g_signal_connect(G_OBJECT(ProcessEncodedByField), "toggled",G_CALLBACK(Select_Fields_Set_Sensitive),NULL);
+ /* The small buttons */
+ vbox = gtk_vbox_new(FALSE,2);
+ gtk_box_pack_start(GTK_BOX(hbox),vbox,FALSE,FALSE,0);
+ Button = gtk_button_new();
+ g_signal_connect(G_OBJECT(Button),"clicked",G_CALLBACK(Select_Fields_Invert_Selection),NULL);
+ gtk_box_pack_start(GTK_BOX(vbox),Button,FALSE,FALSE,0);
+ gtk_widget_set_size_request(Button, 12, 12);
+ //Icon = gtk_image_new_from_stock("easytag-blackwhite", GTK_ICON_SIZE_BUTTON);
+ Icon = Create_Xpm_Image((const char **)blackwhite_xpm);
+ GTK_WIDGET_UNSET_FLAGS(Button,GTK_CAN_DEFAULT); // To have enought space to display the icon
+ GTK_WIDGET_UNSET_FLAGS(Button,GTK_CAN_FOCUS);
+ gtk_container_add(GTK_CONTAINER(Button),Icon);
+ gtk_tooltips_set_tip(Tips,Button,_("Invert Selection"),NULL);
+ Button = gtk_button_new();
+ g_signal_connect(G_OBJECT(Button),"clicked",G_CALLBACK(Select_Fields_Select_Unselect_All),NULL);
+ gtk_box_pack_start(GTK_BOX(vbox),Button,FALSE,FALSE,0);
+ gtk_widget_set_size_request(Button, 12, 12);
+ Icon = Create_Xpm_Image((const char **)black_xpm);
+ GTK_WIDGET_UNSET_FLAGS(Button,GTK_CAN_DEFAULT); // To have enought space to display the icon
+ GTK_WIDGET_UNSET_FLAGS(Button,GTK_CAN_FOCUS);
+ gtk_container_add(GTK_CONTAINER(Button),Icon);
+ gtk_tooltips_set_tip(Tips,Button,_("Select/Unselect All."),NULL);
+
+ /* Separator line */
+ Separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0);
+
+ /* Group: character conversion */
+ ProcessFieldsConvertIntoSpace = gtk_check_button_new_with_label(_("Convert '_' and '%20' to ' '"));
+ ProcessFieldsConvertSpace = gtk_check_button_new_with_label(_("Convert ' ' to '_'"));
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsConvertIntoSpace,FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsConvertSpace, FALSE,FALSE,0);
+ hbox = gtk_hbox_new(FALSE,2);
+ ProcessFieldsConvert = gtk_check_button_new_with_label(_("Convert:")); // Patch from Ben Hearsum, Oct. 3, 2003
+ ProcessFieldsConvertTo = gtk_entry_new();
+ ProcessFieldsConvertLabelTo = gtk_label_new(_("to: ")); // A "space" at the end to allow an other traduction for "to :" (needed in French!)
+ ProcessFieldsConvertFrom = gtk_entry_new();
+ gtk_entry_set_max_length(GTK_ENTRY(ProcessFieldsConvertTo), 1);
+ gtk_entry_set_max_length(GTK_ENTRY(ProcessFieldsConvertFrom), 1);
+ gtk_widget_set_size_request(ProcessFieldsConvertTo,40,-1);
+ gtk_widget_set_size_request(ProcessFieldsConvertFrom,40,-1);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessFieldsConvert, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessFieldsConvertFrom, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessFieldsConvertLabelTo,FALSE,FALSE,4);
+ gtk_box_pack_start(GTK_BOX(hbox),ProcessFieldsConvertTo, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),hbox,FALSE,FALSE,0);
+ /* List creation for check buttons in group */
+ pf_cb_group1 = g_list_append (pf_cb_group1,ProcessFieldsConvertIntoSpace);
+ pf_cb_group1 = g_list_append (pf_cb_group1,ProcessFieldsConvertSpace);
+ pf_cb_group1 = g_list_append (pf_cb_group1,ProcessFieldsConvert);
+ /* Toggled signals */
+ g_signal_connect(G_OBJECT(ProcessFieldsConvertIntoSpace),"toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group1);
+ g_signal_connect(G_OBJECT(ProcessFieldsConvertSpace), "toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group1);
+ g_signal_connect(G_OBJECT(ProcessFieldsConvert), "toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group1);
+ g_signal_connect(G_OBJECT(ProcessFieldsConvert), "toggled",G_CALLBACK(Process_Fields_Convert_Check_Button_Toggled),NULL);
+ /* Set check buttons to init value */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsConvertIntoSpace),PF_CONVERT_INTO_SPACE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsConvertSpace),PF_CONVERT_SPACE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsConvert),PF_CONVERT);
+ /* Tooltips */
+ gtk_tooltips_set_tip(Tips,ProcessFieldsConvertIntoSpace,
+ _("The underscore character or the string '%20' are replaced by one space. "
+ "Example, before: 'Text%20In%20An_Entry', after: 'Text In An Entry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsConvertSpace,
+ _("The space character is replaced by one underscore character. "
+ "Example, before: 'Text In An Entry', after: 'Text_In_An_Entry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsConvert,_("Replace a character by an other one."),NULL);
+
+ /* Separator line */
+ Separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0);
+
+ /* Group: capitalize, ... */
+ ProcessFieldsAllUppercase = gtk_check_button_new_with_label (_("All uppercase"));
+ ProcessFieldsAllDowncase = gtk_check_button_new_with_label (_("All downcase"));
+ ProcessFieldsFirstLetterUppercase = gtk_check_button_new_with_label(_("First letter uppercase"));
+ ProcessFieldsFirstLettersUppercase = gtk_check_button_new_with_label(_("First letter uppercase of each word"));
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsAllUppercase, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsAllDowncase, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsFirstLetterUppercase, FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsFirstLettersUppercase,FALSE,FALSE,0);
+ /* List creation for check buttons in group */
+ pf_cb_group2 = g_list_append(pf_cb_group2,ProcessFieldsAllUppercase);
+ pf_cb_group2 = g_list_append(pf_cb_group2,ProcessFieldsAllDowncase);
+ pf_cb_group2 = g_list_append(pf_cb_group2,ProcessFieldsFirstLetterUppercase);
+ pf_cb_group2 = g_list_append(pf_cb_group2,ProcessFieldsFirstLettersUppercase);
+ /* Toggled signals */
+ g_signal_connect(G_OBJECT(ProcessFieldsAllUppercase),"toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group2);
+ g_signal_connect(G_OBJECT(ProcessFieldsAllDowncase), "toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group2);
+ g_signal_connect(G_OBJECT(ProcessFieldsFirstLetterUppercase),"toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group2);
+ g_signal_connect(G_OBJECT(ProcessFieldsFirstLettersUppercase),"toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group2);
+ /* Set check buttons to init value */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsAllUppercase),PF_CONVERT_ALL_UPPERCASE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsAllDowncase),PF_CONVERT_ALL_DOWNCASE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsFirstLetterUppercase),PF_CONVERT_FIRST_LETTER_UPPERCASE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsFirstLettersUppercase),PF_CONVERT_FIRST_LETTERS_UPPERCASE);
+ /* Tooltips */
+ gtk_tooltips_set_tip(Tips,ProcessFieldsAllUppercase,
+ _("Convert all words in all fields to upper case. "
+ "Example, before: 'Text IN AN entry', after: 'TEXT IN AN ENTRY'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsAllDowncase,
+ _("Convert all words in all fields to lower case. "
+ "Example, before: 'TEXT IN an entry', after: 'text in an entry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsFirstLetterUppercase,
+ _("Convert the initial of the first word in all fields to upper case. "
+ "Example, before: 'text IN An ENTRY', after: 'Text in an entry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsFirstLettersUppercase,
+ _("Convert the initial of each word in all fields to upper case. "
+ "Example, before: 'Text in an ENTRY', after: 'Text In An Entry'."),NULL);
+
+ /* Separator line */
+ Separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(VBox),Separator,FALSE,FALSE,0);
+
+ /* Group: insert/remove spaces */
+ ProcessFieldsRemoveSpace = gtk_check_button_new_with_label(_("Remove spaces"));
+ ProcessFieldsInsertSpace = gtk_check_button_new_with_label(_("Insert a space before an uppercase letter"));
+ ProcessFieldsOnlyOneSpace = gtk_check_button_new_with_label(_("Remove duplicates of space or underscore"));
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsRemoveSpace,FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsInsertSpace,FALSE,FALSE,0);
+ gtk_box_pack_start(GTK_BOX(VBox),ProcessFieldsOnlyOneSpace,FALSE,FALSE,0);
+ /* List creation for check buttons in group */
+ pf_cb_group3 = g_list_append (pf_cb_group3,ProcessFieldsRemoveSpace);
+ pf_cb_group3 = g_list_append (pf_cb_group3,ProcessFieldsInsertSpace);
+ pf_cb_group3 = g_list_append (pf_cb_group3,ProcessFieldsOnlyOneSpace);
+ /* Toggled signals */
+ g_signal_connect(G_OBJECT(ProcessFieldsRemoveSpace), "toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group3);
+ g_signal_connect(G_OBJECT(ProcessFieldsInsertSpace), "toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group3);
+ g_signal_connect(G_OBJECT(ProcessFieldsOnlyOneSpace),"toggled",G_CALLBACK(Process_Fields_Check_Button_Toggled),pf_cb_group3);
+ /* Set check buttons to init value */
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsRemoveSpace),PF_REMOVE_SPACE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsInsertSpace),PF_INSERT_SPACE);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFieldsOnlyOneSpace),PF_ONLY_ONE_SPACE);
+ /* Tooltips */
+ gtk_tooltips_set_tip(Tips,ProcessFieldsRemoveSpace,
+ _("All spaces between words are removed. "
+ "Example, before: 'Text In An Entry', after: 'TextInAnEntry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsInsertSpace,
+ _("A space is inserted before each upper case letter. "
+ "Example, before: 'TextInAnEntry', after: 'Text In An Entry'."),NULL);
+ gtk_tooltips_set_tip(Tips,ProcessFieldsOnlyOneSpace,
+ _("Duplicated spaces or underscores are removed. "
+ "Example, before: 'Text__In__An Entry', after: 'Text_In_An Entry'."),NULL);
+
+ /*
+ * Frame to display codes legend
+ */
+ LegendFrame = gtk_frame_new (_("Legend"));
+ gtk_box_pack_start(GTK_BOX(ScanVBox),LegendFrame,FALSE,FALSE,0);
+ /* Legend labels */
+ Table = gtk_table_new(3,3,FALSE);
+ gtk_container_add(GTK_CONTAINER(LegendFrame),Table);
+ gtk_container_set_border_width(GTK_CONTAINER(Table),4);
+ Label = gtk_label_new(_("%a : artist"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,0,1,0,1);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%b : album"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,0,1,1,2);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%c : comment"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,0,1,2,3);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%p : composer"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,0,1,3,4);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%r : copyright"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,0,1,4,5);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%d : disc number"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,1,2,0,1);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%e : encoded by"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,1,2,1,2);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%g : genre"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,1,2,2,3);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%i : ignored"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,1,2,3,4);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%l : number of tracks"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,1,2,4,5);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%o : orig. artist"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,2,3,0,1);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%n : track"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,2,3,1,2);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%t : title"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,2,3,2,3);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%u : URL"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,2,3,3,4);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+ Label = gtk_label_new(_("%y : year"));
+ gtk_table_attach_defaults(GTK_TABLE(Table),Label,2,3,4,5);
+ gtk_misc_set_alignment(GTK_MISC(Label),0,0.5);
+
+ /*
+ * Masks Editor
+ */
+ MaskEditorFrame = gtk_frame_new (_("Mask Editor"));
+ gtk_box_pack_start(GTK_BOX(ScanVBox),MaskEditorFrame,FALSE,FALSE,0);
+ MaskEditorHBox = gtk_hbox_new(FALSE,4);
+ gtk_container_add(GTK_CONTAINER(MaskEditorFrame),MaskEditorHBox);
+ gtk_container_set_border_width(GTK_CONTAINER(MaskEditorHBox), 4);
+
+ /* The editor part */
+ MaskEditorVBox = gtk_vbox_new(FALSE,2);
+ gtk_box_pack_start(GTK_BOX(MaskEditorHBox),MaskEditorVBox,TRUE,TRUE,0);
+ MaskEditorScrollWindow = gtk_scrolled_window_new(NULL,NULL);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorScrollWindow,TRUE,TRUE,0);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(MaskEditorScrollWindow),
+ GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_size_request(GTK_WIDGET(MaskEditorScrollWindow), -1, 101);
+
+ /* The list */
+ MaskEditorList = gtk_tree_view_new();
+ gtk_tree_view_set_model(GTK_TREE_VIEW(MaskEditorList), GTK_TREE_MODEL(ScanTagListModel));
+
+ renderer = gtk_cell_renderer_text_new();
+ column = gtk_tree_view_column_new_with_attributes(NULL,
+ renderer, "text", MASK_EDITOR_TEXT, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(MaskEditorList), column);
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(MaskEditorList), FALSE);
+ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList)),
+ GTK_SELECTION_MULTIPLE);
+ gtk_tree_view_set_reorderable(GTK_TREE_VIEW(MaskEditorList), TRUE);
+ gtk_container_add(GTK_CONTAINER(MaskEditorScrollWindow), MaskEditorList);
+ g_signal_connect_after(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList))),
+ "changed", G_CALLBACK(Mask_Editor_List_Row_Selected), NULL);
+ g_signal_connect(G_OBJECT(MaskEditorList), "key-press-event",
+ G_CALLBACK(Mask_Editor_List_Key_Press), NULL);
+ /* The entry */
+ hbox = gtk_hbox_new(FALSE,2);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),hbox,FALSE,FALSE,0);
+ MaskEditorEntry = gtk_entry_new();
+ gtk_box_pack_start(GTK_BOX(hbox),MaskEditorEntry,TRUE,TRUE,2);
+ g_signal_connect(G_OBJECT(MaskEditorEntry),"changed",
+ G_CALLBACK(Mask_Editor_Entry_Changed),NULL);
+ // 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(MaskEditorEntry),"changed",
+ G_CALLBACK(Scan_Check_Editor_Mask),G_OBJECT(MaskStatusIconBox));
+
+ /* The buttons part */
+ MaskEditorVBox = gtk_vbox_new(FALSE,0);
+ gtk_box_pack_start(GTK_BOX(MaskEditorHBox),MaskEditorVBox,FALSE,FALSE,0);
+
+ /* New mask button */
+ MaskEditorNewButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_NEW, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorNewButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorNewButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorNewButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorNewButton,_("Create New Mask"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorNewButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_New),NULL);
+
+ /* Move up mask button */
+ MaskEditorUpButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorUpButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorUpButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorUpButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorUpButton,_("Move Up this Mask"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorUpButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Move_Up),NULL);
+
+ /* Move down mask button */
+ MaskEditorDownButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorDownButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorDownButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorDownButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorDownButton,_("Move Down this Mask"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorDownButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Move_Down),NULL);
+
+ /* Copy mask button */
+ MaskEditorCopyButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorCopyButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorCopyButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorCopyButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorCopyButton,_("Duplicate Mask"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorCopyButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Duplicate),NULL);
+
+ /* Add mask button */
+ MaskEditorAddButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorAddButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorAddButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorAddButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorAddButton,_("Add Default Masks"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorAddButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Add),NULL);
+
+ /* Remove mask button */
+ MaskEditorRemoveButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorRemoveButton),Icon);
+ gtk_box_pack_start(GTK_BOX(MaskEditorVBox),MaskEditorRemoveButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorRemoveButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorRemoveButton,_("Remove Mask"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorRemoveButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Remove),NULL);
+
+ /* Save mask button */
+ MaskEditorSaveButton = gtk_button_new();
+ Icon = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ gtk_container_add(GTK_CONTAINER(MaskEditorSaveButton),Icon);
+ gtk_box_pack_end(GTK_BOX(MaskEditorVBox),MaskEditorSaveButton,FALSE,FALSE,0);
+ gtk_button_set_relief(GTK_BUTTON(MaskEditorSaveButton),GTK_RELIEF_NONE);
+ gtk_tooltips_set_tip(Tips,MaskEditorSaveButton,_("Save Masks"),NULL);
+ g_signal_connect(G_OBJECT(MaskEditorSaveButton),"clicked",
+ G_CALLBACK(Mask_Editor_List_Save_Button),NULL);
+
+ gtk_widget_show(ScanVBox);
+ gtk_widget_show_all(HBox1);
+ gtk_widget_show_all(HBox2);
+ gtk_widget_show_all(HBox4);
+ gtk_widget_show(ScannerWindow);
+
+ /* Init position of the scanner window */
+ Scan_Set_Scanner_Window_Init_Position();
+
+ /* To initialize the mask status icon and visibility */
+ g_signal_emit_by_name(G_OBJECT(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)),"changed");
+ g_signal_emit_by_name(G_OBJECT(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)),"changed");
+ g_signal_emit_by_name(G_OBJECT(MaskEditorEntry),"changed");
+ g_signal_emit_by_name(G_OBJECT(LegendButton),"toggled"); /* To hide legend frame */
+ g_signal_emit_by_name(G_OBJECT(MaskEditorButton),"toggled"); /* To hide mask editor frame */
+ g_signal_emit_by_name(G_OBJECT(ProcessFieldsConvert),"toggled");/* To enable / disable entries */
+
+ // Activate the current menu in the option menu
+ gtk_combo_box_set_active(GTK_COMBO_BOX(ScannerOptionCombo), scanner_type);
+}
+
+gboolean ScannerWindow_Key_Press (GtkWidget *window, GdkEvent *event)
+{
+ GdkEventKey *kevent;
+
+ if (event && event->type == GDK_KEY_PRESS)
+ {
+ kevent = (GdkEventKey *)event;
+ switch(kevent->keyval)
+ {
+ case GDK_Escape:
+ ScannerWindow_Quit();
+ break;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Select the scanner to run for the current ETFile
+ */
+void Scan_Select_Mode_And_Run_Scanner (ET_File *ETFile)
+{
+ if (!ScannerWindow || !ETFile) return;
+
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_FILL_TAG)
+ {
+ /* Run Scanner Type: Scan Tag */
+ Scan_Tag_With_Mask(ETFile);
+ } else if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_RENAME_FILE)
+ {
+ /* Run Scanner Type: Rename File */
+ Scan_Rename_File_With_Mask(ETFile);
+ } else if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_PROCESS_FIELDS)
+ {
+ /* Run Scanner Type: Process Fields */
+ Scan_Process_Fields(ETFile);
+ }
+}
+
+void Scan_Use_Fill_Tag_Scanner (void)
+{
+ if (!ScannerWindow || gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) != SCANNER_FILL_TAG)
+ Open_ScannerWindow(SCANNER_FILL_TAG);
+ else
+ Action_Scan_Selected_Files();
+}
+
+
+void Scan_Use_Rename_File_Scanner (void)
+{
+ if (!ScannerWindow || gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) != SCANNER_RENAME_FILE)
+ Open_ScannerWindow(SCANNER_RENAME_FILE);
+ else
+ Action_Scan_Selected_Files();
+}
+
+void Scan_Use_Process_Fields_Scanner (void)
+{
+ if (!ScannerWindow || gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) != SCANNER_PROCESS_FIELDS)
+ Open_ScannerWindow(SCANNER_PROCESS_FIELDS);
+ else
+ Action_Scan_Selected_Files();
+}
+
+
+/* Callback from Open_ScannerWindow */
+void ScannerWindow_Quit (void)
+{
+ if (ScannerWindow)
+ {
+ if (SCAN_TAG_DEFAULT_MASK) g_free(SCAN_TAG_DEFAULT_MASK);
+ SCAN_TAG_DEFAULT_MASK = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(ScanTagMaskCombo)->child)));
+ Add_String_To_Combo_List(ScanTagListModel, SCAN_TAG_DEFAULT_MASK);
+ Save_Rename_File_Masks_List(ScanTagListModel, MASK_EDITOR_TEXT);
+
+ if (RENAME_FILE_DEFAULT_MASK) g_free(RENAME_FILE_DEFAULT_MASK);
+ RENAME_FILE_DEFAULT_MASK = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(RenameFileMaskCombo)->child)));
+ Add_String_To_Combo_List(RenameFileListModel, RENAME_FILE_DEFAULT_MASK);
+ Save_Rename_File_Masks_List(RenameFileListModel, MASK_EDITOR_TEXT);
+
+ ScannerWindow_Apply_Changes();
+
+ gtk_widget_destroy(ScannerWindow);
+ gtk_list_store_clear(ScanTagListModel);
+ gtk_list_store_clear(RenameFileListModel);
+ ScannerWindow = (GtkWidget *)NULL;
+ ScannerOptionCombo= (GtkWidget *)NULL;
+ SWScanButton = (GtkWidget *)NULL;
+
+ // To avoid crashs after tests
+ ScanTagMaskCombo = (GtkWidget *)NULL;
+ RenameFileMaskCombo = (GtkWidget *)NULL;
+ MaskEditorEntry = (GtkWidget *)NULL;
+ LegendFrame = (GtkWidget *)NULL;
+ ProcessFieldsConvertIntoSpace = (GtkWidget *)NULL;
+ ProcessFieldsConvertSpace = (GtkWidget *)NULL;
+ FillTagPreviewLabel = (GtkWidget *)NULL;
+ RenameFilePreviewLabel = (GtkWidget *)NULL;
+ }
+}
+
+
+/*
+ * For the configuration file...
+ */
+void ScannerWindow_Apply_Changes (void)
+{
+ if (ScannerWindow)
+ {
+ gint x, y;//, width, height;
+
+ if ( ScannerWindow->window!=NULL && gdk_window_is_visible(ScannerWindow->window)
+ && gdk_window_get_state(ScannerWindow->window)!=GDK_WINDOW_STATE_MAXIMIZED )
+ {
+ // Position and Origin of the scanner window
+ gdk_window_get_root_origin(ScannerWindow->window,&x,&y);
+ SCANNER_WINDOW_X = x;
+ SCANNER_WINDOW_Y = y;
+ //gdk_window_get_size(ScannerWindow->window,&width,&height);
+ //SCANNER_WINDOW_WIDTH = width;
+ //SCANNER_WINDOW_HEIGHT = height;
+ }
+
+ // The scanner selected
+ SCANNER_TYPE = gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo));
+
+ SCAN_MASK_EDITOR_BUTTON = GTK_TOGGLE_BUTTON(MaskEditorButton)->active;
+ SCAN_LEGEND_BUTTON = GTK_TOGGLE_BUTTON(LegendButton)->active;
+
+ /* Group: select entries to process */
+ PROCESS_FILENAME_FIELD = GTK_TOGGLE_BUTTON(ProcessFileNameField)->active;
+ PROCESS_TITLE_FIELD = GTK_TOGGLE_BUTTON(ProcessTitleField)->active;
+ PROCESS_ARTIST_FIELD = GTK_TOGGLE_BUTTON(ProcessArtistField)->active;
+ PROCESS_ALBUM_FIELD = GTK_TOGGLE_BUTTON(ProcessAlbumField)->active;
+ PROCESS_GENRE_FIELD = GTK_TOGGLE_BUTTON(ProcessGenreField)->active;
+ PROCESS_COMMENT_FIELD = GTK_TOGGLE_BUTTON(ProcessCommentField)->active;
+ PROCESS_COMPOSER_FIELD = GTK_TOGGLE_BUTTON(ProcessComposerField)->active;
+ PROCESS_ORIG_ARTIST_FIELD = GTK_TOGGLE_BUTTON(ProcessOrigArtistField)->active;
+ PROCESS_COPYRIGHT_FIELD = GTK_TOGGLE_BUTTON(ProcessCopyrightField)->active;
+ PROCESS_URL_FIELD = GTK_TOGGLE_BUTTON(ProcessURLField)->active;
+ PROCESS_ENCODED_BY_FIELD = GTK_TOGGLE_BUTTON(ProcessEncodedByField)->active;
+
+ /* Group: convert one character */
+ PF_CONVERT_INTO_SPACE = GTK_TOGGLE_BUTTON(ProcessFieldsConvertIntoSpace)->active;
+ PF_CONVERT_SPACE = GTK_TOGGLE_BUTTON(ProcessFieldsConvertSpace)->active;
+ PF_CONVERT = GTK_TOGGLE_BUTTON(ProcessFieldsConvert)->active;
+
+ /* Group: capitalize */
+ PF_CONVERT_ALL_UPPERCASE = GTK_TOGGLE_BUTTON(ProcessFieldsAllUppercase)->active;
+ PF_CONVERT_ALL_DOWNCASE = GTK_TOGGLE_BUTTON(ProcessFieldsAllDowncase)->active;
+ PF_CONVERT_FIRST_LETTER_UPPERCASE = GTK_TOGGLE_BUTTON(ProcessFieldsFirstLetterUppercase)->active;
+ PF_CONVERT_FIRST_LETTERS_UPPERCASE = GTK_TOGGLE_BUTTON(ProcessFieldsFirstLettersUppercase)->active;
+
+ /* Group: remove/insert space */
+ PF_REMOVE_SPACE = GTK_TOGGLE_BUTTON(ProcessFieldsConvertIntoSpace)->active;
+ PF_INSERT_SPACE = GTK_TOGGLE_BUTTON(ProcessFieldsConvertSpace)->active;
+ PF_ONLY_ONE_SPACE = GTK_TOGGLE_BUTTON(ProcessFieldsOnlyOneSpace)->active;
+ }
+}
+
+
+/* Callback from Option button */
+void Scan_Option_Button (void)
+{
+ Open_OptionsWindow();
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(OptionsNoteBook), OptionsNoteBook_Scanner_Page_Num);
+}
+
+
+
+/*
+ * Check if mask of the "Scan Tag" is valid. Return TRUE if valid, else FALSE.
+ */
+gboolean Scan_Check_Scan_Tag_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source)
+{
+ gchar *tmp = NULL;
+ gchar *mask = NULL;
+ gint loop = 0;
+
+
+ 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 )
+ {
+ if (loop==0)
+ /* There is no code the first time => not accepted */
+ goto Bad_Mask;
+ else
+ /* There is no more code => accepted */
+ goto Good_Mask;
+ }
+ if ( strlen(tmp)>1
+ && (tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='c' || tmp[1]=='d' || tmp[1]=='p' ||
+ tmp[1]=='r' || tmp[1]=='e' || tmp[1]=='g' || tmp[1]=='i' || tmp[1]=='l' ||
+ tmp[1]=='o' || tmp[1]=='n' || tmp[1]=='t' || tmp[1]=='u' || tmp[1]=='y' ) )
+ {
+ /* Code is correct */
+ *(mask+strlen(mask)-strlen(tmp)) = '\0';
+ }else
+ {
+ goto Bad_Mask;
+ }
+
+ /* Check the following code and separator */
+ if ( (tmp=strrchr(mask,'%'))==NULL )
+ /* There is no more code => accepted */
+ goto Good_Mask;
+
+ if ( strlen(tmp)>2
+ && (tmp[1]=='a' || tmp[1]=='b' || tmp[1]=='c' || tmp[1]=='d' || tmp[1]=='p' ||
+ tmp[1]=='r' || tmp[1]=='e' || tmp[1]=='g' || tmp[1]=='i' || tmp[1]=='l' ||
+ tmp[1]=='o' || tmp[1]=='n' || tmp[1]=='t' || tmp[1]=='u' || tmp[1]=='y' ) )
+ {
+ /* There is a separator and code is correct */
+ *(mask+strlen(mask)-strlen(tmp)) = '\0';
+ }else
+ {
+ goto Bad_Mask;
+ }
+ loop++;
+ }
+
+ 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;
+}
+/*
+ * Check if mask of the "Rename File" is valid. Return TRUE if valid, else FALSE.
+ */
+gboolean Scan_Check_Rename_File_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;
+
+ // Since version 1.99.4, it is available!
+ /*if ( strchr(mask,G_DIR_SEPARATOR)!=NULL ) // Renaming directory is not yet available
+ goto Bad_Mask;*/
+ // Not a valid path....
+ if ( strstr(mask,"//") != NULL
+ || strstr(mask,"./") != NULL
+ || strstr(mask,"../") != NULL)
+ 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]=='a' || tmp[1]=='b' || tmp[1]=='c' || tmp[1]=='d' || tmp[1]=='p' ||
+ tmp[1]=='r' || tmp[1]=='e' || tmp[1]=='g' || tmp[1]=='i' || tmp[1]=='l' ||
+ tmp[1]=='o' || tmp[1]=='n' || tmp[1]=='t' || tmp[1]=='u' || tmp[1]=='y' ) )
+ {
+ /* 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;
+}
+
+
+/*
+ * Check if the selected mask in the Mask Editor is valid, else display the mask status icon.
+ */
+gboolean Scan_Check_Editor_Mask (GtkObject *widget_to_show_hide, GtkEntry *widget_source)
+{
+ /* Select and get result of check scanner */
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_FILL_TAG)
+ {
+ return Scan_Check_Scan_Tag_Mask(widget_to_show_hide,widget_source);
+ } else if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_RENAME_FILE)
+ {
+ return Scan_Check_Rename_File_Mask(widget_to_show_hide,widget_source);
+ } else
+ return FALSE;
+}
+
+
+void Scan_Toggle_Legend_Button (void)
+{
+ if (!LegendButton || !LegendFrame) return;
+
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(LegendButton)) )
+ gtk_widget_show_all(LegendFrame);
+ else
+ gtk_widget_hide(LegendFrame);
+}
+
+
+void Scan_Toggle_Mask_Editor_Button (void)
+{
+ GtkTreeModel *treemodel;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+
+ if (!MaskEditorButton || !MaskEditorFrame || !MaskEditorList) return;
+
+ if ( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(MaskEditorButton)) )
+ {
+ gtk_widget_show_all(MaskEditorFrame);
+
+ // Select first row in list
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+ if (gtk_tree_model_get_iter_first(treemodel, &iter))
+ {
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ gtk_tree_selection_unselect_all(selection);
+ gtk_tree_selection_select_iter(selection, &iter);
+ }
+
+ // Update status of the icon box cause prev instruction show it for all cases
+ g_signal_emit_by_name(GTK_OBJECT(MaskEditorEntry),"changed");
+ }else
+ {
+ gtk_widget_hide_all(MaskEditorFrame);
+ }
+}
+
+
+
+/*
+ * Manage/Toggle check buttons into 'Process Fields' frame
+ */
+void Process_Fields_Check_Button_Toggled (GtkObject *object, GList *list)
+{
+ gint i = 0;
+
+ if ( GTK_TOGGLE_BUTTON(object)->active )
+ {
+ while (list)
+ {
+ if ( list->data!=NULL && GTK_OBJECT(list->data)!=object )
+ gtk_toggle_button_set_active((GtkToggleButton *)list->data,FALSE);
+ i++;
+ if (!list->next) break;
+ list = list->next;
+ }
+ }
+}
+
+
+void Process_Fields_Convert_Check_Button_Toggled (GtkObject *object)
+{
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertTo),GTK_TOGGLE_BUTTON(object)->active);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertFrom),GTK_TOGGLE_BUTTON(object)->active);
+}
+
+
+/*
+ * Small buttons of Process Fields scanner
+ */
+void Select_Fields_Invert_Selection (void)
+{
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFileNameField),
+ !GTK_TOGGLE_BUTTON(ProcessFileNameField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessTitleField),
+ !GTK_TOGGLE_BUTTON(ProcessTitleField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessArtistField),
+ !GTK_TOGGLE_BUTTON(ProcessArtistField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessAlbumField),
+ !GTK_TOGGLE_BUTTON(ProcessAlbumField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessGenreField),
+ !GTK_TOGGLE_BUTTON(ProcessGenreField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCommentField),
+ !GTK_TOGGLE_BUTTON(ProcessCommentField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessComposerField),
+ !GTK_TOGGLE_BUTTON(ProcessComposerField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessOrigArtistField),
+ !GTK_TOGGLE_BUTTON(ProcessOrigArtistField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCopyrightField),
+ !GTK_TOGGLE_BUTTON(ProcessCopyrightField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessURLField),
+ !GTK_TOGGLE_BUTTON(ProcessURLField)->active);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessEncodedByField),
+ !GTK_TOGGLE_BUTTON(ProcessEncodedByField)->active);
+}
+void Select_Fields_Select_Unselect_All (void)
+{
+ static gboolean state = 1;
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessFileNameField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessTitleField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessArtistField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessAlbumField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessGenreField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCommentField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessComposerField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessOrigArtistField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessCopyrightField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessURLField), state);
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ProcessEncodedByField), state);
+ state = !state;
+}
+
+/*
+ * Set sensitive state of the processing check boxes : if no one is selected => all disabled
+ */
+void Select_Fields_Set_Sensitive (void)
+{
+ if (GTK_TOGGLE_BUTTON(ProcessFileNameField)->active
+ || GTK_TOGGLE_BUTTON(ProcessTitleField)->active
+ || GTK_TOGGLE_BUTTON(ProcessArtistField)->active
+ || GTK_TOGGLE_BUTTON(ProcessAlbumField)->active
+ || GTK_TOGGLE_BUTTON(ProcessGenreField)->active
+ || GTK_TOGGLE_BUTTON(ProcessCommentField)->active
+ || GTK_TOGGLE_BUTTON(ProcessComposerField)->active
+ || GTK_TOGGLE_BUTTON(ProcessOrigArtistField)->active
+ || GTK_TOGGLE_BUTTON(ProcessCopyrightField)->active
+ || GTK_TOGGLE_BUTTON(ProcessURLField)->active
+ || GTK_TOGGLE_BUTTON(ProcessEncodedByField)->active)
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertIntoSpace), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertSpace), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvert), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertLabelTo), TRUE);
+ // Activate the two entries only if the check box is actived, esle keep them disabled
+ if (GTK_TOGGLE_BUTTON(ProcessFieldsConvert)->active)
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertTo), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertFrom), TRUE);
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsAllUppercase), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsAllDowncase), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsFirstLetterUppercase), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsFirstLettersUppercase),TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsRemoveSpace), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsInsertSpace), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsOnlyOneSpace), TRUE);
+ }else
+ {
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertIntoSpace), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertSpace), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvert), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertTo), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertLabelTo), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsConvertFrom), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsAllUppercase), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsAllDowncase), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsFirstLetterUppercase), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsFirstLettersUppercase),FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsRemoveSpace), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsInsertSpace), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(ProcessFieldsOnlyOneSpace), FALSE);
+ }
+}
+
+/*
+ * Callbacks from Mask Editor buttons
+ */
+
+/*
+ * Callback from the mask edit list
+ * Previously known as Mask_Editor_List_Select_Row
+ */
+void Mask_Editor_List_Row_Selected (GtkTreeSelection* selection, gpointer data)
+{
+ GList *selectedRows;
+ gchar *text = NULL;
+ GtkTreePath *lastSelected;
+ GtkTreeIter lastFile;
+ GtkTreeModel *treemodel;
+ gboolean valid;
+
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ /* We must block the function, else the previous selected row will be modified */
+ g_signal_handlers_block_by_func(G_OBJECT(MaskEditorEntry),
+ G_CALLBACK(Mask_Editor_Entry_Changed),NULL);
+
+ selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+ /*
+ * At some point, we might get called when no rows are selected?
+ */
+ if (g_list_length(selectedRows) == 0)
+ {
+ g_list_foreach(selectedRows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ g_signal_handlers_unblock_by_func(G_OBJECT(MaskEditorEntry),
+ G_CALLBACK(Mask_Editor_Entry_Changed),NULL);
+ return;
+ }
+
+ /* Get the text of the last selected row */
+ lastSelected = (GtkTreePath *)g_list_last(selectedRows)->data;
+
+ valid= gtk_tree_model_get_iter(treemodel, &lastFile, lastSelected);
+ if (valid)
+ {
+ gtk_tree_model_get(treemodel, &lastFile, MASK_EDITOR_TEXT, &text, -1);
+
+ if (text)
+ {
+ gtk_entry_set_text(GTK_ENTRY(MaskEditorEntry),text);
+ g_free(text);
+ }
+ }
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(MaskEditorEntry),
+ G_CALLBACK(Mask_Editor_Entry_Changed),NULL);
+}
+
+
+/*
+ * Add a new mask to the list
+ */
+void Mask_Editor_List_New (void)
+{
+ gchar *text = _("New_mask");
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ GtkTreeModel *treemodel;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ gtk_list_store_insert(GTK_LIST_STORE(treemodel), &iter, 0);
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &iter, MASK_EDITOR_TEXT, text, -1);
+
+ gtk_tree_selection_unselect_all(selection);
+ gtk_tree_selection_select_iter(selection, &iter);
+}
+
+/*
+ * Duplicate a mask on the list
+ */
+void Mask_Editor_List_Duplicate (void)
+{
+ gchar *text = NULL;
+ GList *selectedRows;
+ GList *toInsert = NULL;
+ GtkTreeSelection *selection;
+ GtkTreeIter row;
+ GtkTreeModel *treemodel;
+ gboolean valid;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ if (g_list_length(selectedRows) == 0)
+ {
+ Log_Print(_("Copy: No row selected!"));
+ g_list_foreach(selectedRows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ return;
+ }
+
+ /* Loop through selected rows, duplicating them into a GList */
+ /* We cannot directly insert because the paths in selectedRows get out of date after an insertion */
+ while(selectedRows)
+ {
+ valid = gtk_tree_model_get_iter(treemodel, &row, (GtkTreePath*) selectedRows->data);
+ if (valid)
+ {
+ gtk_tree_model_get(treemodel, &row, MASK_EDITOR_TEXT, &text, -1);
+ toInsert = g_list_append(toInsert, text);
+ }
+
+ selectedRows = selectedRows->next;
+ if (!selectedRows) break;
+ }
+
+ /* Duplicate the relevant entries, by looping through the list backwards (to preserve original order) */
+ toInsert = g_list_last(toInsert);
+ while(toInsert)
+ {
+ gtk_list_store_insert(GTK_LIST_STORE(treemodel), &row, 0);
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &row, MASK_EDITOR_TEXT, (gchar*) toInsert->data, -1);
+ g_free(toInsert->data);
+
+ toInsert = toInsert->prev;
+ if (!toInsert) break;
+ }
+
+ /* Free data no longer needed */
+ selectedRows = g_list_first(selectedRows);
+ toInsert = g_list_first(toInsert);
+ g_list_foreach(selectedRows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ g_list_foreach(toInsert, (GFunc) g_free, NULL);
+ g_list_free(toInsert);
+}
+
+void Mask_Editor_List_Add(void)
+{
+ gint i = 0;
+ GtkTreeIter iter;
+ GtkTreeModel *treemodel;
+ gchar *temp;
+
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_FILL_TAG)
+ {
+ while(Scan_Masks[i])
+ {
+ if (!g_utf8_validate(Scan_Masks[i], -1, NULL))
+ temp = convert_to_utf8(Scan_Masks[i]);
+ else
+ temp = g_strdup(Scan_Masks[i]);
+
+ gtk_list_store_append(GTK_LIST_STORE(treemodel), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &iter,
+ MASK_EDITOR_TEXT, temp, -1);
+ g_free(temp);
+ i++;
+ }
+ } else if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_RENAME_FILE)
+ {
+ while(Rename_File_Masks[i])
+ {
+ if (!g_utf8_validate(Rename_File_Masks[i], -1, NULL))
+ temp = convert_to_utf8(Rename_File_Masks[i]);
+ else
+ temp = g_strdup(Scan_Masks[i]);
+
+ gtk_list_store_append(GTK_LIST_STORE(treemodel), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &iter,
+ MASK_EDITOR_TEXT, temp, -1);
+ g_free(temp);
+ i++;
+ }
+ }
+}
+
+/*
+ * Remove the selected rows from the mask editor list
+ */
+void Mask_Editor_List_Remove (void)
+{
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreeModel *treemodel;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ if (gtk_tree_selection_count_selected_rows(selection) == 0) {
+ Log_Print(_("Remove: No row selected!"));
+ return;
+ }
+
+ if (!gtk_tree_model_get_iter_first(treemodel, &iter))
+ return;
+
+ while (TRUE)
+ {
+ if (gtk_tree_selection_iter_is_selected(selection, &iter))
+ {
+ if (!gtk_list_store_remove(GTK_LIST_STORE(treemodel), &iter))
+ {
+ break;
+ }
+ } else
+ {
+ if (!gtk_tree_model_iter_next(treemodel, &iter))
+ {
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Move all selected rows up one place in the mask list
+ */
+void Mask_Editor_List_Move_Up (void)
+{
+ GtkTreeSelection *selection;
+ GList *selectedRows;
+ GList *selectedRowsCopy;
+ GtkTreeIter currentFile;
+ GtkTreeIter nextFile;
+ GtkTreePath *currentPath;
+ GtkTreeModel *treemodel;
+ gboolean valid;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+ selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+ if (g_list_length(selectedRows) == 0)
+ {
+ Log_Print(_("Move Up: No row selected!"));
+ g_list_foreach(selectedRows, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ return;
+ }
+
+ selectedRowsCopy = selectedRows;
+
+ while(selectedRows)
+ {
+ currentPath = (GtkTreePath*) selectedRows->data;
+ valid = gtk_tree_model_get_iter(treemodel, &currentFile, currentPath);
+ if (valid)
+ {
+ /* Find the entry above the node... */
+ if (gtk_tree_path_prev(currentPath)) {
+ /* ...and if it exists, swap the two rows by iter */
+ gtk_tree_model_get_iter(treemodel, &nextFile, currentPath);
+ gtk_list_store_swap(GTK_LIST_STORE(treemodel), &currentFile, &nextFile);
+ }
+ }
+
+ selectedRows = selectedRows->next;
+ if (!selectedRows) break;
+ }
+
+ g_list_foreach(selectedRowsCopy, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selectedRowsCopy);
+}
+
+/*
+ * Move all selected rows down one place in the mask list
+ */
+void Mask_Editor_List_Move_Down (void)
+{
+ GtkTreeSelection *selection;
+ GList *selectedRows;
+ GList *selectedRowsCopy;
+ GtkTreeIter currentFile;
+ GtkTreeIter nextFile;
+ GtkTreePath *currentPath;
+ GtkTreeModel *treemodel;
+ gboolean valid;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+ selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+ if (g_list_length(selectedRows) == 0) {
+ Log_Print(_("Move Down: No row selected!"));
+ g_list_foreach(selectedRows, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ return;
+ }
+
+ selectedRowsCopy = selectedRows;
+
+ while (selectedRows)
+ {
+ currentPath = (GtkTreePath*) selectedRows->data;
+ valid = gtk_tree_model_get_iter(treemodel, &currentFile, currentPath);
+ if (valid)
+ {
+ /* Find the entry below the node and swap the two nodes by iter */
+ gtk_tree_path_next(currentPath);
+ gtk_tree_model_get_iter(treemodel, &nextFile, currentPath);
+ gtk_list_store_swap(GTK_LIST_STORE(treemodel), &currentFile, &nextFile);
+ }
+
+ if (!selectedRows->next) break;
+ selectedRows = selectedRows->next;
+ }
+
+ g_list_foreach(selectedRowsCopy, (GFunc)gtk_tree_path_free, NULL);
+ g_list_free(selectedRowsCopy);
+}
+
+/*
+ * Save the currently displayed mask list in the mask editor
+ */
+void Mask_Editor_List_Save_Button (void)
+{
+ Mask_Editor_Clean_Up_Masks_List();
+
+ if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_FILL_TAG)
+ {
+ Save_Scan_Tag_Masks_List(ScanTagListModel, MASK_EDITOR_TEXT);
+ } else if (gtk_combo_box_get_active(GTK_COMBO_BOX(ScannerOptionCombo)) == SCANNER_RENAME_FILE)
+ {
+ Save_Rename_File_Masks_List(RenameFileListModel, MASK_EDITOR_TEXT);
+ }
+}
+
+/*
+ * Clean up the currently displayed masks lists, ready for saving
+ */
+void Mask_Editor_Clean_Up_Masks_List (void)
+{
+ gchar *text = NULL;
+ gchar *text1 = NULL;
+ GtkTreeIter currentIter;
+ GtkTreeIter itercopy;
+ GtkTreeModel *treemodel;
+
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+
+ /* Remove blank and duplicate items */
+ if (gtk_tree_model_get_iter_first(treemodel, &currentIter))
+ {
+
+ while(TRUE)
+ {
+ gtk_tree_model_get(treemodel, &currentIter, MASK_EDITOR_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(treemodel), &currentIter))
+ break; /* No following entries */
+ else
+ continue; /* Go on to next entry, which the remove function already moved onto for us */
+ }
+
+ /* Check for duplicate entries */
+ itercopy = currentIter;
+ if (!gtk_tree_model_iter_next(treemodel, &itercopy))
+ {
+ g_free(text);
+ break;
+ }
+
+ while(TRUE)
+ {
+ gtk_tree_model_get(treemodel, &itercopy, MASK_EDITOR_TEXT, &text1, -1);
+ if (text1 && g_utf8_collate(text,text1) == 0)
+ {
+ g_free(text1);
+
+ if (!gtk_list_store_remove(GTK_LIST_STORE(treemodel), &itercopy))
+ break; /* No following entries */
+ else
+ continue; /* Go on to next entry, which the remove function already set iter to for us */
+
+ }
+ g_free(text1);
+ if (!gtk_tree_model_iter_next(treemodel, &itercopy))
+ break;
+ }
+
+ g_free(text);
+
+ if (!gtk_tree_model_iter_next(treemodel, &currentIter))
+ break;
+ }
+ }
+}
+
+/*
+ * Update the Mask List with the new value of the entry box
+ */
+void Mask_Editor_Entry_Changed (void)
+{
+ GtkTreeSelection *selection;
+ GtkTreePath *firstSelected;
+ GtkTreeModel *treemodel;
+ GList *selectedRows;
+ GtkTreeIter row;
+ const gchar* text;
+ gboolean valid;
+
+ if (!MaskEditorList) return;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(MaskEditorList));
+ treemodel = gtk_tree_view_get_model(GTK_TREE_VIEW(MaskEditorList));
+ selectedRows = gtk_tree_selection_get_selected_rows(selection, NULL);
+
+ if (g_list_length(selectedRows) == 0)
+ {
+ g_list_foreach(selectedRows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+ return;
+ }
+
+ firstSelected = (GtkTreePath *)g_list_first(selectedRows)->data;
+ text = gtk_entry_get_text(GTK_ENTRY(MaskEditorEntry));
+
+ valid = gtk_tree_model_get_iter(treemodel, &row, firstSelected);
+ if (valid)
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &row, MASK_EDITOR_TEXT, text, -1);
+
+ g_list_foreach(selectedRows, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free(selectedRows);
+}
+
+/*
+ * Actions when the a key is pressed into the masks editor clist
+ */
+gboolean Mask_Editor_List_Key_Press (GtkWidget *widget, GdkEvent *event)
+{
+ if (event && event->type == GDK_KEY_PRESS) {
+ GdkEventKey *kevent = (GdkEventKey *)event;
+
+ switch(kevent->keyval) {
+ case GDK_Delete:
+ Mask_Editor_List_Remove();
+ break;
+/* case GDK_Up:
+ Mask_Editor_Clist_Move_Up();
+ break;
+ case GDK_Down:
+ Mask_Editor_Clist_Move_Down();
+ break;
+*/ }
+ }
+ return TRUE;
+}
+
+/*
+ * Function when you select an item of the option menu
+ */
+void Scanner_Option_Menu_Activate_Item (GtkWidget *combo, gpointer data)
+{
+ switch (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)))
+ {
+ case SCANNER_FILL_TAG:
+ gtk_widget_show(MaskEditorButton);
+ gtk_widget_show(LegendButton);
+ gtk_widget_show(ScanTagFrame);
+ gtk_widget_hide(RenameFileFrame);
+ gtk_widget_hide(ProcessFieldsFrame);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(MaskEditorList), GTK_TREE_MODEL(ScanTagListModel));
+ Scan_Fill_Tag_Generate_Preview();
+ g_signal_emit_by_name(G_OBJECT(LegendButton),"toggled"); /* To hide or show legend frame */
+ g_signal_emit_by_name(G_OBJECT(MaskEditorButton),"toggled"); /* To hide or show mask editor frame */
+ break;
+
+ case SCANNER_RENAME_FILE:
+ gtk_widget_show(MaskEditorButton);
+ gtk_widget_show(LegendButton);
+ gtk_widget_hide(ScanTagFrame);
+ gtk_widget_show(RenameFileFrame);
+ gtk_widget_hide(ProcessFieldsFrame);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(MaskEditorList), GTK_TREE_MODEL(RenameFileListModel));
+ Scan_Rename_File_Generate_Preview();
+ g_signal_emit_by_name(G_OBJECT(LegendButton),"toggled"); /* To hide or show legend frame */
+ g_signal_emit_by_name(G_OBJECT(MaskEditorButton),"toggled"); /* To hide or show mask editor frame */
+ break;
+
+ case SCANNER_PROCESS_FIELDS:
+ gtk_widget_hide(MaskEditorButton);
+ gtk_widget_hide(LegendButton);
+ gtk_widget_hide(ScanTagFrame);
+ gtk_widget_hide(RenameFileFrame);
+ gtk_widget_show_all(ProcessFieldsFrame);
+ // Hide directly the frames to don't change state of the buttons!
+ gtk_widget_hide(LegendFrame);
+ gtk_widget_hide(MaskEditorFrame);
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(MaskEditorList), NULL);
+ break;
+ }
+}
+
+/*
+ * Init the position of the scanner window
+ */
+void Scan_Set_Scanner_Window_Init_Position (void)
+{
+ if (ScannerWindow && SET_SCANNER_WINDOW_POSITION)
+ {
+ gtk_widget_realize(ScannerWindow);
+ gdk_window_move(ScannerWindow->window,SCANNER_WINDOW_X,SCANNER_WINDOW_Y);
+ }
+}