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.
21 #include <gdk/gdkkeysyms.h>
24 #include <glade/glade.h>
32 #include "playlist3.h"
33 #include "playlist3-current-playlist-browser.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
);
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
),
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
);
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
);
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",
149 .plugin_type
= GMPC_PLUGIN_PL_BROWSER
,
151 .browser
= ¤t_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
;
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
);
178 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
185 static void pl3_current_playlist_column_changed(GtkTreeView
*tree
)
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
);
201 void pl3_current_playlist_destroy()
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
);
217 /* destroy the entry */
218 if(pl3_curb_tree_ref
)
222 path
= gtk_tree_row_reference_get_path(pl3_curb_tree_ref
);
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 */
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
);
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
);
263 for(i
=0;text
&& text
[i
];i
++)
266 mpd_playlist_search_start(connection
, FALSE
);
267 mpd_playlist_search_add_constraint(connection
, MPD_TAG_ITEM_ANY
,text
[i
]);
271 data
= mpd_playlist_search_commit(connection
);
272 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(mod_fill
), data
);
274 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_cp_tree
), mod_fill
);
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
);
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
);
303 }else if(event
->keyval
== GDK_Escape
)
305 search_keep_open
= FALSE
;
306 gtk_entry_set_text(GTK_ENTRY(entry
), "");
311 static void mod_fill_entry_changed(GtkWidget
*entry
, GtkWidget
*tree
)
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
)
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
));
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);
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
);
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 */
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);
401 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_cp_tree
),
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
)
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"),
422 PL3_CAT_ICON_ID
, "playlist-browser",
424 PL3_CAT_ICON_SIZE
,GTK_ICON_SIZE_DND
,
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
);
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 */
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
);
469 /* this one allready has the pos. */
470 gtk_tree_model_get (model
, &iter
, MPDDATA_MODEL_COL_SONG_POS
, &value
, -1);
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
);
479 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
484 /* create a warning message dialog */
486 gtk_message_dialog_new (GTK_WINDOW
487 (glade_xml_get_widget
488 (pl3_xml
, "pl3_win")),
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)
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
);
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
));
543 }while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
));
546 if(gtk_tree_selection_iter_is_selected(selection
, &iter
))
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
))
563 mpd_playlist_queue_delete_pos(connection
, 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
);
590 iter
= g_list_first(list
);
593 if(gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*)iter
->data
))
596 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, -1);
597 mpd_database_playlist_list_add(connection
, data
,file
);
600 }while((iter
= g_list_next(iter
)));
602 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
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 &>k_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
);
621 gtk_tree_path_free(path
);
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)
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
);
681 if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(tree
)) == 1)
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
);
691 if(path
&& gtk_tree_model_get_iter(model
, &iter
, path
)) {
692 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
695 submenu_for_song(menu
, song
);
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
);
711 static void pl3_current_playlist_browser_row_activated(GtkTreeView
*tree
, GtkTreePath
*path
, GtkTreeViewColumn
*col
)
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)
739 list
= gtk_tree_selection_get_selected_rows (selection
, &model
);
741 list
= g_list_last (list
);
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);
750 info2_fill_song_view(song
);
754 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
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*/
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
);
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 ();
812 else if(event
->keyval
== GDK_i
&& event
->state
&GDK_MOD1_MASK
)
814 pl3_current_playlist_browser_show_info();
817 else if (event
->keyval
== GDK_space
)
819 pl3_current_playlist_browser_scroll_to_current_song();
820 pl3_current_playlist_browser_select_current_song();
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
;
830 else if((event
->state
&(GDK_CONTROL_MASK
|GDK_MOD1_MASK
)) == 0 )/*&&
831 ((event->keyval >= GDK_space && event->keyval <= GDK_z)))*/
834 gunichar uc
= gdk_keyval_to_unicode(event
->keyval
);
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);
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 ()
853 GladeXML
*xml
= NULL
;
855 /* check if the connection is up */
856 if (!mpd_check_connected(connection
))
860 /* create the interface */
861 str
= gmpc_get_full_glade_path("playlist3.glade");
862 xml
= glade_xml_new (str
, "save_pl", NULL
);
865 /* run the interface */
868 switch (gtk_dialog_run (GTK_DIALOG (glade_xml_get_widget (xml
, "save_pl"))))
870 case GTK_RESPONSE_OK
:
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"));
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
:
893 mpd_database_delete_playlist(connection
, str
);
894 mpd_database_save_playlist(connection
,str
);
895 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
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"));
906 else if (retv
!= MPD_OK
)
908 playlist3_show_error_message(_("Failed to save the playlist file."), ERROR_WARNING
);
912 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
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
)
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
);
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
);
980 static int pl3_current_playlist_key_press_event(GtkWidget
*mw
, GdkEventKey
*event
, int type
)
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
);
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
);