small updates
[gmpc.git] / src / browsers / gmpc-metadata-browser2.vala
blobc4aa042b777476da65ac7977bbf1f82c66f1b656
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.
20 /**
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
25 * * Similar songs.
26 * * Similar artist.
27 * * More. (expands, collapses a sub widget
30 using Config;
31 using Gtk;
32 using Gmpc;
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()
52 select_browser(null);
55 construct
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(
70 _("switch metadata"),
71 "",
72 _("Switch to Metadata view"),
73 (Gmpc.Easy.Command.Callback *)show_metadata_search,
74 this);
77 private const int[] version = {0,0,0};
78 public override unowned int[] get_version()
80 return 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);
99 if(this.rref != null)
101 var path = rref.get_path();
102 if(path != null)
104 unowned int[] indices = path.get_indices();
105 config.set_int(this.get_name(), "position", indices[0]);
109 /* Now playing browser */
113 * Browser part
115 /* 'base' widget */
116 private Gtk.Paned paned = null;
117 /* holding the 3 browsers */
118 private Gtk.Box browser_box = null;
119 /* The 3 browsers */
120 /* artist */
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;
126 /* album */
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;
132 /* song */
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
151 * and search
153 private void select_metadata_browser_search(Gtk.Widget widget)
155 select_browser(null);
156 set_base();
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);
169 menu.append(item);
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);
177 menu.append(item);
179 return 2;
181 return 0;
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);
198 return true;
201 return false;
204 * Artist tree view functions */
205 private void browser_artist_entry_changed(Gtk.Editable entry)
207 string text = (entry as Gtk.Entry).get_text();
208 if(text.length > 0)
210 (entry as Gtk.Widget).show();
211 (entry as Gtk.Widget).grab_focus();
213 else
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) =>
232 Gtk.TreeModel model;
233 Gtk.TreeIter iter;
234 if(tree.get_selection().get_selected(out model, out iter))
236 string artist;
237 model.get(iter,7, out artist);
238 if(artist != null)
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();
244 if(data != null)
246 data.first();
249 MPD.PlayQueue.queue_add_song(server, data.song.file);
250 data.next_free();
252 while(data != null);
253 MPD.PlayQueue.queue_commit(server);
258 menu.append(item);
260 item = new Gtk.ImageMenuItem.from_stock("gtk-media-play",null);
261 item.activate.connect((source) =>
263 Gtk.TreeModel model;
264 Gtk.TreeIter iter;
265 if(tree.get_selection().get_selected(out model, out iter))
267 string artist;
268 model.get(iter,7, out artist);
269 if(artist != null)
271 MPD.PlayQueue.clear(server);
272 MPD.PlayQueue.add_artist(server, artist);
273 MPD.Player.play(server);
277 menu.append(item);
279 menu.popup(null, null, null, event.button, event.time);
280 menu.show_all();
281 return true;
285 return false;
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" */
292 string str = null;
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)
299 visible = true;
301 return visible;
303 private bool browser_artist_key_press_event(Gtk.Widget widget, Gdk.EventKey event)
305 unichar uc = Gdk.keyval_to_unicode(event.keyval);
306 if(uc > 0)
308 string outbuf = " ";
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);
315 return true;
317 return false;
320 * Album tree view
322 private void album_add_clicked(Gtk.Widget item )
324 string artist = browser_get_selected_artist();
325 if(artist != null)
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);
335 if(ydata != null)
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);
345 else
346 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
348 if(album != null)
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();
353 if(data != null)
357 MPD.PlayQueue.queue_add_song(server, data.song.file);
358 data.next_free();
360 while(data != null);
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);
381 menu.append(item);
383 item = new Gtk.ImageMenuItem.from_stock("gtk-media-play",null);
384 item.activate.connect(album_replace_clicked);
385 menu.append(item);
387 menu.popup(null, null, null, event.button, event.time);
388 menu.show_all();
389 return true;
393 return false;
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" */
399 string str = null;
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)
406 visible = true;
408 return visible;
412 private bool browser_album_key_press_event(Gtk.Widget widget, Gdk.EventKey event)
414 unichar uc = Gdk.keyval_to_unicode(event.keyval);
415 if(uc > 0)
417 string outbuf = " ";
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);
424 return true;
426 return false;
429 private void browser_album_entry_changed(Gtk.Editable pentry)
431 Gtk.Entry entry = (pentry as Gtk.Entry);
432 string text = entry.get_text();
433 if(text.length > 0)
435 entry.show();
436 entry.grab_focus();
438 else
440 entry.hide();
441 this.tree_album.grab_focus();
443 this.model_filter_album.refilter();
446 * Songs
448 private void song_add_clicked(Gtk.Widget item )
450 unowned MPD.Song? song = browser_get_selected_song();
451 if(song != null)
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);
473 menu.append(item);
475 item = new Gtk.ImageMenuItem.from_stock("gtk-media-play",null);
476 item.activate.connect(song_replace_clicked);
477 menu.append(item);
479 menu.popup(null, null, null, event.button, event.time);
480 menu.show_all();
481 return true;
484 return false;
487 private bool browser_button_release_event(Gtk.Widget widget, Gdk.EventButton event)
489 if(event.button == 8)
491 history_previous();
492 return true;
494 else if (event.button == 9)
496 history_next();
497 return true;
499 return false;
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);
512 /* Artist list */
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);
545 sw.add(tree_artist);
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);
567 /* Album list */
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);
599 sw.add(tree_album);
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);
628 /* Song list */
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);
638 sw.add(tree_songs);
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);
667 /* The right view */
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());
681 /* header */
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);
696 header.show();
698 this.paned.add2(vb);
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()
734 Gtk.TreeIter iter;
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);
741 return artist;
743 return null;
746 private string? browser_get_selected_album()
748 Gtk.TreeIter iter;
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))
753 string album = null;
754 model.get(iter, 6,out album, -1);
755 return album;
757 return null;
759 private unowned MPD.Song? browser_get_selected_song()
761 Gtk.TreeIter iter;
762 var sel = this.tree_songs.get_selection();
763 Gtk.TreeModel model;
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);
768 return songs;
770 return null;
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();
779 if(artist != null)
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();
790 if(iter!= null)
794 list.append_new();
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);
803 if(ydata != null)
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;
812 yi.next(false);
815 iter.next(false);
817 while(iter!= null);
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();
838 if(artist != null)
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);
849 if(ydata != null)
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);
859 else
860 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
862 if(album != null)
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();
876 * Metadata box
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();
884 if(song != null)
886 MPD.PlayQueue.add_song(server,song.file);
887 return;
889 if(artist != null )
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);
899 if(ydata != null)
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);
909 else
910 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
911 if(album != null)
912 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
913 var data = MPD.Database.search_commit(server);
914 if(data != null)
916 data.sort_album_disc_track();
917 while(data != null)
919 MPD.PlayQueue.queue_add_song(server, data.song.file);
920 data.next_free();
922 MPD.PlayQueue.queue_commit(server);
927 private void play_selected_song(Gtk.Button button)
929 unowned MPD.Song? song = browser_get_selected_song();
930 if(song != null)
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)
946 child.destroy();
950 * Add a row to a gtk table
951 * <b>$label:</b> $value
952 * then increments i
955 private void add_entry(Gtk.Grid table, string entry_label, string? value,Gtk.Widget? extra, ref int i, string ? image = null)
957 int j=0;
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));
964 if(image != null)
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);
969 ali.add(wimage);
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);
975 j++;
977 if(value != null)
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);
985 j++;
987 if(extra != null)
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);
991 j++;
993 i++;
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 */
1007 /* Artist image */
1008 var hbox = new Gtk.HBox(false, 6);
1009 /* Album image */
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);
1021 /* Artist image */
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);
1039 int i=0;
1040 /* Title */
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);
1065 i++;
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);
1077 i++;
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);
1108 i++;
1110 /* Artist */
1111 if(song.artist != null)
1113 this.add_entry(info_box, _("Artist"), song.artist, null,ref i, "media-artist");
1115 /* Album */
1116 if(song.album != null)
1118 this.add_entry(info_box, _("Album"), song.album,null, ref i, "media-album");
1120 /* Genre */
1121 if(song.genre != null)
1123 this.add_entry(info_box, _("Genre"), song.genre,null, ref i, "media-genre");
1125 /* 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");
1147 /* Time*/
1148 if(song.time > 0)
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",
1159 song.track,
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);
1193 i++;
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);
1208 /* Lyrics */
1209 i = 0;
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);
1223 var j = i;
1224 button.clicked.connect((source) =>
1226 debug("notebook page %i clicked", j);
1227 notebook.set_current_page(j);
1229 i++;
1231 alib.show();
1234 /* Guitar Tabs */
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);
1248 var j = i;
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;
1260 if(i == 0)
1262 text_view.query_from_song(song);
1263 text_view_queried = true;
1265 alib.show();
1266 i++;
1268 /* Similar songs */
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);
1281 var j = i;
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();
1296 if(i == 0)
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();
1305 i++;
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);
1318 var j = i;
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();
1326 i++;
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 */
1336 if(i > 0)
1338 var page = config.get_int_with_default("MetaData", "song-last-page", 0);
1339 if(page > i)
1341 notebook.set_current_page(0);
1343 else
1345 /* The list is in reversed order, compensate for that. */
1346 var w = group.nth_data(i-page-1);
1347 w.set_active(true);
1348 notebook.set_current_page(page);
1352 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1353 ali.add(hboxje);
1355 /* Create pane in 2. */
1356 var bottom_hbox = new Gtk.HBox(false, 6);
1357 /* left pane */
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);
1375 /* show it */
1376 master_box.pack_start(vbox, false, false, 0);
1377 return master_box;
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(),
1398 0x046,
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);
1451 menu.append(item);
1453 stdout.printf("song context menu show\n");
1454 menu.show_all();
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();
1466 result_hbox.show();
1467 vbox.pack_start(result_hbox, false, false);
1469 if(current != null)
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;
1491 if(state == true)
1493 this.browser_box.hide();
1494 show_button.label = _("Show sidebar");
1496 else {
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);
1527 /* Artist image */
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;
1538 song.album = album;
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);
1547 int i=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);
1607 /* Separator */
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);
1619 /* Lyrics */
1620 i = 0;
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);
1635 var j = i;
1636 rbutton.clicked.connect((source) =>
1638 debug("notebook page %i clicked", j);
1639 notebook.set_current_page(j);
1641 i++;
1643 alib.show();
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);
1680 menu.append(item);
1682 stdout.printf("song context menu show\n");
1683 menu.show_all();
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);
1691 var j = i;
1692 bool seen = false;
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);
1701 if(!seen)
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);
1710 if(ydata != null)
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);
1719 else
1720 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
1722 if(album != null)
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);
1729 seen = true;
1732 slhbox.show();
1733 i++;
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 */
1743 if(i > 0)
1745 var page = config.get_int_with_default("MetaData", "album-last-page", 0);
1746 if(page > i)
1748 notebook.set_current_page(0);
1750 else
1752 /* The list is in reversed order, compensate for that. */
1753 var w = group.nth_data(i-page-1);
1754 w.set_active(true);
1755 notebook.set_current_page(page);
1759 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1760 ali.add(hboxje);
1762 /* Create pane in 2. */
1763 var bottom_hbox = new Gtk.HBox(false, 6);
1764 /* left pane */
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
1784 * <artist name>
1785 * <image> | <array with info>
1786 * < buttonss>
1788 * <artist info text>
1790 * <similar artists>
1791 * <links>
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);
1797 var i = 0;
1798 vbox.border_width = 8;
1800 /* Set up header */
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;
1807 /* Artist image */
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);
1827 /* Artist */
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);
1881 /* Separator */
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);
1892 i = 0;
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);
1908 var j = i;
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);
1917 i++;
1919 alib.show();
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);
1933 var j = i;
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();
1944 i++;
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);
1981 menu.append(item);
1983 stdout.printf("song context menu show\n");
1984 menu.show_all();
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);
1993 var j = i;
1994 bool seen = false;
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);
2003 if(!seen)
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);
2012 seen = true;
2015 slhbox.show();
2016 i++;
2019 if( song.artist != null)
2021 int albums =0;
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.
2030 Gtk.TreeIter titer;
2031 if(this.model_albums.get_iter_first(out titer))
2035 unowned MPD.Song? asong = null;
2036 this.model_albums.get(titer,0, &asong);
2037 if(asong != null)
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();
2045 /* Create button */
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);
2058 /* Create label */
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");
2063 strlabel += "</b>";
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);
2068 /* add label */
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);
2077 return true;
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);
2091 p.destroy();
2095 * Play machine
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,
2105 but_song.artist,
2106 but_song.album);
2107 MPD.Player.play(server);
2108 p.destroy();
2112 * Add to play queue
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,
2121 but_song.artist,
2122 but_song.album);
2123 p.destroy();
2126 p.add(hbox);
2127 hbox.show_all();
2128 p.popup(event);
2129 return true;
2131 return false;
2133 albums++;
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);
2146 var j = i;
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);
2155 album_hbox.show();
2156 i++;
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 */
2167 if(i > 0)
2169 var page = config.get_int_with_default("MetaData", "artist-last-page", 0);
2170 if(page > i)
2172 notebook.set_current_page(0);
2174 else
2176 /* The list is in reversed order, compensate for that. */
2177 var w = group.nth_data(i-page-1);
2178 w.set_active(true);
2179 notebook.set_current_page(page);
2184 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
2185 ali.add(hboxje);
2187 /* left pane */
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;
2224 return false;
2226 string artist = browser_get_selected_artist();
2227 string album = browser_get_selected_album();
2228 unowned MPD.Song? song = browser_get_selected_song();
2230 if(song != null)
2232 /** Add item to history */
2233 var item = new Hitem();
2234 item.song = song.copy();
2235 item.type = HitemType.SONG;
2236 history_add(item);
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;
2250 history_add(item);
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;
2261 history_add(item);
2263 metadata_box_show_artist(artist);
2265 else
2267 var item = new Hitem();
2268 item.search_string = null;
2269 item.type = HitemType.BASE;
2270 history_add(item);
2271 metadata_box_show_base();
2274 this.update_timeout = 0;
2275 return false;
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();
2285 Gtk.TreeIter iter;
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)
2294 string artist;
2295 this.selected = true;
2296 this.browser_init();
2297 container.add(this.paned);
2299 /* update if non selected */
2300 artist = browser_get_selected_artist();
2301 if(artist == null)
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);
2314 private
2315 void
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();
2325 private
2326 void
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);
2342 * History
2344 private enum HitemType
2346 BASE,
2347 ARTIST,
2348 ALBUM,
2349 SONG
2351 private class Hitem
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)
2361 switch(hi.type)
2363 case HitemType.BASE:
2364 this.set_base();
2365 break;
2366 case HitemType.ARTIST:
2367 this.set_artist(hi.song.artist);
2368 break;
2369 case HitemType.ALBUM:
2370 this.set_album(hi.song.artist, hi.song.album);
2371 break;
2372 case HitemType.SONG:
2373 this.set_song(hi.song);
2374 break;
2375 default:
2376 metadata_box_clear();
2377 break;
2380 private void history_previous()
2382 if(history == null || current == null)
2384 return;
2386 if(current.next == null)
2388 return;
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)
2399 return;
2401 if(current.prev == null)
2403 return;
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");
2413 if(a != null)
2415 current = a;
2416 show_hitem(current.data);
2419 private void history_show_list()
2421 var menu = new Gtk.Menu();
2422 unowned List<Hitem?> iter = history.last();
2423 while(iter!= null)
2425 unowned Hitem i = iter.data;
2426 string label = "";
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;
2435 else
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);
2455 menu.append(item);
2456 iter = iter.prev;
2458 menu.show_all();
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())
2467 child.destroy();
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);
2480 ali.add(image);
2481 hist_box.attach(ali, 0, 0, 1, 1);//pack_start(ali, true, true, 0);
2482 //hist_box.attach(ali, 1, 0, 1,1);
2484 else
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 */
2494 if(artist != null)
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)=>
2503 set_artist(artist);
2505 hist_box.attach(button, 1, 0, 1,1);//pack_start(button, true, true, 0);
2508 else
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);
2517 /* Album */
2518 if(album != null)
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);
2529 else
2531 var button = new Gtk.Button();//.with_label(album);
2533 var ali = new Gtk.Alignment(0.0f, 0.5f, 0.0f, 0.0f);
2534 button.add(ali);
2536 var gr = new Gtk.Grid();
2537 gr.set_column_spacing(6);
2538 ali.add(gr);
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);
2552 button.show_all();
2553 hist_box.attach(button, 4,0,1,1);//pack_start(button, true, true, 0);
2557 if(title != null)
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);
2593 dd_but.add(arrow);
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);
2606 return box;
2608 private void history_add(Hitem hi)
2610 if(history != null)
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))
2617 return;
2621 /* clean items in the future */
2622 if(history != null)
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);
2638 current = history;
2640 private void history_clear()
2642 this.current = null;
2643 this.history = null;
2648 * Public api
2650 public
2651 void
2652 set_base()
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();
2661 public
2662 void
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();
2671 /* clear */
2672 this.artist_filter_entry.set_text("");
2673 Gtk.TreeIter iter;
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();
2688 return;
2691 while((this.model_filter_artist).iter_next(ref iter));
2693 this.block_update--;
2696 this.metadata_box_clear();
2697 this.metadata_box_update();
2700 public
2701 void
2702 set_album(string artist, string album)
2704 if(!this.get_enabled()) return;
2705 this.block_update++;
2706 this.set_artist(artist);
2707 /* clear */
2708 this.album_filter_entry.set_text("");
2709 Gtk.TreeIter iter;
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();
2723 return;
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();
2737 public
2738 void
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);
2752 Gtk.TreeIter iter;
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();
2765 return;
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;
2784 history_add(item);
2786 var view = metadata_box_show_song(song,true);
2787 this.metadata_box.add(view);
2788 this.metadata_box.show_all();
2790 public
2791 void
2792 select_browser(Gtk.TreeView? tree)
2794 if(rref != null)
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();
2799 if(path != null)
2801 sel.select_path(path);
2806 private string get_extension(string path)
2808 long length = path.length;
2809 long i=length;
2810 string retv = null;
2811 for(; i>0 && (length-i) <8; i--)
2813 if(path[i] == '.')
2815 retv = path.substring(i+1);
2816 return retv;
2819 return retv;
2822 public override void set_enabled(bool state)
2824 if(state)
2826 if(rref == null)
2828 browser_add( Gmpc.Playlist3.get_category_tree_view());
2829 browser_init();
2832 else
2834 if(this.rref != null)
2836 var path = rref.get_path();
2837 if(path != null)
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();
2842 Gtk.TreeIter iter;
2843 if(model.get_iter(out iter, path))
2845 model.remove(iter);
2848 rref = null;
2852 if(this.get_name() != null)
2853 Gmpc.config.set_int(this.get_name(), "enabled", (int)state);