1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 * This plugin consists of 3 parts
22 * Metadata2 plugin: Implements metadata 2 browser.
23 * Now Playing plugin: Reusing the metadata 2 browser it implements a now playing browser.
24 * Custom widget, there are some custom widgets used by the metadata 2 browser
27 * * More. (expands, collapses a sub widget
34 private const bool use_transition_mdb
= Gmpc
.use_transition
;
35 private const string some_unique_name_mdb
= Config
.VERSION
;
37 public class Gmpc
.Browsers
.Metadata
: Gmpc
.Plugin
.Base
, Gmpc
.Plugin
.BrowserIface
39 private int block_update
= 0;
40 /* Stores the location in the cat_tree */
41 private Gtk
.TreeRowReference rref
= null;
43 private string title_color
= config
.get_string_with_default("Now Playing", "title-color", "#4d90dd");
44 private string item_color
= config
.get_string_with_default("Now Playing", "item-color", "#304ab8");
45 private bool theme_colors
= (bool) config
.get_int_with_default("Now Playing", "use-theme-color",1);
46 private Gdk
.Color background
;
47 private Gdk
.Color foreground
;
50 private void show_metadata_search()
57 /* Set the plugin as an internal one and of type pl_browser */
58 this
.plugin_type
= 2|8;
60 gmpcconn
.connection_changed
.connect(con_changed
);
61 gmpcconn
.status_changed
.connect(status_changed
);
64 var background
= config
.get_string_with_default("Now Playing", "background-color", "#000");
65 var foreground
= config
.get_string_with_default("Now Playing", "foreground-color", "#FFF");
66 Gdk
.Color
.parse(background
,out this
.background
);
67 Gdk
.Color
.parse(foreground
,out this
.foreground
);
69 easy_command
.add_entry(
72 _("Switch to Metadata view"),
73 (Gmpc
.Easy
.Command
.Callback
*)show_metadata_search
,
77 private const int[] version
= {0,0,0};
78 public override unowned
int[] get_version()
83 public override unowned
string get_name()
85 return N_("Metadata Browser");
88 public override void save_yourself()
90 if(this
.paned
!= null)
92 int pos
= this
.paned
.get_position();
93 config
.set_int(this
.get_name(), "pane-pos", pos
);
96 if(this
.model_artist
!= null) this
.model_artist
.set_mpd_data(null);
97 if(this
.model_albums
!= null)this
.model_albums
.set_mpd_data(null);
101 var path
= rref
.get_path();
104 unowned
int[] indices
= path
.get_indices();
105 config
.set_int(this
.get_name(), "position", indices
[0]);
109 /* Now playing browser */
116 private Gtk
.Paned paned
= null;
117 /* holding the 3 browsers */
118 private Gtk
.Box browser_box
= null;
121 private Gtk
.TreeView tree_artist
= null;
122 private Gmpc
.MpdData
.Model model_artist
= null;
123 private Gtk
.TreeModelFilter model_filter_artist
= null;
124 private Gtk
.Entry artist_filter_entry
= null;
127 private Gtk
.TreeView tree_album
= null;
128 private Gmpc
.MpdData
.Model model_albums
= null;
129 private Gtk
.TreeModelFilter model_filter_album
= null;
130 private Gtk
.Entry album_filter_entry
= null;
133 private Gtk
.TreeView tree_songs
= null;
134 private Gmpc
.MpdData
.Model model_songs
= null;
136 /* The right hand "browser" box */
137 private Gtk
.ScrolledWindow metadata_sw
= null;
138 private Gtk
.EventBox metadata_box
= null;
140 private Gtk
.EventBox header
= null;
143 * Makes gmpc jump to the metadata browser
145 private void select_metadata_browser(Gtk
.Widget widget
)
147 this
.select_browser(null);
150 * Makes gmpc jump to the metadata browser
153 private void select_metadata_browser_search(Gtk
.Widget widget
)
155 select_browser(null);
159 * Gmpc.Plugin.BrowserIface.add_go_menu
161 private int browser_add_go_menu(Gtk
.Menu menu
)
163 if(this
.get_enabled())
165 var item
= new Gtk
.ImageMenuItem
.with_mnemonic(_(this
.get_name()));
166 item
.set_image(new Gtk
.Image
.from_icon_name("gmpc-metabrowser", Gtk
.IconSize
.MENU
));
167 item
.activate
.connect(select_metadata_browser
);
168 item
.add_accelerator("activate", menu
.get_accel_group(),0xffc1,0, Gtk
.AccelFlags
.VISIBLE
);
171 item
= new Gtk
.ImageMenuItem
.with_mnemonic(_("Search metadata"));
172 item
.set_image(new Gtk
.Image
.from_stock("gtk-find", Gtk
.IconSize
.MENU
));
173 item
.activate
.connect(select_metadata_browser_search
);
174 item
.add_accelerator("activate", menu
.get_accel_group(),
175 0x04d,Gdk
.ModifierType
.CONTROL_MASK
,
176 Gtk
.AccelFlags
.VISIBLE
);
185 * This builds the browser
187 /* This hack makes clicking a selected row again, unselect it */
188 private bool browser_button_press_event(Gtk
.Widget treel
, Gdk
.EventButton event
)
190 var tree
= (treel as Gtk
.TreeView
);
191 Gtk
.TreePath path
= null;
192 if(event
.button
!= 1) return false;
193 if(tree
.get_path_at_pos((int)event
.x
,(int)event
.y
,out path
, null, null, null))
195 if(tree
.get_selection().path_is_selected(path
))
197 tree
.get_selection().unselect_path(path
);
204 * Artist tree view functions */
205 private void browser_artist_entry_changed(Gtk
.Editable entry
)
207 string text
= (entry as Gtk
.Entry
).get_text();
210 (entry as Gtk
.Widget
).show();
211 (entry as Gtk
.Widget
).grab_focus();
215 (entry as Gtk
.Widget
).hide();
216 this
.tree_artist
.grab_focus();
218 this
.model_filter_artist
.refilter();
220 /* Handle right mouse click */
221 private bool artist_browser_button_release_event(Gtk
.Widget treel
, Gdk
.EventButton event
)
223 var tree
= (treel as Gtk
.TreeView
);
224 if(event
.button
== 3)
226 if(tree
.get_selection().count_selected_rows()>0)
228 var menu
= new Gtk
.Menu();
229 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
230 item
.activate
.connect((source
) =>
234 if(tree
.get_selection().get_selected(out model
, out iter
))
237 model
.get(iter
,7, out artist
);
240 MPD
.Database
.search_start(server
,true);
241 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
242 MPD
.Data
.Item data
= MPD
.Database
.search_commit(server
);
243 data
.sort_album_disc_track();
249 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
253 MPD
.PlayQueue
.queue_commit(server
);
260 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
261 item
.activate
.connect((source
) =>
265 if(tree
.get_selection().get_selected(out model
, out iter
))
268 model
.get(iter
,7, out artist
);
271 MPD
.PlayQueue
.clear(server
);
272 MPD
.PlayQueue
.add_artist(server
, artist
);
273 MPD
.Player
.play(server
);
279 menu
.popup(null, null, null, event
.button
, event
.time
);
288 private bool visible_func_artist (Gtk
.TreeModel model
, Gtk
.TreeIter iter
)
290 string text
= this
.artist_filter_entry
.get_text();
291 /* Visible if row is non-empty and first column is "HI" */
293 bool visible
= false;
295 if(text
[0] == '\0') return true;
297 model
.get (iter
, 7, out str
, -1);
298 if (str
!= null && str
.casefold().normalize().index_of(text
.casefold().normalize()) >= 0)
303 private bool browser_artist_key_press_event(Gtk
.Widget widget
, Gdk
.EventKey event
)
305 unichar uc
= Gdk
.keyval_to_unicode(event
.keyval
);
309 int i
= uc
.to_utf8(outbuf
);
310 ((char[])outbuf
)[i
] = '\0';
311 this
.artist_filter_entry
.set_text(outbuf
);
312 this
.artist_filter_entry
.grab_focus();
313 this
.artist_filter_entry
.set_position(1);
322 private void album_add_clicked(Gtk
.Widget item
)
324 string artist
= browser_get_selected_artist();
327 string albumartist
= null;
328 string album
= browser_get_selected_album();
329 if(album
!= null && Gmpc
.server
.tag_supported(MPD
.Tag
.Type
.ALBUM_ARTIST
))
331 MPD
.Database
.search_field_start(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
);
332 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
333 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
334 var ydata
= MPD
.Database
.search_commit(server
);
337 if(ydata
.tag
.length
> 0)
338 albumartist
= ydata
.tag
;
341 /* Fill in the first browser */
342 MPD
.Database
.search_start(server
,true);
343 if(albumartist
!= null && albumartist
.length
> 0)
344 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM_ARTIST
, albumartist
);
346 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
349 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
350 var data
= MPD
.Database
.search_commit(server
);
352 data
.sort_album_disc_track();
357 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
361 MPD
.PlayQueue
.queue_commit(server
);
365 private void album_replace_clicked(Gtk
.Widget item
)
367 MPD
.PlayQueue
.clear(server
);
368 album_add_clicked(item
);
369 MPD
.Player
.play(server
);
371 /* Handle right mouse click */
372 private bool album_browser_button_release_event(Gtk
.Widget tree
, Gdk
.EventButton event
)
374 if(event
.button
== 3)
376 if((tree as Gtk
.TreeView
).get_selection().count_selected_rows()>0)
378 var menu
= new Gtk
.Menu();
379 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
380 item
.activate
.connect(album_add_clicked
);
383 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
384 item
.activate
.connect(album_replace_clicked
);
387 menu
.popup(null, null, null, event
.button
, event
.time
);
395 private bool visible_func_album (Gtk
.TreeModel model
, Gtk
.TreeIter iter
)
397 string text
= this
.album_filter_entry
.get_text();
398 /* Visible if row is non-empty and first column is "HI" */
400 bool visible
= false;
402 if(text
[0] == '\0') return true;
404 model
.get (iter
, 6, out str
, -1);
405 if (str
!= null && str
.casefold().normalize().index_of(text
.casefold().normalize()) >= 0)
412 private bool browser_album_key_press_event(Gtk
.Widget widget
, Gdk
.EventKey event
)
414 unichar uc
= Gdk
.keyval_to_unicode(event
.keyval
);
418 int i
= uc
.to_utf8(outbuf
);
419 ((char[])outbuf
)[i
] = '\0';
420 this
.album_filter_entry
.set_text(outbuf
);
421 this
.album_filter_entry
.grab_focus();
422 this
.album_filter_entry
.set_position(1);
429 private void browser_album_entry_changed(Gtk
.Editable pentry
)
431 Gtk
.Entry entry
= (pentry as Gtk
.Entry
);
432 string text
= entry
.get_text();
441 this
.tree_album
.grab_focus();
443 this
.model_filter_album
.refilter();
448 private void song_add_clicked(Gtk
.Widget item
)
450 unowned MPD
.Song? song
= browser_get_selected_song();
453 MPD
.PlayQueue
.add_song(server
,song
.file
);
456 private void song_replace_clicked(Gtk
.Widget item
)
458 MPD
.PlayQueue
.clear(server
);
459 song_add_clicked(item
);
460 MPD
.Player
.play(server
);
462 /* Handle right mouse click */
463 private bool song_browser_button_release_event(Gtk
.Widget ptree
, Gdk
.EventButton event
)
465 Gtk
.TreeView tree
= (ptree as Gtk
.TreeView
);
466 if(event
.button
== 3)
468 if(tree
.get_selection().count_selected_rows()>0)
470 var menu
= new Gtk
.Menu();
471 var item
= new Gtk
.ImageMenuItem
.from_stock("gtk-add",null);
472 item
.activate
.connect(song_add_clicked
);
475 item
= new Gtk
.ImageMenuItem
.from_stock("gtk-media-play",null);
476 item
.activate
.connect(song_replace_clicked
);
479 menu
.popup(null, null, null, event
.button
, event
.time
);
487 private bool browser_button_release_event(Gtk
.Widget widget
, Gdk
.EventButton event
)
489 if(event
.button
== 8)
494 else if (event
.button
== 9)
501 public void set_orientation()
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
);
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
);
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
);
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);
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
);
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
);
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
);
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
);
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());
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);
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()
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);
760 private string?
browser_get_selected_album()
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
))
768 model
.get(iter
, 6,out album
, -1);
773 private unowned MPD
.Song?
browser_get_selected_song()
776 var sel
= this
.tree_songs
.get_selection();
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);
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();
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();
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
);
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
;
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();
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
);
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
);
874 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
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();
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();
900 MPD
.PlayQueue
.add_song(server
,song
.file
);
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
);
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
);
924 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
926 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ALBUM
, album
);
927 var data
= MPD
.Database
.search_commit(server
);
930 data
.sort_album_disc_track();
933 MPD
.PlayQueue
.queue_add_song(server
, data
.song
.file
);
936 MPD
.PlayQueue
.queue_commit(server
);
941 private void play_selected_song(Gtk
.Button button
)
943 unowned MPD
.Song? song
= browser_get_selected_song();
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
)
964 * Add a row to a gtk table
965 * <b>$label:</b> $value
969 private void add_entry(Gtk
.Grid table
, string entry_label
, string? value
,Gtk
.Widget? extra
, ref int i
, string ? image
= null)
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
));
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
);
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);
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);
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);
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 */
1022 var hbox
= new Gtk
.HBox(false, 6);
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);
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);
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);
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);
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);
1134 if(song
.artist
!= null)
1136 this
.add_entry(info_box
, _("Artist"), song
.artist
, null,ref i
, "media-artist");
1139 if(song
.album
!= null)
1141 this
.add_entry(info_box
, _("Album"), song
.album
,null, ref i
, "media-album");
1144 if(song
.genre
!= null)
1146 this
.add_entry(info_box
, _("Genre"), song
.genre
,null, ref i
, "media-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");
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",
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);
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);
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);
1247 button
.clicked
.connect((source
) =>
1249 debug("notebook page %i clicked", j
);
1250 notebook
.set_current_page(j
);
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);
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;
1285 text_view
.query_from_song(song
);
1286 text_view_queried
= true;
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);
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();
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();
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);
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();
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 */
1361 var page
= config
.get_int_with_default("MetaData", "song-last-page", 0);
1364 notebook
.set_current_page(0);
1368 /* The list is in reversed order, compensate for that. */
1369 var w
= group
.nth_data(i
-page
-1);
1371 notebook
.set_current_page(page
);
1375 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
1378 /* Create pane in 2. */
1379 var bottom_hbox
= new Gtk
.HBox(false, 6);
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);
1399 master_box
.pack_start(vbox
, false, false, 0);
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(),
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
);
1476 stdout
.printf("song context menu show\n");
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();
1490 vbox
.pack_start(result_hbox
, false, false);
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
;
1516 this
.browser_box
.hide();
1517 show_button
.label
= _("Show sidebar");
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);
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
;
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);
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);
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);
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);
1659 rbutton
.clicked
.connect((source
) =>
1661 debug("notebook page %i clicked", j
);
1662 notebook
.set_current_page(j
);
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
);
1705 stdout
.printf("song context menu show\n");
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);
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
);
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
);
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
);
1743 MPD
.Database
.search_add_constraint(server
, MPD
.Tag
.Type
.ARTIST
, artist
);
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);
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 */
1768 var page
= config
.get_int_with_default("MetaData", "album-last-page", 0);
1771 notebook
.set_current_page(0);
1775 /* The list is in reversed order, compensate for that. */
1776 var w
= group
.nth_data(i
-page
-1);
1778 notebook
.set_current_page(page
);
1782 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
1785 /* Create pane in 2. */
1786 var bottom_hbox
= new Gtk
.HBox(false, 6);
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
1808 * <image> | <array with info>
1811 * <artist info text>
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);
1821 vbox
.border_width
= 8;
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
;
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);
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);
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);
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);
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
);
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);
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();
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
);
2006 stdout
.printf("song context menu show\n");
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);
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
);
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);
2042 if( song
.artist
!= null)
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.
2054 if(this
.model_albums
.get_iter_first(out titer
))
2058 unowned MPD
.Song? asong
= null;
2059 this
.model_albums
.get(titer
,0, &asong
);
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();
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
);
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");
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
);
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
);
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
);
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
,
2130 MPD
.Player
.play(server
);
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
,
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);
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
);
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 */
2192 var page
= config
.get_int_with_default("MetaData", "artist-last-page", 0);
2195 notebook
.set_current_page(0);
2199 /* The list is in reversed order, compensate for that. */
2200 var w
= group
.nth_data(i
-page
-1);
2202 notebook
.set_current_page(page
);
2207 ali
= new Gtk
.Alignment(0.0f
, 0.5f
,0f
,0f
);
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;
2249 string artist
= browser_get_selected_artist();
2250 string album
= browser_get_selected_album();
2251 unowned MPD
.Song? song
= browser_get_selected_song();
2255 /** Add item to history */
2256 var item
= new
Hitem();
2257 item
.song
= song
.copy();
2258 item
.type
= HitemType
.SONG
;
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
;
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
;
2286 metadata_box_show_artist(artist
);
2290 var item
= new
Hitem();
2291 item
.search_string
= null;
2292 item
.type
= HitemType
.BASE
;
2294 metadata_box_show_base();
2297 this
.update_timeout
= 0;
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();
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
)
2318 this
.selected
= true;
2319 this
.browser_init();
2320 container
.add(this
.paned
);
2322 /* update if non selected */
2323 artist
= browser_get_selected_artist();
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
);
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();
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
);
2367 private enum HitemType
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
)
2386 case HitemType
.BASE
:
2389 case HitemType
.ARTIST
:
2390 this
.set_artist(hi
.song
.artist
);
2392 case HitemType
.ALBUM
:
2393 this
.set_album(hi
.song
.artist
, hi
.song
.album
);
2395 case HitemType
.SONG
:
2396 this
.set_song(hi
.song
);
2399 metadata_box_clear();
2403 private void history_previous()
2405 if(history
== null || current
== null)
2409 if(current
.next
== null)
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)
2424 if(current
.prev
== null)
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");
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();
2453 unowned Hitem i
= iter
.data
;
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
;
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
);
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())
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);
2508 hist_box
.attach(ali
, 0, 0, 1, 1);//pack_start(ali, true, true, 0);
2509 //hist_box.attach(ali, 1, 0, 1,1);
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 */
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
)=>
2532 hist_box
.attach(button
, 1, 0, 1,1);//pack_start(button, true, true, 0);
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);
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);
2558 var button
= new Gtk
.Button();//.with_label(album);
2560 var ali
= new Gtk
.Alignment(0.0f
, 0.5f
, 0.0f
, 0.0f
);
2563 var gr
= new Gtk
.Grid();
2564 gr
.set_column_spacing(6);
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
);
2580 hist_box
.attach(button
, 4,0,1,1);//pack_start(button, true, true, 0);
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
);
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);
2635 private void history_add(Hitem hi
)
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
))
2648 /* clean items in the future */
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
);
2667 private void history_clear()
2669 this
.current
= null;
2670 this
.history
= null;
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();
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();
2699 this
.artist_filter_entry
.set_text("");
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();
2718 while((this
.model_filter_artist
).iter_next(ref iter
));
2720 this
.block_update
--;
2723 this
.metadata_box_clear();
2724 this
.metadata_box_update();
2729 set_album(string artist
, string album
)
2731 if(!this
.get_enabled()) return;
2732 this
.block_update
++;
2733 this
.set_artist(artist
);
2735 this
.album_filter_entry
.set_text("");
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();
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();
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
);
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();
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
;
2813 var view
= metadata_box_show_song(song
,true);
2814 this
.metadata_box
.add(view
);
2815 this
.metadata_box
.show_all();
2819 select_browser(Gtk
.TreeView? tree
)
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();
2828 sel
.select_path(path
);
2833 private string get_extension(string path
)
2835 long length
= path
.length
;
2838 for(; i
>0 && (length
-i
) <8; i
--)
2842 retv
= path
.substring(i
+1);
2849 public override void set_enabled(bool state
)
2855 browser_add( Gmpc
.Playlist3
.get_category_tree_view());
2861 if(this
.rref
!= null)
2863 var path
= rref
.get_path();
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();
2870 if(model
.get_iter(out iter
, path
))
2879 if(this
.get_name() != null)
2880 Gmpc
.config
.set_int(this
.get_name(), "enabled", (int)state
);