Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evince/ChangeLog,v
retrieving revision 1.807
diff -u -u -r1.807 ChangeLog
--- ChangeLog	29 Apr 2006 12:20:23 -0000	1.807
+++ ChangeLog	29 Apr 2006 18:28:28 -0000
@@ -1,3 +1,11 @@
+2006-04-29  Carlos Garcia Campos  <carlosgc@gnome.org>
+
+	* backend/ev-attachment.c: 
+	* shell/ev-attachment-bar.c:
+	* shell/ev-window.c:
+
+	Allow multiple selection of attachments
+
 2006-04-29  Nickolay V. Shmyrev  <<nshmyrev@yandex.ru>>
 
 	* shell/ev-view.c: (view_update_range_and_current_page),
Index: backend/ev-attachment.c
===================================================================
RCS file: /cvs/gnome/evince/backend/ev-attachment.c,v
retrieving revision 1.2
diff -u -u -r1.2 ev-attachment.c
--- backend/ev-attachment.c	4 Apr 2006 16:52:48 -0000	1.2
+++ backend/ev-attachment.c	29 Apr 2006 18:28:28 -0000
@@ -367,10 +367,14 @@
 	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 @@
 		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);
Index: shell/ev-attachment-bar.c
===================================================================
RCS file: /cvs/gnome/evince/shell/ev-attachment-bar.c,v
retrieving revision 1.2
diff -u -u -r1.2 ev-attachment-bar.c
--- shell/ev-attachment-bar.c	3 Apr 2006 12:35:04 -0000	1.2
+++ shell/ev-attachment-bar.c	29 Apr 2006 18:28:29 -0000
@@ -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 <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <gtk/gtk.h>
@@ -201,13 +205,76 @@
 }
 
 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 @@
 	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 @@
 	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 @@
 				 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 @@
 			      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 @@
 	/* 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,
@@ -505,10 +550,6 @@
 	g_signal_connect (G_OBJECT (ev_attachbar->priv->icon_view),
 			  "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),
Index: shell/ev-window.c
===================================================================
RCS file: /cvs/gnome/evince/shell/ev-window.c,v
retrieving revision 1.270
diff -u -u -r1.270 ev-window.c
--- shell/ev-window.c	21 Apr 2006 15:06:28 -0000	1.270
+++ shell/ev-window.c	29 Apr 2006 18:28:29 -0000
@@ -135,7 +135,7 @@
 
 	/* Popup attachment */
 	GtkWidget    *attachment_popup;
-	EvAttachment *attachment;
+	GList        *attach_list;
 
 	/* Document */
 	char *uri;
@@ -1137,7 +1137,7 @@
 	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 @@
 			ev_window_error_dialog (GTK_WINDOW (fc), msg, err);
 			g_free (msg);
 		}
+
+		g_free (uri);
 	}
 
 	gtk_widget_destroy (fc);
@@ -2567,25 +2569,30 @@
 	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 @@
 		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 @@
 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 @@
 				    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 @@
 	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->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 */
 
