First context item equals double click
[gmpc.git] / src / browsers / playlist3-find2-browser.c
blobff39db70a171345bdff9c237d4d67f54db5b82a3
1 /*
2 *Copyright (C) 2004-2007 Qball Cow <qball@sarine.nl>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <glade/glade.h>
26 #include "plugin.h"
28 #include "main.h"
29 #include "misc.h"
30 #include "playlist3.h"
31 #include "playlist3-find2-browser.h"
32 #include "config1.h"
34 #include "gmpc-mpddata-model.h"
35 #include "gmpc-mpddata-treeview.h"
37 static void pl3_find2_browser_edit_columns(void);
38 static void pl3_find2_browser_destroy(void);
39 static void pl3_find2_browser_selected(GtkWidget *);
40 static void pl3_find2_browser_unselected(GtkWidget *);
41 static void pl3_find2_browser_add(GtkWidget *cat_tree);
42 static int pl3_find2_browser_add_go_menu(GtkWidget *);
43 static void pl3_find2_browser_search(void);
44 static void pl3_find2_browser_row_activated(GtkTreeView *, GtkTreePath *);
45 static int pl3_find2_browser_playlist_key_press(GtkWidget *, GdkEventKey *);
46 static void pl3_find2_browser_add_selected(void);
47 static gboolean pl3_find2_browser_button_release_event(GtkWidget *but, GdkEventButton *event);
48 static gboolean pl3_find2_browser_button_press_event(GtkWidget *giv, GdkEventButton *event, gpointer data);
49 static void pl3_find2_browser_connection_changed(MpdObj *mi, int connect, gpointer data);
50 static int pl3_find2_browser_key_press_event(GtkWidget *mw, GdkEventKey *event, int type);
51 static void pl3_find2_browser_status_changed(MpdObj *mi,ChangedStatusType what, void *data);
52 extern GladeXML *pl3_xml;
53 static void pl3_find2_combo_box_changed(GtkComboBox *cb, gpointer data);
55 static void pl3_find2_save_myself(void);
57 int pl3_find2_last_entry = MPD_TAG_ITEM_ANY;
61 typedef struct {
62 GtkWidget *hbox;
63 GtkWidget *combo;
64 GtkWidget *lcombo;
65 GtkWidget *entry;
66 int tag_type;
67 }crit_struct;
71 /* Playlist window row reference */
72 static GtkTreeRowReference *pl3_find2_ref = NULL;
75 extern GladeXML *pl3_xml;
77 /* internal */
78 static GtkWidget *pl3_find2_curpl = NULL;
79 static GtkWidget *pl3_find2_tree = NULL;
80 static GmpcMpdDataModel *pl3_find2_store2 = NULL;
81 static GtkWidget *pl3_find2_vbox = NULL;
82 static GtkWidget *pl3_find2_findbut = NULL;
83 static GtkWidget *pl3_find2_critaddbut = NULL;
84 static GtkListStore *pl3_find2_combo_store = NULL;
85 static GtkListStore *pl3_find2_autocomplete = NULL;
86 static GList *criterias = NULL;
87 static GtkWidget *pl3_find2_crit_vbox = NULL;
89 static void pl3_find2_fill_combo()
91 GtkTreeIter iter;
92 int i=0, max = 3;
93 gtk_list_store_clear(pl3_find2_combo_store);
95 if(mpd_server_check_version(connection,0,12,0))
97 max = MPD_TAG_NUM_OF_ITEM_TYPES;
99 for(i=0;i< max;i++)
101 gtk_list_store_append(pl3_find2_combo_store, &iter);
102 gtk_list_store_set(pl3_find2_combo_store, &iter, 1, mpdTagItemKeys[i], 0,i, -1);
106 static void pl3_find2_browser_bg_style_changed(GtkWidget *vbox, GtkStyle *style, GtkWidget *vp)
108 gtk_widget_modify_bg(vp,GTK_STATE_NORMAL, &(GTK_WIDGET(vbox)->style->light[GTK_STATE_SELECTED]));
111 static void pl3_find2_browser_remove_crit(GtkWidget *button,crit_struct *cs)
113 criterias = g_list_remove(criterias, cs);
114 gtk_widget_destroy(cs->hbox);
115 g_free(cs);
116 if(!criterias)
118 gtk_widget_set_sensitive(pl3_find2_findbut, FALSE);
120 pl3_find2_browser_search();
121 gtk_widget_set_sensitive(pl3_find2_critaddbut, TRUE);
123 static void pl3_find2_combo_box_changed(GtkComboBox *cb, gpointer data)
125 pl3_find2_last_entry= gtk_combo_box_get_active(cb);
129 * Add a criteria
131 static void pl3_find2_browser_add_crit()
133 crit_struct *cs = g_malloc0(sizeof(*cs));
134 GtkWidget *removebut = NULL;
135 GtkCellRenderer *renderer = NULL;
136 GtkEntryCompletion *ent_comp = NULL;
138 cs->hbox = gtk_hbox_new(FALSE, 6);
140 cs->lcombo = gtk_combo_box_new_text();
141 gtk_combo_box_append_text(GTK_COMBO_BOX(cs->lcombo), _("And"));
142 gtk_combo_box_append_text(GTK_COMBO_BOX(cs->lcombo), _("Or"));
143 gtk_combo_box_set_active(GTK_COMBO_BOX(cs->lcombo), 0);
144 gtk_box_pack_start(GTK_BOX(cs->hbox), cs->lcombo, FALSE, TRUE, 0);
146 cs->combo= gtk_combo_box_new();
148 renderer = gtk_cell_renderer_text_new();
149 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cs->combo), renderer, TRUE);
150 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cs->combo), renderer, "text", 1, NULL);
151 gtk_combo_box_set_model(GTK_COMBO_BOX(cs->combo), GTK_TREE_MODEL(pl3_find2_combo_store));
152 gtk_combo_box_set_active(GTK_COMBO_BOX(cs->combo), pl3_find2_last_entry);
153 gtk_box_pack_start(GTK_BOX(cs->hbox), cs->combo, FALSE, TRUE, 0);
154 g_signal_connect(G_OBJECT(cs->combo), "changed", G_CALLBACK(pl3_find2_combo_box_changed), NULL);
157 cs->entry = gtk_entry_new();
158 ent_comp = gtk_entry_completion_new();
159 gtk_entry_completion_set_text_column(ent_comp, 0);
160 gtk_entry_completion_set_inline_completion(ent_comp, TRUE);
161 gtk_entry_completion_set_model(GTK_ENTRY_COMPLETION(ent_comp), GTK_TREE_MODEL(pl3_find2_autocomplete));
162 gtk_entry_completion_set_popup_completion(GTK_ENTRY_COMPLETION(ent_comp), TRUE);
163 gtk_entry_set_completion(GTK_ENTRY(cs->entry), ent_comp);
166 g_signal_connect(G_OBJECT(cs->entry), "activate",G_CALLBACK(pl3_find2_browser_search), NULL);
167 gtk_box_pack_start(GTK_BOX(cs->hbox), cs->entry, TRUE, TRUE, 0);
169 removebut = gtk_button_new();
170 gtk_button_set_image(GTK_BUTTON(removebut), gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_BUTTON));
171 gtk_box_pack_end(GTK_BOX(cs->hbox), removebut, FALSE, TRUE, 0);
172 g_signal_connect(G_OBJECT(removebut), "clicked", G_CALLBACK(pl3_find2_browser_remove_crit),cs);
174 gtk_box_pack_start(GTK_BOX(pl3_find2_crit_vbox), cs->hbox, FALSE, TRUE,0);
176 criterias = g_list_append(criterias, cs);
178 gtk_widget_show_all(pl3_find2_vbox);
179 /** This causes some weird crashes when adding a default crit */
180 /* gtk_widget_grab_focus(cs->combo);*/
181 gtk_widget_set_sensitive(pl3_find2_findbut, TRUE);
184 gtk_widget_set_sensitive(pl3_find2_critaddbut, TRUE);
185 if(g_list_length(criterias) >= (MPD_TAG_NUM_OF_ITEM_TYPES-1))
187 gtk_widget_set_sensitive(pl3_find2_critaddbut, FALSE);
191 static void playtime_changed(GmpcMpdDataModel *model, gulong playtime)
193 if(pl3_cat_get_selected_browser() == find2_browser_plug.id)
195 playlist3_show_playtime(playtime);
200 * Construct the browser
202 static void pl3_find2_browser_init()
204 GtkWidget *frame, *event, *vbox, *label;
205 GtkWidget *pl3_find2_sw = NULL;
206 GtkWidget *hbox = NULL;
207 /* autocomplete later on */
208 pl3_find2_autocomplete = gtk_list_store_new(1, G_TYPE_STRING);
210 pl3_find2_store2 = gmpc_mpddata_model_new();
211 g_signal_connect(G_OBJECT(pl3_find2_store2), "playtime_changed", G_CALLBACK(playtime_changed), NULL);
214 pl3_find2_combo_store = gtk_list_store_new(2,G_TYPE_INT, G_TYPE_STRING);
215 /** Fill the view */
216 pl3_find2_fill_combo();
218 /* Column */
219 /* set up the tree */
220 pl3_find2_tree= gmpc_mpddata_treeview_new("find2-browser",TRUE,GTK_TREE_MODEL(pl3_find2_store2));
222 /* setup signals */
223 g_signal_connect(G_OBJECT(pl3_find2_tree), "row-activated",G_CALLBACK(pl3_find2_browser_row_activated), NULL);
224 g_signal_connect(G_OBJECT(pl3_find2_tree), "button-press-event", G_CALLBACK(pl3_find2_browser_button_press_event), NULL);
225 g_signal_connect(G_OBJECT(pl3_find2_tree), "button-release-event", G_CALLBACK(pl3_find2_browser_button_release_event), NULL);
226 g_signal_connect(G_OBJECT(pl3_find2_tree), "key-press-event", G_CALLBACK(pl3_find2_browser_playlist_key_press), NULL);
228 /* set up the scrolled window */
229 pl3_find2_sw = gtk_scrolled_window_new(NULL, NULL);
230 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_find2_sw), GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
231 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_find2_sw), GTK_SHADOW_ETCHED_IN);
232 gtk_container_add(GTK_CONTAINER(pl3_find2_sw), pl3_find2_tree);
234 /* set initial state */
236 pl3_find2_vbox = gtk_vbox_new(FALSE, 6);
237 gtk_box_pack_end(GTK_BOX(pl3_find2_vbox), pl3_find2_sw, TRUE, TRUE,0);
239 /* pom */
240 frame = gtk_frame_new(NULL);
241 event = gtk_event_box_new();
242 vbox = gtk_vbox_new(FALSE,6);
243 label = gtk_label_new("");
244 gtk_misc_set_alignment(GTK_MISC(label), 0,0.5);
246 /* Header box */
247 hbox = gtk_hbox_new(FALSE,0);
249 /* browser label */
250 gtk_label_set_markup(GTK_LABEL(label), _("<span size='xx-large' weight='bold'>Search</span>"));
251 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE,0);
253 /* search in playlist */
254 pl3_find2_curpl = gtk_check_button_new_with_mnemonic(_("Search in current _play queue"));
255 g_signal_connect(G_OBJECT(pl3_find2_curpl), "toggled", G_CALLBACK(pl3_find2_browser_search),NULL);
256 gtk_box_pack_start(GTK_BOX(hbox), pl3_find2_curpl, FALSE, TRUE,6);
258 /* find button */
259 pl3_find2_findbut = gtk_button_new_from_stock(GTK_STOCK_FIND);
260 gtk_widget_set_sensitive(pl3_find2_findbut, FALSE);
261 g_signal_connect(G_OBJECT(pl3_find2_findbut), "clicked", G_CALLBACK(pl3_find2_browser_search),NULL);
262 gtk_box_pack_start(GTK_BOX(hbox), pl3_find2_findbut, FALSE, TRUE,0);
264 /* Add criteria button */
265 pl3_find2_critaddbut = gtk_button_new();
266 gtk_button_set_image(GTK_BUTTON(pl3_find2_critaddbut), gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
267 g_signal_connect(G_OBJECT(pl3_find2_critaddbut), "clicked", G_CALLBACK(pl3_find2_browser_add_crit), NULL);
268 gtk_box_pack_start(GTK_BOX(hbox), pl3_find2_critaddbut, FALSE, TRUE,0);
270 /* Add it to the vbox */
271 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE,0);
273 gtk_container_set_border_width(GTK_CONTAINER(vbox), 12);
274 g_signal_connect(G_OBJECT(vbox), "style-set", G_CALLBACK(pl3_find2_browser_bg_style_changed), event);
276 pl3_find2_crit_vbox = gtk_vbox_new(FALSE,6);
277 gtk_box_pack_start(GTK_BOX(vbox), pl3_find2_crit_vbox, FALSE, TRUE,0);
279 /* add it */
280 gtk_container_add(GTK_CONTAINER(event), vbox);
281 gtk_container_add(GTK_CONTAINER(frame), event);
282 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
283 gtk_box_pack_start(GTK_BOX(pl3_find2_vbox), frame, FALSE, TRUE,0);
285 gtk_widget_show_all(pl3_find2_vbox);
286 g_object_ref(G_OBJECT(pl3_find2_vbox));
288 /** Add a default item */
289 pl3_find2_browser_add_crit();
292 static void pl3_find2_browser_selected(GtkWidget *container)
294 if(pl3_find2_tree == NULL)
296 pl3_find2_browser_init();
298 gtk_container_add(GTK_CONTAINER(container),pl3_find2_vbox);
299 gtk_widget_grab_focus(pl3_find2_tree);
300 gtk_widget_show(pl3_find2_vbox);
302 playlist3_show_playtime(gmpc_mpddata_model_get_playtime(GMPC_MPDDATA_MODEL(pl3_find2_store2)));
304 static void pl3_find2_browser_unselected(GtkWidget *container)
306 gtk_container_remove(GTK_CONTAINER(container), pl3_find2_vbox);
312 /*****************************************************************
313 * Find Browser
315 static void pl3_find2_browser_add(GtkWidget *cat_tree)
317 GtkTreePath *path = NULL;
318 GtkTreeIter iter;
319 gint pos = cfg_get_single_value_as_int_with_default(config, "find2-browser","position",4);
320 playlist3_insert_browser(&iter, pos);
321 gtk_list_store_set(GTK_LIST_STORE(pl3_tree), &iter,
322 PL3_CAT_TYPE, find2_browser_plug.id,
323 PL3_CAT_TITLE, _("Search"),
324 PL3_CAT_INT_ID, "",
325 PL3_CAT_ICON_ID, "gtk-find",
326 PL3_CAT_PROC, TRUE,
327 PL3_CAT_ICON_SIZE,GTK_ICON_SIZE_DND,-1);
329 if (pl3_find2_ref) {
330 gtk_tree_row_reference_free(pl3_find2_ref);
331 pl3_find2_ref = NULL;
334 path = gtk_tree_model_get_path(GTK_TREE_MODEL(playlist3_get_category_tree_store()), &iter);
335 if (path) {
336 pl3_find2_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(playlist3_get_category_tree_store()), path);
337 gtk_tree_path_free(path);
350 static gint __position_sort(gpointer aa, gpointer bb, gpointer data)
352 MpdData_real *a = *(MpdData_real **)aa;
353 MpdData_real *b = *(MpdData_real **)bb;
354 return a->song->pos - b->song->pos;
356 static unsigned long pl3_find2_browser_view_playlist()
358 if(mpd_server_check_command_allowed(connection, "playlistsearch")== MPD_SERVER_COMMAND_ALLOWED &&
359 mpd_server_check_command_allowed(connection, "playlistfind")== MPD_SERVER_COMMAND_ALLOWED)
361 GList *node = NULL;
362 int found = 0;
363 MpdData *data = NULL, *data_t= NULL;
364 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree), NULL);
365 if(criterias == NULL)
366 return 0;
367 /** check rules, see if there is a usefull one, if so compile a regex */
368 node= g_list_first(criterias);
369 for(; node; node = g_list_next(node))
371 GtkTreeIter cc_iter;
372 crit_struct *cs = node->data;
373 const gchar *name = gtk_entry_get_text(GTK_ENTRY(cs->entry));
374 cs->tag_type = -1;
375 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cs->combo), &cc_iter) && name && name[0] != '\0')
377 int num_field;
378 gchar **splitted = NULL;
379 int i =0;
380 splitted = tokenize_string(name);// g_strsplit(name, " ",0);
381 for(i=0;splitted && splitted[i];i++)
383 if(!found)
385 mpd_playlist_search_start(connection, FALSE);
386 found = TRUE;
388 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_combo_store),&cc_iter , 0, &num_field, -1);
390 mpd_playlist_search_add_constraint(connection, num_field, splitted[i]);
393 //mpd_playlist_search_add_constraint(connection, num_field, name);
394 if(splitted)
395 g_strfreev(splitted);
397 GtkTreeIter iter;
398 gboolean found2 = FALSE;
399 for(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter);
400 gtk_list_store_iter_is_valid(pl3_find2_autocomplete, &iter) && !found2;
401 gtk_tree_model_iter_next(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter))
403 gchar *entry;
404 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter, 0,&entry,-1);
405 if(strcmp(entry, name) == 0)
407 found2 = TRUE;
409 g_free(entry);
411 if(!found2) {
412 gtk_list_store_insert_with_values(pl3_find2_autocomplete, &iter,-1, 0,name,-1);
417 if(node->next)
419 crit_struct *cs2 = node->next->data;
420 if(gtk_combo_box_get_active(GTK_COMBO_BOX(cs2->lcombo))==1)
422 data = mpd_database_search_commit(connection);
423 data_t = mpd_data_concatenate(data_t, data);
424 data = NULL;
425 found = FALSE;
430 if(found)
431 data = mpd_playlist_search_commit(connection);
432 data_t = mpd_data_concatenate(data_t, data);
433 data_t = misc_mpddata_remove_duplicate_songs(data_t);
434 data_t = misc_sort_mpddata(data_t,(GCompareDataFunc)__position_sort,NULL);
435 gmpc_mpddata_model_set_mpd_data(pl3_find2_store2, data_t);
437 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree), GTK_TREE_MODEL(pl3_find2_store2));
439 return 0;
443 static unsigned long pl3_find2_browser_view_database()
445 GList *node = NULL;
446 int found = 0;
448 MpdData *data_t = NULL, *data =NULL;
450 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree), NULL);
451 if(criterias == NULL)
453 return 0;
455 node= g_list_first(criterias);
456 for(; node; node = g_list_next(node))
458 GtkTreeIter cc_iter;
459 int num_field;
460 crit_struct *cs = node->data;
461 const gchar *name = gtk_entry_get_text(GTK_ENTRY(cs->entry));
462 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cs->combo), &cc_iter) && name && name[0] != '\0')
464 gchar **splitted = NULL;
465 int i =0;
467 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_combo_store),&cc_iter , 0, &num_field, -1);
469 splitted = tokenize_string(name);//g_strsplit(name, " ",0);
470 for(i=0;splitted && splitted[i];i++)
472 if(!found)
474 mpd_database_search_start(connection, FALSE);
475 found = TRUE;
477 mpd_database_search_add_constraint(connection, num_field, splitted[i]);
479 if(splitted)
480 g_strfreev(splitted);
481 /* hack to correctly update the autocompletion. damn I must write something that does this more efficient */
483 GtkTreeIter iter;
484 gboolean found2 = FALSE;
485 for(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter);
486 gtk_list_store_iter_is_valid(pl3_find2_autocomplete, &iter) && !found2;
487 gtk_tree_model_iter_next(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter))
489 gchar *entry;
490 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete), &iter, 0,&entry,-1);
491 if(strcmp(entry, name) == 0)
493 found2 = TRUE;
495 g_free(entry);
497 if(!found2) {
498 gtk_list_store_insert_with_values(pl3_find2_autocomplete, &iter,-1, 0,name,-1);
502 if(node->next)
504 crit_struct *cs2 = node->next->data;
505 if(gtk_combo_box_get_active(GTK_COMBO_BOX(cs2->lcombo))==1)
507 data = mpd_database_search_commit(connection);
508 data_t = mpd_data_concatenate(data_t, data);
509 data = NULL;
510 found = FALSE;
514 if(found)
515 data = mpd_database_search_commit(connection);
516 data_t = mpd_data_concatenate(data_t, data);
517 data_t = misc_mpddata_remove_duplicate_songs(data_t);
518 gmpc_mpddata_model_set_mpd_data(pl3_find2_store2, data_t);
519 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree), GTK_TREE_MODEL(pl3_find2_store2));
520 return 0;
524 * Search
526 static void pl3_find2_browser_search()
528 if(pl3_find2_vbox == NULL)
529 return;
530 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pl3_find2_curpl)))
532 pl3_find2_browser_view_playlist();
533 }else{
534 pl3_find2_browser_view_database();
539 static void pl3_find2_browser_show_info()
541 GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW(pl3_find2_tree));
542 GtkTreeSelection *selection =gtk_tree_view_get_selection (GTK_TREE_VIEW(pl3_find2_tree));
543 if(!mpd_server_check_version(connection,0,12,0))
545 return;
547 if (gtk_tree_selection_count_selected_rows (selection) > 0)
549 GList *list = NULL;
550 list = gtk_tree_selection_get_selected_rows (selection, &model);
552 list = g_list_last (list);
554 GtkTreeIter iter;
555 mpd_Song *song =NULL;
556 char *path;
557 gtk_tree_model_get_iter (model, &iter, (GtkTreePath *) list->data);
558 gtk_tree_model_get(model,&iter,MPDDATA_MODEL_COL_PATH, &path,-1);
559 song = mpd_database_get_fileinfo(connection, path);
560 if(song) {
561 info2_activate();
562 info2_fill_song_view(song);
563 mpd_freeSong(song);
565 q_free(path);
568 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
569 g_list_free (list);
573 static void pl3_find2_browser_row_activated(GtkTreeView *tree, GtkTreePath *tp)
575 GtkTreeIter iter;
576 gchar *song_id;
577 gint r_type;
578 gtk_tree_model_get_iter(gtk_tree_view_get_model(tree), &iter, tp);
579 gtk_tree_model_get(gtk_tree_view_get_model(tree), &iter,MPDDATA_MODEL_COL_PATH,&song_id,MPDDATA_MODEL_ROW_TYPE, &r_type, -1);
581 play_path(song_id);
584 q_free(song_id);
587 static void pl3_find2_browser_replace_selected()
589 mpd_playlist_clear(connection);
590 if(mpd_check_connected(connection))
592 pl3_find2_browser_add_selected();
593 mpd_player_play(connection);
597 static int pl3_find2_browser_playlist_key_press(GtkWidget *tree, GdkEventKey *event)
599 if(event->state == GDK_CONTROL_MASK && event->keyval == GDK_Insert)
601 pl3_find2_browser_replace_selected();
603 else if(event->keyval == GDK_Insert)
605 pl3_find2_browser_add_selected();
607 else if(event->keyval == GDK_i && event->state&GDK_MOD1_MASK)
609 pl3_find2_browser_show_info();
611 else
613 return pl3_window_key_press_event(tree,event);
615 return TRUE;
620 static void pl3_find2_browser_add_selected()
622 GtkTreeIter iter;
623 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(pl3_find2_tree));
624 GtkTreeModel *model = GTK_TREE_MODEL (pl3_find2_store2);
625 GList *rows = gtk_tree_selection_get_selected_rows (selection, &model);
626 int songs=0;
627 if(rows != NULL)
629 gchar *name;
630 gint type;
631 GList *node = g_list_first(rows);
634 GtkTreePath *path = node->data;
635 gtk_tree_model_get_iter (model, &iter, path);
636 gtk_tree_model_get (model, &iter,MPDDATA_MODEL_COL_PATH,&name,MPDDATA_MODEL_ROW_TYPE, &type, -1);
637 /* does this bitmask thingy works ok? I think it hsould */
638 if(type == MPD_DATA_TYPE_SONG)
640 /* add them to the add list */
641 mpd_playlist_queue_add(connection, name);
643 songs++;
644 q_free(name);
645 }while((node = g_list_next(node)) != NULL);
647 /* if there are items in the add list add them to the playlist */
648 mpd_playlist_queue_commit(connection);
649 if(songs != 0)
651 gchar * message = g_strdup_printf("Added %i song%s", songs, (songs != 1)? "s":"");
652 pl3_push_statusbar_message(message);
653 q_free(message);
656 g_list_foreach (rows, (GFunc) gtk_tree_path_free, NULL);
657 g_list_free (rows);
659 static void pl3_find2_browser_edit_columns(void)
661 gmpc_mpddata_treeview_edit_columns(GMPC_MPDDATA_TREEVIEW(pl3_find2_tree));
664 static gboolean pl3_find2_browser_button_press_event(GtkWidget *giv, GdkEventButton *event, gpointer data)
666 GtkTreePath *path = NULL;
667 if(event->button == 3 &&gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(giv), event->x, event->y,&path,NULL,NULL,NULL))
669 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(giv));
670 if(gtk_tree_selection_path_is_selected(sel, path))
672 gtk_tree_path_free(path);
673 return TRUE;
676 if(path) {
677 gtk_tree_path_free(path);
679 return FALSE;
681 static void pl3_find2_playlist_editor_add_to_playlist(GtkWidget *menu)
683 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree));
684 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree));
685 gchar *data = g_object_get_data(G_OBJECT(menu), "playlist");
686 GList *iter, *list = gtk_tree_selection_get_selected_rows (selection, &model);
687 if(list)
689 iter = g_list_first(list);
691 GtkTreeIter giter;
692 if(gtk_tree_model_get_iter(model, &giter, (GtkTreePath *)iter->data))
694 gchar *file = NULL;
695 gtk_tree_model_get(model, &giter, MPDDATA_MODEL_COL_PATH, &file, -1);
696 mpd_database_playlist_list_add(connection, data,file);
697 g_free(file);
699 }while((iter = g_list_next(iter)));
701 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
702 g_list_free (list);
705 playlist_editor_fill_list();
709 * Play the selected row, only usefull if one row is selected
711 static void pl3_find2_activate_row(GtkWidget *item,GtkTreeView *tree)
713 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree));
714 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree));
715 GList *iter, *list = gtk_tree_selection_get_selected_rows (selection, &model);
716 if(list)
718 iter = g_list_first(list);
720 GtkTreeIter giter;
721 if(gtk_tree_model_get_iter(model, &giter, (GtkTreePath *)iter->data))
723 gchar *song_id;
724 gtk_tree_model_get(gtk_tree_view_get_model(tree), &giter,MPDDATA_MODEL_COL_PATH,&song_id, -1);
725 play_path(song_id);
726 q_free(song_id);
728 }while((iter = g_list_next(iter)));
730 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
731 g_list_free (list);
735 static gboolean pl3_find2_browser_button_release_event(GtkWidget *but, GdkEventButton *event)
737 if(event->button != 3) return FALSE;
738 else if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree))) > 0)
740 GtkWidget *item;
741 GtkWidget *menu = gtk_menu_new();
743 if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree))) == 1)
745 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_MEDIA_PLAY,NULL);
746 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
747 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(pl3_find2_activate_row), pl3_find2_tree);
751 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD,NULL);
752 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
753 g_signal_connect(G_OBJECT(item), "activate",
754 G_CALLBACK(pl3_find2_browser_add_selected), NULL);
755 gtk_widget_show(item);
757 /* add the replace widget */
758 item = gtk_image_menu_item_new_with_label(_("Replace"));
759 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
760 gtk_image_new_from_stock(GTK_STOCK_REDO, GTK_ICON_SIZE_MENU));
761 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
762 g_signal_connect(G_OBJECT(item), "activate",
763 G_CALLBACK(pl3_find2_browser_replace_selected), NULL);
764 gtk_widget_show(item);
766 if(mpd_server_check_version(connection,0,12,0))
768 item = gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO,NULL);
769 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
770 g_signal_connect(G_OBJECT(item), "activate",
771 G_CALLBACK(pl3_find2_browser_show_info), NULL);
772 gtk_widget_show(item);
775 item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
776 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
777 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
778 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
779 g_signal_connect(G_OBJECT(item), "activate",
780 G_CALLBACK(pl3_find2_browser_edit_columns), NULL);
781 gtk_widget_show(item);
782 /* add sub menu */
783 if(gtk_tree_selection_count_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree))) == 1)
785 mpd_Song *song = NULL;
786 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_find2_tree));
787 GtkTreePath *path;
788 GtkTreeIter iter;
789 GList *list = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree)),&model);
790 path = list->data;
791 /* free result */
792 g_list_free(list);
793 if(path && gtk_tree_model_get_iter(model, &iter, path)) {
794 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_MPDSONG, &song, -1);
795 if(song)
796 submenu_for_song(menu, song);
798 if(path)
799 gtk_tree_path_free(path);
803 playlist_editor_right_mouse(menu,pl3_find2_playlist_editor_add_to_playlist);
805 gtk_widget_show_all(menu);
806 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,NULL, NULL, 0, event->time);
807 return TRUE;
809 return FALSE;
812 static void pl3_find2_browser_disconnect()
817 static void pl3_find2_browser_activate()
819 GtkTreeSelection *selec = gtk_tree_view_get_selection((GtkTreeView *)
820 glade_xml_get_widget (pl3_xml, "cat_tree"));
822 GtkTreePath *path = gtk_tree_row_reference_get_path(pl3_find2_ref);
823 if(path)
825 gtk_tree_selection_select_path(selec, path);
826 gtk_tree_path_free(path);
830 static int pl3_find2_browser_add_go_menu(GtkWidget *menu)
832 GtkWidget *item = NULL;
834 item = gtk_image_menu_item_new_with_label(_("Search"));
835 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
836 gtk_image_new_from_icon_name("gtk-find", GTK_ICON_SIZE_MENU));
837 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
838 gtk_widget_add_accelerator(GTK_WIDGET(item),
839 "activate",
840 gtk_menu_get_accel_group(GTK_MENU(menu)),
841 GDK_F3, 0,
842 GTK_ACCEL_VISIBLE);
843 g_signal_connect(G_OBJECT(item), "activate",
844 G_CALLBACK(pl3_find2_browser_activate), NULL);
846 return 1;
849 static void pl3_find2_browser_connection_changed(MpdObj *mi, int connect, gpointer data)
851 if(!connect)
853 pl3_find2_browser_disconnect();
858 * Handle program-global key events
860 static int pl3_find2_browser_key_press_event(GtkWidget *mw, GdkEventKey *event, int type)
862 if(event->state&GDK_CONTROL_MASK && event->keyval == GDK_j)
864 crit_struct *cs;
865 pl3_find2_browser_activate();
867 while(criterias && g_list_length(criterias) > 1)
869 cs = criterias->data;
870 criterias = g_list_remove(criterias, cs);
871 gtk_widget_destroy(cs->hbox);
872 q_free(cs);
874 if(!criterias)
876 pl3_find2_browser_add_crit();
878 cs = criterias->data;
879 gtk_combo_box_set_active(GTK_COMBO_BOX(cs->combo), MPD_TAG_ITEM_ANY);
880 gtk_widget_grab_focus(cs->entry);
881 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pl3_find2_curpl), TRUE);
882 return TRUE;
885 return FALSE;
888 static void pl3_find2_browser_destroy(void)
890 if(pl3_find2_ref)
892 GtkTreeIter iter;
893 GtkTreePath *path;
894 path = gtk_tree_row_reference_get_path(pl3_find2_ref);
895 if(path)
897 if(gtk_tree_model_get_iter(GTK_TREE_MODEL(gtk_tree_row_reference_get_model(pl3_find2_ref)), &iter,path))
899 gtk_list_store_remove(GTK_LIST_STORE(gtk_tree_row_reference_get_model(pl3_find2_ref)), &iter);
901 gtk_tree_path_free(path);
903 gtk_tree_row_reference_free(pl3_find2_ref);
904 pl3_find2_ref = NULL;
906 if(pl3_find2_vbox)
908 gtk_widget_destroy(pl3_find2_vbox);
909 pl3_find2_vbox = NULL;
911 if(pl3_find2_store2)
913 g_object_unref(pl3_find2_store2);
914 pl3_find2_store2 = NULL;
918 static void pl3_find2_browser_status_changed(MpdObj *mi,ChangedStatusType what, void *data)
920 if(what&MPD_CST_DATABASE)
922 pl3_find2_browser_search();
925 static void pl3_find2_save_myself(void)
927 if(pl3_find2_ref)
929 GtkTreePath *path = gtk_tree_row_reference_get_path(pl3_find2_ref);
930 if(path)
932 gint *indices = gtk_tree_path_get_indices(path);
933 debug_printf(DEBUG_INFO,"Saving myself to position: %i\n", indices[0]);
934 cfg_set_single_value_as_int(config, "find2-browser","position",indices[0]);
935 gtk_tree_path_free(path);
940 * Plugin structure
942 gmpcPlBrowserPlugin find2_browser_gbp = {
943 .add = pl3_find2_browser_add,
944 .selected = pl3_find2_browser_selected,
945 .unselected = pl3_find2_browser_unselected,
946 .add_go_menu = pl3_find2_browser_add_go_menu,
947 .key_press_event = pl3_find2_browser_key_press_event
950 gmpcPlugin find2_browser_plug = {
951 .name = "Search Browser",
952 .version = {1,1,1},
953 .plugin_type = GMPC_PLUGIN_PL_BROWSER,
954 .destroy = pl3_find2_browser_destroy,
955 .browser = &find2_browser_gbp,
956 .mpd_status_changed = pl3_find2_browser_status_changed,
957 .mpd_connection_changed = pl3_find2_browser_connection_changed,
958 .save_yourself = pl3_find2_save_myself,