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-file-browser.h"
28 #include "playlist3-find2-browser.h"
29 #include "advanced-search.h"
30 #include "gmpc-mpddata-model.h"
31 #include "gmpc-mpddata-treeview.h"
32 #include "playlist3-playlist-editor.h"
33 #include "gmpc-extras.h"
35 #define LOG_DOMAIN "FileBrowser"
37 static void pl3_file_browser_plugin_init(void);
39 static gboolean
pl3_file_browser_is_field_supported(int tag
);
40 static MpdData
*pl3_file_browser_is_search(const int num_field
, const gchar
* search_string
, GError
** error
);
42 static int pl3_file_browser_option_menu(GmpcMpdDataTreeview
*tree
, GtkMenu
*menu
);
44 static void pl3_file_browser_destroy(void);
45 static void pl3_file_browser_add(GtkWidget
* cat_tree
);
46 static void pl3_file_browser_unselected(GtkWidget
* container
);
47 static void pl3_file_browser_selected(GtkWidget
* container
);
48 static void pl3_file_browser_fill_tree(GtkWidget
* tree
, GtkTreeIter
* iter
, GtkTreePath
* tpath
, gpointer user_data
);
49 static void pl3_file_browser_collapse_row(GtkTreeView
* tree
, GtkTreeIter
* iter
, GtkTreePath
* path
,
51 static int pl3_file_browser_cat_popup(GtkWidget
* tree
, GdkEventButton
* event
, gpointer user_data
);
52 static gboolean
pl3_file_browser_cat_key_press(GtkWidget
* tree
, GdkEventKey
* event
, gpointer data
);
53 static void pl3_file_browser_delete_playlist_from_right(GtkMenuItem
* bt
);
55 static void pl3_file_browser_reupdate(void);
56 static void pl3_file_browser_save_myself(void);
57 static int pl3_file_browser_add_go_menu(GtkWidget
* menu
);
58 static void pl3_file_browser_activate(void);
59 static gboolean
pl3_file_browser_button_release_event(GtkWidget
* but
, GdkEventButton
* event
);
60 static void pl3_file_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* tp
);
61 static void pl3_file_browser_add_selected(void);
62 static void pl3_file_browser_replace_selected(void);
63 static int pl3_file_browser_playlist_key_press(GtkWidget
* tree
, GdkEventKey
* event
);
64 static void pl3_file_browser_show_info(void);
65 static void pl3_file_browser_view_folder(GtkTreeSelection
* selection
, gpointer user_data
);
66 static void pl3_file_browser_update_folder(void);
67 static void pl3_file_browser_add_folder(void);
68 static void pl3_file_browser_delete_playlist(GtkMenuItem
* bt
);
69 static void pl3_file_browser_connection_changed(MpdObj
* mi
, int connect
, gpointer data
);
70 static void pl3_file_browser_status_changed(MpdObj
* mi
, ChangedStatusType what
, void *data
);
71 static void pl3_file_browser_disconnect(void);
73 GtkTreeRowReference
*pl3_fb_tree_ref
= NULL
;
85 static int pl3_file_browser_get_enabled(void)
87 return cfg_get_single_value_as_int_with_default(config
, "file-browser", "enable", TRUE
);
90 static void pl3_file_browser_set_enabled(int enabled
)
92 cfg_set_single_value_as_int(config
, "file-browser", "enable", enabled
);
95 GtkTreeView
*tree
= playlist3_get_category_tree_view();
96 pl3_file_browser_add((GtkWidget
*) tree
);
99 pl3_file_browser_destroy();
106 gmpcPlBrowserPlugin file_browser_gbp
= {
107 .add
= pl3_file_browser_add
,
108 .selected
= pl3_file_browser_selected
,
109 .unselected
= pl3_file_browser_unselected
,
110 .add_go_menu
= pl3_file_browser_add_go_menu
,
111 .integrate_search_field_supported
= pl3_file_browser_is_field_supported
,
112 .integrate_search
= pl3_file_browser_is_search
,
113 .song_list_option_menu
= pl3_file_browser_option_menu
116 gmpcPlugin file_browser_plug
= {
117 .name
= N_("Database"),
120 .plugin_type
= GMPC_PLUGIN_PL_BROWSER
| GMPC_INTERNALL
,
121 .init
= pl3_file_browser_plugin_init
,
122 .destroy
= pl3_file_browser_destroy
,
123 .browser
= &file_browser_gbp
,
124 .mpd_status_changed
= pl3_file_browser_status_changed
,
125 .mpd_connection_changed
= pl3_file_browser_connection_changed
,
126 .get_enabled
= pl3_file_browser_get_enabled
,
127 .set_enabled
= pl3_file_browser_set_enabled
,
128 .save_yourself
= pl3_file_browser_save_myself
132 GtkWidget
*pl3_fb_tree
= NULL
;
133 GtkWidget
*pl3_fb_vbox
= NULL
;
134 GtkWidget
*pl3_fb_tree_search
= NULL
;
135 GmpcMpdDataModel
*pl3_fb_store2
= NULL
;
136 static GtkTreeStore
*pl3_fb_dir_store
= NULL
;
137 static GtkWidget
*pl3_fb_dir_tree
= NULL
;
138 static GtkWidget
*pl3_fb_warning_box
= NULL
;
140 static void pl3_file_browser_dir_row_activated(GtkTreeView
* tree
, GtkTreePath
* tp
, GtkTreeViewColumn
* col
,
143 if (!mpd_check_connected(connection
))
145 if (gtk_tree_view_row_expanded(tree
, tp
))
146 gtk_tree_view_collapse_row(tree
, tp
);
148 gtk_tree_view_expand_row(tree
, tp
, FALSE
);
151 static void playtime_changed(GmpcMpdDataModel
* model
, gulong playtime
)
154 static void pl3_file_support_help_button_clicked(GObject
*a
)
156 open_help("ghelp:gmpc?ProblemSolving");
158 static void pl3_file_browser_init(void)
160 GtkCellRenderer
*renderer
;
161 GtkTreeViewColumn
*column
;
162 GtkWidget
*pl3_fb_sw
= NULL
;
163 GtkWidget
*vbox
, *sw
, *tree
,*label
;
164 GtkWidget
*misc
, *button
;
166 pl3_fb_store2
= gmpc_mpddata_model_new();
167 gmpc_mpddata_model_disable_image(GMPC_MPDDATA_MODEL(pl3_fb_store2
));
168 g_signal_connect(G_OBJECT(pl3_fb_store2
), "playtime_changed", G_CALLBACK(playtime_changed
), NULL
);
170 pl3_fb_vbox
= gtk_hpaned_new();
171 gmpc_paned_size_group_add_paned(GMPC_PANED_SIZE_GROUP(paned_size_group
), GTK_PANED(pl3_fb_vbox
));
172 vbox
= gtk_vbox_new(FALSE
, 6);
174 /* icon id, name, full path */
175 pl3_fb_dir_store
= gtk_tree_store_new(4, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_BOOLEAN
);
177 sw
= gtk_scrolled_window_new(NULL
, NULL
);
178 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
179 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
), GTK_SHADOW_ETCHED_IN
);
180 pl3_fb_dir_tree
= tree
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(pl3_fb_dir_store
));
181 gtk_tree_view_set_enable_tree_lines(GTK_TREE_VIEW(tree
), TRUE
);
182 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree
), TRUE
);
183 column
= gtk_tree_view_column_new();
184 gtk_tree_view_column_set_title(column
, _("Directories"));
185 renderer
= gtk_cell_renderer_pixbuf_new();
186 gtk_tree_view_column_pack_start(column
, renderer
, FALSE
);
187 gtk_tree_view_column_add_attribute(column
, renderer
, "icon-name", PL3_FB_ICON
);
188 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
189 renderer
= gtk_cell_renderer_text_new();
190 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
191 gtk_tree_view_column_add_attribute(column
, renderer
, "text", PL3_FB_NAME
);
192 gtk_tree_view_insert_column(GTK_TREE_VIEW(tree
), column
, -1);
194 gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(tree
), TRUE
);
195 gtk_tree_view_set_search_column(GTK_TREE_VIEW(pl3_fb_dir_tree
), PL3_FB_NAME
);
196 /* set the search column */
197 gtk_tree_view_set_search_column(GTK_TREE_VIEW(tree
), PL3_FB_NAME
);
199 g_signal_connect(G_OBJECT(tree
), "row-expanded", G_CALLBACK(pl3_file_browser_fill_tree
), NULL
);
200 g_signal_connect(G_OBJECT(tree
), "row-collapsed", G_CALLBACK(pl3_file_browser_collapse_row
), NULL
);
201 g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
))), "changed",
202 G_CALLBACK(pl3_file_browser_view_folder
), NULL
);
203 g_signal_connect(G_OBJECT(tree
), "button-release-event", G_CALLBACK(pl3_file_browser_cat_popup
), NULL
);
204 g_signal_connect(G_OBJECT(tree
), "key-press-event", G_CALLBACK(pl3_file_browser_cat_key_press
), NULL
);
205 g_signal_connect(G_OBJECT(tree
), "row-activated", G_CALLBACK(pl3_file_browser_dir_row_activated
), NULL
);
207 gtk_container_add(GTK_CONTAINER(sw
), tree
);
208 gtk_widget_show_all(sw
);
209 gtk_paned_add1(GTK_PANED(pl3_fb_vbox
), sw
);
211 /* set up the tree */
212 pl3_fb_tree
= gmpc_mpddata_treeview_new("file-browser", TRUE
, GTK_TREE_MODEL(pl3_fb_store2
));
213 gmpc_mpddata_treeview_enable_click_fix(GMPC_MPDDATA_TREEVIEW(pl3_fb_tree
));
214 gtk_tree_view_set_search_column(GTK_TREE_VIEW(pl3_fb_tree
), MPDDATA_MODEL_COL_SONG_TITLE
);
216 g_signal_connect(G_OBJECT(pl3_fb_tree
), "row-activated", G_CALLBACK(pl3_file_browser_row_activated
), NULL
);
217 g_signal_connect(G_OBJECT(pl3_fb_tree
), "button-release-event", G_CALLBACK(pl3_file_browser_button_release_event
),
219 g_signal_connect(G_OBJECT(pl3_fb_tree
), "key-press-event", G_CALLBACK(pl3_file_browser_playlist_key_press
), NULL
);
221 /* set up the scrolled window */
222 pl3_fb_sw
= gtk_scrolled_window_new(NULL
, NULL
);
223 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pl3_fb_sw
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
224 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pl3_fb_sw
), GTK_SHADOW_ETCHED_IN
);
225 gtk_container_add(GTK_CONTAINER(pl3_fb_sw
), pl3_fb_tree
);
227 gtk_box_pack_start(GTK_BOX(vbox
), pl3_fb_sw
, TRUE
, TRUE
, 0);
228 gtk_widget_show_all(pl3_fb_sw
);
230 /******************************************/
231 /* Warning box for when there is no music */
232 /******************************************/
233 pl3_fb_warning_box
= gtk_vbox_new(FALSE
, 6);
235 label
= gtk_label_new("");
236 gtk_label_set_markup(GTK_LABEL(label
),
237 _("It seems you have no music in your database.\n"
238 "To add music, copy the music to your <i>music_directory</i> as specified in your mpd config file.\n"
239 "Then update the database. (Server->Update Database)"));
240 gtk_misc_set_alignment(GTK_MISC(label
), 0.0, 0.0);
241 gtk_widget_show(label
);
242 gtk_box_pack_start(GTK_BOX(pl3_fb_warning_box
), label
, FALSE
, FALSE
, 0);
245 misc
= gtk_alignment_new(0, 0.5, 0, 0);
246 button
= gtk_button_new_from_stock(GTK_STOCK_HELP
);
247 g_signal_connect(G_OBJECT(button
), "clicked",
248 G_CALLBACK(pl3_file_support_help_button_clicked
), NULL
);
249 gtk_container_add(GTK_CONTAINER(misc
), button
);
250 gtk_widget_show(button
);
251 gtk_widget_show_all(misc
);
252 gtk_box_pack_start(GTK_BOX(pl3_fb_warning_box
), misc
, FALSE
, FALSE
, 0);
253 gtk_widget_set_no_show_all(pl3_fb_warning_box
, TRUE
);
256 gtk_box_pack_end(GTK_BOX(vbox
), pl3_fb_warning_box
, FALSE
, TRUE
, 0);
257 gtk_paned_add2(GTK_PANED(pl3_fb_vbox
), vbox
);
258 /* set initial state */
259 gtk_widget_show(vbox
);
260 gtk_widget_show(pl3_fb_vbox
);
261 g_object_ref_sink(G_OBJECT(pl3_fb_vbox
));
264 static void pl3_file_browser_add_folder(void)
266 GtkTreeSelection
*selec
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_dir_tree
));
267 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
270 if (!mpd_check_connected(connection
))
274 if (gtk_tree_selection_get_selected(selec
, &model
, &iter
))
277 gtk_tree_model_get(model
, &iter
, PL3_FB_PATH
, &path
, PL3_FB_ICON
, &icon
, -1);
279 if (strcmp("media-playlist", icon
))
281 mpd_playlist_queue_add(connection
, path
);
284 mpd_playlist_queue_load(connection
, path
);
286 mpd_playlist_queue_commit(connection
);
292 static void pl3_file_browser_update_folder(void)
294 GtkTreeSelection
*selec
= gtk_tree_view_get_selection((GtkTreeView
*) pl3_fb_dir_tree
);
295 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
298 if (!mpd_check_connected(connection
))
302 if (gtk_tree_selection_get_selected(selec
, &model
, &iter
))
305 gtk_tree_model_get(model
, &iter
, PL3_FB_PATH
, &path
, -1);
308 mpd_database_update_dir(connection
, path
);
315 static void pl3_file_browser_update_folder_left_pane(void)
317 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_store2
);
318 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
321 if (!mpd_check_connected(connection
))
324 if (gtk_tree_selection_count_selected_rows(selection
) == 1)
326 GList
*list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
328 if (gtk_tree_model_get_iter(model
, &iter
, list
->data
))
331 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &path
, -1);
334 mpd_database_update_dir(connection
, path
);
338 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
343 static void pl3_file_browser_replace_folder(void)
345 mpd_playlist_clear(connection
);
346 if (mpd_check_connected(connection
))
348 pl3_file_browser_add_folder();
349 mpd_player_play(connection
);
353 /* add's the toplevel entry for the file browser, it also add's a fantom child */
354 static void pl3_file_browser_add(GtkWidget
* cat_tree
)
360 pos
= cfg_get_single_value_as_int_with_default(config
, "file-browser", "position", 2);
363 playlist3_insert_browser(&iter
, PL3_CAT_BROWSER_LIBRARY
+pos
%PL3_CAT_BROWSER_LIBRARY
);
364 TEC("insert browser")
365 gtk_list_store_set(GTK_LIST_STORE(pl3_tree
), &iter
,
366 PL3_CAT_TYPE
, file_browser_plug
.id
,
367 PL3_CAT_TITLE
, _("Database"), PL3_CAT_ICON_ID
, "gmpc-database", -1);
368 TEC("set list store")
372 gtk_tree_row_reference_free(pl3_fb_tree_ref
);
373 pl3_fb_tree_ref
= NULL
;
375 TEC("Free references")
377 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_tree
), &iter
);
380 pl3_fb_tree_ref
= gtk_tree_row_reference_new(GTK_TREE_MODEL(pl3_tree
), path
);
381 gtk_tree_path_free(path
);
383 TEC("New references")
388 static int directory_sort_func(gpointer ppaa
, gpointer ppbb
, gpointer data
)
390 MpdData_real
*a
= *(MpdData_real
**) ppaa
;
391 MpdData_real
*b
= *(MpdData_real
**) ppbb
;
395 if (a
->type
!= b
->type
)
396 return a
->type
- b
->type
;
397 if ((a
->type
== MPD_DATA_TYPE_DIRECTORY
) && (b
->type
== MPD_DATA_TYPE_DIRECTORY
))
399 if (a
->directory
&& b
->directory
)
402 sa
= g_utf8_strdown(a
->directory
, -1);
403 sb
= g_utf8_strdown(b
->directory
, -1);
404 val
= g_utf8_collate(sa
, sb
);
412 /* Reverse sort function, needed for prepending instead of appending */
413 static int directory_sort_func_inv(gpointer a
, gpointer b
, gpointer d
)
415 return -directory_sort_func(a
, b
, d
);
418 static void pl3_file_browser_reupdate_folder(GtkTreeIter
* iter
)
420 MpdData
*data
= NULL
;
422 gboolean temp
= FALSE
;
423 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
424 gtk_tree_model_get(GTK_TREE_MODEL(pl3_fb_dir_store
), iter
, 3, &temp
, 2, &path
, -1);
427 GtkTreeIter child
, child2
, child3
;
428 data
= mpd_database_get_directory(connection
, path
);
429 data
= misc_sort_mpddata(data
, (GCompareDataFunc
) directory_sort_func
, NULL
);
431 if (gtk_tree_model_iter_children(model
, &child
, iter
))
433 gchar
*test_path
= NULL
;
434 gboolean has_next
= FALSE
;
437 gtk_tree_model_get(model
, &child
, 3, &temp
, 2, &test_path
, -1);
441 /* if no more data, remove the subdir */
442 has_next
= gtk_tree_store_remove(pl3_fb_dir_store
, &child
);
446 /* get the next directory */
447 while (data
&& data
->type
!= MPD_DATA_TYPE_DIRECTORY
)
448 data
= mpd_data_get_next(data
);
451 compare
= strcmp(data
->directory
, test_path
);
454 gchar
*basename
= g_path_get_basename(data
->directory
);
455 gtk_tree_store_insert_before(pl3_fb_dir_store
, &child2
, iter
, &child
);
456 gtk_tree_store_set(pl3_fb_dir_store
, &child2
,
457 PL3_FB_ICON
, "gtk-open",
458 PL3_FB_NAME
, basename
,
459 PL3_FB_PATH
, data
->directory
, PL3_FB_OPEN
, FALSE
, -1);
461 gtk_tree_store_append(pl3_fb_dir_store
, &child3
, &child2
);
464 /* if the new dir is smaller the temp, we add it. */
465 data
= mpd_data_get_next(data
);
467 } else if (compare
> 0)
469 /* if it's bigger, we delete the row */
470 has_next
= gtk_tree_store_remove(pl3_fb_dir_store
, &child
);
474 /* if equal we process children if available */
477 pl3_file_browser_reupdate_folder(&child
);
479 /* move to next entry in both */
480 has_next
= gtk_tree_model_iter_next(model
, &child
);
481 data
= mpd_data_get_next(data
);
491 if (data
->type
== MPD_DATA_TYPE_DIRECTORY
)
493 gchar
*basename
= g_path_get_basename(data
->directory
);
494 gtk_tree_store_append(pl3_fb_dir_store
, &child2
, iter
);
495 gtk_tree_store_set(pl3_fb_dir_store
, &child2
,
496 PL3_FB_ICON
, "gtk-open",
497 PL3_FB_NAME
, basename
, PL3_FB_PATH
, data
->directory
, PL3_FB_OPEN
, FALSE
, -1);
498 gtk_tree_store_append(pl3_fb_dir_store
, &child3
, &child2
);
501 } while ((data
= mpd_data_get_next(data
)));
507 static void pl3_file_browser_reupdate(void)
514 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
516 if (mpd_stats_get_total_songs(connection
) == 0 && !mpd_status_db_is_updating(connection
))
518 gtk_widget_show(pl3_fb_warning_box
);
521 gtk_widget_hide(pl3_fb_warning_box
);
524 if (gtk_tree_model_get_iter_first(model
, &iter
))
527 if (!gtk_tree_model_iter_children(model
, &child
, &iter
))
529 gtk_tree_store_set(GTK_TREE_STORE(model
), &iter
, PL3_FB_OPEN
, FALSE
, -1);
530 gtk_tree_store_append(pl3_fb_dir_store
, &child
, &iter
);
532 pl3_file_browser_reupdate_folder(&iter
);
533 pl3_file_browser_view_folder(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_dir_tree
)), NULL
);
538 static void pl3_file_browser_view_folder(GtkTreeSelection
* selection
, gpointer user_data
)
540 MpdData
*data
= NULL
;
541 char *path
= NULL
, *icon
= NULL
;
542 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
543 GtkTreeIter iter_cat
;
545 gmpc_mpddata_model_set_mpd_data(pl3_fb_store2
, NULL
);
547 if (!gtk_tree_selection_get_selected(selection
, &model
, &iter_cat
))
550 /* check the connection state and when its valid proceed */
551 if (!mpd_check_connected(connection
))
555 gtk_tree_model_get(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter_cat
, PL3_FB_PATH
, &path
, PL3_FB_ICON
, &icon
, -1);
556 if (strcmp("media-playlist", icon
))
558 data
= mpd_database_get_directory(connection
, path
);
561 data
= mpd_database_get_playlist_content(connection
, path
);
563 /* Check, and set the up arrow in the model */
564 if (!strcmp(path
, "/"))
565 gmpc_mpddata_model_set_has_up(pl3_fb_store2
, FALSE
);
567 gmpc_mpddata_model_set_has_up(pl3_fb_store2
, TRUE
);
568 gmpc_mpddata_model_set_mpd_data(pl3_fb_store2
, data
);
574 static void pl3_file_browser_collapse_row(GtkTreeView
* tree
, GtkTreeIter
* iter
, GtkTreePath
* path
,
578 int valid
= gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store
), &child
, iter
);
579 if (!cfg_get_single_value_as_int_with_default(config
, "file-browser", "extra-lazy", TRUE
))
584 valid
= gtk_tree_store_remove(pl3_fb_dir_store
, &child
);
587 gtk_tree_store_set(pl3_fb_dir_store
, iter
, PL3_FB_OPEN
, FALSE
, -1);
588 /* add phantom child */
589 gtk_tree_store_append(pl3_fb_dir_store
, &child
, iter
);
592 static void pl3_file_browser_fill_tree(GtkWidget
* tree
, GtkTreeIter
* iter
, GtkTreePath
* tpath
, gpointer user_data
)
595 MpdData
*data
= NULL
;
596 GtkTreeIter child
, child2
, dummy
;
598 gtk_tree_model_get(GTK_TREE_MODEL(pl3_fb_dir_store
), iter
, PL3_FB_PATH
, &path
, PL3_FB_OPEN
, &open
, -1);
599 gtk_tree_store_set(pl3_fb_dir_store
, iter
, PL3_FB_OPEN
, TRUE
, -1);
602 GTimer
*tim
= g_timer_new();
603 data
= mpd_database_get_directory(connection
, path
);
604 /* Do a reverse sort, because adding it to the gtk view by prepending is faster
606 data
= misc_sort_mpddata(data
, (GCompareDataFunc
) directory_sort_func_inv
, NULL
);
607 g_log(LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Elapsed time sorting before adding: %f\n", g_timer_elapsed(tim
, NULL
));
609 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store
), &dummy
, iter
))
613 if (data
->type
== MPD_DATA_TYPE_DIRECTORY
)
615 gchar
*basename
= g_path_get_basename(data
->directory
);
616 gtk_tree_store_prepend(pl3_fb_dir_store
, &child
, iter
);
617 gtk_tree_store_set(pl3_fb_dir_store
, &child
,
618 PL3_FB_ICON
, "gtk-open",
619 PL3_FB_NAME
, basename
, PL3_FB_PATH
, data
->directory
, PL3_FB_OPEN
, FALSE
, -1);
620 gtk_tree_store_append(pl3_fb_dir_store
, &child2
, &child
);
624 data
= mpd_data_get_next(data
);
627 gtk_tree_store_remove(pl3_fb_dir_store
, &dummy
);
630 g_log(LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Elapsed time sorting after adding: %f\n", g_timer_elapsed(tim
, NULL
));
631 g_timer_destroy(tim
);
638 static int pl3_file_browser_cat_popup(GtkWidget
* wid
, GdkEventButton
* event
, gpointer user_data
)
641 if (event
->button
== 3)
644 /* here we have: Add. Replace, (update?) */
646 menu
= gtk_menu_new();
647 /* add the add widget */
648 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD
, NULL
);
649 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
650 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_add_folder
), NULL
);
652 /* add the replace widget */
653 item
= gtk_image_menu_item_new_with_label(_("Replace"));
654 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
655 gtk_image_new_from_stock(GTK_STOCK_REDO
, GTK_ICON_SIZE_MENU
));
656 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item
), NULL
);
657 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
658 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_replace_folder
), NULL
);
661 GtkTreeView
*tree
= GTK_TREE_VIEW(pl3_fb_dir_tree
);
662 GtkTreeModel
*model
= (GtkTreeModel
*) pl3_fb_dir_store
;
663 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(tree
);
665 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
668 gtk_tree_model_get(model
, &iter
, PL3_FB_ICON
, &icon
, -1);
669 if (!strcmp("media-playlist", icon
))
671 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE
, NULL
);
672 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
673 g_signal_connect(G_OBJECT(item
), "activate",
674 G_CALLBACK(pl3_file_browser_delete_playlist_from_right
), NULL
);
677 /* add the update widget */
678 item
= gtk_image_menu_item_new_with_label(_("Update"));
679 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
680 gtk_image_new_from_stock(GTK_STOCK_REFRESH
, GTK_ICON_SIZE_MENU
));
681 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
682 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_update_folder
), NULL
);
687 gtk_widget_show_all(menu
);
688 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
689 /* show everything and popup */
695 static gboolean
pl3_file_browser_cat_key_press(GtkWidget
* tree
, GdkEventKey
* event
, gpointer data
)
697 if (event
->state
& GDK_CONTROL_MASK
&& (event
->keyval
== GDK_KEY_Insert
|| event
->keyval
== GDK_KEY_KP_Insert
))
699 pl3_file_browser_replace_folder();
700 } else if (event
->keyval
== GDK_KEY_Insert
|| event
->keyval
== GDK_KEY_KP_Insert
)
702 pl3_file_browser_add_folder();
707 static int pl3_file_browser_playlist_key_press(GtkWidget
* tree
, GdkEventKey
* event
)
709 if (event
->keyval
== GDK_KEY_i
&& event
->state
& GDK_MOD1_MASK
)
711 pl3_file_browser_show_info();
716 static void pl3_file_browser_selected(GtkWidget
* container
)
718 if (pl3_fb_tree
== NULL
)
720 GtkTreeIter iter
,child
;
721 pl3_file_browser_init();
722 gtk_tree_store_append(pl3_fb_dir_store
, &iter
, NULL
);
723 gtk_tree_store_set(pl3_fb_dir_store
, &iter
,
724 PL3_FB_ICON
, "gtk-open", PL3_FB_NAME
, "/", PL3_FB_PATH
, "/", PL3_FB_OPEN
, FALSE
, -1);
725 gtk_tree_store_append(pl3_fb_dir_store
, &child
, &iter
);
728 gtk_container_add(GTK_CONTAINER(container
), pl3_fb_vbox
);
729 gtk_widget_grab_focus(pl3_fb_tree
);
730 gtk_widget_show(pl3_fb_vbox
);
732 /* Make sure root node is always open. */
735 if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_fb_dir_store
), &child
))
737 GtkTreePath
*path
= NULL
;
738 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_fb_dir_store
), &child
);
739 gtk_tree_view_expand_row(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
,FALSE
);
740 gtk_tree_path_free(path
);
746 static void pl3_file_browser_unselected(GtkWidget
* container
)
748 gtk_container_remove(GTK_CONTAINER(container
), pl3_fb_vbox
);
751 static void pl3_file_browser_show_info(void)
753 GtkTreeModel
*model
= gtk_tree_view_get_model(GTK_TREE_VIEW(pl3_fb_tree
));
754 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
755 if (!mpd_server_check_version(connection
, 0, 12, 0))
759 if (gtk_tree_selection_count_selected_rows(selection
) > 0)
762 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
764 list
= g_list_last(list
);
766 mpd_Song
*song
= NULL
;
769 gtk_tree_model_get_iter(model
, &iter
, (GtkTreePath
*) list
->data
);
770 gtk_tree_model_get(GTK_TREE_MODEL(pl3_fb_store2
), &iter
,
771 MPDDATA_MODEL_ROW_TYPE
, &type
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
772 if (type
== MPD_DATA_TYPE_SONG
)
777 info2_fill_song_view(song
);
781 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
786 static void pl3_file_browser_row_activated(GtkTreeView
* tree
, GtkTreePath
* tp
)
792 gtk_tree_model_get_iter(gtk_tree_view_get_model(tree
), &iter
, tp
);
793 gtk_tree_model_get(gtk_tree_view_get_model(tree
), &iter
, MPDDATA_MODEL_COL_PATH
, &song_path
, MPDDATA_MODEL_ROW_TYPE
,
795 if (song_path
== NULL
&& r_type
!= -1)
799 if (r_type
== MPD_DATA_TYPE_PLAYLIST
)
801 mpd_playlist_queue_load(connection
, song_path
);
802 mpd_playlist_queue_commit(connection
);
803 } else if (r_type
== MPD_DATA_TYPE_DIRECTORY
)
805 GtkTreeSelection
*selec
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_dir_tree
));
806 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
808 if (gtk_tree_selection_get_selected(selec
, &model
, &iter
))
811 GtkTreePath
*path
= gtk_tree_model_get_path(model
, &iter
);
812 gtk_tree_view_expand_row(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
, FALSE
);
813 gtk_tree_path_free(path
);
814 if (gtk_tree_model_iter_children(model
, &citer
, &iter
))
820 gtk_tree_model_get(model
, &citer
, PL3_FB_PATH
, &name
, PL3_FB_ICON
, &type
, -1);
821 if (strcmp(name
, song_path
) == 0 && strcmp(type
, "gtk-open") == 0)
823 gtk_tree_selection_select_iter(selec
, &citer
);
824 path
= gtk_tree_model_get_path(model
, &citer
);
825 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
, NULL
, TRUE
, 0.5, 0);
826 gtk_tree_path_free(path
);
830 } while (gtk_tree_model_iter_next(model
, &citer
));
834 } else if (r_type
== -1)
836 GtkTreeSelection
*selec
= gtk_tree_view_get_selection((GtkTreeView
*) pl3_fb_dir_tree
);
837 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_dir_store
);
839 if (gtk_tree_selection_get_selected(selec
, &model
, &iter
))
842 if (gtk_tree_model_iter_parent(model
, &piter
, &iter
))
844 GtkTreePath
*path
= NULL
;
845 gtk_tree_selection_select_iter(selec
, &piter
);
846 path
= gtk_tree_model_get_path(model
, &piter
);
847 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
, NULL
, TRUE
, 0.5, 0);
848 gtk_tree_path_free(path
);
853 play_path(song_path
);
859 static void pl3_file_browser_add_to_playlist(GtkWidget
* menu
, gpointer cb_data
)
861 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_store2
);
862 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
863 gchar
*data
= g_object_get_data(G_OBJECT(menu
), "playlist");
864 GList
*iter
, *list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
867 iter
= g_list_first(list
);
871 if (gtk_tree_model_get_iter(model
, &giter
, (GtkTreePath
*) iter
->data
))
875 gtk_tree_model_get(model
, &giter
, MPDDATA_MODEL_COL_PATH
, &file
, MPDDATA_MODEL_ROW_TYPE
, &type
, -1);
876 if (type
== MPD_DATA_TYPE_SONG
)
878 mpd_database_playlist_list_add(connection
, data
, file
);
879 } else if (type
== MPD_DATA_TYPE_DIRECTORY
)
881 MpdData
*data2
= mpd_database_get_directory_recursive(connection
, file
);
882 for (; data2
; data2
= mpd_data_get_next(data2
))
884 if (data2
->type
== MPD_DATA_TYPE_SONG
)
886 mpd_database_playlist_list_add(connection
, data
, data2
->song
->file
);
892 } while ((iter
= g_list_next(iter
)));
894 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
899 static gboolean
pl3_file_browser_button_release_event(GtkWidget
* but
, GdkEventButton
* event
)
902 GtkWidget
*menu
= NULL
;
903 GtkTreeSelection
*sel
= NULL
;
904 if (event
->button
!= 3)
906 menu
= gtk_menu_new();
907 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
908 /* don't show it when where listing custom streams...
909 * show always when version 12.. or when searching in playlist.
911 if (gtk_tree_selection_count_selected_rows(sel
) == 1)
913 mpd_Song
*song
= NULL
;
914 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_store2
);
915 GList
*list
= gtk_tree_selection_get_selected_rows(sel
, &model
);
921 GtkTreePath
*tree_path
;
922 list
= g_list_first(list
);
923 gtk_tree_model_get_iter(model
, &iter
, list
->data
);
924 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &path
, MPDDATA_MODEL_ROW_TYPE
, &row_type
, -1);
925 if (row_type
== MPD_DATA_TYPE_SONG
)
927 if (mpd_server_check_version(connection
, 0, 12, 0))
929 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DIALOG_INFO
, NULL
);
930 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
931 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_show_info
), NULL
);
933 /* add the add widget */
934 if(mpd_server_check_command_allowed(connection
, "prioid") ==
935 MPD_SERVER_COMMAND_ALLOWED
)
937 item
= gtk_image_menu_item_new_with_label(_("Add (raised priority)"));
938 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
939 g_signal_connect_swapped(G_OBJECT(item
), "activate",
940 G_CALLBACK(gmpc_mpddata_treeview_insert_selected_rows_with_priority
),
943 } else if (row_type
== MPD_DATA_TYPE_PLAYLIST
)
945 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_DELETE
, NULL
);
946 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
947 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_delete_playlist
), NULL
);
948 } else if (row_type
== MPD_DATA_TYPE_DIRECTORY
)
950 item
= gtk_image_menu_item_new_with_label(_("Update"));
951 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
952 gtk_image_new_from_stock(GTK_STOCK_REFRESH
, GTK_ICON_SIZE_MENU
));
953 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
954 g_signal_connect(G_OBJECT(item
), "activate",
955 G_CALLBACK(pl3_file_browser_update_folder_left_pane
), NULL
);
959 /* replace the replace widget */
960 item
= gtk_image_menu_item_new_with_label(_("Replace"));
961 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
962 gtk_image_new_from_stock(GTK_STOCK_REDO
, GTK_ICON_SIZE_MENU
));
963 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), item
);
964 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_replace_selected
), NULL
);
966 /* add the delete widget */
967 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD
, NULL
);
968 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), item
);
969 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_add_selected
), NULL
);
971 playlist_editor_right_mouse(menu
, pl3_file_browser_add_to_playlist
, NULL
);
974 tree_path
= list
->data
;
975 if (tree_path
&& gtk_tree_model_get_iter(model
, &iter
, tree_path
))
977 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
980 submenu_for_song(menu
, song
);
983 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
989 /* replace the replace widget */
990 item
= gtk_image_menu_item_new_with_label(_("Replace"));
991 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
992 gtk_image_new_from_stock(GTK_STOCK_REDO
, GTK_ICON_SIZE_MENU
));
993 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), item
);
994 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_replace_selected
), NULL
);
996 if(mpd_server_check_command_allowed(connection
, "prioid") ==
997 MPD_SERVER_COMMAND_ALLOWED
)
999 item
= gtk_image_menu_item_new_with_label(_("Add (raised priority)"));
1000 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), item
);
1001 g_signal_connect_swapped(G_OBJECT(item
), "activate",
1002 G_CALLBACK(gmpc_mpddata_treeview_insert_selected_rows_with_priority
),
1005 /* add the delete widget */
1006 item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_ADD
, NULL
);
1007 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), item
);
1008 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_add_selected
), NULL
);
1010 gmpc_mpddata_treeview_right_mouse_intergration(GMPC_MPDDATA_TREEVIEW(pl3_fb_tree
), GTK_MENU(menu
));
1014 item = gtk_image_menu_item_new_with_label(_("Edit Columns"));
1015 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item),
1016 gtk_image_new_from_stock(GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU));
1017 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1018 g_signal_connect(G_OBJECT(item), "activate",
1019 G_CALLBACK(pl3_file_browser_edit_columns), NULL);
1021 gtk_widget_show_all(menu
);
1022 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 0, event
->time
);
1026 gtk_widget_destroy(menu);
1032 static void pl3_file_browser_replace_selected(void)
1034 mpd_playlist_clear(connection
);
1035 if (mpd_check_connected(connection
))
1037 pl3_file_browser_add_selected();
1038 mpd_player_play(connection
);
1042 static void pl3_file_browser_add_selected(void)
1045 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
1046 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_store2
);
1047 GList
*rows
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1051 /*gchar *message; */
1056 GList
*node
= g_list_first(rows
);
1059 GtkTreePath
*path
= node
->data
;
1060 gtk_tree_model_get_iter(model
, &iter
, path
);
1061 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &name
, MPDDATA_MODEL_ROW_TYPE
, &type
, -1);
1062 /* does this bitmask thingy works ok? I think it hsould */
1063 if (type
== MPD_DATA_TYPE_SONG
|| type
== MPD_DATA_TYPE_DIRECTORY
)
1065 /* add them to the add list */
1066 mpd_playlist_queue_add(connection
, name
);
1067 if (type
== MPD_DATA_TYPE_DIRECTORY
)
1069 if (type
== MPD_DATA_TYPE_SONG
)
1071 } else if (type
== MPD_DATA_TYPE_PLAYLIST
)
1073 mpd_playlist_queue_load(connection
, name
);
1077 } while ((node
= g_list_next(node
)) != NULL
);
1079 /* if there are items in the add list add them to the playlist */
1080 mpd_playlist_queue_commit(connection
);
1081 g_list_foreach(rows
, (GFunc
) gtk_tree_path_free
, NULL
);
1085 static void pl3_file_browser_delete_playlist_from_right(GtkMenuItem
* bt
)
1087 GtkTreeView
*tree
= GTK_TREE_VIEW(pl3_fb_dir_tree
);
1088 GtkTreeModel
*model
= (GtkTreeModel
*) pl3_fb_dir_store
;
1089 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(tree
);
1092 /* create a warning message dialog */
1093 GtkWidget
*dialog
= gtk_message_dialog_new(GTK_WINDOW(playlist3_get_window()),
1095 GTK_MESSAGE_WARNING
,
1097 _("Are you sure you want to clear the selected playlist?"));
1099 gtk_dialog_add_buttons(GTK_DIALOG(dialog
), GTK_STOCK_NO
, GTK_RESPONSE_CANCEL
, GTK_STOCK_YES
, GTK_RESPONSE_OK
, NULL
);
1100 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_CANCEL
);
1102 if (gtk_tree_selection_get_selected(selection
, &model
, &iter
))
1105 gtk_tree_model_get(model
, &iter
, 3, &icon
, 2, &path
, -1);
1106 if (path
&& strcmp("media-playlist", icon
))
1117 gtk_widget_destroy(dialog
);
1121 switch (gtk_dialog_run(GTK_DIALOG(dialog
)))
1123 case GTK_RESPONSE_OK
:
1124 mpd_database_delete_playlist(connection
, path
);
1125 pl3_file_browser_reupdate();
1129 gtk_widget_destroy(GTK_WIDGET(dialog
));
1133 static void pl3_file_browser_delete_playlist(GtkMenuItem
* bt
)
1136 GtkTreeSelection
*sel
= NULL
;
1137 /* create a warning message dialog */
1138 GtkWidget
*dialog
= gtk_message_dialog_new(GTK_WINDOW(playlist3_get_window()),
1140 GTK_MESSAGE_WARNING
,
1142 _("Are you sure you want to clear the selected playlist?"));
1144 gtk_dialog_add_buttons(GTK_DIALOG(dialog
), GTK_STOCK_NO
, GTK_RESPONSE_CANCEL
, GTK_STOCK_YES
, GTK_RESPONSE_OK
, NULL
);
1145 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), GTK_RESPONSE_CANCEL
);
1147 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_tree
));
1148 if (gtk_tree_selection_count_selected_rows(sel
) == 1)
1150 GtkTreeModel
*model
= GTK_TREE_MODEL(pl3_fb_store2
);
1151 GList
*list
= gtk_tree_selection_get_selected_rows(sel
, &model
);
1156 list
= g_list_first(list
);
1157 gtk_tree_model_get_iter(model
, &iter
, list
->data
);
1158 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_PATH
, &path
, -1);
1159 g_list_foreach(list
, (GFunc
) gtk_tree_path_free
, NULL
);
1166 gtk_widget_destroy(dialog
);
1170 switch (gtk_dialog_run(GTK_DIALOG(dialog
)))
1172 case GTK_RESPONSE_OK
:
1173 mpd_database_delete_playlist(connection
, path
);
1174 pl3_file_browser_reupdate();
1178 gtk_widget_destroy(GTK_WIDGET(dialog
));
1182 static void pl3_file_browser_disconnect(void)
1185 if (pl3_fb_tree_ref
)
1189 if (pl3_fb_dir_store
!= NULL
&& gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
))
1191 int valid
= gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store
), &child
, &iter
);
1195 valid
= gtk_tree_store_remove(pl3_fb_dir_store
, &child
);
1198 gtk_tree_store_set(pl3_fb_dir_store
, &iter
, PL3_FB_OPEN
, FALSE
, -1);
1199 /* add phantom child */
1200 gtk_tree_store_append(pl3_fb_dir_store
, &child
, &iter
);
1205 gmpc_mpddata_model_set_has_up(pl3_fb_store2
, FALSE
);
1206 gmpc_mpddata_model_set_mpd_data(pl3_fb_store2
, NULL
);
1210 static void pl3_file_browser_activate(void)
1212 GtkTreeSelection
*selec
= gtk_tree_view_get_selection((GtkTreeView
*) playlist3_get_category_tree_view());
1214 GtkTreePath
*path
= gtk_tree_row_reference_get_path(pl3_fb_tree_ref
);
1217 gtk_tree_selection_select_path(selec
, path
);
1218 gtk_tree_path_free(path
);
1222 static int pl3_file_browser_add_go_menu(GtkWidget
* menu
)
1224 GtkWidget
*item
= NULL
;
1225 if (!pl3_file_browser_get_enabled())
1228 item
= gtk_image_menu_item_new_with_label(_("Database"));
1229 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1230 gtk_image_new_from_icon_name("gmpc-database", GTK_ICON_SIZE_MENU
));
1231 gtk_widget_add_accelerator(GTK_WIDGET(item
),
1232 "activate", gtk_menu_get_accel_group(GTK_MENU(menu
)), GDK_KEY_F2
, 0, GTK_ACCEL_VISIBLE
);
1234 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1235 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_activate
), NULL
);
1239 static void pl3_file_browser_connection_changed(MpdObj
* mi
, int connect
, gpointer data
)
1243 if(pl3_fb_tree
!= NULL
)
1245 GtkTreePath
*path
= gtk_tree_path_new_from_string("0");
1246 if (mpd_stats_get_total_songs(connection
) == 0)
1248 gtk_widget_show(pl3_fb_warning_box
);
1251 gtk_widget_hide(pl3_fb_warning_box
);
1254 gtk_tree_view_expand_to_path(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
);
1255 gtk_tree_path_free(path
);
1258 pl3_file_browser_disconnect();
1261 static void pl3_file_browser_status_changed(MpdObj
* mi
, ChangedStatusType what
, void *data
)
1263 if (what
& MPD_CST_UPDATING
)
1265 if (pl3_fb_vbox
!= NULL
&& mpd_status_db_is_updating(connection
))
1267 gtk_widget_hide(pl3_fb_warning_box
);
1270 if (what
& MPD_CST_DATABASE
)
1272 pl3_file_browser_reupdate();
1274 /* We might not be able to read the data.
1275 * because off insufficient permission.
1276 * So if permission failed, lets reload things (it is fairly cheap.
1278 else if (what
& MPD_CST_PERMISSION
)
1280 pl3_file_browser_reupdate();
1284 static void pl3_file_browser_destroy(void)
1286 if (pl3_fb_tree_ref
)
1290 path
= gtk_tree_row_reference_get_path(pl3_fb_tree_ref
);
1293 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(gtk_tree_row_reference_get_model(pl3_fb_tree_ref
)), &iter
, path
))
1295 gtk_list_store_remove(GTK_LIST_STORE(gtk_tree_row_reference_get_model(pl3_fb_tree_ref
)), &iter
);
1297 gtk_tree_path_free(path
);
1299 gtk_tree_row_reference_free(pl3_fb_tree_ref
);
1300 pl3_fb_tree_ref
= NULL
;
1304 gtk_widget_destroy(pl3_fb_vbox
);
1309 g_object_unref(pl3_fb_store2
);
1310 pl3_fb_store2
= NULL
;
1317 static void pl3_file_browser_save_myself(void)
1319 if (pl3_fb_tree_ref
)
1321 GtkTreePath
*path
= gtk_tree_row_reference_get_path(pl3_fb_tree_ref
);
1324 gint
*indices
= gtk_tree_path_get_indices(path
);
1325 g_log(LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "Saving myself to position: %i\n", indices
[0]);
1326 cfg_set_single_value_as_int(config
, "file-browser", "position", indices
[0]);
1327 gtk_tree_path_free(path
);
1333 * This is a dirty hack to work around GTK limitation.
1335 static gboolean
__pl3_file_browser_center_on_path(GtkTreePath
*path
)
1337 if(pl3_fb_dir_tree
!= NULL
)
1338 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
, NULL
, TRUE
, 0.5, 0);
1339 gtk_tree_path_free(path
);
1344 static void pl3_file_browser_open_path_real(gchar
** dirs
, GtkTreeIter
* parent
)
1347 if ((dirs
[0]) == NULL
)
1350 GtkTreePath
*path
= NULL
;
1351 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(pl3_fb_dir_tree
)), parent
);
1353 path
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_fb_dir_store
), parent
);
1354 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(pl3_fb_dir_tree
), path
, NULL
, TRUE
, 0.5, 0);
1356 g_idle_add(__pl3_file_browser_center_on_path
, path
);
1357 // gtk_tree_path_free(path);
1360 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
, parent
))
1365 gtk_tree_model_get(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
, PL3_FB_NAME
, &name
, -1);
1366 if (name
&& g_utf8_collate(name
, dirs
[0]) == 0)
1368 GtkTreePath
*tpath
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
);
1369 gtk_tree_view_expand_row(GTK_TREE_VIEW(pl3_fb_dir_tree
), tpath
, FALSE
);
1370 gtk_tree_path_free(tpath
);
1371 pl3_file_browser_open_path_real(&dirs
[1], &iter
);
1377 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
));
1382 void pl3_file_browser_open_path(const gchar
* path
)
1384 pl3_file_browser_activate();
1385 if (pl3_fb_dir_store
)
1387 gchar
**dirs
= g_strsplit(path
, G_DIR_SEPARATOR_S
, -1);
1391 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
, NULL
))
1393 GtkTreePath
*tpath
= gtk_tree_model_get_path(GTK_TREE_MODEL(pl3_fb_dir_store
), &iter
);
1394 gtk_tree_view_expand_row(GTK_TREE_VIEW(pl3_fb_dir_tree
), tpath
, FALSE
);
1395 gtk_tree_path_free(tpath
);
1396 pl3_file_browser_open_path_real(dirs
, &iter
);
1403 static gboolean
pl3_file_browser_is_field_supported(int tag
)
1405 if (tag
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1407 return mpd_server_tag_supported(connection
, tag
);
1410 static MpdData
*pl3_file_browser_is_search(const int num_field
, const gchar
* search_string
, GError
** error
)
1412 MpdData
*data_t
= NULL
;
1413 if (num_field
== MPD_TAG_NUM_OF_ITEM_TYPES
)
1415 data_t
= advanced_search(search_string
, FALSE
);
1418 gchar
**splitted
= tokenize_string(search_string
);
1420 gboolean found
= FALSE
;
1421 for (i
= 0; splitted
&& splitted
[i
]; i
++)
1425 mpd_database_search_start(connection
, FALSE
);
1428 mpd_database_search_add_constraint(connection
, num_field
, splitted
[i
]);
1431 g_strfreev(splitted
);
1434 data_t
= mpd_database_search_commit(connection
);
1440 void pl3_find2_ec_database(gpointer user_data
, const char *param
)
1442 pl3_find2_select_plugin_id(file_browser_plug
.id
);
1443 pl3_find2_do_search_any(param
);
1446 static void pl3_file_browser_plugin_init(void)
1448 gmpc_easy_command_add_entry(gmpc_easy_command
,
1449 _("search database"), ".*",
1450 _("Search database <query>"), (GmpcEasyCommandCallback
*) pl3_find2_ec_database
, NULL
);
1453 /*** Integrates the file browser in the right mouse menu ****/
1455 /* Handle the click on the menu item */
1456 static void pl3_file_browser_option_menu_activate (GtkMenuItem
*item
, gpointer data
)
1458 /* Get previously stored path from item */
1459 const gchar
*path
= g_object_get_data(G_OBJECT(item
), "path");
1460 /* if there is one, act */
1463 /* This function calls the file browser and opens the path */
1464 pl3_file_browser_open_path(path
);
1468 /* add item to menu */
1469 static int pl3_file_browser_option_menu(GmpcMpdDataTreeview
*tree
, GtkMenu
*menu
)
1472 GtkTreeSelection
*selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(tree
));
1473 /* Only works on 1 song */
1474 if(gtk_tree_selection_count_selected_rows(selection
) == 1)
1477 GtkTreeModel
*model
;
1478 mpd_Song
*song
= NULL
;
1479 /* Get a list of selected rows (1) */
1480 list
= gtk_tree_selection_get_selected_rows(selection
, &model
);
1483 GtkTreePath
*path
= (GtkTreePath
*)list
->data
;
1484 /* Convert the path into an actual iter we can use to get values from the model */
1485 if(gtk_tree_model_get_iter(model
, &iter
,path
))
1487 /* Get a pointer to the mpd_Song in the model. */
1488 gtk_tree_model_get(model
, &iter
, MPDDATA_MODEL_COL_MPDSONG
, &song
, -1);
1489 /* Only show if song exists and has a path */
1490 if(song
&& song
->file
)
1492 gchar
*scheme
= g_uri_parse_scheme(song
->file
);
1493 /* If path has a scheme it is not in our db */
1496 GtkWidget
*item
= gtk_image_menu_item_new_with_label(_("Lookup directory in database"));
1497 /* Add folder icon */
1498 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item
),
1499 gtk_image_new_from_stock("gtk-open", GTK_ICON_SIZE_MENU
));
1501 /* Attach a copy of the path to open, so we don't have to look it up again */
1502 g_object_set_data_full(G_OBJECT(item
), "path", g_path_get_dirname(song
->file
), (GDestroyNotify
)g_free
);
1503 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
1505 /* Connect signal */
1506 g_signal_connect(G_OBJECT(item
), "activate", G_CALLBACK(pl3_file_browser_option_menu_activate
), NULL
);
1509 else g_free(scheme
);
1514 /* Free the list of rows */
1515 g_list_foreach (list
, (GFunc
) gtk_tree_path_free
, NULL
);