Small updates and fixes
[gmpc.git] / src / browsers / playlist3-file-browser.c
blob0bf8d0d2b1c5ed51bb89ec50e37ce8c88944d11f
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "main.h"
25 #include "misc.h"
26 #include "playlist3.h"
27 #include "playlist3-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,
50 gpointer user_data);
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);
54 /* testing */
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;
75 enum
77 PL3_FB_ICON = 0,
78 PL3_FB_NAME = 1,
79 PL3_FB_PATH = 2,
80 PL3_FB_OPEN = 3
82 /**
83 * Get/Set enabled
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);
93 if (enabled)
95 GtkTreeView *tree = playlist3_get_category_tree_view();
96 pl3_file_browser_add((GtkWidget *) tree);
97 } else if (!enabled)
99 pl3_file_browser_destroy();
104 * Plugin structure
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"),
118 .version = {1, 1, 1}
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
131 /* internal */
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,
141 gpointer user_data)
143 if (!mpd_check_connected(connection))
144 return;
145 if (gtk_tree_view_row_expanded(tree, tp))
146 gtk_tree_view_collapse_row(tree, tp);
147 else
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);
215 /* setup signals */
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),
218 NULL);
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);
234 /* label */
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);
244 /* help button */
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);
268 GtkTreeIter iter;
270 if (!mpd_check_connected(connection))
272 return;
274 if (gtk_tree_selection_get_selected(selec, &model, &iter))
276 char *path, *icon;
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);
282 } else
284 mpd_playlist_queue_load(connection, path);
286 mpd_playlist_queue_commit(connection);
287 q_free(path);
288 q_free(icon);
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);
296 GtkTreeIter iter;
298 if (!mpd_check_connected(connection))
300 return;
302 if (gtk_tree_selection_get_selected(selec, &model, &iter))
304 char *path;
305 gtk_tree_model_get(model, &iter, PL3_FB_PATH, &path, -1);
306 if (path)
308 mpd_database_update_dir(connection, path);
309 q_free(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));
319 GtkTreeIter iter;
321 if (!mpd_check_connected(connection))
322 return;
324 if (gtk_tree_selection_count_selected_rows(selection) == 1)
326 GList *list = gtk_tree_selection_get_selected_rows(selection, &model);
327 /* free list */
328 if (gtk_tree_model_get_iter(model, &iter, list->data))
330 char *path;
331 gtk_tree_model_get(model, &iter, MPDDATA_MODEL_COL_PATH, &path, -1);
332 if (path)
334 mpd_database_update_dir(connection, path);
335 q_free(path);
338 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
339 g_list_free(list);
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)
356 GtkTreeIter iter;
357 GtkTreePath *path;
358 gint pos;
359 INIT_TIC_TAC()
360 pos = cfg_get_single_value_as_int_with_default(config, "file-browser", "position", 2);
362 TEC("get pos ")
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")
370 if (pl3_fb_tree_ref)
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);
378 if (path)
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;
392 int val = 0;
393 if (!(a && b))
394 return val;
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)
401 gchar *sa, *sb;
402 sa = g_utf8_strdown(a->directory, -1);
403 sb = g_utf8_strdown(b->directory, -1);
404 val = g_utf8_collate(sa, sb);
405 g_free(sa);
406 g_free(sb);
409 return val;
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;
421 gchar *path = 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);
425 if (path && temp)
427 GtkTreeIter child, child2, child3;
428 data = mpd_database_get_directory(connection, path);
429 data = misc_sort_mpddata(data, (GCompareDataFunc) directory_sort_func, NULL);
430 g_free(path);
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);
439 if (data == NULL)
441 /* if no more data, remove the subdir */
442 has_next = gtk_tree_store_remove(pl3_fb_dir_store, &child);
443 } else
445 int compare = 0;
446 /* get the next directory */
447 while (data && data->type != MPD_DATA_TYPE_DIRECTORY)
448 data = mpd_data_get_next(data);
449 if (data)
451 compare = strcmp(data->directory, test_path);
452 if (compare < 0)
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);
462 q_free(basename);
464 /* if the new dir is smaller the temp, we add it. */
465 data = mpd_data_get_next(data);
466 has_next = TRUE;
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);
472 } else
474 /* if equal we process children if available */
475 if (temp)
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);
485 g_free(test_path);
486 } while (has_next);
487 if (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);
499 q_free(basename);
501 } while ((data = mpd_data_get_next(data)));
507 static void pl3_file_browser_reupdate(void)
510 if (pl3_fb_vbox)
512 GtkTreeIter iter;
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);
519 } else
521 gtk_widget_hide(pl3_fb_warning_box);
524 if (gtk_tree_model_get_iter_first(model, &iter))
526 GtkTreeIter child;
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;
544 /* Clear the view */
545 gmpc_mpddata_model_set_mpd_data(pl3_fb_store2, NULL);
547 if (!gtk_tree_selection_get_selected(selection, &model, &iter_cat))
548 return;
550 /* check the connection state and when its valid proceed */
551 if (!mpd_check_connected(connection))
553 return;
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);
559 } else
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);
566 else
567 gmpc_mpddata_model_set_has_up(pl3_fb_store2, TRUE);
568 gmpc_mpddata_model_set_mpd_data(pl3_fb_store2, data);
569 q_free(path);
570 q_free(icon);
571 return;
574 static void pl3_file_browser_collapse_row(GtkTreeView * tree, GtkTreeIter * iter, GtkTreePath * path,
575 gpointer user_data)
577 GtkTreeIter child;
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))
580 return;
582 while (valid)
584 valid = gtk_tree_store_remove(pl3_fb_dir_store, &child);
586 /* set unopened */
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)
594 char *path;
595 MpdData *data = NULL;
596 GtkTreeIter child, child2, dummy;
597 gboolean open;
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);
600 if (open == FALSE)
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
605 * then appending */
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))
611 while (data != NULL)
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);
622 q_free(basename);
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);
635 q_free(path);
638 static int pl3_file_browser_cat_popup(GtkWidget * wid, GdkEventButton * event, gpointer user_data)
640 GtkWidget *menu;
641 if (event->button == 3)
644 /* here we have: Add. Replace, (update?) */
645 GtkWidget *item;
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);
664 GtkTreeIter iter;
665 if (gtk_tree_selection_get_selected(selection, &model, &iter))
667 char *icon = NULL;
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);
675 } else
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);
684 q_free(icon);
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 */
690 return TRUE;
692 return FALSE;
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();
704 return FALSE;
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();
713 return FALSE;
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. */
734 GtkTreeIter child;
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))
757 return;
759 if (gtk_tree_selection_count_selected_rows(selection) > 0)
761 GList *list = NULL;
762 list = gtk_tree_selection_get_selected_rows(selection, &model);
764 list = g_list_last(list);
766 mpd_Song *song = NULL;
767 GtkTreeIter iter;
768 int type;
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)
774 if (song)
776 info2_activate();
777 info2_fill_song_view(song);
781 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
782 g_list_free(list);
786 static void pl3_file_browser_row_activated(GtkTreeView * tree, GtkTreePath * tp)
788 GtkTreeIter iter;
789 gchar *song_path;
790 gint r_type;
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,
794 &r_type, -1);
795 if (song_path == NULL && r_type != -1)
797 return;
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))
810 GtkTreeIter citer;
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))
818 char *name = NULL;
819 char *type = NULL;
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);
828 q_free(name);
829 q_free(type);
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))
841 GtkTreeIter piter;
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);
851 } else
853 play_path(song_path);
856 q_free(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);
865 if (list)
867 iter = g_list_first(list);
870 GtkTreeIter giter;
871 if (gtk_tree_model_get_iter(model, &giter, (GtkTreePath *) iter->data))
873 gchar *file = NULL;
874 int type = 0;
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);
890 g_free(file);
892 } while ((iter = g_list_next(iter)));
894 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
895 g_list_free(list);
899 static gboolean pl3_file_browser_button_release_event(GtkWidget * but, GdkEventButton * event)
901 GtkWidget *item;
902 GtkWidget *menu = NULL;
903 GtkTreeSelection *sel = NULL;
904 if (event->button != 3)
905 return FALSE;
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);
916 if (list != NULL)
918 GtkTreeIter iter;
919 int row_type;
920 char *path;
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),
941 pl3_fb_tree);
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);
957 if (row_type != -1)
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);
978 if (song)
980 submenu_for_song(menu, song);
983 g_list_foreach(list, (GFunc) gtk_tree_path_free, NULL);
984 g_list_free(list);
985 q_free(path);
987 } else
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),
1003 pl3_fb_tree);
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));
1011 /* if(has_item) */
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);
1023 return TRUE;
1025 /* else{
1026 gtk_widget_destroy(menu);
1029 return FALSE;
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)
1044 GtkTreeIter iter;
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);
1048 int songs = 0;
1049 int dirs = 0;
1050 int pl = 0;
1051 /*gchar *message; */
1052 if (rows != NULL)
1054 gchar *name;
1055 gint type;
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)
1068 dirs++;
1069 if (type == MPD_DATA_TYPE_SONG)
1070 songs++;
1071 } else if (type == MPD_DATA_TYPE_PLAYLIST)
1073 mpd_playlist_queue_load(connection, name);
1074 pl++;
1076 q_free(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);
1082 g_list_free(rows);
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);
1090 GtkTreeIter iter;
1091 char *path = NULL;
1092 /* create a warning message dialog */
1093 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(playlist3_get_window()),
1094 GTK_DIALOG_MODAL,
1095 GTK_MESSAGE_WARNING,
1096 GTK_BUTTONS_NONE,
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))
1104 char *icon = NULL;
1105 gtk_tree_model_get(model, &iter, 3, &icon, 2, &path, -1);
1106 if (path && strcmp("media-playlist", icon))
1108 if (path)
1109 q_free(path);
1110 path = NULL;
1112 q_free(icon);
1115 if (path == NULL)
1117 gtk_widget_destroy(dialog);
1118 return;
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();
1126 default:
1127 break;
1129 gtk_widget_destroy(GTK_WIDGET(dialog));
1130 q_free(path);
1133 static void pl3_file_browser_delete_playlist(GtkMenuItem * bt)
1135 char *path = NULL;
1136 GtkTreeSelection *sel = NULL;
1137 /* create a warning message dialog */
1138 GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(playlist3_get_window()),
1139 GTK_DIALOG_MODAL,
1140 GTK_MESSAGE_WARNING,
1141 GTK_BUTTONS_NONE,
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);
1152 if (list != NULL)
1154 GtkTreeIter iter;
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);
1160 g_list_free(list);
1164 if (path == NULL)
1166 gtk_widget_destroy(dialog);
1167 return;
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();
1175 default:
1176 break;
1178 gtk_widget_destroy(GTK_WIDGET(dialog));
1179 q_free(path);
1182 static void pl3_file_browser_disconnect(void)
1185 if (pl3_fb_tree_ref)
1187 GtkTreeIter iter;
1188 GtkTreeIter child;
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);
1193 while (valid)
1195 valid = gtk_tree_store_remove(pl3_fb_dir_store, &child);
1197 /* set unopened */
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);
1203 if (pl3_fb_store2)
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);
1215 if (path)
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())
1226 return 0;
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);
1236 return 1;
1239 static void pl3_file_browser_connection_changed(MpdObj * mi, int connect, gpointer data)
1241 if (connect)
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);
1249 } else
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);
1257 } else
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)
1288 GtkTreeIter iter;
1289 GtkTreePath *path;
1290 path = gtk_tree_row_reference_get_path(pl3_fb_tree_ref);
1291 if (path)
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;
1302 if (pl3_fb_vbox)
1304 gtk_widget_destroy(pl3_fb_vbox);
1305 pl3_fb_vbox = NULL;
1307 if (pl3_fb_store2)
1309 g_object_unref(pl3_fb_store2);
1310 pl3_fb_store2 = NULL;
1312 if(pl3_fb_tree) {
1313 pl3_fb_tree = 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);
1322 if (path)
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);
1340 // Remove
1341 return FALSE;
1344 static void pl3_file_browser_open_path_real(gchar ** dirs, GtkTreeIter * parent)
1346 GtkTreeIter iter;
1347 if ((dirs[0]) == NULL)
1349 /* found dir */
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);
1355 // Dirty hack.
1356 g_idle_add(__pl3_file_browser_center_on_path, path);
1357 // gtk_tree_path_free(path);
1358 return;
1360 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(pl3_fb_dir_store), &iter, parent))
1364 gchar *name = NULL;
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);
1372 g_free(name);
1373 return;
1375 if (name)
1376 g_free(name);
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);
1388 if (dirs)
1390 GtkTreeIter iter;
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);
1398 g_strfreev(dirs);
1403 static gboolean pl3_file_browser_is_field_supported(int tag)
1405 if (tag == MPD_TAG_NUM_OF_ITEM_TYPES)
1406 return TRUE;
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);
1416 } else
1418 gchar **splitted = tokenize_string(search_string);
1419 int i = 0;
1420 gboolean found = FALSE;
1421 for (i = 0; splitted && splitted[i]; i++)
1423 if (!found)
1425 mpd_database_search_start(connection, FALSE);
1426 found = TRUE;
1428 mpd_database_search_add_constraint(connection, num_field, splitted[i]);
1430 if (splitted)
1431 g_strfreev(splitted);
1432 if (found)
1434 data_t = mpd_database_search_commit(connection);
1437 return data_t;
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 */
1461 if(path != NULL)
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)
1471 int retv = 0;
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)
1476 GList *list;
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);
1481 if(list) {
1482 GtkTreeIter iter;
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 */
1494 if(!scheme)
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);
1507 retv++;
1509 else g_free(scheme);
1514 /* Free the list of rows */
1515 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
1516 g_list_free (list);
1519 return retv;