1 /*
2  * Copyright (C) 2007 Felipe Weckx <felipe.weckx@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 
21 
22 #include "gbemol-playlist.h"
23 #include "gbemol-utils.h"
24 
25 #include <gdk/gdkkeysyms.h>
26 #include <gtk/gtk.h>
27 
28 static GObjectClass *parent_class = NULL;
29 
30 /* Playlists View Columns */
31 enum
32 {
33 	COLUMN_PLAYLISTS_TITLE,
34 	COLUMN_PLAYLISTS_ICON,
35 	COLUMN_PLAYLISTS_CURRENT,   /* is it the current playlist ? */
36 	COLUMN_PLAYLISTS_BOLD,
37 	COLUMN_PLAYLISTS_BOLD_SET,
38 	N_COLUMNS_PLAYLISTS
39 };
40 
41 /* Songs View Columns */
42 enum
43 {
44 	COLUMN_SONGS_MARKUP,
45 	COLUMN_SONGS_POS,
46 	COLUMN_SONGS_ARTIST,
47 	COLUMN_SONGS_TITLE,
48 	COLUMN_SONGS_ALBUM,
49 	COLUMN_SONGS_TRACK,
50 	COLUMN_SONGS_DATE,
51 	COLUMN_SONGS_GENRE,
52 	COLUMN_SONGS_COMPOSER,
53 	COLUMN_SONGS_DISC,
54 	COLUMN_SONGS_COMMENT,
55 	COLUMN_SONGS_TIME,
56 	COLUMN_SONGS_ID,
57 	COLUMN_SONGS_BOLD,
58 	COLUMN_SONGS_BOLD_SET,
59 	COLUMN_SONGS_BG,
60 	COLUMN_SONGS_BG_SET,
61 	COLUMN_SONGS_FG,
62 	COLUMN_SONGS_FG_SET,
63 	N_COLUMNS_SONGS
64 };
65 
66 
67 struct _GbemolPlaylistPrivate {
68 	GbemolMpd* mpd;
69 
70 	GtkUIManager *manager;
71 	GtkTreeView *tv_playlists;
72 	GtkTreeView *tv_songs;
73 	GtkListStore *lst_playlists;
74 	GtkListStore *lst_songs;
75 	GtkTreeSelection *sel_playlists;
76 	GtkTreeSelection *sel_songs;
77 	GtkTreeModel *fil_songs;
78 	GtkListStore *lst_column_search;
79 
80 	GtkWidget *ent_search;
81 	GtkWidget *cmb_search;
82 	GtkWidget *btn_search;
83 	GtkWidget *btn_search_clear;
84 	GtkWidget *btn_add;
85 	GtkWidget *btn_replace;
86 	GtkWidget *btn_new_playlist;
87 	GtkWidget *btn_save_playlist;
88 	GtkWidget *btn_add_url;
89 
90 	GtkWidget *mnu_songs;
91 	GtkWidget *mnu_item_columns;
92 	GtkWidget *mnu_item_mode[N_PLAYLIST_MODES];
93 
94 	GtkWidget *mnu_playlists;
95 
96 	GtkTooltips *tips;
97 
98 	GbemolPlaylistMode mode;
99 
100 	gboolean dispose_has_run;
101 };
102 
103 /* Constructors/Destructors */
104 static void gbemol_playlist_class_init (GObjectClass *g_class);
105 static void gbemol_playlist_init (GbemolPlaylist *obj);
106 static void gbemol_playlist_finalize (GObject *object);
107 static void gbemol_playlist_dispose (GObject *object);
108 
109 /* Private functions */
110 static gchar* gbemol_playlist_save_dialog (GbemolPlaylist *pls);
111 void gbemol_playlist_clear_all (GbemolPlaylist* pls);
112 static GList* gbemol_playlist_get_selected (GtkTreeView* view);
113 static void gbemol_playlist_free_selected (GList* l);
114 void gbemol_playlist_append_song (GbemolPlaylist* pls, mpd_Song* song);
115 void gbemol_playlist_populate_songs (GbemolPlaylist *pls, GList* songs);
116 void gbemol_playlist_populate_playlists (GbemolPlaylist* pls);
117 void gbemol_playlist_update_songs (GbemolPlaylist* pls);
118 void gbemol_playlist_remove_selected_songs (GbemolPlaylist *pls);
119 void gbemol_playlist_play_selected (GbemolPlaylist *pls);
120 void gbemol_playlist_play_last_song (GbemolPlaylist *pls);
121 void gbemol_playlist_remove_selected_playlist (GbemolPlaylist *pls);
122 void gbemol_playlist_load_selected_playlist (GbemolPlaylist *pls);
123 gchar* gbemol_playlist_save_dialog (GbemolPlaylist *pls);
124 void gbemol_playlist_columns_dialog (GbemolPlaylist* pls);
125 
126 /* Callbacks */
127 static void on_sel_playlists_changed (GtkTreeSelection *select, GbemolPlaylist* pls);
128 static gboolean on_tvw_playlists_key_press_event (GtkWidget *w, GdkEventKey *event, GbemolPlaylist* pls);
129 static gint on_tvw_playlists_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolPlaylist* pls);
130 static gboolean on_tvw_songs_key_press_event (GtkWidget* w, GdkEventKey* event, GbemolPlaylist* pls);
131 static gboolean on_tvw_songs_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolPlaylist* pls);
132 static void on_btn_new_playlist_clicked (GtkButton *button, GbemolPlaylist* pls);
133 static void on_btn_save_playlist_clicked (GtkButton *button, GbemolPlaylist* pls);
134 static void on_btn_playlist_add_clicked (GtkWidget* b, GbemolPlaylist* pls);
135 static void on_btn_playlist_replace_clicked (GtkWidget* b, GbemolPlaylist* pls);
136 static void on_mnu_playlist_remove_activate (GtkWidget* m, GbemolPlaylist* pls);
137 static void on_mnu_clear_activate (GtkWidget* w, GbemolPlaylist* pls);
138 static void on_mnu_shuffle_activate (GtkWidget* w, GbemolPlaylist* pls);
139 static void on_mnu_column_activate (GtkWidget* w, GbemolPlaylist* pls);
140 static void on_column_clicked (GtkTreeViewColumn* column, GbemolPlaylist* pls);
141 static void on_mnu_mode_toggled (GtkCheckMenuItem *item, GbemolPlaylist *pls);
142 static void on_mnu_remove_activate (GtkWidget* w, GbemolPlaylist *pls);
143 static void on_btn_clear_search_activate (GtkButton* btn, GbemolPlaylist *pls);
144 static void on_ent_search_changed (GtkEditable* entry, GbemolPlaylist *pls);
145 static void on_btn_add_url_clicked (GtkButton* btn, GbemolPlaylist *pls);
146 
147 static gboolean gbemol_playlist_is_visible (GtkTreeModel* model, GtkTreeIter *iter, GbemolPlaylist* pls);
148 
149 static const gchar* column_songs[N_COLUMNS] = {
150 		NULL,
151 		N_("#"),
152 		N_("Artist"),
153 		N_("Title"),
154 		N_("Album"),
155 		N_("Track"),
156 		N_("Date"),
157 		N_("Genre"),
158 		N_("Composer"),
159 		N_("Disc"),
160 		N_("Comment"),
161 		N_("Time")
162 	};
163 
164 
165 GType
gbemol_playlist_get_type(void)166 gbemol_playlist_get_type (void)
167 {
168 	static GType type = 0;
169 	if (type == 0) {
170 		static const GTypeInfo info = {
171 			sizeof (GbemolPlaylistClass),
172 			NULL,   /* base_init */
173 			NULL,   /* base_finalize */
174 			(GClassInitFunc) gbemol_playlist_class_init,   /* class_init */
175 			NULL,   /* class_finalize */
176 			NULL,   /* class_data */
177 			sizeof (GbemolPlaylist),
178 			0,      /* n_preallocs */
179 			(GInstanceInitFunc) gbemol_playlist_init    /* instance_init */
180 		};
181 
182 		type = g_type_register_static (GTK_TYPE_VBOX,
183 				"GbemolPlaylist",
184 				&info, 0);
185 	}
186 	return type;
187 }
188 
189 static void
gbemol_playlist_class_init(GObjectClass * g_class)190 gbemol_playlist_class_init (GObjectClass *g_class)
191 {
192 	parent_class = g_type_class_peek_parent (g_class);
193 	g_class->finalize = gbemol_playlist_finalize;
194 	g_class->dispose = gbemol_playlist_dispose;
195 }
196 
197 static void
gbemol_playlist_dispose(GObject * obj)198 gbemol_playlist_dispose (GObject* obj)
199 {
200 	GbemolPlaylist* self = (GbemolPlaylist *) obj;
201 
202 	if (self->priv->dispose_has_run)
203 		return;
204 
205 	self->priv->dispose_has_run = TRUE;
206 
207 	gbemol_cfg_set_int ("playlist", "cmb_search",
208 			gtk_combo_box_get_active (GTK_COMBO_BOX (self->priv->cmb_search)));
209 
210 	G_OBJECT_CLASS (parent_class)->dispose (obj);
211 
212 }
213 
214 static void
gbemol_playlist_finalize(GObject * obj)215 gbemol_playlist_finalize (GObject *obj)
216 {
217 	g_free (GBEMOL_PLAYLIST (obj)->priv);
218 	G_OBJECT_CLASS (parent_class)->finalize (obj);
219 }
220 
221 static void
gbemol_playlist_init(GbemolPlaylist * obj)222 gbemol_playlist_init (GbemolPlaylist *obj)
223 {
224 	obj->priv = g_new0 (GbemolPlaylistPrivate, 1);
225 	obj->priv->mode = GBEMOL_PLAYLIST_MODE_COLUMNS;
226 	obj->priv->dispose_has_run = FALSE;
227 
228 	/* Playlist modes names */
229 	obj->playlist_modes[GBEMOL_PLAYLIST_MODE_COLUMNS] = _("Columns Mode");
230 	obj->playlist_modes[GBEMOL_PLAYLIST_MODE_LINES] = _("Lines Mode");
231 }
232 
233 static void
gbemol_playlist_build_menus(GbemolPlaylist * pls)234 gbemol_playlist_build_menus (GbemolPlaylist *pls)
235 {
236 	GtkWidget *item, *img, *submnu;
237 	GSList *group = NULL;
238 	gint i;
239 
240 	pls->priv->mnu_songs = gtk_menu_new ();
241 
242 	/*** SONGS MENU ****/
243 	/* Remove song */
244 	item = gtk_image_menu_item_new_with_label (_("Remove"));
245 	img = gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU);
246 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
247 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
248 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_remove_activate), pls);
249 	gtk_widget_show (item);
250 
251 	/* Clear songs */
252 	item = gtk_image_menu_item_new_from_stock (GTK_STOCK_CLEAR, NULL);
253 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
254 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_clear_activate), pls);
255 	gtk_widget_show (item);
256 
257 	/* Shuffle songs */
258 	item = gtk_image_menu_item_new_with_label (_("Shuffle"));
259 	img = gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU);
260 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
261 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
262 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_shuffle_activate), pls);
263 	gtk_widget_show (item);
264 
265 	item = gtk_separator_menu_item_new ();
266 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
267 	gtk_widget_show (item);
268 
269 	/* Modes Submenu */
270 	item = gtk_menu_item_new_with_label (_("Playlist Mode"));
271 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
272 	gtk_widget_show (item);
273 
274 	submnu = gtk_menu_new ();
275 	gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submnu);
276 
277 	/* Modes */
278 	item = gtk_radio_menu_item_new_with_label (NULL, pls->playlist_modes[0]);
279 	g_object_set_data (G_OBJECT (item), "mode", GINT_TO_POINTER (0));
280 	g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (on_mnu_mode_toggled), pls);
281 	gtk_menu_shell_append (GTK_MENU_SHELL (submnu), item);
282 	gtk_widget_show (item);
283 	pls->priv->mnu_item_mode[0] = item;
284 	group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
285 
286 	for (i = 1; i < N_PLAYLIST_MODES; i++)
287 	{
288 		item = gtk_radio_menu_item_new_with_label (group, pls->playlist_modes[i]);
289 		g_object_set_data (G_OBJECT (item), "mode", GINT_TO_POINTER (i));
290 		g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (on_mnu_mode_toggled), pls);
291 		gtk_menu_shell_append (GTK_MENU_SHELL (submnu), item);
292 		gtk_widget_show (item);
293 		pls->priv->mnu_item_mode[i] = item;
294 		group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
295 	}
296 
297 	/* Separator */
298 	item = gtk_separator_menu_item_new ();
299 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
300 	gtk_widget_show (item);
301 
302 	/* Columns edit */
303 	item = gtk_image_menu_item_new_with_label (_("Edit Columns"));
304 	img = gtk_image_new_from_stock (GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_MENU);
305 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
306 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_songs), item);
307 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_column_activate), pls);
308 	gtk_widget_show (item);
309 	pls->priv->mnu_item_columns = item;
310 
311 	/*** PLAYLISTS MENU ***/
312 	pls->priv->mnu_playlists = gtk_menu_new ();
313 
314 	/* Add to current playlist */
315 	item = gtk_image_menu_item_new_with_label (_("Enqueue"));
316 	img = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU);
317 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
318 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_playlists), item);
319 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_btn_playlist_add_clicked), pls);
320 	gtk_widget_show (item);
321 
322 	/* Replace current playlist */
323 	item = gtk_image_menu_item_new_with_label (_("Play"));
324 	img = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_MENU);
325 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
326 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_playlists), item);
327 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_btn_playlist_replace_clicked), pls);
328 	gtk_widget_show (item);
329 
330 	/* Delete selected playlist */
331 	item = gtk_image_menu_item_new_with_label (_("Delete"));
332 	img = gtk_image_new_from_stock (GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU);
333 	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), img);
334 	gtk_menu_shell_append (GTK_MENU_SHELL (pls->priv->mnu_playlists), item);
335 	g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (on_mnu_playlist_remove_activate), pls);
336 	gtk_widget_show (item);
337 }
338 
339 GbemolPlaylist*
gbemol_playlist_new(GbemolMpd * mpd)340 gbemol_playlist_new (GbemolMpd* mpd)
341 {
342 	GbemolPlaylist *pls;
343 	GtkCellRenderer* renderer;
344 	GtkTreeViewColumn *column;
345 	GtkWidget *hpnd, *btn, *hbox, *vbox, *lbl, *scr;
346 	GtkTreeIter iter;
347 	int i;
348 	gchar *str;
349 
350 	pls = GBEMOL_PLAYLIST (g_object_new (GBEMOL_TYPE_PLAYLIST, NULL));
351 
352 	pls->priv->mpd = mpd;
353 
354 
355 	gbemol_playlist_build_menus (pls);
356 	pls->priv->tips = gtk_tooltips_new ();
357 
358 	hpnd = gtk_hpaned_new ();
359 	gtk_box_pack_start (GTK_BOX (pls), hpnd, TRUE, TRUE, 0);
360 
361 	/* The playlists store */
362 	pls->priv->lst_playlists = gtk_list_store_new (N_COLUMNS_PLAYLISTS,
363 			G_TYPE_STRING,
364 			G_TYPE_STRING,
365 			G_TYPE_BOOLEAN,
366 			G_TYPE_INT,
367 			G_TYPE_BOOLEAN);
368 
369 	pls->priv->tv_playlists = GTK_TREE_VIEW (gtk_tree_view_new ());
370 	gtk_tree_view_set_model (pls->priv->tv_playlists, GTK_TREE_MODEL (pls->priv->lst_playlists));
371 	gtk_tree_view_set_headers_visible (pls->priv->tv_playlists, FALSE);
372 	g_object_unref (G_OBJECT (pls->priv->lst_playlists));
373 
374 	scr = gtk_scrolled_window_new (NULL, NULL);
375 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
376 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_ETCHED_IN);
377 	gtk_container_add (GTK_CONTAINER (scr), GTK_WIDGET (pls->priv->tv_playlists));
378 
379 	gtk_paned_pack1 (GTK_PANED (hpnd), scr, TRUE, FALSE);
380 
381 	gtk_tree_view_set_search_column (pls->priv->tv_playlists, COLUMN_PLAYLISTS_TITLE);
382 	pls->priv->sel_playlists = gtk_tree_view_get_selection (pls->priv->tv_playlists);
383 	gtk_tree_selection_set_mode (pls->priv->sel_playlists, GTK_SELECTION_BROWSE);
384 
385 	/* The Icon column */
386 	renderer = gtk_cell_renderer_pixbuf_new ();
387 	column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
388 			"stock-id", COLUMN_PLAYLISTS_ICON,
389 			NULL);
390 	gtk_tree_view_append_column (pls->priv->tv_playlists, column);
391 
392 	/* The playlist name column */
393 	renderer = gtk_cell_renderer_text_new ();
394 	column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
395 			"text", COLUMN_PLAYLISTS_TITLE,
396 			"weight", COLUMN_PLAYLISTS_BOLD,
397 			"weight-set", COLUMN_PLAYLISTS_BOLD_SET,
398 			NULL);
399 	gtk_tree_view_append_column (pls->priv->tv_playlists, column);
400 
401 	vbox = gtk_vbox_new (FALSE, 5);
402 
403 	/* The search field */
404 	hbox = gtk_hbox_new (FALSE, 5);
405 	lbl = gtk_label_new (_("Search:"));
406 	gtk_box_pack_start (GTK_BOX (hbox), lbl, FALSE, FALSE, 0);
407 
408 	pls->priv->ent_search = gtk_entry_new ();
409 	gtk_tooltips_set_tip (pls->priv->tips, pls->priv->ent_search, _("Enter text to be searched"), NULL);
410 	gtk_box_pack_start (GTK_BOX (hbox), pls->priv->ent_search, FALSE, FALSE, 0);
411 	g_signal_connect (G_OBJECT (pls->priv->ent_search), "changed", G_CALLBACK (on_ent_search_changed), pls);
412 
413 	pls->priv->cmb_search = gtk_combo_box_new ();
414 	gtk_box_pack_start (GTK_BOX (hbox), pls->priv->cmb_search, FALSE, FALSE, 0);
415 
416 	btn = gbemol_utils_make_button (NULL, GTK_STOCK_CLEAR);
417 	gtk_button_set_relief (GTK_BUTTON (btn), GTK_RELIEF_NONE);
418 	gtk_tooltips_set_tip (pls->priv->tips, btn, _("Clear search results"), NULL);
419 	gtk_box_pack_start (GTK_BOX (hbox), btn, FALSE, FALSE, 0);
420 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_clear_search_activate), pls);
421 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_clear_search_activate), pls);
422 	pls->priv->btn_search_clear = btn;
423 
424 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
425 
426 	pls->priv->lst_column_search = gtk_list_store_new (2, GTK_TYPE_STRING, G_TYPE_INT);
427 
428 	/* The songs list */
429 	pls->priv->lst_songs = gtk_list_store_new (N_COLUMNS_SONGS,
430 			G_TYPE_STRING,	  /* Lines mode title, markup */
431 			G_TYPE_INT,	  /* Position */
432 			G_TYPE_STRING,    /* Title */
433 			G_TYPE_STRING,    /* Artist */
434 			G_TYPE_STRING,    /* Album */
435 			G_TYPE_STRING,    /* Track */
436 			G_TYPE_STRING,    /* Date */
437 			G_TYPE_STRING,    /* Genre */
438 			G_TYPE_STRING,    /* Composer */
439 			G_TYPE_STRING,    /* Disc */
440 			G_TYPE_STRING,    /* Comment */
441 			G_TYPE_STRING,    /* Time */
442 			G_TYPE_INT,       /* Song id */
443 			G_TYPE_INT,       /* Bold */
444 			G_TYPE_BOOLEAN,   /* Bold set? */
445 			G_TYPE_STRING,	  /* Background color */
446 			G_TYPE_INT,	  /* Background set? */
447 			G_TYPE_STRING,    /* Foreground color */
448 			G_TYPE_INT	  /* Foreground set? */
449 			);
450 
451 
452 	pls->priv->fil_songs = gtk_tree_model_filter_new (GTK_TREE_MODEL (pls->priv->lst_songs), NULL);
453 	gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (pls->priv->fil_songs),
454 			(GtkTreeModelFilterVisibleFunc) gbemol_playlist_is_visible, pls, NULL);
455 	g_object_unref (G_OBJECT (pls->priv->lst_songs));
456 
457 	pls->priv->tv_songs = GTK_TREE_VIEW (gtk_tree_view_new ());
458 	gtk_tree_view_set_model (pls->priv->tv_songs, GTK_TREE_MODEL (pls->priv->fil_songs));
459 	gtk_tree_view_set_rules_hint (pls->priv->tv_songs, TRUE);
460 	gtk_tree_view_set_headers_clickable (pls->priv->tv_songs, TRUE);
461 	g_object_unref (G_OBJECT (pls->priv->fil_songs));
462 	gtk_widget_set_name (GTK_WIDGET (pls->priv->tv_songs), "tv_songs");
463 
464 	scr = gtk_scrolled_window_new (NULL, NULL);
465 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
466 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scr), GTK_SHADOW_ETCHED_IN);
467 	gtk_container_add (GTK_CONTAINER (scr), GTK_WIDGET (pls->priv->tv_songs));
468 
469 	gtk_box_pack_start (GTK_BOX (vbox), scr, TRUE, TRUE, 5);
470 
471 	/* The bottom buttons */
472 	hbox = gtk_hbox_new (FALSE, 5);
473 
474 	btn = gbemol_utils_make_button (NULL, GTK_STOCK_NEW);
475 	gtk_tooltips_set_tip (pls->priv->tips, btn, _("New Playist"), _("Will erase current playlist"));
476 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_new_playlist_clicked), pls);
477 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_new_playlist_clicked), pls);
478 	gtk_box_pack_start (GTK_BOX (hbox), btn, FALSE, FALSE, 5);
479 	pls->priv->btn_new_playlist = btn;
480 
481 	btn = gbemol_utils_make_button (NULL, GTK_STOCK_SAVE);
482 	gtk_tooltips_set_tip (pls->priv->tips, btn, _("Save Playlist"), NULL);
483 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_save_playlist_clicked), pls);
484 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_save_playlist_clicked), pls);
485 	gtk_box_pack_start (GTK_BOX (hbox), btn, FALSE, FALSE, 5);
486 	pls->priv->btn_save_playlist = btn;
487 
488 	btn = gbemol_utils_make_button (NULL, GTK_STOCK_NETWORK);
489 	gtk_tooltips_set_tip (pls->priv->tips, btn, _("Add URL"), NULL);
490 	g_signal_connect (G_OBJECT (btn), "clicked", G_CALLBACK (on_btn_add_url_clicked), pls);
491 	g_signal_connect (G_OBJECT (btn), "activate", G_CALLBACK (on_btn_add_url_clicked), pls);
492 	gtk_box_pack_start (GTK_BOX (hbox), btn, FALSE, FALSE, 5);
493 	pls->priv->btn_add_url = btn;
494 
495 	pls->priv->btn_add = gbemol_utils_make_button (_("_Enqueue"), GTK_STOCK_ADD);
496 	gtk_tooltips_set_tip (pls->priv->tips, pls->priv->btn_add, _("Add playlist to current playlist"), NULL);
497 	g_signal_connect (G_OBJECT (pls->priv->btn_add), "clicked", G_CALLBACK (on_btn_playlist_add_clicked), pls);
498 	g_signal_connect (G_OBJECT (pls->priv->btn_add), "activate", G_CALLBACK (on_btn_playlist_add_clicked), pls);
499 	gtk_box_pack_end (GTK_BOX (hbox), pls->priv->btn_add, FALSE, FALSE, 5);
500 
501 	pls->priv->btn_replace = gbemol_utils_make_button (_("_Play"), GTK_STOCK_MEDIA_PLAY);
502 	gtk_tooltips_set_tip (pls->priv->tips, pls->priv->btn_replace, _("Replace current playlist with this playlist"), NULL);
503 	g_signal_connect (G_OBJECT (pls->priv->btn_replace), "clicked",
504 			G_CALLBACK (on_btn_playlist_replace_clicked), pls);
505 	g_signal_connect (G_OBJECT (pls->priv->btn_replace), "activate",
506 			G_CALLBACK (on_btn_playlist_replace_clicked), pls);
507 	gtk_box_pack_end (GTK_BOX (hbox), pls->priv->btn_replace, FALSE, FALSE, 5);
508 
509 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 5);
510 
511 	gtk_paned_pack2 (GTK_PANED (hpnd), vbox, TRUE, FALSE);
512 
513 	gtk_tree_view_set_search_column (pls->priv->tv_songs, COLUMN_SONGS_TITLE);
514 	pls->priv->sel_songs = gtk_tree_view_get_selection (pls->priv->tv_songs);
515 	gtk_tree_selection_set_mode (pls->priv->sel_songs, GTK_SELECTION_MULTIPLE);
516 
517 	renderer = gtk_cell_renderer_text_new ();
518 	g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL);
519 	column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
520 				"markup", COLUMN_SONGS_MARKUP,
521 				"foreground", COLUMN_SONGS_FG,
522 				"foreground-set", COLUMN_SONGS_FG_SET,
523 				"background", COLUMN_SONGS_BG,
524 				"background-set", COLUMN_SONGS_BG_SET,
525 				NULL);
526 	gtk_tree_view_append_column (GTK_TREE_VIEW (pls->priv->tv_songs), column);
527 	gtk_tree_view_column_set_resizable (column, TRUE);
528 	gtk_tree_view_column_set_reorderable (column, TRUE);
529 	gtk_tree_view_column_set_visible (column, FALSE);
530 
531 	/* The columns for the playlist */
532 	for (i = 1; i < N_COLUMNS; i++) {
533 		renderer = gtk_cell_renderer_text_new ();
534 		column = gtk_tree_view_column_new_with_attributes (column_songs[i], renderer,
535 				"text", i,
536 				"weight", COLUMN_SONGS_BOLD,
537 				"weight-set", COLUMN_SONGS_BOLD_SET,
538 				"foreground", COLUMN_SONGS_FG,
539 				"foreground-set", COLUMN_SONGS_FG_SET,
540 				"background", COLUMN_SONGS_BG,
541 				"background-set", COLUMN_SONGS_BG_SET,
542 				NULL);
543 		gtk_tree_view_append_column (GTK_TREE_VIEW (pls->priv->tv_songs), column);
544 		gtk_tree_view_column_set_resizable (column, TRUE);
545 		gtk_tree_view_column_set_reorderable (column, TRUE);
546 		gtk_tree_view_column_set_clickable (column, TRUE);
547 		g_object_set_data (G_OBJECT (column), "id", GINT_TO_POINTER (i));
548 		g_signal_connect (G_OBJECT (column), "clicked", G_CALLBACK (on_column_clicked), pls);
549 		if (i == COLUMN_SONGS_TIME)
550 			g_object_set (G_OBJECT (renderer), "xalign", 1.0, NULL);
551 
552 		str = g_strdup_printf ("column%d", i);
553 		gtk_tree_view_column_set_visible (column, gbemol_cfg_get_int ("playlist", str));
554 		g_free (str);
555 
556 		/* The search combo box */
557 		if (i != 1)
558 		{
559 			gtk_list_store_append (pls->priv->lst_column_search, &iter);
560 			gtk_list_store_set (pls->priv->lst_column_search, &iter,
561 					0, column_songs[i],
562 					1, i,
563 					-1);
564 		}
565 
566 
567 	}
568 
569 	gtk_combo_box_set_model (GTK_COMBO_BOX (pls->priv->cmb_search), GTK_TREE_MODEL (pls->priv->lst_column_search));
570 	renderer = gtk_cell_renderer_text_new ();
571 	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (pls->priv->cmb_search), renderer, TRUE);
572 	gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (pls->priv->cmb_search), renderer,
573 				"text", 0,
574 				NULL);
575 	g_object_unref (G_OBJECT (pls->priv->lst_column_search));
576 
577 	gbemol_playlist_populate_playlists (pls);
578 	gbemol_playlist_set_mode (pls, gbemol_cfg_get_int ("playlist", "mode"));
579 
580 	if (gbemol_mpd_is_connected (pls->priv->mpd))
581 		gbemol_playlist_bold_song (pls, pls->priv->mpd->status->songid);
582 
583 	gtk_combo_box_set_active (GTK_COMBO_BOX (pls->priv->cmb_search), gbemol_cfg_get_int ("playlist", "cmb_search"));
584 	/* Signal connecting */
585 	g_signal_connect (G_OBJECT (pls->priv->sel_playlists),
586 			"changed",
587 			G_CALLBACK (on_sel_playlists_changed),
588 			pls);
589 	g_signal_connect (G_OBJECT (pls->priv->tv_playlists),
590 			"key-press-event",
591 			G_CALLBACK (on_tvw_playlists_key_press_event),
592 			pls);
593 	g_signal_connect (G_OBJECT (pls->priv->tv_playlists),
594 			"button-press-event",
595 			G_CALLBACK (on_tvw_playlists_button_press_event),
596 			pls);
597 	g_signal_connect (G_OBJECT (pls->priv->tv_songs),
598 			"key-press-event",
599 			G_CALLBACK (on_tvw_songs_key_press_event),
600 			pls);
601 	g_signal_connect (G_OBJECT (pls->priv->tv_songs),
602 			"button-press-event",
603 			G_CALLBACK (on_tvw_songs_button_press_event),
604 			pls);
605 
606 	gtk_widget_show_all (GTK_WIDGET (pls));
607 	gtk_widget_hide (pls->priv->btn_add);
608 	gtk_widget_hide (pls->priv->btn_replace);
609 
610 	return pls;
611 }
612 
gbemol_playlist_set_sensitive(GbemolPlaylist * pls,gboolean sensitive)613 void gbemol_playlist_set_sensitive (GbemolPlaylist* pls, gboolean sensitive)
614 {
615 	if (sensitive)
616 	{
617 		gbemol_playlist_update_songs (pls);
618 		gbemol_playlist_populate_playlists (pls);
619 	}
620 	else
621 	{
622 		gtk_list_store_clear (pls->priv->lst_playlists);
623 		gtk_list_store_clear (pls->priv->lst_songs);
624 	}
625 
626 	gtk_widget_set_sensitive (GTK_WIDGET (pls->priv->tv_playlists), sensitive);
627 	gtk_widget_set_sensitive (GTK_WIDGET (pls->priv->tv_songs), sensitive);
628 	gtk_widget_set_sensitive (pls->priv->cmb_search, sensitive);
629 	gtk_widget_set_sensitive (pls->priv->ent_search, sensitive);
630 	gtk_widget_set_sensitive (pls->priv->btn_add, sensitive);
631 	gtk_widget_set_sensitive (pls->priv->btn_replace, sensitive);
632 	gtk_widget_set_sensitive (pls->priv->btn_new_playlist, sensitive);
633 	gtk_widget_set_sensitive (pls->priv->btn_save_playlist, sensitive);
634 	gtk_widget_set_sensitive (pls->priv->btn_search_clear, sensitive);
635 }
636 
637 /* Return TRUE if the current playlist is selected */
638 gboolean
gbemol_playlist_current_is_selected(GbemolPlaylist * pls)639 gbemol_playlist_current_is_selected (GbemolPlaylist* pls)
640 {
641 	GtkTreeIter iter;
642 	gboolean current = FALSE;
643 	GtkTreeModel* mdl;
644 
645 	if (gtk_tree_selection_get_selected (pls->priv->sel_playlists, &mdl, &iter))
646 		gtk_tree_model_get (mdl, &iter, COLUMN_PLAYLISTS_CURRENT, &current, -1);
647 
648 	return current;
649 }
650 
651 
gbemol_playlist_clear_all(GbemolPlaylist * pls)652 void gbemol_playlist_clear_all (GbemolPlaylist* pls)
653 {
654 	gtk_list_store_clear (pls->priv->lst_playlists);
655 	gtk_list_store_clear (pls->priv->lst_songs);
656 }
657 
gbemol_playlist_set_mode(GbemolPlaylist * pls,GbemolPlaylistMode mode)658 void gbemol_playlist_set_mode (GbemolPlaylist* pls, GbemolPlaylistMode mode)
659 {
660 	gint i;
661 	GtkTreeViewColumn* column;
662 	gchar *str;
663 
664 	switch (mode)
665 	{
666 		case GBEMOL_PLAYLIST_MODE_COLUMNS:
667 			for (i = 1; i < N_COLUMNS; i++)
668 			{
669 				str = g_strdup_printf ("column%d", i);
670 				column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), i);
671 				gtk_tree_view_column_set_visible (column, gbemol_cfg_get_int ("playlist", str));
672 				g_free (str);
673 			}
674 			gtk_widget_show (pls->priv->mnu_item_columns);
675 			gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pls->priv->tv_songs), TRUE);
676 			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (pls->priv->mnu_item_mode[mode]), TRUE);
677 			break;
678 
679 		case GBEMOL_PLAYLIST_MODE_LINES:
680 			for (i = 0; i < N_COLUMNS; i++)
681 			{
682 				column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), i);
683 				gtk_tree_view_column_set_visible (column, FALSE);
684 			}
685 			/* Only two columns needed */
686 			column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), COLUMN_SONGS_MARKUP);
687 			gtk_tree_view_column_set_visible (column, TRUE);
688 
689 			column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), COLUMN_SONGS_TIME);
690 			gtk_tree_view_column_set_visible (column, TRUE);
691 
692 			gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (pls->priv->tv_songs), FALSE);
693 			gtk_widget_hide (pls->priv->mnu_item_columns);
694 			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (pls->priv->mnu_item_mode[mode]), TRUE);
695 			break;
696 		default:
697 			break;
698 	}
699 
700 	gbemol_cfg_set_int ("playlist", "mode", mode);
701 	pls->priv->mode = mode;
702 
703 	gbemol_playlist_update_songs (pls);
704 }
705 
706 
gbemol_playlist_get_selected(GtkTreeView * view)707 static GList* gbemol_playlist_get_selected (GtkTreeView* view)
708 {
709 	GtkTreeModel *model;
710 	GtkTreeSelection *select;
711 	GList *rows = NULL;
712 
713 	select = gtk_tree_view_get_selection (view);
714 	if (gtk_tree_selection_count_selected_rows (select) > 0)
715 	{
716 		rows = gtk_tree_selection_get_selected_rows (select, &model);
717 		return rows;
718 	}
719 	else
720 		return NULL;
721 }
722 
gbemol_playlist_columns_dialog(GbemolPlaylist * pls)723 void gbemol_playlist_columns_dialog (GbemolPlaylist* pls)
724 {
725 	GtkWidget *dlg, *vbox, *chk[N_COLUMNS];
726 	GtkTreeViewColumn* column;
727 	gchar *str;
728 	int i;
729 
730 	if (pls->priv->mode == GBEMOL_PLAYLIST_MODE_LINES)
731 		return;
732 
733 	dlg = gtk_dialog_new_with_buttons (_("Playlist Columns"),
734 			NULL,
735 			GTK_DIALOG_DESTROY_WITH_PARENT,
736 			GTK_STOCK_OK,
737 			GTK_RESPONSE_ACCEPT,
738 			GTK_STOCK_CANCEL,
739 			GTK_RESPONSE_REJECT,
740 			NULL);
741 
742 	vbox = gtk_vbox_new (TRUE, 5);
743 
744 	for (i = 0; i < (N_COLUMNS-1); i++)
745 	{
746 		column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), i+1);
747 		chk[i+1] = gtk_check_button_new_with_label (column_songs[i+1]);
748 		gtk_box_pack_start (GTK_BOX (vbox), chk[i+1], FALSE, FALSE, 0);
749 		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(chk[i+1]),
750 				gtk_tree_view_column_get_visible (column));
751 	}
752 
753 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, TRUE, TRUE, 5);
754 	gtk_widget_show_all (vbox);
755 
756 	if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT)
757 	{
758 		for (i = 0; i < (N_COLUMNS-1); i++)
759 		{
760 			column = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), i+1);
761 			gtk_tree_view_column_set_visible (column,
762 					gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(chk[i+1])));
763 			/* Save the config */
764 			str = g_strdup_printf ("column%d", i+1);
765 			gbemol_cfg_set_int ("playlist", str,
766 					gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chk[i+1])));
767 			g_free (str);
768 		}
769 	}
770 
771 	gtk_widget_destroy (dlg);
772 }
773 
774 
gbemol_playlist_free_selected(GList * l)775 static void gbemol_playlist_free_selected (GList* l)
776 {
777         if (l)
778         {
779                 g_list_foreach (l, (GFunc) gtk_tree_path_free, NULL);
780                 g_list_free (l);
781         }
782 }
783 
gbemol_playlist_append_song(GbemolPlaylist * pls,mpd_Song * song)784 void gbemol_playlist_append_song (GbemolPlaylist* pls, mpd_Song* song)
785 {
786 	GtkTreeIter iter;
787 	gchar* str, *artist, *time;
788 
789 	if (song->time == MPD_SONG_NO_TIME)
790 		time = g_strdup ("--:--");
791 	else
792 		time = g_strdup_printf ("%02d:%02d", song->time / 60, song->time % 60);
793 
794 	if (gbemol_mpd_song_is_stream (song))
795 		artist = song->name;
796 	else
797 		artist = song->artist;
798 
799 	gtk_list_store_append (pls->priv->lst_songs, &iter);
800 	gtk_list_store_set (pls->priv->lst_songs, &iter,
801 			COLUMN_SONGS_TIME, time,
802 			COLUMN_SONGS_ID, song->id,
803 			-1);
804 	g_free (time);
805 
806 	switch (pls->priv->mode)
807 	{
808 		case GBEMOL_PLAYLIST_MODE_COLUMNS:
809 			gtk_list_store_set (pls->priv->lst_songs, &iter,
810 					COLUMN_SONGS_ARTIST, artist,
811 					COLUMN_SONGS_TITLE, song->title,
812 					COLUMN_SONGS_ALBUM, song->album,
813 					COLUMN_SONGS_TRACK, song->track,
814 					COLUMN_SONGS_DATE, song->date,
815 					COLUMN_SONGS_GENRE, song->genre,
816 					COLUMN_SONGS_COMPOSER, song->composer,
817 					COLUMN_SONGS_DISC, song->disc,
818 					COLUMN_SONGS_COMMENT, song->comment,
819 					COLUMN_SONGS_POS, song->pos + 1,
820 					-1);
821 			break;
822 		case GBEMOL_PLAYLIST_MODE_LINES:
823 			if (!gbemol_mpd_song_is_stream (song))
824 				str = g_markup_printf_escaped
825 					("<span weight=\"ultrabold\" size=\"medium\">%s</span>\n"
826 					 "<span size=\"small\">%s</span> - <span size=\"small\">%s</span>",
827 					 song->title, song->artist, song->album);
828 			else
829 				str = g_markup_printf_escaped
830 					("<span weight=\"ultrabold\" size=\"medium\">%s</span>\n"
831 					 "<span size=\"small\">%s</span>",
832 					 song->title, artist);
833 			gtk_list_store_set (pls->priv->lst_songs, &iter,
834 					COLUMN_SONGS_MARKUP, str,
835 					COLUMN_SONGS_ARTIST, artist,
836 					COLUMN_SONGS_TITLE, song->title,
837 					COLUMN_SONGS_ALBUM, song->album,
838 					COLUMN_SONGS_TRACK, song->track,
839 					COLUMN_SONGS_DATE, song->date,
840 					COLUMN_SONGS_GENRE, song->genre,
841 					COLUMN_SONGS_COMPOSER, song->composer,
842 					COLUMN_SONGS_DISC, song->disc,
843 					COLUMN_SONGS_COMMENT, song->comment,
844 					COLUMN_SONGS_POS, song->pos + 1,
845 				       	-1);
846 			g_free (str);
847 			break;
848 		default:
849 			break;
850 	}
851 }
852 
gbemol_playlist_populate_songs(GbemolPlaylist * pls,GList * songs)853 void gbemol_playlist_populate_songs (GbemolPlaylist *pls, GList* songs)
854 {
855 	gint total_time=0, total_songs=0;
856 
857 	gtk_list_store_clear (pls->priv->lst_songs);
858 	if (!songs)
859 		return;
860 	do
861 	{
862 		total_time += ((GbemolMpdSong *)songs->data)->time;
863 		total_songs++;
864 		gbemol_playlist_append_song (pls, (GbemolMpdSong *)songs->data);
865 	} while ((songs = g_list_next(songs)));
866 
867 }
868 
gbemol_playlist_populate_playlists(GbemolPlaylist * pls)869 void gbemol_playlist_populate_playlists (GbemolPlaylist* pls)
870 {
871 	GList* playlists;
872 	GtkTreeIter iter;
873 
874 	gtk_list_store_clear (pls->priv->lst_playlists);
875 
876 	gtk_list_store_append (pls->priv->lst_playlists, &iter);
877 	gtk_list_store_set (pls->priv->lst_playlists, &iter,
878 				COLUMN_PLAYLISTS_TITLE, _("Current Playlist"),
879 				COLUMN_PLAYLISTS_ICON, "gtk-justify-fill",
880 				COLUMN_PLAYLISTS_CURRENT, TRUE,
881 				COLUMN_PLAYLISTS_BOLD, PANGO_WEIGHT_ULTRABOLD,
882 				COLUMN_PLAYLISTS_BOLD_SET, TRUE,
883 				-1);
884 
885 	gtk_tree_selection_select_iter (pls->priv->sel_playlists, &iter);
886 
887 	playlists = gbemol_mpd_get_playlists (pls->priv->mpd);
888 	if (!playlists)
889 		return;
890 
891 	do
892 	{
893 		gtk_list_store_append (pls->priv->lst_playlists, &iter);
894 		gtk_list_store_set (pls->priv->lst_playlists, &iter,
895 				COLUMN_PLAYLISTS_TITLE, (gchar *)playlists->data,
896 				COLUMN_PLAYLISTS_CURRENT, FALSE,
897 				COLUMN_PLAYLISTS_ICON, "gtk-edit",
898 				-1);
899 	} while ((playlists = g_list_next(playlists)));
900 
901 	gbemol_utils_char_list_free (playlists);
902 }
903 
904 void
gbemol_playlist_bold_song(GbemolPlaylist * pls,gint song_id)905 gbemol_playlist_bold_song (GbemolPlaylist *pls, gint song_id)
906 {
907 	gboolean oro, bold;
908 	GtkTreeIter iter;
909 	gint id;
910 	GtkTreePath* path;
911 	GtkListStore* lst = pls->priv->lst_songs;
912 
913 	if (song_id < 0)
914 		return;
915 
916 	oro = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lst), &iter);
917 	while (oro)
918 	{
919 		gtk_tree_model_get (GTK_TREE_MODEL (lst), &iter,
920 				COLUMN_SONGS_ID, &id,
921 				-1);
922 
923 		gtk_tree_model_get (GTK_TREE_MODEL (lst), &iter,
924 				COLUMN_SONGS_BOLD_SET, &bold,
925 				-1);
926 
927 		if (bold)
928 			gtk_list_store_set (lst, &iter,
929 					COLUMN_SONGS_BOLD, PANGO_WEIGHT_NORMAL,
930 					COLUMN_SONGS_BOLD_SET, FALSE,
931 					COLUMN_SONGS_FG, "black",
932 					COLUMN_SONGS_FG_SET, FALSE,
933 					COLUMN_SONGS_BG, "white",
934 					COLUMN_SONGS_FG_SET, FALSE,
935 					-1);
936 
937 		if (id == song_id)
938 		{
939 			gtk_list_store_set (lst, &iter,
940 					COLUMN_SONGS_BOLD, PANGO_WEIGHT_ULTRABOLD,
941 					COLUMN_SONGS_BOLD_SET, TRUE,
942 					COLUMN_SONGS_FG, "white",
943 					COLUMN_SONGS_FG_SET, TRUE,
944 					COLUMN_SONGS_BG, "black",
945 					COLUMN_SONGS_FG_SET, TRUE,
946 					-1);
947 			path = gtk_tree_model_get_path (GTK_TREE_MODEL (lst), &iter);
948 			gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (pls->priv->tv_songs), path, NULL, TRUE, 0.5, 0.5);
949 			gtk_tree_path_free (path);
950 		}
951 		oro = gtk_tree_model_iter_next (GTK_TREE_MODEL (lst), &iter);
952 	}
953 }
954 
955 
gbemol_playlist_update_songs(GbemolPlaylist * pls)956 void gbemol_playlist_update_songs (GbemolPlaylist* pls)
957 {
958 	GList* songs;
959 
960 	songs = gbemol_mpd_playlist_get_songs (pls->priv->mpd);
961 	gbemol_playlist_populate_songs (pls, songs);
962 	if (pls->priv->mpd->status)
963 		gbemol_playlist_bold_song (pls, pls->priv->mpd->status->songid);
964 
965 	gbemol_utils_song_list_free (songs);
966 	gtk_tree_view_columns_autosize (GTK_TREE_VIEW (pls->priv->tv_songs));
967 }
968 
969 
gbemol_playlist_remove_selected_songs(GbemolPlaylist * pls)970 void gbemol_playlist_remove_selected_songs (GbemolPlaylist *pls)
971 {
972 	GList *l;
973 	GtkTreeIter iter;
974 	gint id;
975 	GtkListStore* lst = pls->priv->lst_songs;
976 	GbemolMpd* mpd = pls->priv->mpd;
977 
978 	l = gbemol_playlist_get_selected (pls->priv->tv_songs);
979 
980 	if (l)
981 	{
982 		gbemol_mpd_queue_start (mpd);
983 		do
984 		{
985 			gtk_tree_model_get_iter (GTK_TREE_MODEL (lst), &iter, (GtkTreePath *) l->data);
986 			gtk_tree_model_get (GTK_TREE_MODEL (lst), &iter, COLUMN_SONGS_ID, &id, -1);
987 			gbemol_mpd_queue_remove_song (mpd, id);
988 		} while ((l = g_list_next (l)));
989 
990 		gbemol_mpd_queue_finish (mpd);
991 		gbemol_playlist_free_selected (l);
992 	}
993 
994 	gbemol_playlist_update_songs (pls);
995 }
996 
gbemol_playlist_play_selected(GbemolPlaylist * pls)997 void gbemol_playlist_play_selected (GbemolPlaylist *pls)
998 {
999 	GtkTreeIter iter;
1000 	gint id;
1001 	GList* l;
1002 
1003 	l = gbemol_playlist_get_selected (pls->priv->tv_songs);
1004 
1005 	if (l)
1006 	{
1007 		gtk_tree_model_get_iter (GTK_TREE_MODEL (pls->priv->fil_songs), &iter, (GtkTreePath *) l->data);
1008 		gtk_tree_model_get (GTK_TREE_MODEL (pls->priv->fil_songs), &iter, COLUMN_SONGS_ID, &id, -1);
1009 
1010 		gbemol_mpd_player_play_song_by_id (pls->priv->mpd, id);
1011 		gbemol_playlist_free_selected (l);
1012 	}
1013 }
1014 
gbemol_playlist_play_last_song(GbemolPlaylist * pls)1015 void gbemol_playlist_play_last_song (GbemolPlaylist *pls)
1016 {
1017 	gbemol_mpd_player_play_song_by_pos (pls->priv->mpd, pls->priv->mpd->status->playlistLength - 1);
1018 }
1019 
1020 
gbemol_playlist_remove_selected_playlist(GbemolPlaylist * pls)1021 void gbemol_playlist_remove_selected_playlist (GbemolPlaylist *pls)
1022 {
1023 	GtkTreeIter iter;
1024 	gchar *str;
1025 	gboolean oro;
1026 	GtkTreeModel* model;
1027 
1028 	if (gtk_tree_selection_get_selected (pls->priv->sel_playlists, &model, &iter))
1029         {
1030 		gtk_tree_model_get (model, &iter,
1031 				COLUMN_PLAYLISTS_CURRENT, &oro, -1);
1032 
1033 		if (!oro)
1034 		{
1035 			gtk_tree_model_get (model, &iter,
1036 					COLUMN_PLAYLISTS_TITLE, &str, -1);
1037 			gbemol_mpd_delete_playlist (pls->priv->mpd, str);
1038 			g_free (str);
1039 		}
1040 		gbemol_playlist_populate_playlists (pls);
1041 	}
1042 }
1043 
gbemol_playlist_load_selected_playlist(GbemolPlaylist * pls)1044 void gbemol_playlist_load_selected_playlist (GbemolPlaylist *pls)
1045 {
1046 	GtkTreeIter iter;
1047 	gchar* str;
1048 	GtkTreeModel* model;
1049 
1050 	if (gtk_tree_selection_get_selected (pls->priv->sel_playlists, &model, &iter))
1051         {
1052 		gtk_tree_model_get (model, &iter, COLUMN_PLAYLISTS_TITLE, &str, -1);
1053 		gbemol_mpd_load_playlist (pls->priv->mpd, str);
1054 		g_free (str);
1055 	}
1056 }
1057 
gbemol_playlist_save_dialog(GbemolPlaylist * pls)1058 gchar* gbemol_playlist_save_dialog (GbemolPlaylist *pls)
1059 {
1060 	GtkWidget* dialog;
1061 	GtkWidget* cmb_entry, *lbl;
1062 	GtkListStore* model;
1063 	gint oro;
1064 	gchar* str;
1065 	GtkTreeIter iter;
1066 	GList *l;
1067 
1068 	model = gtk_list_store_new (1, G_TYPE_STRING);
1069 
1070 	dialog = gtk_dialog_new_with_buttons (_("Save Playlist"),
1071 			NULL,
1072 			GTK_DIALOG_DESTROY_WITH_PARENT,
1073 			GTK_STOCK_OK,
1074 			GTK_RESPONSE_ACCEPT,
1075 			GTK_STOCK_CANCEL,
1076 			GTK_RESPONSE_REJECT,
1077 			NULL);
1078 
1079 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
1080 
1081 	lbl = gtk_label_new (_("Select playlist to overwrite or create a new one"));
1082 	cmb_entry = gtk_combo_box_entry_new_with_model (GTK_TREE_MODEL (model), 0);
1083 
1084 	l = gbemol_mpd_get_playlists (pls->priv->mpd);
1085 
1086 	if (l)
1087 	{
1088 		do
1089 		{
1090 			gtk_list_store_append (model, &iter);
1091 			gtk_list_store_set (model, &iter, 0, (gchar *)l->data, -1);
1092 		} while ((l = g_list_next(l)));
1093 
1094 		gbemol_utils_char_list_free (l);
1095 	}
1096 
1097 	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lbl, TRUE, TRUE, 5);
1098 	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), cmb_entry,
1099 			FALSE, FALSE, 0);
1100 	gtk_widget_show_all (GTK_DIALOG(dialog)->vbox);
1101 
1102 	oro = gtk_dialog_run (GTK_DIALOG (dialog));
1103 
1104 	if (oro == GTK_RESPONSE_ACCEPT)
1105 		str = g_strdup (gtk_combo_box_get_active_text (GTK_COMBO_BOX (cmb_entry)));
1106 	else
1107 		str = NULL;
1108 
1109 	gtk_widget_destroy (dialog);
1110 
1111 	return str;
1112 
1113 }
gbemol_playlist_add_url_dialog(GbemolPlaylist * pls)1114 gchar* gbemol_playlist_add_url_dialog (GbemolPlaylist *pls)
1115 {
1116 	GtkWidget* dialog;
1117 	GtkWidget* entry, *lbl;
1118 	gchar* str;
1119 	gint oro;
1120 
1121 	dialog = gtk_dialog_new_with_buttons (_("Add URL to playlist"),
1122 			NULL,
1123 			GTK_DIALOG_DESTROY_WITH_PARENT,
1124 			GTK_STOCK_OK,
1125 			GTK_RESPONSE_ACCEPT,
1126 			GTK_STOCK_CANCEL,
1127 			GTK_RESPONSE_REJECT,
1128 			NULL);
1129 
1130 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
1131 
1132 	lbl = gtk_label_new (_("Stream URL:"));
1133 	entry = gtk_entry_new ();
1134 
1135 	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lbl, TRUE, TRUE, 5);
1136 	gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE, FALSE, 0);
1137 	gtk_widget_show_all (GTK_DIALOG(dialog)->vbox);
1138 
1139 	oro = gtk_dialog_run (GTK_DIALOG (dialog));
1140 
1141 	if (oro == GTK_RESPONSE_ACCEPT)
1142 		str = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
1143 	else
1144 		str = NULL;
1145 
1146 	gtk_widget_destroy (dialog);
1147 
1148 	return str;
1149 }
1150 
1151 static void
on_sel_playlists_changed(GtkTreeSelection * select,GbemolPlaylist * pls)1152 on_sel_playlists_changed (GtkTreeSelection *select, GbemolPlaylist* pls)
1153 {
1154 	GtkTreeIter iter;
1155 	GtkTreeViewColumn* column;
1156 	GtkTreeModel* model;
1157         gchar *str;
1158 	GList* songs = NULL;
1159 
1160 	column = gtk_tree_view_get_column (pls->priv->tv_songs, COLUMN_SONGS_POS);
1161 
1162 	if (gbemol_playlist_current_is_selected (pls))
1163 	{
1164 		gtk_widget_hide (pls->priv->btn_add);
1165 		gtk_widget_hide (pls->priv->btn_replace);
1166 		gtk_widget_show (pls->priv->btn_save_playlist);
1167 		gtk_widget_show (pls->priv->btn_new_playlist);
1168 		gtk_widget_show (pls->priv->btn_add_url);
1169 		gbemol_playlist_update_songs (pls);
1170 	}
1171 	else
1172 	{
1173 		if (gtk_tree_selection_get_selected (select, &model, &iter))
1174 		{
1175 			gtk_tree_model_get (model, &iter,
1176 					COLUMN_PLAYLISTS_TITLE, &str,
1177 					-1);
1178 			songs = gbemol_mpd_preview_playlist (pls->priv->mpd, str);
1179 			g_free (str);
1180 
1181 			gtk_widget_show (pls->priv->btn_add);
1182 			gtk_widget_show (pls->priv->btn_replace);
1183 			gtk_widget_hide (pls->priv->btn_save_playlist);
1184 			gtk_widget_hide (pls->priv->btn_new_playlist);
1185 			gtk_widget_hide (pls->priv->btn_add_url);
1186 
1187 			gtk_tree_view_column_set_visible (column, FALSE);
1188 
1189 			gbemol_playlist_populate_songs (pls, songs);
1190 			gbemol_utils_song_list_free (songs);
1191 		}
1192 	}
1193 
1194 
1195 }
1196 
1197 static gboolean
on_tvw_playlists_key_press_event(GtkWidget * w,GdkEventKey * event,GbemolPlaylist * pls)1198 on_tvw_playlists_key_press_event (GtkWidget *w, GdkEventKey *event, GbemolPlaylist* pls)
1199 {
1200 	if (event->keyval == GDK_Delete)
1201 	{
1202 		gbemol_playlist_remove_selected_playlist (pls);
1203 		return TRUE;
1204 	}
1205 
1206 	return FALSE;
1207 }
1208 
1209 static gint
on_tvw_playlists_button_press_event(GtkWidget * w,GdkEventButton * event,GbemolPlaylist * pls)1210 on_tvw_playlists_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolPlaylist* pls)
1211 {
1212 	if (gbemol_playlist_current_is_selected (pls))
1213 		return FALSE;
1214 
1215 	if (event->type == GDK_2BUTTON_PRESS)
1216 		gbemol_playlist_load_selected_playlist (pls);
1217 
1218 	if (event->type == GDK_BUTTON_PRESS)
1219 		if (event->button == 3)
1220 		{
1221 			gtk_menu_popup (GTK_MENU(pls->priv->mnu_playlists),
1222 						NULL, NULL, NULL, NULL,
1223 					       	event->button, event->time);
1224 			return TRUE;
1225 		}
1226 
1227 	return FALSE;
1228 
1229 }
1230 
1231 static gboolean
on_tvw_songs_key_press_event(GtkWidget * w,GdkEventKey * event,GbemolPlaylist * pls)1232 on_tvw_songs_key_press_event (GtkWidget* w, GdkEventKey* event, GbemolPlaylist* pls)
1233 {
1234 	if (event->keyval == GDK_Delete)
1235 	{
1236 		if (gbemol_playlist_current_is_selected (pls))
1237 			gbemol_playlist_remove_selected_songs (pls);
1238 		return TRUE;
1239 	}
1240 
1241 	return FALSE;
1242 }
1243 
1244 static gboolean
on_tvw_songs_button_press_event(GtkWidget * w,GdkEventButton * event,GbemolPlaylist * pls)1245 on_tvw_songs_button_press_event (GtkWidget *w, GdkEventButton *event, GbemolPlaylist* pls)
1246 {
1247 	if (event->type == GDK_BUTTON_PRESS)
1248 		if (event->button == 3)
1249 		{
1250 			if (gbemol_playlist_current_is_selected (pls))
1251 				gtk_menu_popup (GTK_MENU (pls->priv->mnu_songs),
1252 					NULL, NULL, NULL, NULL,
1253 					event->button, event->time);
1254 			return TRUE;
1255 		}
1256 
1257 	if (event->type == GDK_2BUTTON_PRESS)
1258 		gbemol_playlist_play_selected (pls);
1259 
1260 	return FALSE;
1261 }
1262 
1263 static void
on_btn_new_playlist_clicked(GtkButton * button,GbemolPlaylist * pls)1264 on_btn_new_playlist_clicked (GtkButton *button, GbemolPlaylist* pls)
1265 {
1266 	gbemol_mpd_player_stop (pls->priv->mpd);
1267 	gbemol_mpd_playlist_clear (pls->priv->mpd);
1268 }
1269 
1270 static void
on_btn_save_playlist_clicked(GtkButton * button,GbemolPlaylist * pls)1271 on_btn_save_playlist_clicked (GtkButton *button, GbemolPlaylist* pls)
1272 {
1273 	gchar* path;
1274 
1275 	path = gbemol_playlist_save_dialog (pls);
1276 
1277 	if (path != NULL)
1278 	{
1279 		gbemol_mpd_save_playlist (pls->priv->mpd, path);
1280 		gbemol_playlist_populate_playlists (pls);
1281 		g_free (path);
1282 	}
1283 }
1284 
1285 static void
on_btn_playlist_add_clicked(GtkWidget * b,GbemolPlaylist * pls)1286 on_btn_playlist_add_clicked (GtkWidget* b, GbemolPlaylist* pls)
1287 {
1288 
1289 	GtkTreeIter iter;
1290 	gchar* str;
1291 	GtkTreeModel* mdl;
1292 
1293 	if (gtk_tree_selection_get_selected (pls->priv->sel_playlists, &mdl, &iter))
1294         {
1295 		gtk_tree_model_get (mdl, &iter, COLUMN_PLAYLISTS_TITLE, &str, -1);
1296 		gbemol_mpd_load_playlist (pls->priv->mpd, str);
1297 		g_free (str);
1298 	}
1299 }
1300 
1301 static void
on_btn_playlist_replace_clicked(GtkWidget * b,GbemolPlaylist * pls)1302 on_btn_playlist_replace_clicked (GtkWidget* b, GbemolPlaylist* pls)
1303 {
1304 	GtkTreeIter iter;
1305 	gchar* str;
1306 	GtkTreeModel* mdl;
1307 
1308 	if (gtk_tree_selection_get_selected (pls->priv->sel_playlists, &mdl, &iter))
1309         {
1310 		gtk_tree_model_get (mdl, &iter, COLUMN_PLAYLISTS_TITLE, &str, -1);
1311 		gbemol_mpd_playlist_clear (pls->priv->mpd);
1312 		gbemol_mpd_load_playlist (pls->priv->mpd, str);
1313 		g_free (str);
1314 	}
1315 
1316 	gbemol_mpd_player_play_song_by_pos (pls->priv->mpd, 0);
1317 }
1318 
1319 static void
on_mnu_playlist_remove_activate(GtkWidget * m,GbemolPlaylist * pls)1320 on_mnu_playlist_remove_activate (GtkWidget* m, GbemolPlaylist* pls)
1321 {
1322 	gbemol_playlist_remove_selected_playlist (pls);
1323 }
1324 
1325 static void
on_mnu_clear_activate(GtkWidget * w,GbemolPlaylist * pls)1326 on_mnu_clear_activate (GtkWidget* w, GbemolPlaylist* pls)
1327 {
1328 	gbemol_mpd_playlist_clear (pls->priv->mpd);
1329 }
1330 
1331 static void
on_mnu_shuffle_activate(GtkWidget * w,GbemolPlaylist * pls)1332 on_mnu_shuffle_activate (GtkWidget* w, GbemolPlaylist* pls)
1333 {
1334 	gbemol_mpd_playlist_shuffle (pls->priv->mpd);
1335 }
1336 
1337 static void
on_mnu_column_activate(GtkWidget * w,GbemolPlaylist * pls)1338 on_mnu_column_activate (GtkWidget* w, GbemolPlaylist* pls)
1339 {
1340 	gbemol_playlist_columns_dialog (pls);
1341 }
1342 
on_column_clicked(GtkTreeViewColumn * column,GbemolPlaylist * pls)1343 static void on_column_clicked (GtkTreeViewColumn* column, GbemolPlaylist* pls)
1344 {
1345 	int old_id, new_id;
1346 	GtkSortType old_sort, new_sort;
1347 	GtkTreeViewColumn* c;
1348 
1349 	new_sort = GTK_SORT_ASCENDING;
1350 	new_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (column), "id"));
1351 
1352 	gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (pls->priv->lst_songs), &old_id, &old_sort);
1353 
1354 	/* Same column, reverse order */
1355 	if (old_id == new_id)
1356 		if (old_sort == GTK_SORT_ASCENDING)
1357 			new_sort = GTK_SORT_DESCENDING;
1358 
1359 	gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (pls->priv->lst_songs), new_id, new_sort);
1360 
1361 	c = gtk_tree_view_get_column (GTK_TREE_VIEW (pls->priv->tv_songs), old_id);
1362 	gtk_tree_view_column_set_sort_indicator (c, FALSE);
1363 	gtk_tree_view_column_set_sort_indicator (column, TRUE);
1364 	gtk_tree_view_column_set_sort_order (column, new_sort);
1365 }
1366 
on_mnu_mode_toggled(GtkCheckMenuItem * item,GbemolPlaylist * pls)1367 static void on_mnu_mode_toggled (GtkCheckMenuItem *item, GbemolPlaylist *pls)
1368 {
1369 	if (gtk_check_menu_item_get_active (item))
1370 		gbemol_playlist_set_mode (pls, GPOINTER_TO_INT (g_object_get_data(G_OBJECT (item), "mode")));
1371 }
1372 
1373 static void
on_btn_clear_search_activate(GtkButton * btn,GbemolPlaylist * pls)1374 on_btn_clear_search_activate (GtkButton* btn, GbemolPlaylist *pls)
1375 {
1376 	gtk_entry_set_text (GTK_ENTRY (pls->priv->ent_search), "");
1377 }
1378 
1379 static gboolean
gbemol_playlist_is_visible(GtkTreeModel * model,GtkTreeIter * iter,GbemolPlaylist * pls)1380 gbemol_playlist_is_visible (GtkTreeModel* model, GtkTreeIter *iter, GbemolPlaylist* pls)
1381 {
1382 	gchar *str1, *list_str = NULL, *search_str = NULL;
1383 	const gchar *str2, *str3;
1384 	GtkTreeIter cmb_iter;
1385 	gint column;
1386 	gboolean result = TRUE;
1387 
1388 	if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (pls->priv->cmb_search), &cmb_iter))
1389 		return TRUE;
1390 
1391 	gtk_tree_model_get (GTK_TREE_MODEL (pls->priv->lst_column_search), &cmb_iter, 1, &column, -1);
1392 	gtk_tree_model_get (model, iter, column, &str1, -1);
1393 
1394 	str2 = gtk_entry_get_text (GTK_ENTRY (pls->priv->ent_search));
1395 	/* Case sensitive search? */
1396 	if (!gbemol_cfg_get_int ("playlist", "case-sensitive"))
1397 	{
1398 		if (str1)
1399 			list_str = g_utf8_casefold (str1, -1);
1400 		if (str2)
1401 			search_str = g_utf8_casefold (str2, -1);
1402 	}
1403 	else
1404 	{
1405 		list_str = str1;
1406 		search_str = g_strdup (str2);
1407 	}
1408 
1409 	/* Const strs for comparing */
1410 	str2 = list_str;
1411 	str3 = search_str;
1412 
1413 	if (str2 && str3)
1414 		if (!g_strrstr (list_str, search_str))
1415 			result = FALSE;
1416 
1417 	if (str1 != list_str)
1418 		g_free (list_str);
1419 	g_free (str1);
1420 	g_free (search_str);
1421 
1422 	return result;
1423 }
1424 
1425 static void
on_mnu_remove_activate(GtkWidget * w,GbemolPlaylist * pls)1426 on_mnu_remove_activate (GtkWidget* w, GbemolPlaylist *pls)
1427 {
1428 	gbemol_playlist_remove_selected_songs (pls);
1429 }
1430 
1431 static void
on_ent_search_changed(GtkEditable * entry,GbemolPlaylist * pls)1432 on_ent_search_changed (GtkEditable* entry, GbemolPlaylist *pls)
1433 {
1434 	gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (pls->priv->fil_songs));
1435 }
1436 
1437 static void
on_btn_add_url_clicked(GtkButton * btn,GbemolPlaylist * pls)1438 on_btn_add_url_clicked (GtkButton* btn, GbemolPlaylist *pls)
1439 {
1440 	gchar *url;
1441 
1442 	url = gbemol_playlist_add_url_dialog (pls);
1443 	if (url)
1444 		gbemol_mpd_playlist_add_song (pls->priv->mpd, url);
1445 	g_free (url);
1446 }
1447 
1448 
1449