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>
26 #include "playlist3.h"
27 #include "playlist3-find2-browser.h"
28 #include "gmpc-mpddata-model.h"
29 #include "gmpc-mpddata-treeview.h"
30 #include "advanced-search.h"
31 #include "playlist3-playlist-editor.h"
33 static void pl3_find2_browser_destroy(void);
34 static void pl3_find2_browser_selected(GtkWidget
*);
35 static void pl3_find2_browser_unselected(GtkWidget
*);
36 static void pl3_find2_browser_add(GtkWidget
* cat_tree
);
37 static int pl3_find2_browser_add_go_menu(GtkWidget
*);
38 static void pl3_find2_browser_search(void);
39 static void pl3_find2_browser_row_activated(GtkTreeView
*, GtkTreePath
*);
40 static int pl3_find2_browser_playlist_key_press(GtkWidget
*, GdkEventKey
*);
41 static void pl3_find2_browser_add_selected(void);
42 static gboolean
pl3_find2_browser_button_release_event(GtkWidget
* but
, GdkEventButton
* event
);
43 static void pl3_find2_browser_connection_changed(MpdObj
* mi
, int connect
, gpointer data
);
44 static gboolean
pl3_find2_entry_key_press_event(GtkWidget
* entry
, GdkEventKey
* event
, gpointer data
);
45 static void pl3_find2_browser_status_changed(MpdObj
* mi
, ChangedStatusType what
, void *data
);
47 static void pl3_find2_entry_changed(GtkWidget
* entry
, gpointer data
);
48 static void pl3_find2_save_myself(void);
50 /* Playlist window row reference */
51 static GtkTreeRowReference
*pl3_find2_ref
= NULL
;
54 static GtkWidget
*pl3_find2_curpl
= NULL
;
55 static GtkListStore
*pl3_find2_curpl_model
= NULL
;
56 static GtkWidget
*pl3_find2_tree
= NULL
;
57 static GmpcMpdDataModel
*pl3_find2_store2
= NULL
;
58 static GtkWidget
*pl3_find2_vbox
= NULL
;
59 static GtkListStore
*pl3_find2_combo_store
= NULL
;
60 static GtkListStore
*pl3_find2_autocomplete
= NULL
;
62 static GtkWidget
*search_combo
= NULL
;
63 static GtkWidget
*search_entry
= NULL
;
65 #define QUERY_ENTRY MPD_TAG_NUM_OF_ITEM_TYPES
66 static void pl3_find2_fill_combo(gmpcPluginParent
* plug
)
69 int i
= 0, max
= MPD_TAG_NUM_OF_ITEM_TYPES
;
70 gtk_list_store_clear(pl3_find2_combo_store
);
72 for (i
= 0; i
< max
; i
++)
74 if (plug
== NULL
|| gmpc_plugin_browser_integrate_search_field_supported(plug
, i
))
76 gtk_list_store_append(pl3_find2_combo_store
, &iter
);
77 gtk_list_store_set(pl3_find2_combo_store
, &iter
, 1, mpdTagItemKeys
[i
], 0, i
, -1);
80 if (plug
== NULL
|| gmpc_plugin_browser_integrate_search_field_supported(plug
, QUERY_ENTRY
))
82 gtk_list_store_append(pl3_find2_combo_store
, &iter
);
83 gtk_list_store_set(pl3_find2_combo_store
, &iter
, 1, _("Query"), 0, QUERY_ENTRY
, -1);
87 static void pl3_find2_combo_box_field_changed(GtkComboBox
* cb
, gpointer data
)
90 if (gtk_combo_box_get_active_iter(cb
, &iter
))
93 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_combo_store
), &iter
, 0, &selected_type
, -1);
94 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(data
), &iter
))
98 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(data
)), &iter
, 0, &type
, -1);
101 cfield
= g_strdup_printf("selected_type_%s", type
);
103 cfg_set_single_value_as_int(config
, "find2-browser", cfield
, selected_type
);
110 static void playtime_changed(GmpcMpdDataModel
* model
, gulong playtime
)
114 static void pl3_find2_browser_type_plugin_changed(GtkComboBox
* box
, gpointer user_data
)
117 GtkTreeModel
*model
= gtk_combo_box_get_model(box
);
118 gmpcPluginParent
*plug
= NULL
;
119 gchar
*cfield
= NULL
;
123 /* this should always be active */
124 if (gtk_combo_box_get_active_iter(box
, &iter
))
126 gtk_tree_model_get(GTK_TREE_MODEL(model
), &iter
, 0, &type
, 2, &plug
, -1);
127 pl3_find2_fill_combo(plug
);
130 cfield
= g_strdup_printf("selected_type_%s", type
);
131 selected_type
= cfg_get_single_value_as_int_with_default(config
, "find2-browser", cfield
, 0);
134 /* Loop through the field until the match is found */
135 for (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_find2_combo_store
), &iter
);
136 gtk_list_store_iter_is_valid(pl3_find2_combo_store
, &iter
);
137 gtk_tree_model_iter_next(GTK_TREE_MODEL(pl3_find2_combo_store
), &iter
))
140 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_combo_store
), &iter
, 0, &sel_type
, -1);
141 if (sel_type
== selected_type
)
143 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(search_combo
), &iter
);
147 /* default, if nothing is found. */
148 gtk_combo_box_set_active(GTK_COMBO_BOX(search_combo
), 0);
151 static void pl3_find2_browser_clear_search_entry(GtkEntry
* entry
, GtkEntryIconPosition icon_pos
, GdkEvent
* event
,
154 if (icon_pos
== GTK_ENTRY_ICON_SECONDARY
)
156 gtk_entry_set_text(GTK_ENTRY(entry
), "");
161 * Construct the browser
163 static void pl3_find2_browser_init(void)
166 GtkWidget
*pl3_find2_sw
= NULL
;
167 GtkWidget
*hbox
= NULL
;
168 GtkCellRenderer
*renderer
;
169 GtkEntryCompletion
*entrcomp
;
171 /* autocomplete later on */
172 pl3_find2_autocomplete
= gtk_list_store_new(1, G_TYPE_STRING
);
174 pl3_find2_store2
= gmpc_mpddata_model_new();
175 gmpc_mpddata_model_disable_image(GMPC_MPDDATA_MODEL(pl3_find2_store2
));
176 g_signal_connect(G_OBJECT(pl3_find2_store2
), "playtime_changed", G_CALLBACK(playtime_changed
), NULL
);
178 pl3_find2_combo_store
= gtk_list_store_new(2, G_TYPE_INT
, G_TYPE_STRING
);
180 pl3_find2_fill_combo(NULL
);
183 /* set up the tree */
184 pl3_find2_tree
= gmpc_mpddata_treeview_new("find2-browser", TRUE
, GTK_TREE_MODEL(pl3_find2_store2
));
185 gmpc_mpddata_treeview_enable_click_fix(GMPC_MPDDATA_TREEVIEW(pl3_find2_tree
));
186 /* Disable interactive search, somewhat */
187 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(pl3_find2_tree
), FALSE
);
189 g_signal_connect(G_OBJECT(pl3_find2_tree
), "row-activated", G_CALLBACK(pl3_find2_browser_row_activated
), NULL
);
190 g_signal_connect(G_OBJECT(pl3_find2_tree
), "button-release-event",
191 G_CALLBACK(pl3_find2_browser_button_release_event
), NULL
);
192 g_signal_connect(G_OBJECT(pl3_find2_tree
), "key-press-event", G_CALLBACK(pl3_find2_browser_playlist_key_press
),
195 /* set up the scrolled window */
196 pl3_find2_sw
= gtk_scrolled_window_new(NULL
, NULL
);
197 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_find2_sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
198 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_find2_sw
), GTK_SHADOW_ETCHED_IN
);
199 gtk_container_add(GTK_CONTAINER(pl3_find2_sw
), pl3_find2_tree
);
201 /* set initial state */
203 pl3_find2_vbox
= gtk_vbox_new(FALSE
, 6);
204 gtk_box_pack_start(GTK_BOX(pl3_find2_vbox
), pl3_find2_sw
, TRUE
, TRUE
, 0);
206 /** Add a default item */
207 hbox
= gtk_hbox_new(FALSE
, 6);
209 /* search in playlist */
210 pl3_find2_curpl_model
= gtk_list_store_new(3, G_TYPE_STRING
, G_TYPE_INT
, G_TYPE_POINTER
);
211 pl3_find2_curpl
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(pl3_find2_curpl_model
));
212 renderer
= gtk_cell_renderer_text_new();
213 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(pl3_find2_curpl
), renderer
, TRUE
);
214 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(pl3_find2_curpl
), renderer
, "text", 0, NULL
);
216 for (i
= 0; i
< num_plugins
; i
++)
218 if (gmpc_plugin_get_enabled(plugins
[i
]))
220 if (gmpc_plugin_is_browser(plugins
[i
]))
222 if (gmpc_plugin_browser_has_integrate_search(plugins
[i
]))
225 gtk_list_store_append(GTK_LIST_STORE(pl3_find2_curpl_model
), &titer
);
226 gtk_list_store_set(GTK_LIST_STORE(pl3_find2_curpl_model
), &titer
,
227 0, gmpc_plugin_get_name(plugins
[i
]), 1, 0, 2, plugins
[i
], -1);
233 gtk_combo_box_set_active(GTK_COMBO_BOX(pl3_find2_curpl
), 0);
234 g_signal_connect(G_OBJECT(pl3_find2_curpl
), "changed", G_CALLBACK(pl3_find2_browser_type_plugin_changed
), NULL
);
236 gtk_box_pack_start(GTK_BOX(hbox
), pl3_find2_curpl
, FALSE
, TRUE
, 0);
239 search_combo
= gtk_combo_box_new();
241 renderer
= gtk_cell_renderer_text_new();
242 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(search_combo
), renderer
, TRUE
);
243 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(search_combo
), renderer
, "text", 1, NULL
);
244 gtk_combo_box_set_model(GTK_COMBO_BOX(search_combo
), GTK_TREE_MODEL(pl3_find2_combo_store
));
246 /* Update the tag combo to the right field */
247 pl3_find2_browser_type_plugin_changed(GTK_COMBO_BOX(pl3_find2_curpl
), NULL
);
249 gtk_box_pack_start(GTK_BOX(hbox
), search_combo
, FALSE
, TRUE
, 0);
250 g_signal_connect(G_OBJECT(search_combo
), "changed", G_CALLBACK(pl3_find2_combo_box_field_changed
), pl3_find2_curpl
);
254 search_entry
= gtk_entry_new();
255 gtk_entry_set_icon_from_stock(GTK_ENTRY(search_entry
), GTK_ENTRY_ICON_SECONDARY
, GTK_STOCK_CLEAR
);
256 g_signal_connect(GTK_ENTRY(search_entry
), "icon-press", G_CALLBACK(pl3_find2_browser_clear_search_entry
), NULL
);
259 entrcomp
= gtk_entry_completion_new();
260 gtk_entry_completion_set_text_column(entrcomp
, 0);
261 gtk_entry_completion_set_inline_completion(entrcomp
, TRUE
);
262 gtk_entry_completion_set_model(GTK_ENTRY_COMPLETION(entrcomp
), GTK_TREE_MODEL(pl3_find2_autocomplete
));
263 gtk_entry_completion_set_popup_completion(GTK_ENTRY_COMPLETION(entrcomp
), TRUE
);
264 gtk_entry_set_completion(GTK_ENTRY(search_entry
), entrcomp
);
266 g_signal_connect(G_OBJECT(search_entry
), "activate", G_CALLBACK(pl3_find2_browser_search
), NULL
);
267 g_signal_connect(G_OBJECT(search_entry
), "key-press-event", G_CALLBACK(pl3_find2_entry_key_press_event
), NULL
);
268 g_signal_connect(G_OBJECT(search_entry
), "changed", G_CALLBACK(pl3_find2_entry_changed
), NULL
);
269 gtk_box_pack_start(GTK_BOX(hbox
), search_entry
, TRUE
, TRUE
, 0);
272 button
= gtk_button_new_from_stock(GTK_STOCK_FIND
);
273 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(pl3_find2_browser_search
), NULL
);
274 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, TRUE
, 0);
276 gtk_box_pack_start(GTK_BOX(pl3_find2_vbox
), hbox
, FALSE
, TRUE
, 0);
278 gtk_widget_show_all(pl3_find2_vbox
);
279 g_object_ref_sink(G_OBJECT(pl3_find2_vbox
));
282 static void pl3_find2_browser_selected(GtkWidget
* container
)
284 if (pl3_find2_tree
== NULL
)
286 pl3_find2_browser_init();
288 gtk_container_add(GTK_CONTAINER(container
), pl3_find2_vbox
);
289 gtk_widget_grab_focus(pl3_find2_tree
);
290 gtk_widget_show(pl3_find2_vbox
);
293 static void pl3_find2_browser_unselected(GtkWidget
* container
)
295 gtk_container_remove(GTK_CONTAINER(container
), pl3_find2_vbox
);
298 /*****************************************************************
301 static void pl3_find2_browser_add(GtkWidget
* cat_tree
)
303 GtkTreePath
*path
= NULL
;
305 gint pos
= cfg_get_single_value_as_int_with_default(config
, "find2-browser", "position", 4);
306 playlist3_insert_browser(&iter
, PL3_CAT_BROWSER_LIBRARY
+pos
%PL3_CAT_BROWSER_LIBRARY
);
307 gtk_list_store_set(GTK_LIST_STORE(pl3_tree
), &iter
,
308 PL3_CAT_TYPE
, find2_browser_plug
.id
,
309 PL3_CAT_TITLE
, _("Search"),
310 PL3_CAT_ICON_ID
, GTK_STOCK_FIND
,
315 gtk_tree_row_reference_free(pl3_find2_ref
);
316 pl3_find2_ref
= NULL
;
319 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter
);
322 pl3_find2_ref
= gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path
);
323 gtk_tree_path_free(path
);
330 static void pl3_find2_browser_search(void)
332 GtkTreeIter iter
, cc_iter
;
333 if (pl3_find2_vbox
== NULL
)
336 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree
), NULL
);
337 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pl3_find2_curpl
), &iter
))
341 gmpcPluginParent
*plug
= NULL
;
342 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_curpl_model
), &iter
, 1, &type
, 2, &plug
, -1);
344 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(search_combo
), &cc_iter
))
346 GError
*error
= NULL
;
347 MpdData
*data_t
= NULL
;
348 const gchar
*real_name
= gtk_entry_get_text(GTK_ENTRY(search_entry
));
349 gchar
*name
= g_strstrip(g_strdup(real_name
));
350 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_combo_store
), &cc_iter
, 0, &num_field
, -1);
352 data_t
= gmpc_plugin_browser_integrate_search(plug
, num_field
, name
, &error
);
356 g_markup_printf_escaped("<b>%s</b> %s: %s", gmpc_plugin_get_name(plug
), _("Search failed"),
358 playlist3_show_error_message(mes
, ERROR_WARNING
);
363 gmpc_mpddata_model_set_mpd_data(pl3_find2_store2
, data_t
);
364 /* update autocompletion */
368 for (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_find2_autocomplete
), &iter
);
369 gtk_list_store_iter_is_valid(pl3_find2_autocomplete
, &iter
) && !found2
;
370 gtk_tree_model_iter_next(GTK_TREE_MODEL(pl3_find2_autocomplete
), &iter
))
373 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete
), &iter
, 0, &entry
, -1);
374 if (strcmp(entry
, name
) == 0)
382 gtk_list_store_insert_with_values(pl3_find2_autocomplete
, &iter
, -1, 0, name
, -1);
388 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree
), GTK_TREE_MODEL(pl3_find2_store2
));
391 static void pl3_find2_browser_show_info(void)
393 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree
));
394 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
));
395 if (!mpd_server_check_version(connection
, 0, 12, 0))
399 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
402 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
404 list
= g_list_last(list
);
407 mpd_Song
*song
= NULL
;
408 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) list
->data
);
409 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
413 info2_fill_song_view(song
);
417 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
422 static void pl3_find2_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* tp
)
427 gtk_tree_model_get_iter(gtk_tree_view_get_model(tree
), &iter
, tp
);
428 gtk_tree_model_get(gtk_tree_view_get_model(tree
), &iter
, MPDDATA_MODEL_COL_PATH
, &song_id
, MPDDATA_MODEL_ROW_TYPE
,
437 static void pl3_find2_browser_replace_selected(void)
439 mpd_playlist_clear(connection
);
440 if (mpd_check_connected(connection
))
442 pl3_find2_browser_add_selected();
443 mpd_player_play(connection
);
447 static int pl3_find2_browser_playlist_key_press(GtkWidget
* tree
, GdkEventKey
* event
)
449 if (event
->keyval
== GDK_KEY_i
&& event
->state
& GDK_MOD1_MASK
)
451 pl3_find2_browser_show_info();
454 /* Make ctrl-f focus the search entry */
455 else if (event
->keyval
== GDK_KEY_f
&& event
->state
& GDK_CONTROL_MASK
)
457 gtk_widget_grab_focus(GTK_WIDGET(search_entry
));
461 return pl3_window_key_press_event(tree
, event
);
466 static void pl3_find2_browser_add_selected(void)
469 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
));
470 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_find2_store2
);
471 GList
*rows
= gtk_tree_selection_get_selected_rows(selection
, &model
);
477 GList
*node
= g_list_first(rows
);
480 GtkTreePath
*path
= node
->data
;
481 gtk_tree_model_get_iter(model
, &iter
, path
);
482 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &name
, MPDDATA_MODEL_ROW_TYPE
, &type
, -1);
483 /* does this bitmask thingy works ok? I think it hsould */
484 if (type
== MPD_DATA_TYPE_SONG
)
486 if ((songs
& 16383) == 16383)
488 mpd_playlist_queue_commit(connection
);
490 /* add them to the add list */
491 mpd_playlist_queue_add(connection
, name
);
495 } while ((node
= g_list_next(node
)) != NULL
);
497 /* if there are items in the add list add them to the playlist */
498 mpd_playlist_queue_commit(connection
);
500 g_list_foreach(rows
, (GFunc
) gtk_tree_path_free
, NULL
);
504 static void pl3_find2_browser_add_all(void)
507 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_find2_store2
);
509 if (gtk_tree_model_get_iter_first(model
, &iter
))
515 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &name
, MPDDATA_MODEL_ROW_TYPE
, &type
, -1);
516 /* does this bitmask thingy works ok? I think it hsould */
517 if (type
== MPD_DATA_TYPE_SONG
)
519 if ((songs
& 16383) == 16383)
521 mpd_playlist_queue_commit(connection
);
523 /* add them to the add list */
524 mpd_playlist_queue_add(connection
, name
);
528 } while (gtk_tree_model_iter_next(model
, &iter
));
530 /* if there are items in the add list add them to the playlist */
531 mpd_playlist_queue_commit(connection
);
534 static void pl3_find2_playlist_editor_add_to_playlist(GtkWidget
* menu
, gpointer cb_data
)
536 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree
));
537 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
));
538 gchar
*data
= g_object_get_data(G_OBJECT(menu
), "playlist");
539 GList
*iter
, *list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
542 iter
= g_list_first(list
);
546 if (gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*) iter
->data
))
549 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, -1);
550 mpd_database_playlist_list_add(connection
, data
, file
);
553 } while ((iter
= g_list_next(iter
)));
555 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
559 playlist_editor_fill_list();
563 * Play the selected row, only usefull if one row is selected
565 static void pl3_find2_activate_row(GtkWidget *item,GtkTreeView *tree)
567 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree));
568 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree));
569 GList *iter, *list = gtk_tree_selection_get_selected_rows (selection, &model);
572 iter = g_list_first(list);
575 if(gtk_tree_model_get_iter(model, &giter, (GtkTreePath *)iter->data))
578 gtk_tree_model_get(gtk_tree_view_get_model(tree), &giter,MPDDATA_MODEL_COL_PATH,&song_id, -1);
582 }while((iter = g_list_next(iter)));
584 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
590 static gboolean
pl3_find2_browser_button_release_event(GtkWidget
* but
, GdkEventButton
* event
)
592 if (event
->button
!= 3)
594 else if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
))) > 0)
597 GtkWidget
*menu
= gtk_menu_new();
599 if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree))) == 1)
601 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PLAY,NULL);
602 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
603 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_find2_activate_row), pl3_find2_tree);
607 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD
, NULL
);
608 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
609 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_find2_browser_add_selected
), NULL
);
610 gtk_widget_show(item
);
612 item
= gtk_image_menu_item_new_with_label(_("Add all"));
613 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
614 gtk_image_new_from_stock(GTK_STOCK_ADD
, GTK_ICON_SIZE_MENU
));
615 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
616 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_find2_browser_add_all
), NULL
);
617 gtk_widget_show(item
);
619 /* add the replace widget */
620 item
= gtk_image_menu_item_new_with_label(_("Replace"));
621 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
622 gtk_image_new_from_stock(GTK_STOCK_REDO
, GTK_ICON_SIZE_MENU
));
623 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
624 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_find2_browser_replace_selected
), NULL
);
625 gtk_widget_show(item
);
627 if (mpd_server_check_version(connection
, 0, 12, 0))
629 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO
, NULL
);
630 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
631 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_find2_browser_show_info
), NULL
);
632 gtk_widget_show(item
);
636 if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
))) == 1)
638 mpd_Song
*song
= NULL
;
639 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree
));
643 gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
)),
648 if (path
&& gtk_tree_model_get_iter(model
, &iter
, path
))
650 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
652 submenu_for_song(menu
, song
);
655 gtk_tree_path_free(path
);
658 playlist_editor_right_mouse(menu
, pl3_find2_playlist_editor_add_to_playlist
, NULL
);
659 gmpc_mpddata_treeview_right_mouse_intergration(GMPC_MPDDATA_TREEVIEW(pl3_find2_tree
), GTK_MENU(menu
));
661 gtk_widget_show_all(menu
);
662 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
668 static void pl3_find2_browser_activate(void)
670 GtkTreeSelection
*selec
= gtk_tree_view_get_selection(GTK_TREE_VIEW(gtk_builder_get_object(pl3_xml
, "cat_tree")));
672 GtkTreePath
*path
= gtk_tree_row_reference_get_path(pl3_find2_ref
);
675 gtk_tree_selection_select_path(selec
, path
);
676 gtk_tree_path_free(path
);
678 gtk_widget_grab_focus(GTK_WIDGET(search_entry
));
681 static int pl3_find2_browser_add_go_menu(GtkWidget
* menu
)
683 GtkWidget
*item
= NULL
;
685 item
= gtk_image_menu_item_new_with_label(_("Search"));
686 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
687 gtk_image_new_from_icon_name("gtk-find", GTK_ICON_SIZE_MENU
));
688 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
689 gtk_widget_add_accelerator(GTK_WIDGET(item
),
690 "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_F3
, 0, GTK_ACCEL_VISIBLE
);
691 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_find2_browser_activate
), NULL
);
696 static void pl3_find2_browser_connection_changed(MpdObj
* mi
, int connect
, gpointer data
)
702 pl3_find2_browser_type_plugin_changed(GTK_COMBO_BOX(pl3_find2_curpl
), NULL
);
703 pl3_find2_browser_search();
707 void pl3_find2_select_plugin_id(int id
)
711 pl3_find2_browser_activate();
712 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(pl3_find2_curpl
));
713 if (gtk_tree_model_get_iter_first(model
, &iter
))
718 gmpcPluginParent
*plug
;
719 gtk_tree_model_get(model
, &iter
, 2, &plug
, -1);
720 if (plug
!= NULL
&& gmpc_plugin_get_id(plug
) == id
)
722 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pl3_find2_curpl
), &iter
);
725 } while (gtk_tree_model_iter_next(model
, &iter
) && found
);
727 gtk_widget_grab_focus(search_entry
);
730 static guint entry_timeout
= 0;
732 static gboolean
do_entry_changed_search(GtkEntry
* entry
)
734 pl3_find2_browser_search();
739 static void pl3_find2_entry_changed(GtkWidget
* entry
, gpointer data
)
741 if (entry_timeout
> 0)
743 g_source_remove(entry_timeout
);
746 if (cfg_get_single_value_as_int_with_default(config
, "general", "search-as-you-type", 0) == 1)
748 entry_timeout
= g_timeout_add(250, (GSourceFunc
) do_entry_changed_search
, entry
);
752 static gboolean
pl3_find2_entry_key_press_event(GtkWidget
* entry
, GdkEventKey
* event
, gpointer data
)
754 if (event
->keyval
== GDK_KEY_Escape
)
755 gtk_entry_set_text(GTK_ENTRY(entry
), "");
760 static void pl3_find2_browser_destroy(void)
766 path
= gtk_tree_row_reference_get_path(pl3_find2_ref
);
769 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(gtk_tree_row_reference_get_model(pl3_find2_ref
)), &iter
, path
))
771 gtk_list_store_remove(GTK_LIST_STORE(gtk_tree_row_reference_get_model(pl3_find2_ref
)), &iter
);
773 gtk_tree_path_free(path
);
775 gtk_tree_row_reference_free(pl3_find2_ref
);
776 pl3_find2_ref
= NULL
;
780 gtk_widget_destroy(pl3_find2_vbox
);
781 pl3_find2_vbox
= NULL
;
783 if (pl3_find2_store2
)
785 g_object_unref(pl3_find2_store2
);
786 pl3_find2_store2
= NULL
;
790 static void pl3_find2_browser_status_changed(MpdObj
* mi
, ChangedStatusType what
, void *data
)
792 if (what
& MPD_CST_DATABASE
)
794 pl3_find2_browser_search();
796 if (what
& MPD_CST_PERMISSION
)
799 pl3_find2_browser_type_plugin_changed(GTK_COMBO_BOX(pl3_find2_curpl
), NULL
);
803 static void pl3_find2_save_myself(void)
807 GtkTreePath
*path
= gtk_tree_row_reference_get_path(pl3_find2_ref
);
810 gint
*indices
= gtk_tree_path_get_indices(path
);
811 cfg_set_single_value_as_int(config
, "find2-browser", "position", indices
[0]);
812 gtk_tree_path_free(path
);
817 /* Easy command integration */
819 void pl3_find2_do_search_any(const char *param
)
823 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(search_combo
));
824 if (gtk_tree_model_get_iter_first(model
, &iter
))
830 gtk_tree_model_get(model
, &iter
, 0, &field
, -1);
831 if (field
== QUERY_ENTRY
)
833 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(search_combo
), &iter
);
836 } while (gtk_tree_model_iter_next(model
, &iter
) && found
);
838 gtk_entry_set_text(GTK_ENTRY(search_entry
), param
);
839 gtk_widget_activate(search_entry
);
842 static void pl3_find2_plugin_init(void)
844 gmpc_easy_command_add_entry(gmpc_easy_command
,
845 _("switch search"), "",
846 _("Switch to the search browser"),
847 (GmpcEasyCommandCallback
*) pl3_find2_browser_activate
, NULL
);
851 static int pl3_find2_get_enabled(void)
853 return cfg_get_single_value_as_int_with_default(config
, "find2-browser", "enable", TRUE
);
857 static void pl3_find2_set_enabled(int enabled
)
859 cfg_set_single_value_as_int(config
, "find2-browser", "enable", enabled
);
860 if (enabled
&& !pl3_find2_ref
)
862 GtkTreeView
*tree
= playlist3_get_category_tree_view();
863 pl3_find2_browser_add((GtkWidget
*) tree
);
864 } else if (!enabled
&& pl3_find2_ref
)
866 pl3_find2_browser_destroy();
872 gmpcPlBrowserPlugin find2_browser_gbp
= {
873 .add
= pl3_find2_browser_add
,
874 .selected
= pl3_find2_browser_selected
,
875 .unselected
= pl3_find2_browser_unselected
,
876 .add_go_menu
= pl3_find2_browser_add_go_menu
,
879 gmpcPlugin find2_browser_plug
= {
880 .name
= N_("Search Browser"),
881 .version
= {1, 1, 1},
882 .plugin_type
= GMPC_PLUGIN_PL_BROWSER
| GMPC_INTERNALL
,
883 .init
= pl3_find2_plugin_init
,
884 .destroy
= pl3_find2_browser_destroy
,
885 .browser
= &find2_browser_gbp
,
886 .mpd_status_changed
= pl3_find2_browser_status_changed
,
887 .mpd_connection_changed
= pl3_find2_browser_connection_changed
,
888 .save_yourself
= pl3_find2_save_myself
,
889 .get_enabled
= pl3_find2_get_enabled
,
890 .set_enabled
= pl3_find2_set_enabled
,