/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2003 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
*
* 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
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <glib.h>
#include <gdk/gdkkeysyms.h>
-#include <gtk/gtkwidget.h>
-#include <gtk/gtkfilesel.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
-#include <gtk/gtkeditable.h>
+#include <gtk/gtk.h>
+
+#ifdef MAEMO
+#ifdef CHINOOK
+#include <hildon/hildon-file-chooser-dialog.h>
+#else
+#include <hildon-widgets/hildon-file-chooser-dialog.h>
+#endif
+#endif
-#include "sylpheed.h"
+#include "claws.h"
#include "filesel.h"
#include "manage_window.h"
#include "gtkutils.h"
#include "utils.h"
+#include "codeconv.h"
+#include "procmime.h"
+#include "prefs_common.h"
-static GtkWidget *filesel;
-static gboolean filesel_ack;
-static gboolean filesel_fin;
-static gchar *filesel_oldfilename;
-
-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 gboolean 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 void
+update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
{
- static gchar *filename = NULL;
- static gchar *cwd = NULL;
-
- filesel_create(title, FALSE);
+ GtkWidget *preview;
+ char *filename = NULL, *type = NULL;
+ GdkPixbuf *pixbuf = NULL;
+ gboolean have_preview = FALSE;
- manage_window_set_transient(GTK_WINDOW(filesel));
+ preview = GTK_WIDGET (data);
+ filename = gtk_file_chooser_get_preview_filename (file_chooser);
- if (filename) {
- g_free(filename);
- filename = NULL;
+ if (filename == NULL) {
+ gtk_file_chooser_set_preview_widget_active (file_chooser, FALSE);
+ return;
}
+ type = procmime_get_mime_type(filename);
+
+ if (type && !strncmp(type, "image/", 6))
+ pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);
+
+ g_free(type);
+ g_free (filename);
- if (!cwd)
- cwd = g_strconcat(sylpheed_get_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);
- filesel_oldfilename = g_strdup(file);
- } else {
- filesel_oldfilename = NULL;
+ if (pixbuf) {
+ have_preview = TRUE;
+ gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
+ gdk_pixbuf_unref (pixbuf);
}
- gtk_widget_show(filesel);
-
- filesel_ack = filesel_fin = FALSE;
-
- while (filesel_fin == FALSE)
- gtk_main_iteration();
-
- if (filesel_ack) {
- const gchar *str;
-
- str = gtk_file_selection_get_filename
- (GTK_FILE_SELECTION(filesel));
- if (str && str[0] != '\0') {
- gchar *dir;
-
- filename = g_strdup(str);
- dir = g_dirname(str);
- g_free(cwd);
- cwd = g_strconcat(dir, G_DIR_SEPARATOR_S, NULL);
- g_free(dir);
- }
- }
-
- if (filesel_oldfilename)
- g_free(filesel_oldfilename);
-
- manage_window_focus_out(filesel, NULL, NULL);
- gtk_widget_destroy(filesel);
- GTK_EVENTS_FLUSH();
-
- return filename;
+ gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
}
-
-GList *filesel_select_multiple_files(const gchar *title, const gchar *file)
+
+static GList *filesel_create(const gchar *title, const gchar *path,
+ gboolean multiple_files,
+ gboolean open, gboolean folder_mode,
+ const gchar *filter)
{
- /* 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;
+ GSList *slist = NULL, *slist_orig = NULL;
+ GList *list = NULL;
+
+ gint action = (open == TRUE) ?
+ (folder_mode == TRUE ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ GTK_FILE_CHOOSER_ACTION_OPEN):
+ (folder_mode == TRUE ? GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:
+ GTK_FILE_CHOOSER_ACTION_SAVE);
+
+ gchar * action_btn = (open == TRUE) ? GTK_STOCK_OPEN:GTK_STOCK_SAVE;
+#ifdef MAEMO
+ GtkWidget *chooser;
+ if( path && strcmp(path, get_plugin_dir()) == 0 ) {
+#if !GTK_CHECK_VERSION(2,14,0)
+ chooser = gtk_file_chooser_dialog_new_with_backend
+ (title, NULL, action, "gtk+",
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ action_btn, GTK_RESPONSE_ACCEPT,
+ NULL);
+#else
+ chooser = gtk_file_chooser_dialog_new
+ (title, NULL, action,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ action_btn, GTK_RESPONSE_ACCEPT,
+ NULL);
+#endif
+ }
+ else {
+ chooser = hildon_file_chooser_dialog_new (NULL, action);
+ }
+#else
+#if !GTK_CHECK_VERSION(2,14,0)
+ GtkWidget *chooser = gtk_file_chooser_dialog_new_with_backend
+ (title, NULL, action, "gtk+",
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ action_btn, GTK_RESPONSE_ACCEPT,
+ NULL);
+#else
+ GtkWidget *chooser = gtk_file_chooser_dialog_new
+ (title, NULL, action,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ action_btn, GTK_RESPONSE_ACCEPT,
+ NULL);
+#endif
+#endif
+ if (filter != NULL) {
+ GtkFileFilter *file_filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(file_filter, filter);
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(chooser),
+ file_filter);
}
- if (!cwd)
- cwd = g_strconcat(sylpheed_get_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);
-
- filesel_ack = filesel_fin = FALSE;
-
- while (filesel_fin == FALSE)
- gtk_main_iteration();
+ if (action == GTK_FILE_CHOOSER_ACTION_OPEN) {
+ GtkImage *preview;
+ preview = GTK_IMAGE(gtk_image_new ());
+ gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER(chooser), GTK_WIDGET(preview));
+ g_signal_connect (chooser, "update-preview",
+ G_CALLBACK (update_preview_cb), preview);
- if (filesel_ack) {
- const gchar *fname = NULL;
+ }
- list = filesel_get_multiple_filenames();
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
+ gtk_dialog_set_default_response(GTK_DIALOG(chooser), GTK_RESPONSE_ACCEPT);
+ }
- if (!list) {
- fname = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
- list = g_list_append(list, g_strdup(fname));
+ manage_window_set_transient (GTK_WINDOW(chooser));
+ gtk_window_set_modal(GTK_WINDOW(chooser), TRUE);
+
+ gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER(chooser), multiple_files);
+
+ if (path && strlen(path) > 0) {
+ char *filename = NULL;
+ char *realpath = g_strdup(path);
+ char *tmp = NULL;
+ if (path[strlen(path)-1] == G_DIR_SEPARATOR) {
+ filename = "";
+ } else if ((filename = strrchr(path, G_DIR_SEPARATOR)) != NULL) {
+ filename++;
+ *(strrchr(realpath, G_DIR_SEPARATOR)+1) = '\0';
+ } else {
+ filename = (char *) path;
+ g_free(realpath);
+ realpath = g_strdup(get_home_dir());
}
- /* store dir of first entry */
- if (NULL != (fname = list->data) && *fname) {
- gchar *dir;
- if (NULL != (dir = g_dirname(fname))) {
- g_free(cwd);
- cwd = g_strconcat(dir, G_DIR_SEPARATOR_S, NULL);
- g_free(dir);
- }
+ tmp = NULL;
+ if (g_utf8_validate(realpath, -1, NULL))
+ tmp = g_filename_from_utf8(realpath, -1, NULL, NULL, NULL);
+ if (tmp == NULL)
+ tmp = g_strdup(realpath);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), tmp);
+ g_free(tmp);
+ if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
+ tmp = NULL;
+ if (g_utf8_validate(filename, -1, NULL))
+ tmp = g_filename_from_utf8(filename, -1, NULL, NULL, NULL);
+ if (tmp == NULL)
+ tmp = g_strdup(filename);
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), tmp);
+ g_free(tmp);
}
+ g_free(realpath);
+ } else {
+ gchar *tmp = NULL;
+ if (!prefs_common.attach_load_dir || !*prefs_common.attach_load_dir)
+ prefs_common.attach_load_dir = g_strdup_printf("%s%c", get_home_dir(), G_DIR_SEPARATOR);
+ if (g_utf8_validate(prefs_common.attach_load_dir, -1, NULL))
+ tmp = g_filename_from_utf8(prefs_common.attach_load_dir, -1, NULL, NULL, NULL);
+ if (tmp == NULL)
+ tmp = g_strdup(prefs_common.attach_load_dir);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), tmp);
+ g_free(tmp);
}
- manage_window_focus_out(filesel, NULL, NULL);
- gtk_widget_destroy(filesel);
- GTK_EVENTS_FLUSH();
+#ifdef MAEMO
+ if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_OK
+ || gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
+#else
+ if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
+#endif
+ slist = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
+
+ manage_window_focus_out(chooser, NULL, NULL);
+ gtk_widget_destroy (chooser);
- return list;
-}
+ slist_orig = slist;
+
+ if (slist) {
+ gchar *tmp = g_strdup(slist->data);
-static void filesel_create(const gchar *title, gboolean multiple_files)
-{
- filesel = gtk_file_selection_new(title);
- gtk_window_set_position(GTK_WINDOW(filesel), GTK_WIN_POS_CENTER);
- gtk_window_set_modal(GTK_WINDOW(filesel), TRUE);
- gtk_window_set_wmclass
- (GTK_WINDOW(filesel), "file_selection", "Sylpheed");
+ if (!path && prefs_common.attach_load_dir)
+ g_free(prefs_common.attach_load_dir);
+
+ if (strrchr(tmp, G_DIR_SEPARATOR))
+ *(strrchr(tmp, G_DIR_SEPARATOR)+1) = '\0';
- g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button),
- "clicked", G_CALLBACK(filesel_ok_cb),
- NULL);
- g_signal_connect
- (G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
- "clicked", G_CALLBACK(filesel_cancel_cb),
- NULL);
- g_signal_connect(G_OBJECT(filesel), "delete_event",
- G_CALLBACK(delete_event), NULL);
- g_signal_connect(G_OBJECT(filesel), "key_press_event",
- G_CALLBACK(key_pressed), NULL);
- MANAGE_WINDOW_SIGNALS_CONNECT(filesel);
+ if (!path)
+ prefs_common.attach_load_dir = g_filename_to_utf8(tmp, -1, NULL, NULL, NULL);
- 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_after(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->file_list),
- "select_row",
- GTK_SIGNAL_FUNC(filesel_file_list_select_row_single),
- NULL);
- gtk_signal_connect_after(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->dir_list),
- "select_row",
- GTK_SIGNAL_FUNC(filesel_dir_list_select_row_single),
- NULL);
+ g_free(tmp);
}
+
+ while (slist) {
+ list = g_list_append(list, slist->data);
+ slist = slist->next;
+ }
+
+ if (slist_orig)
+ g_slist_free(slist_orig);
+
+ return list;
}
-static void filesel_ok_cb(GtkWidget *widget, gpointer data)
+/**
+ * This function lets the user select multiple files.
+ * This opens an Open type dialog.
+ * @param title the title of the dialog
+ */
+GList *filesel_select_multiple_files_open(const gchar *title)
{
- filesel_ack = TRUE;
- filesel_fin = TRUE;
+ return filesel_create(title, NULL, TRUE, TRUE, FALSE, NULL);
}
-static void filesel_cancel_cb(GtkWidget *widget, gpointer data)
+GList *filesel_select_multiple_files_open_with_filter( const gchar *title,
+ const gchar *path,
+ const gchar *filter)
{
- filesel_ack = FALSE;
- filesel_fin = TRUE;
+ return filesel_create (title, path, TRUE, TRUE, FALSE, filter);
}
-static gint delete_event(GtkWidget *widget, GdkEventAny *event, gpointer data)
+/**
+ * This function lets the user select one file.
+ * This opens an Open type dialog if "file" is NULL,
+ * Save dialog if "file" contains a path.
+ * @param title the title of the dialog
+ * @param path the optional path to save to
+ */
+static gchar *filesel_select_file(const gchar *title, const gchar *path,
+ gboolean open, gboolean folder_mode,
+ const gchar *filter)
{
- filesel_cancel_cb(NULL, NULL);
- if (filesel_oldfilename) {
- g_free(filesel_oldfilename);
- filesel_oldfilename = NULL;
+ GList * list = filesel_create(title, path, FALSE, open, folder_mode, filter);
+ gchar * result = NULL;
+ if (list) {
+ result = g_strdup(list->data);
}
- return TRUE;
+ g_list_free(list);
+ return result;
}
-
-static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event, gpointer data)
+gchar *filesel_select_file_open(const gchar *title, const gchar *path)
{
- if (event && event->keyval == GDK_Escape)
- filesel_cancel_cb(NULL, NULL);
- return FALSE;
+ return filesel_select_file (title, path, TRUE, FALSE, 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)
+gchar *filesel_select_file_open_with_filter(const gchar *title, const gchar *path,
+ const gchar *filter)
{
- /* 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
+ return filesel_select_file (title, path, TRUE, FALSE, filter);
}
-static void filesel_dir_list_select_row_multi(GtkCList *clist, gint row, gint col,
- GdkEventButton *event, gpointer userdata)
+gchar *filesel_select_file_save(const gchar *title, const gchar *path)
{
- 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);
+ return filesel_select_file (title, path, FALSE, FALSE, NULL);
}
-static void filesel_file_list_select_row_single(GtkCList *clist, gint row, gint col,
- GdkEventButton *event, gpointer userdata)
+gchar *filesel_select_file_open_folder(const gchar *title, const gchar *path)
{
- gchar *text;
-
- if(gtk_clist_get_text(clist, row, 0, &text)) {
- filesel_oldfilename = g_strdup(text);
- debug_print("%s\n", filesel_oldfilename);
- } else {
- filesel_oldfilename = NULL;
- }
-}
-
-static void filesel_dir_list_select_row_single(GtkCList *clist, gint row, gint col,
- GdkEventButton *event, gpointer userdata)
-{
- gchar *buf;
- GtkEntry *entry = GTK_ENTRY(GTK_FILE_SELECTION(filesel)->selection_entry);
-
- buf = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);
- if(filesel_oldfilename && !(*buf)) {
- gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
- gtk_entry_append_text(entry, filesel_oldfilename);
- }
- g_free(buf);
+ return filesel_select_file (title, path, TRUE, TRUE, NULL);
}
-static GList *filesel_get_multiple_filenames(void)
+gchar *filesel_select_file_save_folder(const gchar *title, const gchar *path)
{
- /* 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);
- GList *list = NULL, *sel_list;
- gchar *cwd;
- gboolean separator;
-
- g_return_val_if_fail(file_list->selection != NULL, NULL);
-
- cwd = g_dirname(gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)));
- 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);
- }
-
- g_free(cwd);
-
- return list;
+ return filesel_select_file (title, path, FALSE, TRUE, NULL);
}