From ab8da3ce3810df8dc6a9df049031292ee03b4393 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Sun, 30 Apr 2006 21:27:04 +0000 Subject: Allow multiple selection of attachments 2006-04-29 Carlos Garcia Campos * backend/ev-attachment.c: * shell/ev-attachment-bar.c: * shell/ev-window.c: Allow multiple selection of attachments --- diff --git a/ChangeLog b/ChangeLog index 6dbe465..28f4908 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2006-04-29 Carlos Garcia Campos + + * backend/ev-attachment.c: + * shell/ev-attachment-bar.c: + * shell/ev-window.c: + + Allow multiple selection of attachments + 2006-04-29 Nickolay V. Shmyrev <> * shell/ev-view.c: (view_update_range_and_current_page), diff --git a/backend/ev-attachment.c b/backend/ev-attachment.c index f0002f3..3314738 100644 --- a/backend/ev-attachment.c +++ b/backend/ev-attachment.c @@ -367,10 +367,14 @@ ev_attachment_open (EvAttachment *attachment, gboolean retval = FALSE; GnomeVFSMimeApplication *default_app = NULL; - if (!attachment->priv->app) + g_return_val_if_fail (EV_IS_ATTACHMENT (attachment), FALSE); + + if (!attachment->priv->app) { default_app = gnome_vfs_mime_get_default_application (attachment->priv->mime_type); + attachment->priv->app = default_app; + } - if (!default_app) { + if (!attachment->priv->app) { g_set_error (error, EV_ATTACHMENT_ERROR, 0, @@ -380,8 +384,6 @@ ev_attachment_open (EvAttachment *attachment, return FALSE; } - attachment->priv->app = default_app; - if (attachment->priv->tmp_uri && g_file_test (attachment->priv->tmp_uri, G_FILE_TEST_EXISTS)) { retval = ev_attachment_launch_app (attachment, error); diff --git a/shell/ev-attachment-bar.c b/shell/ev-attachment-bar.c index b58f583..cdeba89 100644 --- a/shell/ev-attachment-bar.c +++ b/shell/ev-attachment-bar.c @@ -21,6 +21,10 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include @@ -201,13 +205,76 @@ ev_attachment_bar_get_attachment_at_pos (EvAttachmentBar *ev_attachbar, } static gboolean +ev_attachment_bar_popup_menu_show (EvAttachmentBar *ev_attachbar, + gint x, + gint y) +{ + GtkIconView *icon_view; + GtkTreePath *path; + GList *selected = NULL, *l; + GList *attach_list = NULL; + + icon_view = GTK_ICON_VIEW (ev_attachbar->priv->icon_view); + + path = gtk_icon_view_get_path_at_pos (icon_view, x, y); + if (!path) + return FALSE; + + if (!gtk_icon_view_path_is_selected (icon_view, path)) { + gtk_icon_view_unselect_all (icon_view); + gtk_icon_view_select_path (icon_view, path); + } + + gtk_tree_path_free (path); + + selected = gtk_icon_view_get_selected_items (icon_view); + if (!selected) + return FALSE; + + for (l = selected; l && l->data; l = g_list_next (l)) { + GtkTreeIter iter; + EvAttachment *attachment = NULL; + + path = (GtkTreePath *) l->data; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model), + &iter, path); + gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter, + COLUMN_ATTACHMENT, &attachment, + -1); + + if (attachment) + attach_list = g_list_prepend (attach_list, attachment); + + gtk_tree_path_free (path); + } + + g_list_free (selected); + + if (!attach_list) + return FALSE; + + g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attach_list); + + return TRUE; +} + +static gboolean +ev_attachment_bar_popup_menu (GtkWidget *widget) +{ + EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget); + gint x, y; + + gtk_widget_get_pointer (widget, &x, &y); + + return ev_attachment_bar_popup_menu_show (ev_attachbar, x, y); +} + +static gboolean ev_attachment_bar_button_press (EvAttachmentBar *ev_attachbar, GdkEventButton *event, GtkWidget *icon_view) { - EvAttachment *attachment; - gboolean handled = FALSE; - if (!GTK_WIDGET_HAS_FOCUS (icon_view)) { gtk_widget_grab_focus (icon_view); } @@ -215,37 +282,35 @@ ev_attachment_bar_button_press (EvAttachmentBar *ev_attachbar, if (event->button == 2) return FALSE; - attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar, - event->x, - event->y); - if (!attachment) - return FALSE; - switch (event->button) { case 1: if (event->type == GDK_2BUTTON_PRESS) { GError *error = NULL; - + EvAttachment *attachment; + + attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar, + event->x, + event->y); + if (!attachment) + return FALSE; + ev_attachment_open (attachment, &error); if (error) { g_warning (error->message); g_error_free (error); } + + g_object_unref (attachment); - handled = TRUE; + return TRUE; } break; - case 3: - g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment); - handled = TRUE; - - break; + case 3: + return ev_attachment_bar_popup_menu_show (ev_attachbar, event->x, event->y); } - g_object_unref (attachment); - - return handled; + return FALSE; } static gboolean @@ -260,24 +325,6 @@ ev_attachment_bar_focus_in (GtkWidget *widget, return TRUE; } -static gboolean -ev_attachment_bar_popup_menu (GtkWidget *widget) -{ - EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (widget); - EvAttachment *attachment; - gint x, y; - - gtk_widget_get_pointer (widget, &x, &y); - attachment = ev_attachment_bar_get_attachment_at_pos (ev_attachbar, - x, y); - if (!attachment) - return FALSE; - - g_signal_emit (ev_attachbar, signals[SIGNAL_POPUP_MENU], 0, attachment); - - return TRUE; -} - static void ev_attachment_bar_update_icons (EvAttachmentBar *ev_attachbar, gpointer user_data) @@ -327,70 +374,66 @@ ev_attachment_bar_drag_data_get (GtkWidget *widget, gpointer user_data) { EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (user_data); - EvAttachment *attachment; - GtkTreePath *path; - GtkTreeIter iter; - GList *selected = NULL; - gchar *uri, *filename; - GError *error = NULL; + GString *uri_list; + gchar *uris = NULL; + GList *selected = NULL, *l; selected = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (ev_attachbar->priv->icon_view)); if (!selected) return; - path = (GtkTreePath *) selected->data; + uri_list = g_string_new (NULL); + + for (l = selected; l && l->data; l = g_list_next (l)) { + EvAttachment *attachment; + GtkTreePath *path; + GtkTreeIter iter; + gchar *uri, *filename; + GError *error = NULL; + + path = (GtkTreePath *) l->data; - gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model), - &iter, path); - gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter, - COLUMN_ATTACHMENT, &attachment, - -1); + gtk_tree_model_get_iter (GTK_TREE_MODEL (ev_attachbar->priv->model), + &iter, path); + gtk_tree_model_get (GTK_TREE_MODEL (ev_attachbar->priv->model), &iter, + COLUMN_ATTACHMENT, &attachment, + -1); - filename = g_build_filename (g_get_tmp_dir (), - ev_attachment_get_name (attachment), - NULL); - uri = g_filename_to_uri (filename, NULL, NULL); + filename = g_build_filename (g_get_tmp_dir (), + ev_attachment_get_name (attachment), + NULL); + + uri = g_filename_to_uri (filename, NULL, NULL); - g_object_set_data_full (G_OBJECT (drag_context), - "tmp-filename", filename, - g_free); - + if (ev_attachment_save (attachment, filename, &error)) { + g_string_append (uri_list, uri); + g_string_append_c (uri_list, '\n'); + } - if (ev_attachment_save (attachment, uri, &error)) { + if (error) { + g_warning (error->message); + g_error_free (error); + } + + g_free (uri); + gtk_tree_path_free (path); + g_object_unref (attachment); + } + + uris = g_string_free (uri_list, FALSE); + + if (uris) { gtk_selection_data_set (data, data->target, 8, - (guchar *)uri, - strlen (uri)); - } - - if (error) { - g_warning (error->message); - g_error_free (error); + (guchar *)uris, + strlen (uris)); } - g_free (uri); - g_object_unref (attachment); - g_list_foreach (selected, - (GFunc) gtk_tree_path_free, - NULL); g_list_free (selected); } static void -ev_attachment_bar_drag_data_delete (GtkWidget *widget, - GdkDragContext *drag_context, - gpointer user_data) -{ - gchar *filename; - - filename = g_object_get_data (G_OBJECT (drag_context), "tmp-filename"); - - if (filename && g_file_test (filename, G_FILE_TEST_EXISTS)) - g_unlink (filename); -} - -static void ev_attachment_bar_destroy (GtkObject *object) { EvAttachmentBar *ev_attachbar = EV_ATTACHMENT_BAR (object); @@ -432,9 +475,9 @@ ev_attachment_bar_class_init (EvAttachmentBarClass *ev_attachbar_class) G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EvAttachmentBarClass, popup_menu), NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, + g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, - G_TYPE_OBJECT); + G_TYPE_POINTER); } static void @@ -462,6 +505,8 @@ ev_attachment_bar_init (EvAttachmentBar *ev_attachbar) /* Icon View */ ev_attachbar->priv->icon_view = gtk_icon_view_new_with_model (GTK_TREE_MODEL (ev_attachbar->priv->model)); + gtk_icon_view_set_selection_mode (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), + GTK_SELECTION_MULTIPLE); gtk_icon_view_set_columns (GTK_ICON_VIEW (ev_attachbar->priv->icon_view), -1); g_object_set (G_OBJECT (ev_attachbar->priv->icon_view), "text-column", COLUMN_NAME, @@ -506,10 +551,6 @@ ev_attachment_bar_init (EvAttachmentBar *ev_attachbar) "drag-data-get", G_CALLBACK (ev_attachment_bar_drag_data_get), (gpointer) ev_attachbar); - g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view), - "drag-data-delete", - G_CALLBACK (ev_attachment_bar_drag_data_delete), - (gpointer) ev_attachbar); g_signal_connect (G_OBJECT (ev_attachbar), "notify::expanded", diff --git a/shell/ev-window.c b/shell/ev-window.c index f0dc8bb..71cf0ec 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -135,7 +135,7 @@ struct _EvWindowPrivate { /* Popup attachment */ GtkWidget *attachment_popup; - EvAttachment *attachment; + GList *attach_list; /* Document */ char *uri; @@ -1137,7 +1137,7 @@ file_save_dialog_response_cb (GtkWidget *fc, gboolean success; if (response_id == GTK_RESPONSE_OK) { - const char *uri; + gchar *uri; GError *err = NULL; uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc)); @@ -1152,6 +1152,8 @@ file_save_dialog_response_cb (GtkWidget *fc, ev_window_error_dialog (GTK_WINDOW (fc), msg, err); g_free (msg); } + + g_free (uri); } gtk_widget_destroy (fc); @@ -2567,25 +2569,30 @@ view_menu_popup_cb (EvView *view, return FALSE; } -static void +static gboolean attachment_bar_menu_popup_cb (EvAttachmentBar *attachbar, - EvAttachment *attachment, + GList *attach_list, EvWindow *ev_window) { GtkWidget *popup; - if (ev_window->priv->attachment) - g_object_unref (ev_window->priv->attachment); - if (attachment) - ev_window->priv->attachment = g_object_ref (attachment); - else - ev_window->priv->attachment = NULL; + g_assert (attach_list != NULL); + + if (ev_window->priv->attach_list) { + g_list_foreach (ev_window->priv->attach_list, + (GFunc) g_object_unref, NULL); + g_list_free (ev_window->priv->attach_list); + } + + ev_window->priv->attach_list = attach_list; popup = ev_window->priv->attachment_popup; gtk_menu_popup (GTK_MENU (popup), NULL, NULL, NULL, NULL, 3, gtk_get_current_event_time ()); + + return TRUE; } static void @@ -2781,9 +2788,12 @@ ev_window_dispose (GObject *object) priv->link = NULL; } - if (priv->attachment) { - g_object_unref (priv->attachment); - priv->attachment = NULL; + if (priv->attach_list) { + g_list_foreach (priv->attach_list, + (GFunc) g_object_unref, + NULL); + g_list_free (priv->attach_list); + priv->attach_list = NULL; } if (priv->find_bar) { @@ -3313,18 +3323,25 @@ ev_view_popup_cmd_copy_link_address (GtkAction *action, EvWindow *window) static void ev_attachment_popup_cmd_open_attachment (GtkAction *action, EvWindow *window) { - GError *error = NULL; + GList *l; - if (!window->priv->attachment) + if (!window->priv->attach_list) return; - - ev_attachment_open (window->priv->attachment, &error); - if (error) { - ev_window_error_dialog (GTK_WINDOW (window), - _("Unable to open attachment"), - error); - g_error_free (error); + for (l = window->priv->attach_list; l && l->data; l = g_list_next (l)) { + EvAttachment *attachment; + GError *error = NULL; + + attachment = (EvAttachment *) l->data; + + ev_attachment_open (attachment, &error); + + if (error) { + ev_window_error_dialog (GTK_WINDOW (window), + _("Unable to open attachment"), + error); + g_error_free (error); + } } } @@ -3333,37 +3350,72 @@ attachment_save_dialog_response_cb (GtkWidget *fc, gint response_id, EvWindow *ev_window) { - if (response_id == GTK_RESPONSE_OK) { - const char *uri; - GError *error = NULL; - - uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc)); + gchar *uri; + GList *l; + GtkFileChooserAction fc_action; + gboolean is_dir; + + if (response_id != GTK_RESPONSE_OK) { + gtk_widget_destroy (fc); + return; + } - ev_attachment_save (ev_window->priv->attachment, uri, &error); + uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc)); + + g_object_get (G_OBJECT (fc), "action", &fc_action, NULL); + is_dir = (fc_action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER); + + for (l = ev_window->priv->attach_list; l && l->data; l = g_list_next (l)) { + EvAttachment *attachment; + gchar *filename; + GError *error = NULL; + + attachment = (EvAttachment *) l->data; + if (is_dir) { + filename = g_strjoin ("/", uri, + ev_attachment_get_name (attachment), + NULL); + } else { + filename = g_strdup (uri); + } + + ev_attachment_save (attachment, filename, &error); + g_free (filename); + if (error) { ev_window_error_dialog (GTK_WINDOW (fc), - _("The attachment could not be saved."), - error); + _("The attachment could not be saved."), + error); g_error_free (error); } } + g_free (uri); + gtk_widget_destroy (fc); } static void ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, EvWindow *window) { - GtkWidget *fc; + GtkWidget *fc; + EvAttachment *attachment = NULL; - fc = gtk_file_chooser_dialog_new (_("Save a Copy"), - GTK_WINDOW (window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); + if (!window->priv->attach_list) + return; + + if (g_list_length (window->priv->attach_list) == 1) + attachment = (EvAttachment *) window->priv->attach_list->data; + + fc = gtk_file_chooser_dialog_new ( + _("Save a Copy"), + GTK_WINDOW (window), + attachment ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_OK, + NULL); gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK); @@ -3371,8 +3423,9 @@ ev_attachment_popup_cmd_save_attachment_as (GtkAction *action, EvWindow *window) gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (fc), TRUE); #endif - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc), - ev_attachment_get_name (window->priv->attachment)); + if (attachment) + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (fc), + ev_attachment_get_name (attachment)); g_signal_connect (fc, "response", G_CALLBACK (attachment_save_dialog_response_cb), @@ -3654,19 +3707,21 @@ ev_window_init (EvWindow *ev_window) ev_window->priv->attachment_popup = gtk_ui_manager_get_widget (ev_window->priv->ui_manager, "/AttachmentPopup"); - ev_window->priv->attachment = NULL; + ev_window->priv->attach_list = NULL; /* Give focus to the document view */ gtk_widget_grab_focus (ev_window->priv->view); /* Drag and Drop */ - gtk_drag_dest_unset (GTK_WIDGET (ev_window)); - gtk_drag_dest_set (GTK_WIDGET (ev_window), GTK_DEST_DEFAULT_ALL, + gtk_drag_dest_unset (GTK_WIDGET (ev_window->priv->view)); + gtk_drag_dest_set (GTK_WIDGET (ev_window->priv->view), + GTK_DEST_DEFAULT_ALL, ev_drop_types, sizeof (ev_drop_types) / sizeof (ev_drop_types[0]), GDK_ACTION_COPY); - g_signal_connect (G_OBJECT (ev_window), "drag-data-received", - G_CALLBACK (drag_data_received_cb), NULL); + g_signal_connect_swapped (G_OBJECT (ev_window->priv->view), "drag-data-received", + G_CALLBACK (drag_data_received_cb), + ev_window); /* Set it user interface params */ -- cgit v0.9.1