First context item equals double click
[gmpc.git] / src / browsers / playlist3-current-playlist-browser.c
blobb7ee581b73f545a599a8c884aae6b4b333e4758c
1 /*
2 *Copyright (C) 2004-2007 Qball Cow <qball@sarine.nl>
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.
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.
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.
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glade/glade.h>
25 #include <config.h>
26 #include <regex.h>
28 #include "plugin.h"
30 #include "main.h"
31 #include "misc.h"
32 #include "playlist3.h"
33 #include "playlist3-current-playlist-browser.h"
34 #include "config1.h"
35 #include "TreeSearchWidget.h"
36 #include "gmpc-mpddata-model.h"
37 #include "gmpc-mpddata-model-playlist.h"
38 #include "gmpc-mpddata-treeview.h"
39 #include "eggcolumnchooserdialog.h"
40 #include "sexy-icon-entry.h"
42 static int pl3_current_playlist_browser_button_press_event(GtkTreeView *tree, GdkEventButton *event);
43 static void pl3_current_playlist_browser_scroll_to_current_song(void);
44 static void pl3_current_playlist_browser_add(GtkWidget *cat_tree);
46 static void pl3_current_playlist_browser_selected(GtkWidget *container);
47 static void pl3_current_playlist_browser_unselected(GtkWidget *container);
49 static int pl3_current_playlist_browser_cat_menu_popup(GtkWidget *menu, int type, GtkWidget *tree, GdkEventButton *event);
52 static void pl3_current_playlist_status_changed(MpdObj *mi, ChangedStatusType what, void *userdata);
53 static int pl3_current_playlist_browser_add_go_menu(GtkWidget *menu);
55 /* just for here */
56 static void pl3_current_playlist_browser_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *col);
57 static int pl3_current_playlist_browser_button_release_event(GtkTreeView *tree, GdkEventButton *event);
58 static int pl3_current_playlist_browser_button_press_event(GtkTreeView *tree, GdkEventButton *event);
59 static int pl3_current_playlist_browser_key_release_event(GtkTreeView *tree, GdkEventKey *event,GtkWidget *entry);
60 static void pl3_current_playlist_browser_show_info(void);
61 static void pl3_current_playlist_save_playlist(void);
62 static void pl3_current_playlist_browser_shuffle_playlist(void);
63 static void pl3_current_playlist_browser_clear_playlist(void);
64 static int pl3_current_playlist_key_press_event(GtkWidget *mw, GdkEventKey *event, int type);
65 static void pl3_current_playlist_connection_changed(MpdObj *mi, int connect, gpointer data);
66 static void pl3_current_playlist_save_myself(void);
67 static void pl3_current_playlist_browser_init(void);
71 GtkTreeModel *playlist = NULL;
72 GtkWidget *pl3_cp_tree = NULL;
73 static gboolean search_keep_open = FALSE;
78 static void pl3_cp_current_song_changed(GmpcMpdDataModelPlaylist *model2,GtkTreePath *path, GtkTreeIter *iter,gpointer data)
80 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_cp_tree));
81 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(model))
83 if(cfg_get_single_value_as_int_with_default(config, "playlist", "st_cur_song", 0))
85 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_cp_tree),
86 path,
87 NULL,
88 TRUE,0.5,0);
92 static void __real_pl3_total_playtime_changed(GmpcMpdDataModelPlaylist *model, unsigned long loaded_songs, unsigned long total_playtime, gpointer user_data)
94 if(mpd_playlist_get_playlist_length(connection)&&loaded_songs > 0)
97 unsigned long total_songs = GMPC_MPDDATA_MODEL(model)->num_rows;
98 guint playtime = total_playtime*((gdouble)(total_songs/(gdouble)loaded_songs));
99 gchar *string = format_time(playtime);
100 gchar *mesg = NULL;
102 mesg = g_strdup_printf("%lu %s%c %s %s (%lu%% counted)", total_songs,
103 ngettext("item", "items", total_songs ), (string[0])?',':' ', string,
104 (string[0] == 0 || total_songs == loaded_songs)? "":_("(Estimation)"),(loaded_songs*100)/total_songs);
106 pl3_push_rsb_message(mesg);
108 q_free(string);
110 q_free(mesg);
112 } else {
114 pl3_push_rsb_message("");
119 static void pl3_total_playtime_changed(GmpcMpdDataModelPlaylist *model, unsigned long loaded_songs, unsigned long total_playtime, gpointer user_data)
121 if(pl3_cat_get_selected_browser() == current_playlist_plug.id)
123 __real_pl3_total_playtime_changed(model, loaded_songs, total_playtime, user_data);
127 static void pl3_cp_init()
129 playlist = (GtkTreeModel *)gmpc_mpddata_model_playlist_new(gmpcconn,connection);
130 pl3_current_playlist_browser_init();
131 g_signal_connect(G_OBJECT(playlist), "current_song_changed", G_CALLBACK(pl3_cp_current_song_changed), NULL);
132 g_signal_connect(G_OBJECT(playlist), "total_playtime_changed", G_CALLBACK(pl3_total_playtime_changed), NULL);
136 gmpcPlBrowserPlugin current_playlist_gbp = {
137 .add = pl3_current_playlist_browser_add,
138 .selected = pl3_current_playlist_browser_selected,
139 .unselected = pl3_current_playlist_browser_unselected,
140 .cat_right_mouse_menu = pl3_current_playlist_browser_cat_menu_popup,
141 .add_go_menu = pl3_current_playlist_browser_add_go_menu,
142 .key_press_event = pl3_current_playlist_key_press_event
146 gmpcPlugin current_playlist_plug = {
147 .name = "Play Queue Browser",
148 .version = {1,1,1},
149 .plugin_type = GMPC_PLUGIN_PL_BROWSER,
150 .init = pl3_cp_init,
151 .browser = &current_playlist_gbp,
152 .mpd_status_changed = pl3_current_playlist_status_changed,
153 .mpd_connection_changed = pl3_current_playlist_connection_changed,
154 .destroy = pl3_current_playlist_destroy,
155 .save_yourself = pl3_current_playlist_save_myself
159 /* external objects */
160 extern GladeXML *pl3_xml;
162 /* internal */
164 static GtkWidget *pl3_cp_sw = NULL;
165 static GtkWidget *pl3_cp_vbox = NULL;
166 static TreeSearch *tree_search = NULL;
167 static GtkTreeRowReference *pl3_curb_tree_ref = NULL;
169 static void pl3_current_playlist_search_activate(TreeSearch *search,GtkTreeView *tree)
171 GtkTreeModel *model = gtk_tree_view_get_model(tree);
172 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
173 if (gtk_tree_selection_count_selected_rows (selection) == 1)
175 GList *list = gtk_tree_selection_get_selected_rows (selection, &model);
176 pl3_current_playlist_browser_row_activated(GTK_TREE_VIEW(tree),(GtkTreePath *)list->data, NULL);
177 /* free list */
178 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
179 g_list_free (list);
185 static void pl3_current_playlist_column_changed(GtkTreeView *tree)
187 int position = 0;
188 GList *iter,*cols = gtk_tree_view_get_columns(tree);
189 for(iter = cols; iter; iter = g_list_next(iter))
191 gpointer data = g_object_get_data(G_OBJECT(iter->data), "colid");
192 int colid = GPOINTER_TO_INT(data);
193 char *string = g_strdup_printf("%i", position);
194 cfg_set_single_value_as_int(config, "current-playlist-column-pos", string, colid);
195 position++;
196 q_free(string);
198 g_list_free(cols);
201 void pl3_current_playlist_destroy()
203 if(pl3_cp_tree)
205 GList *iter,*cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(pl3_cp_tree));
206 for(iter = cols; iter; iter = g_list_next(iter))
208 gpointer data = g_object_get_data(G_OBJECT(iter->data), "colid");
209 int colid = GPOINTER_TO_INT(data);
210 gchar *string = g_strdup_printf("%i", colid);
211 int width = gtk_tree_view_column_get_width(GTK_TREE_VIEW_COLUMN(iter->data));
212 cfg_set_single_value_as_int(config, "current-playlist-column-width", string,width);
213 q_free(string);
215 g_list_free(cols);
217 /* destroy the entry */
218 if(pl3_curb_tree_ref)
220 GtkTreeIter piter;
221 GtkTreePath *path;
222 path = gtk_tree_row_reference_get_path(pl3_curb_tree_ref);
223 if(path)
225 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(gtk_tree_row_reference_get_model(pl3_curb_tree_ref)), &piter,path))
227 gtk_list_store_remove(GTK_LIST_STORE(gtk_tree_row_reference_get_model(pl3_curb_tree_ref)), &piter);
229 gtk_tree_path_free(path);
231 gtk_tree_row_reference_free(pl3_curb_tree_ref);
232 pl3_curb_tree_ref = NULL;
234 /* destroy the browser */
235 if(pl3_cp_vbox)
237 /* remove the signal handler so when the widget is destroyed, the numbering of the labels are not changed again */
238 g_signal_handlers_disconnect_by_func(G_OBJECT(pl3_cp_tree), G_CALLBACK(pl3_current_playlist_column_changed), NULL);
239 g_object_unref(pl3_cp_vbox);
240 pl3_cp_vbox = NULL;
242 pl3_cp_tree = NULL;
249 static GtkTreeModel *mod_fill = NULL;
250 static GtkWidget *filter_entry = NULL;
251 static guint timeout=0;
253 static gboolean mod_fill_do_entry_changed(GtkWidget *entry, GtkWidget *tree)
255 const gchar *text2 = gtk_entry_get_text(GTK_ENTRY(entry));
256 if(strlen(text2) > 0)
258 MpdData *data = NULL;
259 gchar **text = tokenize_string(text2);
260 int i;
261 int searched = 0;
263 for(i=0;text && text[i];i++)
265 if(!searched)
266 mpd_playlist_search_start(connection, FALSE);
267 mpd_playlist_search_add_constraint(connection, MPD_TAG_ITEM_ANY,text[i]);
268 searched = 1;
270 if(searched)
271 data = mpd_playlist_search_commit(connection);
272 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(mod_fill), data);
273 g_strfreev(text);
274 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_cp_tree), mod_fill);
276 else
278 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_cp_tree), playlist);
279 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(mod_fill), NULL);
280 if(!search_keep_open)
282 gtk_widget_hide(entry);
283 gtk_widget_grab_focus(pl3_cp_tree);
286 timeout = 0;
287 return FALSE;
290 static gboolean mod_fill_entry_key_press_event(GtkWidget *entry, GdkEventKey *event, gpointer data)
292 const gchar *text = gtk_entry_get_text(GTK_ENTRY(entry));
294 if(strlen(text) == 0)
296 if(event->keyval == GDK_BackSpace || event->keyval == GDK_Escape)
298 search_keep_open = FALSE;
299 gtk_widget_hide(entry);
300 gtk_widget_grab_focus(pl3_cp_tree);
301 return TRUE;
303 }else if(event->keyval == GDK_Escape)
305 search_keep_open = FALSE;
306 gtk_entry_set_text(GTK_ENTRY(entry), "");
308 return FALSE;
311 static void mod_fill_entry_changed(GtkWidget *entry, GtkWidget *tree)
313 if(timeout != 0)
314 g_source_remove(timeout);
315 timeout = g_timeout_add_seconds(1, (GSourceFunc)mod_fill_do_entry_changed, entry);
316 gtk_widget_show(entry);
318 static void mod_fill_entry_activate(GtkWidget *entry, gpointer data)
320 if(timeout != 0)
321 g_source_remove(timeout);
322 mod_fill_do_entry_changed(entry, data);
323 gtk_widget_grab_focus(pl3_cp_tree);
327 static void pl3_current_playlist_browser_init(void)
329 GtkWidget *entry = NULL,*tree = NULL,*sw = NULL;
330 pl3_cp_vbox = gtk_vbox_new(FALSE,6);
331 tree = gmpc_mpddata_treeview_new("current-pl", FALSE, GTK_TREE_MODEL(playlist));
333 /* filter */
334 mod_fill = (GtkTreeModel *)gmpc_mpddata_model_new();
335 entry = sexy_icon_entry_new();
336 sexy_icon_entry_add_clear_button(SEXY_ICON_ENTRY(entry));
337 gtk_box_pack_start(GTK_BOX(pl3_cp_vbox), entry, FALSE, TRUE,0);
338 filter_entry= entry;
339 g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(mod_fill_entry_changed), tree);
340 g_signal_connect(G_OBJECT(entry), "key-press-event", G_CALLBACK(mod_fill_entry_key_press_event), NULL);
341 g_signal_connect(G_OBJECT(entry), "activate", G_CALLBACK(mod_fill_entry_activate), NULL);
343 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tree), TRUE);
344 sw = gtk_scrolled_window_new(NULL, NULL);
345 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
346 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
347 gtk_container_add(GTK_CONTAINER(sw), tree);
348 gtk_box_pack_start(GTK_BOX(pl3_cp_vbox), GTK_WIDGET(sw), TRUE, TRUE,0);
349 gtk_widget_show_all(sw);
350 /* set up the tree */
351 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree), FALSE);
353 /* setup signals */
354 g_signal_connect(G_OBJECT(tree), "row-activated",G_CALLBACK(pl3_current_playlist_browser_row_activated), NULL);
355 g_signal_connect(G_OBJECT(tree), "button-press-event", G_CALLBACK(pl3_current_playlist_browser_button_press_event), NULL);
356 g_signal_connect(G_OBJECT(tree), "button-release-event", G_CALLBACK(pl3_current_playlist_browser_button_release_event), NULL);
357 g_signal_connect(G_OBJECT(tree), "key-press-event", G_CALLBACK(pl3_current_playlist_browser_key_release_event), entry);
359 /* set up the scrolled window */
360 pl3_cp_sw = gtk_scrolled_window_new(NULL, NULL);
361 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_cp_sw), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
362 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_cp_sw), GTK_SHADOW_ETCHED_IN);
365 tree_search = (TreeSearch *)treesearch_new(GTK_TREE_VIEW(tree), MPDDATA_MODEL_COL_MARKUP);
366 g_signal_connect(G_OBJECT(tree_search), "result-activate", G_CALLBACK(pl3_current_playlist_search_activate),tree);
369 gtk_box_pack_end(GTK_BOX(pl3_cp_vbox), GTK_WIDGET(tree_search), FALSE, TRUE, 0);
372 /* set initial state */
373 pl3_cp_tree = tree;
374 g_object_ref(G_OBJECT(pl3_cp_vbox));
377 static void pl3_current_playlist_browser_select_current_song()
379 if(pl3_cp_tree == NULL|| !GTK_WIDGET_REALIZED(pl3_cp_tree)) return;
380 /* scroll to the playing song */
381 if(mpd_player_get_current_song_pos(connection) >= 0 && mpd_playlist_get_playlist_length(connection) > 0)
383 GtkTreePath *path = gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection),-1);
384 if(path != NULL && GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_cp_tree))))
386 gtk_tree_view_set_cursor(GTK_TREE_VIEW(pl3_cp_tree), path, NULL, FALSE);
388 gtk_tree_path_free(path);
392 static void pl3_current_playlist_browser_scroll_to_current_song()
394 if(pl3_cp_tree == NULL || !GTK_WIDGET_REALIZED(pl3_cp_tree)) return;
395 /* scroll to the playing song */
396 if(mpd_player_get_current_song_pos(connection) >= 0 && mpd_playlist_get_playlist_length(connection) > 0)
398 GtkTreePath *path = gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection),-1);
399 if(path != NULL)
401 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_cp_tree),
402 path,
403 NULL,
404 TRUE,0.5,0);
405 gtk_tree_path_free(path);
411 /* add's the toplevel entry for the current playlist view */
412 static void pl3_current_playlist_browser_add(GtkWidget *cat_tree)
414 GtkTreeIter iter;
415 GtkTreePath *path;
416 gint pos = cfg_get_single_value_as_int_with_default(config, "current-playlist","position",0);
417 playlist3_insert_browser(&iter, pos);
418 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &iter,
419 PL3_CAT_TYPE, current_playlist_plug.id,/*PL3_CURRENT_PLAYLIST,*/
420 PL3_CAT_TITLE, _("Play Queue"),
421 PL3_CAT_INT_ID, "",
422 PL3_CAT_ICON_ID, "playlist-browser",
423 PL3_CAT_PROC, TRUE,
424 PL3_CAT_ICON_SIZE,GTK_ICON_SIZE_DND,
425 -1);
426 if(pl3_curb_tree_ref)
428 gtk_tree_row_reference_free(pl3_curb_tree_ref);
429 pl3_curb_tree_ref = NULL;
431 path = gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_tree), &iter);
432 if(path)
434 pl3_curb_tree_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(pl3_tree),path);
435 gtk_tree_path_free(path);
440 /* delete all selected songs,
441 * if no songs select ask the user if he want's to clear the list
443 static void pl3_current_playlist_browser_delete_selected_songs ()
445 /* grab the selection from the tree */
446 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pl3_cp_tree));
447 /* check if where connected */
448 /* see if there is a row selected */
449 if (gtk_tree_selection_count_selected_rows (selection) > 0)
451 GList *list = NULL, *llist = NULL;
452 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_cp_tree));
453 /* start a command list */
454 /* grab the selected songs */
455 list = gtk_tree_selection_get_selected_rows (selection, &model);
456 /* grab the last song that is selected */
457 llist = g_list_last (list);
458 /* remove every selected song one by one */
460 GtkTreeIter iter;
461 int value;
462 gtk_tree_model_get_iter (model, &iter,(GtkTreePath *) llist->data);
463 //gtk_tree_model_get (model, &iter, MPDDATA_MODEL_COL_SONG_ID, &value, -1);
464 /* Trick that avoids roundtrip to mpd */
465 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(model))
467 value = gmpc_mpddata_model_get_pos(GMPC_MPDDATA_MODEL(model), &iter);
468 }else{
469 /* this one allready has the pos. */
470 gtk_tree_model_get (model, &iter, MPDDATA_MODEL_COL_SONG_POS, &value, -1);
471 value--;
473 mpd_playlist_queue_delete_pos(connection, value);
474 } while ((llist = g_list_previous (llist)));
476 /* close the list, so it will be executed */
477 mpd_playlist_queue_commit(connection);
478 /* free list */
479 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
480 g_list_free (list);
482 else
484 /* create a warning message dialog */
485 GtkWidget *dialog =
486 gtk_message_dialog_new (GTK_WINDOW
487 (glade_xml_get_widget
488 (pl3_xml, "pl3_win")),
489 GTK_DIALOG_MODAL,
490 GTK_MESSAGE_WARNING,
491 GTK_BUTTONS_NONE,
492 _("Are you sure you want to clear the playlist?"));
493 gtk_dialog_add_buttons (GTK_DIALOG (dialog), GTK_STOCK_CANCEL,
494 GTK_RESPONSE_CANCEL, GTK_STOCK_OK,
495 GTK_RESPONSE_OK, NULL);
496 gtk_dialog_set_default_response (GTK_DIALOG (dialog),
497 GTK_RESPONSE_CANCEL);
499 switch (gtk_dialog_run (GTK_DIALOG (dialog)))
501 case GTK_RESPONSE_OK:
502 /* check if where still connected */
503 mpd_playlist_clear(connection);
505 gtk_widget_destroy (GTK_WIDGET (dialog));
507 /* update everything if where still connected */
508 gtk_tree_selection_unselect_all(selection);
510 mpd_status_queue_update(connection);
513 static void pl3_current_playlist_browser_crop_selected_songs()
515 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_cp_tree));
516 /* grab the selection from the tree */
517 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pl3_cp_tree));
519 /* see if there is a row selected */
520 if (gtk_tree_selection_count_selected_rows (selection) > 0)
522 GtkTreeIter iter;
523 /* Use the walk through list and traverse it method, if done right, this can safe roundtrips to mpd */
524 int last_seen = mpd_playlist_get_playlist_length(connection);
525 int position = 0;
526 GList *node,*list = NULL;
527 printf("Crop method 2\n");
530 /* we want to delete from back to front, so we have to transverse this list */
531 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter))
534 if(GMPC_IS_MPDDATA_MODEL_PLAYLIST(model)){
535 /* Count my self, so we don't have to fetch any unselected row from mpd */
537 if(gtk_tree_selection_iter_is_selected(selection, &iter))
539 /* song pos starts at 1, not a 0, compensate for that */
540 list = g_list_append(list, GINT_TO_POINTER(position));
542 position++;
543 }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
544 }else{
546 if(gtk_tree_selection_iter_is_selected(selection, &iter))
548 int pos=0;
549 /* song pos starts at 1, not a 0, compensate for that */
550 gtk_tree_model_get (GTK_TREE_MODEL(model), &iter, MPDDATA_MODEL_COL_SONG_POS, &pos, -1);
551 list = g_list_append(list, GINT_TO_POINTER(pos-1));
553 }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter));
557 for(node = g_list_last(list);node; node = g_list_previous(node))
559 int pos = GPOINTER_TO_INT(node->data)+1;
560 while(last_seen > (pos))
562 last_seen--;
563 mpd_playlist_queue_delete_pos(connection, last_seen);
565 last_seen = pos-1;
567 while(last_seen > 0)
569 last_seen--;
570 mpd_playlist_queue_delete_pos(connection, last_seen);
573 mpd_playlist_queue_commit(connection);
574 if(list) g_list_free(list);
575 /* update everything if where still connected */
576 gtk_tree_selection_unselect_all(selection);
578 mpd_status_queue_update(connection);
582 static void pl3_current_playlist_editor_add_to_playlist(GtkWidget *menu)
584 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_cp_tree));
585 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_cp_tree));
586 gchar *data = g_object_get_data(G_OBJECT(menu), "playlist");
587 GList *iter, *list = gtk_tree_selection_get_selected_rows (selection, &model);
588 if(list)
590 iter = g_list_first(list);
592 GtkTreeIter giter;
593 if(gtk_tree_model_get_iter(model, &giter, (GtkTreePath *)iter->data))
595 gchar *file = NULL;
596 gtk_tree_model_get(model, &giter, MPDDATA_MODEL_COL_PATH, &file, -1);
597 mpd_database_playlist_list_add(connection, data,file);
598 g_free(file);
600 }while((iter = g_list_next(iter)));
602 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
603 g_list_free (list);
606 playlist_editor_fill_list();
608 static int pl3_current_playlist_browser_button_press_event(GtkTreeView *tree, GdkEventButton *event)
610 GtkTreePath *path = NULL;
611 if(event->button == 3 &&gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(tree), event->x, event->y,&path,NULL,NULL,NULL))
613 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
614 if(gtk_tree_selection_path_is_selected(sel, path))
616 gtk_tree_path_free(path);
617 return TRUE;
620 if(path) {
621 gtk_tree_path_free(path);
623 return FALSE;
625 static void pl3_current_playlist_browser_edit_columns(void)
627 gmpc_mpddata_treeview_edit_columns(GMPC_MPDDATA_TREEVIEW(pl3_cp_tree));
630 static int pl3_current_playlist_browser_button_release_event(GtkTreeView *tree, GdkEventButton *event)
632 if(event->button == 3)
634 /* del, crop */
635 GtkWidget *item;
636 GtkWidget *menu = gtk_menu_new();
638 /* add the delete widget */
639 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_REMOVE,NULL);
640 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
641 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_delete_selected_songs), NULL);
643 /* add the delete widget */
644 item = gtk_image_menu_item_new_with_label(_("Crop"));
645 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
646 gtk_image_new_from_stock(GTK_STOCK_CUT, GTK_ICON_SIZE_MENU));
647 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_crop_selected_songs), NULL);
648 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
650 gtk_menu_shell_append(GTK_MENU_SHELL(menu),gtk_separator_menu_item_new());
651 /* add the clear widget */
652 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR,NULL);
653 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
654 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist), NULL);
657 /* add the shuffle widget */
658 item = gtk_image_menu_item_new_with_label(_("Shuffle"));
659 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
660 gtk_image_new_from_stock(GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU));
661 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_shuffle_playlist), NULL);
662 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
664 gtk_menu_shell_append(GTK_MENU_SHELL(menu),gtk_separator_menu_item_new());
666 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO,NULL);
667 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
668 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_show_info), NULL);
670 /* add the shuffle widget */
673 item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
674 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
675 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
676 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
677 g_signal_connect(G_OBJECT(item), "activate",
678 G_CALLBACK(pl3_current_playlist_browser_edit_columns), NULL);
680 /* */
681 if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(tree)) == 1)
683 mpd_Song *song;
684 GtkTreeIter iter;
685 GtkTreePath *path;
686 GtkTreeModel *model = gtk_tree_view_get_model(tree);
687 GList *list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), &model);
688 path = list->data;
689 /* free result */
690 g_list_free(list);
691 if(path && gtk_tree_model_get_iter(model, &iter, path)) {
692 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
693 if(song)
695 submenu_for_song(menu, song);
697 if(path)
698 gtk_tree_path_free(path);
702 playlist_editor_right_mouse(menu,pl3_current_playlist_editor_add_to_playlist);
704 gtk_widget_show_all(menu);
705 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL,0, event->time);
706 return TRUE;
708 return FALSE;
711 static void pl3_current_playlist_browser_row_activated(GtkTreeView *tree, GtkTreePath *path, GtkTreeViewColumn *col)
713 GtkTreeIter iter;
714 gint song_id;
715 GtkTreeModel *model = gtk_tree_view_get_model(tree);
716 gtk_tree_model_get_iter(model, &iter, path);
717 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_SONG_ID,&song_id, -1);
718 mpd_player_play_id(connection, song_id);
720 if(!search_keep_open && model == mod_fill)
722 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_cp_tree), playlist);
723 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(mod_fill), NULL);
724 gtk_widget_hide(filter_entry);
726 pl3_current_playlist_browser_select_current_song();
731 static void pl3_current_playlist_browser_show_info()
734 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(pl3_cp_tree));
735 GtkTreeSelection *selection =gtk_tree_view_get_selection (GTK_TREE_VIEW(pl3_cp_tree));
736 if (gtk_tree_selection_count_selected_rows (selection) > 0)
738 GList *list = NULL;
739 list = gtk_tree_selection_get_selected_rows (selection, &model);
741 list = g_list_last (list);
744 GtkTreeIter iter;
745 mpd_Song *song = NULL;
746 gtk_tree_model_get_iter (model, &iter, (GtkTreePath *) list->data);
747 gtk_tree_model_get (model, &iter, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
749 info2_activate();
750 info2_fill_song_view(song);
754 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
755 g_list_free (list);
759 static void pl3_current_playlist_browser_selected(GtkWidget *container)
761 unsigned long a = 0,b = 0;
762 if(pl3_cp_vbox == NULL)
764 pl3_current_playlist_browser_init();
766 gtk_container_add(GTK_CONTAINER(container), pl3_cp_vbox);
767 gtk_widget_show(pl3_cp_vbox);
769 gtk_widget_grab_focus(pl3_cp_tree);
770 gmpc_mpddata_model_playlist_get_total_playtime(GMPC_MPDDATA_MODEL_PLAYLIST(playlist), &a, &b);
771 __real_pl3_total_playtime_changed(GMPC_MPDDATA_MODEL_PLAYLIST(playlist),a,b,NULL);
773 gtk_widget_grab_focus(pl3_cp_tree);
775 static void pl3_current_playlist_browser_unselected(GtkWidget *container)
777 gtk_container_remove(GTK_CONTAINER(container), pl3_cp_vbox);
781 static int pl3_current_playlist_browser_cat_menu_popup(GtkWidget *menu, int type, GtkWidget *tree, GdkEventButton *event)
783 /* here we have: Save, Clear*/
784 GtkWidget *item;
785 if(type != current_playlist_plug.id) return 0;
786 /* add the save widget */
787 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE,NULL);
788 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
789 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_save_playlist), NULL);
791 /* add the clear widget */
792 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR,NULL);
793 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
794 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist), NULL);
796 item = gtk_image_menu_item_new_with_label(_("Add URL"));
797 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
798 gtk_image_new_from_icon_name("gmpc-add-url", GTK_ICON_SIZE_MENU));
799 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
800 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_start), NULL);
802 return 1;
805 static int pl3_current_playlist_browser_key_release_event(GtkTreeView *tree, GdkEventKey *event,GtkWidget *entry)
807 if(event->keyval == GDK_Delete)
809 pl3_current_playlist_browser_delete_selected_songs ();
810 return TRUE;
812 else if(event->keyval == GDK_i && event->state&GDK_MOD1_MASK)
814 pl3_current_playlist_browser_show_info();
815 return TRUE;
817 else if (event->keyval == GDK_space)
819 pl3_current_playlist_browser_scroll_to_current_song();
820 pl3_current_playlist_browser_select_current_song();
821 return TRUE;
823 else if (event->keyval == GDK_f && event->state&GDK_CONTROL_MASK)
825 mod_fill_entry_changed(entry, NULL);
826 gtk_widget_grab_focus(entry);
827 search_keep_open = TRUE;
828 return TRUE;
830 else if((event->state&(GDK_CONTROL_MASK|GDK_MOD1_MASK)) == 0 )/*&&
831 ((event->keyval >= GDK_space && event->keyval <= GDK_z)))*/
833 char data[10];
834 gunichar uc = gdk_keyval_to_unicode(event->keyval);
835 if(uc)
837 memset(data,'\0',10);
838 g_unichar_to_utf8 (uc, data);
839 gtk_widget_grab_focus(entry);
840 gtk_entry_set_text(GTK_ENTRY(entry),data);
841 gtk_editable_set_position(GTK_EDITABLE(entry),1);
843 return TRUE;
846 return pl3_window_key_press_event(GTK_WIDGET(tree),event);
849 /* create a dialog that allows the user to save the current playlist */
850 static void pl3_current_playlist_save_playlist ()
852 gchar *str;
853 GladeXML *xml = NULL;
854 int run = TRUE;
855 /* check if the connection is up */
856 if (!mpd_check_connected(connection))
858 return;
860 /* create the interface */
861 str = gmpc_get_full_glade_path("playlist3.glade");
862 xml = glade_xml_new (str, "save_pl", NULL);
863 q_free(str);
865 /* run the interface */
868 switch (gtk_dialog_run (GTK_DIALOG (glade_xml_get_widget (xml, "save_pl"))))
870 case GTK_RESPONSE_OK:
871 run = FALSE;
872 /* if the users agrees do the following: */
873 /* get the song-name */
874 str = (gchar *) gtk_entry_get_text (GTK_ENTRY
875 (glade_xml_get_widget (xml, "pl-entry")));
876 /* check if the user entered a name, we can't do withouth */
877 /* TODO: disable ok button when nothing is entered */
878 /* also check if there is a connection */
879 if (strlen (str) != 0 && mpd_check_connected(connection))
881 int retv = mpd_database_save_playlist(connection, str);
882 if(retv == MPD_DATABASE_PLAYLIST_EXIST )
884 gchar *errormsg = g_strdup_printf(_("<i>Playlist <b>\"%s\"</b> already exists\nOverwrite?</i>"), str);
885 gtk_label_set_markup(GTK_LABEL(glade_xml_get_widget(xml, "label_error")), errormsg);
886 gtk_widget_show(glade_xml_get_widget(xml, "hbox5"));
887 /* ask to replace */
888 gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "pl-entry")), FALSE);
889 switch (gtk_dialog_run (GTK_DIALOG (glade_xml_get_widget (xml, "save_pl"))))
891 case GTK_RESPONSE_OK:
892 run = FALSE;
893 mpd_database_delete_playlist(connection, str);
894 mpd_database_save_playlist(connection,str);
895 GmpcStatusChangedCallback(connection, MPD_CST_DATABASE, NULL);
896 break;
897 default:
898 run = TRUE;
900 /* return to stare */
901 gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(xml, "pl-entry")), TRUE);
902 gtk_widget_hide(glade_xml_get_widget(xml, "hbox5"));
904 q_free(errormsg);
906 else if (retv != MPD_OK)
908 playlist3_show_error_message(_("Failed to save the playlist file."), ERROR_WARNING);
910 else
912 GmpcStatusChangedCallback(connection, MPD_CST_DATABASE, NULL);
915 break;
916 default:
917 run = FALSE;
919 }while(run);
920 /* destroy the window */
921 gtk_widget_destroy (glade_xml_get_widget (xml, "save_pl"));
923 /* unref the gui description */
924 g_object_unref (xml);
927 static void pl3_current_playlist_browser_clear_playlist()
929 mpd_playlist_clear(connection);
932 static void pl3_current_playlist_browser_shuffle_playlist()
934 mpd_playlist_shuffle(connection);
937 static void pl3_current_playlist_status_changed(MpdObj *mi, ChangedStatusType what, void *userdata)
939 if(pl3_cp_vbox == NULL)
940 return;
941 if(what&MPD_CST_PLAYLIST)
943 mod_fill_do_entry_changed(filter_entry, NULL);
948 static void pl3_current_playlist_browser_activate()
950 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *)
951 glade_xml_get_widget (pl3_xml, "cat_tree"));
954 GtkTreePath *path = gtk_tree_row_reference_get_path(pl3_curb_tree_ref);
955 if(path)
957 gtk_tree_selection_select_path(selec, path);
958 gtk_tree_path_free(path);
963 static int pl3_current_playlist_browser_add_go_menu(GtkWidget *menu)
965 GtkWidget *item = NULL;
967 item = gtk_image_menu_item_new_with_label(_("Play Queue"));
968 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
969 gtk_image_new_from_icon_name("playlist-browser", GTK_ICON_SIZE_MENU));
970 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
971 gtk_widget_add_accelerator(GTK_WIDGET(item), "activate", gtk_menu_get_accel_group(GTK_MENU(menu)), GDK_F1, 0, GTK_ACCEL_VISIBLE);
972 g_signal_connect(G_OBJECT(item), "activate",
973 G_CALLBACK(pl3_current_playlist_browser_activate), NULL);
974 return 1;
980 static int pl3_current_playlist_key_press_event(GtkWidget *mw, GdkEventKey *event, int type)
983 return FALSE;
986 static void pl3_current_playlist_connection_changed(MpdObj *mi, int connect,gpointer data)
988 if(!connect && filter_entry)
990 gtk_entry_set_text(GTK_ENTRY(filter_entry), "");
993 /* function that saves the settings */
994 static void pl3_current_playlist_save_myself(void)
996 if(pl3_curb_tree_ref)
998 GtkTreePath *path = gtk_tree_row_reference_get_path(pl3_curb_tree_ref);
999 if(path)
1001 gint *indices = gtk_tree_path_get_indices(path);
1002 debug_printf(DEBUG_INFO,"Saving myself to position: %i\n", indices[0]);
1003 cfg_set_single_value_as_int(config, "current-playlist","position",indices[0]);
1004 gtk_tree_path_free(path);