Add invalid-tags cover icon.
[gmpc.git] / src / vala / gmpc-favorites.vala
bloba9f0e93b1ea6c656de14044053ca5668ed3e8d9d
2 /* Gnome Music Player Client (GMPC)
3 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
4 * Project homepage: http://gmpclient.org/
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 using Config;
21 using GLib;
22 using Gtk;
23 using Gdk;
24 using MPD;
26 /* trick to get config.h included */
27 static const string some_unique_name_fav = Config.VERSION;
28 private const bool use_transition_fav = Gmpc.use_transition;
29 public static Gmpc.Favorites.List favorites = null;
31 private const string LOG_DOMAIN_FAV = "Gmpc.Favorites";
32 namespace Gmpc.Favorites
34 /**
35 * This class is created, and stays active until the last GmpcFavoritesButton gets removed
37 public class List : GLib.Object
39 private MPD.Data.Item? list = null;
40 public bool disable {get; set; default = false;}
41 construct
43 gmpcconn.connection_changed.connect(con_changed);
44 gmpcconn.status_changed.connect(status_changed);
45 GLib.log(LOG_DOMAIN_FAV, GLib.LogLevelFlags.LEVEL_DEBUG, "Favorites object created");
46 if(Gmpc.server.connected)
48 con_changed(gmpcconn, server, 1);
52 /**
53 * If disconnected from mpd, clear the list.
54 * On connect fill
56 private
57 void
58 con_changed(Gmpc.Connection conn, MPD.Server server, int connect)
60 if(connect == 1)
62 GLib.log(LOG_DOMAIN_FAV, GLib.LogLevelFlags.LEVEL_DEBUG, "Update list");
63 list = MPD.Database.get_playlist_content(server, _("Favorites"));
64 // Enable plugin.
65 disable = false;
66 this.updated();
68 else
70 list = null;
73 /**
74 * If playlist changed update the list
76 private
77 void
78 status_changed(Gmpc.Connection conn, MPD.Server server, MPD.Status.Changed what)
80 if(!disable && (what&MPD.Status.Changed.STORED_PLAYLIST) == MPD.Status.Changed.STORED_PLAYLIST)
82 GLib.log(LOG_DOMAIN_FAV, GLib.LogLevelFlags.LEVEL_DEBUG, "Update list");
83 list = MPD.Database.get_playlist_content(server, _("Favorites"));
84 this.updated();
87 /****************************************************************************************
88 * "Public" api.
89 ****************************************************************************************/
90 /**
91 * Signal for the widget using the list to see if it needs to recheck status
93 public signal void updated();
95 /**
96 * Check if the song (specified by path) is favored
98 public
99 bool
100 is_favorite(string path)
102 unowned MPD.Data.Item iter = this.list.get_first();
103 while(iter != null)
105 if(iter.type == MPD.Data.Type.SONG)
107 if(iter.song.file == path)
109 return true;
112 iter.next(false);
114 return false;
117 * Favor, or unfavor a song
119 public
120 void
121 set_favorite(string path, bool favorite)
123 bool current = this.is_favorite(path);
124 /* Do nothing if state does not change */
125 if(!disable && current != favorite)
127 if(favorite)
129 /* Add it */
130 MPD.Database.playlist_list_add(server, _("Favorites"), path);
132 else
134 /* Remove it */
135 /* To be able to remove it we have to first lookup the position */
136 /* This needs libmpd 0.18.1 */
137 unowned MPD.Data.Item iter = this.list.get_first();
138 while(iter != null)
140 if(iter.type == MPD.Data.Type.SONG)
142 if(iter.song.file == path)
144 MPD.Database.playlist_list_delete(server, _("Favorites"), iter.song.pos);
145 return;
148 iter.next(false);
155 * The actual favorite button
157 public class Button : Gtk.EventBox
159 /* the song the button show show the state for */
160 private MPD.Song? song;
161 /* The image displaying the state */
162 private Gtk.Image image;
163 /* The current state */
164 private bool fstate = false;
165 /* The pixbuf holding the unmodified image */
166 private Gdk.Pixbuf pb = null;
169 * Creation of the object
171 construct
173 this.no_show_all = true;
174 this.visible_window = false;
175 var it = Gtk.IconTheme.get_default();
176 try {
177 pb = it.load_icon("emblem-favorite",24, 0);
179 catch(Error e)
181 GLib.error("error: %s\n", e.message);
183 if(favorites == null)
185 favorites = new List();
186 /* make sure favorites is set to NULL again when destroyed */
187 favorites.add_weak_pointer(&favorites);
189 else {
190 favorites.ref();
192 favorites.notify["disable"].connect((source)=>{
193 if(favorites.disable)
195 this.set_sensitive(false);
197 else{
198 this.set_sensitive(true);
201 favorites.updated.connect(update);
202 this.image = new Gtk.Image();
203 this.update(favorites);
204 this.add(this.image);
205 this.button_press_event.connect(button_press_event_callback);
206 this.enter_notify_event.connect(enter_notify_event_callback);
207 this.leave_notify_event.connect(leave_notify_event_callback);
210 ~Button()
212 if(favorites != null)
213 favorites.unref();
215 private
216 bool
217 button_press_event_callback(Gtk.Widget button,Gdk.EventButton event)
219 if(event.button == 1 && this.song != null)
221 favorites.set_favorite(this.song.file, !this.fstate);
222 this.fstate = !this.fstate;
224 else if (event.button == 3 && this.song != null)
226 var menu = new Gtk.Menu();
227 int items = 0;
228 MPD.Data.Item ? item = MPD.Database.get_playlist_list(server);
229 while(item != null)
231 string pp = item.playlist.path;
232 var entry = new Gtk.ImageMenuItem.with_label(pp);
233 if(pp == _("Favorites"))
235 entry.set_image(new Gtk.Image.from_icon_name("emblem-favorite", Gtk.IconSize.MENU));
237 else
239 entry.set_image(new Gtk.Image.from_icon_name("media-playlist", Gtk.IconSize.MENU));
241 entry.activate.connect((source) =>
243 MPD.Database.playlist_list_add(server,pp, this.song.file);
245 menu.append(entry);
246 item.next_free();
247 items++;
249 if(items > 0)
251 menu.show_all();
252 menu.popup(null, null, null, event.button, event.time);
254 else menu.destroy();
255 return true;
257 return false;
260 /* on mouse over, do some pre-highlighting */
261 private
262 bool
263 enter_notify_event_callback(Gtk.Widget button, Gdk.EventCrossing motion)
265 var pb2 = pb.copy();
266 if(this.fstate)
268 Gmpc.Misc.colorshift_pixbuf(pb2, pb, 10);
270 else
272 Gmpc.Misc.colorshift_pixbuf(pb2, pb,-50);
274 this.image.set_from_pixbuf(pb2);
275 return false;
277 /* Reset default highlighting */
278 private
279 bool
280 leave_notify_event_callback(Gtk.Widget button, Gdk.EventCrossing motion)
282 this.update(favorites);
283 return false;
285 /* Update the icon according to state */
286 private
287 void
288 update(Gmpc.Favorites.List list)
290 if(this.song != null)
292 this.fstate = favorites.is_favorite(this.song.file);
294 else
296 /* Hide the widget and do nothing */
297 this.hide();
298 return;
300 /* Copy the pixbuf */
301 var pb2 = pb.copy();
302 /* Depending on the state colorshift the pixbuf */
303 if(this.fstate)
305 Gmpc.Misc.colorshift_pixbuf(pb2, pb, 30);
307 else
309 Gmpc.Misc.colorshift_pixbuf(pb2, pb, -80);
311 this.image.set_from_pixbuf(pb2);
312 this.image.show();
313 this.show();
315 /**********************************************************************
316 * Public api
317 *********************************************************************/
318 /* Set the song the button should watch. or NULL to watch non */
319 public
320 void
321 set_song(MPD.Song? song)
323 if(this.song == null && song == null ) return;
324 if(this.song != null && song != null && this.song.file == song.file) return;
325 this.song = song.copy();
326 this.update(favorites);