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.
21 #include <gdk/gdkkeysyms.h>
24 #include <glade/glade.h>
30 #include "playlist3.h"
31 #include "playlist3-find2-browser.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
;
71 /* Playlist window row reference */
72 static GtkTreeRowReference
*pl3_find2_ref
= NULL
;
75 extern GladeXML
*pl3_xml
;
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()
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
;
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
);
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
);
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
);
216 pl3_find2_fill_combo();
219 /* set up the tree */
220 pl3_find2_tree
= gmpc_mpddata_treeview_new("find2-browser",TRUE
,GTK_TREE_MODEL(pl3_find2_store2
));
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);
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);
247 hbox
= gtk_hbox_new(FALSE
,0);
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);
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);
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 /*****************************************************************
315 static void pl3_find2_browser_add(GtkWidget
*cat_tree
)
317 GtkTreePath
*path
= NULL
;
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"),
325 PL3_CAT_ICON_ID
, "gtk-find",
327 PL3_CAT_ICON_SIZE
,GTK_ICON_SIZE_DND
,-1);
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
);
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
)
363 MpdData
*data
= NULL
, *data_t
= NULL
;
364 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree
), NULL
);
365 if(criterias
== NULL
)
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
))
372 crit_struct
*cs
= node
->data
;
373 const gchar
*name
= gtk_entry_get_text(GTK_ENTRY(cs
->entry
));
375 if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cs
->combo
), &cc_iter
) && name
&& name
[0] != '\0')
378 gchar
**splitted
= NULL
;
380 splitted
= tokenize_string(name
);// g_strsplit(name, " ",0);
381 for(i
=0;splitted
&& splitted
[i
];i
++)
385 mpd_playlist_search_start(connection
, FALSE
);
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);
395 g_strfreev(splitted
);
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
))
404 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete
), &iter
, 0,&entry
,-1);
405 if(strcmp(entry
, name
) == 0)
412 gtk_list_store_insert_with_values(pl3_find2_autocomplete
, &iter
,-1, 0,name
,-1);
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
);
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
));
443 static unsigned long pl3_find2_browser_view_database()
448 MpdData
*data_t
= NULL
, *data
=NULL
;
450 gtk_tree_view_set_model(GTK_TREE_VIEW(pl3_find2_tree
), NULL
);
451 if(criterias
== NULL
)
455 node
= g_list_first(criterias
);
456 for(; node
; node
= g_list_next(node
))
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
;
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
++)
474 mpd_database_search_start(connection
, FALSE
);
477 mpd_database_search_add_constraint(connection
, num_field
, splitted
[i
]);
480 g_strfreev(splitted
);
481 /* hack to correctly update the autocompletion. damn I must write something that does this more efficient */
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
))
490 gtk_tree_model_get(GTK_TREE_MODEL(pl3_find2_autocomplete
), &iter
, 0,&entry
,-1);
491 if(strcmp(entry
, name
) == 0)
498 gtk_list_store_insert_with_values(pl3_find2_autocomplete
, &iter
,-1, 0,name
,-1);
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
);
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
));
526 static void pl3_find2_browser_search()
528 if(pl3_find2_vbox
== NULL
)
530 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pl3_find2_curpl
)))
532 pl3_find2_browser_view_playlist();
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))
547 if (gtk_tree_selection_count_selected_rows (selection
) > 0)
550 list
= gtk_tree_selection_get_selected_rows (selection
, &model
);
552 list
= g_list_last (list
);
555 mpd_Song
*song
=NULL
;
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
);
562 info2_fill_song_view(song
);
568 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
573 static void pl3_find2_browser_row_activated(GtkTreeView
*tree
, GtkTreePath
*tp
)
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);
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();
613 return pl3_window_key_press_event(tree
,event
);
620 static void pl3_find2_browser_add_selected()
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
);
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
);
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
);
651 gchar
* message
= g_strdup_printf("Added %i song%s", songs
, (songs
!= 1)? "s":"");
652 pl3_push_statusbar_message(message
);
656 g_list_foreach (rows
, (GFunc
) gtk_tree_path_free
, NULL
);
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 &>k_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
);
677 gtk_tree_path_free(path
);
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
);
689 iter
= g_list_first(list
);
692 if(gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*)iter
->data
))
695 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, -1);
696 mpd_database_playlist_list_add(connection
, data
,file
);
699 }while((iter
= g_list_next(iter
)));
701 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
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
);
718 iter
= g_list_first(list
);
721 if(gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*)iter
->data
))
724 gtk_tree_model_get(gtk_tree_view_get_model(tree
), &giter
,MPDDATA_MODEL_COL_PATH
,&song_id
, -1);
728 }while((iter
= g_list_next(iter
)));
730 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);
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)
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
);
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
));
789 GList
*list
= gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_find2_tree
)),&model
);
793 if(path
&& gtk_tree_model_get_iter(model
, &iter
, path
)) {
794 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
796 submenu_for_song(menu
, song
);
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
);
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
);
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
),
840 gtk_menu_get_accel_group(GTK_MENU(menu
)),
843 g_signal_connect(G_OBJECT(item
), "activate",
844 G_CALLBACK(pl3_find2_browser_activate
), NULL
);
849 static void pl3_find2_browser_connection_changed(MpdObj
*mi
, int connect
, gpointer data
)
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
)
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
);
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
);
888 static void pl3_find2_browser_destroy(void)
894 path
= gtk_tree_row_reference_get_path(pl3_find2_ref
);
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
;
908 gtk_widget_destroy(pl3_find2_vbox
);
909 pl3_find2_vbox
= NULL
;
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)
929 GtkTreePath
*path
= gtk_tree_row_reference_get_path(pl3_find2_ref
);
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
);
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",
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
,