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.
21 * This plugin consists of 3 parts
22 * Metadata2 plugin: Implements metadata 2 browser.
23 * Now Playing plugin: Reusing the metadata 2 browser it implements a now playing browser.
24 * Custom widget, there are some custom widgets used by the metadata 2 browser
27 * * More. (expands, collapses a sub widget
34 private const bool use_transition_mdb
= Gmpc
.use_transition
;
35 private const string some_unique_name_mdb
= Config
.VERSION
;
37 public class Gmpc
.Browsers
.Metadata
: Gmpc
.Plugin
.Base
, Gmpc
.Plugin
.BrowserIface
39 private int block_update
= 0;
40 /* Stores the location in the cat_tree */
41 private Gtk
.TreeRowReference rref
= null;
43 private string title_color
= config
.get_string_with_default("Now Playing", "title-color", "#4d90dd");
44 private string item_color
= config
.get_string_with_default("Now Playing", "item-color", "#304ab8");
45 private bool theme_colors
= (bool) config
.get_int_with_default("Now Playing", "use-theme-color",1);
46 private Gdk
.Color background
;
47 private Gdk
.Color foreground
;
50 private void show_metadata_search()
57 /* Set the plugin as an internal one and of type pl_browser */
58 this
.plugin_type
= 2|8;
60 gmpcconn
.connection_changed
.connect(con_changed
);
61 gmpcconn
.status_changed
.connect(status_changed
);
64 var background
= config
.get_string_with_default("Now Playing", "background-color", "#000");
65 var foreground
= config
.get_string_with_default("Now Playing", "foreground-color", "#FFF");
66 Gdk
.Color
.parse(background
,out this
.background
);
67 Gdk
.Color
.parse(foreground
,out this
.foreground
);
69 easy_command
.add_entry(
72 _("Switch to Metadata view"),
73 (Gmpc
.Easy
.Command
.Callback
*)show_metadata_search
,
77 private const int[] version
= {0,0,0};
78 public override unowned
int[] get_version()
83 public override unowned
string get_name()
85 return N_("Metadata Browser");
88 public override void save_yourself()
90 if(this
.paned
!= null)
92 int pos
= this
.paned
.get_position();
93 config
.set_int(this
.get_name(), "pane-pos", pos
);
96 if(this
.model_artist
!= null) this
.model_artist
.set_mpd_data(null);
97 if(this
.model_albums
!= null)this
.model_albums
.set_mpd_data(null);
101 var path
= rref
.get_path();
104 unowned
int[] indices
= path
.get_indices();
105 config
.set_int(this
.get_name(), "position", indices
[0]);
109 /* Now playing browser */
116 private Gtk
.Paned paned
= null;
117 /* holding the 3 browsers */
118 private Gtk
.Box browser_box
= null;
121 private Gtk
.TreeView tree_artist
= null;
122 private Gmpc
.MpdData
.Model model_artist
= null;
123 private Gtk
.TreeModelFilter model_filter_artist
= null;
124 private Gtk
.Entry artist_filter_entry
= null;
127 private Gtk
.TreeView tree_album
= null;
128 private Gmpc
.MpdData
.Model model_albums
= null;
129 private Gtk
.TreeModelFilter model_filter_album
= null;
130 private Gtk
.Entry album_filter_entry
= null;
133 private Gtk
.TreeView tree_songs
= null;
134 private Gmpc
.MpdData
.Model model_songs
= null;
136 /* The right hand "browser" box */
137 private Gtk
.ScrolledWindow metadata_sw
= null;
138 private Gtk
.EventBox metadata_box
= null;
140 private Gtk
.EventBox header
= null;
143 * Makes gmpc jump to the metadata browser
145 private void select_metadata_browser(Gtk
.Widget widget
)
147 this
.select_browser(null);
150 * Makes gmpc jump to the metadata browser
153 private void select_metadata_browser_search(Gtk
.Widget widget
)
155 select_browser(null);
159 * Gmpc.Plugin.BrowserIface.add_go_menu
161 private int browser_add_go_menu(Gtk
.Menu menu
)
163 if(this
.get_enabled())
165 var item
= new Gtk
.ImageMenuItem
.with_mnemonic(_(this
.get_name()));
166 item
.set_image(new Gtk
.Image
.from_icon_name("gmpc-metabrowser", Gtk
.IconSize
.MENU
));
167 item
.activate
.connect(select_metadata_browser
);
168 item
.add_accelerator("activate", menu
.get_accel_group(),0xffc1,0, Gtk
.AccelFlags
.VISIBLE
);
171 item
= new Gtk
.ImageMenuItem
.with_mnemonic(_("Search metadata"));
172 item
.set_image(new Gtk
.Image
.from_stock("gtk-find", Gtk
.IconSize
.MENU
));
173 item
.activate
.connect(select_metadata_browser_search
);
174 item
.add_accelerator("activate", menu
.get_accel_group(),
175 0x04d,Gdk
.ModifierType
.CONTROL_MASK
,
176 Gtk
.AccelFlags
.VISIBLE
);
185 * This builds the browser
187 /* This hack makes clicking a selected row again, unselect it */
188 private bool browser_button_press_event(Gtk
.Widget treel
, Gdk
.EventButton event
)
190 var tree
= (treel as Gtk
.TreeView
);
191 Gtk
.TreePath path
= null;
192 if(event
.button
!= 1) return false;
193 if(tree
.get_path_at_pos((int)event
.x
,(int)event
.y
,out path
, null, null, null))
195 if(tree
.get_selection().path_is_selected(path
))
197 tree
.get_selection().unselect_path(path
);
204 * Artist tree view functions */
205 private void browser_artist_entry_changed(Gtk
.Editable entry
)
207 string text
= (entry as Gtk
.Entry
).get_text();
210 (entry as Gtk
.Widget
).show();
211 (entry as Gtk
.Widget
).grab_focus();
215 (entry as Gtk
.Widget
).hide();
216 this
.tree_artist
.grab_focus();
218 this
.model_filter_artist
.refilter();
220 /* Handle right mouse click */
221 private bool artist_browser_button_release_event(Gtk
.Widget treel
, Gdk
.EventButton event
)
223 var tree
= (treel as Gtk
.TreeView
);
224 if(event
.button
== 3)
226 if(tree
.get_selection().count_selected_rows()>0)
228 var menu
= new Gtk
.Menu();
229 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
230 item
.activate
.connect((source
) =>
234 if(tree
.get_selection().get_selected(out model
, out iter
))
237 model
.get(iter
,7, out artist
);
240 MPD
.Database
.search_start(server
,true);
241 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
242 MPD
.Data
.Item data
= MPD
.Database
.search_commit(server
);
243 data
.sort_album_disc_track();
249 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
253 MPD
.PlayQueue
.queue_commit(server
);
260 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
261 item
.activate
.connect((source
) =>
265 if(tree
.get_selection().get_selected(out model
, out iter
))
268 model
.get(iter
,7, out artist
);
271 MPD
.PlayQueue
.clear(server
);
272 MPD
.PlayQueue
.add_artist(server
, artist
);
273 MPD
.Player
.play(server
);
279 menu
.popup(null, null, null, event
.button
, event
.time
);
288 private bool visible_func_artist (Gtk
.TreeModel model
, Gtk
.TreeIter iter
)
290 string text
= this
.artist_filter_entry
.get_text();
291 /* Visible if row is non-empty and first column is "HI" */
293 bool visible
= false;
295 if(text
[0] == '\0') return true;
297 model
.get (iter
, 7, out str
, -1);
298 if (str
!= null && str
.casefold().normalize().index_of(text
.casefold().normalize()) >= 0)
303 private bool browser_artist_key_press_event(Gtk
.Widget widget
, Gdk
.EventKey event
)
305 unichar uc
= Gdk
.keyval_to_unicode(event
.keyval
);
309 int i
= uc
.to_utf8(outbuf
);
310 ((char[])outbuf
)[i
] = '\0';
311 this
.artist_filter_entry
.set_text(outbuf
);
312 this
.artist_filter_entry
.grab_focus();
313 this
.artist_filter_entry
.set_position(1);
322 private void album_add_clicked(Gtk
.Widget item
)
324 string artist
= browser_get_selected_artist();
327 string albumartist
= null;
328 string album
= browser_get_selected_album();
329 if(album
!= null && Gmpc
.server
.tag_supported(MPD
.Tag
.Type
.ALBUM_ARTIST
))
331 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
);
332 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
333 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
334 var ydata
= MPD
.Database
.search_commit(server
);
337 if(ydata
.tag
.length
> 0)
338 albumartist
= ydata
.tag
;
341 /* Fill in the first browser */
342 MPD
.Database
.search_start(server
,true);
343 if(albumartist
!= null && albumartist
.length
> 0)
344 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
, albumartist
);
346 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
349 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
350 var data
= MPD
.Database
.search_commit(server
);
352 data
.sort_album_disc_track();
357 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
361 MPD
.PlayQueue
.queue_commit(server
);
365 private void album_replace_clicked(Gtk
.Widget item
)
367 MPD
.PlayQueue
.clear(server
);
368 album_add_clicked(item
);
369 MPD
.Player
.play(server
);
371 /* Handle right mouse click */
372 private bool album_browser_button_release_event(Gtk
.Widget tree
, Gdk
.EventButton event
)
374 if(event
.button
== 3)
376 if((tree as Gtk
.TreeView
).get_selection().count_selected_rows()>0)
378 var menu
= new Gtk
.Menu();
379 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
380 item
.activate
.connect(album_add_clicked
);
383 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
384 item
.activate
.connect(album_replace_clicked
);
387 menu
.popup(null, null, null, event
.button
, event
.time
);
395 private bool visible_func_album (Gtk
.TreeModel model
, Gtk
.TreeIter iter
)
397 string text
= this
.album_filter_entry
.get_text();
398 /* Visible if row is non-empty and first column is "HI" */
400 bool visible
= false;
402 if(text
[0] == '\0') return true;
404 model
.get (iter
, 6, out str
, -1);
405 if (str
!= null && str
.casefold().normalize().index_of(text
.casefold().normalize()) >= 0)
412 private bool browser_album_key_press_event(Gtk
.Widget widget
, Gdk
.EventKey event
)
414 unichar uc
= Gdk
.keyval_to_unicode(event
.keyval
);
418 int i
= uc
.to_utf8(outbuf
);
419 ((char[])outbuf
)[i
] = '\0';
420 this
.album_filter_entry
.set_text(outbuf
);
421 this
.album_filter_entry
.grab_focus();
422 this
.album_filter_entry
.set_position(1);
429 private void browser_album_entry_changed(Gtk
.Editable pentry
)
431 Gtk
.Entry entry
= (pentry as Gtk
.Entry
);
432 string text
= entry
.get_text();
441 this
.tree_album
.grab_focus();
443 this
.model_filter_album
.refilter();
448 private void song_add_clicked(Gtk
.Widget item
)
450 unowned MPD
.Song? song
= browser_get_selected_song();
453 MPD
.PlayQueue
.add_song(server
,song
.file
);
456 private void song_replace_clicked(Gtk
.Widget item
)
458 MPD
.PlayQueue
.clear(server
);
459 song_add_clicked(item
);
460 MPD
.Player
.play(server
);
462 /* Handle right mouse click */
463 private bool song_browser_button_release_event(Gtk
.Widget ptree
, Gdk
.EventButton event
)
465 Gtk
.TreeView tree
= (ptree as Gtk
.TreeView
);
466 if(event
.button
== 3)
468 if(tree
.get_selection().count_selected_rows()>0)
470 var menu
= new Gtk
.Menu();
471 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
472 item
.activate
.connect(song_add_clicked
);
475 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
476 item
.activate
.connect(song_replace_clicked
);
479 menu
.popup(null, null, null, event
.button
, event
.time
);
487 private bool browser_button_release_event(Gtk
.Widget widget
, Gdk
.EventButton event
)
489 if(event
.button
== 8)
494 else if (event
.button
== 9)
501 private void browser_init()
503 if(this
.paned
== null)
505 this
.paned
= new Gtk
.HPaned();
506 paned_size_group
.add_paned(this
.paned
);
507 /* Bow with browsers */
508 this
.browser_box
= new Gtk
.VBox(true, 6);
509 this
.paned
.add1(this
.browser_box
);
513 var box
= new Gtk
.VBox(false, 6);
514 this
.browser_box
.pack_start(box
, true, true, 0);
516 this
.artist_filter_entry
= new Gtk
.Entry();
518 this
.artist_filter_entry
.set_icon_from_stock(Gtk
.EntryIconPosition
.SECONDARY
, "gtk-clear");
519 this
.artist_filter_entry
.icon_press
.connect((source
, pos
, event
)=>
521 if(pos
== Gtk
.EntryIconPosition
.SECONDARY
) source
.set_text("");
524 this
.artist_filter_entry
.set_no_show_all(true);
525 this
.artist_filter_entry
.changed
.connect(browser_artist_entry_changed
);
527 box
.pack_start(this
.artist_filter_entry
, false, false, 0);
529 var sw
= new Gtk
.ScrolledWindow(null, null);
530 sw
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
531 sw
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
532 box
.pack_start(sw
, true, true, 0);
534 this
.model_artist
= new Gmpc
.MpdData
.Model();
535 this
.model_filter_artist
= new Gtk
.TreeModelFilter(this
.model_artist
, null);
536 this
.model_filter_artist
.set_visible_func(visible_func_artist
);
537 this
.tree_artist
= new Gtk
.TreeView
.with_model(this
.model_filter_artist
);
538 this
.tree_artist
.rules_hint
= true;
539 new Gmpc
.MpdData
.Treeview
.Tooltip(this
.tree_artist
, Gmpc
.MetaData
.Type
.ARTIST_ART
);
541 this
.tree_artist
.set_enable_search(false);
542 this
.tree_artist
.button_press_event
.connect(browser_button_press_event
);
543 this
.tree_artist
.button_release_event
.connect(artist_browser_button_release_event
);
544 this
.tree_artist
.key_press_event
.connect(browser_artist_key_press_event
);
546 /* setup the columns */
547 var column
= new Gtk
.TreeViewColumn();
548 if(config
.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
550 var prenderer
= new Gtk
.CellRendererPixbuf();
551 prenderer
.set("height", this
.model_artist
.icon_size
);
552 column
.pack_start(prenderer
, false);
553 column
.add_attribute(prenderer
, "pixbuf",27);
555 var trenderer
= new Gtk
.CellRendererText();
556 column
.pack_start(trenderer
, true);
557 column
.add_attribute(trenderer
, "text", 7);
558 this
.tree_artist
.append_column(column
);
559 column
.set_title(_("Artist"));
560 this
.tree_artist
.get_selection().changed
.connect(browser_artist_changed
);
562 /* set fixed height mode */
563 column
.sizing
= Gtk
.TreeViewColumnSizing
.FIXED
;
564 this
.tree_artist
.set_fixed_height_mode(true);
569 box
= new Gtk
.VBox(false, 6);
570 this
.browser_box
.pack_start(box
, true, true, 0);
573 this
.album_filter_entry
= new Gtk
.Entry();
575 this
.album_filter_entry
.set_icon_from_stock(Gtk
.EntryIconPosition
.SECONDARY
, "gtk-clear");
576 this
.album_filter_entry
.icon_press
.connect((source
, pos
, event
)=>
578 if(pos
== Gtk
.EntryIconPosition
.SECONDARY
) source
.set_text("");
580 this
.album_filter_entry
.set_no_show_all(true);
581 this
.album_filter_entry
.changed
.connect(browser_album_entry_changed
);
582 box
.pack_start(this
.album_filter_entry
, false, false, 0);
584 sw
= new Gtk
.ScrolledWindow(null, null);
585 sw
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
586 sw
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
587 box
.pack_start(sw
, true, true, 0);
588 this
.model_albums
= new Gmpc
.MpdData
.Model();
589 this
.model_filter_album
= new Gtk
.TreeModelFilter(this
.model_albums
, null);
590 this
.model_filter_album
.set_visible_func(visible_func_album
);
591 this
.tree_album
= new Gtk
.TreeView
.with_model(this
.model_filter_album
);
592 this
.tree_album
.rules_hint
= true;
593 this
.tree_album
.set_enable_search(false);
594 new Gmpc
.MpdData
.Treeview
.Tooltip(this
.tree_album
, Gmpc
.MetaData
.Type
.ALBUM_ART
);
596 this
.tree_album
.button_press_event
.connect(browser_button_press_event
);
597 this
.tree_album
.button_release_event
.connect(album_browser_button_release_event
);
598 this
.tree_album
.key_press_event
.connect(browser_album_key_press_event
);
600 /* setup the columns */
601 column
= new Gtk
.TreeViewColumn();
602 if(config
.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
604 var prenderer
= new Gtk
.CellRendererPixbuf();
605 prenderer
.set("height", this
.model_albums
.icon_size
);
606 column
.pack_start(prenderer
, false);
607 column
.add_attribute(prenderer
, "pixbuf",27);
609 this
.tree_album
.append_column(column
);
611 column
= new Gtk
.TreeViewColumn();
612 trenderer
= new Gtk
.CellRendererText();
613 column
.pack_start(trenderer
, true);
614 column
.add_attribute(trenderer
, "text", 14);
615 this
.tree_album
.append_column(column
);
616 column
.set_title(_("Year"));
618 column
= new Gtk
.TreeViewColumn();
619 trenderer
= new Gtk
.CellRendererText();
620 column
.pack_start(trenderer
, true);
621 column
.add_attribute(trenderer
, "text", 6);
622 this
.tree_album
.append_column(column
);
623 column
.set_title(_("Album"));
626 this
.tree_album
.get_selection().changed
.connect(browser_album_changed
);
629 sw
= new Gtk
.ScrolledWindow(null, null);
630 sw
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
631 sw
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
632 this
.browser_box
.pack_start(sw
, true, true, 0);
633 this
.model_songs
= new Gmpc
.MpdData
.Model();
634 this
.tree_songs
= new Gtk
.TreeView
.with_model(this
.model_songs
);
635 this
.tree_songs
.rules_hint
= true;
636 this
.tree_songs
.button_press_event
.connect(browser_button_press_event
);
637 this
.tree_songs
.button_release_event
.connect(song_browser_button_release_event
);
639 /* setup the columns */
640 column
= new Gtk
.TreeViewColumn();
642 if(config
.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
644 var prenderer
= new Gtk
.CellRendererPixbuf();
645 column
.pack_start(prenderer
, false);
646 column
.add_attribute(prenderer
, "icon-name",23);
648 trenderer
= new Gtk
.CellRendererText();
649 column
.pack_start(trenderer
, false);
650 column
.add_attribute(trenderer
, "text", 10);
652 column
.set_title(_("Track"));
653 this
.tree_songs
.append_column(column
);
655 column
= new Gtk
.TreeViewColumn();
656 trenderer
= new Gtk
.CellRendererText();
657 column
.pack_start(trenderer
, true);
658 column
.add_attribute(trenderer
, "text", 7);
661 this
.tree_songs
.append_column(column
);
662 this
.tree_songs
.set_search_column(7);
663 column
.set_title(_("Songs"));
665 this
.tree_songs
.get_selection().changed
.connect(browser_songs_changed
);
668 this
.metadata_sw
= new Gtk
.ScrolledWindow(null, null);
669 this
.metadata_sw
.set_policy(Gtk
.PolicyType
.AUTOMATIC
, Gtk
.PolicyType
.AUTOMATIC
);
670 this
.metadata_sw
.set_shadow_type(Gtk
.ShadowType
.ETCHED_IN
);
672 this
.metadata_box
= new Gtk
.EventBox();
673 this
.metadata_box
.set_visible_window(true);
674 this
.metadata_sw
.add_with_viewport(this
.metadata_box
);
675 (this
.metadata_box as Gtk
.Container
).set_focus_hadjustment(
676 this
.metadata_sw
.get_hadjustment());
677 (this
.metadata_box as Gtk
.Container
).set_focus_vadjustment(
678 this
.metadata_sw
.get_vadjustment());
682 var vb
= new Gtk
.VBox(false, 0);
683 vb
.pack_end(this
.metadata_sw
, true,true,0);
685 this
.metadata_box
.get_style_context().add_class(Gtk
.STYLE_CLASS_VIEW
);
687 this
.header
= new Gtk
.EventBox();
689 this
.header
.get_style_context().add_class(Gtk
.STYLE_CLASS_HIGHLIGHT
);
692 var sp
= new Gtk
.Separator(Gtk
.Orientation
.HORIZONTAL
);
693 sp
.set_size_request(-1, 1);
694 vb
.pack_start(sp
, false, false, 0);
695 vb
.pack_start(header
, false, false,0);
702 this
.paned
.button_release_event
.connect(browser_button_release_event
);
704 this
.reload_browsers();
706 this
.paned
.show_all();
708 if(config
.get_int_with_default("metadata browser", "show-browsers", 1) == 0)
710 this
.browser_box
.hide();
714 private void reload_browsers()
716 if(this
.paned
== null) return;
718 this
.model_songs
.set_mpd_data(null);
719 this
.model_albums
.set_mpd_data(null);
720 this
.model_artist
.set_mpd_data(null);
722 this
.artist_filter_entry
.set_text("");
723 this
.album_filter_entry
.set_text("");
725 /* Fill in the first browser */
726 MPD
.Database
.search_field_start(server
,MPD
.Tag
.Type
.ARTIST
);
727 var data
= MPD
.Database
.search_commit(server
);
728 data
.sort_album_disc_track();
729 this
.model_artist
.set_mpd_data((owned
)data
);
732 private string?
browser_get_selected_artist()
735 var sel
= this
.tree_artist
.get_selection();
736 Gtk
.TreeModel model
= null;//this.model_artist;
737 if(sel
.get_selected(out model
, out iter
))
739 string artist
= null;
740 model
.get(iter
, 7,out artist
, -1);
746 private string?
browser_get_selected_album()
749 var sel
= this
.tree_album
.get_selection();
750 Gtk
.TreeModel model
= null;//this.model_albums;
751 if(sel
.get_selected(out model
, out iter
))
754 model
.get(iter
, 6,out album
, -1);
759 private unowned MPD
.Song?
browser_get_selected_song()
762 var sel
= this
.tree_songs
.get_selection();
764 if(sel
.get_selected(out model
, out iter
))
766 unowned MPD
.Song? songs
= null;
767 this
.model_songs
.get(iter
, 0,out songs
, -1);
772 private void browser_artist_changed(Gtk
.TreeSelection sel
)
774 this
.model_albums
.set_mpd_data(null);
775 this
.model_songs
.set_mpd_data(null);
776 this
.metadata_box_clear();
778 string artist
= browser_get_selected_artist();
781 /* Fill in the first browser */
782 MPD
.Database
.search_field_start(server
,MPD
.Tag
.Type
.ALBUM
);
783 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
784 var data
= MPD
.Database
.search_commit(server
);
785 data
.sort_album_disc_track();
787 this
.model_albums
.set_request_artist(artist
);
788 MPD
.Data
.Item list
= null;
789 unowned MPD
.Data
.Item iter
= data
.get_first();
795 list
.type
= MPD
.Data
.Type
.SONG
;
796 list
.song
= new MPD
.Song();
797 list
.song
.artist
= artist
;
798 list
.song
.album
= iter
.tag
;
799 MPD
.Database
.search_field_start(server
,MPD
.Tag
.Type
.DATE
);
800 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
801 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, iter
.tag
);
802 var ydata
= MPD
.Database
.search_commit(server
);
805 unowned MPD
.Data
.Item yi
= ydata
.get_first();
806 while(list
.song
.date
== null && yi
!= null)
808 if(yi
.tag
!= null && yi
.tag
.length
> 0)
810 list
.song
.date
= yi
.tag
;
820 list
.sort_album_disc_track();
821 this
.model_albums
.set_mpd_data((owned
)list
);
823 MPD
.Database
.search_start(server
,true);
824 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
825 data
= MPD
.Database
.search_commit(server
);
826 data
.sort_album_disc_track();
827 this
.model_songs
.set_mpd_data((owned
)data
);
830 this
.metadata_box_update();
832 private void browser_album_changed(Gtk
.TreeSelection album_sel
)
834 this
.model_songs
.set_mpd_data(null);
835 this
.metadata_box_clear();
837 string artist
= browser_get_selected_artist();
840 string album
= browser_get_selected_album();
841 string albumartist
= null;
843 if(album
!= null && Gmpc
.server
.tag_supported(MPD
.Tag
.Type
.ALBUM_ARTIST
))
845 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
);
846 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
847 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
848 var ydata
= MPD
.Database
.search_commit(server
);
851 if(ydata
.tag
.length
> 0)
852 albumartist
= ydata
.tag
;
855 /* Fill in the first browser */
856 MPD
.Database
.search_start(server
,true);
857 if(albumartist
!= null&& albumartist
.length
> 0)
858 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
, albumartist
);
860 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
863 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
864 var data
= MPD
.Database
.search_commit(server
);
865 data
.sort_album_disc_track();
866 this
.model_songs
.set_mpd_data((owned
)data
);
868 this
.metadata_box_update();
870 private void browser_songs_changed (Gtk
.TreeSelection song_sel
)
872 this
.metadata_box_clear();
873 this
.metadata_box_update();
879 private void add_selected_song(Gtk
.Button button
)
881 string artist
= browser_get_selected_artist();
882 string album
= browser_get_selected_album();
883 unowned MPD
.Song? song
= browser_get_selected_song();
886 MPD
.PlayQueue
.add_song(server
,song
.file
);
891 /* Hunt albumartist */
892 string albumartist
= null;
893 if(album
!= null&& Gmpc
.server
.tag_supported(MPD
.Tag
.Type
.ALBUM_ARTIST
))
895 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
);
896 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
897 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
898 var ydata
= MPD
.Database
.search_commit(server
);
901 if(ydata
.tag
.length
> 0)
902 albumartist
= ydata
.tag
;
906 MPD
.Database
.search_start(server
,true);//server,MPD.Tag.Type.FILENAME);
907 if(albumartist
!= null&& albumartist
.length
> 0)
908 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
, albumartist
);
910 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
912 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
913 var data
= MPD
.Database
.search_commit(server
);
916 data
.sort_album_disc_track();
919 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
922 MPD
.PlayQueue
.queue_commit(server
);
927 private void play_selected_song(Gtk
.Button button
)
929 unowned MPD
.Song? song
= browser_get_selected_song();
932 Gmpc
.MpdInteraction
.play_path(song
.file
);
935 private void replace_selected_song(Gtk
.Button button
)
937 MPD
.PlayQueue
.clear(server
);
938 this
.add_selected_song(button
);
939 MPD
.Player
.play(server
);
941 private void metadata_box_clear()
943 var list
= this
.metadata_box
.get_children();
944 foreach(Gtk
.Widget child
in list
)
950 * Add a row to a gtk table
951 * <b>$label:</b> $value
955 private void add_entry(Gtk
.Grid table
, string entry_label
, string? value
,Gtk
.Widget? extra
, ref int i
, string ? image
= null)
958 if(value
== null && extra
== null) return;
959 var box
= new Gtk
.Grid();
960 var label
= new Gtk
.Label("");
961 box
.column_spacing
= 6;
962 label
.set_alignment(0.0f
, 0.0f
);
963 label
.set_markup(Markup
.printf_escaped("<b>%s:</b>",entry_label
));
966 /* Make sure the icon always lines out to the top */
967 var ali
= new Gtk
.Alignment (0f
, 0f
, 0f
, 0f
);
968 var wimage
= new Gtk
.Image
.from_icon_name(image
, Gtk
.IconSize
.MENU
);
970 box
.attach(ali
, 0,0,1,1);
972 box
.attach(label
, 1,0,1,1);
973 // table.attach(box, j,(j+1),i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
974 table
.attach(box
,j
,i
, 1, 1);
979 var pt_label
= new Gtk
.Label(value
);
980 pt_label
.set_selectable(true);
981 pt_label
.set_alignment(0.0f
, 0.0f
);
982 pt_label
.set_line_wrap(true);
983 // table.attach(pt_label, j,(j+1),i,i+1,Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
984 table
.attach(pt_label
, j
, i
, 1, 1);
989 //table.attach(extra, j,(j+1),i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
990 table
.attach(extra
,j
, i
, 1, 1);
996 public Gtk
.Widget
metadata_box_show_song(MPD
.Song tmp_song
, bool show_controls
)
998 var master_box
= new Gtk
.VBox (false, 6);
999 var vbox
= new Gtk
.VBox (false,6);
1000 var song
= tmp_song
.copy();
1001 vbox
.border_width
= 8;
1003 history_bc_header(HitemType
.SONG
, song
.artist
, song
.album
, song
.title
);
1006 /* Start building the gui */
1008 var hbox
= new Gtk
.HBox(false, 6);
1010 var ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
1011 int meta_size
= (int)(this
.metadata_box
.get_allocated_width()*0.20);
1012 meta_size
= int.min(meta_size
, (int)(this
.metadata_sw
.get_allocated_height()*0.30));
1013 meta_size
= int.min(int.max(100, meta_size
), 250);
1014 var album_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, meta_size
);
1015 album_image
.set_scale_up(true);
1016 album_image
.set_squared(false);
1017 ali
.add(album_image
);
1018 album_image
.update_from_song(song
);
1019 hbox
.pack_start(ali
, false, false, 0);
1022 ali
= new Gtk
.Alignment(1f
,0f
,0f
,0f
);
1023 var artist_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ARTIST_ART
, meta_size
);
1025 artist_image
.set_no_cover_icon("no-artist");
1026 artist_image
.set_loading_cover_icon("fetching-artist");
1027 artist_image
.set_scale_up(true);
1028 artist_image
.set_hide_on_na(true);
1029 artist_image
.set_squared(false);
1030 artist_image
.update_from_song(song
);
1031 ali
.add(artist_image
);
1032 hbox
.pack_end(ali
, false, false, 0);
1035 /* Information box */
1036 var info_box
= new Gtk
.Grid();
1037 info_box
.set_row_spacing(3);
1038 info_box
.set_column_spacing(8);
1041 if(song
.title
!= null)
1044 var box
= new Gtk
.HBox(false, 6);
1046 if(config
.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
1048 var fav_button
= new Gmpc
.Favorites
.Button();
1049 fav_button
.set_song(song
);
1050 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
1051 ali
.add(fav_button
);
1052 box
.pack_start(ali
, false, false, 0);
1054 var label
= new Gtk
.Label(song
.title
);
1055 label
.selectable
= true;
1056 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
1057 this
.title_color
,Pango
.SCALE
*20 ,song
.title
));
1058 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1059 label
.set_alignment(0.0f
, 0.5f
);
1060 box
.pack_start(label
, true, true, 0);
1061 //hist_box.pack_start(box, true, true, 0);
1062 //vbox.pack_start(box, true, true, 0);
1063 //info_box.attach(box, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1064 info_box
.attach(box
, i
,0, 2,1);
1067 else if (song
.name
!= null)
1069 var label
= new Gtk
.Label(song
.name
);
1070 label
.selectable
= true;
1071 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
1072 title_color
, Pango
.SCALE
*20, song
.name
));
1073 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1074 label
.set_alignment(0.0f
, 0.5f
);
1075 //info_box.attach(label, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1076 info_box
.attach(label
,i
, 0, 2, 1);
1079 else if (song
.file
!= null)
1081 var filename
= GLib
.Path
.get_basename(song
.file
);
1082 var label
= new Gtk
.Label(song
.name
);
1083 label
.selectable
= true;
1086 var regex_a
= new GLib
.Regex ("\\.[0-9a-zA-Z]*$");
1087 filename
= regex_a
.replace_literal (filename
, -1, 0, "");
1089 catch (GLib
.RegexError e
)
1091 GLib
.error("%s", e
.message
);
1095 var regex_b
= new GLib
.Regex ("_");
1096 filename
= regex_b
.replace_literal (filename
, -1, 0, " ");
1098 catch (GLib
.RegexError e
)
1100 GLib
.error("%s", e
.message
);
1102 label
.set_markup(GLib
.Markup
.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this
.
1103 title_color
, Pango
.SCALE
*20, filename
));
1104 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1105 label
.set_alignment(0.0f
, 0.5f
);
1106 //info_box.attach(label, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1107 info_box
.attach(label
, 0,2, i
, i
+1);
1111 if(song
.artist
!= null)
1113 this
.add_entry(info_box
, _("Artist"), song
.artist
, null,ref i
, "media-artist");
1116 if(song
.album
!= null)
1118 this
.add_entry(info_box
, _("Album"), song
.album
,null, ref i
, "media-album");
1121 if(song
.genre
!= null)
1123 this
.add_entry(info_box
, _("Genre"), song
.genre
,null, ref i
, "media-genre");
1126 if(song
.date
!= null)
1128 this
.add_entry(info_box
, _("Date"), song
.date
,null, ref i
, "media-date");
1130 if(song
.file
!= null)
1133 string extension
= null;
1134 extension
= get_extension(song
.file
);
1135 if(extension
!= null)
1137 this
.add_entry(info_box
, _("Codec"), extension
,null, ref i
, "media-codec");
1140 string directory
= GLib
.Path
.get_dirname(song
.file
);
1141 if(directory
!= null)
1143 this
.add_entry(info_box
, _("Directory"), directory
, null, ref i
, "gtk-open");
1150 this
.add_entry(info_box
, _("Length"),Gmpc
.Misc
.format_time((ulong) song
.time
, ""),null, ref i
, "media-track-length");
1153 if(song
.track
!= null)
1155 var label
= new Gtk
.Label("");
1156 label
.selectable
= true;
1157 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
1158 label
.set_markup(GLib
.Markup
.printf_escaped("%s %s",
1160 (song
.disc
!= null)?
"[%s]".printf(song
.disc
):""
1162 label
.set_alignment(0.0f
, 0.5f
);
1163 this
.add_entry(info_box
, _("Track"),null,label
, ref i
, "media-num-tracks");
1167 /* Player controls */
1168 var control_hbox
= new Gtk
.VBox (false, 6);
1170 var abutton
= new Gtk
.Button
.from_stock("gtk-add");
1171 abutton
.set_tooltip_text(_("Add the item to the play queue"));
1172 abutton
.set_property("xalign", 0.0f
);
1173 abutton
.set_relief(Gtk
.ReliefStyle
.NONE
);
1174 abutton
.clicked
.connect(add_selected_song
);
1175 control_hbox
.pack_start(abutton
, false, false,0);
1177 abutton
= new Gtk
.Button
.with_mnemonic(_("_Clear and play"));
1178 abutton
.set_tooltip_text(_("Replace the current play queue with this item"));
1179 abutton
.set_property("xalign", 0.0f
);
1180 abutton
.set_image(new Gtk
.Image
.from_stock("gtk-redo", Gtk
.IconSize
.BUTTON
));
1181 abutton
.set_relief(Gtk
.ReliefStyle
.NONE
);
1182 abutton
.clicked
.connect(replace_selected_song
);
1183 control_hbox
.pack_start(abutton
, false, false,0);
1185 abutton
= new Gtk
.Button
.from_stock("gtk-media-play");
1186 abutton
.set_tooltip_text(_("Play this song"));
1187 abutton
.set_property("xalign", 0.0f
);
1188 abutton
.set_relief(Gtk
.ReliefStyle
.NONE
);
1189 abutton
.clicked
.connect(play_selected_song
);
1190 control_hbox
.pack_start(abutton
, false, false,0);
1192 // info_box.attach(control_hbox, 0,2,i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
1196 hbox
.pack_start(info_box
, true, true, 0);
1197 hbox
.pack_start(control_hbox
, false, false, 0);
1198 vbox
.pack_start(hbox
, false, false, 0);
1201 var hboxje
= new Gtk
.HBox(false, 6);
1203 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1204 var notebook
= new Gtk
.Notebook();
1205 notebook
.set_show_border(false);
1206 notebook
.set_show_tabs(false);
1210 unowned SList
<unowned Gtk
.RadioButton
> group
= null;
1211 if(config
.get_int_with_default("MetaData", "show-lyrics",1) == 1)
1213 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
1214 var text_view
= new Gmpc
.MetaData
.TextView(Gmpc
.MetaData
.Type
.SONG_TXT
);
1215 text_view
.set_left_margin(8);
1216 text_view
.query_from_song(song
);
1218 alib
.add(text_view
);
1219 notebook
.append_page(alib
, new Gtk
.Label("Lyrics"));
1220 var button
= new Gtk
.RadioButton
.with_label(group
,("Lyrics"));
1221 group
= button
.get_group();
1222 hboxje
.pack_start(button
, false, false, 0);
1224 button
.clicked
.connect((source
) =>
1226 debug("notebook page %i clicked", j
);
1227 notebook
.set_current_page(j
);
1235 if(config
.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
1237 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
1238 var text_view
= new Gmpc
.MetaData
.TextView(Gmpc
.MetaData
.Type
.SONG_GUITAR_TAB
);
1239 text_view
.use_monospace
= true;
1240 text_view
.set_left_margin(8);
1241 var text_view_queried
= false;
1243 alib
.add(text_view
);
1244 notebook
.append_page(alib
, new Gtk
.Label(_("Guitar Tabs")));
1245 var button
= new Gtk
.RadioButton
.with_label(group
,_("Guitar Tabs"));
1246 group
= button
.get_group();
1247 hboxje
.pack_start(button
, false, false, 0);
1249 /* Only query the guitar-tab when opened or first notebook page*/
1250 button
.clicked
.connect((source
) =>
1252 debug("notebook page %i clicked", j
);
1253 notebook
.set_current_page(j
);
1254 if(!text_view_queried
)
1256 text_view
.query_from_song(song
);
1257 text_view_queried
= true;
1262 text_view
.query_from_song(song
);
1263 text_view_queried
= true;
1270 if(config
.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
1272 var similar_songs_queried
= false;
1273 var similar_songs_box
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
1275 notebook
.append_page(similar_songs_box
, new Gtk
.Label(_("Similar Songs")));
1277 var button
= new Gtk
.RadioButton
.with_label(group
,_("Similar Songs"));
1278 group
= button
.get_group();
1279 hboxje
.pack_start(button
, false, false, 0);
1282 /* Only query when opened or first notebook page*/
1283 button
.clicked
.connect((source
) =>
1285 debug("notebook page %i clicked", j
);
1286 notebook
.set_current_page(j
);
1287 if(!similar_songs_queried
)
1289 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
1290 similar_songs
.update();
1291 similar_songs_queried
= true;
1292 similar_songs_box
.add(similar_songs
);
1293 similar_songs_box
.show_all();
1298 var similar_songs
= new Gmpc
.MetaData
.Widgets
.SimilarSongs(song
);
1299 similar_songs
.update();
1300 similar_songs_queried
= true;
1301 similar_songs_box
.add(similar_songs
);
1302 similar_songs_box
.show_all();
1304 similar_songs_box
.show();
1308 if(config
.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song
.artist
!= null)
1310 var similar_artist
= new Gmpc
.MetaData
.Widgets
.SimilarArtists(Gmpc
.server
,song
);
1312 notebook
.append_page(similar_artist
, new Gtk
.Label(_("Similar Artist")));
1314 var button
= new Gtk
.RadioButton
.with_label(group
,_("Similar Artist"));
1315 group
= button
.get_group();
1316 hboxje
.pack_start(button
, false, false, 0);
1319 button
.clicked
.connect((source
) =>
1321 debug("notebook page %i clicked", j
);
1322 notebook
.set_current_page(j
);
1323 similar_artist
.first_show();
1325 similar_artist
.show();
1328 /* Track changed pages */
1329 notebook
.notify
["page"].connect((source
,spec
) =>
1331 var page
= notebook
.get_current_page();
1332 config
.set_int("MetaData", "song-last-page", (int)page
);
1335 /* Restore right page */
1338 var page
= config
.get_int_with_default("MetaData", "song-last-page", 0);
1341 notebook
.set_current_page(0);
1345 /* The list is in reversed order, compensate for that. */
1346 var w
= group
.nth_data(i
-page
-1);
1348 notebook
.set_current_page(page
);
1352 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
1355 /* Create pane in 2. */
1356 var bottom_hbox
= new Gtk
.HBox(false, 6);
1359 var metadata_vbox
= new Gtk
.VBox(false, 6);
1361 var sep
= new Gtk
.HSeparator();
1362 sep
.set_size_request(-1, 1);
1363 metadata_vbox
.pack_start(sep
, false, false, 0);
1365 metadata_vbox
.pack_start(ali
, false, false, 0);
1366 sep
= new Gtk
.HSeparator();
1367 sep
.set_size_request(-1, 1);
1368 metadata_vbox
.pack_start(sep
, false, false, 0);
1369 metadata_vbox
.pack_start(notebook
, false, false, 0);
1371 bottom_hbox
.pack_start(metadata_vbox
, true, true, 0);
1373 vbox
.pack_start(bottom_hbox
, true, true, 0);
1376 master_box
.pack_start(vbox
, false, false, 0);
1380 private void metadata_box_show_base()
1382 Gtk
.Entry MetadataBoxShowBaseEntry
= null;
1383 var master_box
= new Gtk
.VBox (false, 6);
1384 var vbox
= new Gtk
.VBox (false,6);
1385 vbox
.border_width
= 8;
1388 history_bc_header(HitemType
.BASE
, null, null, null);
1390 var hbox
= new Gtk
.HBox(false, 6);
1391 var label
= new Gtk
.Label("");
1392 label
.set_markup(_("<b>Search:</b>"));
1393 hbox
.pack_start(label
, false, false, 0);
1394 MetadataBoxShowBaseEntry
= new Gtk
.Entry();
1396 MetadataBoxShowBaseEntry
.add_accelerator("grab-focus",
1397 Gmpc
.Playlist
.get_accel_group(),
1399 Gdk
.ModifierType
.CONTROL_MASK
,
1402 /* Add clear icon */
1403 MetadataBoxShowBaseEntry
.set_icon_from_stock(Gtk
.EntryIconPosition
.SECONDARY
, "gtk-clear");
1404 MetadataBoxShowBaseEntry
.icon_press
.connect((source
, pos
, event
) =>
1406 source
.set_text("");
1410 hbox
.pack_start(MetadataBoxShowBaseEntry
, true, true, 0);
1412 vbox
.pack_start(hbox
, false, false, 0);
1415 var result_hbox
= new Gmpc
.Widgets
.Songlist();
1416 result_hbox
.artist_song_clicked
.connect((source
, song
) =>
1418 if(song
.artist
!= null)
1420 this
.set_artist(song
.artist
);
1423 result_hbox
.album_song_clicked
.connect((source
, song
) =>
1425 if(song
.artist
!= null && song
.album
!= null)
1427 this
.set_album(song
.artist
, song
.album
);
1430 result_hbox
.song_clicked
.connect((source
, song
) =>
1432 this
.set_song(song
);
1435 result_hbox
.play_song_clicked
.connect((source
, song
) =>
1437 if(song
.file
!= null)
1439 Gmpc
.MpdInteraction
.play_path(song
.file
);
1442 result_hbox
.song_context_menu
.connect((source
, song
) =>
1444 var menu
= new Gtk
.Menu();
1446 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-open",null);
1447 MPD
.Song song_pass
= song
.copy();
1448 item
.activate
.connect((source
)=>{
1449 this
.set_song(song_pass
);
1453 stdout
.printf("song context menu show\n");
1455 menu
.popup(null, null, null, 3, Gtk
.get_current_event_time());
1458 MetadataBoxShowBaseEntry
.activate
.connect((source
) =>
1460 string value
= source
.get_text();
1461 current
.data
.search_string
= value
;
1462 MPD
.Data
.Item? list
= Gmpc
.Query
.search(value
, false);
1463 result_hbox
.set_from_data((owned
)list
,true,true);
1464 result_hbox
.show_all();
1467 vbox
.pack_start(result_hbox
, false, false);
1471 if(current
.data
.type
== HitemType
.BASE
&& current
.data
.search_string
!= null)
1473 MetadataBoxShowBaseEntry
.set_text(current
.data
.search_string
);
1474 MetadataBoxShowBaseEntry
.activate();
1479 * Button that allows you to enable/disable the side bars
1481 var show_button
= new Gtk
.ToggleButton
.with_label(_("Hide sidebar"));
1483 if(config
.get_int_with_default("metadata browser", "show-browsers", 1) == 0)
1485 show_button
.label
= _("Show sidebar");
1486 show_button
.set_active(true);
1488 show_button
.toggled
.connect((source
) =>
1490 var state
= show_button
.active
;
1493 this
.browser_box
.hide();
1494 show_button
.label
= _("Show sidebar");
1497 this
.browser_box
.show();
1498 show_button
.label
= _("Hide sidebar");
1500 config
.set_int("metadata browser", "show-browsers", (int)!state
);
1504 var ali
= new Gtk
.Alignment(0.0f
, 0.5f
, 0f
,0f
);
1505 ali
.add(show_button
);
1506 vbox
.pack_start(ali
, false, false);
1508 * Add it to the view
1510 master_box
.pack_start(vbox
, false, false, 0);
1511 this
.metadata_box
.add(master_box
);
1512 this
.metadata_sw
.show_all();
1513 // MetadataBoxShowBaseEntry.grab_focus();
1518 private void metadata_box_show_album(string artist
, string album
)
1520 var master_box
= new Gtk
.VBox (false, 6);
1521 var vbox
= new Gtk
.VBox (false,6);
1522 vbox
.border_width
= 8;
1525 history_bc_header(HitemType
.ALBUM
, artist
, album
, null);
1528 var hbox
= new Gtk
.HBox(false, 6);
1529 var ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
1531 int meta_size
= (int)(this
.metadata_box
.get_allocated_width()*0.20);
1532 meta_size
= int.min(meta_size
, (int)(this
.metadata_sw
.get_allocated_height()*0.30));
1533 meta_size
= int.min(int.max(100, meta_size
), 250);
1534 var artist_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, meta_size
);
1535 artist_image
.set_squared(false);
1536 MPD
.Song song
= new MPD
.Song();
1537 song
.artist
= artist
;
1539 artist_image
.update_from_song(song
);
1540 ali
.add(artist_image
);
1541 hbox
.pack_start(ali
, false, false, 0);
1542 /* Artist information */
1543 var info_box
= new Gtk
.Grid();
1544 info_box
.set_row_spacing(3);
1545 info_box
.set_column_spacing(8);
1546 hbox
.pack_start(info_box
, true, true, 0);
1550 var label
= new Gtk
.Label(artist
!= null?artist
:_("Unknown"));
1551 label
.set_alignment(0.0f
, 0.5f
);
1552 label
.set_line_wrap(true);
1553 this
.add_entry(info_box
, _("Artist"), null, label
, ref i
, "media-artist");
1555 label
= new Gtk
.Label(album
!= null?album
:_("Unknown"));
1556 label
.set_alignment(0.0f
, 0.5f
);
1557 label
.set_line_wrap(true);
1558 this
.add_entry(info_box
, _("Album"), null, label
, ref i
, "media-album");
1560 /* Genres of songs */
1561 var pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ALBUM_GENRES_SONGS
, song
);
1562 pt_label
.set_selectable(true);
1563 pt_label
.set_alignment(0.0f
, 0.5f
);
1564 pt_label
.set_line_wrap(true);
1565 this
.add_entry(info_box
, _("Genres"), null, pt_label
, ref i
, "media-genre");
1567 /* Dates of songs */
1568 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ALBUM_DATES_SONGS
, song
);
1569 pt_label
.set_selectable(true);
1570 pt_label
.set_line_wrap(true);
1571 pt_label
.set_alignment(0.0f
, 0.5f
);
1572 this
.add_entry(info_box
, _("Dates"), null, pt_label
, ref i
,"media-date");
1573 /* Total number of songs */
1574 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ALBUM_NUM_SONGS
, song
);
1575 pt_label
.set_selectable(true);
1576 pt_label
.set_line_wrap(true);
1577 pt_label
.set_alignment(0.0f
, 0.5f
);
1578 this
.add_entry(info_box
, _("Songs"), null, pt_label
, ref i
, "media-num-tracks");
1579 /* Total playtime */
1580 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ALBUM_PLAYTIME_SONGS
, song
);
1581 pt_label
.set_selectable(true);
1582 pt_label
.set_line_wrap(true);
1583 pt_label
.set_alignment(0.0f
, 0.5f
);
1584 this
.add_entry(info_box
, _("Playtime"), null, pt_label
, ref i
, "media-track-length");
1586 vbox
.pack_start(hbox
, false, false, 0);
1588 /* Player controls */
1589 var control_hbox
= new Gtk
.VBox (false, 6);
1591 var button
= new Gtk
.Button
.from_stock("gtk-add");
1592 button
.set_tooltip_text(_("Add the item to the play queue"));
1593 button
.set_property("xalign", 0.0f
);
1594 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1595 button
.clicked
.connect(add_selected_song
);
1596 control_hbox
.pack_start(button
, false, false,0);
1598 button
= new Gtk
.Button
.from_stock("gtk-media-play");
1599 button
.set_tooltip_text(_("Replace the current play queue with this item and play"));
1600 button
.set_property("xalign", 0.0f
);
1601 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1602 button
.clicked
.connect(replace_selected_song
);
1603 control_hbox
.pack_start(button
, false, false,0);
1605 hbox
.pack_start(control_hbox
, false, false, 0);
1608 var sep
= new Gtk
.HSeparator();
1609 sep
.set_size_request(-1, 4);
1610 vbox
.pack_start(sep
, false, false, 0);
1612 var hboxje
= new Gtk
.HBox(false, 6);
1614 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1615 var notebook
= new Gtk
.Notebook();
1616 notebook
.set_show_border(false);
1617 notebook
.set_show_tabs(false);
1621 unowned SList
<unowned Gtk
.RadioButton
> group
= null;
1622 /* Album information */
1623 if(config
.get_int_with_default("MetaData", "show-album-information",1) == 1)
1625 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
1626 var text_view
= new Gmpc
.MetaData
.TextView(Gmpc
.MetaData
.Type
.ALBUM_TXT
);
1627 text_view
.set_left_margin(8);
1628 text_view
.query_from_song(song
);
1630 alib
.add(text_view
);
1631 notebook
.append_page(alib
, new Gtk
.Label(_("Album information")));
1632 var rbutton
= new Gtk
.RadioButton
.with_label(group
,_("Album information"));
1633 group
= rbutton
.get_group();
1634 hboxje
.pack_start(rbutton
, false, false, 0);
1636 rbutton
.clicked
.connect((source
) =>
1638 debug("notebook page %i clicked", j
);
1639 notebook
.set_current_page(j
);
1646 var slhbox
= new Gtk
.VBox(false, 6);
1648 var sl
= new Gmpc
.Widgets
.Songlist();
1649 slhbox
.pack_start(sl
, false, false, 0);
1651 sl
.album_song_clicked
.connect((source
, song
) =>
1653 if(song
.artist
!= null && song
.album
!= null)
1655 this
.set_album(song
.artist
, song
.album
);
1658 sl
.song_clicked
.connect((source
, song
) =>
1660 this
.set_song(song
);
1663 sl
.play_song_clicked
.connect((source
, song
) =>
1665 if(song
.file
!= null)
1667 Gmpc
.MpdInteraction
.play_path(song
.file
);
1671 sl
.song_context_menu
.connect((source
,song
)=>
1673 var menu
= new Gtk
.Menu();
1675 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-open",null);
1676 MPD
.Song song_pass
= song
.copy();
1677 item
.activate
.connect((source
)=>{
1678 this
.set_song(song_pass
);
1682 stdout
.printf("song context menu show\n");
1684 menu
.popup(null, null, null, 3, Gtk
.get_current_event_time());
1687 notebook
.append_page(slhbox
, new Gtk
.Label(_("Song list")));
1688 var rbutton
= new Gtk
.RadioButton
.with_label(group
,_("Song list"));
1689 group
= rbutton
.get_group();
1690 hboxje
.pack_start(rbutton
, false, false, 0);
1693 rbutton
.clicked
.connect((source
) =>
1695 notebook
.set_current_page(j
);
1697 notebook
.notify
["page"].connect((source
)=>
1699 if(notebook
.page
!= j
) return;
1700 debug("notebook page %i clicked", j
);
1703 string albumartist
= null;
1704 if(Gmpc
.server
.tag_supported(MPD
.Tag
.Type
.ALBUM_ARTIST
))
1706 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
);
1707 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
1708 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
1709 var ydata
= MPD
.Database
.search_commit(server
);
1712 if(ydata
.tag
.length
> 0)
1713 albumartist
= ydata
.tag
;
1716 MPD
.Database
.search_start(server
,true);
1717 if(albumartist
!= null&& albumartist
.length
> 0)
1718 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
, albumartist
);
1720 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
1723 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
1724 var data
= MPD
.Database
.search_commit(server
);
1725 data
.sort_album_disc_track();
1727 sl
.set_from_data((owned
)data
,false);
1735 /* Track changed pages */
1736 notebook
.notify
["page"].connect((source
,spec
) =>
1738 var page
= notebook
.get_current_page();
1739 config
.set_int("MetaData", "album-last-page", (int)page
);
1742 /* Restore right page */
1745 var page
= config
.get_int_with_default("MetaData", "album-last-page", 0);
1748 notebook
.set_current_page(0);
1752 /* The list is in reversed order, compensate for that. */
1753 var w
= group
.nth_data(i
-page
-1);
1755 notebook
.set_current_page(page
);
1759 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
1762 /* Create pane in 2. */
1763 var bottom_hbox
= new Gtk
.HBox(false, 6);
1765 var metadata_vbox
= new Gtk
.VBox(false, 6);
1766 metadata_vbox
.pack_start(ali
, false, false, 0);
1767 sep
= new Gtk
.HSeparator();
1768 sep
.set_size_request(-1, 1);
1769 metadata_vbox
.pack_start(sep
, false, false, 0);
1770 metadata_vbox
.pack_start(notebook
, false, false, 0);
1771 bottom_hbox
.pack_start(metadata_vbox
, true, true, 0);
1774 vbox
.pack_start(bottom_hbox
, true, true, 0);
1776 * Add it to the view
1778 master_box
.pack_start(vbox
, false, false, 0);
1779 this
.metadata_box
.add(master_box
);
1780 this
.metadata_sw
.show_all();
1783 * This fills the view for artist
1785 * <image> | <array with info>
1788 * <artist info text>
1793 private void metadata_box_show_artist(string artist
)
1795 var master_box
= new Gtk
.VBox (false, 6);
1796 var vbox
= new Gtk
.VBox (false,6);
1798 vbox
.border_width
= 8;
1801 history_bc_header(HitemType
.ARTIST
, artist
, null, null);
1803 /* Create an MPD.Song with the info for this type set */
1804 MPD
.Song song
= new MPD
.Song();
1805 song
.artist
= artist
;
1808 var hbox
= new Gtk
.HBox(false, 6);
1809 var ali
= new Gtk
.Alignment(0f
,0f
,0f
,0f
);
1810 int meta_size
= (int)(this
.metadata_box
.get_allocated_width()*0.20);
1811 meta_size
= int.min(meta_size
, (int)(this
.metadata_sw
.get_allocated_height()*0.30));
1812 meta_size
= int.min(int.max(100, meta_size
), 250);
1813 var artist_image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ARTIST_ART
, meta_size
);
1815 artist_image
.set_no_cover_icon("no-artist");
1816 artist_image
.set_loading_cover_icon("fetching-artist");
1817 artist_image
.set_squared(false);
1818 artist_image
.update_from_song(song
);
1819 ali
.add(artist_image
);
1820 hbox
.pack_start(ali
, false, false, 0);
1821 /* Artist information */
1822 var info_box
= new Gtk
.Grid();
1823 info_box
.set_row_spacing(3);
1824 info_box
.set_column_spacing(8);
1825 hbox
.pack_start(info_box
, true, true, 0);
1828 var label
= new Gtk
.Label((artist
!= null)?artist
:_("Unknown"));
1829 label
.set_selectable(true);
1830 label
.set_alignment(0.0f
, 0.5f
);
1831 this
.add_entry(info_box
, _("Artist"), null, label
, ref i
, "media-artist");
1833 /* Genres of songs */
1834 var pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ARTIST_GENRES_SONGS
, song
);
1835 pt_label
.set_selectable(true);
1836 pt_label
.set_alignment(0.0f
, 0.5f
);
1837 pt_label
.set_line_wrap(true);
1838 this
.add_entry(info_box
, _("Genres"), null, pt_label
, ref i
, "media-genre");
1839 /* Dates of songs */
1840 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ARTIST_DATES_SONGS
, song
);
1841 pt_label
.set_selectable(true);
1842 pt_label
.set_line_wrap(true);
1843 pt_label
.set_alignment(0.0f
, 0.5f
);
1844 this
.add_entry(info_box
, _("Dates"), null, pt_label
, ref i
,"media-date");
1845 /* Total number of songs */
1846 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ARTIST_NUM_SONGS
, song
);
1847 pt_label
.set_selectable(true);
1848 pt_label
.set_line_wrap(true);
1849 pt_label
.set_alignment(0.0f
, 0.5f
);
1850 this
.add_entry(info_box
, _("Songs"), null, pt_label
, ref i
, "media-num-tracks");
1851 /* Total playtime */
1852 pt_label
= new Gmpc
.MetaData
.StatsLabel(Gmpc
.MetaData
.StatsLabel
.Type
.ARTIST_PLAYTIME_SONGS
, song
);
1853 pt_label
.set_selectable(true);
1854 pt_label
.set_line_wrap(true);
1855 pt_label
.set_alignment(0.0f
, 0.5f
);
1856 this
.add_entry(info_box
, _("Playtime"), null, pt_label
, ref i
, "media-track-length");
1858 vbox
.pack_start(hbox
, true, true, 0);
1860 /* Player controls */
1861 var hbox_2
= new Gtk
.VBox (false, 6);
1863 var button
= new Gtk
.Button
.from_stock("gtk-add");
1864 button
.set_tooltip_text(_("Add the item to the play queue"));
1865 button
.set_property("xalign", 0.0f
);
1866 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1867 button
.clicked
.connect(add_selected_song
);
1868 hbox_2
.pack_start(button
, false, false,0);
1870 button
= new Gtk
.Button
.from_stock("gtk-media-play");
1871 button
.set_tooltip_text(_("Replace the current play queue with this item and play"));
1872 button
.set_property("xalign", 0.0f
);
1873 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
1874 button
.clicked
.connect(replace_selected_song
);
1875 hbox_2
.pack_start(button
, false, false,0);
1877 hbox
.pack_start(hbox_2
, false, false, 0);
1880 var hboxje
= new Gtk
.HBox(false, 6);
1882 var sep
= new Gtk
.HSeparator();
1883 sep
.set_size_request(-1, 4);
1884 vbox
.pack_start(sep
, false, false, 0);
1887 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1888 var notebook
= new Gtk
.Notebook();
1889 notebook
.set_show_border(false);
1890 notebook
.set_show_tabs(false);
1893 unowned SList
<unowned Gtk
.RadioButton
> group
= null;
1894 /* Artist information */
1895 if(config
.get_int_with_default("MetaData", "show-artist-information",1) == 1)
1897 var alib
= new Gtk
.Alignment(0f
,0f
,1f
,0f
);
1898 var text_view
= new Gmpc
.MetaData
.TextView(Gmpc
.MetaData
.Type
.ARTIST_TXT
);
1899 text_view
.set_left_margin(8);
1900 text_view
.query_from_song(song
);
1902 alib
.add(text_view
);
1903 notebook
.append_page(alib
, new Gtk
.Label(_("Artist information")));
1904 var button_sai
= new Gtk
.RadioButton
.with_label(group
,_("Artist information"));
1905 group
= button_sai
.get_group();
1906 hboxje
.pack_start(button_sai
, false, false, 0);
1909 button_sai
.clicked
.connect((source
) =>
1911 if((source as Gtk
.CheckButton
).get_active())
1913 debug("notebook page %i clicked", j
);
1914 notebook
.set_current_page(j
);
1922 /* Show similar artist */
1923 if(config
.get_int_with_default("MetaData", "show-similar-artist",1) == 1)
1925 var similar_artist
= new Gmpc
.MetaData
.Widgets
.SimilarArtists(Gmpc
.server
,song
);
1927 notebook
.append_page(similar_artist
, new Gtk
.Label(_("Similar Artist")));
1929 var button_sa
= new Gtk
.RadioButton
.with_label(group
,_("Similar Artist"));
1930 group
= button_sa
.get_group();
1931 hboxje
.pack_start(button_sa
, false, false, 0);
1934 button_sa
.clicked
.connect((source
) =>
1936 if((source as Gtk
.CheckButton
).get_active())
1938 debug("notebook page %i clicked", j
);
1939 similar_artist
.first_show();
1940 notebook
.set_current_page(j
);
1943 similar_artist
.show();
1948 var slhbox
= new Gtk
.VBox(false, 6);
1950 var sl
= new Gmpc
.Widgets
.Songlist();
1951 slhbox
.pack_start(sl
, false, false, 0);
1953 sl
.album_song_clicked
.connect((source
, song
) =>
1955 if(song
.artist
!= null && song
.album
!= null)
1957 this
.set_album(song
.artist
, song
.album
);
1960 sl
.song_clicked
.connect((source
, song
) =>
1962 this
.set_song(song
);
1965 sl
.play_song_clicked
.connect((source
, song
) =>
1967 if(song
.file
!= null)
1969 Gmpc
.MpdInteraction
.play_path(song
.file
);
1972 sl
.song_context_menu
.connect((source
,song
)=>
1974 var menu
= new Gtk
.Menu();
1976 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-open",null);
1977 MPD
.Song song_pass
= song
.copy();
1978 item
.activate
.connect((source
)=>{
1979 this
.set_song(song_pass
);
1983 stdout
.printf("song context menu show\n");
1985 menu
.popup(null, null, null, 3, Gtk
.get_current_event_time());
1989 notebook
.append_page(slhbox
, new Gtk
.Label(_("Song list")));
1990 var rbutton
= new Gtk
.RadioButton
.with_label(group
,_("Song list"));
1991 group
= rbutton
.get_group();
1992 hboxje
.pack_start(rbutton
, false, false, 0);
1995 rbutton
.clicked
.connect((source
) =>
1997 notebook
.set_current_page(j
);
1999 notebook
.notify
["page"].connect((source
)=>
2001 if(notebook
.page
!= j
) return;
2002 debug("notebook page %i clicked", j
);
2005 MPD
.Database
.search_start(server
,true);
2006 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
2007 var data
= MPD
.Database
.search_commit(server
);
2008 data
.sort_album_disc_track();
2010 sl
.set_from_data((owned
)data
, true);
2019 if( song
.artist
!= null)
2022 /* Create album list */
2023 var album_hbox
= new Gtk
.VBox(false, 6);
2025 var album_view
= new Gmpc
.Widgets
.Qtable();
2026 album_hbox
.pack_start(album_view
, false, true, 0);
2028 * Reuse the album browser view.
2031 if(this
.model_albums
.get_iter_first(out titer
))
2035 unowned MPD
.Song? asong
= null;
2036 this
.model_albums
.get(titer
,0, &asong
);
2039 /* Make a copy of the song. Otherwise only a reference is added to the
2040 * button clicked handler.
2041 * This reference can be invalid before click completed.
2043 MPD
.Song but_song
= asong
.copy();
2046 var but_hbox
= new Gtk
.VBox(false, 6);
2047 var image
= new Gmpc
.MetaData
.Image(Gmpc
.MetaData
.Type
.ALBUM_ART
, 175);
2048 image
.set_squared(true);
2049 image
.set_scale_up(true);
2050 image
.set_has_tooltip(false);
2051 image
.update_from_song_delayed(but_song
);
2053 but_hbox
.pack_start(image
, false, false, 0);
2055 var but_label
= new Gtk
.Label(but_song
.album
);
2056 but_label
.selectable
= true;
2057 but_label
.set_alignment(0.5f
, 0.0f
);
2059 var strlabel
= "<b>";
2060 if(but_song
.date
!= null && but_song
.date
.length
> 0) strlabel
+= GLib
.Markup
.printf_escaped("%s - ",but_song
.date
);
2061 if(but_song
.album
!= null) strlabel
+=GLib
.Markup
.escape_text(but_song
.album
);
2062 else strlabel
+= _("No Album");
2064 if(but_song
.artist
!= null) strlabel
+= GLib
.Markup
.printf_escaped("\n%s",but_song
.artist
);
2065 but_label
.set_markup(strlabel
);
2066 (but_label as Gtk
.Misc
).set_alignment(0.0f
, 0.0f
);
2067 but_label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
2069 but_hbox
.pack_start(but_label
, true, true, 0);
2071 /* If clicked switch to browser */
2072 image
.button_release_event
.connect((source
, event
) =>
2074 if(event
.button
== 2)
2076 set_album(but_song
.artist
, but_song
.album
);
2079 else if (event
.button
== 1)
2081 var p
= new
PopupMenu();
2083 hbox
= new Gtk
.HBox(false, 0);
2084 var open
= new Gtk
.Button();
2085 open
.set_tooltip_text(_("Open"));
2086 open
.add(new Image
.from_stock("gtk-open", Gtk
.IconSize
.DND
));
2087 hbox
.pack_start(open
, false, false, 0);
2088 open
.clicked
.connect( (source
) =>
2090 set_album(but_song
.artist
, but_song
.album
);
2097 var play
= new
Button();
2098 play
.add(new Image
.from_stock("gtk-media-play", Gtk
.IconSize
.DND
));
2099 play
.set_tooltip_text(_("Play album"));
2100 hbox
.pack_start(play
, false, false, 0);
2101 play
.clicked
.connect( (source
) =>
2103 MPD
.PlayQueue
.clear(server
);
2104 MPD
.PlayQueue
.add_album(server
,
2107 MPD
.Player
.play(server
);
2114 var add
= new
Button();
2115 add
.add(new Image
.from_stock("gtk-add", Gtk
.IconSize
.DND
));
2116 add
.set_tooltip_text(_("Add album to play-queue"));
2117 hbox
.pack_start(add
, false, false, 0);
2118 add
.clicked
.connect( (source
) =>
2120 MPD
.PlayQueue
.add_album(server
,
2136 album_view
.add(but_hbox
);
2139 while(this
.model_albums
.iter_next(ref titer
));
2142 notebook
.append_page(album_hbox
, new Gtk
.Label(_("Albums")));
2143 var button_sl
= new Gtk
.RadioButton
.with_label(group
,_("Albums"));
2144 group
= button_sl
.get_group();
2145 hboxje
.pack_start(button_sl
, false, false, 0);
2147 button_sl
.clicked
.connect((source
) =>
2149 if((source as Gtk
.CheckButton
).get_active())
2151 debug("notebook page %i clicked", j
);
2152 notebook
.set_current_page(j
);
2159 /* Track changed pages */
2160 notebook
.notify
["page"].connect((source
,spec
) =>
2162 var page
= notebook
.get_current_page();
2163 config
.set_int("MetaData", "artist-last-page", (int)page
);
2166 /* Restore right page */
2169 var page
= config
.get_int_with_default("MetaData", "artist-last-page", 0);
2172 notebook
.set_current_page(0);
2176 /* The list is in reversed order, compensate for that. */
2177 var w
= group
.nth_data(i
-page
-1);
2179 notebook
.set_current_page(page
);
2184 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
2188 var metadata_vbox
= new Gtk
.VBox(false, 6);
2189 metadata_vbox
.pack_start(ali
, false, false, 0);
2190 sep
= new Gtk
.HSeparator();
2191 sep
.set_size_request(-1, 1);
2192 metadata_vbox
.pack_start(sep
, false, false, 0);
2193 metadata_vbox
.pack_start(notebook
, false, false, 0);
2196 vbox
.pack_start(metadata_vbox
, true, true, 0);
2200 * Add it to the view
2203 master_box
.pack_start(vbox
, false, false, 0);
2204 this
.metadata_box
.add(master_box
);
2205 this
.metadata_box
.show_all();
2209 private uint update_timeout
= 0;
2210 /* If we get an update, wait for idle time, then do it.*/
2211 private void metadata_box_update()
2213 if(this
.update_timeout
> 0)
2215 GLib
.Source
.remove(this
.update_timeout
);
2217 update_timeout
= GLib
.Idle
.add(this
.metadata_box_update_real
);
2219 private bool metadata_box_update_real()
2221 if(this
.block_update
> 0)
2223 this
.update_timeout
= 0;
2226 string artist
= browser_get_selected_artist();
2227 string album
= browser_get_selected_album();
2228 unowned MPD
.Song? song
= browser_get_selected_song();
2232 /** Add item to history */
2233 var item
= new
Hitem();
2234 item
.song
= song
.copy();
2235 item
.type
= HitemType
.SONG
;
2238 var view
= metadata_box_show_song(song
,true);
2239 this
.metadata_box
.add(view
);
2240 this
.metadata_box
.show_all();
2242 else if(album
!= null && artist
!= null)
2244 /** Add item to history */
2245 var item
= new
Hitem();
2246 item
.song
= new MPD
.Song();
2247 item
.song
.artist
=artist
;
2248 item
.song
.album
= album
;
2249 item
.type
= HitemType
.ALBUM
;
2252 metadata_box_show_album(artist
,album
);
2254 else if (artist
!= null)
2256 /** Add item to history */
2257 var item
= new
Hitem();
2258 item
.song
= new MPD
.Song();
2259 item
.song
.artist
=artist
;
2260 item
.type
= HitemType
.ARTIST
;
2263 metadata_box_show_artist(artist
);
2267 var item
= new
Hitem();
2268 item
.search_string
= null;
2269 item
.type
= HitemType
.BASE
;
2271 metadata_box_show_base();
2274 this
.update_timeout
= 0;
2278 * Browser Interface bindings
2280 public void browser_add (Gtk
.Widget category_tree
)
2282 Gtk
.TreeView tree
= (Gtk
.TreeView
)category_tree
;
2283 Gtk
.ListStore store
= (Gtk
.ListStore
)tree
.get_model();
2284 Gtk
.TreeModel model
= tree
.get_model();
2286 Gmpc
.Browser
.insert(out iter
,
2287 Playlist
.BrowserType
.LIBRARY
+config
.get_int_with_default(this
.get_name(), "position", 100)%Playlist
.BrowserType
.LIBRARY
);
2288 store
.set(iter
, 0, this
.id
, 1, _(this
.get_name()), 3, "gmpc-metabrowser");
2289 /* Create a row reference */
2290 this
.rref
= new Gtk
.TreeRowReference(model
, model
.get_path(iter
));
2292 public void browser_selected (Gtk
.Container container
)
2295 this
.selected
= true;
2296 this
.browser_init();
2297 container
.add(this
.paned
);
2299 /* update if non selected */
2300 artist
= browser_get_selected_artist();
2303 metadata_box_clear();
2304 metadata_box_update();
2308 private bool selected
= false;
2309 public void browser_unselected(Gtk
.Container container
)
2311 this
.selected
= false;
2312 container
.remove(this
.paned
);
2316 con_changed(Gmpc
.Connection conn
, MPD
.Server server
, int connect
)
2318 if(this
.paned
== null) return;
2319 this
.history_clear();
2321 this
.reload_browsers();
2322 metadata_box_clear();
2323 metadata_box_update();
2327 status_changed(Gmpc
.Connection conn
, MPD
.Server server
, MPD
.Status
.Changed what
)
2329 if(this
.paned
== null) return;
2330 if((what
&MPD
.Status
.Changed
.DATABASE
) != 0)
2332 this
.reload_browsers();
2333 /* Restore old selection */
2334 if(this
.current
!= null)
2336 this
.show_hitem(this
.current
.data
);
2344 private enum HitemType
2353 public HitemType type
;
2354 public MPD
.Song? song
;
2355 public string search_string
;
2357 private List
<Hitem?
> history
= null;
2358 private unowned List
<Hitem?
> current
= null;
2359 private void show_hitem(Hitem hi
)
2363 case HitemType
.BASE
:
2366 case HitemType
.ARTIST
:
2367 this
.set_artist(hi
.song
.artist
);
2369 case HitemType
.ALBUM
:
2370 this
.set_album(hi
.song
.artist
, hi
.song
.album
);
2372 case HitemType
.SONG
:
2373 this
.set_song(hi
.song
);
2376 metadata_box_clear();
2380 private void history_previous()
2382 if(history
== null || current
== null)
2386 if(current
.next
== null)
2390 current
= current
.next
;
2391 if(current
!= null) show_hitem(current
.data
);
2392 else metadata_box_clear();
2395 private void history_next()
2397 if(history
== null || current
== null)
2401 if(current
.prev
== null)
2405 current
= current
.prev
;
2406 if(current
!= null) show_hitem(current
.data
);
2407 else metadata_box_clear();
2410 private void history_show_list_clicked(Gtk
.MenuItem item
)
2412 unowned List
<Hitem?
> a
= (List
<Hitem?
>) item
.get_data
<List
<Hitem?
>>("current");
2416 show_hitem(current
.data
);
2419 private void history_show_list()
2421 var menu
= new Gtk
.Menu();
2422 unowned List
<Hitem?
> iter
= history
.last();
2425 unowned Hitem i
= iter
.data
;
2427 if(i
.type
== HitemType
.ARTIST
)
2428 label
= i
.song
.artist
;
2429 else if (i
.type
== HitemType
.ALBUM
)
2430 label
= "%s - %s".printf(i
.song
.artist
, i
.song
.album
);
2431 else if (i
.type
== HitemType
.SONG
)
2433 if(i
.song
.title
!= null)
2434 label
= i
.song
.title
;
2436 label
= _("Unknown");
2438 else if (i
.type
== HitemType
.BASE
)
2440 label
= _("Metadata Browser");
2441 if(i
.search_string
!= null)
2443 label
+= " ("+i
.search_string
+")";
2447 var item
= new Gtk
.CheckMenuItem
.with_label(label
);
2448 item
.draw_as_radio
= true;
2449 if(current
!= null && current
== iter
)
2451 item
.set_active(true);
2453 item
.activate
.connect(history_show_list_clicked
);
2454 item
.set_data("current", (void*)iter
);
2459 menu
.popup(null, null, null, 0, Gtk
.get_current_event_time());
2463 private void history_bc_header(HitemType type
, string? artist
, string? album
, string? title
)
2465 foreach(var child
in this
.header
.get_children())
2469 /* Add the history buttons.
2470 * we use the history buttons hbox for adding our buttons */
2471 var hist_box
= history_buttons();
2472 this
.header
.add(hist_box
);
2474 /* The 'BASE' button */
2475 if(artist
== null && album
== null && title
==null)
2477 var image
= new Gtk
.Image
.from_icon_name("gmpc-metabrowser", Gtk
.IconSize
.MENU
);
2478 var ali
= new Gtk
.Alignment(0.5f
,0.5f
, 0f
, 0f
);
2479 ali
.set_padding(6,6,6,6);
2481 hist_box
.attach(ali
, 0, 0, 1, 1);//pack_start(ali, true, true, 0);
2482 //hist_box.attach(ali, 1, 0, 1,1);
2486 var image
= new Gtk
.Image
.from_icon_name("gmpc-metabrowser", Gtk
.IconSize
.MENU
);
2487 var button
= new Gtk
.Button();
2488 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
2489 button
.set_image(image
);
2490 button
.clicked
.connect((source
)=> { set_base();});
2491 hist_box
.attach(button
, 0, 0, 1, 1);//pack_start(button, true, true, 0);
2493 /* If there is an artist, we can show more */
2496 if(type
!= HitemType
.ARTIST
)
2498 var button
= new Gtk
.Button
.with_label(artist
);
2499 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
2500 button
.set_image(new Gtk
.Image
.from_icon_name("media-artist", Gtk
.IconSize
.MENU
));
2501 button
.clicked
.connect((source
)=>
2505 hist_box
.attach(button
, 1, 0, 1,1);//pack_start(button, true, true, 0);
2510 var label
= new Gtk
.Label(artist
);
2511 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
2512 var image
= new Gtk
.Image
.from_icon_name("media-artist", Gtk
.IconSize
.MENU
);
2513 label
.set_alignment(0.0f
, 0.5f
);
2514 hist_box
.attach(image
, 2, 0, 1,1);
2515 hist_box
.attach(label
, 3, 0, 1,1);
2520 if(type
== HitemType
.ALBUM
)
2522 var label
= new Gtk
.Label(album
);
2523 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
2524 var image
= new Gtk
.Image
.from_icon_name("media-album", Gtk
.IconSize
.MENU
);
2525 label
.set_alignment(0.0f
, 0.5f
);
2526 hist_box
.attach(image
, 4, 0, 1,1);
2527 hist_box
.attach(label
, 5, 0, 1,1);
2531 var button
= new Gtk
.Button();//.with_label(album);
2533 var ali
= new Gtk
.Alignment(0.0f
, 0.5f
, 0.0f
, 0.0f
);
2536 var gr
= new Gtk
.Grid();
2537 gr
.set_column_spacing(6);
2540 var im
= new Gtk
.Image
.from_icon_name("media-album", Gtk
.IconSize
.MENU
);
2541 // button.set_image(im);
2542 gr
.attach(im
,0,0,1,1);
2543 var label
= new Gtk
.Label(album
);
2544 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
2545 gr
.attach(label
, 1,0,1,1);
2547 button
.set_relief(Gtk
.ReliefStyle
.NONE
);
2548 button
.clicked
.connect((source
)=>
2550 set_album(artist
, album
);
2553 hist_box
.attach(button
, 4,0,1,1);//pack_start(button, true, true, 0);
2559 var image
= new Gtk
.Image
.from_icon_name("media-audiofile", Gtk
.IconSize
.MENU
);
2560 hist_box
.attach(image
, 6, 0, 1,1);
2562 var label
= new Gtk
.Label(title
);
2563 label
.set_alignment(0.0f
, 0.5f
);
2564 label
.set_ellipsize(Pango
.EllipsizeMode
.END
);
2565 label
.set_line_wrap(false);
2567 hist_box
.attach(label
, 7, 0, 1,1);
2569 this
.header
.show_all();
2572 private Gtk
.Grid
history_buttons()
2574 var box
= new Gtk
.Grid();
2575 box
.set_column_spacing(6);
2576 if(history
== null && current
== null) return box
;
2578 var back_but
= new Gtk
.Button
.from_stock("gtk-go-back");
2579 back_but
.set_relief(Gtk
.ReliefStyle
.NONE
);
2580 if(current
== null || current
.next
== null) back_but
.sensitive
= false;
2581 back_but
.clicked
.connect(history_previous
);
2584 back_but
.set_hexpand(true);
2585 back_but
.set_halign(Gtk
.Align
.END
);
2586 box
.attach(back_but
, 10, 0, 1, 1);
2589 if(current
!= null && (current
.next
!= null || current
.prev
!= null))
2591 var dd_but
= new Gtk
.Button();
2592 var arrow
= new Gtk
.Arrow(Gtk
.ArrowType
.DOWN
, Gtk
.ShadowType
.ETCHED_IN
);
2594 dd_but
.set_relief(Gtk
.ReliefStyle
.NONE
);
2595 dd_but
.clicked
.connect(history_show_list
);
2597 box
.attach(dd_but
, 11, 0, 1, 1);
2599 var next_but
= new Gtk
.Button
.from_stock("gtk-go-forward");
2600 next_but
.set_relief(Gtk
.ReliefStyle
.NONE
);
2601 if(current
== null || current
.prev
== null) next_but
.sensitive
= false;
2602 next_but
.clicked
.connect(history_next
);
2604 box
.attach(next_but
, 12, 0, 1, 1);
2608 private void history_add(Hitem hi
)
2612 unowned Hitem a
= current
.data
;
2613 if(a
.type
== hi
.type
)
2615 if(Gmpc
.Misc
.song_checksum(a
.song
) == Gmpc
.Misc
.song_checksum(hi
.song
))
2621 /* clean items in the future */
2624 unowned List
<Hitem?
>? iter
= current
.prev
;
2625 while(iter
!= null && iter
!= current
)
2627 history
.remove(iter
.data
);
2628 iter
= history
.first();
2632 history
.prepend(hi
);
2633 if(history
.length() > 25)
2635 unowned List
<Hitem?
> a
= history
.last();
2636 history
.remove(a
.data
);
2640 private void history_clear()
2642 this
.current
= null;
2643 this
.history
= null;
2655 this
.tree_artist
.get_selection().unselect_all();
2656 this
.artist_filter_entry
.set_text("");
2658 this
.metadata_box_clear();
2659 this
.metadata_box_update();
2663 set_artist(string artist
)
2665 if(!this
.get_enabled()) return;
2666 this
.block_update
++;
2669 this
.tree_artist
.get_selection().unselect_all();
2670 this
.tree_album
.get_selection().unselect_all();
2672 this
.artist_filter_entry
.set_text("");
2674 if(this
.model_filter_artist
.get_iter_first(out iter
))
2678 string lartist
= null;
2679 this
.model_filter_artist
.get(iter
, 7, out lartist
, -1);
2680 if( lartist
!= null && lartist
.collate(artist
) == 0)
2682 this
.tree_artist
.get_selection().select_iter(iter
);
2683 this
.tree_artist
.scroll_to_cell(this
.model_filter_artist
.get_path(iter
), null, true, 0.5f
,0f
);
2684 this
.block_update
--;
2686 this
.metadata_box_clear();
2687 this
.metadata_box_update();
2691 while((this
.model_filter_artist
).iter_next(ref iter
));
2693 this
.block_update
--;
2696 this
.metadata_box_clear();
2697 this
.metadata_box_update();
2702 set_album(string artist
, string album
)
2704 if(!this
.get_enabled()) return;
2705 this
.block_update
++;
2706 this
.set_artist(artist
);
2708 this
.album_filter_entry
.set_text("");
2710 if(this
.model_filter_album
.get_iter_first(out iter
))
2714 string lalbum
= null;
2715 this
.model_filter_album
.get(iter
, 6, out lalbum
, -1);
2716 if( lalbum
!= null && lalbum
.collate(album
) == 0)
2718 this
.tree_album
.get_selection().select_iter(iter
);
2719 this
.tree_album
.scroll_to_cell(this
.model_filter_album
.get_path(iter
), null, true, 0.5f
,0f
);
2720 this
.tree_songs
.get_selection().unselect_all();
2721 this
.block_update
--;
2722 this
.metadata_box_update();
2726 while((this
.model_filter_album
).iter_next(ref iter
));
2729 this
.tree_songs
.get_selection().unselect_all();
2731 this
.block_update
--;
2733 this
.metadata_box_clear();
2734 this
.metadata_box_update();
2739 set_song(MPD
.Song song
)
2741 if(!this
.get_enabled()) return;
2742 this
.block_update
++;
2743 if(song
.artist
!= null)
2745 this
.set_artist(song
.artist
);
2746 if(song
.album
!= null)
2748 this
.set_album(song
.artist
,song
.album
);
2753 if(this
.model_songs
.get_iter_first(out iter
))
2757 string ltitle
= null;
2758 this
.model_songs
.get(iter
, 7, out ltitle
, -1);
2759 if( ltitle
!= null && ltitle
.collate(song
.title
) == 0)
2761 this
.tree_songs
.get_selection().select_iter(iter
);
2762 this
.tree_songs
.scroll_to_cell(this
.model_songs
.get_path(iter
), null, true, 0.5f
,0f
);
2763 this
.block_update
--;
2764 this
.metadata_box_update();
2768 while((this
.model_songs
).iter_next(ref iter
));
2772 this
.block_update
--;
2773 this
.metadata_box_clear();
2774 if(this
.update_timeout
> 0)
2776 GLib
.Source
.remove(this
.update_timeout
);
2777 this
.update_timeout
= 0;
2780 /** Add item to history */
2781 var item
= new
Hitem();
2782 item
.song
= song
.copy();
2783 item
.type
= HitemType
.SONG
;
2786 var view
= metadata_box_show_song(song
,true);
2787 this
.metadata_box
.add(view
);
2788 this
.metadata_box
.show_all();
2792 select_browser(Gtk
.TreeView? tree
)
2796 unowned Gtk
.TreeView category_tree
= Gmpc
.Playlist3
.get_category_tree_view();
2797 var sel
= category_tree
.get_selection();
2798 var path
= rref
.get_path();
2801 sel
.select_path(path
);
2806 private string get_extension(string path
)
2808 long length
= path
.length
;
2811 for(; i
>0 && (length
-i
) <8; i
--)
2815 retv
= path
.substring(i
+1);
2822 public override void set_enabled(bool state
)
2828 browser_add( Gmpc
.Playlist3
.get_category_tree_view());
2834 if(this
.rref
!= null)
2836 var path
= rref
.get_path();
2839 unowned
int[] indices
= path
.get_indices();
2840 config
.set_int(this
.get_name(), "position", indices
[0]);
2841 Gtk
.ListStore model
= (Gtk
.ListStore
)rref
.get_model();
2843 if(model
.get_iter(out iter
, path
))
2852 if(this
.get_name() != null)
2853 Gmpc
.config
.set_int(this
.get_name(), "enabled", (int)state
);