Added the support to DnD remote URL to the attachment window. It downloads

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.

svn path=/trunk/; revision=29405
This commit is contained in:
Srinivasa Ragavan
2005-05-24 08:45:16 +00:00
committed by Srinivasa Ragavan
parent 52df90026f
commit 0822a01317
7 changed files with 433 additions and 34 deletions

View File

@ -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)

View File

@ -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>

View File

@ -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 */
@ -327,6 +340,27 @@ update (CalAttachmentBar *bar)
gnome_icon_list_thaw (icon_list);
}
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)
{
@ -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));

View File

@ -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);

View File

@ -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"));
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);
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"));
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"

View File

@ -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

View File

@ -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))