1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
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 private const bool use_transition_tp
= Gmpc
.use_transition
;
26 public class Gmpc
.MetaData
.EditWindow
: Gtk
.Window
28 private const string some_unique_name
= Config
.VERSION
;
29 private MPD
.Song? song
= null;
30 private Gmpc
.MetaData
.Type query_type
= Gmpc
.MetaData
.Type
.ALBUM_ART
;
32 private GLib
.List
<unowned Gmpc
.AsyncDownload
.Handle
> downloads
= null;
33 /** fetching handles */
34 private void *handle
= null;
35 private void *handle2
= null;
37 private Gtk
.HBox pbox
= null;
38 private Gtk
.Label warning_label
= null;
39 private Gtk
.Entry artist_entry
;
40 private Gtk
.Entry album_entry
;
41 private Gtk
.Entry title_entry
;
42 private Gtk
.Button cancel
= null;
43 private Gtk
.Button refresh
= null;
44 private Gtk
.ComboBox combo
= null;
45 private Gtk
.ProgressBar bar
= null;
47 private uint pulse_callback
= 0;
50 private Gtk
.ScrolledWindow sw
= null;
51 private Gtk
.EventBox ilevent
= null;
53 private Gtk
.VBox itemslist
= new Gtk
.VBox(false, 6);
57 this
.type
= Gtk
.WindowType
.TOPLEVEL
;
58 int height
= config
.get_int_with_default(
59 "Metadata Selector" , "window_height", 600);
60 int width
= config
.get_int_with_default(
61 "Metadata Selector" , "window_width", 480);
63 this
.resize(width
,height
);
64 this
.set_border_width(8);
65 /* Connect to allocation changes so I can store new size */
66 this
.size_allocate
.connect((source
, alloc
) => {
68 "Metadata Selector" , "window_width", alloc
.width
);
71 "Metadata Selector" , "window_height", alloc
.height
);
75 private void add_entry_image(Gmpc
.MetaData
.Item met
, string? provider
, string uri
,Gdk
.PixbufFormat? format
, Gdk
.Pixbuf pb
, bool is_raw
= false, bool is_thumbnail
= false)
78 a
= "";// Markup.printf_escaped("<b>%s</b>: %s",_("Uri"),uri);
81 a
+= Markup
.printf_escaped("\n<b>%s</b>: %s",_("Provider"), provider
);
85 a
+= Markup
.printf_escaped("\n<b>%s</b>: %s",_("Filetype"), format
.get_name());
91 a
+="\n<b>%s</b>: %ix%i (%s) (%s)".printf(_("Size"), pb
.width
, pb
.height
,_("width x height"),
92 _("high-res image will be downloaded"));
96 a
+="\n<b>%s</b>: %ix%i (%s)".printf(_("Size"), pb
.width
, pb
.height
,_("width x height"));
101 if(pb
.width
< pb
.height
)
104 new_w
= (int)((150.0/(double)pb
.height
)*pb
.width
);
109 new_h
= (int)((150.0/(double)pb
.width
)*pb
.height
);
113 var hbox
= new Gtk
.HBox(false, 6);
114 var label
= new Gtk
.Label("");
115 label
.set_ellipsize(Pango
.EllipsizeMode
.MIDDLE
);
117 label
.set_line_wrap(true);
118 label
.set_alignment(0.0f
, 0.5f
);
120 var image
= new Gtk
.Image
.from_pixbuf(pb
.scale_simple(new_w
,new_h
,Gdk
.InterpType
.BILINEAR
));
121 image
.set_size_request(180,-1);
122 hbox
.pack_start(image
, false, true, 0);
123 hbox
.pack_start(label
, true, true, 0);
126 var ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
127 var button
= new Gtk
.Button
.with_label(_("Set"));
129 button
.set_data
<Gmpc
.MetaData
.Item
>("metadata", met
.dup());
131 hbox
.pack_start(ali
, false, true, 0);
132 button
.clicked
.connect(set_metadata
);
135 this
.itemslist
.pack_start(hbox
,false, true, 0);
136 var sep
= new Gtk
.HSeparator();
137 sep
.set_size_request(-1, 4);
139 this
.itemslist
.pack_start(sep
, false, true, 0);
143 private void add_entry_text(MetaData
.Item item
, string? provider
, string uri
,string text
)
146 a
= "";// "<b>%s</b>: %s".printf(_("Uri"),uri);
149 a
+="\n<b>%s</b>: %s".printf(_("Provider"), provider
);
151 var hbox
= new Gtk
.HBox(false, 6);
152 var label
= new Gtk
.Label("");
154 label
.set_ellipsize(Pango
.EllipsizeMode
.MIDDLE
);
155 label
.set_line_wrap(true);
156 label
.set_alignment(0.0f
, 0.0f
);
157 label
.set_size_request(280,-1);
158 hbox
.pack_start(label
, false, true, 0);
160 var text_label
= new Gtk
.Label(text
);
161 text_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
162 text_label
.set_alignment(0.0f
, 0.0f
);
163 text_label
.set_size_request(180,-1);
164 hbox
.pack_start(text_label
, true, true, 0);
166 var ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
167 var button
= new Gtk
.Button
.with_label(_("Set"));
168 button
.set_data("lyrics",text
);
169 button
.set_data
<MetaData
.Item
>("metadata", item
.dup());
173 hbox
.pack_start(ali
, false, true, 0);
174 button
.clicked
.connect(set_metadata
);
177 this
.itemslist
.pack_start(hbox
,false, true, 0);
178 var sep
= new Gtk
.HSeparator();
179 sep
.set_size_request(-1, 4);
181 this
.itemslist
.pack_start(sep
, false, true, 0);
184 public void callback(void *handle
,string? plugin_name
,GLib
.List
<MetaData
.Item
>? list
)
186 stdout
.printf("result callback\n");
190 if(this
.handle
== handle
)
193 if(this
.handle
== null && this
.downloads
== null)
196 if(this
.pulse_callback
> 0){
197 GLib
.Source
.remove(this
.pulse_callback
);
198 this
.pulse_callback
= 0;
200 this
.refresh
.sensitive
= true;
201 this
.ilevent
.sensitive
= true;
202 this
.combo
.sensitive
= true;
205 if(this
.handle2
== handle
)
210 if(this
.handle
== null && this
.downloads
== null)
213 if(this
.pulse_callback
> 0){
214 GLib
.Source
.remove(this
.pulse_callback
);
215 this
.pulse_callback
= 0;
217 this
.combo
.sensitive
= true;
218 this
.ilevent
.sensitive
= true;
219 this
.refresh
.sensitive
= true;
223 foreach(unowned MetaData
.Item md
in list
)
226 if(this
.query_type
== Gmpc
.MetaData
.Type
.ALBUM_ART
|| this
.query_type
== Gmpc
.MetaData
.Type
.ARTIST_ART
||
227 this
.query_type
== Gmpc
.MetaData
.Type
.BACKDROP_ART
)
229 if (md
.content_type
== Gmpc
.MetaData
.ContentType
.RAW
)
231 var data
= md
.get_raw();
232 var load
= new Gdk
.PixbufLoader();
239 GLib
.debug("Failed to load raw data: %s\n",e
.message
);
247 GLib
.debug("Failed to close loader: %s\n",e
.message
);
250 Gdk
.Pixbuf pb
= load
.get_pixbuf();
253 var base16
= GLib
.Base64
.encode(data
);
254 this
.add_entry_image(md
, md
.plugin_name
,base16
,load
.get_format(),pb
,true);
261 if(md
.content_type
== Gmpc
.MetaData
.ContentType
.TEXT
)
263 unowned
string uri
= md
.get_text();
264 add_entry_text(md
, md
.plugin_name
, "n/a", uri
);
266 else if(md
.content_type
== Gmpc
.MetaData
.ContentType
.HTML
)
268 string uri
= md
.get_text_from_html();
269 add_entry_text(md
, md
.plugin_name
, "n/a", uri
);
271 else if(md
.content_type
== Gmpc
.MetaData
.ContentType
.URI
)
273 unowned
string uri
= md
.get_uri();
279 if(GLib
.FileUtils
.get_contents(uri
,out content
))
281 add_entry_text(md
, md
.plugin_name
,uri
, content
);
297 set_metadata(Gtk
.Button button
)
299 unowned MetaData
.Item? item
= button
.get_data
<MetaData
.Item
>("metadata");
302 Gmpc
.MetaData
.set_metadata(this
.song
, item
);
307 destroy_popup(Gtk
.Button button
)
311 private void clear_itemslist()
313 foreach(Gtk
.Widget client
in this
.itemslist
.get_children())
319 public void refresh_query(Gtk
.Button button
)
322 GLib
.log("MetadataSelector", GLib
.LogLevelFlags
.LEVEL_DEBUG
, "Query metadata");
323 MPD
.Song ss
= this
.song
.copy();
324 ss
.artist
= this
.artist_entry
.get_text();
325 ss
.album
= this
.album_entry
.get_text();
326 ss
.title
= this
.title_entry
.get_text();
328 if(this
.handle
== null && this
.handle2
== null)
331 if(this
.pulse_callback
> 0){
332 GLib
.Source
.remove(this
.pulse_callback
);
333 this
.pulse_callback
= 0;
335 this
.pulse_callback
= GLib
.Timeout
.add(300, () => {
336 if(this
.bar
== null) return false;
340 this
.refresh
.sensitive
= false;
341 this
.combo
.sensitive
= false;
342 this
.ilevent
.sensitive
= false;
343 GLib
.log("MetadataSelector", GLib
.LogLevelFlags
.LEVEL_DEBUG
,"Start metdata get_list query");
344 this
.handle
= Gmpc
.MetaData
.get_list(ss
, this
.query_type
, callback);
345 GLib
.log("MetadataSelector", GLib
.LogLevelFlags
.LEVEL_DEBUG
,"Wait");
349 private void combo_box_changed(Gtk
.ComboBox comb
)
352 int active
= comb
.active
;
353 this
.title_entry
.sensitive
= false;
354 this
.album_entry
.sensitive
= false;
355 this
.artist_entry
.sensitive
= false;
356 this
.refresh
.sensitive
= false;
357 this
.warning_label
.hide();
360 this
.query_type
= Gmpc
.MetaData
.Type
.ARTIST_ART
;
361 if(this
.song
.artist
!= null)
363 this
.artist_entry
.sensitive
= true;
364 this
.refresh
.sensitive
= true;
366 else this
.warning_label
.show();
368 else if (active
== 1)
370 this
.query_type
= Gmpc
.MetaData
.Type
.ALBUM_ART
;
372 if(this
.song
.artist
!= null && this
.song
.album
!= null)
374 this
.artist_entry
.sensitive
= true;
375 this
.album_entry
.sensitive
= true;
376 this
.refresh
.sensitive
= true;
378 else this
.warning_label
.show();
380 else if (active
== 2)
382 this
.query_type
= Gmpc
.MetaData
.Type
.SONG_TXT
;
384 if(this
.song
.artist
!= null && this
.song
.title
!= null)
386 this
.artist_entry
.sensitive
= true;
387 this
.title_entry
.sensitive
= true;
388 this
.refresh
.sensitive
= true;
390 else this
.warning_label
.show();
392 else if (active
== 3)
394 this
.query_type
= Gmpc
.MetaData
.Type
.ALBUM_TXT
;
396 if(this
.song
.artist
!= null && this
.song
.album
!= null)
398 this
.artist_entry
.sensitive
= true;
399 this
.album_entry
.sensitive
= true;
400 this
.refresh
.sensitive
= true;
402 else this
.warning_label
.show();
404 else if (active
== 4)
406 this
.query_type
= Gmpc
.MetaData
.Type
.ARTIST_TXT
;
408 if(this
.song
.artist
!= null)
410 this
.artist_entry
.sensitive
= true;
411 this
.refresh
.sensitive
= true;
413 else this
.warning_label
.show();
415 else if (active
== 5)
417 this
.query_type
= Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
;
419 if(this
.song
.artist
!= null && this
.song
.title
!= null)
421 this
.artist_entry
.sensitive
= true;
422 this
.title_entry
.sensitive
= true;
423 this
.refresh
.sensitive
= true;
425 else this
.warning_label
.show();
427 else if ( active
== 6)
429 this
.query_type
= Gmpc
.MetaData
.Type
.BACKDROP_ART
;
430 if(this
.song
.artist
!= null)
432 this
.artist_entry
.sensitive
= true;
433 this
.refresh
.sensitive
= true;
435 else this
.warning_label
.show();
440 EditWindow (MPD
.Song song
, Gmpc
.MetaData
.Type type
)
442 var vbox
= new Gtk
.VBox(false, 6);
443 this
.song
= song
.copy();
444 this
.query_type
= type
;
445 this
.pbox
= new Gtk
.HBox(false, 6);
446 this
.bar
= new Gtk
.ProgressBar();
447 vbox
.pack_start(this
.pbox
, false, false, 0);
448 this
.cancel
= new Gtk
.Button
.from_stock("gtk-cancel");
449 this
.cancel
.clicked
.connect(this
.b_cancel
);
450 this
.pbox
.pack_start(this
.bar
, true, true, 0);
451 this
.pbox
.pack_start(this
.cancel
, false, false, 0);
454 this
.pbox
.no_show_all
= true;
456 if(this
.pulse_callback
> 0){
457 GLib
.Source
.remove(this
.pulse_callback
);
458 this
.pulse_callback
= 0;
461 sw
= new Gtk
.ScrolledWindow(null, null);
463 sw
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
464 sw
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
468 var hbox
= new Gtk
.HBox(false, 6);
470 var button
= new Gtk
.Button
.from_stock("gtk-quit");
471 button
.clicked
.connect(destroy_popup
);
472 hbox
.pack_end(button
, false, false, 0);
473 vbox
.pack_end(hbox
, false, false,0);
476 this
.warning_label
= new Gtk
.Label("");
477 this
.warning_label
.set_markup("<span size='x-large'>%s</span>".printf(_("Insufficient information to store/fetch this metadata")));
478 this
.warning_label
.set_alignment(0.0f
, 0.5f
);
479 vbox
.pack_start(this
.warning_label
, false, false, 0);
480 this
.warning_label
.hide();
482 var group
= new Gtk
.SizeGroup(Gtk
.SizeGroupMode
.HORIZONTAL
);
483 var qhbox
= new Gtk
.HBox(false, 6);
484 Gtk
.Label label
= null;
486 var list
= new Gtk
.ListStore(2,typeof(string), typeof(string),-1);
487 list
.insert_with_values(null, -1, 0, "media-artist", 1, _("Artist art"));
488 list
.insert_with_values(null, -1, 0, "media-album", 1, _("Album art"));
489 list
.insert_with_values(null, -1, 0, "gtk-dnd", 1, _("Song lyrics"));
490 list
.insert_with_values(null, -1, 0, "media-album", 1, _("Album Info"));
491 list
.insert_with_values(null, -1, 0, "media-artist", 1, _("Artist Biography"));
492 list
.insert_with_values(null, -1, 0, "media-album", 1, _("Guitar Tab"));
493 list
.insert_with_values(null, -1, 0, "media-artist", 1, _("Backdrop"));
495 this
.combo
= new Gtk
.ComboBox
.with_model(list
);
497 Gtk
.CellRenderer renderer
= new Gtk
.CellRendererPixbuf();
498 this
.combo
.pack_start(renderer
,false);
499 this
.combo
.add_attribute(renderer
, "icon-name", 0);
500 renderer
= new Gtk
.CellRendererText();
501 this
.combo
.pack_start(renderer
,true);
502 this
.combo
.add_attribute(renderer
, "text", 1);
504 qhbox
.pack_start(this
.combo
, true,true,0);
505 this
.combo
.changed
.connect(combo_box_changed
);
507 vbox
.pack_start(qhbox
, false, false, 0);
510 qhbox
= new Gtk
.HBox(false, 6);
512 label
= new Gtk
.Label(_("Artist"));
513 label
.set_alignment(0.0f
, 0.5f
);
514 group
.add_widget(label
);
515 qhbox
.pack_start(label
, false, false, 0);
516 var image
= new Gtk
.Image
.from_icon_name("media-artist", Gtk
.IconSize
.BUTTON
);
517 qhbox
.pack_start(image
, false, false, 0);
519 this
.artist_entry
= new Gtk
.Entry();
520 this
.artist_entry
.set_text(song
.artist
);
521 qhbox
.pack_start(this
.artist_entry
, true, true, 0);
522 vbox
.pack_start(qhbox
, false, false, 0);
524 qhbox
= new Gtk
.HBox(false, 6);
525 label
= new Gtk
.Label(_("Album"));
526 label
.set_alignment(0.0f
, 0.5f
);
527 group
.add_widget(label
);
528 qhbox
.pack_start(label
, false, false, 0);
529 image
= new Gtk
.Image
.from_icon_name("media-album", Gtk
.IconSize
.BUTTON
);
530 qhbox
.pack_start(image
, false, false, 0);
531 this
.album_entry
= new Gtk
.Entry();
532 if(song
.album
!= null)
533 this
.album_entry
.set_text(song
.album
);
534 qhbox
.pack_start(this
.album_entry
, true, true, 0);
535 vbox
.pack_start(qhbox
, false, false, 0);
537 qhbox
= new Gtk
.HBox(false, 6);
538 label
= new Gtk
.Label(_("Title"));
539 label
.set_alignment(0.0f
, 0.5f
);
540 group
.add_widget(label
);
541 qhbox
.pack_start(label
, false, false, 0);
542 image
= new Gtk
.Image
.from_icon_name("media-audiofile", Gtk
.IconSize
.BUTTON
);
543 qhbox
.pack_start(image
, false, false, 0);
544 this
.title_entry
= new Gtk
.Entry();
545 if(song
.title
!= null)
546 this
.title_entry
.set_text(song
.title
);
547 qhbox
.pack_start(this
.title_entry
, true, true, 0);
549 vbox
.pack_start(qhbox
, false, false, 0);
551 if(type
!= Gmpc
.MetaData
.Type
.ALBUM_ART
|| type
!= Gmpc
.MetaData
.Type
.BACKDROP_ART
)
552 this
.album_entry
.sensitive
= false;
555 this
.refresh
= button
= new Gtk
.Button
.with_label(_("Query"));
556 var ali
= new Gtk
.Alignment(1.0f
, 0.5f
, 0.0f
, 0.0f
);
558 vbox
.pack_start(ali
, false, false, 0);
559 button
.clicked
.connect(refresh_query
);
563 vbox
.pack_start(sw
, true, true,0);
565 this
.hide_on_delete();
567 ilevent
= new Gtk
.EventBox();
568 this
.itemslist
.border_width
= 8;
569 ilevent
.visible_window
= true;
570 ilevent
.modify_bg(Gtk
.StateType
.NORMAL
,this
.style
.base[Gtk
.StateType
.NORMAL
]);
571 this
.style_set
.connect((source
, old
) =>
573 this
.itemslist
.get_parent().modify_bg(Gtk
.StateType
.NORMAL
,this
.style
.base[Gtk
.StateType
.NORMAL
]);
575 ilevent
.add(itemslist
);
576 sw
.add_with_viewport(ilevent
);
579 if(type
== Gmpc
.MetaData
.Type
.ARTIST_ART
) this
.combo
.set_active(0);
580 else if(type
== Gmpc
.MetaData
.Type
.ALBUM_ART
) this
.combo
.set_active(1);
581 else if(type
== Gmpc
.MetaData
.Type
.SONG_TXT
) this
.combo
.set_active(2);
582 else if(type
== Gmpc
.MetaData
.Type
.ALBUM_TXT
) this
.combo
.set_active(3);
583 else if(type
== Gmpc
.MetaData
.Type
.ARTIST_TXT
)this
.combo
.set_active(4);
584 else if(type
== Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
)this
.combo
.set_active(5);
585 else if(type
== Gmpc
.MetaData
.Type
.BACKDROP_ART
)this
.combo
.set_active(6);
587 refresh_query(button
);
589 public void b_cancel()
591 if(this
.handle
!= null)
593 Gmpc
.MetaData
.get_list_cancel(this
.handle
);
596 if(this
.handle2
!= null)
598 Gmpc
.MetaData
.get_list_cancel(this
.handle2
);
601 this
.downloads
.first();
602 while(this
.downloads
!= null)
604 unowned Gmpc
.AsyncDownload
.Handle handle
= this
.downloads
.data
;
607 this
.downloads
.first();
611 if(this
.pulse_callback
> 0){
612 GLib
.Source
.remove(this
.pulse_callback
);
613 this
.pulse_callback
= 0;
615 this
.refresh
.sensitive
= true;
616 this
.combo
.sensitive
= true;