X-Git-Url: http://git.claws-mail.org/?p=claws.git;a=blobdiff_plain;f=src%2Ffilesel.c;h=44f77a48461719f9d0b3756508d4f73c83f6e57f;hp=27093fc55d3956a0d2394d06317c41ba70a74546;hb=561628aa0791e6457137977362ed0ceaec6c8bc6;hpb=6d56b06e24b86af8ff10f31996b66f2fe79efcd5;ds=sidebyside diff --git a/src/filesel.c b/src/filesel.c index 27093fc55..44f77a484 100644 --- a/src/filesel.c +++ b/src/filesel.c @@ -1,6 +1,6 @@ /* * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client - * Copyright (C) 1999,2000 Hiroyuki Yamamoto + * Copyright (C) 1999-2001 Hiroyuki Yamamoto * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include "main.h" #include "filesel.h" @@ -31,18 +33,32 @@ static GtkWidget *filesel; static gboolean filesel_ack; +static gchar *filesel_oldfilename = NULL; -static void filesel_create(const gchar *title); +static void filesel_create(const gchar *title, gboolean multiple_files); static void filesel_ok_cb(GtkWidget *widget, gpointer data); static void filesel_cancel_cb(GtkWidget *widget, gpointer data); +static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data); static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data); +static void filesel_file_list_select_row_multi(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata); +static void filesel_file_list_select_row_single(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata); + +static void filesel_dir_list_select_row_multi(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata); +static void filesel_dir_list_select_row_single(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata); + +static GList *filesel_get_multiple_filenames(void); + gchar *filesel_select_file(const gchar *title, const gchar *file) { static gchar *filename = NULL; static gchar *cwd = NULL; - filesel_create(title); + filesel_create(title, FALSE); manage_window_set_transient(GTK_WINDOW(filesel)); @@ -56,9 +72,11 @@ gchar *filesel_select_file(const gchar *title, const gchar *file) gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), cwd); - if (file) + if (file) { gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), file); + filesel_oldfilename = g_strdup(file); + } gtk_widget_show(filesel); @@ -87,7 +105,46 @@ gchar *filesel_select_file(const gchar *title, const gchar *file) return filename; } -static void filesel_create(const gchar *title) +GList *filesel_select_multiple_files(const gchar *title, const gchar *file) +{ + /* ALF - sorry for the exuberant code duping... need to + * be cleaned up. */ + static gchar *filename = NULL; + static gchar *cwd = NULL; + GList *list = NULL; + + filesel_create(title, TRUE); + + manage_window_set_transient(GTK_WINDOW(filesel)); + + if (filename) { + g_free(filename); + filename = NULL; + } + + if (!cwd) + cwd = g_strconcat(startup_dir, G_DIR_SEPARATOR_S, NULL); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), cwd); + + if (file) + gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), + file); + gtk_widget_show(filesel); + + gtk_main(); + + if (filesel_ack) + list = filesel_get_multiple_filenames(); + + manage_window_focus_out(filesel, NULL, NULL); + gtk_widget_destroy(filesel); + GTK_EVENTS_FLUSH(); + + return list; +} + +static void filesel_create(const gchar *title, gboolean multiple_files) { filesel = gtk_file_selection_new(title); gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), @@ -98,8 +155,7 @@ static void filesel_create(const gchar *title) "clicked", GTK_SIGNAL_FUNC(filesel_cancel_cb), NULL); gtk_signal_connect(GTK_OBJECT(filesel), "delete_event", - GTK_SIGNAL_FUNC(filesel_cancel_cb), - NULL); + GTK_SIGNAL_FUNC(delete_event), NULL); gtk_signal_connect(GTK_OBJECT(filesel), "key_press_event", GTK_SIGNAL_FUNC(key_pressed), NULL); gtk_signal_connect(GTK_OBJECT(filesel), "focus_in_event", @@ -108,22 +164,171 @@ static void filesel_create(const gchar *title) GTK_SIGNAL_FUNC(manage_window_focus_out), NULL); gtk_window_set_modal(GTK_WINDOW(filesel), TRUE); + + if (multiple_files) { + gtk_clist_set_selection_mode + (GTK_CLIST(GTK_FILE_SELECTION(filesel)->file_list), + GTK_SELECTION_MULTIPLE); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->file_list), + "select_row", + GTK_SIGNAL_FUNC(filesel_file_list_select_row_multi), + NULL); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->file_list), + "unselect_row", + GTK_SIGNAL_FUNC(filesel_file_list_select_row_multi), + NULL); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->dir_list), + "select_row", + GTK_SIGNAL_FUNC(filesel_dir_list_select_row_multi), + NULL); + } else { + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->file_list), + "select_row", + GTK_SIGNAL_FUNC(filesel_file_list_select_row_single), + NULL); + gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->dir_list), + "select_row", + GTK_SIGNAL_FUNC(filesel_dir_list_select_row_single), + NULL); + } } static void filesel_ok_cb(GtkWidget *widget, gpointer data) { filesel_ack = TRUE; + g_free(filesel_oldfilename); gtk_main_quit(); } static void filesel_cancel_cb(GtkWidget *widget, gpointer data) { filesel_ack = FALSE; + g_free(filesel_oldfilename); gtk_main_quit(); } +static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data) +{ + filesel_cancel_cb(NULL, NULL); + g_free(filesel_oldfilename); + return TRUE; +} + static void key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data) { if (event && event->keyval == GDK_Escape) filesel_cancel_cb(NULL, NULL); } + +/* handle both "select_row" and "unselect_row". note that we're using the + * entry box to put there the selected file names in. we're not using these + * entry box to get the selected file names. instead we use the clist selection. + * the entry box is used only to retrieve dir name. */ +static void filesel_file_list_select_row_multi(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata) +{ + /* simple implementation in which we clear the file entry and refill it */ + GList *list = clist->selection; + GtkEntry *entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry); + + gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1); + +#define INVALID_FILENAME_CHARS " " + for (; list; list = list->next) { + gint row = GPOINTER_TO_INT(list->data); + gchar *text = NULL, *tmp; + + if (!gtk_clist_get_text(clist, row, 0, &text)) + break; + + /* NOTE: quick glance in source code of GtkCList + * reveals we should not free the returned 'text' */ + + tmp = g_strconcat(text, " ", NULL); + text = tmp; + gtk_entry_append_text(entry, text); + g_free(text); + } +#undef INVALID_FILENAME_CHARS +} + +static void filesel_dir_list_select_row_multi(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata) +{ + GtkEntry *entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry); + GtkCList *file_list = GTK_CLIST(GTK_FILE_SELECTION(filesel)->file_list); + + /* if dir list is selected we clean everything */ + gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1); + gtk_clist_unselect_all(file_list); +} + +static void filesel_file_list_select_row_single(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata) +{ + GtkEntry *entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry); + + g_free(filesel_oldfilename); + filesel_oldfilename = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); +} + +static void filesel_dir_list_select_row_single(GtkCList *clist, gint row, gint col, + GdkEventButton *event, gpointer userdata) +{ + GtkEntry *entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry); + + gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1); + if(filesel_oldfilename) { + gtk_entry_append_text(entry, filesel_oldfilename); + } +} + +static GList *filesel_get_multiple_filenames(void) +{ + /* as noted before we are not using the entry text when selecting + * multiple files. to much hassle to parse out invalid chars (chars + * that need to be escaped). instead we use the file_list. the + * entry is only useful for extracting the current directory. */ + GtkCList *file_list = GTK_CLIST(GTK_FILE_SELECTION(filesel)->file_list); + GtkEntry *file_entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry); + GList *list = NULL, *sel_list; + gchar *cwd, *tmp; + gboolean separator; + + g_return_val_if_fail(file_list->selection != NULL, NULL); + + tmp = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)); + tmp = g_strdup(tmp); + cwd = g_dirname(tmp); + g_free(tmp); + g_return_val_if_fail(cwd != NULL, NULL); + + /* only quick way to check the end of a multi byte string for our + * separator... */ + g_strreverse(cwd); + separator = 0 == g_strncasecmp(cwd, G_DIR_SEPARATOR_S, strlen(G_DIR_SEPARATOR_S)) + ? TRUE : FALSE; + g_strreverse(cwd); + + /* fetch the selected file names */ + for (sel_list = file_list->selection; sel_list; sel_list = sel_list->next) { + gint sel = GPOINTER_TO_INT(sel_list->data); + gchar *sel_text = NULL; + gchar *fname = NULL; + + gtk_clist_get_text(file_list, sel, 0, &sel_text); + if (!sel_text) continue; + sel_text = g_strdup(sel_text); + + if (separator) + fname = g_strconcat(cwd, sel_text, NULL); + else + fname = g_strconcat(cwd, G_DIR_SEPARATOR_S, sel_text, NULL); + + list = g_list_append(list, fname); + g_free(sel_text); + } + + return list; +} +