1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <gdk/gdkkeysyms.h>
28 #include "playlist3.h"
29 #include "playlist3-current-playlist-browser.h"
30 #include "playlist3-find2-browser.h"
31 #include "gmpc-mpddata-model.h"
32 #include "gmpc-mpddata-model-playlist.h"
33 #include "gmpc-mpddata-treeview.h"
34 #include "advanced-search.h"
35 #include "playlist3-messages.h"
37 #include "playlist3-playlist-editor.h"
39 static void pl3_current_playlist_browser_priority_raise_selected_songs(PlayQueuePlugin
* self
);
40 static void pl3_current_playlist_browser_priority_remove_selected_songs(PlayQueuePlugin
* self
);
46 PLAY_QUEUE_DUMMY_PROPERTY
,
50 * Private data structure
52 typedef struct _PlayQueuePluginPrivate
54 gulong status_changed_handler
;
55 gulong connection_changed_handler
;
58 gboolean search_keep_open
;
59 GtkWidget
*filter_entry
;
60 GtkTreeModel
*mod_fill
;
61 gboolean quick_search
;
62 guint quick_search_timeout
;
64 GtkWidget
*pl3_cp_tree
;
65 GtkWidget
*pl3_cp_vbox
;
66 /* reference to the row */
67 GtkTreeRowReference
*pl3_curb_tree_ref
;
70 } _PlayQueuePluginPrivate
;
73 * Propperty setter/getter
75 static void play_queue_get_property(GObject
* object
, guint property_id
, GValue
* value
, GParamSpec
* pspec
)
77 PlayQueuePlugin
*self
;
78 self
= (PlayQueuePlugin
*) (object
);
82 g_value_set_string(value
, self
->priv
->uid
);
85 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
91 static void play_queue_set_property(GObject
* object
, guint property_id
, const GValue
* value
, GParamSpec
* pspec
)
93 PlayQueuePlugin
*self
;
94 self
= (PlayQueuePlugin
*) (object
);
99 g_free(self
->priv
->uid
);
100 self
->priv
->uid
= g_value_dup_string(value
);
103 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, property_id
, pspec
);
108 static void pl3_current_playlist_browser_paste_after_songs(GtkTreeView
* tree
, GList
* paste_list
,
109 PlayQueuePlugin
* self
);
110 static void pl3_current_playlist_browser_paste_before_songs(GtkTreeView
* tree
, GList
* paste_list
,
111 PlayQueuePlugin
* self
);
112 static void pl3_current_playlist_browser_delete_selected_songs(PlayQueuePlugin
* self
);
114 static void pl3_current_playlist_browser_add(GmpcPluginBrowserIface
* obj
, GtkWidget
* cat_tree
);
116 static void pl3_current_playlist_browser_selected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
);
117 static void pl3_current_playlist_browser_unselected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
);
119 static void pl3_current_playlist_browser_activate(PlayQueuePlugin
* self
);
122 static void pl3_current_playlist_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* path
, GtkTreeViewColumn
* col
,
123 PlayQueuePlugin
* self
);
124 static int pl3_current_playlist_browser_button_release_event(GtkTreeView
* tree
, GdkEventButton
* event
,
125 PlayQueuePlugin
* self
);
126 static int pl3_current_playlist_browser_key_press_event(GtkTreeView
* tree
, GdkEventKey
* event
,
127 PlayQueuePlugin
* self
);
128 static void pl3_current_playlist_browser_show_info(PlayQueuePlugin
* self
);
129 static void pl3_current_playlist_save_playlist(void);
130 static void pl3_current_playlist_browser_shuffle_playlist(void);
131 static void pl3_current_playlist_browser_clear_playlist(void);
133 static void pl3_current_playlist_browser_init(PlayQueuePlugin
* self
);
135 static void pl3_current_playlist_browser_clear_playlist_real(void)
137 mpd_playlist_clear(connection
);
139 static void pl3_cp_current_song_changed(GmpcMpdDataModelPlaylist
* model2
, GtkTreePath
* path
, GtkTreeIter
* iter
,
140 PlayQueuePlugin
* self
)
143 if (self
->priv
->pl3_cp_tree
== NULL
)
145 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
146 if (GMPC_IS_MPDDATA_MODEL_PLAYLIST(model
))
148 if (cfg_get_single_value_as_int_with_default(config
, "playlist", "st_cur_song", 0))
150 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), path
, NULL
, TRUE
, 0.5, 0);
155 static void pl3_current_playlist_browser_crop_current_song(PlayQueuePlugin
* self
, const gchar
* param
)
157 mpd_Song
*song
= mpd_playlist_get_current_song(connection
);
160 int length
= mpd_playlist_get_playlist_length(connection
);
161 /* Move to first place, this avoid possible "issues" */
162 mpd_playlist_move_id(connection
, song
->id
, 0);
163 for (; length
> 1; length
--)
165 mpd_playlist_queue_delete_pos(connection
, length
- 1);
166 if ((length
& 16383) == 16383)
168 mpd_playlist_queue_commit(connection
);
171 mpd_playlist_queue_commit(connection
);
175 static void pl3_cp_ec_playlist(PlayQueuePlugin
* self
, const gchar
* param
)
177 pl3_find2_select_plugin_id(GMPC_PLUGIN_BASE(self
)->id
);
178 pl3_find2_do_search_any(param
);
181 static void pl3_cp_init(PlayQueuePlugin
* self
)
183 g_signal_connect(G_OBJECT(playlist
), "current_song_changed", G_CALLBACK(pl3_cp_current_song_changed
), self
);
185 gmpc_easy_command_add_entry(gmpc_easy_command
,
186 _("switch play queue"), "",
187 _("Switch to play queue"),
188 (GmpcEasyCommandCallback
*) pl3_current_playlist_browser_activate
, self
);
189 gmpc_easy_command_add_entry(gmpc_easy_command
,
191 _("Clear play queue"),
192 (GmpcEasyCommandCallback
*) pl3_current_playlist_browser_clear_playlist_real
, self
);
194 gmpc_easy_command_add_entry(gmpc_easy_command
,
195 _("Crop current song"), "",
196 _("Crop the playlist so it only contains the current song"),
197 (GmpcEasyCommandCallback
*) pl3_current_playlist_browser_crop_current_song
, self
);
199 gmpc_easy_command_add_entry(gmpc_easy_command
,
200 _("search playlist"), ".*",
201 _("Search playlist <query>"),
202 (GmpcEasyCommandCallback
*) pl3_cp_ec_playlist
, self
);
205 void pl3_current_playlist_destroy(PlayQueuePlugin
* self
);
209 static void pl3_current_playlist_column_changed(GtkTreeView
* tree
)
212 GList
*iter
, *cols
= gtk_tree_view_get_columns(tree
);
213 for (iter
= cols
; iter
; iter
= g_list_next(iter
))
215 gpointer data
= g_object_get_data(G_OBJECT(iter
->data
), "colid");
216 int colid
= GPOINTER_TO_INT(data
);
217 char *string
= g_strdup_printf("%i", position
);
218 cfg_set_single_value_as_int(config
, "current-playlist-column-pos", string
, colid
);
225 void pl3_current_playlist_destroy(PlayQueuePlugin
* self
)
227 /* destroy the entry */
228 if (self
->priv
->pl3_curb_tree_ref
)
232 path
= gtk_tree_row_reference_get_path(self
->priv
->pl3_curb_tree_ref
);
235 if (gtk_tree_model_get_iter
236 (GTK_TREE_MODEL(gtk_tree_row_reference_get_model(self
->priv
->pl3_curb_tree_ref
)), &piter
, path
))
238 gtk_list_store_remove(GTK_LIST_STORE(gtk_tree_row_reference_get_model(self
->priv
->pl3_curb_tree_ref
)),
241 gtk_tree_path_free(path
);
243 gtk_tree_row_reference_free(self
->priv
->pl3_curb_tree_ref
);
244 self
->priv
->pl3_curb_tree_ref
= NULL
;
246 /* destroy the browser */
247 if (self
->priv
->pl3_cp_vbox
)
249 /* remove the signal handler so when the widget is destroyed, the numbering of the labels are not changed again */
250 g_signal_handlers_disconnect_by_func(G_OBJECT(self
->priv
->pl3_cp_tree
),
251 G_CALLBACK(pl3_current_playlist_column_changed
), NULL
);
252 g_object_unref(self
->priv
->pl3_cp_vbox
);
253 self
->priv
->pl3_cp_vbox
= NULL
;
255 self
->priv
->pl3_cp_tree
= NULL
;
258 static gboolean
mod_fill_do_entry_changed(PlayQueuePlugin
* self
)
260 const gchar
*text2
= gtk_entry_get_text(GTK_ENTRY(self
->priv
->filter_entry
));
262 if (strlen(text2
) > 0)
265 MpdData
*data
= NULL
;
266 data
= advanced_search(text2
, TRUE
);
267 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(self
->priv
->mod_fill
), data
);
268 self
->priv
->quick_search
= TRUE
;
269 gtk_tree_view_set_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), self
->priv
->mod_fill
);
270 gtk_widget_show(self
->priv
->filter_entry
);
273 gtk_tree_view_set_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), playlist
);
275 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(self
->priv
->mod_fill
), NULL
);
276 if (!self
->priv
->search_keep_open
)
278 self
->priv
->quick_search
= 0;
279 gtk_widget_hide(self
->priv
->filter_entry
);
280 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
283 self
->priv
->quick_search_timeout
= 0;
287 static gboolean
mod_fill_entry_key_press_event(GtkWidget
* entry
, GdkEventKey
* event
, PlayQueuePlugin
* self
)
289 const gchar
*text
= gtk_entry_get_text(GTK_ENTRY(entry
));
291 if (strlen(text
) == 0)
293 if (event
->keyval
== GDK_KEY_BackSpace
|| event
->keyval
== GDK_KEY_Escape
)
295 self
->priv
->search_keep_open
= FALSE
;
296 gtk_tree_view_set_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), playlist
);
298 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(self
->priv
->mod_fill
), NULL
);
299 self
->priv
->quick_search
= 0;
300 gtk_widget_hide(entry
);
301 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
304 } else if (event
->keyval
== GDK_KEY_Escape
)
306 self
->priv
->search_keep_open
= FALSE
;
307 gtk_entry_set_text(GTK_ENTRY(entry
), "");
308 } else if (event
->keyval
== GDK_KEY_Up
|| event
->keyval
== GDK_KEY_Down
)
310 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
316 static void mod_fill_entry_changed(GtkWidget
* entry
, PlayQueuePlugin
* self
)
318 if (self
->priv
->quick_search_timeout
!= 0)
320 g_source_remove(self
->priv
->quick_search_timeout
);
321 self
->priv
->quick_search_timeout
= 0;
324 if (cfg_get_single_value_as_int_with_default(config
, "general", "search-as-you-type", 0) == 1)
326 self
->priv
->quick_search_timeout
= g_timeout_add(250, (GSourceFunc
) mod_fill_do_entry_changed
, self
);
328 gtk_widget_show(entry
);
331 static void mod_fill_entry_activate(GtkWidget
* entry
, PlayQueuePlugin
* self
)
333 if (self
->priv
->quick_search_timeout
!= 0)
334 g_source_remove(self
->priv
->quick_search_timeout
);
335 mod_fill_do_entry_changed(self
);
336 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
339 static void mod_fill_clear_search_entry(GtkEntry
* entry
, GtkEntryIconPosition icon_pos
, GdkEvent
* event
,
342 if (icon_pos
== GTK_ENTRY_ICON_SECONDARY
)
344 gtk_entry_set_text(GTK_ENTRY(entry
), "");
349 static void pl3_current_playlist_browser_init(PlayQueuePlugin
* self
)
351 GtkWidget
*entry
= NULL
, *tree
= NULL
, *sw
= NULL
, *pl3_cp_sw
;
352 /* Mark the plugin internal */
353 GMPC_PLUGIN_BASE(self
)->plugin_type
= GMPC_INTERNALL
| GMPC_PLUGIN_PL_BROWSER
;
355 self
->priv
->pl3_cp_vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 6);
357 tree
= gmpc_mpddata_treeview_new(self
->priv
->uid
, FALSE
, GTK_TREE_MODEL(playlist
));
359 g_signal_connect(G_OBJECT(tree
), "paste_before", G_CALLBACK(pl3_current_playlist_browser_paste_before_songs
), self
);
360 g_signal_connect(G_OBJECT(tree
), "paste_after", G_CALLBACK(pl3_current_playlist_browser_paste_after_songs
), self
);
361 g_signal_connect_swapped(G_OBJECT(tree
), "cut", G_CALLBACK(pl3_current_playlist_browser_delete_selected_songs
),
365 /* Enable this for this model only */
366 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree
), gmt_targetentries
, 1, GDK_ACTION_DEFAULT
|GDK_ACTION_MOVE
|GDK_ACTION_COPY
);
369 self
->priv
->mod_fill
= (GtkTreeModel
*) gmpc_mpddata_model_new();
370 entry
= gtk_entry_new();
371 gtk_entry_set_icon_from_stock(GTK_ENTRY(entry
), GTK_ENTRY_ICON_SECONDARY
, GTK_STOCK_CLEAR
);
372 g_signal_connect(GTK_ENTRY(entry
), "icon-press", G_CALLBACK(mod_fill_clear_search_entry
), NULL
);
374 gtk_entry_set_icon_from_stock(GTK_ENTRY(entry
), GTK_ENTRY_ICON_PRIMARY
, GTK_STOCK_FIND
);
375 gtk_entry_set_icon_activatable(GTK_ENTRY(entry
), GTK_ENTRY_ICON_PRIMARY
, FALSE
);
378 gtk_box_pack_end(GTK_BOX(self
->priv
->pl3_cp_vbox
), entry
, FALSE
, TRUE
, 0);
379 self
->priv
->filter_entry
= entry
;
380 g_signal_connect(G_OBJECT(entry
), "changed", G_CALLBACK(mod_fill_entry_changed
), self
);
381 g_signal_connect(G_OBJECT(entry
), "key-press-event", G_CALLBACK(mod_fill_entry_key_press_event
), self
);
382 g_signal_connect(G_OBJECT(entry
), "activate", G_CALLBACK(mod_fill_entry_activate
), self
);
384 sw
= gtk_scrolled_window_new(NULL
, NULL
);
385 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
386 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
), GTK_SHADOW_ETCHED_IN
);
387 gtk_container_add(GTK_CONTAINER(sw
), tree
);
388 gtk_box_pack_start(GTK_BOX(self
->priv
->pl3_cp_vbox
), GTK_WIDGET(sw
), TRUE
, TRUE
, 0);
389 gtk_widget_show_all(sw
);
390 /* set up the tree */
391 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree
), FALSE
);
393 gmpc_mpddata_treeview_enable_click_fix(GMPC_MPDDATA_TREEVIEW(tree
));
395 g_signal_connect(G_OBJECT(tree
), "row-activated", G_CALLBACK(pl3_current_playlist_browser_row_activated
), self
);
396 g_signal_connect(G_OBJECT(tree
), "button-release-event",
397 G_CALLBACK(pl3_current_playlist_browser_button_release_event
), self
);
398 g_signal_connect(G_OBJECT(tree
), "key-press-event", G_CALLBACK(pl3_current_playlist_browser_key_press_event
),
401 /* set up the scrolled window */
402 pl3_cp_sw
= gtk_scrolled_window_new(NULL
, NULL
);
403 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_cp_sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
404 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_cp_sw
), GTK_SHADOW_ETCHED_IN
);
406 /* set initial state */
407 self
->priv
->pl3_cp_tree
= tree
;
408 g_object_ref_sink(G_OBJECT(self
->priv
->pl3_cp_vbox
));
411 static void pl3_current_playlist_browser_select_current_song(PlayQueuePlugin
* self
)
413 if (self
->priv
->pl3_cp_tree
== NULL
|| !gtk_widget_get_realized(self
->priv
->pl3_cp_tree
))
415 /* scroll to the playing song */
416 if (mpd_player_get_current_song_pos(connection
) >= 0 && mpd_playlist_get_playlist_length(connection
) > 0)
418 GtkTreePath
*path
= gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection
), -1);
420 && GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
))))
422 gtk_tree_view_set_cursor(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), path
, NULL
, FALSE
);
424 gtk_tree_path_free(path
);
428 static void pl3_current_playlist_browser_scroll_to_current_song(PlayQueuePlugin
* self
)
430 if (self
->priv
->pl3_cp_tree
== NULL
|| !gtk_widget_get_realized(self
->priv
->pl3_cp_tree
))
432 /* scroll to the playing song */
433 if (mpd_player_get_current_song_pos(connection
) >= 0 && mpd_playlist_get_playlist_length(connection
) > 0)
435 GtkTreePath
*path
= gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection
), -1);
438 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), path
, NULL
, TRUE
, 0.5, 0);
439 gtk_tree_path_free(path
);
445 /* add's the toplevel entry for the current playlist view */
446 static void pl3_current_playlist_browser_add(GmpcPluginBrowserIface
* obj
, GtkWidget
* cat_tree
)
448 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
451 playlist3_insert_browser(&iter
, PL3_CAT_BROWSER_TOP
+1);
452 gtk_list_store_set(GTK_LIST_STORE(pl3_tree
), &iter
, PL3_CAT_TYPE
, GMPC_PLUGIN_BASE(self
)->id
/*current_playlist_plug.id */ , /*PL3_CURRENT_PLAYLIST, */
453 PL3_CAT_TITLE
, _(gmpc_plugin_base_get_name(GMPC_PLUGIN_BASE(self
))),
454 PL3_CAT_ICON_ID
, "playlist-browser", -1);
455 if (self
->priv
->pl3_curb_tree_ref
)
457 gtk_tree_row_reference_free(self
->priv
->pl3_curb_tree_ref
);
458 self
->priv
->pl3_curb_tree_ref
= NULL
;
460 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_tree
), &iter
);
463 self
->priv
->pl3_curb_tree_ref
= gtk_tree_row_reference_new(GTK_TREE_MODEL(pl3_tree
), path
);
464 gtk_tree_path_free(path
);
468 /* delete all selected songs,
469 * if no songs select ask the user if he want's to clear the list
471 static void pl3_current_playlist_browser_delete_selected_songs(PlayQueuePlugin
* self
)
473 /* grab the selection from the tree */
474 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
475 /* check if where connected */
476 /* see if there is a row selected */
477 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
479 GList
*list
= NULL
, *llist
= NULL
;
480 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
481 /* start a command list */
482 /* grab the selected songs */
483 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
484 /* grab the last song that is selected */
485 llist
= g_list_last(list
);
486 /* remove every selected song one by one */
491 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
492 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &value
, -1);
493 mpd_playlist_queue_delete_id(connection
, value
);
494 } while ((llist
= g_list_previous(llist
)));
496 /* close the list, so it will be executed */
497 mpd_playlist_queue_commit(connection
);
498 /* unselect all if multiple songs were selected */
499 if (g_list_length(list
) > 1)
500 gtk_tree_selection_unselect_all(selection
);
502 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
506 pl3_current_playlist_browser_clear_playlist();
509 /* update everything if where still connected */
510 mpd_status_queue_update(connection
);
513 static void pl3_current_playlist_browser_crop_selected_songs(PlayQueuePlugin
* self
)
515 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
516 /* grab the selection from the tree */
517 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
519 /* see if there is a row selected */
520 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
523 /* we want to delete from back to front, so we have to transverse this list */
524 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
))
529 if (!gtk_tree_selection_iter_is_selected(selection
, &iter
))
532 /* song pos starts at 1, not a 0, compensate for that */
533 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
534 mpd_playlist_queue_delete_id(connection
, id
);
536 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
));
538 mpd_playlist_queue_commit(connection
);
539 /* update everything if where still connected */
540 gtk_tree_selection_unselect_all(selection
);
542 mpd_status_queue_update(connection
);
546 static void pl3_current_playlist_editor_add_to_playlist(GtkWidget
* menu
, gpointer cb_data
)
548 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) cb_data
;
549 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
550 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
551 gchar
*data
= g_object_get_data(G_OBJECT(menu
), "playlist");
552 GList
*iter
, *list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
555 iter
= g_list_first(list
);
559 if (gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*) iter
->data
))
562 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, -1);
563 mpd_database_playlist_list_add(connection
, data
, file
);
566 } while ((iter
= g_list_next(iter
)));
568 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
572 playlist_editor_fill_list();
575 static void pl3_current_playlist_browser_paste_after_songs(GtkTreeView
* tree
, GList
* paste_list
,
576 PlayQueuePlugin
* self
)
578 /* grab the selection from the tree */
579 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
582 /* check if where connected */
583 /* see if there is a row selected */
584 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
586 GList
*list
= NULL
, *llist
= NULL
;
587 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
588 /* start a command list */
589 /* grab the selected songs */
590 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
591 /* grab the last song that is selected */
592 llist
= g_list_last(list
);
593 /* remove every selected song one by one */
597 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
598 /* Trick that avoids roundtrip to mpd */
602 int length
= mpd_playlist_get_playlist_length(connection
);
603 GList
*liter
= g_list_first(paste_list
);
604 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_POS
, &id
, -1);
609 song_id
= mpd_playlist_add_get_id(connection
, path
);
610 if (song_id
== -1 && !seen
)
612 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."),
616 mpd_playlist_move_pos(connection
, length
, id
);
618 liter
= g_list_next(liter
);
623 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
627 GList
*liter
= g_list_first(paste_list
);;
630 char *path
= liter
->data
;
631 int song_id
= mpd_playlist_add_get_id(connection
, path
);
632 if (song_id
== -1 && !seen
)
634 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."), ERROR_WARNING
);
637 liter
= g_list_next(liter
);
641 gtk_tree_selection_unselect_all(selection
);
644 static void pl3_current_playlist_browser_paste_before_songs(GtkTreeView
* tree
, GList
* paste_list
,
645 PlayQueuePlugin
* self
)
647 /* grab the selection from the tree */
648 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
651 /* check if where connected */
652 /* see if there is a row selected */
653 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
655 GList
*list
= NULL
, *llist
= NULL
;
656 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
657 /* start a command list */
658 /* grab the selected songs */
659 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
660 /* grab the last song that is selected */
661 llist
= g_list_first(list
);
662 /* remove every selected song one by one */
666 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
667 /* Trick that avoids roundtrip to mpd */
670 int length
= mpd_playlist_get_playlist_length(connection
);
671 GList
*liter
= g_list_first(paste_list
);
672 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_POS
, &id
, -1);
675 char *path
= liter
->data
;
676 int song_id
= mpd_playlist_add_get_id(connection
, path
);
677 if (song_id
== -1 && !seen
)
679 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."),
683 mpd_playlist_move_pos(connection
, length
, id
- 1);
684 /* The song is now one lower */
685 /* length one longer */
687 liter
= g_list_next(liter
);
692 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
696 GList
*liter
= g_list_first(paste_list
);
699 char *path
= liter
->data
;
700 int song_id
= mpd_playlist_add_get_id(connection
, path
);
701 if (song_id
== -1 && !seen
)
703 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."), ERROR_WARNING
);
706 liter
= g_list_next(liter
);
711 gtk_tree_selection_unselect_all(selection
);
714 static int pl3_current_playlist_browser_button_release_event(GtkTreeView
* tree
, GdkEventButton
* event
,
715 PlayQueuePlugin
* self
)
717 if (event
->button
== 3)
721 GtkWidget
*menu
= gtk_menu_new();
723 int rows
= gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(tree
));
724 /* add the delete widget */
725 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_REMOVE
, NULL
);
726 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
727 g_signal_connect_swapped(G_OBJECT(item
), "activate",
728 G_CALLBACK(pl3_current_playlist_browser_delete_selected_songs
), self
);
732 /* add the delete widget */
733 item
= gtk_image_menu_item_new_with_label(_("Crop"));
734 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
735 gtk_image_new_from_stock(GTK_STOCK_CUT
, GTK_ICON_SIZE_MENU
));
736 g_signal_connect_swapped(G_OBJECT(item
), "activate",
737 G_CALLBACK(pl3_current_playlist_browser_crop_selected_songs
), self
);
738 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
740 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), gtk_separator_menu_item_new());
741 /* add the clear widget */
742 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR
, NULL
);
743 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
744 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist
), NULL
);
746 /* add the shuffle widget */
747 item
= gtk_image_menu_item_new_with_label(_("Shuffle"));
748 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
749 gtk_image_new_from_stock(GTK_STOCK_REFRESH
, GTK_ICON_SIZE_MENU
));
750 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_shuffle_playlist
), NULL
);
751 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
753 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), gtk_separator_menu_item_new());
755 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
758 item
= gtk_menu_item_new_with_label(_("Raise priority"));
759 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
760 g_signal_connect_swapped(G_OBJECT(item
), "activate",
761 G_CALLBACK(pl3_current_playlist_browser_priority_raise_selected_songs
), self
);
762 /* remove priority */
763 item
= gtk_menu_item_new_with_label(_("Remove priority"));
764 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
765 g_signal_connect_swapped(G_OBJECT(item
), "activate",
766 G_CALLBACK(pl3_current_playlist_browser_priority_remove_selected_songs
), self
);
773 GtkTreeModel
*model
= gtk_tree_view_get_model(tree
);
776 gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
)), &model
);
778 if (path
&& gtk_tree_model_get_iter(model
, &iter
, path
))
780 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
783 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO
, NULL
);
784 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
785 g_signal_connect_swapped(G_OBJECT(item
), "activate",
786 G_CALLBACK(pl3_current_playlist_browser_show_info
), self
);
788 /* Add song sebmenu */
789 submenu_for_song(menu
, song
);
792 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
796 playlist_editor_right_mouse(menu
, pl3_current_playlist_editor_add_to_playlist
, self
);
797 gmpc_mpddata_treeview_right_mouse_intergration(GMPC_MPDDATA_TREEVIEW(tree
), GTK_MENU(menu
));
798 gtk_widget_show_all(menu
);
799 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
805 static void pl3_current_playlist_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* path
, GtkTreeViewColumn
* col
,
806 PlayQueuePlugin
* self
)
810 GtkTreeModel
*model
= gtk_tree_view_get_model(tree
);
811 gtk_tree_model_get_iter(model
, &iter
, path
);
812 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &song_id
, -1);
813 mpd_player_play_id(connection
, song_id
);
815 if (!self
->priv
->search_keep_open
&& model
== self
->priv
->mod_fill
)
817 gtk_tree_view_set_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), playlist
);
819 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(self
->priv
->mod_fill
), NULL
);
820 self
->priv
->quick_search
= 0;
821 gtk_widget_hide(self
->priv
->filter_entry
);
823 pl3_current_playlist_browser_select_current_song(self
);
828 static void pl3_current_playlist_browser_show_info(PlayQueuePlugin
* self
)
831 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
832 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
833 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
836 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
838 list
= g_list_last(list
);
842 mpd_Song
*song
= NULL
;
843 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) list
->data
);
844 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
847 info2_fill_song_view(song
);
850 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
855 static void pl3_current_playlist_browser_selected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
)
857 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
858 gboolean init
= FALSE
;
859 if (self
->priv
->pl3_cp_vbox
== NULL
)
861 pl3_current_playlist_browser_init((PlayQueuePlugin
*) obj
);
864 gtk_container_add(GTK_CONTAINER(container
), self
->priv
->pl3_cp_vbox
);
865 gtk_widget_show(self
->priv
->pl3_cp_vbox
);
867 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
869 if (init
&& cfg_get_single_value_as_int_with_default(config
, "playlist", "st_cur_song", 0))
871 pl3_current_playlist_browser_scroll_to_current_song(self
);
872 pl3_current_playlist_browser_select_current_song(self
);
876 static void pl3_current_playlist_browser_unselected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
)
878 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
879 gtk_container_remove(GTK_CONTAINER(container
), self
->priv
->pl3_cp_vbox
);
881 static void pl3_current_playlist_add_after_current_song(GtkWidget
*item
, GtkTreeView
*tree
)
883 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
));
884 int cur_song_pos
= mpd_player_get_current_song_pos(connection
);
885 GList
*list
, *list_iter
;
887 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
890 for(list_iter
= g_list_first(list
); list_iter
!= NULL
; list_iter
= g_list_next(list_iter
))
893 GtkTreePath
*path
= (GtkTreePath
*)list_iter
->data
;
894 /* Convert the path into an actual iter we can use to get values from the model */
895 if(gtk_tree_model_get_iter(model
, &iter
,path
))
897 mpd_Song
*song
= NULL
;
898 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
899 if(song
!= NULL
&& song
->file
!= NULL
)
901 int songid
= mpd_playlist_add_get_id(connection
, (gchar
*) song
->file
);
902 if(cur_song_pos
>= 0)
905 mpd_playlist_move_id(connection
, songid
, cur_song_pos
);
910 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
915 static int pl3_current_playlist_song_list_option_menu (GmpcPluginBrowserIface
*obj
, GtkWidget
*tree
, GtkMenu
*menu
)
917 printf("list option menu\n");
918 if(mpd_check_connected(connection
) && !mpd_player_get_random(connection
))
920 GtkWidget
*item
= gtk_image_menu_item_new_with_label(_("Add after current song"));
921 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
922 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_add_after_current_song
), tree
);
928 static int pl3_current_playlist_browser_option_menu(GmpcPluginBrowserIface
* obj
, GtkMenu
* menu
)
930 /* here we have: Save, Clear */
933 /* add the save widget */
934 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE
, NULL
);
935 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
936 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_save_playlist
), NULL
);
938 /* add the clear widget */
939 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR
, NULL
);
940 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
941 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist
), NULL
);
946 static int pl3_current_playlist_tool_menu_integration(GmpcPluginToolMenuIface
* obj
, GtkMenu
* menu
)
949 item
= gtk_image_menu_item_new_with_label(_("Add URL"));
950 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
951 gtk_image_new_from_icon_name("add-url", GTK_ICON_SIZE_MENU
));
952 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
953 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(url_start
), NULL
);
958 static int pl3_current_playlist_browser_key_press_event(GtkTreeView
* tree
, GdkEventKey
* event
,
959 PlayQueuePlugin
* self
)
961 if (event
->keyval
== GDK_KEY_Delete
)
963 pl3_current_playlist_browser_delete_selected_songs(self
);
965 } else if (event
->keyval
== GDK_KEY_i
&& event
->state
& GDK_MOD1_MASK
)
967 pl3_current_playlist_browser_show_info(self
);
969 } else if (event
->state
&GDK_MOD1_MASK
&& event
->keyval
== GDK_KEY_q
)
971 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
973 pl3_current_playlist_browser_priority_raise_selected_songs(self
);
975 } else if (event
->state
&GDK_MOD1_MASK
&& event
->keyval
== GDK_KEY_d
)
977 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
979 pl3_current_playlist_browser_priority_remove_selected_songs(self
);
981 } else if (event
->keyval
== GDK_KEY_space
)
983 pl3_current_playlist_browser_scroll_to_current_song(self
);
984 pl3_current_playlist_browser_select_current_song(self
);
986 } else if (event
->keyval
== GDK_KEY_f
&& event
->state
& GDK_CONTROL_MASK
)
988 mod_fill_entry_changed(self
->priv
->filter_entry
, self
);
989 gtk_widget_grab_focus(self
->priv
->filter_entry
);
990 self
->priv
->search_keep_open
= TRUE
;
992 } else if ((event
->state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
)) == 0) /*&&
993 ((event->keyval >= GDK_space && event->keyval <= GDK_z))) */
996 guint32 uc
= gdk_keyval_to_unicode(event
->keyval
);
997 if (uc
&& g_unichar_isalnum(uc
))
999 memset(data
, '\0', 10);
1000 g_unichar_to_utf8(uc
, data
);
1001 gtk_widget_grab_focus(self
->priv
->filter_entry
);
1002 gtk_entry_set_text(GTK_ENTRY(self
->priv
->filter_entry
), data
);
1003 gtk_editable_set_position(GTK_EDITABLE(self
->priv
->filter_entry
), 1);
1008 return pl3_window_key_press_event(GTK_WIDGET(tree
), event
);
1011 /* create a dialog that allows the user to save the current playlist */
1012 static void pl3_current_playlist_save_playlist(void)
1015 GtkBuilder
*xml
= NULL
;
1017 /* check if the connection is up */
1018 if (!mpd_check_connected(connection
))
1022 /* create the interface */
1023 str
= gmpc_get_full_glade_path("playlist-save-dialog.ui");
1024 xml
= gtk_builder_new();
1025 gtk_builder_add_from_file(xml
, str
, NULL
);
1028 /* run the interface */
1031 switch (gtk_dialog_run(GTK_DIALOG(gtk_builder_get_object(xml
, "save_pl"))))
1033 case GTK_RESPONSE_OK
:
1035 /* if the users agrees do the following: */
1036 /* get the song-name */
1037 str
= (gchar
*) gtk_entry_get_text(GTK_ENTRY((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")));
1038 /* check if the user entered a name, we can't do withouth */
1039 /* TODO: disable ok button when nothing is entered */
1040 /* also check if there is a connection */
1041 if (strlen(str
) != 0 && mpd_check_connected(connection
))
1043 int retv
= mpd_database_save_playlist(connection
, str
);
1044 if (retv
== MPD_DATABASE_PLAYLIST_EXIST
)
1047 g_markup_printf_escaped(_("<i>Playlist <b>\"%s\"</b> already exists\nOverwrite?</i>"), str
);
1048 gtk_label_set_markup(GTK_LABEL((GtkWidget
*) gtk_builder_get_object(xml
, "label_error")), errormsg
);
1049 gtk_widget_show((GtkWidget
*) gtk_builder_get_object(xml
, "hbox5"));
1050 /* ask to replace */
1051 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")), FALSE
);
1052 switch (gtk_dialog_run(GTK_DIALOG((GtkWidget
*) gtk_builder_get_object(xml
, "save_pl"))))
1054 case GTK_RESPONSE_OK
:
1056 mpd_database_delete_playlist(connection
, str
);
1057 mpd_database_save_playlist(connection
, str
);
1058 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
1063 /* return to stare */
1064 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")), TRUE
);
1065 gtk_widget_hide((GtkWidget
*) gtk_builder_get_object(xml
, "hbox5"));
1068 } else if (retv
!= MPD_OK
)
1070 playlist3_show_error_message(_("Failed to save the playlist file."), ERROR_WARNING
);
1073 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
1081 /* destroy the window */
1082 gtk_widget_destroy((GtkWidget
*) gtk_builder_get_object(xml
, "save_pl"));
1084 /* unref the gui description */
1085 g_object_unref(xml
);
1088 static void pl3_current_playlist_browser_clear_playlist(void)
1091 if(cfg_get_single_value_as_int(config
, "playlist","no-confirm-clear") != 1)
1094 delete = gtk_button_new_from_stock(GTK_STOCK_CLEAR
);
1095 g_signal_connect(G_OBJECT(delete),
1097 G_CALLBACK(pl3_current_playlist_browser_clear_playlist_real
),
1101 playlist3_message_show(pl3_messages
,
1102 _("Are you sure you want to clear the play queue?")
1104 playlist3_message_add_widget(pl3_messages
, delete);
1105 gtk_widget_grab_focus(GTK_WIDGET(delete));
1108 pl3_current_playlist_browser_clear_playlist_real();
1112 static void pl3_current_playlist_browser_shuffle_playlist(void)
1114 mpd_playlist_shuffle(connection
);
1117 static void pl3_current_playlist_status_changed(GmpcConnection
* conn
, MpdObj
* mi
, ChangedStatusType what
,
1118 PlayQueuePlugin
* self
)
1120 if (self
->priv
->pl3_cp_vbox
== NULL
)
1122 if (what
& MPD_CST_PLAYLIST
)
1125 if (self
->priv
->quick_search
)
1126 mod_fill_do_entry_changed(self
);
1130 static void pl3_current_playlist_browser_activate(PlayQueuePlugin
* self
)
1132 GtkTreeSelection
*selec
= gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml
, "cat_tree")));
1134 GtkTreePath
*path
= gtk_tree_row_reference_get_path(self
->priv
->pl3_curb_tree_ref
);
1137 gtk_tree_selection_select_path(selec
, path
);
1138 gtk_tree_path_free(path
);
1140 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
1143 static void pl3_current_playlist_do_playlist_search(GmpcPluginBase
* self
)
1145 pl3_find2_select_plugin_id(self
->id
);
1148 static int pl3_current_playlist_browser_add_go_menu(GmpcPluginBrowserIface
* obj
, GtkMenu
* menu
)
1150 GtkWidget
*item
= NULL
;
1152 item
= gtk_image_menu_item_new_with_label(_("Play Queue"));
1153 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1154 gtk_image_new_from_icon_name("playlist-browser", GTK_ICON_SIZE_MENU
));
1155 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1156 gtk_widget_add_accelerator(GTK_WIDGET(item
), "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_F1
, 0,
1158 g_signal_connect_swapped(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_activate
), obj
);
1160 item
= gtk_image_menu_item_new_with_label(_("Search Playlist"));
1161 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1162 gtk_image_new_from_icon_name("gtk-find", GTK_ICON_SIZE_MENU
));
1163 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1164 gtk_widget_add_accelerator(GTK_WIDGET(item
), "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_j
,
1165 GDK_CONTROL_MASK
, GTK_ACCEL_VISIBLE
);
1166 g_signal_connect_swapped(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_do_playlist_search
), obj
);
1170 static void pl3_current_playlist_connection_changed(GmpcConnection
* conn
, MpdObj
* mi
, int connect
,
1171 PlayQueuePlugin
* self
)
1173 if (!connect
&& self
->priv
->filter_entry
)
1175 gtk_entry_set_text(GTK_ENTRY(self
->priv
->filter_entry
), "");
1179 /* function that saves the settings */
1180 static void pl3_current_playlist_save_myself(GmpcPluginBase
* obj
)
1182 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
1183 if (self
->priv
->pl3_curb_tree_ref
)
1185 GtkTreePath
*path
= gtk_tree_row_reference_get_path(self
->priv
->pl3_curb_tree_ref
);
1188 gint
*indices
= gtk_tree_path_get_indices(path
);
1189 cfg_set_single_value_as_int(config
, "current-playlist", "position", indices
[0]);
1190 gtk_tree_path_free(path
);
1198 GType
play_queue_plugin_get_type(void);
1200 static int *play_queue_plugin_get_version(GmpcPluginBase
* plug
, int *length
)
1202 static int version
[3] = { 0, 0, 1 };
1205 return (int *)version
;
1208 static const char *play_queue_plugin_get_name(GmpcPluginBase
* plug
)
1210 return N_("Play Queue");
1213 static void play_queue_plugin_finalize(GObject
* obj
)
1215 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
1216 PlayQueuePluginClass
*klass
= (g_type_class_peek(play_queue_plugin_get_type()));
1217 gpointer parent_class
= g_type_class_peek_parent(klass
);
1218 pl3_current_playlist_destroy((PlayQueuePlugin
*) obj
);
1222 if (self
->priv
->uid
)
1224 g_free(self
->priv
->uid
);
1225 self
->priv
->uid
= NULL
;
1227 if (self
->priv
->mod_fill
)
1229 g_object_unref(self
->priv
->mod_fill
);
1230 self
->priv
->mod_fill
= NULL
;
1232 if (g_signal_handler_is_connected(G_OBJECT(gmpcconn
), self
->priv
->status_changed_handler
))
1233 g_signal_handler_disconnect(G_OBJECT(gmpcconn
), self
->priv
->status_changed_handler
);
1235 if (g_signal_handler_is_connected(G_OBJECT(gmpcconn
), self
->priv
->connection_changed_handler
))
1236 g_signal_handler_disconnect(G_OBJECT(gmpcconn
), self
->priv
->connection_changed_handler
);
1241 G_OBJECT_CLASS(parent_class
)->finalize(obj
);
1244 static GObject
*play_queue_plugin_constructor(GType type
, guint n_construct_properties
,
1245 GObjectConstructParam
* construct_properties
)
1247 PlayQueuePluginClass
*klass
;
1248 PlayQueuePlugin
*self
;
1249 GObjectClass
*parent_class
;
1250 klass
= (g_type_class_peek(play_queue_plugin_get_type()));
1251 parent_class
= G_OBJECT_CLASS(g_type_class_peek_parent(klass
));
1252 self
= (PlayQueuePlugin
*) parent_class
->constructor(type
, n_construct_properties
, construct_properties
);
1254 /* setup private structure */
1255 self
->priv
= g_malloc0(sizeof(PlayQueuePluginPrivate
));
1256 self
->priv
->status_changed_handler
=
1257 g_signal_connect_object(G_OBJECT(gmpcconn
), "status-changed", G_CALLBACK(pl3_current_playlist_status_changed
),
1259 self
->priv
->connection_changed_handler
=
1260 g_signal_connect_object(G_OBJECT(gmpcconn
), "connection-changed",
1261 G_CALLBACK(pl3_current_playlist_connection_changed
), self
, 0);
1263 self
->priv
->search_keep_open
= FALSE
;
1264 self
->priv
->filter_entry
= NULL
;
1265 self
->priv
->mod_fill
= NULL
;
1266 self
->priv
->quick_search
= 0;
1267 self
->priv
->quick_search_timeout
= 0;
1269 self
->priv
->pl3_cp_tree
= NULL
;
1270 self
->priv
->pl3_cp_vbox
= NULL
;
1271 self
->priv
->pl3_curb_tree_ref
= NULL
;
1273 /* Make it an internal plugin */
1274 GMPC_PLUGIN_BASE(self
)->plugin_type
= GMPC_PLUGIN_PL_BROWSER
| GMPC_INTERNALL
;
1277 return G_OBJECT(self
);
1281 * Base GmpcPluginBase class
1283 static void play_queue_plugin_class_init(PlayQueuePluginClass
* klass
)
1285 /* Connect destroy and construct */
1286 G_OBJECT_CLASS(klass
)->finalize
= play_queue_plugin_finalize
;
1287 G_OBJECT_CLASS(klass
)->constructor
= play_queue_plugin_constructor
;
1288 G_OBJECT_CLASS(klass
)->get_property
= play_queue_get_property
;
1289 G_OBJECT_CLASS(klass
)->set_property
= play_queue_set_property
;
1290 /* Connect plugin functions */
1291 GMPC_PLUGIN_BASE_CLASS(klass
)->get_version
= play_queue_plugin_get_version
;
1292 GMPC_PLUGIN_BASE_CLASS(klass
)->get_name
= play_queue_plugin_get_name
;
1294 GMPC_PLUGIN_BASE_CLASS(klass
)->save_yourself
= pl3_current_playlist_save_myself
;
1296 g_object_class_install_property(G_OBJECT_CLASS(klass
), PLAY_QUEUE_UID
,
1297 g_param_spec_string("uid", "uid", "stores an unique id", "play-queue",
1298 G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
1299 | G_PARAM_READABLE
| G_PARAM_WRITABLE
));
1306 static void play_queue_browser_iface_init(GmpcPluginBrowserIfaceIface
* iface
)
1308 iface
->browser_add
= pl3_current_playlist_browser_add
;
1309 iface
->browser_selected
= pl3_current_playlist_browser_selected
;
1310 iface
->browser_unselected
= pl3_current_playlist_browser_unselected
;
1311 iface
->browser_option_menu
= pl3_current_playlist_browser_option_menu
;
1312 iface
->browser_add_go_menu
= pl3_current_playlist_browser_add_go_menu
;
1315 static void play_queue_song_list_iface_init(GmpcPluginSongListIfaceIface
*iface
)
1317 iface
->song_list
= pl3_current_playlist_song_list_option_menu
;
1321 * Tool menu interface
1323 static void play_queue_plugin_tool_menu_iface_init(GmpcPluginToolMenuIfaceIface
* iface
)
1325 iface
->tool_menu_integration
= pl3_current_playlist_tool_menu_integration
;
1328 /* Integrate Search */
1329 static gboolean
play_queue_plugin_is_field_supported(GmpcPluginIntegrateSearchIface
* obj
, mpd_TagItems tag
)
1331 if (tag
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1333 return mpd_server_tag_supported(connection
, tag
);
1336 static MpdData
*play_queue_plugin_is_search(GmpcPluginIntegrateSearchIface
* obj
, mpd_TagItems num_field
,
1337 const gchar
* search_string
)
1339 MpdData
*data_t
= NULL
;
1340 if (num_field
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1342 data_t
= advanced_search(search_string
, TRUE
);
1345 gchar
**splitted
= tokenize_string(search_string
);
1347 gboolean found
= FALSE
;
1348 for (i
= 0; splitted
&& splitted
[i
]; i
++)
1352 mpd_playlist_search_start(connection
, FALSE
);
1355 mpd_playlist_search_add_constraint(connection
, num_field
, splitted
[i
]);
1358 g_strfreev(splitted
);
1361 data_t
= mpd_playlist_search_commit(connection
);
1367 static void play_queue_plugin_is_iface_init(GmpcPluginIntegrateSearchIfaceIface
* iface
)
1369 iface
->field_supported
= play_queue_plugin_is_field_supported
;
1370 iface
->search
= play_queue_plugin_is_search
;
1373 GType
play_queue_plugin_get_type(void)
1375 static GType play_queue_plugin_type_id
= 0;
1376 if (play_queue_plugin_type_id
== 0)
1378 static const GTypeInfo info
= {
1379 .class_size
= sizeof(PlayQueuePluginClass
),
1380 .class_init
= (GClassInitFunc
) play_queue_plugin_class_init
,
1381 .instance_size
= sizeof(PlayQueuePlugin
),
1384 static const GInterfaceInfo iface_info
= {
1385 (GInterfaceInitFunc
) play_queue_browser_iface_init
,
1386 (GInterfaceFinalizeFunc
) NULL
, NULL
1388 static const GInterfaceInfo iface_song_list
= {
1389 (GInterfaceInitFunc
) play_queue_song_list_iface_init
,
1390 (GInterfaceFinalizeFunc
) NULL
, NULL
1392 static const GInterfaceInfo iface_tm_info
= {
1393 (GInterfaceInitFunc
) play_queue_plugin_tool_menu_iface_init
,
1394 (GInterfaceFinalizeFunc
) NULL
, NULL
1397 static const GInterfaceInfo iface_is_info
= {
1398 (GInterfaceInitFunc
) play_queue_plugin_is_iface_init
,
1399 (GInterfaceFinalizeFunc
) NULL
, NULL
1401 play_queue_plugin_type_id
= g_type_register_static(GMPC_PLUGIN_TYPE_BASE
, "PlayQueuePlugin", &info
, 0);
1403 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_BROWSER_IFACE
, &iface_info
);
1404 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_TOOL_MENU_IFACE
, &iface_tm_info
);
1405 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_INTEGRATE_SEARCH_IFACE
, &iface_is_info
);
1406 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_SONG_LIST_IFACE
, &iface_song_list
);
1408 return play_queue_plugin_type_id
;
1411 PlayQueuePlugin
*play_queue_plugin_new(const gchar
* uid
)
1413 PlayQueuePlugin
*plug
= g_object_new(play_queue_plugin_get_type(), "uid", uid
, NULL
);
1423 static void pl3_current_playlist_browser_priority_raise_selected_songs(PlayQueuePlugin
* self
)
1425 GList
*list
= NULL
, *llist
= NULL
;
1426 GtkTreeModel
*model
= NULL
;
1428 /* grab the selection from the tree */
1429 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
1431 int sel_rows
= gtk_tree_selection_count_selected_rows(selection
);
1433 if(sel_rows
>= 254) {
1434 playlist3_show_error_message(_("You can only queue 254 songs at the time."),
1438 else if (sel_rows
== 0)
1443 /* start a command list */
1444 /* grab the selected songs */
1445 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1446 /* grab the last song that is selected */
1447 /* remove every selected song one by one */
1451 llist
= g_list_first(list
);
1456 if(gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
))
1459 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
1460 mpd_playlist_set_priority(connection
, id
, priority
--);
1462 llist
= g_list_next(llist
);
1465 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
1469 static void pl3_current_playlist_browser_priority_remove_selected_songs(PlayQueuePlugin
* self
)
1471 GList
*list
= NULL
, *llist
= NULL
;
1472 GtkTreeModel
*model
= NULL
;
1473 /* grab the selection from the tree */
1474 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
1476 int sel_rows
= gtk_tree_selection_count_selected_rows(selection
);
1483 /* start a command list */
1484 /* grab the selected songs */
1485 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1486 /* grab the last song that is selected */
1487 /* remove every selected song one by one */
1490 llist
= g_list_first(list
);
1495 if(gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
))
1498 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
1499 mpd_playlist_set_priority(connection
, id
, 0);
1501 llist
= g_list_next(llist
);
1504 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);