Add extra checks (exists and rw) before adding song to tag-queue
[gmpc-tagedit.git] / src / plugin.c
blob0d2d6c58da2c4e7be7515631e1590aff3cc3f13c
1 /* gmpc-tagedit (GMPC plugin)
2 * Copyright (C) 2008-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <string.h>
21 #include <unistd.h>
22 #include <config.h>
23 #include <glib.h>
24 #include <glib/gi18n-lib.h>
25 #include <gdk/gdkkeysyms.h>
26 #include <libmpd/libmpd.h>
27 #include <gmpc/plugin.h>
28 #include <gmpc/playlist3-messages.h>
29 #include <tag_c.h>
30 #include "gmpc-mpddata-model-tagedit.h"
31 #include "tagedit.h"
34 static void __save_myself(void);
35 /* The plugin structure */
36 gmpcPlugin plugin;
39 static GtkTreeRowReference *te_ref = NULL;
40 static GtkWidget *browser_box = NULL;
41 static GtkWidget *browser_tree = NULL;
42 static GtkTreeModel *browser_model = NULL;
43 static GtkWidget *entries[7];
44 static gulong signal_entries[7];
46 static inline GQuark
47 tagedit_quark(void)
49 return g_quark_from_static_string("tagedit_plugin");
51 /**
52 * Preferences
54 static void info_entry_edited(GtkWidget *entry)
56 const char *str = gtk_entry_get_text(GTK_ENTRY(entry));
58 cfg_set_single_value_as_string(config, CONFIG_NAME, "music_root",(char *)str);
59 if(str && browser_box)
61 if(strlen(str) > 0){
62 gtk_widget_set_sensitive(browser_box, TRUE);
63 }else {
64 gtk_widget_set_sensitive(browser_box, FALSE);
69 static void __pref_destroy(GtkWidget *container)
71 gtk_widget_destroy(gtk_bin_get_child(GTK_BIN(container)));
73 static void __pref_construct(GtkWidget *container)
75 GtkWidget *entry = NULL;
76 char *entry_str = cfg_get_single_value_as_string(config, CONFIG_NAME, "music_root");
77 GtkWidget *vbox = gtk_vbox_new(FALSE,6);
80 gtk_container_add(GTK_CONTAINER(container), vbox);
82 entry = gtk_entry_new();
83 if(entry_str)
85 gtk_entry_set_text(GTK_ENTRY(entry), entry_str);
86 g_free(entry_str);
88 gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new("Music Root:"), FALSE, FALSE,0);
89 gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE,0);
90 g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(info_entry_edited), NULL);
92 gtk_widget_show_all(container);
96 /**
97 * Taglib functions
100 static mpd_Song * get_song_from_file(const char *root, const char *filename, GError **error)
102 TagLib_File *file = NULL;
103 TagLib_Tag *tag;
104 mpd_Song *song = NULL;
105 gchar *url = g_build_path(G_DIR_SEPARATOR_S, root, filename,NULL);
106 if(!g_file_test(url, G_FILE_TEST_EXISTS|G_FILE_TEST_IS_REGULAR)){
107 g_set_error(error, tagedit_quark(), 0, "%s: '%s'", _("File does not exists"), url);
108 g_free(url);
109 return NULL;
111 if(g_access(url, R_OK|W_OK) != 0) {
112 g_set_error(error, tagedit_quark(), 0, "%s: '%s'", _("File is read-only"), url);
113 g_free(url);
114 return NULL;
116 file = taglib_file_new(url);
117 if(file && taglib_file_is_valid(file))
119 char *a = NULL;
120 song = mpd_newSong();
121 song->file = g_strdup(filename);
122 tag = taglib_file_tag(file);
123 if(tag)
125 if((a = taglib_tag_title(tag)) && a[0] != '\0')
126 song->title = g_strdup(a);
127 if((a = taglib_tag_album(tag)) && a[0] != '\0')
128 song->album = g_strdup(a);
129 if((a = taglib_tag_artist(tag)) && a[0] != '\0')
130 song->artist = g_strdup(a);
131 if(taglib_tag_track(tag) > 0)
132 song->track = g_strdup_printf("%i", taglib_tag_track(tag));
133 if((a = taglib_tag_genre(tag)) && a[0] != '\0')
134 song->genre = g_strdup(a);
135 if((a = taglib_tag_comment(tag)) && a[0] != '\0')
136 song->comment = g_strdup(a);
137 if(taglib_tag_year(tag) > 0)
138 song->date = g_strdup_printf("%i", taglib_tag_year(tag));
141 taglib_tag_free_strings();
143 if(file)
144 taglib_file_free(file);
145 g_free(url);
146 return song;
148 static gboolean __timeout_mpd_update(gchar *url)
150 printf("update: %s\n",url);
151 mpd_database_update_dir(connection, url);
153 return FALSE;
156 static void save_song_to_file(const char *root, const mpd_Song *song)
158 TagLib_File *file;
159 TagLib_Tag *tag;
161 gchar *url = g_build_path(G_DIR_SEPARATOR_S, root, song->file,NULL);
162 file = taglib_file_new(url);
163 if(file)
165 tag = taglib_file_tag(file);
166 if(song->title) taglib_tag_set_title(tag, song->title);
167 if(song->artist) taglib_tag_set_artist(tag, song->artist);
168 if(song->album) taglib_tag_set_album(tag, song->album);
169 if(song->genre) taglib_tag_set_genre(tag, song->genre);
170 if(song->comment) taglib_tag_set_comment(tag, song->comment);
171 if(song->track){
172 guint track = (guint) g_ascii_strtoll(song->track, NULL, 10);
173 taglib_tag_set_track(tag, track);
175 if(song->date){
176 guint year = (guint) g_ascii_strtoll(song->date, NULL, 10);
177 taglib_tag_set_year(tag, year);
179 if(taglib_file_save(file)){
180 gchar *errorstr = g_strdup_printf("%s: %s '%s'", _("Tag Edit"), _("Failed to save song"), url);
181 playlist3_show_error_message(errorstr, DEBUG_ERROR);
182 g_free(errorstr);
183 }else {
184 g_timeout_add_seconds_full(G_PRIORITY_DEFAULT ,1, (GSourceFunc)__timeout_mpd_update, g_strdup(song->file), g_free);
186 taglib_tag_free_strings();
187 taglib_file_free(file);
190 g_free(url);
197 * Browser View
201 static void free_si(gpointer data)
203 si *i = data;
204 printf("free si\n");
205 if(i->revert) mpd_freeSong(i->revert);
206 g_free(i);
208 static void queue_selected_songs_for_edit(GtkMenuItem *item, GmpcMpdDataTreeview *tree)
210 char *root = cfg_get_single_value_as_string(config, CONFIG_NAME, "music_root");
211 MpdData *data = NULL;
212 GList *selected = NULL;
213 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(tree));
214 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
215 if(!browser_model)
216 browser_model = (GtkTreeModel *)gmpc_mpddata_model_tagedit_new();
217 data = gmpc_mpddata_model_steal_mpd_data(GMPC_MPDDATA_MODEL(browser_model));
218 selected = gtk_tree_selection_get_selected_rows(selection, &model);
219 if(selected && root )
221 GList *iter = g_list_first(selected);
222 for(;iter; iter = g_list_next(iter))
224 GtkTreeIter titer;
226 if(gtk_tree_model_get_iter(model, &titer, iter->data))
228 mpd_Song *song = NULL;
229 gtk_tree_model_get(model, &titer, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
230 if(song && song->file)
232 GError *error= NULL;
233 mpd_Song *edited = get_song_from_file(root, song->file, &error);
234 printf("adding: %s\n", song->file);
235 if(edited)
237 si *i = g_malloc0(sizeof(*i));
238 data = mpd_new_data_struct_append(data);
239 data->type = MPD_DATA_TYPE_SONG;
240 data->song = edited;
241 i->changed = 0;
242 i->revert = mpd_songDup(data->song);
243 data->userdata =i;
244 data->freefunc = free_si;
246 else
248 gchar *errorstr = g_strdup_printf("%s: %s", _("Tag Edit"), error->message);
249 playlist3_show_error_message(errorstr, ERROR_CRITICAL);
250 g_error_free(error);
251 g_free(errorstr);
252 error = NULL;
257 g_list_foreach (selected, (GFunc)gtk_tree_path_free, NULL);
258 g_list_free (selected);
260 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(browser_model),data);
261 if(root)g_free(root);
264 static int __song_list_option_menu ( GmpcMpdDataTreeview *tree, GtkMenu *menu)
266 int retv = 0;
267 GtkWidget *item;
268 char *entry_str = cfg_get_single_value_as_string(config, CONFIG_NAME, "music_root");
269 if(plugin.get_enabled() && entry_str && strlen(entry_str) > 0)
271 item = gtk_image_menu_item_new_with_label("Queue songs for tag edit");
272 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
273 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
274 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
275 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(queue_selected_songs_for_edit), tree);
276 retv++;
278 if(entry_str) g_free(entry_str);
279 return retv;
281 static void browser_selection_changed(GtkTreeSelection *selec, gpointer data)
283 GList *selected = gtk_tree_selection_get_selected_rows(selec, &browser_model);
284 int i =0;
285 for(i=0;i< 6;i++)
287 if(signal_entries[i])
288 g_signal_handler_block(G_OBJECT(entries[i]), signal_entries[i]);
289 if(i<4) gtk_entry_set_text(GTK_ENTRY(entries[i]), "");
290 else gtk_spin_button_set_value(GTK_SPIN_BUTTON(entries[i]), 0.0);
292 if(selected)
294 GList *iter = g_list_first(selected);
295 for(;iter; iter = g_list_next(iter))
297 GtkTreeIter titer;
298 if(gtk_tree_model_get_iter(browser_model, &titer, iter->data))
300 mpd_Song *song = NULL;
301 gtk_tree_model_get(browser_model, &titer, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
302 if(song)
304 if(song->title)
306 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries[0]))) == 0)
307 gtk_entry_set_text(GTK_ENTRY(entries[0]), song->title);
309 if(song->artist)
311 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries[1]))) == 0)
312 gtk_entry_set_text(GTK_ENTRY(entries[1]), song->artist);
314 if(song->album)
316 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries[2]))) == 0)
317 gtk_entry_set_text(GTK_ENTRY(entries[2]), song->album);
319 if(song->genre)
321 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries[3]))) == 0)
322 gtk_entry_set_text(GTK_ENTRY(entries[3]), song->genre);
324 if(song->date)
326 guint year = (guint) g_ascii_strtoll(song->date, NULL, 10);
327 if(year && gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entries[4])) == 0)
328 gtk_spin_button_set_value(GTK_SPIN_BUTTON(entries[4]), (gdouble) year);
330 if(song->track)
332 guint track = (guint) g_ascii_strtoll(song->track, NULL, 10);
333 if(track && gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entries[5])) == 0)
334 gtk_spin_button_set_value(GTK_SPIN_BUTTON(entries[5]), (gdouble) track);
340 g_list_foreach (selected, (GFunc)gtk_tree_path_free, NULL);
341 g_list_free (selected);
343 for(i=0;i<6;i++)
345 if(signal_entries[i])
346 g_signal_handler_unblock(G_OBJECT(entries[i]), signal_entries[i]);
349 static void __revert_selected(GtkWidget *button, gpointer data)
351 GtkTreeSelection *selec = gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree));
352 GList *selected = gtk_tree_selection_get_selected_rows(selec, &browser_model);
353 if(selected)
355 GList *iter = g_list_first(selected);
356 for(;iter; iter = g_list_next(iter))
358 GtkTreeIter titer;
359 if(gtk_tree_model_get_iter(browser_model, &titer, iter->data))
361 si *ud = NULL;
362 mpd_Song *song = NULL;
363 gtk_tree_model_get(browser_model, &titer, MPDDATA_MODEL_COL_MPDSONG, &song, MPDDATA_MODEL_USERDATA, &ud,-1);
364 gmpc_mpddata_model_tagedit_revert_song(browser_model, &titer);
368 g_list_foreach (selected, (GFunc)gtk_tree_path_free, NULL);
369 g_list_free (selected);
371 browser_selection_changed(selec, NULL);
376 static void __field_changed(GtkWidget *entry, gpointer data)
378 int id = GPOINTER_TO_INT(data);
380 const gchar *text = NULL;
381 gint value = 0;
382 GList *selected = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree)), &browser_model);
383 if(id < 4)
385 text = gtk_entry_get_text(GTK_ENTRY(entry));
387 else if (id < 6)
389 value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry));
391 if(selected)
393 GList *iter = g_list_first(selected);
394 for(;iter; iter = g_list_next(iter))
396 GtkTreeIter titer;
397 if(gtk_tree_model_get_iter(browser_model, &titer, iter->data))
399 mpd_Song *song = NULL;
400 si *ud = NULL;
401 gtk_tree_model_get(browser_model, &titer, MPDDATA_MODEL_COL_MPDSONG, &song,MPDDATA_MODEL_USERDATA, &ud, -1);
402 if(song)
404 if(id == 0) {
405 if(song->title == NULL || strcmp(song->title, text) != 0)
407 if(song->title) g_free(song->title);
408 song->title = g_strdup(text);
409 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
410 if(ud->revert->title && strcmp(text, ud->revert->title) == 0)
411 ud->changed &= ~1;
412 else
413 ud->changed |= 1;
416 else if(id == 1) {
417 if(song->artist == NULL || strcmp(song->artist, text) != 0)
419 if(song->artist) g_free(song->artist);
420 song->artist = g_strdup(text);
421 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
422 if(ud->revert->artist && strcmp(text, ud->revert->artist) == 0)
423 ud->changed &= ~(1<<1);
424 else
425 ud->changed |= (1<<1);
428 else if(id == 2) {
429 if(song->album == NULL || strcmp(song->album, text) != 0)
431 if(song->album) g_free(song->album);
432 song->album = g_strdup(text);
433 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
434 if(ud->revert->album && strcmp(text, ud->revert->album) == 0)
435 ud->changed &= ~(1<<2);
436 else
437 ud->changed |= (1<<2);
440 else if(id == 3) {
441 if(song->genre == NULL || strcmp(song->genre, text) != 0)
443 if(song->genre) g_free(song->genre);
444 song->genre = g_strdup(text);
445 if(ud->revert->genre && strcmp(text, ud->revert->genre) == 0)
446 ud->changed &= ~(1<<3);
447 else
448 ud->changed |= (1<<3);
449 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
452 else if (id == 4) {
453 guint val = 0;
454 if(song->date)
455 val = (guint)g_ascii_strtoll(song->date, NULL, 10);
456 if(val != value)
458 if(song->date ) g_free(song->date );
459 if(value > 0)
460 song->date = g_strdup_printf("%i", value);
461 else
462 song->date = NULL;
465 if(ud->revert->date == NULL && song->date == NULL) ud->changed &= ~(1<<4);
466 else if(ud->revert->date && song->date && strcmp(song->date, ud->revert->date) == 0)
467 ud->changed &= ~(1<<4);
468 else
469 ud->changed |= (1<<4);
470 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
473 else if (id == 5) {
474 guint val = 0;
475 if(song->track)
476 val = (guint)g_ascii_strtoll(song->track, NULL, 10);
477 if(val != value)
479 if(song->track) g_free(song->track);
480 if(value > 0)
481 song->track = g_strdup_printf("%i", value);
482 else
483 song->track = NULL;
484 if(song->track == NULL && ud->revert->track == NULL)
485 ud->changed &= ~(1<<5);
486 else if(ud->revert->track && song->track && strcmp(song->track, ud->revert->track) == 0)
487 ud->changed &= ~(1<<5);
488 else
489 ud->changed |= (1<<5);
490 gtk_tree_model_row_changed(browser_model, (GtkTreePath *)iter->data, &titer);
495 printf("changed: %i-%i\n", id, ud->changed);
498 g_list_foreach (selected, (GFunc)gtk_tree_path_free, NULL);
499 g_list_free (selected);
503 static void save_all(GtkWidget *button, gpointer data)
505 char *root = cfg_get_single_value_as_string(config, CONFIG_NAME, "music_root");
506 GtkTreeIter iter;
507 if(root && gtk_tree_model_get_iter_first(browser_model, &iter))
510 mpd_Song *song = NULL;
511 si *ud = NULL;
512 gtk_tree_model_get(browser_model, &iter, MPDDATA_MODEL_COL_MPDSONG, &song, MPDDATA_MODEL_USERDATA, &ud,-1);
513 if(song)
515 /* check if song changed */
516 if(ud->changed > 0)
518 printf("saving: %s\n", song->file);
519 save_song_to_file(root, song);
520 ud->changed = 0;
523 }while(gtk_tree_model_iter_next(browser_model, &iter));
525 if(root)g_free(root);
527 static void clear_all(GtkWidget *button, gpointer data)
529 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(browser_model), NULL);
532 static void __edit_columns(void)
534 gmpc_mpddata_treeview_edit_columns(GMPC_MPDDATA_TREEVIEW(browser_tree));
536 static int __button_release_event(GtkTreeView *tree, GdkEventButton *event)
538 if(event->button == 3)
540 /* del, crop */
541 GtkWidget *item;
542 GtkWidget *menu = gtk_menu_new();
543 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree));
544 if(gtk_tree_selection_count_selected_rows(selection) == 1)
546 item = gtk_image_menu_item_new_with_label(_("Revert changes"));
547 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
548 gtk_image_new_from_stock(GTK_STOCK_REVERT_TO_SAVED, GTK_ICON_SIZE_MENU));
549 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
550 g_signal_connect(G_OBJECT(item), "activate",
551 G_CALLBACK(__revert_selected), NULL);
553 item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
554 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
555 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
556 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
557 g_signal_connect(G_OBJECT(item), "activate",
558 G_CALLBACK(__edit_columns), NULL);
560 gtk_widget_show_all(menu);
561 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL,0, event->time);
562 return TRUE;
564 return FALSE;
567 static int __key_release_event(GtkWidget *box , GdkEventKey *event, gpointer data)
569 if(event->keyval == GDK_Page_Up||event->keyval == GDK_Page_Down)
571 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree));
572 if(gtk_tree_selection_count_selected_rows(selection) == 1)
574 GList *list = gtk_tree_selection_get_selected_rows(selection, &browser_model);
575 if(list)
577 GtkTreePath *path = list->data;
578 if(event->keyval == GDK_Page_Up)
580 if(gtk_tree_path_prev(path)){
581 gtk_tree_selection_unselect_all(selection);
582 gtk_tree_selection_select_path(selection, path);
584 }else{
585 gtk_tree_path_next(path);
586 gtk_tree_selection_unselect_all(selection);
587 gtk_tree_selection_select_path(selection, path);
590 g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
591 g_list_free (list);
593 return TRUE;
595 return FALSE;
598 static void __browser_init ( )
600 GtkWidget *hbox = NULL;
601 GtkWidget *sw = NULL, *label;
602 GtkWidget *table = NULL;
603 browser_box = gtk_vbox_new(FALSE, 6);
604 if(!browser_model)
605 browser_model = (GtkTreeModel *)gmpc_mpddata_model_tagedit_new();
606 sw = gtk_scrolled_window_new(NULL, NULL);
607 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
608 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
609 browser_tree = gmpc_mpddata_treeview_new(CONFIG_NAME, TRUE, browser_model);
610 gmpc_mpddata_treeview_enable_click_fix(GMPC_MPDDATA_TREEVIEW(browser_tree));
611 gtk_container_add(GTK_CONTAINER(sw), browser_tree);
612 gtk_box_pack_start(GTK_BOX(browser_box), sw, TRUE, TRUE,0);
614 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree))),
615 "changed", G_CALLBACK(browser_selection_changed), NULL);
616 /** Add all the fill in fields */
617 table = gtk_table_new(4,6,FALSE);
618 /* title */
619 label = gtk_label_new(_("Title"));
620 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
621 gtk_table_attach(GTK_TABLE(table),label, 0,1,0,1,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
622 entries[0] = gtk_entry_new();
623 gtk_table_attach(GTK_TABLE(table),entries[0], 1,2,0,1,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
624 signal_entries[0] = g_signal_connect(G_OBJECT(entries[0]), "changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(0));
625 /* artist */
626 label = gtk_label_new(_("Artist"));
627 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
628 gtk_table_attach(GTK_TABLE(table),label, 0,1,1,2,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
629 entries[1] = gtk_entry_new();
630 gtk_table_attach(GTK_TABLE(table),entries[1], 1,2,1,2,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
631 signal_entries[1] = g_signal_connect(G_OBJECT(entries[1]), "changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(1));
632 /* album */
633 label = gtk_label_new(_("Album"));
634 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
635 gtk_table_attach(GTK_TABLE(table),label, 0,1,2,3,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
636 entries[2] = gtk_entry_new();
637 gtk_table_attach(GTK_TABLE(table),entries[2], 1,2,2,3,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
638 signal_entries[2] = g_signal_connect(G_OBJECT(entries[2]), "changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(2));
639 /* album */
640 label = gtk_label_new(_("Genre"));
641 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
642 gtk_table_attach(GTK_TABLE(table),label, 0,1,3,4,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
643 entries[3] = gtk_entry_new();
644 gtk_table_attach(GTK_TABLE(table),entries[3], 1,2,3,4,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
645 signal_entries[3] = g_signal_connect(G_OBJECT(entries[3]), "changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(3));
646 /* album */
647 label = gtk_label_new(_("Year"));
648 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
649 gtk_table_attach(GTK_TABLE(table),label, 3,4,0,1,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
650 entries[4] = gtk_spin_button_new_with_range(0, 3000,1);
651 gtk_table_attach(GTK_TABLE(table),entries[4], 4,5,0,1,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
652 signal_entries[4] = g_signal_connect(G_OBJECT(entries[4]), "value-changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(4));
653 g_signal_connect(G_OBJECT(entries[4]), "key-press-event", G_CALLBACK(__key_release_event), NULL);
654 /* album */
655 label = gtk_label_new(_("Track"));
656 gtk_misc_set_alignment(GTK_MISC(label), 1.0,0.5);
657 gtk_table_attach(GTK_TABLE(table),label, 3,4,1,2,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
658 entries[5] = gtk_spin_button_new_with_range(0, 3000,1);
659 gtk_table_attach(GTK_TABLE(table),entries[5], 4,5,1,2,GTK_EXPAND|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
660 signal_entries[5] = g_signal_connect(G_OBJECT(entries[5]), "value-changed", G_CALLBACK(__field_changed), GINT_TO_POINTER(5));
662 g_signal_connect(G_OBJECT(entries[5]), "key-press-event", G_CALLBACK(__key_release_event), NULL);
665 hbox = gtk_hbox_new(FALSE, 6);
666 label = gtk_button_new_from_stock(GTK_STOCK_SAVE);
667 g_signal_connect(G_OBJECT(label), "clicked", G_CALLBACK(save_all), NULL);
668 gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, TRUE,0);
669 label = gtk_button_new_with_label("Clear tag queue");
670 gtk_button_set_image(GTK_BUTTON(label), gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON));
671 g_signal_connect(G_OBJECT(label), "clicked", G_CALLBACK(clear_all), NULL);
672 gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, TRUE,0);
674 gtk_table_attach(GTK_TABLE(table),hbox, 4,5,3,4,GTK_SHRINK|GTK_FILL, GTK_SHRINK|GTK_FILL, 0,0);
676 gtk_box_pack_start(GTK_BOX(browser_box), table, FALSE, TRUE,0);
678 g_signal_connect(G_OBJECT(browser_tree), "button-release-event", G_CALLBACK(__button_release_event), NULL);
680 g_signal_connect(G_OBJECT(browser_box), "key-press-event", G_CALLBACK(__key_release_event), NULL);
681 gtk_widget_show_all(browser_box);
682 g_object_ref(browser_box);
685 gchar *root = cfg_get_single_value_as_string(config, CONFIG_NAME, "music_root");
686 if((root == NULL || strlen(root) ==0) && browser_box)
687 gtk_widget_set_sensitive(browser_box, FALSE);
688 if(root) g_free(root);
691 static void __browser_add ( GtkWidget *cat_tree)
693 GtkTreePath *path = NULL;
694 GtkTreeIter iter;
695 GtkListStore *pl3_tree = (GtkListStore *)gtk_tree_view_get_model(GTK_TREE_VIEW(cat_tree));
696 gint pos = cfg_get_single_value_as_int_with_default(config, CONFIG_NAME,"position",20);
698 if(!cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "enable", TRUE)) return;
700 debug_printf(DEBUG_INFO,"Adding at position: %i", pos);
701 playlist3_insert_browser(&iter, pos);
702 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &iter,
703 PL3_CAT_TYPE, plugin.id,
704 PL3_CAT_TITLE, _("Tag Editor"),
705 PL3_CAT_INT_ID, "",
706 PL3_CAT_ICON_ID, "gtk-edit",
707 -1);
709 * Clean up old row reference if it exists
711 if (te_ref)
713 gtk_tree_row_reference_free(te_ref);
714 te_ref = NULL;
717 * create row reference
719 path = gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter);
720 if (path)
722 te_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path);
723 gtk_tree_path_free(path);
727 static void __browser_selected (GtkWidget *container)
729 if(browser_box == NULL)
731 __browser_init();
733 gtk_container_add(GTK_CONTAINER(container), browser_box);
735 static void __browser_unselected ( GtkWidget *container)
737 gtk_container_remove(GTK_CONTAINER(container), gtk_bin_get_child(GTK_BIN(container)));
740 static void __destroy()
742 if(browser_box) {
743 g_object_unref(browser_box);
744 browser_box = NULL;
746 if(browser_model){
747 g_object_unref(browser_model);
748 browser_model = NULL;
753 * Get/Set enabled
755 static int ___get_enabled()
757 return cfg_get_single_value_as_int_with_default(config, CONFIG_NAME, "enable", TRUE);
759 static void ___set_enabled(int enabled)
761 cfg_set_single_value_as_int(config, CONFIG_NAME, "enable", enabled);
762 if(enabled)
764 /* Add the browser to the left pane, if there is none to begin with */
765 if(te_ref == NULL)
767 __browser_add(GTK_WIDGET(playlist3_get_category_tree_view()));
770 else if (te_ref)
772 /* Remove it from the left pane */
773 GtkTreePath *path = gtk_tree_row_reference_get_path(te_ref);
774 if (path){
775 GtkTreeIter iter;
776 /* for a save of myself */
777 __save_myself();
778 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter, path)){
779 gtk_list_store_remove(playlist3_get_category_tree_store(), &iter);
781 gtk_tree_path_free(path);
782 gtk_tree_row_reference_free(te_ref);
783 te_ref = NULL;
787 static void __save_myself(void)
789 /* Save the position in the left tree */
790 if (te_ref)
792 GtkTreePath *path = gtk_tree_row_reference_get_path(te_ref);
793 if(path)
795 gint *indices = gtk_tree_path_get_indices(path);
796 debug_printf(DEBUG_INFO,"Saving myself '%s' to position: %i\n",plugin.name, indices[0]);
797 cfg_set_single_value_as_int(config, CONFIG_NAME,"position",indices[0]);
798 gtk_tree_path_free(path);
802 static void __init(void)
804 taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_UTF8);
806 static const gchar *__get_translation_domain(void)
808 return GETTEXT_PACKAGE;
810 int plugin_api_version = PLUGIN_API_VERSION;
812 gmpcPlBrowserPlugin __browser = {
813 /* browser */
814 .add = __browser_add,
815 .selected = __browser_selected,
816 .unselected = __browser_unselected,
817 .song_list_option_menu = __song_list_option_menu
819 gmpcPrefPlugin __pref = {
820 .construct = __pref_construct,
821 .destroy = __pref_destroy
823 gmpcPlugin plugin = {
824 .name = N_("Tag Edit"),
825 .version = {PLUGIN_MAJOR_VERSION,PLUGIN_MINOR_VERSION,PLUGIN_MICRO_VERSION},
826 .plugin_type = GMPC_PLUGIN_PL_BROWSER,
828 .save_yourself = __save_myself,
829 .init = __init,
830 .destroy = __destroy,
831 .pref = &__pref,
832 .browser = &__browser,
833 .set_enabled = ___set_enabled,
834 .get_enabled = ___get_enabled,
836 .get_translation_domain = __get_translation_domain