2 * (SLIK) SimpLIstic sKin functions
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
24 #include <sys/types.h>
29 #include <gdk/gdkkeysyms.h> /* for key values */
31 #include "ui_pathsel.h"
33 #include "ui_bookmark.h"
34 #include "ui_fileops.h"
37 #include "ui_utildlg.h"
38 #include "ui_tabcomp.h"
39 #include "ui_tree_edit.h"
42 #define DEST_WIDTH 250
43 #define DEST_HEIGHT 210
45 #define RENAME_PRESS_DELAY 333 /* 1/3 second, to allow double clicks */
47 #define PATH_SEL_USE_HEADINGS FALSE
50 FILTER_COLUMN_NAME = 0,
54 typedef struct _Dest_Data Dest_Data;
64 GList *filter_text_list;
65 GtkWidget *filter_combo;
68 GtkWidget *hidden_button;
70 GtkWidget *bookmark_list;
72 GtkTreePath *right_click_path;
74 void (*select_func)(const gchar *path, gpointer data);
77 GenericDialog *gd; /* any open confirm dialogs ? */
80 typedef struct _DestDel_Data DestDel_Data;
88 static void dest_view_delete_dlg_cancel(GenericDialog *gd, gpointer data);
92 *-----------------------------------------------------------------------------
94 *-----------------------------------------------------------------------------
97 static void dest_free_data(GtkWidget *widget, gpointer data)
103 GenericDialog *gd = dd->gd;
104 dest_view_delete_dlg_cancel(dd->gd, dd->gd->data);
105 generic_dialog_close(gd);
107 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path);
114 static gint dest_check_filter(const gchar *filter, const gchar *file)
116 const gchar *f_ptr = filter;
117 const gchar *strt_ptr;
123 if (filter[0] == '*') return TRUE;
124 while (f_ptr < filter + strlen(filter))
128 while (*f_ptr != ';' && *f_ptr != '\0')
133 if (*f_ptr != '\0' && f_ptr[1] == ' ') f_ptr++; /* skip space immediately after separator */
135 if (l >= i && strncasecmp(file + l - i, strt_ptr, i) == 0) return TRUE;
141 #define CASE_SORT strcmp
144 static gint dest_sort_cb(void *a, void *b)
146 return CASE_SORT((gchar *)a, (gchar *)b);
149 static gint is_hidden(const gchar *name)
151 if (name[0] != '.') return FALSE;
152 if (name[1] == '\0') return FALSE;
153 if (name[1] == '.' && name[2] == '\0') return FALSE;
157 static void dest_populate(Dest_Data *dd, const gchar *path)
161 struct stat ent_sbuf;
162 GList *path_list = NULL;
163 GList *file_list = NULL;
170 pathl = path_from_utf8(path);
178 while ((dir = readdir(dp)) != NULL)
180 if (dd->show_hidden || !is_hidden(dir->d_name))
182 gchar *name = dir->d_name;
183 gchar *filepath = g_strconcat(pathl, "/", name, NULL);
184 if (stat(filepath, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
186 path_list = g_list_prepend(path_list, path_to_utf8(name));
190 if (!dd->filter || (dd->filter && dest_check_filter(dd->filter, name)))
191 file_list = g_list_prepend(file_list, path_to_utf8(name));
199 path_list = g_list_sort(path_list, (GCompareFunc) dest_sort_cb);
200 file_list = g_list_sort(file_list, (GCompareFunc) dest_sort_cb);
202 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->d_view)));
203 gtk_list_store_clear(store);
211 if (strcmp(list->data, ".") == 0)
213 filepath = g_strdup(path);
215 else if (strcmp(list->data, "..") == 0)
218 filepath = g_strdup(path);
219 p = (gchar *)filename_from_path(filepath);
220 if (p - 1 != filepath) p--;
225 filepath = concat_dir_and_file(path, list->data);
228 gtk_list_store_append(store, &iter);
229 gtk_list_store_set(store, &iter, 0, list->data, 1, filepath, -1);
235 path_list_free(path_list);
240 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->f_view)));
241 gtk_list_store_clear(store);
248 const gchar *name = list->data;
250 filepath = concat_dir_and_file(path, name);
252 gtk_list_store_append(store, &iter);
253 gtk_list_store_set(store, &iter, 0, name, 1, filepath, -1);
259 path_list_free(file_list);
263 dd->path = g_strdup(path);
266 static void dest_change_dir(Dest_Data *dd, const gchar *path, gint retain_name)
268 gchar *old_name = NULL;
273 const gchar *buf = gtk_entry_get_text(GTK_ENTRY(dd->entry));
276 if (path && strcmp(path, "/") == 0)
278 old_name = g_strdup(filename_from_path(buf));
282 old_name = g_strconcat("/", filename_from_path(buf), NULL);
288 gtk_entry_set_text(GTK_ENTRY(dd->entry), path);
290 dest_populate(dd, path);
292 /* remember filename */
296 gtk_editable_insert_text(GTK_EDITABLE(dd->entry), old_name, -1, &pos);
297 gtk_editable_select_region(GTK_EDITABLE(dd->entry), strlen(path) + s, strlen(path) + strlen(old_name));
303 *-----------------------------------------------------------------------------
305 *-----------------------------------------------------------------------------
313 static GtkTargetEntry dest_drag_types[] = {
314 { "text/uri-list", 0, TARGET_URI_LIST },
315 { "text/plain", 0, TARGET_TEXT_PLAIN }
317 #define dest_drag_types_n 2
320 static void dest_dnd_set_data(GtkWidget *view,
321 GdkDragContext *context, GtkSelectionData *selection_data,
322 guint info, guint time, gpointer data)
325 gchar *uri_text = NULL;
329 GtkTreeSelection *selection;
332 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
333 if (!gtk_tree_selection_get_selected(selection, &model, &iter)) return;
335 gtk_tree_model_get(model, &iter, 1, &path, -1);
338 list = g_list_append(list, path);
342 case TARGET_URI_LIST:
343 uri_text = uri_text_from_list(list, &length, FALSE);
345 case TARGET_TEXT_PLAIN:
346 uri_text = uri_text_from_list(list, &length, TRUE);
350 path_list_free(list);
352 if (!uri_text) return;
354 gtk_selection_data_set(selection_data, selection_data->target,
355 8, (guchar *)uri_text, length);
359 static void dest_dnd_init(Dest_Data *dd)
361 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->d_view), GDK_BUTTON1_MASK,
362 dest_drag_types, dest_drag_types_n,
363 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
364 g_signal_connect(G_OBJECT(dd->d_view), "drag_data_get",
365 G_CALLBACK(dest_dnd_set_data), dd);
369 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(dd->f_view), GDK_BUTTON1_MASK,
370 dest_drag_types, dest_drag_types_n,
371 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
372 g_signal_connect(G_OBJECT(dd->f_view), "drag_data_get",
373 G_CALLBACK(dest_dnd_set_data), dd);
379 *-----------------------------------------------------------------------------
380 * destination widget file management utils
381 *-----------------------------------------------------------------------------
384 static void dest_view_store_selection(Dest_Data *dd, GtkTreeView *view)
387 GtkTreeSelection *selection;
390 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path);
391 dd->right_click_path = NULL;
393 selection = gtk_tree_view_get_selection(view);
394 if (!gtk_tree_selection_get_selected(selection, &model, &iter))
399 dd->right_click_path = gtk_tree_model_get_path(model, &iter);
402 static gint dest_view_rename_cb(TreeEditData *ted, const gchar *old, const gchar *new, gpointer data)
404 Dest_Data *dd = data;
411 model = gtk_tree_view_get_model(GTK_TREE_VIEW(ted->tree));
412 gtk_tree_model_get_iter(model, &iter, dd->right_click_path);
414 gtk_tree_model_get(model, &iter, 1, &old_path, -1);
415 if (!old_path) return FALSE;
417 buf = remove_level_from_path(old_path);
418 new_path = concat_dir_and_file(buf, new);
421 if (isname(new_path))
423 buf = g_strdup_printf(_("A file with name %s already exists."), new);
424 warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_INFO, dd->entry);
427 else if (!rename_file(old_path, new_path))
429 buf = g_strdup_printf(_("Failed to rename %s to %s."), old, new);
430 warning_dialog("Rename failed", buf, GTK_STOCK_DIALOG_ERROR, dd->entry);
437 gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, new, 1, new_path, -1);
439 text = gtk_entry_get_text(GTK_ENTRY(dd->entry));
440 if (text && old_path && strcmp(text, old_path) == 0)
442 gtk_entry_set_text(GTK_ENTRY(dd->entry), new_path);
452 static void dest_view_rename(Dest_Data *dd, GtkTreeView *view)
458 if (!dd->right_click_path) return;
460 model = gtk_tree_view_get_model(view);
461 gtk_tree_model_get_iter(model, &iter, dd->right_click_path);
462 gtk_tree_model_get(model, &iter, 0, &text, -1);
464 tree_edit_by_path(view, dd->right_click_path, 0, text,
465 dest_view_rename_cb, dd);
470 static void dest_view_delete_dlg_cancel(GenericDialog *gd, gpointer data)
472 DestDel_Data *dl = data;
479 static void dest_view_delete_dlg_ok_cb(GenericDialog *gd, gpointer data)
481 DestDel_Data *dl = data;
483 if (!unlink_file(dl->path))
485 gchar *text = g_strdup_printf(_("Unable to delete file:\n%s"), dl->path);
486 warning_dialog(_("File deletion failed"), text, GTK_STOCK_DIALOG_WARNING, dl->dd->entry);
489 else if (dl->dd->path)
492 gchar *path = g_strdup(dl->dd->path);
493 dest_populate(dl->dd, path);
497 dest_view_delete_dlg_cancel(gd, data);
500 static void dest_view_delete(Dest_Data *dd, GtkTreeView *view)
508 if (view != GTK_TREE_VIEW(dd->f_view)) return;
509 if (!dd->right_click_path) return;
511 model = gtk_tree_view_get_model(view);
512 gtk_tree_model_get_iter(model, &iter, dd->right_click_path);
513 gtk_tree_model_get(model, &iter, 1, &path, -1);
517 dl = g_new(DestDel_Data, 1);
523 GenericDialog *gd = dd->gd;
524 dest_view_delete_dlg_cancel(dd->gd, dd->gd->data);
525 generic_dialog_close(gd);
528 dd->gd = generic_dialog_new(_("Delete file"), PACKAGE, "dlg_confirm",
530 dest_view_delete_dlg_cancel, dl);
532 generic_dialog_add_button(dd->gd, GTK_STOCK_DELETE, NULL, dest_view_delete_dlg_ok_cb, TRUE);
534 text = g_strdup_printf(_("About to delete the file:\n %s"), path);
535 generic_dialog_add_message(dd->gd, GTK_STOCK_DIALOG_QUESTION,
536 _("Delete file"), text);
539 gtk_widget_show(dd->gd->dialog);
542 static void dest_view_bookmark(Dest_Data *dd, GtkTreeView *view)
548 if (!dd->right_click_path) return;
550 model = gtk_tree_view_get_model(view);
551 gtk_tree_model_get_iter(model, &iter, dd->right_click_path);
552 gtk_tree_model_get(model, &iter, 1, &path, -1);
554 bookmark_list_add(dd->bookmark_list, filename_from_path(path), path);
558 static void dest_popup_dir_rename_cb(GtkWidget *widget, gpointer data)
560 Dest_Data *dd = data;
561 dest_view_rename(dd, GTK_TREE_VIEW(dd->d_view));
564 static void dest_popup_dir_bookmark_cb(GtkWidget *widget, gpointer data)
566 Dest_Data *dd = data;
567 dest_view_bookmark(dd, GTK_TREE_VIEW(dd->d_view));
570 static void dest_popup_file_rename_cb(GtkWidget *widget, gpointer data)
572 Dest_Data *dd = data;
573 dest_view_rename(dd, GTK_TREE_VIEW(dd->f_view));
576 static void dest_popup_file_delete_cb(GtkWidget *widget, gpointer data)
578 Dest_Data *dd = data;
579 dest_view_delete(dd, GTK_TREE_VIEW(dd->f_view));
582 static void dest_popup_file_bookmark_cb(GtkWidget *widget, gpointer data)
584 Dest_Data *dd = data;
585 dest_view_bookmark(dd, GTK_TREE_VIEW(dd->f_view));
588 static void dest_popup_position_cb(GtkMenu *menu, gint *x, gint *y,
589 gboolean *push_in, gpointer data)
591 Dest_Data *dd = data;
595 view = g_object_get_data(G_OBJECT(menu), "active_view");
597 tree_view_get_cell_clamped(view, dd->right_click_path, 0, TRUE, x, y, &cw, &ch);
599 popup_menu_position_clamp(menu, x, y, 0);
602 static gint dest_popup_menu(Dest_Data *dd, GtkTreeView *view,
603 gint button, guint32 time, gint local)
607 if (!dd->right_click_path) return FALSE;
609 if (view == GTK_TREE_VIEW(dd->d_view))
616 model = gtk_tree_view_get_model(view);
617 gtk_tree_model_get_iter(model, &iter, dd->right_click_path);
618 gtk_tree_model_get(model, &iter, 0, &text, -1);
620 if (!text) return FALSE;
622 normal_dir = (strcmp(text, ".") == 0 || strcmp(text, "..") == 0);
624 menu = popup_menu_short_lived();
625 menu_item_add_sensitive(menu, _("_Rename"), !normal_dir,
626 G_CALLBACK(dest_popup_dir_rename_cb), dd);
627 menu_item_add_stock(menu, _("Add _Bookmark"), GTK_STOCK_JUMP_TO,
628 G_CALLBACK(dest_popup_dir_bookmark_cb), dd);
632 menu = popup_menu_short_lived();
633 menu_item_add(menu, _("_Rename"),
634 G_CALLBACK(dest_popup_file_rename_cb), dd);
635 menu_item_add_stock(menu, _("_Delete"), GTK_STOCK_DELETE,
636 G_CALLBACK(dest_popup_file_delete_cb), dd);
637 menu_item_add_stock(menu, _("Add _Bookmark"), GTK_STOCK_JUMP_TO,
638 G_CALLBACK(dest_popup_file_bookmark_cb), dd);
643 g_object_set_data(G_OBJECT(menu), "active_view", view);
644 gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
645 dest_popup_position_cb, dd, button, time);
649 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, button, time);
655 static gint dest_press_cb(GtkWidget *view, GdkEventButton *event, gpointer data)
657 Dest_Data *dd = data;
659 GtkTreeViewColumn *column;
663 GtkTreeSelection *selection;
665 if (event->button != 3 ||
666 !gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(view), event->x, event->y,
667 &tpath, &column, &cell_x, &cell_y))
672 model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
673 gtk_tree_model_get_iter(model, &iter, tpath);
675 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
676 gtk_tree_selection_select_iter(selection, &iter);
678 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path);
679 dd->right_click_path = tpath;
681 return dest_popup_menu(dd, GTK_TREE_VIEW(view), 0, event->time, FALSE);
684 static gboolean dest_keypress_cb(GtkWidget *view, GdkEventKey *event, gpointer data)
686 Dest_Data *dd = data;
688 switch (event->keyval)
691 if (!(event->state & GDK_CONTROL_MASK)) return FALSE;
693 dest_view_store_selection(dd, GTK_TREE_VIEW(view));
694 dest_popup_menu(dd, GTK_TREE_VIEW(view), 0, event->time, TRUE);
698 if (event->state & GDK_CONTROL_MASK)
700 dest_view_store_selection(dd, GTK_TREE_VIEW(view));
701 dest_view_rename(dd, GTK_TREE_VIEW(view));
706 dest_view_store_selection(dd, GTK_TREE_VIEW(view));
707 dest_view_delete(dd, GTK_TREE_VIEW(view));
711 if (event->state & GDK_CONTROL_MASK)
713 dest_view_store_selection(dd, GTK_TREE_VIEW(view));
714 dest_view_bookmark(dd, GTK_TREE_VIEW(view));
723 static void dest_new_dir_cb(GtkWidget *widget, gpointer data)
725 Dest_Data *dd = data;
729 gint from_text = FALSE;
731 tmp = gtk_entry_get_text(GTK_ENTRY(dd->entry));
734 path = g_strdup(tmp);
739 buf = concat_dir_and_file(dd->path, _("New folder"));
740 path = unique_filename(buf, NULL, " ", FALSE);
744 if (!mkdir_utf8(path, 0755))
749 text = g_strdup_printf(_("Unable to create folder:\n%s"), filename_from_path(path));
750 warning_dialog(_("Error creating folder"), text, GTK_STOCK_DIALOG_ERROR, dd->entry);
759 if (from_text) gtk_entry_set_text(GTK_ENTRY(dd->entry), dd->path);
761 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dd->d_view)));
763 text = filename_from_path(path);
765 gtk_list_store_append(store, &iter);
766 gtk_list_store_set(store, &iter, 0, text, 1, path, -1);
768 if (dd->right_click_path) gtk_tree_path_free(dd->right_click_path);
769 dd->right_click_path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
771 tree_edit_by_path(GTK_TREE_VIEW(dd->d_view), dd->right_click_path, 0, text,
772 dest_view_rename_cb, dd);
779 *-----------------------------------------------------------------------------
780 * destination widget file selection, traversal, view options
781 *-----------------------------------------------------------------------------
784 static void dest_select_cb(GtkTreeSelection *selection, gpointer data)
786 Dest_Data *dd = data;
792 if (!gtk_tree_selection_get_selected(selection, NULL, &iter)) return;
794 view = gtk_tree_selection_get_tree_view(selection);
795 store = gtk_tree_view_get_model(view);
796 gtk_tree_model_get(store, &iter, 1, &path, -1);
798 if (view == GTK_TREE_VIEW(dd->d_view))
800 dest_change_dir(dd, path, (dd->f_view != NULL));
804 gtk_entry_set_text(GTK_ENTRY(dd->entry), path);
810 static void dest_activate_cb(GtkWidget *view, GtkTreePath *tpath, GtkTreeViewColumn *column, gpointer data)
812 Dest_Data *dd = data;
817 store = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
818 gtk_tree_model_get_iter(store, &iter, tpath);
819 gtk_tree_model_get(store, &iter, 1, &path, -1);
821 if (view == dd->d_view)
823 dest_change_dir(dd, path, (dd->f_view != NULL));
829 dd->select_func(path, dd->select_data);
836 static void dest_home_cb(GtkWidget *widget, gpointer data)
838 Dest_Data *dd = data;
840 dest_change_dir(dd, homedir(), (dd->f_view != NULL));
843 static void dest_show_hidden_cb(GtkWidget *widget, gpointer data)
845 Dest_Data *dd = data;
848 dd->show_hidden = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dd->hidden_button));
850 buf = g_strdup(dd->path);
851 dest_populate(dd, buf);
855 static void dest_entry_changed_cb(GtkEditable *editable, gpointer data)
857 Dest_Data *dd = data;
861 path = gtk_entry_get_text(GTK_ENTRY(dd->entry));
862 if (dd->path && strcmp(path, dd->path) == 0) return;
864 buf = remove_level_from_path(path);
866 if (buf && (!dd->path || strcmp(buf, dd->path) != 0))
868 gchar *tmp = remove_trailing_slash(path);
871 dest_populate(dd, tmp);
875 dest_populate(dd, buf);
882 static void dest_filter_list_sync(Dest_Data *dd)
890 if (!dd->filter_list || !dd->filter_combo) return;
892 entry = GTK_BIN(dd->filter_combo)->child;
893 old_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
895 store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(dd->filter_combo)));
896 gtk_list_store_clear(store);
898 fwork = dd->filter_list;
899 twork = dd->filter_text_list;
900 while (fwork && twork)
907 filter = fwork->data;
909 gtk_list_store_append(store, &iter);
910 gtk_list_store_set(store, &iter, FILTER_COLUMN_NAME, name,
911 FILTER_COLUMN_FILTER, filter, -1);
913 if (strcmp(old_text, filter) == 0)
915 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dd->filter_combo), &iter);
925 static void dest_filter_add(Dest_Data *dd, const gchar *filter, const gchar *description, gint set)
933 work = dd->filter_list;
936 gchar *f = work->data;
938 if (strcmp(f, filter) == 0)
940 if (set) gtk_combo_box_set_active(GTK_COMBO_BOX(dd->filter_combo), c);
947 dd->filter_list = uig_list_insert_link(dd->filter_list, g_list_last(dd->filter_list), g_strdup(filter));
951 buf = g_strdup_printf("%s ( %s )", description, filter);
955 buf = g_strdup_printf("( %s )", filter);
957 dd->filter_text_list = uig_list_insert_link(dd->filter_text_list, g_list_last(dd->filter_text_list), buf);
959 if (set) gtk_entry_set_text(GTK_ENTRY(GTK_BIN(dd->filter_combo)->child), filter);
960 dest_filter_list_sync(dd);
963 static void dest_filter_clear(Dest_Data *dd)
965 path_list_free(dd->filter_list);
966 dd->filter_list = NULL;
968 path_list_free(dd->filter_text_list);
969 dd->filter_text_list = NULL;
971 dest_filter_add(dd, "*", _("All Files"), TRUE);
974 static void dest_filter_changed_cb(GtkEditable *editable, gpointer data)
976 Dest_Data *dd = data;
981 entry = GTK_BIN(dd->filter_combo)->child;
982 buf = gtk_entry_get_text(GTK_ENTRY(entry));
986 if (strlen(buf) > 0) dd->filter = g_strdup(buf);
988 path = g_strdup(dd->path);
989 dest_populate(dd, path);
993 static void dest_bookmark_select_cb(const gchar *path, gpointer data)
995 Dest_Data *dd = data;
999 dest_change_dir(dd, path, (dd->f_view != NULL));
1001 else if (isfile(path) && dd->f_view)
1003 gtk_entry_set_text(GTK_ENTRY(dd->entry), path);
1008 *-----------------------------------------------------------------------------
1009 * destination widget setup routines (public)
1010 *-----------------------------------------------------------------------------
1013 GtkWidget *path_selection_new_with_files(GtkWidget *entry, const gchar *path,
1014 const gchar *filter, const gchar *filter_desc)
1018 GtkWidget *scrolled;
1021 GtkListStore *store;
1022 GtkTreeSelection *selection;
1023 GtkTreeViewColumn *column;
1024 GtkCellRenderer *renderer;
1026 dd = g_new0(Dest_Data, 1);
1027 dd->show_hidden = FALSE;
1028 dd->select_func = NULL;
1029 dd->select_data = NULL;
1032 table = gtk_table_new(4, (filter != NULL) ? 3 : 1, FALSE);
1033 gtk_table_set_col_spacings(GTK_TABLE(table), PREF_PAD_GAP);
1034 gtk_table_set_row_spacing(GTK_TABLE(table), 0, PREF_PAD_GAP);
1035 gtk_widget_show(table);
1038 g_object_set_data(G_OBJECT(dd->entry), "destination_data", dd);
1040 hbox2 = pref_table_box(table, 0, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
1041 gtk_box_set_spacing(GTK_BOX(hbox2), PREF_PAD_BUTTON_GAP);
1042 pref_button_new(hbox2, NULL, _("Home"), FALSE,
1043 G_CALLBACK(dest_home_cb), dd);
1044 pref_button_new(hbox2, NULL, _("New folder"), FALSE,
1045 G_CALLBACK(dest_new_dir_cb), dd);
1047 dd->hidden_button = gtk_check_button_new_with_label(_("Show hidden"));
1048 g_signal_connect(G_OBJECT(dd->hidden_button), "clicked",
1049 G_CALLBACK(dest_show_hidden_cb), dd);
1050 gtk_box_pack_end(GTK_BOX(hbox2), dd->hidden_button, FALSE, FALSE, 0);
1051 gtk_widget_show(dd->hidden_button);
1053 hbox2 = gtk_hbox_new(FALSE, PREF_PAD_GAP);
1056 paned = gtk_hpaned_new();
1057 gtk_table_attach(GTK_TABLE(table), paned, 0, 3, 1, 2,
1058 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1059 gtk_widget_show(paned);
1060 gtk_paned_add1(GTK_PANED(paned), hbox2);
1065 gtk_table_attach(GTK_TABLE(table), hbox2, 0, 1, 1, 2,
1066 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1068 gtk_widget_show(hbox2);
1071 scrolled = bookmark_list_new(NULL, dest_bookmark_select_cb, dd);
1072 gtk_box_pack_start(GTK_BOX(hbox2), scrolled, FALSE, FALSE, 0);
1073 gtk_widget_show(scrolled);
1075 dd->bookmark_list = scrolled;
1077 scrolled = gtk_scrolled_window_new(NULL, NULL);
1078 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1079 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1080 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1081 gtk_box_pack_start(GTK_BOX(hbox2), scrolled, TRUE, TRUE, 0);
1082 gtk_widget_show(scrolled);
1084 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
1085 dd->d_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1086 g_object_unref(store);
1088 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dd->d_view), PATH_SEL_USE_HEADINGS);
1090 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dd->d_view));
1091 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1093 column = gtk_tree_view_column_new();
1094 gtk_tree_view_column_set_title(column, _("Folders"));
1095 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1097 renderer = gtk_cell_renderer_text_new();
1098 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1099 gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
1101 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->d_view), column);
1104 /* only for debugging */
1105 column = gtk_tree_view_column_new();
1106 gtk_tree_view_column_set_title(column, _("Path"));
1107 renderer = gtk_cell_renderer_text_new();
1108 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1109 gtk_tree_view_column_add_attribute(column, renderer, "text", 1);
1110 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->d_view), column);
1113 gtk_widget_set_size_request(dd->d_view, DEST_WIDTH, DEST_HEIGHT);
1114 gtk_container_add(GTK_CONTAINER(scrolled), dd->d_view);
1115 gtk_widget_show(dd->d_view);
1117 g_signal_connect(G_OBJECT(dd->d_view), "button_press_event",
1118 G_CALLBACK(dest_press_cb), dd);
1119 g_signal_connect(G_OBJECT(dd->d_view), "key_press_event",
1120 G_CALLBACK(dest_keypress_cb), dd);
1121 g_signal_connect(G_OBJECT(dd->d_view), "row_activated",
1122 G_CALLBACK(dest_activate_cb), dd);
1123 g_signal_connect(G_OBJECT(dd->d_view), "destroy",
1124 G_CALLBACK(dest_free_data), dd);
1128 GtkListStore *store;
1130 hbox2 = pref_table_box(table, 2, 0, GTK_ORIENTATION_HORIZONTAL, NULL);
1131 pref_label_new(hbox2, _("Filter:"));
1133 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
1135 dd->filter_combo = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(store),
1136 FILTER_COLUMN_FILTER);
1137 g_object_unref(store);
1138 gtk_cell_layout_clear(GTK_CELL_LAYOUT(dd->filter_combo));
1139 renderer = gtk_cell_renderer_text_new();
1140 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dd->filter_combo), renderer, TRUE);
1141 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dd->filter_combo), renderer,
1142 "text", FILTER_COLUMN_NAME, NULL);
1144 gtk_combo_set_case_sensitive(GTK_COMBO(dd->filter_combo), TRUE);
1146 gtk_box_pack_start(GTK_BOX(hbox2), dd->filter_combo, TRUE, TRUE, 0);
1147 gtk_widget_show(dd->filter_combo);
1149 scrolled = gtk_scrolled_window_new(NULL, NULL);
1150 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
1151 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
1152 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1155 gtk_paned_add2(GTK_PANED(paned), scrolled);
1159 gtk_table_attach(GTK_TABLE(table), scrolled, 2, 3, 1, 2,
1160 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1162 gtk_widget_show(scrolled);
1164 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
1165 dd->f_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1166 g_object_unref(store);
1168 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(dd->f_view), PATH_SEL_USE_HEADINGS);
1170 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dd->f_view));
1171 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_SINGLE);
1173 column = gtk_tree_view_column_new();
1174 gtk_tree_view_column_set_title(column, _("Files"));
1175 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1177 renderer = gtk_cell_renderer_text_new();
1178 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1179 gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
1181 gtk_tree_view_append_column(GTK_TREE_VIEW(dd->f_view), column);
1183 gtk_widget_set_size_request(dd->f_view, DEST_WIDTH, DEST_HEIGHT);
1184 gtk_container_add(GTK_CONTAINER(scrolled), dd->f_view);
1185 gtk_widget_show(dd->f_view);
1187 g_signal_connect(G_OBJECT(dd->f_view), "button_press_event",
1188 G_CALLBACK(dest_press_cb), dd);
1189 g_signal_connect(G_OBJECT(dd->f_view), "key_press_event",
1190 G_CALLBACK(dest_keypress_cb), dd);
1191 g_signal_connect(G_OBJECT(dd->f_view), "row_activated",
1192 G_CALLBACK(dest_activate_cb), dd);
1193 g_signal_connect(selection, "changed",
1194 G_CALLBACK(dest_select_cb), dd);
1196 dest_filter_clear(dd);
1197 dest_filter_add(dd, filter, filter_desc, TRUE);
1199 dd->filter = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_BIN(dd->filter_combo)->child)));
1202 if (path && path[0] == '/' && isdir(path))
1204 dest_populate(dd, path);
1208 gchar *buf = remove_level_from_path(path);
1209 if (buf && buf[0] == '/' && isdir(buf))
1211 dest_populate(dd, buf);
1217 dest_populate(dd, (gchar *)homedir());
1218 if (path) gtk_editable_insert_text(GTK_EDITABLE(dd->entry), "/", -1, &pos);
1219 if (path) gtk_editable_insert_text(GTK_EDITABLE(dd->entry), path, -1, &pos);
1224 if (dd->filter_combo)
1226 g_signal_connect(G_OBJECT(GTK_BIN(dd->filter_combo)->child), "changed",
1227 G_CALLBACK(dest_filter_changed_cb), dd);
1229 g_signal_connect(G_OBJECT(dd->entry), "changed",
1230 G_CALLBACK(dest_entry_changed_cb), dd);
1237 GtkWidget *path_selection_new(const gchar *path, GtkWidget *entry)
1239 return path_selection_new_with_files(entry, path, NULL, NULL);
1242 void path_selection_sync_to_entry(GtkWidget *entry)
1244 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data");
1249 path = gtk_entry_get_text(GTK_ENTRY(entry));
1251 if (isdir(path) && (!dd->path || strcmp(path, dd->path) != 0))
1253 dest_populate(dd, path);
1257 gchar *buf = remove_level_from_path(path);
1258 if (isdir(buf) && (!dd->path || strcmp(buf, dd->path) != 0))
1260 dest_populate(dd, buf);
1266 void path_selection_add_select_func(GtkWidget *entry,
1267 void (*func)(const gchar *, gpointer), gpointer data)
1269 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data");
1273 dd->select_func = func;
1274 dd->select_data = data;
1277 void path_selection_add_filter(GtkWidget *entry, const gchar *filter, const gchar *description, gint set)
1279 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data");
1282 if (!filter) return;
1284 dest_filter_add(dd, filter, description, set);
1287 void path_selection_clear_filter(GtkWidget *entry)
1289 Dest_Data *dd = g_object_get_data(G_OBJECT(entry), "destination_data");
1293 dest_filter_clear(dd);