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.
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>
30 #include "gmpc-mpddata-model-tagedit.h"
34 static void __save_myself(void);
35 /* The plugin structure */
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];
49 return g_quark_from_static_string("tagedit_plugin");
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
)
62 gtk_widget_set_sensitive(browser_box
, TRUE
);
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();
85 gtk_entry_set_text(GTK_ENTRY(entry
), 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
);
100 static mpd_Song
* get_song_from_file(const char *root
, const char *filename
, GError
**error
)
102 TagLib_File
*file
= NULL
;
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
);
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
);
116 file
= taglib_file_new(url
);
117 if(file
&& taglib_file_is_valid(file
))
120 song
= mpd_newSong();
121 song
->file
= g_strdup(filename
);
122 tag
= taglib_file_tag(file
);
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();
144 taglib_file_free(file
);
148 static gboolean
__timeout_mpd_update(gchar
*url
)
150 printf("update: %s\n",url
);
151 mpd_database_update_dir(connection
, url
);
156 static void save_song_to_file(const char *root
, const mpd_Song
*song
)
161 gchar
*url
= g_build_path(G_DIR_SEPARATOR_S
, root
, song
->file
,NULL
);
162 file
= taglib_file_new(url
);
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
);
172 guint track
= (guint
) g_ascii_strtoll(song
->track
, NULL
, 10);
173 taglib_tag_set_track(tag
, track
);
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
);
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
);
201 static void free_si(gpointer data
)
205 if(i
->revert
) mpd_freeSong(i
->revert
);
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
));
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
))
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
)
233 mpd_Song
*edited
= get_song_from_file(root
, song
->file
, &error
);
234 printf("adding: %s\n", song
->file
);
237 si
*i
= g_malloc0(sizeof(*i
));
238 data
= mpd_new_data_struct_append(data
);
239 data
->type
= MPD_DATA_TYPE_SONG
;
242 i
->revert
= mpd_songDup(data
->song
);
244 data
->freefunc
= free_si
;
248 gchar
*errorstr
= g_strdup_printf("%s: %s", _("Tag Edit"), error
->message
);
249 playlist3_show_error_message(errorstr
, ERROR_CRITICAL
);
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
)
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
);
278 if(entry_str
) g_free(entry_str
);
281 static void browser_selection_changed(GtkTreeSelection
*selec
, gpointer data
)
283 GList
*selected
= gtk_tree_selection_get_selected_rows(selec
, &browser_model
);
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);
294 GList
*iter
= g_list_first(selected
);
295 for(;iter
; iter
= g_list_next(iter
))
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);
306 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries
[0]))) == 0)
307 gtk_entry_set_text(GTK_ENTRY(entries
[0]), song
->title
);
311 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries
[1]))) == 0)
312 gtk_entry_set_text(GTK_ENTRY(entries
[1]), song
->artist
);
316 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries
[2]))) == 0)
317 gtk_entry_set_text(GTK_ENTRY(entries
[2]), song
->album
);
321 if(strlen(gtk_entry_get_text(GTK_ENTRY(entries
[3]))) == 0)
322 gtk_entry_set_text(GTK_ENTRY(entries
[3]), song
->genre
);
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
);
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
);
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
);
355 GList
*iter
= g_list_first(selected
);
356 for(;iter
; iter
= g_list_next(iter
))
359 if(gtk_tree_model_get_iter(browser_model
, &titer
, iter
->data
))
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
;
382 GList
*selected
= gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(browser_tree
)), &browser_model
);
385 text
= gtk_entry_get_text(GTK_ENTRY(entry
));
389 value
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry
));
393 GList
*iter
= g_list_first(selected
);
394 for(;iter
; iter
= g_list_next(iter
))
397 if(gtk_tree_model_get_iter(browser_model
, &titer
, iter
->data
))
399 mpd_Song
*song
= NULL
;
401 gtk_tree_model_get(browser_model
, &titer
, MPDDATA_MODEL_COL_MPDSONG
, &song
,MPDDATA_MODEL_USERDATA
, &ud
, -1);
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)
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);
425 ud
->changed
|= (1<<1);
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);
437 ud
->changed
|= (1<<2);
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);
448 ud
->changed
|= (1<<3);
449 gtk_tree_model_row_changed(browser_model
, (GtkTreePath
*)iter
->data
, &titer
);
455 val
= (guint
)g_ascii_strtoll(song
->date
, NULL
, 10);
458 if(song
->date
) g_free(song
->date
);
460 song
->date
= g_strdup_printf("%i", value
);
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);
469 ud
->changed
|= (1<<4);
470 gtk_tree_model_row_changed(browser_model
, (GtkTreePath
*)iter
->data
, &titer
);
476 val
= (guint
)g_ascii_strtoll(song
->track
, NULL
, 10);
479 if(song
->track
) g_free(song
->track
);
481 song
->track
= g_strdup_printf("%i", value
);
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);
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");
507 if(root
&& gtk_tree_model_get_iter_first(browser_model
, &iter
))
510 mpd_Song
*song
= NULL
;
512 gtk_tree_model_get(browser_model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, MPDDATA_MODEL_USERDATA
, &ud
,-1);
515 /* check if song changed */
518 printf("saving: %s\n", song
->file
);
519 save_song_to_file(root
, song
);
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)
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
);
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
);
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
);
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
);
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);
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
);
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));
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));
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));
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));
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
);
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
;
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"),
706 PL3_CAT_ICON_ID
, "gtk-edit",
709 * Clean up old row reference if it exists
713 gtk_tree_row_reference_free(te_ref
);
717 * create row reference
719 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter
);
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
)
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()
743 g_object_unref(browser_box
);
747 g_object_unref(browser_model
);
748 browser_model
= NULL
;
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
);
764 /* Add the browser to the left pane, if there is none to begin with */
767 __browser_add(GTK_WIDGET(playlist3_get_category_tree_view()));
772 /* Remove it from the left pane */
773 GtkTreePath
*path
= gtk_tree_row_reference_get_path(te_ref
);
776 /* for a save of 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
);
787 static void __save_myself(void)
789 /* Save the position in the left tree */
792 GtkTreePath
*path
= gtk_tree_row_reference_get_path(te_ref
);
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
= {
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
,
830 .destroy
= __destroy
,
832 .browser
= &__browser
,
833 .set_enabled
= ___set_enabled
,
834 .get_enabled
= ___get_enabled
,
836 .get_translation_domain
= __get_translation_domain