diff options
Diffstat (limited to 'calendar')
-rw-r--r-- | calendar/ChangeLog | 7 | ||||
-rw-r--r-- | calendar/calendar.error.xml | 14 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-attachment-bar.c | 186 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-attachment-bar.h | 2 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-attachment.c | 222 | ||||
-rw-r--r-- | calendar/gui/dialogs/cal-attachment.h | 10 | ||||
-rw-r--r-- | calendar/gui/dialogs/comp-editor.c | 28 |
7 files changed, 434 insertions, 35 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 2b3574ef54..7d277d1e45 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,10 @@ +2005-05-24 Srinivasa Ragavan <sragavan@novell.com> + * gui/dialogs/cal-attachment-bar.c, gui/dialogs/cal-attachment-bar.h, + gui/dialogs/cal-attachment.c, gui/dialogs/cal-attachment.h, + gui/dialogs/comp-editor.c, calendar.error.xml: Added the support to DnD + remote URL to the attachment window. It downloads asynchronously and + attaches. + 2005-05-16 Srinivasa Ragavan <sragavan@novell.com> * gui/dialogs/comp-editor.c (attachment_bar_changed_cb) diff --git a/calendar/calendar.error.xml b/calendar/calendar.error.xml index b45fe4d453..672ec7a247 100644 --- a/calendar/calendar.error.xml +++ b/calendar/calendar.error.xml @@ -145,6 +145,20 @@ <button _label="Send" response="GTK_RESPONSE_YES"/> </error> + <error id="ask-send-task-pending-download" type="question" default="GTK_RESPONSE_YES"> + <_primary>Download in progress. Do you want to save the task?</_primary> + <_secondary xml:space="preserve"> There are few attachments getting downloaded. Saving the task will cause the task to be saved without those pending attachments </_secondary> + <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/> + <button _label="_Save" response="GTK_RESPONSE_YES"/> + </error> + + <error id="ask-send-event-pending-download" type="question" default="GTK_RESPONSE_YES"> + <_primary>Download in progress. Do you want to save the appointment?</_primary> + <_secondary xml:space="preserve"> There are few attachments getting downloaded. Saving the appointment will cause the appointment to be saved without those pending attachments </_secondary> + <button stock="gtk-cancel" response="GTK_RESPONSE_CANCEL"/> + <button _label="_Save" response="GTK_RESPONSE_YES"/> + </error> + <error id="prompt-send-updated-task-info" type="question" default="GTK_RESPONSE_YES"> <_primary>Would you like to send updated task information to participants?</_primary> <_secondary>Sending updated information allows other participants to keep their task lists up to date.</_secondary> diff --git a/calendar/gui/dialogs/cal-attachment-bar.c b/calendar/gui/dialogs/cal-attachment-bar.c index cacc7c7d30..b102315db8 100644 --- a/calendar/gui/dialogs/cal-attachment-bar.c +++ b/calendar/gui/dialogs/cal-attachment-bar.c @@ -57,6 +57,7 @@ #include "e-util/e-gui-utils.h" #include "e-util/e-icon-factory.h" #include "e-util/e-error.h" +#include "e-util/e-mktemp.h" #include "mail/em-popup.h" #define ICON_WIDTH 64 @@ -78,6 +79,7 @@ struct _CalAttachmentBarPrivate { */ char *local_attachment_store; char *comp_uid; + char *path; }; enum { @@ -226,10 +228,21 @@ update (CalAttachmentBar *bar) CalAttachment *attachment; CamelContentType *content_type; char *size_string, *label; - GdkPixbuf *pixbuf; + GdkPixbuf *pixbuf=NULL; const char *desc; attachment = p->data; + + if (!attachment->is_available_local) { + /* stock_attach would be better, but its fugly scaled up */ + pixbuf = e_icon_factory_get_icon("stock_unknown", E_ICON_SIZE_DIALOG); + if (pixbuf) { + attachment->index = gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, ""); + g_object_unref(pixbuf); + } + continue; + } + content_type = camel_mime_part_get_content_type (attachment->body); /* Get the image out of the attachment and create a thumbnail for it */ @@ -328,6 +341,27 @@ update (CalAttachmentBar *bar) } static void +update_remote_file (CalAttachmentBar *bar, CalAttachment *attachment, char *msg) +{ + CalAttachmentBarPrivate *priv; + GnomeIconList *icon_list; + GnomeIconTextItem *item; + + priv = bar->priv; + icon_list = GNOME_ICON_LIST (bar); + + gnome_icon_list_freeze (icon_list); + + item = gnome_icon_list_get_icon_text_item (icon_list, attachment->index); + if (!item->is_text_allocated) + g_free (item->text); + + gnome_icon_text_item_configure (item, item->x, item->y, item->width, item->fontname, msg, item->is_editable, TRUE); + + gnome_icon_list_thaw (icon_list); +} + +static void remove_selected (CalAttachmentBar *bar) { GnomeIconList *icon_list; @@ -538,6 +572,8 @@ destroy (GtkObject *object) g_free (bar->priv->local_attachment_store); if (bar->priv->comp_uid) g_free (bar->priv->comp_uid); + if (bar->priv->path) + g_free (bar->priv->path); g_free (bar->priv); bar->priv = NULL; } @@ -634,6 +670,7 @@ init (CalAttachmentBar *bar) priv->num_attachments = 0; priv->local_attachment_store = NULL; priv->comp_uid = NULL; + priv->path = NULL; bar->priv = priv; } @@ -776,6 +813,147 @@ cal_attachment_bar_attach (CalAttachmentBar *bar, add_from_file (bar, file_name, "attachment"); } +typedef struct DownloadInfo { + CalAttachment *attachment; + CalAttachmentBar *bar; + gchar *file_name; +}DownloadInfo; + +static int +async_progress_update_cb (GnomeVFSAsyncHandle *handle, + GnomeVFSXferProgressInfo *info, + DownloadInfo *download_info) +{ + int percent=0; + switch (info->status) { + case GNOME_VFS_XFER_PROGRESS_STATUS_OK: + { + gchar *base_path = g_path_get_basename(download_info->attachment->file_name); + if (info->file_size) { + percent = info->bytes_copied*100/info->file_size; + update_remote_file (download_info->bar, + download_info->attachment, + g_strdup_printf("%s (%d\%)", base_path, percent)); + } else { + update_remote_file (download_info->bar, + download_info->attachment, + g_strdup_printf("%s (%d\%)", base_path, percent)); + } + g_free (base_path); + + if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) { + CamelException ex; + + download_info->attachment->is_available_local = TRUE; + download_info->attachment->handle = NULL; + camel_exception_init (&ex); + cal_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex); + update(download_info->bar); + g_free (download_info->file_name); + g_free (download_info); + } + return TRUE; + break; + } + case GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR: + gnome_vfs_async_cancel (handle); + g_free (download_info->file_name); + g_free (download_info); + return FALSE; + break; + + default: + break; + } + + return TRUE; +} + +static void +download_to_local_path (GnomeVFSURI *source_uri, GnomeVFSURI *target_uri, DownloadInfo *download_info) + +{ + GnomeVFSResult result; + GList *source_uri_list = NULL; + GList *target_uri_list = NULL; + + source_uri_list = g_list_prepend (source_uri_list, source_uri); + target_uri_list = g_list_prepend (target_uri_list, target_uri); + + /* Callback info */ + result = gnome_vfs_async_xfer (&download_info->attachment->handle, /* handle_return */ + source_uri_list, /* source_uri_list */ + target_uri_list, /* target_uri_list */ + GNOME_VFS_XFER_DEFAULT, /* xfer_options */ + GNOME_VFS_XFER_ERROR_MODE_ABORT, /* error_mode */ + GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE, /* overwrite_mode */ + GNOME_VFS_PRIORITY_DEFAULT, /* priority */ + async_progress_update_cb, /* progress_update_callback */ + download_info, /* update_callback_data */ + NULL, /* progress_sync_callback */ + NULL); /* sync_callback_data */ +} + + +int +cal_attachment_bar_get_download_count (CalAttachmentBar *bar) +{ + CalAttachmentBarPrivate *priv; + GList *p; + int count=0; + + priv = bar->priv; + + for (p = priv->attachments; p != NULL; p = p->next) { + CalAttachment *attachment; + + attachment = p->data; + if (!attachment->is_available_local) + count++; + } + + return count; +} + +void +cal_attachment_bar_attach_remote_file (CalAttachmentBar *bar, + const gchar *url) +{ + CalAttachment *attachment; + CamelException ex; + gchar *tmpfile; + gchar *base; + + if (!bar->priv->path) + bar->priv->path = e_mkdtemp("attach-XXXXXX"); + base = g_path_get_basename (url); + + g_return_if_fail (E_IS_CAL_ATTACHMENT_BAR (bar)); + tmpfile = g_build_filename (bar->priv->path, base, NULL); + + g_free (base); + + camel_exception_init (&ex); + attachment = cal_attachment_new_remote_file (tmpfile, "attachment", &ex); + if (attachment) { + DownloadInfo *download_info; + download_info = g_new (DownloadInfo, 1); + download_info->attachment = attachment; + download_info->bar =bar; + download_info->file_name = g_strdup (tmpfile); + add_common (bar, attachment); + download_to_local_path (gnome_vfs_uri_new(url), gnome_vfs_uri_new(tmpfile), download_info); + + } else { + e_error_run((GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)bar), "mail-composer:no-attach", + attachment->file_name, camel_exception_get_description(&ex), NULL); + camel_exception_clear (&ex); + } + + g_free (tmpfile); + +} + /* * TODO write a good documentation * this method serializes the attached files on the filesystem @@ -797,6 +975,9 @@ cal_attachment_bar_get_attachment_list (CalAttachmentBar *bar) char *attach_file_url; attachment = p->data; + + if (!attachment->is_available_local) + continue; wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body)); mstream = (CamelStreamMem *) camel_stream_mem_new (); @@ -905,6 +1086,9 @@ cal_attachment_bar_get_mime_attach_list (CalAttachmentBar *bar) CamelStreamMem *mstream; unsigned char *buffer = NULL; char *desc; + + if (!attach->is_available_local) + continue; cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach)); wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attach->body)); diff --git a/calendar/gui/dialogs/cal-attachment-bar.h b/calendar/gui/dialogs/cal-attachment-bar.h index 468bae0495..3eb1dff95c 100644 --- a/calendar/gui/dialogs/cal-attachment-bar.h +++ b/calendar/gui/dialogs/cal-attachment-bar.h @@ -69,6 +69,8 @@ void cal_attachment_bar_to_multipart (CalAttachmentBar *bar, CamelMultipart *mul guint cal_attachment_bar_get_num_attachments (CalAttachmentBar *bar); void cal_attachment_bar_attach (CalAttachmentBar *bar, const char *file_name); void cal_attachment_bar_attach_mime_part (CalAttachmentBar *bar, CamelMimePart *part); +void cal_attachment_bar_attach_remote_file (CalAttachmentBar *bar, const gchar *url); +int cal_attachment_bar_get_download_count (CalAttachmentBar *bar); GSList *cal_attachment_bar_get_attachment_list (CalAttachmentBar *bar); char * cal_attachment_bar_get_nth_attachment_filename (CalAttachmentBar *bar, int n); GSList *cal_attachment_bar_get_mime_attach_list (CalAttachmentBar *bar); diff --git a/calendar/gui/dialogs/cal-attachment.c b/calendar/gui/dialogs/cal-attachment.c index 2f36aaf887..f9ecb9f329 100644 --- a/calendar/gui/dialogs/cal-attachment.c +++ b/calendar/gui/dialogs/cal-attachment.c @@ -71,9 +71,18 @@ finalise(GObject *object) attachment = CAL_ATTACHMENT (object); - camel_object_unref (attachment->body); - if (attachment->pixbuf_cache != NULL) - g_object_unref (attachment->pixbuf_cache); + if (attachment->is_available_local) { + camel_object_unref (attachment->body); + if (attachment->pixbuf_cache != NULL) + g_object_unref (attachment->pixbuf_cache); + } else { + if (attachment->handle) + gnome_vfs_async_cancel(attachment->handle); + if (attachment->file_name) + g_free (attachment->file_name); + if (attachment->description) + g_free (attachment->description); + } G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -116,6 +125,10 @@ init (CalAttachment *cal_attachment) cal_attachment->body = NULL; cal_attachment->size = 0; cal_attachment->pixbuf_cache = NULL; + cal_attachment->index = -1; + cal_attachment->file_name = NULL; + cal_attachment->description = NULL; + cal_attachment->disposition = FALSE; } GType @@ -259,10 +272,122 @@ cal_attachment_new (const char *file_name, new->body = part; new->size = statbuf.st_size; new->guessed_type = TRUE; + new->handle = NULL; + new->is_available_local = TRUE; return new; } +CalAttachment * +cal_attachment_new_remote_file (const char *file_name, + const char *disposition, + CamelException *ex) +{ + CalAttachment *new; + + g_return_val_if_fail (file_name != NULL, NULL); + + new = g_object_new (E_TYPE_CAL_ATTACHMENT, NULL); + new->editor_gui = NULL; + new->body = NULL; + new->size = 0; + new->guessed_type = FALSE; + new->handle = NULL; + new->is_available_local = FALSE; + new->file_name = g_path_get_basename(file_name); + + return new; +} + +void +cal_attachment_build_remote_file (const char *file_name, + CalAttachment *attachment, + const char *disposition, + CamelException *ex) +{ + CamelMimePart *part; + CamelDataWrapper *wrapper; + CamelStream *stream; + struct stat statbuf; + char *mime_type; + char *filename; + + g_return_if_fail (file_name != NULL); + + if (stat (file_name, &statbuf) < 0) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: %s"), + file_name, g_strerror (errno)); + return; + } + + /* return if it's not a regular file */ + if (!S_ISREG (statbuf.st_mode)) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: not a regular file"), + file_name); + return; + } + + stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0); + if (!stream) { + camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, + _("Cannot attach file %s: %s"), + file_name, g_strerror (errno)); + return; + } + + mime_type = cal_attachment_guess_mime_type (file_name); + if (mime_type) { + if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) { + wrapper = (CamelDataWrapper *) camel_mime_message_new (); + } else { + wrapper = camel_data_wrapper_new (); + } + + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_data_wrapper_set_mime_type (wrapper, mime_type); + g_free (mime_type); + } else { + wrapper = camel_data_wrapper_new (); + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_data_wrapper_set_mime_type (wrapper, "application/octet-stream"); + } + + camel_object_unref (stream); + + part = camel_mime_part_new (); + camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); + camel_object_unref (wrapper); + + if (attachment->disposition) + camel_mime_part_set_disposition (part, "inline"); + else + camel_mime_part_set_disposition (part, "attachment"); + + if (!attachment->file_name) + filename = g_path_get_basename (file_name); + else + filename = g_path_get_basename (attachment->file_name); + + camel_mime_part_set_filename (part, filename); + g_free (filename); + + if (attachment->description) { + camel_mime_part_set_description (part, attachment->description); + g_free (attachment->description); + attachment->description = NULL; + } + + attachment->editor_gui = NULL; + attachment->body = part; + attachment->size = statbuf.st_size; + attachment->guessed_type = TRUE; + if (attachment->file_name) { + g_free (attachment->file_name); + attachment->file_name = NULL; + } +} /** * cal_attachment_new_from_mime_part: @@ -380,27 +505,44 @@ ok_cb (GtkWidget *widget, gpointer data) attachment = dialog_data->attachment; str = gtk_entry_get_text (dialog_data->file_name_entry); - camel_mime_part_set_filename (attachment->body, str); + if (attachment->is_available_local) { + camel_mime_part_set_filename (attachment->body, str); + } else { + if (attachment->file_name) + g_free (attachment->file_name); + attachment->file_name = g_strdup (str); + } str = gtk_entry_get_text (dialog_data->description_entry); - camel_mime_part_set_description (attachment->body, str); + if (attachment->is_available_local) { + camel_mime_part_set_description (attachment->body, str); + } else { + if (attachment->description) + g_free (attachment->description); + attachment->description = g_strdup (str); + } str = gtk_entry_get_text (dialog_data->mime_type_entry); - camel_mime_part_set_content_type (attachment->body, str); - - camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str); - - switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) { - case 0: - camel_mime_part_set_disposition (attachment->body, "attachment"); - break; - case 1: - camel_mime_part_set_disposition (attachment->body, "inline"); - break; - default: - /* Hmmmm? */ - break; + if (attachment->is_available_local) { + camel_mime_part_set_content_type (attachment->body, str); + camel_data_wrapper_set_mime_type(camel_medium_get_content_object(CAMEL_MEDIUM (attachment->body)), str); } + + if (attachment->is_available_local) { + switch (gtk_toggle_button_get_active (dialog_data->disposition_checkbox)) { + case 0: + camel_mime_part_set_disposition (attachment->body, "attachment"); + break; + case 1: + camel_mime_part_set_disposition (attachment->body, "inline"); + break; + default: + /* Hmmmm? */ + break; + } + } else { + attachment->disposition = gtk_toggle_button_get_active (dialog_data->disposition_checkbox); + } changed (attachment); close_cb (widget, data); @@ -461,19 +603,35 @@ cal_attachment_edit (CalAttachment *attachment, GtkWidget *parent) glade_xml_get_widget (editor_gui, "mime_type_entry")); dialog_data->disposition_checkbox = GTK_TOGGLE_BUTTON ( glade_xml_get_widget (editor_gui, "disposition_checkbox")); - - set_entry (editor_gui, "file_name_entry", - camel_mime_part_get_filename (attachment->body)); - set_entry (editor_gui, "description_entry", - camel_mime_part_get_description (attachment->body)); - content_type = camel_mime_part_get_content_type (attachment->body); - type = camel_content_type_simple (content_type); - set_entry (editor_gui, "mime_type_entry", type); - g_free (type); - - disposition = camel_mime_part_get_disposition (attachment->body); - gtk_toggle_button_set_active (dialog_data->disposition_checkbox, - disposition && !g_ascii_strcasecmp (disposition, "inline")); + + if (attachment->is_available_local) { + set_entry (editor_gui, "file_name_entry", + camel_mime_part_get_filename (attachment->body)); + set_entry (editor_gui, "description_entry", + camel_mime_part_get_description (attachment->body)); + content_type = camel_mime_part_get_content_type (attachment->body); + type = camel_content_type_simple (content_type); + set_entry (editor_gui, "mime_type_entry", type); + g_free (type); + + disposition = camel_mime_part_get_disposition (attachment->body); + gtk_toggle_button_set_active (dialog_data->disposition_checkbox, + disposition && !g_ascii_strcasecmp (disposition, "inline")); + } else { + set_entry (editor_gui, "file_name_entry", + attachment->file_name); + set_entry (editor_gui, "description_entry", + attachment->description); + type = cal_attachment_guess_mime_type (attachment->file_name); + if (type) { + set_entry (editor_gui, "mime_type_entry", type); + g_free (type); + } else { + set_entry (editor_gui, "mime_type_entry", ""); + } + gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition); + + } connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data); #warning "signal connect while alive" diff --git a/calendar/gui/dialogs/cal-attachment.h b/calendar/gui/dialogs/cal-attachment.h index 842ab2ed4d..c69e0a4173 100644 --- a/calendar/gui/dialogs/cal-attachment.h +++ b/calendar/gui/dialogs/cal-attachment.h @@ -27,6 +27,7 @@ #include <glade/glade-xml.h> #include <camel/camel-mime-part.h> #include <camel/camel-exception.h> +#include <libgnomevfs/gnome-vfs.h> #ifdef __cplusplus extern "C" { @@ -52,6 +53,13 @@ struct _CalAttachment { gulong size; GdkPixbuf *pixbuf_cache; + + GnomeVFSAsyncHandle *handle; + gboolean is_available_local; + char *file_name; + char *description; + gboolean disposition; + int index; }; struct _CalAttachmentClass { @@ -71,6 +79,8 @@ struct CalMimeAttach { GType cal_attachment_get_type (void); CalAttachment *cal_attachment_new (const char *file_name, const char *disposition, CamelException *ex); CalAttachment *cal_attachment_new_from_mime_part (CamelMimePart *part); +CalAttachment * cal_attachment_new_remote_file (const char *file_name, const char *disposition, CamelException *ex); +void cal_attachment_build_remote_file (const char *filename, CalAttachment *attachment, const char *disposition, CamelException *ex); void cal_attachment_edit (CalAttachment *attachment, GtkWidget *parent); #ifdef __cplusplus diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 49a5240b31..cba7968268 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -255,17 +255,23 @@ drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSele g_free (str); } else { url = camel_url_new (str, NULL); - g_free (str); - if (url == NULL) + if (url == NULL) { + g_free (str); continue; + } if (!g_ascii_strcasecmp (url->protocol, "file")) cal_attachment_bar_attach (CAL_ATTACHMENT_BAR (editor->priv->attachment_bar), url->path); + else + cal_attachment_bar_attach_remote_file + (CAL_ATTACHMENT_BAR (editor->priv->attachment_bar), + str); camel_url_free (url); + g_free (str); } } @@ -785,6 +791,24 @@ response_cb (GtkWidget *widget, int response, gpointer data) switch (response) { case GTK_RESPONSE_OK: + /* Check whether the downloads are completed */ + if (cal_attachment_bar_get_download_count (CAL_ATTACHMENT_BAR (editor->priv->attachment_bar)) ){ + ECalComponentVType vtype = e_cal_component_get_vtype(editor->priv->comp); + gboolean response; + + if (vtype == E_CAL_COMPONENT_EVENT) + response = em_utils_prompt_user((GtkWindow *)widget, + NULL, + "calendar:ask-send-event-pending-download", + NULL); + else + response = em_utils_prompt_user((GtkWindow *)widget, + NULL, + "calendar:ask-send-task-pending-download", + NULL); + if (!response) + return; + } commit_all_fields (editor); if (e_cal_component_is_instance (priv->comp)) |