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_data_view_new(self
->priv
->uid
);//gmpc_mpddata_treeview_new(self->priv->uid, FALSE, GTK_TREE_MODEL(playlist));
358 gmpc_data_view_set_is_play_queue(GMPC_DATA_VIEW(tree
), TRUE
);
359 gtk_tree_view_set_model(GTK_TREE_VIEW(tree
), GTK_TREE_MODEL(playlist
));
361 gmpc_data_view_populate(GMPC_DATA_VIEW(tree
));
363 g_signal_connect(G_OBJECT(tree
), "paste_before", G_CALLBACK(pl3_current_playlist_browser_paste_before_songs
), self
);
364 g_signal_connect(G_OBJECT(tree
), "paste_after", G_CALLBACK(pl3_current_playlist_browser_paste_after_songs
), self
);
365 g_signal_connect_swapped(G_OBJECT(tree
), "cut", G_CALLBACK(pl3_current_playlist_browser_delete_selected_songs
),
369 /* Enable this for this model only */
370 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(tree
), gmt_targetentries
, 1, GDK_ACTION_DEFAULT
|GDK_ACTION_MOVE
|GDK_ACTION_COPY
);
373 self
->priv
->mod_fill
= (GtkTreeModel
*) gmpc_mpddata_model_new();
374 entry
= gtk_entry_new();
375 gtk_entry_set_icon_from_stock(GTK_ENTRY(entry
), GTK_ENTRY_ICON_SECONDARY
, GTK_STOCK_CLEAR
);
376 g_signal_connect(GTK_ENTRY(entry
), "icon-press", G_CALLBACK(mod_fill_clear_search_entry
), NULL
);
378 gtk_entry_set_icon_from_stock(GTK_ENTRY(entry
), GTK_ENTRY_ICON_PRIMARY
, GTK_STOCK_FIND
);
379 gtk_entry_set_icon_activatable(GTK_ENTRY(entry
), GTK_ENTRY_ICON_PRIMARY
, FALSE
);
382 gtk_box_pack_end(GTK_BOX(self
->priv
->pl3_cp_vbox
), entry
, FALSE
, TRUE
, 0);
383 self
->priv
->filter_entry
= entry
;
384 g_signal_connect(G_OBJECT(entry
), "changed", G_CALLBACK(mod_fill_entry_changed
), self
);
385 g_signal_connect(G_OBJECT(entry
), "key-press-event", G_CALLBACK(mod_fill_entry_key_press_event
), self
);
386 g_signal_connect(G_OBJECT(entry
), "activate", G_CALLBACK(mod_fill_entry_activate
), self
);
388 sw
= gtk_scrolled_window_new(NULL
, NULL
);
389 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
390 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
), GTK_SHADOW_ETCHED_IN
);
391 gtk_container_add(GTK_CONTAINER(sw
), tree
);
392 gtk_box_pack_start(GTK_BOX(self
->priv
->pl3_cp_vbox
), GTK_WIDGET(sw
), TRUE
, TRUE
, 0);
393 gtk_widget_show_all(sw
);
394 /* set up the tree */
395 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree
), FALSE
);
397 //gmpc_mpddata_treeview_enable_click_fix(GMPC_MPDDATA_TREEVIEW(tree));
399 g_signal_connect(G_OBJECT(tree
), "row-activated", G_CALLBACK(pl3_current_playlist_browser_row_activated
), self
);
400 g_signal_connect(G_OBJECT(tree
), "button-release-event",
401 G_CALLBACK(pl3_current_playlist_browser_button_release_event
), self
);
402 g_signal_connect(G_OBJECT(tree
), "key-press-event", G_CALLBACK(pl3_current_playlist_browser_key_press_event
),
405 /* set up the scrolled window */
406 pl3_cp_sw
= gtk_scrolled_window_new(NULL
, NULL
);
407 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_cp_sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
408 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_cp_sw
), GTK_SHADOW_ETCHED_IN
);
410 /* set initial state */
411 self
->priv
->pl3_cp_tree
= tree
;
412 g_object_ref_sink(G_OBJECT(self
->priv
->pl3_cp_vbox
));
415 static void pl3_current_playlist_browser_select_current_song(PlayQueuePlugin
* self
)
417 if (self
->priv
->pl3_cp_tree
== NULL
|| !gtk_widget_get_realized(self
->priv
->pl3_cp_tree
))
419 /* scroll to the playing song */
420 if (mpd_player_get_current_song_pos(connection
) >= 0 && mpd_playlist_get_playlist_length(connection
) > 0)
422 GtkTreePath
*path
= gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection
), -1);
424 && GMPC_IS_MPDDATA_MODEL_PLAYLIST(gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
))))
426 gtk_tree_view_set_cursor(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), path
, NULL
, FALSE
);
428 gtk_tree_path_free(path
);
432 static void pl3_current_playlist_browser_scroll_to_current_song(PlayQueuePlugin
* self
)
434 if (self
->priv
->pl3_cp_tree
== NULL
|| !gtk_widget_get_realized(self
->priv
->pl3_cp_tree
))
436 /* scroll to the playing song */
437 if (mpd_player_get_current_song_pos(connection
) >= 0 && mpd_playlist_get_playlist_length(connection
) > 0)
439 GtkTreePath
*path
= gtk_tree_path_new_from_indices(mpd_player_get_current_song_pos(connection
), -1);
442 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), path
, NULL
, TRUE
, 0.5, 0);
443 gtk_tree_path_free(path
);
449 /* add's the toplevel entry for the current playlist view */
450 static void pl3_current_playlist_browser_add(GmpcPluginBrowserIface
* obj
, GtkWidget
* cat_tree
)
452 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
455 playlist3_insert_browser(&iter
, PL3_CAT_BROWSER_TOP
+1);
456 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, */
457 PL3_CAT_TITLE
, _(gmpc_plugin_base_get_name(GMPC_PLUGIN_BASE(self
))),
458 PL3_CAT_ICON_ID
, "playlist-browser", -1);
459 if (self
->priv
->pl3_curb_tree_ref
)
461 gtk_tree_row_reference_free(self
->priv
->pl3_curb_tree_ref
);
462 self
->priv
->pl3_curb_tree_ref
= NULL
;
464 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_tree
), &iter
);
467 self
->priv
->pl3_curb_tree_ref
= gtk_tree_row_reference_new(GTK_TREE_MODEL(pl3_tree
), path
);
468 gtk_tree_path_free(path
);
472 /* delete all selected songs,
473 * if no songs select ask the user if he want's to clear the list
475 static void pl3_current_playlist_browser_delete_selected_songs(PlayQueuePlugin
* self
)
477 /* grab the selection from the tree */
478 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
479 /* check if where connected */
480 /* see if there is a row selected */
481 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
483 GList
*list
= NULL
, *llist
= NULL
;
484 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
485 /* start a command list */
486 /* grab the selected songs */
487 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
488 /* grab the last song that is selected */
489 llist
= g_list_last(list
);
490 /* remove every selected song one by one */
495 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
496 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &value
, -1);
497 mpd_playlist_queue_delete_id(connection
, value
);
498 } while ((llist
= g_list_previous(llist
)));
500 /* close the list, so it will be executed */
501 mpd_playlist_queue_commit(connection
);
502 /* unselect all if multiple songs were selected */
503 if (g_list_length(list
) > 1)
504 gtk_tree_selection_unselect_all(selection
);
506 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
510 pl3_current_playlist_browser_clear_playlist();
513 /* update everything if where still connected */
514 mpd_status_queue_update(connection
);
517 static void pl3_current_playlist_browser_crop_selected_songs(PlayQueuePlugin
* self
)
519 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
520 /* grab the selection from the tree */
521 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
523 /* see if there is a row selected */
524 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
527 /* we want to delete from back to front, so we have to transverse this list */
528 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model
), &iter
))
533 if (!gtk_tree_selection_iter_is_selected(selection
, &iter
))
536 /* song pos starts at 1, not a 0, compensate for that */
537 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
538 mpd_playlist_queue_delete_id(connection
, id
);
540 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(model
), &iter
));
542 mpd_playlist_queue_commit(connection
);
543 /* update everything if where still connected */
544 gtk_tree_selection_unselect_all(selection
);
546 mpd_status_queue_update(connection
);
550 static void pl3_current_playlist_editor_add_to_playlist(GtkWidget
* menu
, gpointer cb_data
)
552 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) cb_data
;
553 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
554 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
555 gchar
*data
= g_object_get_data(G_OBJECT(menu
), "playlist");
556 GList
*iter
, *list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
559 iter
= g_list_first(list
);
563 if (gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*) iter
->data
))
566 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, -1);
567 mpd_database_playlist_list_add(connection
, data
, file
);
570 } while ((iter
= g_list_next(iter
)));
572 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
576 playlist_editor_fill_list();
579 static void pl3_current_playlist_browser_paste_after_songs(GtkTreeView
* tree
, GList
* paste_list
,
580 PlayQueuePlugin
* self
)
582 /* grab the selection from the tree */
583 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
586 /* check if where connected */
587 /* see if there is a row selected */
588 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
590 GList
*list
= NULL
, *llist
= NULL
;
591 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
592 /* start a command list */
593 /* grab the selected songs */
594 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
595 /* grab the last song that is selected */
596 llist
= g_list_last(list
);
597 /* remove every selected song one by one */
601 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
602 /* Trick that avoids roundtrip to mpd */
606 int length
= mpd_playlist_get_playlist_length(connection
);
607 GList
*liter
= g_list_first(paste_list
);
608 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_POS
, &id
, -1);
613 song_id
= mpd_playlist_add_get_id(connection
, path
);
614 if (song_id
== -1 && !seen
)
616 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."),
620 mpd_playlist_move_pos(connection
, length
, id
);
622 liter
= g_list_next(liter
);
627 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
631 GList
*liter
= g_list_first(paste_list
);;
634 char *path
= liter
->data
;
635 int song_id
= mpd_playlist_add_get_id(connection
, path
);
636 if (song_id
== -1 && !seen
)
638 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."), ERROR_WARNING
);
641 liter
= g_list_next(liter
);
645 gtk_tree_selection_unselect_all(selection
);
648 static void pl3_current_playlist_browser_paste_before_songs(GtkTreeView
* tree
, GList
* paste_list
,
649 PlayQueuePlugin
* self
)
651 /* grab the selection from the tree */
652 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
655 /* check if where connected */
656 /* see if there is a row selected */
657 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
659 GList
*list
= NULL
, *llist
= NULL
;
660 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
661 /* start a command list */
662 /* grab the selected songs */
663 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
664 /* grab the last song that is selected */
665 llist
= g_list_first(list
);
666 /* remove every selected song one by one */
670 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
);
671 /* Trick that avoids roundtrip to mpd */
674 int length
= mpd_playlist_get_playlist_length(connection
);
675 GList
*liter
= g_list_first(paste_list
);
676 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_POS
, &id
, -1);
679 char *path
= liter
->data
;
680 int song_id
= mpd_playlist_add_get_id(connection
, path
);
681 if (song_id
== -1 && !seen
)
683 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."),
687 mpd_playlist_move_pos(connection
, length
, id
- 1);
688 /* The song is now one lower */
689 /* length one longer */
691 liter
= g_list_next(liter
);
696 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
700 GList
*liter
= g_list_first(paste_list
);
703 char *path
= liter
->data
;
704 int song_id
= mpd_playlist_add_get_id(connection
, path
);
705 if (song_id
== -1 && !seen
)
707 playlist3_show_error_message(_("Your mpd has a broken 'addid', pasting will fail."), ERROR_WARNING
);
710 liter
= g_list_next(liter
);
715 gtk_tree_selection_unselect_all(selection
);
718 static int pl3_current_playlist_browser_button_release_event(GtkTreeView
* tree
, GdkEventButton
* event
,
719 PlayQueuePlugin
* self
)
721 if (event
->button
== 3)
725 GtkWidget
*menu
= gtk_menu_new();
727 int rows
= gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(tree
));
728 /* add the delete widget */
729 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_REMOVE
, NULL
);
730 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
731 g_signal_connect_swapped(G_OBJECT(item
), "activate",
732 G_CALLBACK(pl3_current_playlist_browser_delete_selected_songs
), self
);
736 /* add the delete widget */
737 item
= gtk_image_menu_item_new_with_label(_("Crop"));
738 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
739 gtk_image_new_from_stock(GTK_STOCK_CUT
, GTK_ICON_SIZE_MENU
));
740 g_signal_connect_swapped(G_OBJECT(item
), "activate",
741 G_CALLBACK(pl3_current_playlist_browser_crop_selected_songs
), self
);
742 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
744 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), gtk_separator_menu_item_new());
745 /* add the clear widget */
746 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR
, NULL
);
747 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
748 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist
), NULL
);
750 /* add the shuffle widget */
751 item
= gtk_image_menu_item_new_with_label(_("Shuffle"));
752 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
753 gtk_image_new_from_stock(GTK_STOCK_REFRESH
, GTK_ICON_SIZE_MENU
));
754 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_shuffle_playlist
), NULL
);
755 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
757 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), gtk_separator_menu_item_new());
759 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
762 item
= gtk_menu_item_new_with_label(_("Raise priority"));
763 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
764 g_signal_connect_swapped(G_OBJECT(item
), "activate",
765 G_CALLBACK(pl3_current_playlist_browser_priority_raise_selected_songs
), self
);
766 /* remove priority */
767 item
= gtk_menu_item_new_with_label(_("Remove priority"));
768 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
769 g_signal_connect_swapped(G_OBJECT(item
), "activate",
770 G_CALLBACK(pl3_current_playlist_browser_priority_remove_selected_songs
), self
);
777 GtkTreeModel
*model
= gtk_tree_view_get_model(tree
);
780 gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
)), &model
);
782 if (path
&& gtk_tree_model_get_iter(model
, &iter
, path
))
784 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
787 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO
, NULL
);
788 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
789 g_signal_connect_swapped(G_OBJECT(item
), "activate",
790 G_CALLBACK(pl3_current_playlist_browser_show_info
), self
);
792 /* Add song sebmenu */
793 submenu_for_song(menu
, song
);
796 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
800 playlist_editor_right_mouse(menu
, pl3_current_playlist_editor_add_to_playlist
, self
);
801 //gmpc_mpddata_treeview_right_mouse_intergration(GMPC_MPDDATA_TREEVIEW(tree), GTK_MENU(menu));
802 gtk_widget_show_all(menu
);
803 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
809 static void pl3_current_playlist_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* path
, GtkTreeViewColumn
* col
,
810 PlayQueuePlugin
* self
)
814 GtkTreeModel
*model
= gtk_tree_view_get_model(tree
);
815 gtk_tree_model_get_iter(model
, &iter
, path
);
816 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &song_id
, -1);
817 mpd_player_play_id(connection
, song_id
);
819 if (!self
->priv
->search_keep_open
&& model
== self
->priv
->mod_fill
)
821 gtk_tree_view_set_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
), playlist
);
823 gmpc_mpddata_model_set_mpd_data(GMPC_MPDDATA_MODEL(self
->priv
->mod_fill
), NULL
);
824 self
->priv
->quick_search
= 0;
825 gtk_widget_hide(self
->priv
->filter_entry
);
827 pl3_current_playlist_browser_select_current_song(self
);
832 static void pl3_current_playlist_browser_show_info(PlayQueuePlugin
* self
)
835 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
836 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
837 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
840 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
842 list
= g_list_last(list
);
846 mpd_Song
*song
= NULL
;
847 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) list
->data
);
848 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
851 info2_fill_song_view(song
);
854 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
859 static void pl3_current_playlist_browser_selected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
)
861 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
862 gboolean init
= FALSE
;
863 if (self
->priv
->pl3_cp_vbox
== NULL
)
865 pl3_current_playlist_browser_init((PlayQueuePlugin
*) obj
);
868 gtk_container_add(GTK_CONTAINER(container
), self
->priv
->pl3_cp_vbox
);
869 gtk_widget_show(self
->priv
->pl3_cp_vbox
);
871 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
873 if (init
&& cfg_get_single_value_as_int_with_default(config
, "playlist", "st_cur_song", 0))
875 pl3_current_playlist_browser_scroll_to_current_song(self
);
876 pl3_current_playlist_browser_select_current_song(self
);
880 static void pl3_current_playlist_browser_unselected(GmpcPluginBrowserIface
* obj
, GtkContainer
* container
)
882 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
883 gtk_container_remove(GTK_CONTAINER(container
), self
->priv
->pl3_cp_vbox
);
885 static void pl3_current_playlist_add_after_current_song(GtkWidget
*item
, GtkTreeView
*tree
)
887 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
));
888 int cur_song_pos
= mpd_player_get_current_song_pos(connection
);
889 GList
*list
, *list_iter
;
891 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
894 for(list_iter
= g_list_first(list
); list_iter
!= NULL
; list_iter
= g_list_next(list_iter
))
897 GtkTreePath
*path
= (GtkTreePath
*)list_iter
->data
;
898 /* Convert the path into an actual iter we can use to get values from the model */
899 if(gtk_tree_model_get_iter(model
, &iter
,path
))
901 mpd_Song
*song
= NULL
;
902 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
903 if(song
!= NULL
&& song
->file
!= NULL
)
905 int songid
= mpd_playlist_add_get_id(connection
, (gchar
*) song
->file
);
906 if(cur_song_pos
>= 0)
909 mpd_playlist_move_id(connection
, songid
, cur_song_pos
);
914 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
919 static int pl3_current_playlist_song_list_option_menu (GmpcPluginBrowserIface
*obj
, GtkWidget
*tree
, GtkMenu
*menu
)
921 printf("list option menu\n");
922 if(mpd_check_connected(connection
) && !mpd_player_get_random(connection
))
924 GtkWidget
*item
= gtk_image_menu_item_new_with_label(_("Add after current song"));
925 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
926 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_add_after_current_song
), tree
);
932 static int pl3_current_playlist_browser_option_menu(GmpcPluginBrowserIface
* obj
, GtkMenu
* menu
)
934 /* here we have: Save, Clear */
937 /* add the save widget */
938 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_SAVE
, NULL
);
939 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
940 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_save_playlist
), NULL
);
942 /* add the clear widget */
943 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_CLEAR
, NULL
);
944 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
945 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_clear_playlist
), NULL
);
950 static int pl3_current_playlist_tool_menu_integration(GmpcPluginToolMenuIface
* obj
, GtkMenu
* menu
)
953 item
= gtk_image_menu_item_new_with_label(_("Add URL"));
954 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
955 gtk_image_new_from_icon_name("add-url", GTK_ICON_SIZE_MENU
));
956 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
957 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(url_start
), NULL
);
962 static int pl3_current_playlist_browser_key_press_event(GtkTreeView
* tree
, GdkEventKey
* event
,
963 PlayQueuePlugin
* self
)
965 if (event
->keyval
== GDK_KEY_Delete
)
967 pl3_current_playlist_browser_delete_selected_songs(self
);
969 } else if (event
->keyval
== GDK_KEY_i
&& event
->state
& GDK_MOD1_MASK
)
971 pl3_current_playlist_browser_show_info(self
);
973 } else if (event
->state
&GDK_MOD1_MASK
&& event
->keyval
== GDK_KEY_q
)
975 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
977 pl3_current_playlist_browser_priority_raise_selected_songs(self
);
979 } else if (event
->state
&GDK_MOD1_MASK
&& event
->keyval
== GDK_KEY_d
)
981 if(mpd_server_check_command_allowed(connection
, "prioid") == MPD_SERVER_COMMAND_ALLOWED
)
983 pl3_current_playlist_browser_priority_remove_selected_songs(self
);
985 } else if (event
->keyval
== GDK_KEY_space
)
987 pl3_current_playlist_browser_scroll_to_current_song(self
);
988 pl3_current_playlist_browser_select_current_song(self
);
990 } else if (event
->keyval
== GDK_KEY_f
&& event
->state
& GDK_CONTROL_MASK
)
992 mod_fill_entry_changed(self
->priv
->filter_entry
, self
);
993 gtk_widget_grab_focus(self
->priv
->filter_entry
);
994 self
->priv
->search_keep_open
= TRUE
;
996 } else if ((event
->state
& (GDK_CONTROL_MASK
| GDK_MOD1_MASK
)) == 0) /*&&
997 ((event->keyval >= GDK_space && event->keyval <= GDK_z))) */
1000 guint32 uc
= gdk_keyval_to_unicode(event
->keyval
);
1001 if (uc
&& g_unichar_isalnum(uc
))
1003 memset(data
, '\0', 10);
1004 g_unichar_to_utf8(uc
, data
);
1005 gtk_widget_grab_focus(self
->priv
->filter_entry
);
1006 gtk_entry_set_text(GTK_ENTRY(self
->priv
->filter_entry
), data
);
1007 gtk_editable_set_position(GTK_EDITABLE(self
->priv
->filter_entry
), 1);
1012 return pl3_window_key_press_event(GTK_WIDGET(tree
), event
);
1015 /* create a dialog that allows the user to save the current playlist */
1016 static void pl3_current_playlist_save_playlist(void)
1019 GtkBuilder
*xml
= NULL
;
1021 /* check if the connection is up */
1022 if (!mpd_check_connected(connection
))
1026 /* create the interface */
1027 str
= gmpc_get_full_glade_path("playlist-save-dialog.ui");
1028 xml
= gtk_builder_new();
1029 gtk_builder_add_from_file(xml
, str
, NULL
);
1032 /* run the interface */
1035 switch (gtk_dialog_run(GTK_DIALOG(gtk_builder_get_object(xml
, "save_pl"))))
1037 case GTK_RESPONSE_OK
:
1039 /* if the users agrees do the following: */
1040 /* get the song-name */
1041 str
= (gchar
*) gtk_entry_get_text(GTK_ENTRY((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")));
1042 /* check if the user entered a name, we can't do withouth */
1043 /* TODO: disable ok button when nothing is entered */
1044 /* also check if there is a connection */
1045 if (strlen(str
) != 0 && mpd_check_connected(connection
))
1047 int retv
= mpd_database_save_playlist(connection
, str
);
1048 if (retv
== MPD_DATABASE_PLAYLIST_EXIST
)
1051 g_markup_printf_escaped(_("<i>Playlist <b>\"%s\"</b> already exists\nOverwrite?</i>"), str
);
1052 gtk_label_set_markup(GTK_LABEL((GtkWidget
*) gtk_builder_get_object(xml
, "label_error")), errormsg
);
1053 gtk_widget_show((GtkWidget
*) gtk_builder_get_object(xml
, "hbox5"));
1054 /* ask to replace */
1055 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")), FALSE
);
1056 switch (gtk_dialog_run(GTK_DIALOG((GtkWidget
*) gtk_builder_get_object(xml
, "save_pl"))))
1058 case GTK_RESPONSE_OK
:
1060 mpd_database_delete_playlist(connection
, str
);
1061 mpd_database_save_playlist(connection
, str
);
1062 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
1067 /* return to stare */
1068 gtk_widget_set_sensitive(GTK_WIDGET((GtkWidget
*) gtk_builder_get_object(xml
, "pl-entry")), TRUE
);
1069 gtk_widget_hide((GtkWidget
*) gtk_builder_get_object(xml
, "hbox5"));
1072 } else if (retv
!= MPD_OK
)
1074 playlist3_show_error_message(_("Failed to save the playlist file."), ERROR_WARNING
);
1077 GmpcStatusChangedCallback(connection
, MPD_CST_DATABASE
, NULL
);
1085 /* destroy the window */
1086 gtk_widget_destroy((GtkWidget
*) gtk_builder_get_object(xml
, "save_pl"));
1088 /* unref the gui description */
1089 g_object_unref(xml
);
1092 static void pl3_current_playlist_browser_clear_playlist(void)
1095 if(cfg_get_single_value_as_int(config
, "playlist","no-confirm-clear") != 1)
1098 delete = gtk_button_new_from_stock(GTK_STOCK_CLEAR
);
1099 g_signal_connect(G_OBJECT(delete),
1101 G_CALLBACK(pl3_current_playlist_browser_clear_playlist_real
),
1105 playlist3_message_show(pl3_messages
,
1106 _("Are you sure you want to clear the play queue?")
1108 playlist3_message_add_widget(pl3_messages
, delete);
1109 gtk_widget_grab_focus(GTK_WIDGET(delete));
1112 pl3_current_playlist_browser_clear_playlist_real();
1116 static void pl3_current_playlist_browser_shuffle_playlist(void)
1118 mpd_playlist_shuffle(connection
);
1121 static void pl3_current_playlist_status_changed(GmpcConnection
* conn
, MpdObj
* mi
, ChangedStatusType what
,
1122 PlayQueuePlugin
* self
)
1124 if (self
->priv
->pl3_cp_vbox
== NULL
)
1126 if (what
& MPD_CST_PLAYLIST
)
1129 if (self
->priv
->quick_search
)
1130 mod_fill_do_entry_changed(self
);
1134 static void pl3_current_playlist_browser_activate(PlayQueuePlugin
* self
)
1136 GtkTreeSelection
*selec
= gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml
, "cat_tree")));
1138 GtkTreePath
*path
= gtk_tree_row_reference_get_path(self
->priv
->pl3_curb_tree_ref
);
1141 gtk_tree_selection_select_path(selec
, path
);
1142 gtk_tree_path_free(path
);
1144 gtk_widget_grab_focus(self
->priv
->pl3_cp_tree
);
1147 static void pl3_current_playlist_do_playlist_search(GmpcPluginBase
* self
)
1149 pl3_find2_select_plugin_id(self
->id
);
1152 static int pl3_current_playlist_browser_add_go_menu(GmpcPluginBrowserIface
* obj
, GtkMenu
* menu
)
1154 GtkWidget
*item
= NULL
;
1156 item
= gtk_image_menu_item_new_with_label(_("Play Queue"));
1157 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1158 gtk_image_new_from_icon_name("playlist-browser", GTK_ICON_SIZE_MENU
));
1159 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1160 gtk_widget_add_accelerator(GTK_WIDGET(item
), "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_F1
, 0,
1162 g_signal_connect_swapped(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_browser_activate
), obj
);
1164 item
= gtk_image_menu_item_new_with_label(_("Search Playlist"));
1165 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1166 gtk_image_new_from_icon_name("gtk-find", GTK_ICON_SIZE_MENU
));
1167 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1168 gtk_widget_add_accelerator(GTK_WIDGET(item
), "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_j
,
1169 GDK_CONTROL_MASK
, GTK_ACCEL_VISIBLE
);
1170 g_signal_connect_swapped(G_OBJECT(item
), "activate", G_CALLBACK(pl3_current_playlist_do_playlist_search
), obj
);
1174 static void pl3_current_playlist_connection_changed(GmpcConnection
* conn
, MpdObj
* mi
, int connect
,
1175 PlayQueuePlugin
* self
)
1177 if (!connect
&& self
->priv
->filter_entry
)
1179 gtk_entry_set_text(GTK_ENTRY(self
->priv
->filter_entry
), "");
1183 /* function that saves the settings */
1184 static void pl3_current_playlist_save_myself(GmpcPluginBase
* obj
)
1186 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
1187 if (self
->priv
->pl3_curb_tree_ref
)
1189 GtkTreePath
*path
= gtk_tree_row_reference_get_path(self
->priv
->pl3_curb_tree_ref
);
1192 gint
*indices
= gtk_tree_path_get_indices(path
);
1193 cfg_set_single_value_as_int(config
, "current-playlist", "position", indices
[0]);
1194 gtk_tree_path_free(path
);
1202 GType
play_queue_plugin_get_type(void);
1204 static int *play_queue_plugin_get_version(GmpcPluginBase
* plug
, int *length
)
1206 static int version
[3] = { 0, 0, 1 };
1209 return (int *)version
;
1212 static const char *play_queue_plugin_get_name(GmpcPluginBase
* plug
)
1214 return N_("Play Queue");
1217 static void play_queue_plugin_finalize(GObject
* obj
)
1219 PlayQueuePlugin
*self
= (PlayQueuePlugin
*) obj
;
1220 PlayQueuePluginClass
*klass
= (g_type_class_peek(play_queue_plugin_get_type()));
1221 gpointer parent_class
= g_type_class_peek_parent(klass
);
1222 pl3_current_playlist_destroy((PlayQueuePlugin
*) obj
);
1226 if (self
->priv
->uid
)
1228 g_free(self
->priv
->uid
);
1229 self
->priv
->uid
= NULL
;
1231 if (self
->priv
->mod_fill
)
1233 g_object_unref(self
->priv
->mod_fill
);
1234 self
->priv
->mod_fill
= NULL
;
1236 if (g_signal_handler_is_connected(G_OBJECT(gmpcconn
), self
->priv
->status_changed_handler
))
1237 g_signal_handler_disconnect(G_OBJECT(gmpcconn
), self
->priv
->status_changed_handler
);
1239 if (g_signal_handler_is_connected(G_OBJECT(gmpcconn
), self
->priv
->connection_changed_handler
))
1240 g_signal_handler_disconnect(G_OBJECT(gmpcconn
), self
->priv
->connection_changed_handler
);
1245 G_OBJECT_CLASS(parent_class
)->finalize(obj
);
1248 static GObject
*play_queue_plugin_constructor(GType type
, guint n_construct_properties
,
1249 GObjectConstructParam
* construct_properties
)
1251 PlayQueuePluginClass
*klass
;
1252 PlayQueuePlugin
*self
;
1253 GObjectClass
*parent_class
;
1254 klass
= (g_type_class_peek(play_queue_plugin_get_type()));
1255 parent_class
= G_OBJECT_CLASS(g_type_class_peek_parent(klass
));
1256 self
= (PlayQueuePlugin
*) parent_class
->constructor(type
, n_construct_properties
, construct_properties
);
1258 /* setup private structure */
1259 self
->priv
= g_malloc0(sizeof(PlayQueuePluginPrivate
));
1260 self
->priv
->status_changed_handler
=
1261 g_signal_connect_object(G_OBJECT(gmpcconn
), "status-changed", G_CALLBACK(pl3_current_playlist_status_changed
),
1263 self
->priv
->connection_changed_handler
=
1264 g_signal_connect_object(G_OBJECT(gmpcconn
), "connection-changed",
1265 G_CALLBACK(pl3_current_playlist_connection_changed
), self
, 0);
1267 self
->priv
->search_keep_open
= FALSE
;
1268 self
->priv
->filter_entry
= NULL
;
1269 self
->priv
->mod_fill
= NULL
;
1270 self
->priv
->quick_search
= 0;
1271 self
->priv
->quick_search_timeout
= 0;
1273 self
->priv
->pl3_cp_tree
= NULL
;
1274 self
->priv
->pl3_cp_vbox
= NULL
;
1275 self
->priv
->pl3_curb_tree_ref
= NULL
;
1277 /* Make it an internal plugin */
1278 GMPC_PLUGIN_BASE(self
)->plugin_type
= GMPC_PLUGIN_PL_BROWSER
| GMPC_INTERNALL
;
1281 return G_OBJECT(self
);
1285 * Base GmpcPluginBase class
1287 static void play_queue_plugin_class_init(PlayQueuePluginClass
* klass
)
1289 /* Connect destroy and construct */
1290 G_OBJECT_CLASS(klass
)->finalize
= play_queue_plugin_finalize
;
1291 G_OBJECT_CLASS(klass
)->constructor
= play_queue_plugin_constructor
;
1292 G_OBJECT_CLASS(klass
)->get_property
= play_queue_get_property
;
1293 G_OBJECT_CLASS(klass
)->set_property
= play_queue_set_property
;
1294 /* Connect plugin functions */
1295 GMPC_PLUGIN_BASE_CLASS(klass
)->get_version
= play_queue_plugin_get_version
;
1296 GMPC_PLUGIN_BASE_CLASS(klass
)->get_name
= play_queue_plugin_get_name
;
1298 GMPC_PLUGIN_BASE_CLASS(klass
)->save_yourself
= pl3_current_playlist_save_myself
;
1300 g_object_class_install_property(G_OBJECT_CLASS(klass
), PLAY_QUEUE_UID
,
1301 g_param_spec_string("uid", "uid", "stores an unique id", "play-queue",
1302 G_PARAM_STATIC_NAME
| G_PARAM_STATIC_NICK
| G_PARAM_STATIC_BLURB
1303 | G_PARAM_READABLE
| G_PARAM_WRITABLE
));
1310 static void play_queue_browser_iface_init(GmpcPluginBrowserIfaceIface
* iface
)
1312 iface
->browser_add
= pl3_current_playlist_browser_add
;
1313 iface
->browser_selected
= pl3_current_playlist_browser_selected
;
1314 iface
->browser_unselected
= pl3_current_playlist_browser_unselected
;
1315 iface
->browser_option_menu
= pl3_current_playlist_browser_option_menu
;
1316 iface
->browser_add_go_menu
= pl3_current_playlist_browser_add_go_menu
;
1319 static void play_queue_song_list_iface_init(GmpcPluginSongListIfaceIface
*iface
)
1321 iface
->song_list
= pl3_current_playlist_song_list_option_menu
;
1325 * Tool menu interface
1327 static void play_queue_plugin_tool_menu_iface_init(GmpcPluginToolMenuIfaceIface
* iface
)
1329 iface
->tool_menu_integration
= pl3_current_playlist_tool_menu_integration
;
1332 /* Integrate Search */
1333 static gboolean
play_queue_plugin_is_field_supported(GmpcPluginIntegrateSearchIface
* obj
, mpd_TagItems tag
)
1335 if (tag
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1337 return mpd_server_tag_supported(connection
, tag
);
1340 static MpdData
*play_queue_plugin_is_search(GmpcPluginIntegrateSearchIface
* obj
, mpd_TagItems num_field
,
1341 const gchar
* search_string
)
1343 MpdData
*data_t
= NULL
;
1344 if (num_field
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1346 data_t
= advanced_search(search_string
, TRUE
);
1349 gchar
**splitted
= tokenize_string(search_string
);
1351 gboolean found
= FALSE
;
1352 for (i
= 0; splitted
&& splitted
[i
]; i
++)
1356 mpd_playlist_search_start(connection
, FALSE
);
1359 mpd_playlist_search_add_constraint(connection
, num_field
, splitted
[i
]);
1362 g_strfreev(splitted
);
1365 data_t
= mpd_playlist_search_commit(connection
);
1371 static void play_queue_plugin_is_iface_init(GmpcPluginIntegrateSearchIfaceIface
* iface
)
1373 iface
->field_supported
= play_queue_plugin_is_field_supported
;
1374 iface
->search
= play_queue_plugin_is_search
;
1377 GType
play_queue_plugin_get_type(void)
1379 static GType play_queue_plugin_type_id
= 0;
1380 if (play_queue_plugin_type_id
== 0)
1382 static const GTypeInfo info
= {
1383 .class_size
= sizeof(PlayQueuePluginClass
),
1384 .class_init
= (GClassInitFunc
) play_queue_plugin_class_init
,
1385 .instance_size
= sizeof(PlayQueuePlugin
),
1388 static const GInterfaceInfo iface_info
= {
1389 (GInterfaceInitFunc
) play_queue_browser_iface_init
,
1390 (GInterfaceFinalizeFunc
) NULL
, NULL
1392 static const GInterfaceInfo iface_song_list
= {
1393 (GInterfaceInitFunc
) play_queue_song_list_iface_init
,
1394 (GInterfaceFinalizeFunc
) NULL
, NULL
1396 static const GInterfaceInfo iface_tm_info
= {
1397 (GInterfaceInitFunc
) play_queue_plugin_tool_menu_iface_init
,
1398 (GInterfaceFinalizeFunc
) NULL
, NULL
1401 static const GInterfaceInfo iface_is_info
= {
1402 (GInterfaceInitFunc
) play_queue_plugin_is_iface_init
,
1403 (GInterfaceFinalizeFunc
) NULL
, NULL
1405 play_queue_plugin_type_id
= g_type_register_static(GMPC_PLUGIN_TYPE_BASE
, "PlayQueuePlugin", &info
, 0);
1407 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_BROWSER_IFACE
, &iface_info
);
1408 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_TOOL_MENU_IFACE
, &iface_tm_info
);
1409 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_INTEGRATE_SEARCH_IFACE
, &iface_is_info
);
1410 g_type_add_interface_static(play_queue_plugin_type_id
, GMPC_PLUGIN_TYPE_SONG_LIST_IFACE
, &iface_song_list
);
1412 return play_queue_plugin_type_id
;
1415 PlayQueuePlugin
*play_queue_plugin_new(const gchar
* uid
)
1417 PlayQueuePlugin
*plug
= g_object_new(play_queue_plugin_get_type(), "uid", uid
, NULL
);
1427 static void pl3_current_playlist_browser_priority_raise_selected_songs(PlayQueuePlugin
* self
)
1429 GList
*list
= NULL
, *llist
= NULL
;
1430 GtkTreeModel
*model
= NULL
;
1432 /* grab the selection from the tree */
1433 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
1435 int sel_rows
= gtk_tree_selection_count_selected_rows(selection
);
1437 if(sel_rows
>= 254) {
1438 playlist3_show_error_message(_("You can only queue 254 songs at the time."),
1442 else if (sel_rows
== 0)
1447 /* start a command list */
1448 /* grab the selected songs */
1449 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1450 /* grab the last song that is selected */
1451 /* remove every selected song one by one */
1455 llist
= g_list_first(list
);
1460 if(gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
))
1463 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
1464 mpd_playlist_set_priority(connection
, id
, priority
--);
1466 llist
= g_list_next(llist
);
1469 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
1473 static void pl3_current_playlist_browser_priority_remove_selected_songs(PlayQueuePlugin
* self
)
1475 GList
*list
= NULL
, *llist
= NULL
;
1476 GtkTreeModel
*model
= NULL
;
1477 /* grab the selection from the tree */
1478 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(self
->priv
->pl3_cp_tree
));
1480 int sel_rows
= gtk_tree_selection_count_selected_rows(selection
);
1487 /* start a command list */
1488 /* grab the selected songs */
1489 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1490 /* grab the last song that is selected */
1491 /* remove every selected song one by one */
1494 llist
= g_list_first(list
);
1499 if(gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) llist
->data
))
1502 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_SONG_ID
, &id
, -1);
1503 mpd_playlist_set_priority(connection
, id
, 0);
1505 llist
= g_list_next(llist
);
1508 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);