1 #include <config.h>
2 #include <stdlib.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <glib.h>
6 #include <glib/gi18n.h>
7 #include <gtk/gtk.h>
8 #include <glade/glade.h>
9
10 #include "str_util.h"
11 #include "str_convert.h"
12 #include "file_util.h"
13 #include "file_list.h"
14 #include "prefs.h"
15 #include "progress_dlg.h"
16 #include "cursor.h"
17 #include "audio_file.h"
18 #ifdef ENABLE_MP3
19 # include "mpeg_file.h"
20 #endif
21
22 #include "clear_tab.h"
23
24
25 enum {
26 APPLY_TO_ALL = 0,
27 APPLY_TO_SELECTED = 1
28 };
29
30
31 /* widgets */
32 static GtkButton *b_clear_go = NULL;
33 static GtkComboBox *combo_clear_apply = NULL;
34 static GtkToggleButton *rb_clear_all = NULL;
35 static GtkToggleButton *rb_clear_id3v1 = NULL;
36 static GtkToggleButton *rb_clear_id3v2 = NULL;
37
38 /* preferences */
39 static long* clear_option;
40
41
42 /*** private functions ******************************************************/
43
44 /* sets the interface state according to the preferences */
from_prefs()45 static void from_prefs()
46 {
47 switch (*clear_option) {
48 case 0: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb_clear_all), TRUE);
49 break;
50 case 1: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb_clear_id3v1), TRUE);
51 break;
52 case 2: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rb_clear_id3v2), TRUE);
53 break;
54 }
55 }
56
57 /* sets the preferences according to the curent interface state */
to_prefs()58 static void to_prefs()
59 {
60 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rb_clear_all)))
61 *clear_option = 0;
62 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rb_clear_id3v1)))
63 *clear_option = 1;
64 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rb_clear_id3v2)))
65 *clear_option = 2;
66 }
67
68
clear_tag(audio_file * af)69 static gboolean clear_tag(audio_file *af)
70 {
71 #ifdef ENABLE_MP3
72
73 if (gtk_toggle_button_get_active(rb_clear_all)) {
74 audio_file_remove_tag(af);
75 return TRUE;
76 }
77 else if (af->type == AF_MPEG) {
78 int version;
79 if (gtk_toggle_button_get_active(rb_clear_id3v1))
80 version = ID3TT_ID3V1;
81 else
82 version = ID3TT_ID3V2;
83 mpeg_file_remove_tag_v((mpeg_file*)af, version);
84 return TRUE;
85 }
86 else {
87 return FALSE;
88 }
89
90 #else
91
92 audio_file_remove_tag(af);
93 return TRUE;
94
95 #endif
96 }
97
98
clear_tags(GEList * file_list)99 static void clear_tags(GEList *file_list)
100 {
101 GList *iter;
102 audio_file *af;
103 gchar *last_path = "";
104 gchar *curr_path;
105 gchar *name_utf8;
106 int count_total, count_tagged;
107 int save_errno, res;
108 gboolean cleared;
109
110 pd_start(_("Clearing Tags"));
111 pd_printf(PD_ICON_INFO, _("Starting in directory \"%s\""), fl_get_working_dir_utf8());
112
113 count_total = 0;
114 count_tagged = 0;
115 for (iter = g_elist_first(file_list); iter; iter = g_list_next(iter)) {
116 /* flush pending gtk operations so the UI doesn't freeze */
117 pd_scroll_to_bottom();
118 while (gtk_events_pending()) gtk_main_iteration();
119 if (pd_stop_requested()) {
120 pd_printf(PD_ICON_WARN, _("Operation stopped at user's request"));
121 break;
122 }
123
124 count_total++;
125
126 curr_path = (gchar *)iter->data;
127
128 if (!fu_compare_file_paths(last_path, curr_path)) {
129 gchar *p;
130 gchar *utf8 = str_filename_to_utf8(curr_path, _("(UTF8 conversion error)"));
131 p = g_utf8_strrchr(utf8, -1, '/');
132
133 pd_printf(PD_ICON_INFO, _("Entering directory \"%.*s\""), (gint)(p-utf8), utf8);
134 free(utf8);
135 }
136 last_path = curr_path;
137
138 name_utf8 = str_filename_to_utf8(g_basename(curr_path), _("(UTF8 conversion error)"));
139
140 res = audio_file_new(&af, curr_path, TRUE);
141 if (res != AF_OK) {
142 pd_printf(PD_ICON_FAIL, _("Error in file \"%s\""), name_utf8);
143 if (res == AF_ERR_FILE)
144 pd_printf(PD_ICON_NONE, _("Couldn't open file for writing"));
145 else if (res == AF_ERR_FORMAT)
146 pd_printf(PD_ICON_NONE, _("Audio format not recognized"));
147 else
148 pd_printf(PD_ICON_NONE, _("Unknown error (%d)"), res);
149
150 goto _continue;
151 }
152
153 cleared = clear_tag(af);
154 if (!cleared) {
155 pd_printf(PD_ICON_WARN, _("Skipped \"%s\""), name_utf8);
156 goto _continue;
157 }
158
159 res = audio_file_write_changes(af);
160 if (res != AF_OK) {
161 save_errno = errno;
162 pd_printf(PD_ICON_FAIL, _("Error in file \"%s\""), name_utf8);
163 pd_printf(PD_ICON_NONE, "%s (%d)", strerror(save_errno), save_errno);
164
165 goto _continue;
166 }
167
168 pd_printf(PD_ICON_OK, _("Cleared tag from \"%s\""), name_utf8);
169 count_tagged++;
170
171 _continue:
172 if (af) {
173 audio_file_delete(af);
174 af = NULL;
175 }
176 free(name_utf8);
177 name_utf8 = NULL;
178 }
179
180 pd_printf(PD_ICON_INFO, _("Done (Cleared %d of %d files)"), count_tagged, count_total);
181 pd_end();
182 }
183
184
185 /* orchestrates the call to clear_tags() */
start_operation()186 static void start_operation()
187 {
188 GEList *file_list;
189
190 /*
191 int button;
192 button = message_box(w_main, "Remove all tags",
193 "This will remove tags from all selected files. Proceed?", 0,
194 GTK_STOCK_CANCEL, GTK_STOCK_YES, NULL);
195 if (button == 0)
196 return;
197 */
198
199 if (gtk_combo_box_get_active(combo_clear_apply) == APPLY_TO_ALL)
200 file_list = fl_get_all_files();
201 else
202 file_list = fl_get_selected_files();
203
204 if (g_elist_length(file_list) == 0) {
205 pd_start(_("Clearing Tags"));
206 pd_printf(PD_ICON_FAIL, _("No files selected"));
207 pd_end();
208
209 g_elist_free(file_list);
210 return;
211 }
212
213 to_prefs();
214
215 cursor_set_wait();
216 gtk_widget_set_sensitive(GTK_WIDGET(b_clear_go), FALSE);
217 clear_tags(file_list);
218 gtk_widget_set_sensitive(GTK_WIDGET(b_clear_go), TRUE);
219 cursor_set_normal();
220
221 g_elist_free(file_list);
222 }
223
224
225 /*** UI callbacks ***********************************************************/
226
cb_clear_go(GtkButton * button,gpointer user_data)227 void cb_clear_go(GtkButton *button, gpointer user_data)
228 {
229 start_operation();
230 }
231
cb_file_selection_changed(GtkTreeSelection * selection,gpointer data)232 static void cb_file_selection_changed(GtkTreeSelection *selection, gpointer data)
233 {
234 if (fl_count_selected() > 0)
235 gtk_combo_box_set_active(combo_clear_apply, APPLY_TO_SELECTED);
236 else
237 gtk_combo_box_set_active(combo_clear_apply, APPLY_TO_ALL);
238 }
239
240
241 /*** public functions *******************************************************/
242
ct_init(GladeXML * xml)243 void ct_init(GladeXML *xml)
244 {
245 GtkStyle *style;
246 GtkWidget *w;
247
248 /*
249 * get the widgets from glade
250 */
251
252 b_clear_go = GTK_BUTTON(glade_xml_get_widget(xml, "b_clear_go"));
253 combo_clear_apply = GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_clear_apply"));
254
255 rb_clear_all = GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "rb_clear_all"));
256 rb_clear_id3v1 = GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "rb_clear_id3v1"));
257 rb_clear_id3v2 = GTK_TOGGLE_BUTTON(glade_xml_get_widget(xml, "rb_clear_id3v2"));
258
259 /* initialize some widgets' state */
260 gtk_combo_box_set_active(combo_clear_apply, APPLY_TO_ALL);
261
262 /* connect signals */
263 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(glade_xml_get_widget(xml, "tv_files"))),
264 "changed", G_CALLBACK(cb_file_selection_changed), NULL);
265
266 #ifndef ENABLE_MP3
267 gtk_widget_hide(glade_xml_get_widget(xml, "tab_clear_options"));
268 #endif
269
270
271 /*
272 * set the title colors
273 */
274
275 w = glade_xml_get_widget(xml, "lab_clear_title");
276 gtk_widget_ensure_style(w);
277 style = gtk_widget_get_style(w);
278
279 gtk_widget_modify_fg(w, GTK_STATE_NORMAL, &style->text[GTK_STATE_SELECTED]);
280
281 w = glade_xml_get_widget(xml, "box_clear_title");
282 gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &style->base[GTK_STATE_SELECTED]);
283
284
285 /*
286 * get the preference values, or set them to defaults
287 */
288
289 /* clear_option */
290 clear_option = pref_get_ref("ct:clear_option");
291 if (clear_option == NULL) {
292 long def = 0;
293 clear_option = pref_set("ct:clear_option", PREF_INT, &def);
294 }
295
296 from_prefs();
297 }
298
299