Add new gmpc-data-view (DOES NOT WORK COMPLETELY)
[gmpc.git] / src / browsers / playlist3-find2-browser.c
blob1c4ca863c60467f598c6494c3877c597311a38e7
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.
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "main.h"
25 #include "misc.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;
53 /* internal */
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)
68 GtkTreeIter iter;
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)
89 GtkTreeIter iter;
90 if (gtk_combo_box_get_active_iter(cb, &iter))
92 gint selected_type;
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))
96 gchar *type;
97 gchar *cfield = NULL;
98 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(data)), &iter, 0, &type, -1);
99 if (type)
101 cfield = g_strdup_printf("selected_type_%s", type);
102 g_free(type);
103 cfg_set_single_value_as_int(config, "find2-browser", cfield, selected_type);
104 g_free(cfield);
110 static void playtime_changed(GmpcMpdDataModel * model, gulong playtime)
114 static void pl3_find2_browser_type_plugin_changed(GtkComboBox * box, gpointer user_data)
116 GtkTreeIter iter;
117 GtkTreeModel *model = gtk_combo_box_get_model(box);
118 gmpcPluginParent *plug = NULL;
119 gchar *cfield = NULL;
120 gchar *type = NULL;
121 gint selected_type;
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);
132 g_free(cfield);
133 g_free(type);
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))
139 gint sel_type;
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);
144 return;
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,
152 gpointer user_data)
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)
165 GtkWidget *button;
166 GtkWidget *pl3_find2_sw = NULL;
167 GtkWidget *hbox = NULL;
168 GtkCellRenderer *renderer;
169 GtkEntryCompletion *entrcomp;
170 int i;
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);
179 /** Fill the view */
180 pl3_find2_fill_combo(NULL);
182 /* Column */
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);
188 /* setup signals */
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),
193 NULL);
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]))
224 GtkTreeIter titer;
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);
238 /* What tag field */
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);
271 /* find button */
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 /*****************************************************************
299 * Find Browser
301 static void pl3_find2_browser_add(GtkWidget * cat_tree)
303 GtkTreePath *path = NULL;
304 GtkTreeIter iter;
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,
311 -1);
313 if (pl3_find2_ref)
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);
320 if (path)
322 pl3_find2_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path);
323 gtk_tree_path_free(path);
328 * Search
330 static void pl3_find2_browser_search(void)
332 GtkTreeIter iter, cc_iter;
333 if (pl3_find2_vbox == NULL)
334 return;
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))
339 int type;
340 int num_field;
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);
351 if (plug)
352 data_t = gmpc_plugin_browser_integrate_search(plug, num_field, name, &error);
353 if (error)
355 gchar *mes =
356 g_markup_printf_escaped("<b>%s</b> %s: %s", gmpc_plugin_get_name(plug), _("Search failed"),
357 error->message);
358 playlist3_show_error_message(mes, ERROR_WARNING);
359 g_free(mes);
360 g_error_free(error);
361 error = NULL;
363 gmpc_mpddata_model_set_mpd_data(pl3_find2_store2, data_t);
364 /* update autocompletion */
365 if (data_t)
367 int found2 = 0;
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))
372 gchar *entry;
373 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter, 0, &entry, -1);
374 if (strcmp(entry, name) == 0)
376 found2 = TRUE;
378 g_free(entry);
380 if (!found2)
382 gtk_list_store_insert_with_values(pl3_find2_autocomplete, &iter, -1, 0, name, -1);
385 g_free(name);
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))
397 return;
399 if (gtk_tree_selection_count_selected_rows(selection) > 0)
401 GList *list = NULL;
402 list = gtk_tree_selection_get_selected_rows(selection, &model);
404 list = g_list_last(list);
406 GtkTreeIter iter;
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);
410 if (song)
412 info2_activate();
413 info2_fill_song_view(song);
417 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
418 g_list_free(list);
422 static void pl3_find2_browser_row_activated(GtkTreeView * tree, GtkTreePath * tp)
424 GtkTreeIter iter;
425 gchar *song_id;
426 gint r_type;
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,
429 &r_type, -1);
431 play_path(song_id);
434 q_free(song_id);
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();
452 return TRUE;
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));
458 return TRUE;
459 } else
461 return pl3_window_key_press_event(tree, event);
463 return FALSE;
466 static void pl3_find2_browser_add_selected(void)
468 GtkTreeIter iter;
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);
472 int songs = 0;
473 if (rows != NULL)
475 gchar *name;
476 gint type;
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);
492 songs++;
494 q_free(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);
501 g_list_free(rows);
504 static void pl3_find2_browser_add_all(void)
506 GtkTreeIter iter;
507 GtkTreeModel *model = GTK_TREE_MODEL(pl3_find2_store2);
508 int songs = 0;
509 if (gtk_tree_model_get_iter_first(model, &iter))
511 gchar *name;
512 gint type;
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);
525 songs++;
527 q_free(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);
540 if (list)
542 iter = g_list_first(list);
545 GtkTreeIter giter;
546 if (gtk_tree_model_get_iter(model, &giter, (GtkTreePath *) iter->data))
548 gchar *file = NULL;
549 gtk_tree_model_get(model, &giter, MPDDATA_MODEL_COL_PATH, &file, -1);
550 mpd_database_playlist_list_add(connection, data, file);
551 g_free(file);
553 } while ((iter = g_list_next(iter)));
555 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
556 g_list_free(list);
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);
570 if(list)
572 iter = g_list_first(list);
574 GtkTreeIter giter;
575 if(gtk_tree_model_get_iter(model, &giter, (GtkTreePath *)iter->data))
577 gchar *song_id;
578 gtk_tree_model_get(gtk_tree_view_get_model(tree), &giter,MPDDATA_MODEL_COL_PATH,&song_id, -1);
579 play_path(song_id);
580 q_free(song_id);
582 }while((iter = g_list_next(iter)));
584 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
585 g_list_free (list);
590 static gboolean pl3_find2_browser_button_release_event(GtkWidget * but, GdkEventButton * event)
592 if (event->button != 3)
593 return FALSE;
594 else if (gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree))) > 0)
596 GtkWidget *item;
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);
635 /* add sub menu */
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));
640 GtkTreePath *path;
641 GtkTreeIter iter;
642 GList *list =
643 gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree)),
644 &model);
645 path = list->data;
646 /* free result */
647 g_list_free(list);
648 if (path && gtk_tree_model_get_iter(model, &iter, path))
650 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
651 if (song)
652 submenu_for_song(menu, song);
654 if (path)
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);
663 return TRUE;
665 return FALSE;
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);
673 if (path)
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);
693 return 1;
696 static void pl3_find2_browser_connection_changed(MpdObj * mi, int connect, gpointer data)
698 /* Clear the list */
699 if (connect)
701 if (pl3_find2_curpl)
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)
709 GtkTreeIter iter;
710 GtkTreeModel *model;
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))
715 int found = 1;
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);
723 found = 0;
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();
735 entry_timeout = 0;
736 return FALSE;
739 static void pl3_find2_entry_changed(GtkWidget * entry, gpointer data)
741 if (entry_timeout > 0)
743 g_source_remove(entry_timeout);
744 entry_timeout = 0;
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), "");
757 return FALSE;
760 static void pl3_find2_browser_destroy(void)
762 if (pl3_find2_ref)
764 GtkTreeIter iter;
765 GtkTreePath *path;
766 path = gtk_tree_row_reference_get_path(pl3_find2_ref);
767 if (path)
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;
778 if (pl3_find2_vbox)
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)
798 if (pl3_find2_curpl)
799 pl3_find2_browser_type_plugin_changed(GTK_COMBO_BOX(pl3_find2_curpl), NULL);
803 static void pl3_find2_save_myself(void)
805 if (pl3_find2_ref)
807 GtkTreePath *path = gtk_tree_row_reference_get_path(pl3_find2_ref);
808 if (path)
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)
821 GtkTreeIter iter;
822 GtkTreeModel *model;
823 model = gtk_combo_box_get_model(GTK_COMBO_BOX(search_combo));
824 if (gtk_tree_model_get_iter_first(model, &iter))
826 int found = 1;
829 int field;
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);
834 found = 0;
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();
870 * Plugin structure
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,