Re-add rating.
[gmpc.git] / src / browsers / gmpc-metadata-browser2.vala
bloba2642d3cb357ec83083abd08ddbaf2c528333343
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 public void set_orientation()
503 if(paned != null) {
504 if(config.get_int_with_default("tag2-plugin", "orientation", 0) == 1)
506 (paned as Gtk.Orientable).set_orientation(Gtk.Orientation.VERTICAL);
507 (browser_box as Gtk.Orientable).set_orientation(Gtk.Orientation.HORIZONTAL);
508 }else{
509 (paned as Gtk.Orientable).set_orientation(Gtk.Orientation.HORIZONTAL);
510 (browser_box as Gtk.Orientable).set_orientation(Gtk.Orientation.VERTICAL);
514 private void browser_init()
516 if(this.paned == null)
518 this.paned = new Gtk.HPaned();
519 paned_size_group.add_paned(this.paned);
520 /* Bow with browsers */
521 this.browser_box = new Gtk.VBox(true, 6);
522 this.paned.add1(this.browser_box);
525 /* Artist list */
526 var box = new Gtk.VBox(false, 6);
527 this.browser_box.pack_start(box, true, true, 0);
529 this.artist_filter_entry = new Gtk.Entry();
531 this.artist_filter_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, "gtk-clear");
532 this.artist_filter_entry.icon_press.connect((source, pos, event)=>
534 if(pos == Gtk.EntryIconPosition.SECONDARY) source.set_text("");
537 this.artist_filter_entry.set_no_show_all(true);
538 this.artist_filter_entry.changed.connect(browser_artist_entry_changed);
540 box.pack_start(this.artist_filter_entry, false, false, 0);
542 var sw = new Gtk.ScrolledWindow(null, null);
543 sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
544 sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
545 box.pack_start(sw, true, true, 0);
547 this.model_artist = new Gmpc.MpdData.Model();
548 this.model_filter_artist = new Gtk.TreeModelFilter(this.model_artist, null);
549 this.model_filter_artist.set_visible_func(visible_func_artist);
550 this.tree_artist = new Gtk.TreeView.with_model(this.model_filter_artist);
551 this.tree_artist.rules_hint = true;
552 new Gmpc.MpdData.Treeview.Tooltip(this.tree_artist, Gmpc.MetaData.Type.ARTIST_ART);
554 this.tree_artist.set_enable_search(false);
555 this.tree_artist.button_press_event.connect(browser_button_press_event);
556 this.tree_artist.button_release_event.connect(artist_browser_button_release_event);
557 this.tree_artist.key_press_event.connect(browser_artist_key_press_event);
558 sw.add(tree_artist);
559 /* setup the columns */
560 var column = new Gtk.TreeViewColumn();
561 if(config.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
563 var prenderer = new Gtk.CellRendererPixbuf();
564 prenderer.set("height", this.model_artist.icon_size);
565 column.pack_start(prenderer, false);
566 column.add_attribute(prenderer, "pixbuf",27);
568 var trenderer = new Gtk.CellRendererText();
569 column.pack_start(trenderer, true);
570 column.add_attribute(trenderer, "text", 7);
571 this.tree_artist.append_column(column);
572 column.set_title(_("Artist"));
573 this.tree_artist.get_selection().changed.connect(browser_artist_changed);
575 /* set fixed height mode */
576 column.sizing = Gtk.TreeViewColumnSizing.FIXED;
577 this.tree_artist.set_fixed_height_mode(true);
580 /* Album list */
582 box = new Gtk.VBox(false, 6);
583 this.browser_box.pack_start(box, true, true, 0);
586 this.album_filter_entry = new Gtk.Entry();
588 this.album_filter_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, "gtk-clear");
589 this.album_filter_entry.icon_press.connect((source, pos, event)=>
591 if(pos == Gtk.EntryIconPosition.SECONDARY) source.set_text("");
593 this.album_filter_entry.set_no_show_all(true);
594 this.album_filter_entry.changed.connect(browser_album_entry_changed);
595 box.pack_start(this.album_filter_entry, false, false, 0);
597 sw = new Gtk.ScrolledWindow(null, null);
598 sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
599 sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
600 box.pack_start(sw, true, true, 0);
601 this.model_albums = new Gmpc.MpdData.Model();
602 this.model_filter_album = new Gtk.TreeModelFilter(this.model_albums, null);
603 this.model_filter_album.set_visible_func(visible_func_album);
604 this.tree_album = new Gtk.TreeView.with_model(this.model_filter_album);
605 this.tree_album.rules_hint = true;
606 this.tree_album.set_enable_search(false);
607 new Gmpc.MpdData.Treeview.Tooltip(this.tree_album, Gmpc.MetaData.Type.ALBUM_ART);
609 this.tree_album.button_press_event.connect(browser_button_press_event);
610 this.tree_album.button_release_event.connect(album_browser_button_release_event);
611 this.tree_album.key_press_event.connect(browser_album_key_press_event);
612 sw.add(tree_album);
613 /* setup the columns */
614 column = new Gtk.TreeViewColumn();
615 if(config.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
617 var prenderer = new Gtk.CellRendererPixbuf();
618 prenderer.set("height", this.model_albums.icon_size);
619 column.pack_start(prenderer, false);
620 column.add_attribute(prenderer, "pixbuf",27);
622 this.tree_album.append_column(column);
624 column = new Gtk.TreeViewColumn();
625 trenderer = new Gtk.CellRendererText();
626 column.pack_start(trenderer, true);
627 column.add_attribute(trenderer, "text", 14);
628 this.tree_album.append_column(column);
629 column.set_title(_("Year"));
631 column = new Gtk.TreeViewColumn();
632 trenderer = new Gtk.CellRendererText();
633 column.pack_start(trenderer, true);
634 column.add_attribute(trenderer, "text", 6);
635 this.tree_album.append_column(column);
636 column.set_title(_("Album"));
639 this.tree_album.get_selection().changed.connect(browser_album_changed);
641 /* Song list */
642 sw = new Gtk.ScrolledWindow(null, null);
643 sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
644 sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
645 this.browser_box.pack_start(sw, true, true, 0);
646 this.model_songs = new Gmpc.MpdData.Model();
647 this.tree_songs = new Gtk.TreeView.with_model(this.model_songs);
648 this.tree_songs.rules_hint = true;
649 this.tree_songs.button_press_event.connect(browser_button_press_event);
650 this.tree_songs.button_release_event.connect(song_browser_button_release_event);
651 sw.add(tree_songs);
652 /* setup the columns */
653 column = new Gtk.TreeViewColumn();
655 if(config.get_int_with_default("tag2-plugin", "show-image-column", 1) == 1)
657 var prenderer = new Gtk.CellRendererPixbuf();
658 column.pack_start(prenderer, false);
659 column.add_attribute(prenderer, "icon-name",23);
661 trenderer = new Gtk.CellRendererText();
662 column.pack_start(trenderer, false);
663 column.add_attribute(trenderer, "text", 10);
665 column.set_title(_("Track"));
666 this.tree_songs.append_column(column);
668 column = new Gtk.TreeViewColumn();
669 trenderer = new Gtk.CellRendererText();
670 column.pack_start(trenderer, true);
671 column.add_attribute(trenderer, "text", 7);
674 this.tree_songs.append_column(column);
675 this.tree_songs.set_search_column(7);
676 column.set_title(_("Songs"));
678 this.tree_songs.get_selection().changed.connect(browser_songs_changed);
680 /* The right view */
681 this.metadata_sw = new Gtk.ScrolledWindow(null, null);
682 this.metadata_sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
683 this.metadata_sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN);
685 this.metadata_box = new Gtk.EventBox();
686 this.metadata_box.set_visible_window(true);
687 this.metadata_sw.add_with_viewport(this.metadata_box);
688 (this.metadata_box as Gtk.Container).set_focus_hadjustment(
689 this.metadata_sw.get_hadjustment());
690 (this.metadata_box as Gtk.Container).set_focus_vadjustment(
691 this.metadata_sw.get_vadjustment());
694 /* header */
695 var vb = new Gtk.VBox(false, 0);
696 vb.pack_end(this.metadata_sw, true,true,0);
698 this.metadata_box.get_style_context().add_class(Gtk.STYLE_CLASS_VIEW);
700 this.header = new Gtk.EventBox();
702 this.header.get_style_context().add_class(Gtk.STYLE_CLASS_HIGHLIGHT);
705 var sp = new Gtk.Separator(Gtk.Orientation.HORIZONTAL);
706 sp.set_size_request(-1, 1);
707 vb.pack_start(sp, false, false, 0);
708 vb.pack_start(header, false, false,0);
709 header.show();
711 this.paned.add2(vb);
715 this.paned.button_release_event.connect(browser_button_release_event);
717 this.reload_browsers();
719 this.paned.show_all();
721 if(config.get_int_with_default("metadata browser", "show-browsers", 1) == 0)
723 this.browser_box.hide();
725 this.set_orientation();
728 private void reload_browsers()
730 if(this.paned == null) return;
732 this.model_songs.set_mpd_data(null);
733 this.model_albums.set_mpd_data(null);
734 this.model_artist.set_mpd_data(null);
736 this.artist_filter_entry.set_text("");
737 this.album_filter_entry.set_text("");
739 /* Fill in the first browser */
740 MPD.Database.search_field_start(server,MPD.Tag.Type.ARTIST);
741 var data = MPD.Database.search_commit(server);
742 data.sort_album_disc_track();
743 this.model_artist.set_mpd_data((owned)data);
746 private string? browser_get_selected_artist()
748 Gtk.TreeIter iter;
749 var sel = this.tree_artist.get_selection();
750 Gtk.TreeModel model = null;//this.model_artist;
751 if(sel.get_selected(out model, out iter))
753 string artist = null;
754 model.get(iter, 7,out artist, -1);
755 return artist;
757 return null;
760 private string? browser_get_selected_album()
762 Gtk.TreeIter iter;
763 var sel = this.tree_album.get_selection();
764 Gtk.TreeModel model = null;//this.model_albums;
765 if(sel.get_selected(out model, out iter))
767 string album = null;
768 model.get(iter, 6,out album, -1);
769 return album;
771 return null;
773 private unowned MPD.Song? browser_get_selected_song()
775 Gtk.TreeIter iter;
776 var sel = this.tree_songs.get_selection();
777 Gtk.TreeModel model;
778 if(sel.get_selected(out model, out iter))
780 unowned MPD.Song? songs = null;
781 this.model_songs .get(iter, 0,out songs, -1);
782 return songs;
784 return null;
786 private void browser_artist_changed(Gtk.TreeSelection sel)
788 this.model_albums.set_mpd_data(null);
789 this.model_songs.set_mpd_data(null);
790 this.metadata_box_clear();
792 string artist = browser_get_selected_artist();
793 if(artist != null)
795 /* Fill in the first browser */
796 MPD.Database.search_field_start(server,MPD.Tag.Type.ALBUM);
797 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
798 var data = MPD.Database.search_commit(server);
799 data.sort_album_disc_track();
801 this.model_albums.set_request_artist(artist);
802 MPD.Data.Item list = null;
803 unowned MPD.Data.Item iter = data.get_first();
804 if(iter!= null)
808 list.append_new();
809 list.type = MPD.Data.Type.SONG;
810 list.song = new MPD.Song();
811 list.song.artist = artist;
812 list.song.album = iter.tag;
813 MPD.Database.search_field_start(server,MPD.Tag.Type.DATE);
814 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
815 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, iter.tag);
816 var ydata = MPD.Database.search_commit(server);
817 if(ydata != null)
819 unowned MPD.Data.Item yi = ydata.get_first();
820 while(list.song.date == null && yi != null)
822 if(yi.tag != null && yi.tag.length > 0)
824 list.song.date = yi.tag;
826 yi.next(false);
829 iter.next(false);
831 while(iter!= null);
834 list.sort_album_disc_track();
835 this.model_albums.set_mpd_data((owned)list);
837 MPD.Database.search_start(server,true);
838 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
839 data = MPD.Database.search_commit(server);
840 data.sort_album_disc_track();
841 this.model_songs.set_mpd_data((owned)data);
844 this.metadata_box_update();
846 private void browser_album_changed(Gtk.TreeSelection album_sel)
848 this.model_songs.set_mpd_data(null);
849 this.metadata_box_clear();
851 string artist = browser_get_selected_artist();
852 if(artist != null)
854 string album = browser_get_selected_album();
855 string albumartist = null;
857 if(album != null && Gmpc.server.tag_supported(MPD.Tag.Type.ALBUM_ARTIST))
859 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM_ARTIST);
860 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
861 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
862 var ydata = MPD.Database.search_commit(server);
863 if(ydata != null)
865 if(ydata.tag.length > 0)
866 albumartist = ydata.tag;
869 /* Fill in the first browser */
870 MPD.Database.search_start(server,true);
871 if(albumartist != null&& albumartist.length > 0)
872 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM_ARTIST, albumartist);
873 else
874 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
876 if(album != null)
877 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
878 var data = MPD.Database.search_commit(server);
879 data.sort_album_disc_track();
880 this.model_songs.set_mpd_data((owned)data);
882 this.metadata_box_update();
884 private void browser_songs_changed (Gtk.TreeSelection song_sel)
886 this.metadata_box_clear();
887 this.metadata_box_update();
890 * Metadata box
893 private void add_selected_song(Gtk.Button button)
895 string artist = browser_get_selected_artist();
896 string album = browser_get_selected_album();
897 unowned MPD.Song? song = browser_get_selected_song();
898 if(song != null)
900 MPD.PlayQueue.add_song(server,song.file);
901 return;
903 if(artist != null )
905 /* Hunt albumartist */
906 string albumartist = null;
907 if(album != null&& Gmpc.server.tag_supported(MPD.Tag.Type.ALBUM_ARTIST))
909 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM_ARTIST);
910 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
911 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
912 var ydata = MPD.Database.search_commit(server);
913 if(ydata != null)
915 if(ydata.tag.length > 0)
916 albumartist = ydata.tag;
920 MPD.Database.search_start(server,true);//server,MPD.Tag.Type.FILENAME);
921 if(albumartist != null&& albumartist.length > 0)
922 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM_ARTIST, albumartist);
923 else
924 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
925 if(album != null)
926 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
927 var data = MPD.Database.search_commit(server);
928 if(data != null)
930 data.sort_album_disc_track();
931 while(data != null)
933 MPD.PlayQueue.queue_add_song(server, data.song.file);
934 data.next_free();
936 MPD.PlayQueue.queue_commit(server);
941 private void play_selected_song(Gtk.Button button)
943 unowned MPD.Song? song = browser_get_selected_song();
944 if(song != null)
946 Gmpc.MpdInteraction.play_path(song.file);
949 private void replace_selected_song(Gtk.Button button)
951 MPD.PlayQueue.clear(server);
952 this.add_selected_song(button);
953 MPD.Player.play(server);
955 private void metadata_box_clear()
957 var list = this.metadata_box.get_children();
958 foreach(Gtk.Widget child in list)
960 child.destroy();
964 * Add a row to a gtk table
965 * <b>$label:</b> $value
966 * then increments i
969 private void add_entry(Gtk.Grid table, string entry_label, string? value,Gtk.Widget? extra, ref int i, string ? image = null)
971 int j=0;
972 if(value == null && extra == null) return;
973 var box = new Gtk.Grid();
974 var label = new Gtk.Label("");
975 box.column_spacing = 6;
976 label.set_alignment(0.0f, 0.0f);
977 label.set_markup(Markup.printf_escaped("<b>%s:</b>",entry_label));
978 if(image != null)
980 /* Make sure the icon always lines out to the top */
981 var ali = new Gtk.Alignment (0f, 0f, 0f, 0f);
982 var wimage = new Gtk.Image.from_icon_name(image, Gtk.IconSize.MENU);
983 ali.add(wimage);
984 box.attach(ali, 0,0,1,1);
986 box.attach(label, 1,0,1,1);
987 // table.attach(box, j,(j+1),i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
988 table.attach(box,j,i, 1, 1);
989 j++;
991 if(value != null)
993 var pt_label = new Gtk.Label(value);
994 pt_label.set_selectable(true);
995 pt_label.set_alignment(0.0f, 0.0f);
996 pt_label.set_line_wrap(true);
997 // table.attach(pt_label, j,(j+1),i,i+1,Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
998 table.attach(pt_label, j, i, 1, 1);
999 j++;
1001 if(extra != null)
1003 //table.attach(extra, j,(j+1),i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
1004 table.attach(extra,j, i, 1, 1);
1005 j++;
1007 i++;
1010 public Gtk.Widget metadata_box_show_song(MPD.Song tmp_song, bool show_controls)
1012 var master_box = new Gtk.VBox (false, 6);
1013 var vbox = new Gtk.VBox (false,6);
1014 var song = tmp_song.copy();
1015 vbox.border_width = 8;
1017 history_bc_header(HitemType.SONG, song.artist, song.album, song.title);
1020 /* Start building the gui */
1021 /* Artist image */
1022 var hbox = new Gtk.HBox(false, 6);
1023 /* Album image */
1024 var ali = new Gtk.Alignment(0f,0f,0f,0f);
1025 int meta_size = (int)(this.metadata_box.get_allocated_width()*0.20);
1026 meta_size = int.min(meta_size, (int)(this.metadata_sw.get_allocated_height()*0.30));
1027 meta_size = int.min(int.max(100, meta_size), 250);
1028 var album_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
1029 album_image.set_scale_up(true);
1030 album_image.set_squared(false);
1031 ali.add(album_image);
1032 album_image.update_from_song(song);
1033 hbox.pack_start(ali, false, false, 0);
1035 /* Artist image */
1036 ali = new Gtk.Alignment(1f,0f,0f,0f);
1037 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
1039 artist_image.set_no_cover_icon("no-artist");
1040 artist_image.set_loading_cover_icon("fetching-artist");
1041 artist_image.set_scale_up(true);
1042 artist_image.set_hide_on_na(true);
1043 artist_image.set_squared(false);
1044 artist_image.update_from_song(song);
1045 ali.add(artist_image);
1046 hbox.pack_end(ali, false, false, 0);
1049 /* Information box */
1050 var info_box = new Gtk.Grid();
1051 info_box.set_row_spacing(3);
1052 info_box.set_column_spacing(8);
1053 int i=0;
1054 /* Title */
1055 if(song.title != null)
1058 var box = new Gtk.HBox(false, 6);
1060 if(config.get_int_with_default("Interface", "hide-favorites-icon",0) == 0)
1062 var fav_button = new Gmpc.Favorites.Button();
1063 fav_button.set_song(song);
1064 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1065 ali.add(fav_button);
1066 box.pack_start(ali, false, false, 0);
1068 var label = new Gtk.Label(song.title);
1069 label.selectable = true;
1070 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",
1071 this.title_color,Pango.SCALE*20 ,song.title));
1072 label.set_ellipsize(Pango.EllipsizeMode.END);
1073 label.set_alignment(0.0f, 0.5f);
1074 box.pack_start(label, true, true, 0);
1075 //hist_box.pack_start(box, true, true, 0);
1076 //vbox.pack_start(box, true, true, 0);
1077 //info_box.attach(box, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1078 info_box.attach(box, i,0, 2,1);
1079 i++;
1081 if(MPD.Sticker.supported(server))
1083 var rating_button = new Gmpc.Rating(server, song);
1084 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1085 ali.add(rating_button);
1086 //hist_box.pack_start(ali, false, false, 0);
1087 this.add_entry(info_box, _("Rating"), null,ali,ref i, "rating");
1090 else if (song.name!= null)
1092 var label = new Gtk.Label(song.name);
1093 label.selectable = true;
1094 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
1095 title_color, Pango.SCALE*20, song.name));
1096 label.set_ellipsize(Pango.EllipsizeMode.END);
1097 label.set_alignment(0.0f, 0.5f);
1098 //info_box.attach(label, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1099 info_box.attach(label,i, 0, 2, 1);
1100 i++;
1102 else if (song.file != null)
1104 var filename = GLib.Path.get_basename(song.file);
1105 var label = new Gtk.Label(song.name);
1106 label.selectable = true;
1109 var regex_a = new GLib.Regex ("\\.[0-9a-zA-Z]*$");
1110 filename = regex_a.replace_literal (filename, -1, 0, "");
1112 catch (GLib.RegexError e)
1114 GLib.error("%s", e.message);
1118 var regex_b = new GLib.Regex ("_");
1119 filename = regex_b.replace_literal (filename, -1, 0, " ");
1121 catch (GLib.RegexError e)
1123 GLib.error("%s", e.message);
1125 label.set_markup(GLib.Markup.printf_escaped("<span color='%s' size='%i' weight='bold'>%s</span>",this.
1126 title_color, Pango.SCALE*20, filename));
1127 label.set_ellipsize(Pango.EllipsizeMode.END);
1128 label.set_alignment(0.0f, 0.5f);
1129 //info_box.attach(label, 0,2, i, i+1,Gtk.AttachOptions.FILL,Gtk.AttachOptions.FILL,0,0);
1130 info_box.attach(label, 0,2, i, i+1);
1131 i++;
1133 /* Artist */
1134 if(song.artist != null)
1136 this.add_entry(info_box, _("Artist"), song.artist, null,ref i, "media-artist");
1138 /* Album */
1139 if(song.album != null)
1141 this.add_entry(info_box, _("Album"), song.album,null, ref i, "media-album");
1143 /* Genre */
1144 if(song.genre != null)
1146 this.add_entry(info_box, _("Genre"), song.genre,null, ref i, "media-genre");
1148 /* Genre */
1149 if(song.date != null)
1151 this.add_entry(info_box, _("Date"), song.date,null, ref i, "media-date");
1153 if(song.file != null)
1156 string extension = null;
1157 extension = get_extension(song.file);
1158 if(extension != null)
1160 this.add_entry(info_box, _("Codec"), extension,null, ref i, "media-codec");
1163 string directory = GLib.Path.get_dirname(song.file);
1164 if(directory != null)
1166 this.add_entry(info_box, _("Directory"), directory, null, ref i, "gtk-open");
1170 /* Time*/
1171 if(song.time > 0)
1173 this.add_entry(info_box, _("Length"),Gmpc.Misc.format_time((ulong) song.time, ""),null, ref i, "media-track-length");
1176 if(song.track != null)
1178 var label = new Gtk.Label("");
1179 label.selectable = true;
1180 label.set_ellipsize(Pango.EllipsizeMode.END);
1181 label.set_markup(GLib.Markup.printf_escaped("%s %s",
1182 song.track,
1183 (song.disc != null)? "[%s]".printf(song.disc):""
1185 label.set_alignment(0.0f, 0.5f);
1186 this.add_entry(info_box, _("Track"),null,label, ref i, "media-num-tracks");
1190 /* Player controls */
1191 var control_hbox = new Gtk.VBox (false, 6);
1193 var abutton = new Gtk.Button.from_stock("gtk-add");
1194 abutton.set_tooltip_text(_("Add the item to the play queue"));
1195 abutton.set_property("xalign", 0.0f);
1196 abutton.set_relief(Gtk.ReliefStyle.NONE);
1197 abutton.clicked.connect(add_selected_song);
1198 control_hbox.pack_start(abutton, false, false,0);
1200 abutton = new Gtk.Button.with_mnemonic(_("_Clear and play"));
1201 abutton.set_tooltip_text(_("Replace the current play queue with this item"));
1202 abutton.set_property("xalign", 0.0f);
1203 abutton.set_image(new Gtk.Image.from_stock("gtk-redo", Gtk.IconSize.BUTTON));
1204 abutton.set_relief(Gtk.ReliefStyle.NONE);
1205 abutton.clicked.connect(replace_selected_song);
1206 control_hbox.pack_start(abutton, false, false,0);
1208 abutton = new Gtk.Button.from_stock("gtk-media-play");
1209 abutton.set_tooltip_text(_("Play this song"));
1210 abutton.set_property("xalign", 0.0f);
1211 abutton.set_relief(Gtk.ReliefStyle.NONE);
1212 abutton.clicked.connect(play_selected_song);
1213 control_hbox.pack_start(abutton, false, false,0);
1215 // info_box.attach(control_hbox, 0,2,i,i+1,Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL, Gtk.AttachOptions.SHRINK|Gtk.AttachOptions.FILL,0,0);
1216 i++;
1219 hbox.pack_start(info_box, true, true, 0);
1220 hbox.pack_start(control_hbox, false, false, 0);
1221 vbox.pack_start(hbox, false, false, 0);
1224 var hboxje = new Gtk.HBox(false, 6);
1226 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1227 var notebook = new Gtk.Notebook();
1228 notebook.set_show_border(false);
1229 notebook.set_show_tabs(false);
1231 /* Lyrics */
1232 i = 0;
1233 unowned SList<unowned Gtk.RadioButton> group = null;
1234 if(config.get_int_with_default("MetaData", "show-lyrics",1) == 1)
1236 var alib = new Gtk.Alignment(0f,0f,1f,0f);
1237 var text_view = new Gmpc.MetaData.TextView(Gmpc.MetaData.Type.SONG_TXT);
1238 text_view.set_left_margin(8);
1239 text_view.query_from_song(song);
1241 alib.add(text_view);
1242 notebook.append_page(alib, new Gtk.Label("Lyrics"));
1243 var button = new Gtk.RadioButton.with_label(group,("Lyrics"));
1244 group = button.get_group();
1245 hboxje.pack_start(button, false, false, 0);
1246 var j = i;
1247 button.clicked.connect((source) =>
1249 debug("notebook page %i clicked", j);
1250 notebook.set_current_page(j);
1252 i++;
1254 alib.show();
1257 /* Guitar Tabs */
1258 if(config.get_int_with_default("MetaData", "show-guitar-tabs",1) == 1)
1260 var alib = new Gtk.Alignment(0f,0f,1f,0f);
1261 var text_view = new Gmpc.MetaData.TextView(Gmpc.MetaData.Type.SONG_GUITAR_TAB);
1262 text_view.use_monospace = true;
1263 text_view.set_left_margin(8);
1264 var text_view_queried = false;
1266 alib.add(text_view);
1267 notebook.append_page(alib, new Gtk.Label(_("Guitar Tabs")));
1268 var button = new Gtk.RadioButton.with_label(group,_("Guitar Tabs"));
1269 group = button.get_group();
1270 hboxje.pack_start(button, false, false, 0);
1271 var j = i;
1272 /* Only query the guitar-tab when opened or first notebook page*/
1273 button.clicked.connect((source) =>
1275 debug("notebook page %i clicked", j);
1276 notebook.set_current_page(j);
1277 if(!text_view_queried)
1279 text_view.query_from_song(song);
1280 text_view_queried = true;
1283 if(i == 0)
1285 text_view.query_from_song(song);
1286 text_view_queried = true;
1288 alib.show();
1289 i++;
1291 /* Similar songs */
1293 if(config.get_int_with_default("MetaData", "show-similar-songs",1) == 1)
1295 var similar_songs_queried = false;
1296 var similar_songs_box = new Gtk.Alignment(0f,0f,0f,0f);
1298 notebook.append_page(similar_songs_box, new Gtk.Label(_("Similar Songs")));
1300 var button = new Gtk.RadioButton.with_label(group,_("Similar Songs"));
1301 group = button.get_group();
1302 hboxje.pack_start(button, false, false, 0);
1304 var j = i;
1305 /* Only query when opened or first notebook page*/
1306 button.clicked.connect((source) =>
1308 debug("notebook page %i clicked", j);
1309 notebook.set_current_page(j);
1310 if(!similar_songs_queried)
1312 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
1313 similar_songs.update();
1314 similar_songs_queried = true;
1315 similar_songs_box.add(similar_songs);
1316 similar_songs_box.show_all();
1319 if(i == 0)
1321 var similar_songs = new Gmpc.MetaData.Widgets.SimilarSongs(song);
1322 similar_songs.update();
1323 similar_songs_queried = true;
1324 similar_songs_box.add(similar_songs);
1325 similar_songs_box.show_all();
1327 similar_songs_box.show();
1328 i++;
1331 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1 && song.artist != null)
1333 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
1335 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artists")));
1337 var button = new Gtk.RadioButton.with_label(group,_("Similar Artists"));
1338 group = button.get_group();
1339 hboxje.pack_start(button, false, false, 0);
1341 var j = i;
1342 button.clicked.connect((source) =>
1344 debug("notebook page %i clicked", j);
1345 notebook.set_current_page(j);
1346 similar_artist.first_show();
1348 similar_artist.show();
1349 i++;
1351 /* Track changed pages */
1352 notebook.notify["page"].connect((source,spec) =>
1354 var page = notebook.get_current_page();
1355 config.set_int("MetaData", "song-last-page", (int)page);
1358 /* Restore right page */
1359 if(i > 0)
1361 var page = config.get_int_with_default("MetaData", "song-last-page", 0);
1362 if(page > i)
1364 notebook.set_current_page(0);
1366 else
1368 /* The list is in reversed order, compensate for that. */
1369 var w = group.nth_data(i-page-1);
1370 w.set_active(true);
1371 notebook.set_current_page(page);
1375 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1376 ali.add(hboxje);
1378 /* Create pane in 2. */
1379 var bottom_hbox = new Gtk.HBox(false, 6);
1380 /* left pane */
1382 var metadata_vbox = new Gtk.VBox(false, 6);
1384 var sep = new Gtk.HSeparator();
1385 sep.set_size_request(-1, 1);
1386 metadata_vbox.pack_start(sep, false, false, 0);
1388 metadata_vbox.pack_start(ali, false, false, 0);
1389 sep = new Gtk.HSeparator();
1390 sep.set_size_request(-1, 1);
1391 metadata_vbox.pack_start(sep, false, false, 0);
1392 metadata_vbox.pack_start(notebook, false, false, 0);
1394 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1396 vbox.pack_start(bottom_hbox, true, true, 0);
1398 /* show it */
1399 master_box.pack_start(vbox, false, false, 0);
1400 return master_box;
1403 private void metadata_box_show_base()
1405 Gtk.Entry MetadataBoxShowBaseEntry = null;
1406 var master_box = new Gtk.VBox (false, 6);
1407 var vbox = new Gtk.VBox (false,6);
1408 vbox.border_width = 8;
1411 history_bc_header(HitemType.BASE, null, null, null);
1413 var hbox = new Gtk.HBox(false, 6);
1414 var label = new Gtk.Label("");
1415 label.set_markup(_("<b>Search:</b>"));
1416 hbox.pack_start(label, false, false, 0);
1417 MetadataBoxShowBaseEntry = new Gtk.Entry();
1419 MetadataBoxShowBaseEntry.add_accelerator("grab-focus",
1420 Gmpc.Playlist.get_accel_group(),
1421 0x046,
1422 Gdk.ModifierType.CONTROL_MASK,
1425 /* Add clear icon */
1426 MetadataBoxShowBaseEntry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, "gtk-clear");
1427 MetadataBoxShowBaseEntry.icon_press.connect((source, pos, event) =>
1429 source.set_text("");
1433 hbox.pack_start(MetadataBoxShowBaseEntry, true, true, 0);
1435 vbox.pack_start(hbox, false, false, 0);
1438 var result_hbox = new Gmpc.Widgets.Songlist();
1439 result_hbox.artist_song_clicked.connect((source, song) =>
1441 if(song.artist != null)
1443 this.set_artist(song.artist);
1446 result_hbox.album_song_clicked.connect((source, song) =>
1448 if(song.artist != null && song.album != null)
1450 this.set_album(song.artist, song.album);
1453 result_hbox.song_clicked.connect((source, song) =>
1455 this.set_song(song);
1458 result_hbox.play_song_clicked.connect((source, song) =>
1460 if(song.file != null)
1462 Gmpc.MpdInteraction.play_path(song.file);
1465 result_hbox.song_context_menu.connect((source, song) =>
1467 var menu = new Gtk.Menu();
1469 var item = new Gtk.ImageMenuItem.from_stock("gtk-open",null);
1470 MPD.Song song_pass = song.copy();
1471 item.activate.connect((source)=>{
1472 this.set_song(song_pass);
1474 menu.append(item);
1476 stdout.printf("song context menu show\n");
1477 menu.show_all();
1478 menu.popup(null, null, null, 3, Gtk.get_current_event_time());
1481 MetadataBoxShowBaseEntry.activate.connect((source) =>
1483 string value = source.get_text();
1484 current.data.search_string = value;
1485 MPD.Data.Item? list = Gmpc.Query.search(value, false);
1486 result_hbox.set_from_data((owned)list,true,true);
1487 result_hbox.show_all();
1489 result_hbox.show();
1490 vbox.pack_start(result_hbox, false, false);
1492 if(current != null)
1494 if(current.data.type == HitemType.BASE && current.data.search_string != null)
1496 MetadataBoxShowBaseEntry.set_text(current.data.search_string);
1497 MetadataBoxShowBaseEntry.activate();
1502 * Button that allows you to enable/disable the side bars
1504 var show_button = new Gtk.ToggleButton.with_label(_("Hide sidebar"));
1506 if(config.get_int_with_default("metadata browser", "show-browsers", 1) == 0)
1508 show_button.label = _("Show sidebar");
1509 show_button.set_active(true);
1511 show_button.toggled.connect((source) =>
1513 var state = show_button.active;
1514 if(state == true)
1516 this.browser_box.hide();
1517 show_button.label = _("Show sidebar");
1519 else {
1520 this.browser_box.show();
1521 show_button.label = _("Hide sidebar");
1523 config.set_int("metadata browser", "show-browsers", (int)!state);
1527 var ali = new Gtk.Alignment(0.0f, 0.5f, 0f,0f);
1528 ali.add(show_button);
1529 vbox.pack_start(ali, false, false);
1531 * Add it to the view
1533 master_box.pack_start(vbox, false, false, 0);
1534 this.metadata_box.add(master_box);
1535 this.metadata_sw.show_all();
1536 // MetadataBoxShowBaseEntry.grab_focus();
1541 private void metadata_box_show_album(string artist, string album)
1543 var master_box = new Gtk.VBox (false, 6);
1544 var vbox = new Gtk.VBox (false,6);
1545 vbox.border_width = 8;
1548 history_bc_header(HitemType.ALBUM, artist, album, null);
1550 /* Artist image */
1551 var hbox = new Gtk.HBox(false, 6);
1552 var ali = new Gtk.Alignment(0f,0f,0f,0f);
1554 int meta_size = (int)(this.metadata_box.get_allocated_width()*0.20);
1555 meta_size = int.min(meta_size, (int)(this.metadata_sw.get_allocated_height()*0.30));
1556 meta_size = int.min(int.max(100, meta_size), 250);
1557 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, meta_size);
1558 artist_image.set_squared(false);
1559 MPD.Song song = new MPD.Song();
1560 song.artist = artist;
1561 song.album = album;
1562 artist_image.update_from_song(song);
1563 ali.add(artist_image);
1564 hbox.pack_start(ali, false, false, 0);
1565 /* Artist information */
1566 var info_box = new Gtk.Grid();
1567 info_box.set_row_spacing(3);
1568 info_box.set_column_spacing(8);
1569 hbox.pack_start(info_box, true, true, 0);
1570 int i=0;
1573 var label = new Gtk.Label(artist != null?artist:_("Unknown"));
1574 label.set_alignment(0.0f, 0.5f);
1575 label.set_line_wrap(true);
1576 this.add_entry(info_box, _("Artist"), null, label, ref i, "media-artist");
1578 label = new Gtk.Label(album != null?album:_("Unknown"));
1579 label.set_alignment(0.0f, 0.5f);
1580 label.set_line_wrap(true);
1581 this.add_entry(info_box, _("Album"), null, label, ref i, "media-album");
1583 /* Genres of songs */
1584 var pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ALBUM_GENRES_SONGS, song);
1585 pt_label.set_selectable(true);
1586 pt_label.set_alignment(0.0f, 0.5f);
1587 pt_label.set_line_wrap(true);
1588 this.add_entry(info_box, _("Genres"), null, pt_label, ref i, "media-genre");
1590 /* Dates of songs */
1591 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ALBUM_DATES_SONGS, song);
1592 pt_label.set_selectable(true);
1593 pt_label.set_line_wrap(true);
1594 pt_label.set_alignment(0.0f, 0.5f);
1595 this.add_entry(info_box, _("Dates"), null, pt_label, ref i,"media-date");
1596 /* Total number of songs */
1597 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ALBUM_NUM_SONGS, song);
1598 pt_label.set_selectable(true);
1599 pt_label.set_line_wrap(true);
1600 pt_label.set_alignment(0.0f, 0.5f);
1601 this.add_entry(info_box, _("Songs"), null, pt_label, ref i, "media-num-tracks");
1602 /* Total playtime */
1603 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ALBUM_PLAYTIME_SONGS, song);
1604 pt_label.set_selectable(true);
1605 pt_label.set_line_wrap(true);
1606 pt_label.set_alignment(0.0f, 0.5f);
1607 this.add_entry(info_box, _("Playtime"), null, pt_label, ref i, "media-track-length");
1609 vbox.pack_start(hbox , false, false, 0);
1611 /* Player controls */
1612 var control_hbox = new Gtk.VBox (false, 6);
1614 var button = new Gtk.Button.from_stock("gtk-add");
1615 button.set_tooltip_text(_("Add the item to the play queue"));
1616 button.set_property("xalign", 0.0f);
1617 button.set_relief(Gtk.ReliefStyle.NONE);
1618 button.clicked.connect(add_selected_song);
1619 control_hbox.pack_start(button, false, false,0);
1621 button = new Gtk.Button.from_stock("gtk-media-play");
1622 button.set_tooltip_text(_("Replace the current play queue with this item and play"));
1623 button.set_property("xalign", 0.0f);
1624 button.set_relief(Gtk.ReliefStyle.NONE);
1625 button.clicked.connect(replace_selected_song);
1626 control_hbox.pack_start(button, false, false,0);
1628 hbox.pack_start(control_hbox, false, false, 0);
1630 /* Separator */
1631 var sep = new Gtk.HSeparator();
1632 sep.set_size_request(-1, 4);
1633 vbox.pack_start(sep, false, false, 0);
1635 var hboxje = new Gtk.HBox(false, 6);
1637 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1638 var notebook = new Gtk.Notebook();
1639 notebook.set_show_border(false);
1640 notebook.set_show_tabs(false);
1642 /* Lyrics */
1643 i = 0;
1644 unowned SList<unowned Gtk.RadioButton> group = null;
1645 /* Album information */
1646 if(config.get_int_with_default("MetaData", "show-album-information",1) == 1)
1648 var alib = new Gtk.Alignment(0f,0f,1f,0f);
1649 var text_view = new Gmpc.MetaData.TextView(Gmpc.MetaData.Type.ALBUM_TXT);
1650 text_view.set_left_margin(8);
1651 text_view.query_from_song(song);
1653 alib.add(text_view);
1654 notebook.append_page(alib, new Gtk.Label(_("Album information")));
1655 var rbutton = new Gtk.RadioButton.with_label(group,_("Album information"));
1656 group = rbutton.get_group();
1657 hboxje.pack_start(rbutton, false, false, 0);
1658 var j = i;
1659 rbutton.clicked.connect((source) =>
1661 debug("notebook page %i clicked", j);
1662 notebook.set_current_page(j);
1664 i++;
1666 alib.show();
1669 var slhbox = new Gtk.VBox(false, 6);
1671 var sl = new Gmpc.Widgets.Songlist();
1672 slhbox.pack_start(sl, false, false, 0);
1674 sl.album_song_clicked.connect((source, song) =>
1676 if(song.artist != null && song.album != null)
1678 this.set_album(song.artist, song.album);
1681 sl.song_clicked.connect((source, song) =>
1683 this.set_song(song);
1686 sl.play_song_clicked.connect((source, song) =>
1688 if(song.file != null)
1690 Gmpc.MpdInteraction.play_path(song.file);
1694 sl.song_context_menu.connect((source,song)=>
1696 var menu = new Gtk.Menu();
1698 var item = new Gtk.ImageMenuItem.from_stock("gtk-open",null);
1699 MPD.Song song_pass = song.copy();
1700 item.activate.connect((source)=>{
1701 this.set_song(song_pass);
1703 menu.append(item);
1705 stdout.printf("song context menu show\n");
1706 menu.show_all();
1707 menu.popup(null, null, null, 3, Gtk.get_current_event_time());
1710 notebook.append_page(slhbox, new Gtk.Label(_("Song list")));
1711 var rbutton = new Gtk.RadioButton.with_label(group,_("Song list"));
1712 group = rbutton.get_group();
1713 hboxje.pack_start(rbutton, false, false, 0);
1714 var j = i;
1715 bool seen = false;
1716 rbutton.clicked.connect((source) =>
1718 notebook.set_current_page(j);
1720 notebook.notify["page"].connect((source)=>
1722 if(notebook.page != j) return;
1723 debug("notebook page %i clicked", j);
1724 if(!seen)
1726 string albumartist = null;
1727 if(Gmpc.server.tag_supported(MPD.Tag.Type.ALBUM_ARTIST))
1729 MPD.Database.search_field_start(server, MPD.Tag.Type.ALBUM_ARTIST);
1730 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
1731 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
1732 var ydata = MPD.Database.search_commit(server);
1733 if(ydata != null)
1735 if(ydata.tag.length > 0)
1736 albumartist = ydata.tag;
1739 MPD.Database.search_start(server,true);
1740 if(albumartist != null&& albumartist.length > 0)
1741 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM_ARTIST, albumartist);
1742 else
1743 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
1745 if(album != null)
1746 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ALBUM, album);
1747 var data = MPD.Database.search_commit(server);
1748 data.sort_album_disc_track();
1750 sl.set_from_data((owned)data,false);
1752 seen = true;
1755 slhbox.show();
1756 i++;
1758 /* Track changed pages */
1759 notebook.notify["page"].connect((source,spec) =>
1761 var page = notebook.get_current_page();
1762 config.set_int("MetaData", "album-last-page", (int)page);
1765 /* Restore right page */
1766 if(i > 0)
1768 var page = config.get_int_with_default("MetaData", "album-last-page", 0);
1769 if(page > i)
1771 notebook.set_current_page(0);
1773 else
1775 /* The list is in reversed order, compensate for that. */
1776 var w = group.nth_data(i-page-1);
1777 w.set_active(true);
1778 notebook.set_current_page(page);
1782 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
1783 ali.add(hboxje);
1785 /* Create pane in 2. */
1786 var bottom_hbox = new Gtk.HBox(false, 6);
1787 /* left pane */
1788 var metadata_vbox = new Gtk.VBox(false, 6);
1789 metadata_vbox.pack_start(ali, false, false, 0);
1790 sep = new Gtk.HSeparator();
1791 sep.set_size_request(-1, 1);
1792 metadata_vbox.pack_start(sep, false, false, 0);
1793 metadata_vbox.pack_start(notebook, false, false, 0);
1794 bottom_hbox.pack_start(metadata_vbox, true, true, 0);
1797 vbox.pack_start(bottom_hbox, true, true, 0);
1799 * Add it to the view
1801 master_box.pack_start(vbox, false, false, 0);
1802 this.metadata_box.add(master_box);
1803 this.metadata_sw.show_all();
1806 * This fills the view for artist
1807 * <artist name>
1808 * <image> | <array with info>
1809 * < buttonss>
1811 * <artist info text>
1813 * <similar artists>
1814 * <links>
1816 private void metadata_box_show_artist(string artist)
1818 var master_box = new Gtk.VBox (false, 6);
1819 var vbox = new Gtk.VBox (false,6);
1820 var i = 0;
1821 vbox.border_width = 8;
1823 /* Set up header */
1824 history_bc_header(HitemType.ARTIST, artist, null, null);
1826 /* Create an MPD.Song with the info for this type set */
1827 MPD.Song song = new MPD.Song();
1828 song.artist = artist;
1830 /* Artist image */
1831 var hbox = new Gtk.HBox(false, 6);
1832 var ali = new Gtk.Alignment(0f,0f,0f,0f);
1833 int meta_size = (int)(this.metadata_box.get_allocated_width()*0.20);
1834 meta_size = int.min(meta_size, (int)(this.metadata_sw.get_allocated_height()*0.30));
1835 meta_size = int.min(int.max(100, meta_size), 250);
1836 var artist_image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ARTIST_ART, meta_size);
1838 artist_image.set_no_cover_icon("no-artist");
1839 artist_image.set_loading_cover_icon("fetching-artist");
1840 artist_image.set_squared(false);
1841 artist_image.update_from_song(song);
1842 ali.add(artist_image);
1843 hbox.pack_start(ali, false, false, 0);
1844 /* Artist information */
1845 var info_box = new Gtk.Grid();
1846 info_box.set_row_spacing(3);
1847 info_box.set_column_spacing(8);
1848 hbox.pack_start(info_box, true, true, 0);
1850 /* Artist */
1851 var label = new Gtk.Label((artist != null)?artist:_("Unknown"));
1852 label.set_selectable(true);
1853 label.set_alignment(0.0f, 0.5f);
1854 this.add_entry(info_box, _("Artist"), null, label, ref i, "media-artist");
1856 /* Genres of songs */
1857 var pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ARTIST_GENRES_SONGS, song);
1858 pt_label.set_selectable(true);
1859 pt_label.set_alignment(0.0f, 0.5f);
1860 pt_label.set_line_wrap(true);
1861 this.add_entry(info_box, _("Genres"), null, pt_label, ref i, "media-genre");
1862 /* Dates of songs */
1863 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ARTIST_DATES_SONGS, song);
1864 pt_label.set_selectable(true);
1865 pt_label.set_line_wrap(true);
1866 pt_label.set_alignment(0.0f, 0.5f);
1867 this.add_entry(info_box, _("Dates"), null, pt_label, ref i,"media-date");
1868 /* Total number of songs */
1869 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ARTIST_NUM_SONGS, song);
1870 pt_label.set_selectable(true);
1871 pt_label.set_line_wrap(true);
1872 pt_label.set_alignment(0.0f, 0.5f);
1873 this.add_entry(info_box, _("Songs"), null, pt_label, ref i, "media-num-tracks");
1874 /* Total playtime */
1875 pt_label = new Gmpc.MetaData.StatsLabel(Gmpc.MetaData.StatsLabel.Type.ARTIST_PLAYTIME_SONGS, song);
1876 pt_label.set_selectable(true);
1877 pt_label.set_line_wrap(true);
1878 pt_label.set_alignment(0.0f, 0.5f);
1879 this.add_entry(info_box, _("Playtime"), null, pt_label, ref i, "media-track-length");
1881 vbox.pack_start(hbox , true, true, 0);
1883 /* Player controls */
1884 var hbox_2 = new Gtk.VBox (false, 6);
1886 var button = new Gtk.Button.from_stock("gtk-add");
1887 button.set_tooltip_text(_("Add the item to the play queue"));
1888 button.set_property("xalign", 0.0f);
1889 button.set_relief(Gtk.ReliefStyle.NONE);
1890 button.clicked.connect(add_selected_song);
1891 hbox_2.pack_start(button, false, false,0);
1893 button = new Gtk.Button.from_stock("gtk-media-play");
1894 button.set_tooltip_text(_("Replace the current play queue with this item and play"));
1895 button.set_property("xalign", 0.0f);
1896 button.set_relief(Gtk.ReliefStyle.NONE);
1897 button.clicked.connect(replace_selected_song);
1898 hbox_2.pack_start(button, false, false,0);
1900 hbox.pack_start(hbox_2, false, false, 0);
1903 var hboxje = new Gtk.HBox(false, 6);
1904 /* Separator */
1905 var sep = new Gtk.HSeparator();
1906 sep.set_size_request(-1, 4);
1907 vbox.pack_start(sep, false, false, 0);
1910 /* Notebook where all the metadata items are kept, Override the tabs by a radiobutton list. */
1911 var notebook = new Gtk.Notebook();
1912 notebook.set_show_border(false);
1913 notebook.set_show_tabs(false);
1915 i = 0;
1916 unowned SList<unowned Gtk.RadioButton> group = null;
1917 /* Artist information */
1918 if(config.get_int_with_default("MetaData", "show-artist-information",1) == 1)
1920 var alib = new Gtk.Alignment(0f,0f,1f,0f);
1921 var text_view = new Gmpc.MetaData.TextView(Gmpc.MetaData.Type.ARTIST_TXT);
1922 text_view.set_left_margin(8);
1923 text_view.query_from_song(song);
1925 alib.add(text_view);
1926 notebook.append_page(alib, new Gtk.Label(_("Artist information")));
1927 var button_sai = new Gtk.RadioButton.with_label(group,_("Artist information"));
1928 group = button_sai.get_group();
1929 hboxje.pack_start(button_sai, false, false, 0);
1931 var j = i;
1932 button_sai.clicked.connect((source) =>
1934 if((source as Gtk.CheckButton).get_active())
1936 debug("notebook page %i clicked", j);
1937 notebook.set_current_page(j);
1940 i++;
1942 alib.show();
1945 /* Show similar artist */
1946 if(config.get_int_with_default("MetaData", "show-similar-artist",1) == 1)
1948 var similar_artist = new Gmpc.MetaData.Widgets.SimilarArtists(Gmpc.server,song);
1950 notebook.append_page(similar_artist, new Gtk.Label(_("Similar Artists")));
1952 var button_sa = new Gtk.RadioButton.with_label(group,_("Similar Artists"));
1953 group = button_sa.get_group();
1954 hboxje.pack_start(button_sa, false, false, 0);
1956 var j = i;
1957 button_sa.clicked.connect((source) =>
1959 if((source as Gtk.CheckButton).get_active())
1961 debug("notebook page %i clicked", j);
1962 similar_artist.first_show();
1963 notebook.set_current_page(j);
1966 similar_artist.show();
1967 i++;
1971 var slhbox = new Gtk.VBox(false, 6);
1973 var sl = new Gmpc.Widgets.Songlist();
1974 slhbox.pack_start(sl, false, false, 0);
1976 sl.album_song_clicked.connect((source, song) =>
1978 if(song.artist != null && song.album != null)
1980 this.set_album(song.artist, song.album);
1983 sl.song_clicked.connect((source, song) =>
1985 this.set_song(song);
1988 sl.play_song_clicked.connect((source, song) =>
1990 if(song.file != null)
1992 Gmpc.MpdInteraction.play_path(song.file);
1995 sl.song_context_menu.connect((source,song)=>
1997 var menu = new Gtk.Menu();
1999 var item = new Gtk.ImageMenuItem.from_stock("gtk-open",null);
2000 MPD.Song song_pass = song.copy();
2001 item.activate.connect((source)=>{
2002 this.set_song(song_pass);
2004 menu.append(item);
2006 stdout.printf("song context menu show\n");
2007 menu.show_all();
2008 menu.popup(null, null, null, 3, Gtk.get_current_event_time());
2012 notebook.append_page(slhbox, new Gtk.Label(_("Song list")));
2013 var rbutton = new Gtk.RadioButton.with_label(group,_("Song list"));
2014 group = rbutton.get_group();
2015 hboxje.pack_start(rbutton, false, false, 0);
2016 var j = i;
2017 bool seen = false;
2018 rbutton.clicked.connect((source) =>
2020 notebook.set_current_page(j);
2022 notebook.notify["page"].connect((source)=>
2024 if(notebook.page != j) return;
2025 debug("notebook page %i clicked", j);
2026 if(!seen)
2028 MPD.Database.search_start(server,true);
2029 MPD.Database.search_add_constraint(server, MPD.Tag.Type.ARTIST, artist);
2030 var data = MPD.Database.search_commit(server);
2031 data.sort_album_disc_track();
2033 sl.set_from_data((owned)data, true);
2035 seen = true;
2038 slhbox.show();
2039 i++;
2042 if( song.artist != null)
2044 int albums =0;
2045 /* Create album list */
2046 var album_hbox = new Gtk.VBox(false, 6);
2048 var album_view = new Gmpc.Widgets.Qtable();
2049 album_hbox.pack_start(album_view, false, true, 0);
2051 * Reuse the album browser view.
2053 Gtk.TreeIter titer;
2054 if(this.model_albums.get_iter_first(out titer))
2058 unowned MPD.Song? asong = null;
2059 this.model_albums.get(titer,0, &asong);
2060 if(asong != null)
2062 /* Make a copy of the song. Otherwise only a reference is added to the
2063 * button clicked handler.
2064 * This reference can be invalid before click completed.
2066 MPD.Song but_song = asong.copy();
2068 /* Create button */
2069 var but_hbox = new Gtk.VBox(false, 6);
2070 var image = new Gmpc.MetaData.Image(Gmpc.MetaData.Type.ALBUM_ART, 175);
2071 image.set_squared(true);
2072 image.set_scale_up(true);
2073 image.set_has_tooltip(false);
2074 image.update_from_song_delayed(but_song);
2076 but_hbox.pack_start(image, false, false, 0);
2078 var but_label = new Gtk.Label(but_song.album);
2079 but_label.selectable = true;
2080 but_label.set_alignment(0.5f, 0.0f);
2081 /* Create label */
2082 var strlabel = "<b>";
2083 if(but_song.date != null && but_song.date.length > 0) strlabel += GLib.Markup.printf_escaped("%s - ",but_song.date);
2084 if(but_song.album != null) strlabel+=GLib.Markup.escape_text(but_song.album);
2085 else strlabel += _("No Album");
2086 strlabel += "</b>";
2087 if(but_song.artist != null) strlabel += GLib.Markup.printf_escaped("\n%s",but_song.artist);
2088 but_label.set_markup(strlabel);
2089 (but_label as Gtk.Misc).set_alignment(0.0f, 0.0f);
2090 but_label.set_ellipsize(Pango.EllipsizeMode.END);
2091 /* add label */
2092 but_hbox.pack_start(but_label, true, true, 0);
2094 /* If clicked switch to browser */
2095 image.button_release_event.connect((source, event) =>
2097 if(event.button == 2)
2099 set_album(but_song.artist, but_song.album);
2100 return true;
2102 else if (event.button == 1)
2104 var p = new PopupMenu();
2106 hbox = new Gtk.HBox(false, 0);
2107 var open = new Gtk.Button();
2108 open.set_tooltip_text(_("Open"));
2109 open.add(new Image.from_stock("gtk-open", Gtk.IconSize.DND));
2110 hbox.pack_start(open, false, false, 0);
2111 open.clicked.connect( (source) =>
2113 set_album(but_song.artist, but_song.album);
2114 p.destroy();
2118 * Play machine
2120 var play = new Button();
2121 play.add(new Image.from_stock("gtk-media-play", Gtk.IconSize.DND));
2122 play.set_tooltip_text(_("Play album"));
2123 hbox.pack_start(play, false, false, 0);
2124 play.clicked.connect( (source) =>
2126 MPD.PlayQueue.clear(server);
2127 MPD.PlayQueue.add_album(server,
2128 but_song.artist,
2129 but_song.album);
2130 MPD.Player.play(server);
2131 p.destroy();
2135 * Add to play queue
2137 var add = new Button();
2138 add.add(new Image.from_stock("gtk-add", Gtk.IconSize.DND));
2139 add.set_tooltip_text(_("Add album to play-queue"));
2140 hbox.pack_start(add, false, false, 0);
2141 add.clicked.connect( (source) =>
2143 MPD.PlayQueue.add_album(server,
2144 but_song.artist,
2145 but_song.album);
2146 p.destroy();
2149 p.add(hbox);
2150 hbox.show_all();
2151 p.popup(event);
2152 return true;
2154 return false;
2156 albums++;
2159 album_view.add(but_hbox);
2162 while(this.model_albums.iter_next(ref titer));
2165 notebook.append_page(album_hbox, new Gtk.Label(_("Albums")));
2166 var button_sl = new Gtk.RadioButton.with_label(group,_("Albums"));
2167 group = button_sl.get_group();
2168 hboxje.pack_start(button_sl, false, false, 0);
2169 var j = i;
2170 button_sl.clicked.connect((source) =>
2172 if((source as Gtk.CheckButton).get_active())
2174 debug("notebook page %i clicked", j);
2175 notebook.set_current_page(j);
2178 album_hbox.show();
2179 i++;
2182 /* Track changed pages */
2183 notebook.notify["page"].connect((source,spec) =>
2185 var page = notebook.get_current_page();
2186 config.set_int("MetaData", "artist-last-page", (int)page);
2189 /* Restore right page */
2190 if(i > 0)
2192 var page = config.get_int_with_default("MetaData", "artist-last-page", 0);
2193 if(page > i)
2195 notebook.set_current_page(0);
2197 else
2199 /* The list is in reversed order, compensate for that. */
2200 var w = group.nth_data(i-page-1);
2201 w.set_active(true);
2202 notebook.set_current_page(page);
2207 ali = new Gtk.Alignment(0.0f, 0.5f,0f,0f);
2208 ali.add(hboxje);
2210 /* left pane */
2211 var metadata_vbox = new Gtk.VBox(false, 6);
2212 metadata_vbox.pack_start(ali, false, false, 0);
2213 sep = new Gtk.HSeparator();
2214 sep.set_size_request(-1, 1);
2215 metadata_vbox.pack_start(sep, false, false, 0);
2216 metadata_vbox.pack_start(notebook, false, false, 0);
2219 vbox.pack_start(metadata_vbox, true, true, 0);
2223 * Add it to the view
2226 master_box.pack_start(vbox, false, false, 0);
2227 this.metadata_box.add(master_box);
2228 this.metadata_box.show_all();
2232 private uint update_timeout = 0;
2233 /* If we get an update, wait for idle time, then do it.*/
2234 private void metadata_box_update()
2236 if(this.update_timeout > 0)
2238 GLib.Source.remove(this.update_timeout);
2240 update_timeout = GLib.Idle.add(this.metadata_box_update_real);
2242 private bool metadata_box_update_real()
2244 if(this.block_update > 0)
2246 this.update_timeout = 0;
2247 return false;
2249 string artist = browser_get_selected_artist();
2250 string album = browser_get_selected_album();
2251 unowned MPD.Song? song = browser_get_selected_song();
2253 if(song != null)
2255 /** Add item to history */
2256 var item = new Hitem();
2257 item.song = song.copy();
2258 item.type = HitemType.SONG;
2259 history_add(item);
2261 var view = metadata_box_show_song(song,true);
2262 this.metadata_box.add(view);
2263 this.metadata_box.show_all();
2265 else if(album != null && artist != null)
2267 /** Add item to history */
2268 var item = new Hitem();
2269 item.song = new MPD.Song();
2270 item.song.artist =artist;
2271 item.song.album = album;
2272 item.type = HitemType.ALBUM;
2273 history_add(item);
2275 metadata_box_show_album(artist,album);
2277 else if (artist != null)
2279 /** Add item to history */
2280 var item = new Hitem();
2281 item.song = new MPD.Song();
2282 item.song.artist =artist;
2283 item.type = HitemType.ARTIST;
2284 history_add(item);
2286 metadata_box_show_artist(artist);
2288 else
2290 var item = new Hitem();
2291 item.search_string = null;
2292 item.type = HitemType.BASE;
2293 history_add(item);
2294 metadata_box_show_base();
2297 this.update_timeout = 0;
2298 return false;
2301 * Browser Interface bindings
2303 public void browser_add (Gtk.Widget category_tree)
2305 Gtk.TreeView tree = (Gtk.TreeView)category_tree;
2306 Gtk.ListStore store = (Gtk.ListStore)tree.get_model();
2307 Gtk.TreeModel model = tree.get_model();
2308 Gtk.TreeIter iter;
2309 Gmpc.Browser.insert(out iter,
2310 Playlist.BrowserType.LIBRARY+config.get_int_with_default(this.get_name(), "position", 100)%Playlist.BrowserType.LIBRARY);
2311 store.set(iter, 0, this.id, 1, _(this.get_name()), 3, "gmpc-metabrowser");
2312 /* Create a row reference */
2313 this.rref = new Gtk.TreeRowReference(model, model.get_path(iter));
2315 public void browser_selected (Gtk.Container container)
2317 string artist;
2318 this.selected = true;
2319 this.browser_init();
2320 container.add(this.paned);
2322 /* update if non selected */
2323 artist = browser_get_selected_artist();
2324 if(artist == null)
2326 metadata_box_clear();
2327 metadata_box_update();
2331 private bool selected = false;
2332 public void browser_unselected(Gtk.Container container)
2334 this.selected = false;
2335 container.remove(this.paned);
2337 private
2338 void
2339 con_changed(Gmpc.Connection conn, MPD.Server server, int connect)
2341 if(this.paned == null) return;
2342 this.history_clear();
2344 this.reload_browsers();
2345 metadata_box_clear();
2346 metadata_box_update();
2348 private
2349 void
2350 status_changed(Gmpc.Connection conn, MPD.Server server, MPD.Status.Changed what)
2352 if(this.paned == null) return;
2353 if((what&MPD.Status.Changed.DATABASE) != 0)
2355 this.reload_browsers();
2356 /* Restore old selection */
2357 if(this.current != null)
2359 this.show_hitem(this.current.data);
2365 * History
2367 private enum HitemType
2369 BASE,
2370 ARTIST,
2371 ALBUM,
2372 SONG
2374 private class Hitem
2376 public HitemType type;
2377 public MPD.Song? song;
2378 public string search_string ;
2380 private List<Hitem?> history = null;
2381 private unowned List<Hitem?> current = null;
2382 private void show_hitem(Hitem hi)
2384 switch(hi.type)
2386 case HitemType.BASE:
2387 this.set_base();
2388 break;
2389 case HitemType.ARTIST:
2390 this.set_artist(hi.song.artist);
2391 break;
2392 case HitemType.ALBUM:
2393 this.set_album(hi.song.artist, hi.song.album);
2394 break;
2395 case HitemType.SONG:
2396 this.set_song(hi.song);
2397 break;
2398 default:
2399 metadata_box_clear();
2400 break;
2403 private void history_previous()
2405 if(history == null || current == null)
2407 return;
2409 if(current.next == null)
2411 return;
2413 current = current.next;
2414 if(current != null) show_hitem(current.data);
2415 else metadata_box_clear();
2418 private void history_next()
2420 if(history == null || current == null)
2422 return;
2424 if(current.prev == null)
2426 return;
2428 current = current.prev;
2429 if(current != null) show_hitem(current.data);
2430 else metadata_box_clear();
2433 private void history_show_list_clicked(Gtk.MenuItem item)
2435 unowned List<Hitem?> a = (List<Hitem?>) item.get_data<List<Hitem?>>("current");
2436 if(a != null)
2438 current = a;
2439 show_hitem(current.data);
2443 // Keep the 'menu' around so the pop-up still works.
2444 private Gtk.Menu menu = null;
2447 private void history_show_list()
2449 menu = new Gtk.Menu();
2450 unowned List<Hitem?> iter = history.last();
2451 while(iter!= null)
2453 unowned Hitem i = iter.data;
2454 string label = "";
2455 if(i.type == HitemType.ARTIST)
2456 label = i.song.artist;
2457 else if (i.type == HitemType.ALBUM)
2458 label = "%s - %s".printf(i.song.artist, i.song.album);
2459 else if (i.type == HitemType.SONG)
2461 if(i.song.title != null)
2462 label = i.song.title;
2463 else
2464 label = _("Unknown");
2466 else if (i.type == HitemType.BASE)
2468 label = _("Metadata Browser");
2469 if(i.search_string != null)
2471 label += " ("+i.search_string+")";
2475 var item = new Gtk.CheckMenuItem.with_label(label);
2476 item.draw_as_radio = true;
2477 if(current != null && current == iter)
2479 item.set_active(true);
2481 item.activate.connect(history_show_list_clicked);
2482 item.set_data("current", (void*)iter);
2483 menu.append(item);
2484 iter = iter.prev;
2486 menu.show_all();
2487 menu.popup(null, null, null, 0, Gtk.get_current_event_time());
2490 private void history_bc_header(HitemType type, string? artist, string? album, string? title)
2492 foreach(var child in this.header.get_children())
2494 child.destroy();
2496 /* Add the history buttons.
2497 * we use the history buttons hbox for adding our buttons */
2498 var hist_box = history_buttons();
2499 this.header.add(hist_box);
2501 /* The 'BASE' button */
2502 if(artist == null && album == null && title==null)
2504 var image = new Gtk.Image.from_icon_name("gmpc-metabrowser", Gtk.IconSize.MENU);
2505 var ali = new Gtk.Alignment(0.5f,0.5f, 0f, 0f);
2506 ali.set_padding(6,6,6,6);
2507 ali.add(image);
2508 hist_box.attach(ali, 0, 0, 1, 1);//pack_start(ali, true, true, 0);
2509 //hist_box.attach(ali, 1, 0, 1,1);
2511 else
2513 var image = new Gtk.Image.from_icon_name("gmpc-metabrowser", Gtk.IconSize.MENU);
2514 var button = new Gtk.Button();
2515 button.set_relief(Gtk.ReliefStyle.NONE);
2516 button.set_image(image);
2517 button.clicked.connect((source)=> { set_base();});
2518 hist_box.attach(button, 0, 0, 1, 1);//pack_start(button, true, true, 0);
2520 /* If there is an artist, we can show more */
2521 if(artist != null)
2523 if(type != HitemType.ARTIST)
2525 var button = new Gtk.Button.with_label(artist);
2526 button.set_relief(Gtk.ReliefStyle.NONE);
2527 button.set_image(new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU));
2528 button.clicked.connect((source)=>
2530 set_artist(artist);
2532 hist_box.attach(button, 1, 0, 1,1);//pack_start(button, true, true, 0);
2535 else
2537 var label = new Gtk.Label(artist);
2538 label.set_ellipsize(Pango.EllipsizeMode.END);
2539 var image = new Gtk.Image.from_icon_name("media-artist", Gtk.IconSize.MENU);
2540 label.set_alignment(0.0f, 0.5f);
2541 hist_box.attach(image, 2, 0, 1,1);
2542 hist_box.attach(label, 3, 0, 1,1);
2544 /* Album */
2545 if(album != null)
2547 if(type == HitemType.ALBUM)
2549 var label = new Gtk.Label(album);
2550 label.set_ellipsize(Pango.EllipsizeMode.END);
2551 var image = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
2552 label.set_alignment(0.0f, 0.5f);
2553 hist_box.attach(image, 4, 0, 1,1);
2554 hist_box.attach(label, 5, 0, 1,1);
2556 else
2558 var button = new Gtk.Button();//.with_label(album);
2560 var ali = new Gtk.Alignment(0.0f, 0.5f, 0.0f, 0.0f);
2561 button.add(ali);
2563 var gr = new Gtk.Grid();
2564 gr.set_column_spacing(6);
2565 ali.add(gr);
2567 var im = new Gtk.Image.from_icon_name("media-album", Gtk.IconSize.MENU);
2568 // button.set_image(im);
2569 gr.attach(im,0,0,1,1);
2570 var label = new Gtk.Label(album);
2571 label.set_ellipsize(Pango.EllipsizeMode.END);
2572 gr.attach(label, 1,0,1,1);
2574 button.set_relief(Gtk.ReliefStyle.NONE);
2575 button.clicked.connect((source)=>
2577 set_album(artist, album);
2579 button.show_all();
2580 hist_box.attach(button, 4,0,1,1);//pack_start(button, true, true, 0);
2584 if(title != null)
2586 var image = new Gtk.Image.from_icon_name("media-audiofile", Gtk.IconSize.MENU);
2587 hist_box.attach(image, 6, 0, 1,1);
2589 var label = new Gtk.Label(title);
2590 label.set_alignment(0.0f, 0.5f);
2591 label.set_ellipsize(Pango.EllipsizeMode.END);
2592 label.set_line_wrap(false);
2594 hist_box.attach(label, 7, 0, 1,1);
2596 this.header.show_all();
2599 private Gtk.Grid history_buttons()
2601 var box = new Gtk.Grid();
2602 box.set_column_spacing(6);
2603 if(history == null && current == null) return box;
2605 var back_but = new Gtk.Button.from_stock("gtk-go-back");
2606 back_but.set_relief(Gtk.ReliefStyle.NONE);
2607 if(current == null || current.next == null) back_but.sensitive = false;
2608 back_but.clicked.connect(history_previous);
2611 back_but.set_hexpand(true);
2612 back_but.set_halign(Gtk.Align.END);
2613 box.attach(back_but, 10, 0, 1, 1);
2616 if(current != null && (current.next != null || current.prev != null))
2618 var dd_but = new Gtk.Button();
2619 var arrow = new Gtk.Arrow(Gtk.ArrowType.DOWN, Gtk.ShadowType.ETCHED_IN);
2620 dd_but.add(arrow);
2621 dd_but.set_relief(Gtk.ReliefStyle.NONE);
2622 dd_but.clicked.connect(history_show_list);
2624 box.attach(dd_but, 11, 0, 1, 1);
2626 var next_but = new Gtk.Button.from_stock("gtk-go-forward");
2627 next_but.set_relief(Gtk.ReliefStyle.NONE);
2628 if(current == null || current.prev == null) next_but.sensitive = false;
2629 next_but.clicked.connect(history_next);
2631 box.attach(next_but, 12, 0, 1, 1);
2633 return box;
2635 private void history_add(Hitem hi)
2637 if(history != null)
2639 unowned Hitem a = current.data;
2640 if(a.type == hi.type)
2642 if(Gmpc.Misc.song_checksum(a.song) == Gmpc.Misc.song_checksum(hi.song))
2644 return;
2648 /* clean items in the future */
2649 if(history != null)
2651 unowned List<Hitem?>? iter = current.prev;
2652 while(iter != null && iter != current)
2654 history.remove(iter.data);
2655 iter = history.first();
2659 history.prepend(hi);
2660 if(history.length() > 25)
2662 unowned List<Hitem?> a = history.last();
2663 history.remove(a.data);
2665 current = history;
2667 private void history_clear()
2669 this.current = null;
2670 this.history = null;
2675 * Public api
2677 public
2678 void
2679 set_base()
2682 this.tree_artist.get_selection().unselect_all();
2683 this.artist_filter_entry.set_text("");
2685 this.metadata_box_clear();
2686 this.metadata_box_update();
2688 public
2689 void
2690 set_artist(string artist)
2692 if(!this.get_enabled()) return;
2693 this.block_update++;
2696 this.tree_artist.get_selection().unselect_all();
2697 this.tree_album.get_selection().unselect_all();
2698 /* clear */
2699 this.artist_filter_entry.set_text("");
2700 Gtk.TreeIter iter;
2701 if(this.model_filter_artist.get_iter_first(out iter))
2705 string lartist= null;
2706 this.model_filter_artist.get(iter, 7, out lartist, -1);
2707 if( lartist != null && lartist.collate(artist) == 0)
2709 this.tree_artist.get_selection().select_iter(iter);
2710 this.tree_artist.scroll_to_cell(this.model_filter_artist.get_path(iter), null, true, 0.5f,0f);
2711 this.block_update--;
2713 this.metadata_box_clear();
2714 this.metadata_box_update();
2715 return;
2718 while((this.model_filter_artist).iter_next(ref iter));
2720 this.block_update--;
2723 this.metadata_box_clear();
2724 this.metadata_box_update();
2727 public
2728 void
2729 set_album(string artist, string album)
2731 if(!this.get_enabled()) return;
2732 this.block_update++;
2733 this.set_artist(artist);
2734 /* clear */
2735 this.album_filter_entry.set_text("");
2736 Gtk.TreeIter iter;
2737 if(this.model_filter_album.get_iter_first(out iter))
2741 string lalbum= null;
2742 this.model_filter_album.get(iter, 6, out lalbum, -1);
2743 if( lalbum != null && lalbum.collate(album) == 0)
2745 this.tree_album.get_selection().select_iter(iter);
2746 this.tree_album.scroll_to_cell(this.model_filter_album.get_path(iter), null, true, 0.5f,0f);
2747 this.tree_songs.get_selection().unselect_all();
2748 this.block_update--;
2749 this.metadata_box_update();
2750 return;
2753 while((this.model_filter_album).iter_next(ref iter));
2756 this.tree_songs.get_selection().unselect_all();
2758 this.block_update--;
2760 this.metadata_box_clear();
2761 this.metadata_box_update();
2764 public
2765 void
2766 set_song(MPD.Song song)
2768 if(!this.get_enabled()) return;
2769 this.block_update++;
2770 if(song.artist != null)
2772 this.set_artist(song.artist);
2773 if(song.album != null)
2775 this.set_album(song.artist,song.album);
2779 Gtk.TreeIter iter;
2780 if(this.model_songs.get_iter_first(out iter))
2784 string ltitle = null;
2785 this.model_songs.get(iter, 7, out ltitle, -1);
2786 if( ltitle != null && ltitle.collate(song.title) == 0)
2788 this.tree_songs.get_selection().select_iter(iter);
2789 this.tree_songs.scroll_to_cell(this.model_songs.get_path(iter), null, true, 0.5f,0f);
2790 this.block_update--;
2791 this.metadata_box_update();
2792 return;
2795 while((this.model_songs).iter_next(ref iter));
2799 this.block_update--;
2800 this.metadata_box_clear();
2801 if(this.update_timeout > 0)
2803 GLib.Source.remove(this.update_timeout);
2804 this.update_timeout = 0;
2807 /** Add item to history */
2808 var item = new Hitem();
2809 item.song = song.copy();
2810 item.type = HitemType.SONG;
2811 history_add(item);
2813 var view = metadata_box_show_song(song,true);
2814 this.metadata_box.add(view);
2815 this.metadata_box.show_all();
2817 public
2818 void
2819 select_browser(Gtk.TreeView? tree)
2821 if(rref != null)
2823 unowned Gtk.TreeView category_tree = Gmpc.Playlist3.get_category_tree_view();
2824 var sel = category_tree.get_selection();
2825 var path = rref.get_path();
2826 if(path != null)
2828 sel.select_path(path);
2833 private string get_extension(string path)
2835 long length = path.length;
2836 long i=length;
2837 string retv = null;
2838 for(; i>0 && (length-i) <8; i--)
2840 if(path[i] == '.')
2842 retv = path.substring(i+1);
2843 return retv;
2846 return retv;
2849 public override void set_enabled(bool state)
2851 if(state)
2853 if(rref == null)
2855 browser_add( Gmpc.Playlist3.get_category_tree_view());
2856 browser_init();
2859 else
2861 if(this.rref != null)
2863 var path = rref.get_path();
2864 if(path != null)
2866 unowned int[] indices = path.get_indices();
2867 config.set_int(this.get_name(), "position", indices[0]);
2868 Gtk.ListStore model = (Gtk.ListStore)rref.get_model();
2869 Gtk.TreeIter iter;
2870 if(model.get_iter(out iter, path))
2872 model.remove(iter);
2875 rref = null;
2879 if(this.get_name() != null)
2880 Gmpc.config.set_int(this.get_name(), "enabled", (int)state);