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