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, ¤t, -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