1 #include <config.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <errno.h> 5 #include <string.h> 6 #include <glib.h> 7 #include <glib/gi18n.h> 8 #include <gtk/gtk.h> 9 #include <glade/glade.h> 10 #ifdef HAVE_GNU_REGEX_H 11 # include <gnu/regex.h> /* for recent FreeBSD */ 12 #elif HAVE_GNUREGEX_H 13 # include <gnuregex.h> /* for older FreeBSD */ 14 #else 15 # include <regex.h> /* for everyone else */ 16 #endif use_structs()17 18 #include "elist.h" 19 #include "file_util.h" 20 #include "str_util.h" 21 #include "str_convert.h" 22 #include "mru.h" 23 #include "prefs.h" 24 #include "audio_file.h" 25 #include "genre.h" 26 #include "file_list.h" 27 #include "char_conv_dlg.h" 28 #include "message_box.h" 29 #include "progress_dlg.h" 30 #include "cursor.h" 31 #include "help.h" 32 #include "tag_tab.h" 33 34 35 enum { 36 APPLY_TO_ALL = 0, 37 APPLY_TO_SELECTED = 1 38 }; 39 40 41 /* for parsing file names */ 42 typedef struct { 43 /* regexp to match against the file name */ 44 regex_t re; 45 /* indexes of substring matches */ 46 gint title; 47 gint artist; 48 gint album; 49 gint year; 50 gint comment; 51 gint track; 52 gint genre; 53 } parse_info; 54 55 56 /* widgets */ 57 static GtkCombo *combo_tag_format = NULL; 58 static GtkEntry *ent_tag_format = NULL; 59 static GtkButton *b_tag_edit_format = NULL; 60 static GtkCheckButton *cb_use_filename = NULL; 61 static GtkButton *b_tag_go = NULL; 62 static GtkComboBox *combo_tag_apply = NULL; 63 static GtkCheckButton *cb_title = NULL; 64 static GtkCheckButton *cb_artist = NULL; 65 static GtkCheckButton *cb_album = NULL; 66 static GtkCheckButton *cb_year = NULL; 67 static GtkCheckButton *cb_comment = NULL; 68 static GtkCheckButton *cb_track = NULL; 69 static GtkCheckButton *cb_genre = NULL; 70 static GtkEntry *ent_title = NULL; 71 static GtkEntry *ent_artist = NULL; 72 static GtkEntry *ent_album = NULL; 73 static GtkEntry *ent_year = NULL; 74 static GtkEntry *ent_comment = NULL; 75 static GtkEntry *ent_track = NULL; 76 static GtkCheckButton *cb_track_auto = NULL; 77 static GtkCombo *combo_genre = NULL; 78 static GtkEntry *ent_genre = NULL; 79 static GtkWindow *w_main = NULL; 80 81 /* private data */ 82 static gboolean ignore_field_changed = FALSE; 83 static gboolean from_fn_title = FALSE; 84 static gboolean from_fn_artist = FALSE; 85 static gboolean from_fn_album = FALSE; 86 static gboolean from_fn_year = FALSE; 87 static gboolean from_fn_comment = FALSE; 88 static gboolean from_fn_track = FALSE; 89 static gboolean from_fn_genre = FALSE; 90 91 /* preferences */ 92 static gboolean *use_filename; 93 static MRUList *format_mru; 94 95 96 /*** private functions ******************************************************/ 97 98 static parse_info *build_parse_info(const gchar *format) 99 { 100 parse_info *info = calloc(1, sizeof(parse_info)); 101 gchar *aux_str = calloc(1, 2 + 2*strlen(format)); 102 gchar *expr_str = calloc(1, 2 + 2*strlen(format)); 103 gint i, j, span, pos; 104 gchar *p; 105 gint res; 106 107 108 /* printf("format: %s\n", format); */ 109 110 /* constrain the expression to match the whole string and escape 111 characters that have special meaning in regexps */ 112 i = 0; 113 j = 0; 114 aux_str[j++] = '^'; 115 while (format[i]) { 116 if (strchr(".*+?[]{}()|^$\\", format[i])) 117 aux_str[j++] = '\\'; 118 aux_str[j++] = format[i++]; 119 } 120 aux_str[j++] = '$'; 121 aux_str[j++] = 0; 122 123 /* find the markers, record their relative positions and replace 124 them in the final expression */ 125 i = 0; 126 j = 0; 127 pos = 1; 128 while (TRUE) { 129 p = index(&aux_str[i], '<'); 130 if (p != NULL) { 131 span = (gint)(p - &aux_str[i]); 132 if (span > 0) { 133 strncpy(&expr_str[j], &aux_str[i], span); 134 i += span; 135 j += span; 136 } else if (strncmp(&aux_str[i], "<title>", 7) == 0) { 137 strncpy(&expr_str[j], "(.*)", 4); 138 info->title = pos++; 139 i += 7; 140 j += 4; 141 } else if (strncmp(&aux_str[i], "<artist>", 8) == 0) { 142 strncpy(&expr_str[j], "(.*)", 4); 143 info->artist = pos++; 144 i += 8; 145 j += 4; 146 } else if (strncmp(&aux_str[i], "<album>", 7) == 0) { 147 strncpy(&expr_str[j], "(.*)", 4); 148 info->album = pos++; 149 i += 7; 150 j += 4; 151 } else if (strncmp(&aux_str[i], "<year>", 6) == 0) { 152 strncpy(&expr_str[j], "(.*)", 4); 153 info->year = pos++; 154 i += 6; 155 j += 4; 156 } else if (strncmp(&aux_str[i], "<comment>", 9) == 0) { 157 strncpy(&expr_str[j], "(.*)", 4); 158 info->comment = pos++; 159 i += 9; 160 j += 4; 161 } else if (strncmp(&aux_str[i], "<track>", 7) == 0) { 162 strncpy(&expr_str[j], "([^ ]*)", 7); 163 info->track = pos++; 164 i += 7; 165 j += 7; 166 } else if (strncmp(&aux_str[i], "<genre>", 7) == 0) { 167 strncpy(&expr_str[j], "(.*)", 4); 168 info->genre = pos++; 169 i += 7; 170 j += 4; 171 } else if (strncmp(&aux_str[i], "<\\*>", 4) == 0) { 172 strncpy(&expr_str[j], ".*", 2); 173 i += 4; 174 j += 2; 175 } else { 176 expr_str[j++] = aux_str[i++]; 177 } 178 } else { 179 strcpy(&expr_str[j], &aux_str[i]); 180 break; 181 } 182 } 183 184 185 /* printf("regexp: %s\n", expr_str); */ 186 187 /* compile the regexp from the expression string */ 188 res = regcomp(&info->re, expr_str, REG_EXTENDED | REG_ICASE); 189 if (res != 0) { 190 g_warning("error in regcomp (\"%s\"): %d", expr_str, res); 191 free(aux_str); 192 free(expr_str); 193 free(info); 194 return NULL; 195 } 196 197 free(aux_str); 198 free(expr_str); 199 200 return info; 201 } 202 203 static void free_parse_info(parse_info *info) 204 { 205 regfree(&info->re); 206 free(info); 207 } 208 209 210 static void set_field(audio_file *af, int field, gchar *src, int len) 211 { 212 chconv_tag_options options; 213 char *temp; 214 char *buf = malloc(len+1); 215 str_safe_strncpy(buf, src, len+1); 216 217 /* apply character conversions */ 218 options = chconv_get_tag_options(); 219 if (options.space_conv != NULL && options.space_conv[0] != 0) { 220 str_rtrim(buf); 221 222 temp = buf; 223 buf = str_replace_char(buf, options.space_conv[0], ' '); 224 free(temp); 225 } 226 if (options.case_conv != CASE_CONV_NONE) { 227 temp = buf; 228 buf = str_convert_case(buf, options.case_conv); 229 free(temp); 230 } 231 232 audio_file_set_field(af, field, buf); 233 free(buf); 234 } 235 236 static gboolean tag_from_filename(parse_info *pi, gchar *filename, audio_file *af) 237 { 238 regmatch_t matches[8]; 239 char *filename_utf8; 240 char *p; 241 int res; 242 243 /* convert to UTF-8 */ 244 filename_utf8 = str_filename_to_utf8(filename, NULL); 245 if (filename_utf8 == NULL) 246 return FALSE; 247 248 /* truncate the file extension */ 249 p = g_utf8_strrchr(filename_utf8, -1, '.'); 250 if (p && strlen(p) <= 5) 251 *p = 0; 252 253 /* printf("string: %s\n", filename_utf8); */ 254 255 256 /* match the regexp against the file name (minus extension) and 257 extract the tag fields */ 258 res = regexec(&pi->re, filename_utf8, 8, matches, 0); 259 if (res != 0) { 260 free(filename_utf8); 261 return FALSE; 262 } 263 264 if (pi->title > 0) { 265 set_field(af, AF_TITLE, &filename_utf8[matches[pi->title].rm_so], 266 matches[pi->title].rm_eo - matches[pi->title].rm_so); 267 } 268 if (pi->artist > 0) { 269 set_field(af, AF_ARTIST, &filename_utf8[matches[pi->artist].rm_so], 270 matches[pi->artist].rm_eo - matches[pi->artist].rm_so); 271 } 272 if (pi->album > 0) { 273 set_field(af, AF_ALBUM, &filename_utf8[matches[pi->album].rm_so], 274 matches[pi->album].rm_eo - matches[pi->album].rm_so); 275 } 276 if (pi->year > 0) { 277 set_field(af, AF_YEAR, &filename_utf8[matches[pi->year].rm_so], 278 matches[pi->year].rm_eo - matches[pi->year].rm_so); 279 } 280 if (pi->comment > 0) { 281 set_field(af, AF_COMMENT, &filename_utf8[matches[pi->comment].rm_so], 282 matches[pi->comment].rm_eo - matches[pi->comment].rm_so); 283 } 284 if (pi->track > 0) { 285 set_field(af, AF_TRACK, &filename_utf8[matches[pi->track].rm_so], 286 matches[pi->track].rm_eo - matches[pi->track].rm_so); 287 } 288 if (pi->genre > 0) { 289 set_field(af, AF_GENRE, &filename_utf8[matches[pi->genre].rm_so], 290 matches[pi->genre].rm_eo - matches[pi->genre].rm_so); 291 } 292 293 free(filename_utf8); 294 return TRUE; 295 } 296 297 298 static void tag_files(GEList *file_list) 299 { 300 GList *iter; 301 audio_file *af; 302 parse_info *pi; 303 gint path_components; 304 gchar *last_path; 305 gchar *curr_path; 306 gchar *file_name = NULL; 307 gchar *file_name_utf8 = NULL; 308 gchar *temp_utf8; 309 gint track_auto_index; 310 gint count_total, count_tagged; 311 int save_errno, res; 312 313 gboolean write_title = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_title)); 314 gboolean write_artist = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_artist)); 315 gboolean write_album = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_album)); 316 gboolean write_year = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_year)); 317 gboolean write_comment = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_comment)); 318 gboolean write_track = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_track)); 319 gboolean write_genre = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_genre)); 320 gboolean track_auto = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_track_auto)); 321 322 pd_start(_("Tagging Files")); 323 if (!(write_title || write_artist || write_album || write_year || 324 write_comment || write_track || write_genre)) 325 { 326 pd_printf(PD_ICON_INFO, _("No tag fields to set!")); 327 pd_end(); 328 return; 329 } 330 pd_printf(PD_ICON_INFO, _("Starting in directory \"%s\""), fl_get_working_dir_utf8()); 331 332 if (*use_filename) { 333 const gchar *format = gtk_entry_get_text(ent_tag_format); 334 pi = build_parse_info(format); 335 path_components = fu_count_path_components(format); 336 } 337 else { 338 pi = NULL; 339 path_components = 0; 340 } 341 342 count_total = 0; 343 count_tagged = 0; 344 track_auto_index = 1; 345 last_path = ""; 346 for (iter = g_elist_first(file_list); iter; iter = g_list_next(iter)) { 347 /* flush pending gtk operations so the UI doesn't freeze */ 348 pd_scroll_to_bottom(); 349 while (gtk_events_pending()) gtk_main_iteration(); 350 if (pd_stop_requested()) { 351 pd_printf(PD_ICON_WARN, _("Operation stopped at user's request")); 352 break; 353 } 354 355 count_total++; 356 357 curr_path = (gchar *)iter->data; 358 359 if (!fu_compare_file_paths(last_path, curr_path)) { 360 gchar *p; 361 temp_utf8 = str_filename_to_utf8(curr_path, _("(UTF8 conversion error)")); 362 p = g_utf8_strrchr(temp_utf8, -1, '/'); 363 pd_printf(PD_ICON_INFO, _("Entering directory \"%.*s\""), (gint)(p-temp_utf8), temp_utf8); 364 free(temp_utf8); 365 366 track_auto_index = 1; /* new dir, reset track auto-increment */ 367 } 368 last_path = curr_path; 369 370 file_name = fu_last_n_path_components(curr_path, 1); 371 file_name_utf8 = str_filename_to_utf8(file_name, _("(UTF8 conversion error)")); 372 373 res = audio_file_new(&af, curr_path, TRUE); 374 if (res != AF_OK) { 375 pd_printf(PD_ICON_FAIL, _("Error tagging \"%s\""), file_name_utf8); 376 377 if (res == AF_ERR_FILE) 378 pd_printf(PD_ICON_NONE, _("Couldn't open file for writing")); 379 else if (res == AF_ERR_FORMAT) 380 pd_printf(PD_ICON_NONE, _("Audio format not recognized")); 381 else 382 pd_printf(PD_ICON_NONE, _("Unknown error (%d)"), res); 383 384 goto _continue; 385 } 386 387 /* create the tag if not already present */ 388 audio_file_create_tag(af); 389 390 /* fill in the values from the form */ 391 if (write_title && !(from_fn_title && *use_filename)) 392 audio_file_set_field(af, AF_TITLE, gtk_entry_get_text(ent_title)); 393 if (write_artist && !(from_fn_artist && *use_filename)) 394 audio_file_set_field(af, AF_ARTIST, gtk_entry_get_text(ent_artist)); 395 if (write_album && !(from_fn_album && *use_filename)) 396 audio_file_set_field(af, AF_ALBUM, gtk_entry_get_text(ent_album)); 397 if (write_year && !(from_fn_year && *use_filename)) 398 audio_file_set_field(af, AF_YEAR, gtk_entry_get_text(ent_year)); 399 if (write_comment && !(from_fn_comment && *use_filename)) 400 audio_file_set_field(af, AF_COMMENT, gtk_entry_get_text(ent_comment)); 401 if (write_track && !(from_fn_track && *use_filename)) { 402 if (track_auto) { 403 char buf[10]; 404 snprintf(buf, 10, "%02u", track_auto_index++); 405 audio_file_set_field(af, AF_TRACK, buf); 406 } else 407 audio_file_set_field(af, AF_TRACK, gtk_entry_get_text(ent_track)); 408 } 409 if (write_genre && !(from_fn_genre && *use_filename)) 410 audio_file_set_field(af, AF_GENRE, gtk_entry_get_text(GTK_ENTRY(combo_genre->entry))); 411 412 /* fill in the values from the file name */ 413 if (pi != NULL) { 414 gchar *full_path = fu_join_path(fl_get_working_dir(), curr_path); 415 gchar *relevant_path = fu_last_n_path_components(full_path, path_components); 416 417 res = tag_from_filename(pi, relevant_path, af); 418 free(full_path); 419 420 if (!res) { 421 pd_printf(PD_ICON_FAIL, _("Error tagging \"%s\""), file_name_utf8); 422 pd_printf(PD_ICON_NONE, _("File name does not match expected format")); 423 goto _continue; 424 } 425 } 426 427 /* write new tag to file */ 428 res = audio_file_write_changes(af); 429 if (res != AF_OK) { 430 save_errno = errno; 431 pd_printf(PD_ICON_FAIL, _("Error tagging \"%s\""), file_name_utf8); 432 433 if (res == AF_ERR_FILE) 434 pd_printf(PD_ICON_NONE, "%s (%d)", strerror(save_errno), save_errno); 435 else 436 pd_printf(PD_ICON_NONE, _("Unknown error (%d)"), res); 437 438 goto _continue; 439 } 440 441 pd_printf(PD_ICON_OK, _("Tagged \"%s\""), file_name_utf8); 442 count_tagged++; 443 444 _continue: 445 free(file_name_utf8); 446 if (af) { 447 audio_file_delete(af); 448 af = NULL; 449 } 450 } 451 452 pd_printf(PD_ICON_INFO, _("Done (tagged %d of %d files)"), count_tagged, count_total); 453 pd_end(); 454 455 if (pi != NULL) 456 free_parse_info(pi); 457 } 458 459 460 static void start_operation() 461 { 462 GEList *file_list; 463 464 if (gtk_combo_box_get_active(combo_tag_apply) == APPLY_TO_ALL) 465 file_list = fl_get_all_files(); 466 else 467 file_list = fl_get_selected_files(); 468 469 if (g_elist_length(file_list) == 0) { 470 pd_start(NULL); 471 pd_printf(PD_ICON_FAIL, _("No files selected")); 472 pd_end(); 473 474 g_elist_free(file_list); 475 return; 476 } 477 478 cursor_set_wait(); 479 gtk_widget_set_sensitive(GTK_WIDGET(b_tag_go), FALSE); 480 481 mru_add(format_mru, gtk_entry_get_text(ent_tag_format)); 482 gtk_combo_set_popdown_strings(combo_tag_format, GLIST(format_mru->list)); 483 484 tag_files(file_list); 485 486 gtk_widget_set_sensitive(GTK_WIDGET(b_tag_go), TRUE); 487 cursor_set_normal(); 488 489 g_elist_free(file_list); 490 } 491 492 493 static void update_interface_fname() 494 { 495 static gboolean last_title = FALSE; 496 static gboolean last_artist = FALSE; 497 static gboolean last_album = FALSE; 498 static gboolean last_year = FALSE; 499 static gboolean last_comment = FALSE; 500 static gboolean last_track = FALSE; 501 static gboolean last_genre = FALSE; 502 503 const gchar *format = gtk_entry_get_text(ent_tag_format); 504 gboolean value; 505 gboolean save; 506 507 /* inhibit proccessing signals in 'cb_filed_changed' */ 508 save = ignore_field_changed; 509 ignore_field_changed = TRUE; 510 511 if (strstr(format, "<title>")) from_fn_title = TRUE; 512 else from_fn_title = FALSE; 513 if (strstr(format, "<artist>")) from_fn_artist = TRUE; 514 else from_fn_artist = FALSE; 515 if (strstr(format, "<album>")) from_fn_album = TRUE; 516 else from_fn_album = FALSE; 517 if (strstr(format, "<year>")) from_fn_year = TRUE; 518 else from_fn_year = FALSE; 519 if (strstr(format, "<comment>")) from_fn_comment = TRUE; 520 else from_fn_comment = FALSE; 521 if (strstr(format, "<track>")) from_fn_track = TRUE; 522 else from_fn_track = FALSE; 523 if (strstr(format, "<genre>")) from_fn_genre = TRUE; 524 else from_fn_genre = FALSE; 525 526 value = *use_filename && from_fn_title; 527 if (last_title != value) { 528 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_title), value); 529 gtk_entry_set_text(ent_title, (value ? "<from filename>" : "")); 530 gtk_widget_set_sensitive(GTK_WIDGET(cb_title), !value); 531 gtk_widget_set_sensitive(GTK_WIDGET(ent_title), !value); 532 last_title = value; 533 } 534 value = *use_filename && from_fn_artist; 535 if (last_artist != value) { 536 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_artist), value); 537 gtk_entry_set_text(ent_artist, (value ? "<from filename>" : "")); 538 gtk_widget_set_sensitive(GTK_WIDGET(cb_artist), !value); 539 gtk_widget_set_sensitive(GTK_WIDGET(ent_artist), !value); 540 last_artist = value; 541 } 542 value = *use_filename && from_fn_album; 543 if (last_album != value) { 544 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_album), value); 545 gtk_entry_set_text(ent_album, (value ? "<from filename>" : "")); 546 gtk_widget_set_sensitive(GTK_WIDGET(cb_album), !value); 547 gtk_widget_set_sensitive(GTK_WIDGET(ent_album), !value); 548 last_album = value; 549 } 550 value = *use_filename && from_fn_year; 551 if (last_year != value) { 552 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_year), value); 553 gtk_entry_set_text(ent_year, (value ? "<fn>" : "")); 554 gtk_widget_set_sensitive(GTK_WIDGET(cb_year), !value); 555 gtk_widget_set_sensitive(GTK_WIDGET(ent_year), !value); 556 last_year = value; 557 } 558 value = *use_filename && from_fn_comment; 559 if (last_comment != value) { 560 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_comment), value); 561 gtk_entry_set_text(ent_comment, (value ? "<from filename>" : "")); 562 gtk_widget_set_sensitive(GTK_WIDGET(cb_comment), !value); 563 gtk_widget_set_sensitive(GTK_WIDGET(ent_comment), !value); 564 last_comment = value; 565 } 566 value = *use_filename && from_fn_track; 567 if (last_track != value) { 568 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_track), value); 569 gtk_entry_set_text(ent_track, (value ? "<fn>" : "")); 570 gtk_widget_set_sensitive(GTK_WIDGET(cb_track), !value); 571 gtk_widget_set_sensitive(GTK_WIDGET(ent_track), !value); 572 if (value) 573 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_track_auto), FALSE); 574 gtk_widget_set_sensitive(GTK_WIDGET(cb_track_auto), !value); 575 last_track = value; 576 } 577 value = *use_filename && from_fn_genre; 578 if (last_genre != value) { 579 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_genre), value); 580 gtk_entry_set_text(ent_genre, (value ? "<from filename>" : "")); 581 gtk_widget_set_sensitive(GTK_WIDGET(cb_genre), !value); 582 gtk_widget_set_sensitive(GTK_WIDGET(combo_genre), !value); 583 last_genre = value; 584 } 585 586 ignore_field_changed = save; 587 } 588 589 590 /*** UI callbacks ***********************************************************/ 591 592 void cb_tag_go(GtkButton *button, gpointer user_data) 593 { 594 start_operation(); 595 } 596 597 void cb_update_filename(GObject *obj, gpointer data) 598 { 599 *use_filename = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cb_use_filename)); 600 update_interface_fname(); 601 } 602 603 void cb_field_changed(GObject *obj, gpointer data) 604 { 605 if (ignore_field_changed) 606 return; 607 608 if ((void*)obj == (void*)ent_title) 609 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_title), TRUE); 610 else if ((void*)obj == (void*)ent_artist) 611 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_artist), TRUE); 612 else if ((void*)obj == (void*)ent_album) 613 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_album), TRUE); 614 else if ((void*)obj == (void*)ent_year) 615 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_year), TRUE); 616 else if ((void*)obj == (void*)ent_genre) 617 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_genre), TRUE); 618 else if ((void*)obj == (void*)ent_comment) 619 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_comment), TRUE); 620 else if ((void*)obj == (void*)ent_track || (void*)obj == (void*)cb_track_auto) 621 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_track), TRUE); 622 } 623 624 void cb_check_changed(GtkToggleButton *widget, gpointer data) 625 { 626 gboolean save; 627 628 if (gtk_toggle_button_get_active(widget)) 629 return; 630 631 /* inhibit proccessing signals in 'cb_field_changed' */ 632 save = ignore_field_changed; 633 ignore_field_changed = TRUE; 634 635 if ((void*)widget == (void*)cb_title) 636 gtk_entry_set_text(ent_title, ""); 637 else if ((void*)widget == (void*)cb_artist) 638 gtk_entry_set_text(ent_artist, ""); 639 else if ((void*)widget == (void*)cb_album) 640 gtk_entry_set_text(ent_album, ""); 641 else if ((void*)widget == (void*)cb_year) 642 gtk_entry_set_text(ent_year, ""); 643 else if ((void*)widget == (void*)cb_genre) 644 gtk_entry_set_text(ent_genre, ""); 645 else if ((void*)widget == (void*)cb_comment) 646 gtk_entry_set_text(ent_comment, ""); 647 else if ((void*)widget == (void*)cb_track) { 648 gtk_entry_set_text(ent_track, ""); 649 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_track_auto), FALSE); 650 } 651 652 ignore_field_changed = save; 653 } 654 655 void cb_show_tag_chconv(GtkButton *button, gpointer user_data) 656 { 657 chconv_display(CHCONV_TAG); 658 } 659 660 void cb_tag_help(GtkButton *button, gpointer user_data) 661 { 662 help_display(HELP_TAG_FORMAT); 663 } 664 665 static void cb_file_selection_changed(GtkTreeSelection *selection, gpointer data) 666 { 667 if (fl_count_selected() > 0) 668 gtk_combo_box_set_active(combo_tag_apply, APPLY_TO_SELECTED); 669 else 670 gtk_combo_box_set_active(combo_tag_apply, APPLY_TO_ALL); 671 } 672 673 674 /*** public functions *******************************************************/ 675 676 void tt_init(GladeXML *xml) 677 { 678 GtkStyle *style; 679 GtkWidget *w; 680 GEList *genre_list; 681 GEList *format_list; 682 683 /* 684 * get the widgets from glade 685 */ 686 687 combo_tag_format = GTK_COMBO(glade_xml_get_widget(xml, "combo_tag_format")); 688 ent_tag_format = GTK_ENTRY(glade_xml_get_widget(xml, "ent_tag_format")); 689 b_tag_edit_format = GTK_BUTTON(glade_xml_get_widget(xml, "b_tag_edit_format")); 690 cb_use_filename = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_use_filename")); 691 b_tag_go = GTK_BUTTON(glade_xml_get_widget(xml, "b_tag_go")); 692 combo_tag_apply = GTK_COMBO_BOX(glade_xml_get_widget(xml, "combo_tag_apply")); 693 694 cb_title = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_title")); 695 cb_artist = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_artist")); 696 cb_album = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_album")); 697 cb_year = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_year")); 698 cb_comment = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_comment")); 699 cb_track = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_track")); 700 cb_genre = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_genre")); 701 702 ent_title = GTK_ENTRY(glade_xml_get_widget(xml, "ent_title2")); 703 ent_artist = GTK_ENTRY(glade_xml_get_widget(xml, "ent_artist2")); 704 ent_album = GTK_ENTRY(glade_xml_get_widget(xml, "ent_album2")); 705 ent_year = GTK_ENTRY(glade_xml_get_widget(xml, "ent_year2")); 706 ent_comment = GTK_ENTRY(glade_xml_get_widget(xml, "ent_comment2")); 707 ent_track = GTK_ENTRY(glade_xml_get_widget(xml, "ent_track2")); 708 cb_track_auto = GTK_CHECK_BUTTON(glade_xml_get_widget(xml, "cb_track_auto")); 709 combo_genre = GTK_COMBO(glade_xml_get_widget(xml, "combo_genre2")); 710 ent_genre = GTK_ENTRY(glade_xml_get_widget(xml, "ent_genre2")); 711 712 w_main = GTK_WINDOW(glade_xml_get_widget(xml, "w_main")); 713 714 /* initialize some widgets' state */ 715 gtk_combo_box_set_active(combo_tag_apply, APPLY_TO_ALL); 716 717 genre_list = genre_create_list(TRUE); 718 g_elist_prepend(genre_list, ""); 719 gtk_combo_set_popdown_strings(combo_genre, GLIST(genre_list)); 720 g_elist_free(genre_list); 721 722 /* connect signals */ 723 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(glade_xml_get_widget(xml, "tv_files"))), 724 "changed", G_CALLBACK(cb_file_selection_changed), NULL); 725 726 727 /* 728 * set the title colors 729 */ 730 731 w = glade_xml_get_widget(xml, "lab_tag_title"); 732 gtk_widget_ensure_style(w); 733 style = gtk_widget_get_style(w); 734 735 gtk_widget_modify_fg(w, GTK_STATE_NORMAL, &style->text[GTK_STATE_SELECTED]); 736 737 w = glade_xml_get_widget(xml, "box_tag_title"); 738 gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &style->base[GTK_STATE_SELECTED]); 739 740 741 /* 742 * get the preference values, or set them to defaults 743 */ 744 745 /* use_filename */ 746 use_filename = pref_get_ref("tt:use_filename"); 747 if (!use_filename) { 748 gboolean temp = TRUE; 749 use_filename = pref_set("tt:use_filename", PREF_BOOLEAN, &temp); 750 } 751 752 /* format_mru */ 753 format_list = pref_get_ref("tt:format_mru"); 754 if (!format_list) { 755 GEList *temp_list = g_elist_new(); 756 g_elist_append(temp_list, "<track>. <title>"); 757 g_elist_append(temp_list, "<artist> - <title>"); 758 g_elist_append(temp_list, "<artist> - <album>/<track>. <title>"); 759 g_elist_append(temp_list, "<artist>/<album>/<track>. <title>"); 760 g_elist_append(temp_list, "<artist>/<album> (<year>)/<track>. <title>"); 761 format_list = pref_set("tt:format_mru", PREF_STRING | PREF_LIST, temp_list); 762 g_elist_free(temp_list); 763 } 764 format_mru = mru_new_from_list(10, format_list); 765 766 767 /* 768 * synchronize the interface state 769 */ 770 771 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_use_filename), *use_filename); 772 gtk_combo_set_popdown_strings(combo_tag_format, GLIST(format_mru->list)); 773 774 update_interface_fname(); 775 } 776 777