Modify version string to post-release version 0.18.101
[gmpc.git] / src / gmpc-meta-text-view.gob
blob74efbb9dc1cc84d66415e69fd1e3aac289e6859e
1 /* Gnome M usic Player Client (GMPC)
2  * Copyright (C) 2004-2009 Qball Cow <qball@sarine.nl>
3  * Project homepage: http://gmpc.wikia.com/
4  
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 requires 2.0.0
22 %headertop{
23 #include <gtk/gtk.h>
24 #include <glib/gstdio.h>
25 #include <libmpd/libmpd.h>
26 #include <unistd.h>
27 #include "main.h"
28 #include "misc.h"
30 %ph{
31 #include "vala/gmpc-test-plugin.h"
32 #include "metadata-cache.h"
35 class Gmpc:Meta:Text:View from Gtk:Text:View {
36         private GtkTextBuffer *buffer   = {gtk_text_buffer_new(NULL)} unrefwith g_object_unref;
37         private mpd_Song *song                  = {NULL} destroywith mpd_freeSong;
38         private MetaDataType type                               = {META_ARTIST_TXT};
39         private gulong meta_id                  = {0};
40     private GtkWidget *edit         = {NULL};
41     private GtkWidget *cancel       = {NULL};
42     private MetaData *met = {NULL} destroywith meta_data_free;
44     public gboolean use_monospace       = {FALSE};
46     private gboolean
47     key_press_event(self, GdkEventKey *key, gpointer user_data)
48     {
49         if(key->keyval == GDK_Escape)
50         {
51             if(self->_priv->cancel){
52                 gtk_widget_activate(self->_priv->cancel);
53             }
54             return FALSE;
55         }
56         return FALSE;
57     }
59         init (self)
60         {
61                 gtk_text_view_set_buffer(GTK_TEXT_VIEW(self), self->_priv->buffer);
62                 gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE);
63                 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(self), GTK_WRAP_WORD);
64         g_signal_connect(G_OBJECT(self), "key-press-event", G_CALLBACK(self_key_press_event), NULL);
66                 g_signal_connect(G_OBJECT(self), "populate-popup", G_CALLBACK(self_menu_populate_callback), NULL);
67                 self->_priv->meta_id= g_signal_connect(G_OBJECT(gmw), "data-changed", G_CALLBACK(self_meta_callback), self);
68         }
69         
70         public 
71         GtkWidget * new (int type)
72         {
73                 Self *gmi =  GET_NEW;
74                 gmi->_priv->type = type;
75         gtk_text_buffer_create_tag (gmi->_priv->buffer, "not_editable",
76                 "editable", FALSE, 
77                 NULL);
79         gtk_text_buffer_create_tag (gmi->_priv->buffer, "monospace",
80                 "family", "Monospace",
81                 "family-set", TRUE,
82                 NULL);
83                 return (GtkWidget *)gmi;
84         }
86         private 
87         void
88         menu_populate_callback(self, GtkMenu *menu, gpointer data)
89         {
90                 if(self->_priv->song)
91                 {
92                         GtkWidget *item = gtk_separator_menu_item_new();
93                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
96                         item = gtk_image_menu_item_new_with_label(_("Refetch"));
97                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
98                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_query_refetch),self);
99                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
101                         item = gtk_image_menu_item_new_with_label(_("Select file"));
102                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
103                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_file),self);
104                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
106                         item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR, NULL);
107                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_clear_entry),self);
108                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
110                         item = gtk_image_menu_item_new_with_label(_("Metadata selector"));
111                         gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
112                         g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(self_select_metadata_editor),self);
113                         gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
115                         gtk_widget_show_all(GTK_WIDGET(menu));
116                 }
117         }
119     private void
120     select_metadata_editor(self)
121     {
122                 gmpc_meta_data_edit_window_new(self->_priv->song,self->_priv->type);
123     }
125         public 
126         void
127         query_refetch(self)
128         {
129                 if(self->_priv->song)
130                 {
131                         MetaData *met= NULL;
132                         MetaDataResult ret;
133                         ret = gmpc_meta_watcher_get_meta_path(gmw,self->_priv->song, self->_priv->type|META_QUERY_NO_CACHE, &met);
134                         if(ret == META_DATA_FETCHING) {
135                                 self_set_text_fetching(self);
136                         }else if (ret == META_DATA_AVAILABLE) {
137                 self_set_text_from_metadata(self, met);
138             } else {
139                                 self_set_text_na(self);
140                         }
141                         if(met)
142                         {
143                                 meta_data_free(met);
144                         }
145                 }
146         }
148         public 
149         void
150         query_text_from_song(self, mpd_Song *song)
151     {
152         MetaData *met = NULL;
153         MetaDataResult ret;
155         if(self->_priv->song)
156         {
157             mpd_freeSong(self->_priv->song);
158         }
159         self->_priv->song = mpd_songDup(song);
162         ret = gmpc_meta_watcher_get_meta_path(gmw,self->_priv->song, self->_priv->type, &met);
163         if(ret == META_DATA_FETCHING)
164         {
165             self_set_text_fetching(self);
166         }else if (ret == META_DATA_AVAILABLE) {
167             self_set_text_from_metadata(self,met); 
168         } else {
169             self_set_text_na(self);
170         }
171         if(met)
172         {
173             meta_data_free(met);
174         }
175     }
177     private void
178     cancel_button_clicked(self, GtkWidget *button)
179     {
180         gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE);
181         if(self->_priv->met)
182         {
183             MetaData *met = self->_priv->met;
184             self->_priv->met = NULL;
185             /* Create a copy as self_set_from_path modifies self->_priv->path */
186             self_set_text_from_metadata(self, met);
187             meta_data_free(met);
188         }else self_set_text_na(self);
189     }
191     private void
192     edit_button_clicked(self, GtkWidget *button)
193     {
194         if(gtk_text_view_get_editable(GTK_TEXT_VIEW(self)))
195         {
196             MetaData *met;
197             gchar *content = NULL;
198             GtkTextIter iter_start, iter_end;
200             /* Get start and end of text, and store it */
201             gtk_text_buffer_get_start_iter(self->_priv->buffer, &iter_start);
202             gtk_text_buffer_get_end_iter(self->_priv->buffer, &iter_end);
203             content = gtk_text_buffer_get_text(self->_priv->buffer, &iter_start, &iter_end, FALSE);
204             gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE);
206             /* Copy path, because signal callback my destroy path first */
207             met = meta_data_new();
208             met->plugin_name = "User set";
209             met->type = self->_priv->type;
210             if(content){
211                 met->content_type = META_DATA_CONTENT_TEXT;
212                 met->content = g_strstrip(content);met->size = -1;
213             }else {
214                 met->content_type = META_DATA_CONTENT_EMPTY;
215             }
216             meta_data_set_cache(self->_priv->song, META_DATA_AVAILABLE, met); 
217             gmpc_meta_watcher_data_changed(gmw, self->_priv->song, self->_priv->type, META_DATA_AVAILABLE, met);
218             meta_data_free(met);
220         }else{
221             gtk_widget_show(self->_priv->cancel);
222             gtk_text_view_set_editable(GTK_TEXT_VIEW(self), TRUE);
223             gtk_button_set_label(GTK_BUTTON(button), GTK_STOCK_SAVE);
224         }
226     }
227     private 
228     void
229     set_text(self,const gchar *text, gsize length, int ro)
230     {
231         GtkTextIter iter;
232         GtkTextIter end_iter;
233         gtk_text_buffer_set_text(self->_priv->buffer, text, length);
235         gtk_text_buffer_get_start_iter(self->_priv->buffer, &iter);
236         gtk_text_buffer_get_end_iter(self->_priv->buffer, &end_iter);
237         if(self->use_monospace) {
238             gtk_text_buffer_apply_tag_by_name(self->_priv->buffer, "monospace",&iter, &end_iter);
239         }
240         if(!ro)
241         {
242             GtkTextChildAnchor *anch;
243             self->_priv->edit = gtk_button_new_from_stock(GTK_STOCK_EDIT); 
244             self->_priv->cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); 
246             gtk_text_view_set_editable(GTK_TEXT_VIEW(self), FALSE);
247             gtk_widget_set_no_show_all(self->_priv->cancel, TRUE);
248             /* Add 2 empty lines at the end, and make it non-editable */
249             gtk_text_buffer_get_end_iter(self->_priv->buffer, &end_iter);
250             gtk_text_buffer_insert_with_tags_by_name(self->_priv->buffer, &end_iter, "\n\n", -1,"not_editable", NULL);
252             /* Add edit widget */
253             anch = gtk_text_buffer_create_child_anchor(self->_priv->buffer, &end_iter);
254             gtk_text_buffer_get_iter_at_child_anchor(self->_priv->buffer, &iter,anch);
255             /* Make widget non-editable */
256             gtk_text_buffer_apply_tag_by_name(self->_priv->buffer, "not_editable",&iter, &end_iter);
257             /* attach widget to anchor */
258             gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(self), self->_priv->edit, anch);
260             /* Add edit widget */
261             gtk_text_buffer_get_end_iter(self->_priv->buffer, &end_iter);
262             anch = gtk_text_buffer_create_child_anchor(self->_priv->buffer, &end_iter);
263             gtk_text_buffer_get_iter_at_child_anchor(self->_priv->buffer, &iter,anch);
264             /* Make widget non-editable */
265             gtk_text_buffer_apply_tag_by_name(self->_priv->buffer, "not_editable",&iter, &end_iter);
266             /* attach widget to anchor */
267             gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(self), self->_priv->cancel, anch);
269             /* show button */
270             gtk_widget_show(self->_priv->edit);
271             g_signal_connect_swapped(self->_priv->edit, "clicked",G_CALLBACK(self_edit_button_clicked), self);
272             g_signal_connect_swapped(self->_priv->cancel, "clicked",G_CALLBACK(self_cancel_button_clicked), self);
273         }
274         gtk_text_buffer_get_start_iter(self->_priv->buffer, &iter);
275         gtk_text_buffer_place_cursor(self->_priv->buffer, &iter);
276     }
278         signal last NONE (STRING)       
279         void
280         set_text_from_path(self,const gchar *path)
281         {
282                 gchar *content=NULL;
283                 gsize size = 0;
284                 if(g_file_get_contents (path,&content,&size,NULL))
285                 {
286                         gchar *new_data = NULL;
287                         gsize new_size = 0;
288                         if(g_utf8_validate(content, size, NULL))
289                         {
290                 self_set_text(self, content, size, FALSE);
291                         }
292                         else
293                         {
294                                 new_data = g_locale_to_utf8(content, size, NULL, &new_size, NULL);
295                                 if(new_data)
296                                 {
297                     self_set_text(self, new_data, new_size,FALSE);
298                                         g_free(new_data);
299                                 }
300                                 else
301                                 {
302                                         new_data = g_strdup_printf("%s: '%s' %s", _("Failed to open file:"), path,_("because of encoding issues"));
303                     self_set_text(self, new_data, -1,TRUE);
304                                         g_free(new_data);
305                                 }
306                         }
307                         g_free(content);
308                 }
309         }
311     private
312     void
313     set_text_from_metadata(self, MetaData *met)
314     {
315         if(met->content_type == META_DATA_CONTENT_URI) {
316             const gchar *path = meta_data_get_uri(met);
317             self_set_text_from_path(self, path);
318         }else if(met->content_type == META_DATA_CONTENT_TEXT) {
319             const gchar *text = meta_data_get_text(met);
320             self_set_text(self,text, -1, FALSE); 
321         }else if (met->content_type == META_DATA_CONTENT_HTML) {
322             /* TODO: make utf-8 compatible */
323             const gchar *text = meta_data_get_html(met);
324             if(text)
325             {
326                 /* Get byte length */
327                 gsize length = strlen(text);
328                 gchar *data = g_malloc0(length+1);
329                 gsize i;
330                 int depth=0,j=0;
331                 for(i=0; i<length;i++){
332                     if(text[i] == '<') depth++;
333                     else if(text[i] == '>') depth--;
334                     else if(!depth){
335                         data[j] = text[i];
336                         j++;
337                     }
338                 }
339                 data[j] =  '\0';
340                 self_set_text(self,data, -1, FALSE); 
341                 g_free(data);
342             }else{
343                 self_set_text_na(self);
344             }
345         }
346         if(self->_priv->met) meta_data_free(self->_priv->met);
347         self->_priv->met = meta_data_dup(met);
348     }
349         
350         signal last NONE (NONE) 
351         void
352         set_text_fetching(self)
353         {
354         if(self->_priv->met) meta_data_free(self->_priv->met);
355         self->_priv->met = NULL;
356                 if(self->_priv->type == META_SONG_TXT)
357                 {
358             self_set_text(self, _("Fetching Lyrics"), -1,TRUE);
359                 }
360                 else if (self->_priv->type == META_ARTIST_TXT)
361                 {
362             self_set_text(self, _("Fetching Artist Info"), -1,TRUE);
363                 }
364         else if (self->_priv->type == META_SONG_GUITAR_TAB)
365         {
366             self_set_text(self, _("Fetching Guitar tab"), -1,TRUE);
367         }
368                 else
369                 {
370             self_set_text(self, _("Fetching Album Info"), -1,TRUE);
371                 }
372         }
374         signal last NONE (NONE) 
375         void
376         set_text_na(self)
377         {
378         if(self->_priv->met) meta_data_free(self->_priv->met);
379         self->_priv->met = NULL;
381         self_set_text(self, _("Not Available"), -1,FALSE);
382         }
384         private
385         void
386         meta_callback(GmpcMetaWatcher *mw , mpd_Song *song,  MetaDataType type, MetaDataResult ret, MetaData *met,gpointer data)
387         {
388                 Self *self = data;
389                 /**
390                  * Check for fields
391                  */
392                 if(self->_priv->type != type)
393                         return;
395                 if(!gmpc_meta_watcher_match_data(self->_priv->type, self->_priv->song, song))
396                 {
397                         return;
398                 }
399                 if(ret == META_DATA_AVAILABLE) {
400             self_set_text_from_metadata(self,met); 
401         } else if (ret == META_DATA_FETCHING) {
402                         self_set_text_fetching(self);
403                 } else {
404                         self_set_text_na(self);
405                 }
406         }
407         override (G:Object)
408         void
409         finalize (G:Object *obj)
410         {
412                 PARENT_HANDLER(obj);
413         }
414         override (G:Object)
415         void 
416         dispose (G:Object *obj)
417         {
418                 Self *self = GMPC_META_TEXT_VIEW(obj); 
419                 if(self->_priv->meta_id)
420                 {
421                         g_signal_handler_disconnect(G_OBJECT(gmw),self->_priv->meta_id);
422                         self->_priv->meta_id =  0;
423                 }
425                 PARENT_HANDLER(obj);
426         }
427         public 
428         void
429         clear_entry(self)
430         {
431         MetaData *met = meta_data_new();
432         met->type = self->_priv->type;
433         met->plugin_name = "User set";
434         met->content_type = META_DATA_CONTENT_EMPTY;
435                 meta_data_set_cache(self->_priv->song, META_DATA_UNAVAILABLE, met); 
436                 gmpc_meta_watcher_data_changed(gmw, self->_priv->song, self->_priv->type, META_DATA_UNAVAILABLE, NULL);
437         meta_data_free(met);
438         }
439         public
440         void
441         select_file(self)
442         {
443                 mpd_Song *song = mpd_songDup(self->_priv->song);
444                 MetaDataType type = self->_priv->type;
445                 GtkFileFilter *gff = gtk_file_filter_new();
446                 GtkWidget *fcd = gtk_file_chooser_dialog_new(_("Select File"),NULL,
447                                          GTK_FILE_CHOOSER_ACTION_OPEN,
448                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
449                                       GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
450                                       NULL);
451                 gtk_file_filter_set_name(gff, _("Text Document"));
452                 gtk_file_filter_add_mime_type(gff, "text/plain");
453                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);   
454                 gff = gtk_file_filter_new();
455                 gtk_file_filter_set_name(gff, _("All"));
456                 gtk_file_filter_add_pattern(gff, "*");
457                 gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fcd), gff);   
459                 gtk_widget_show_all(fcd);
460                 switch(gtk_dialog_run(GTK_DIALOG(fcd)))
461                 {
462                         case GTK_RESPONSE_ACCEPT:
463                                 {       
464                                         gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fcd));
465                     MetaData *met = meta_data_new();
466                     met->type = type;
467                     met->plugin_name = "User set";
468                     met->content_type = META_DATA_CONTENT_URI;
469                     met->content = filename; met->size =-1;
470                                         meta_data_set_cache(song, META_DATA_AVAILABLE, met); 
471                                         gmpc_meta_watcher_data_changed(gmw, song, type, META_DATA_AVAILABLE, met);
473                     meta_data_free(met);
474                 }
475             default:
476                                 break;
477                 } 
478                 gtk_widget_destroy(fcd);
479                 mpd_freeSong(song);
481         }