From c8938bd337a03f1d4221cabfff76add54af9aa76 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Mon, 27 Apr 2009 11:52:30 +0200 Subject: Do not delete text lines on signature set in composer ** Fix for bug #553535 * e-msg-composer.c: (is_top_signature), (get_signature_html), (set_editor_text), (e_msg_composer_show_sig_file): Do not eat lines of text when changing signature at top of the message. Add one extra empty line between the signature and the body of the mail when placing signature to the bottom. --- composer/ChangeLog | 10 +++++++ composer/e-msg-composer.c | 72 ++++++++++++++++++++++++----------------------- 2 files changed, 47 insertions(+), 35 deletions(-) (limited to 'composer') diff --git a/composer/ChangeLog b/composer/ChangeLog index 9f1f34f09e..5a38c77178 100644 --- a/composer/ChangeLog +++ b/composer/ChangeLog @@ -1,3 +1,13 @@ +2009-04-27 Milan Crha + + ** Fix for bug #553535 + + * e-msg-composer.c: (is_top_signature), (get_signature_html), + (set_editor_text), (e_msg_composer_show_sig_file): Do not eat + lines of text when changing signature at top of the message. + Add one extra empty line between the signature and the body + of the mail when placing signature to the bottom. + 2009-03-19 Milan Crha ** Fix for bug #574680 diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index b509a97ce8..d39a212e88 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -1279,7 +1279,25 @@ add_signature_delim (void) return res; } +static gboolean +is_top_signature (void) +{ + GConfClient *gconf; + gboolean res = FALSE; + + gconf = gconf_client_get_default (); + + res = gconf_client_get_bool (gconf, COMPOSER_GCONF_TOP_SIGNATURE_KEY, NULL); + + g_object_unref (gconf); + + return res; +} + #define CONVERT_SPACES CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES +#define NO_SIGNATURE_TEXT \ + "" \ + "
" static gchar * get_signature_html (EMsgComposer *composer) @@ -1353,14 +1371,15 @@ get_signature_html (EMsgComposer *composer) */ html = g_strdup_printf ("" "" - "
" + "

" "%s%s%s%s" - "
", + "%s
", encoded_uid ? encoded_uid : "", format_html ? "" : "
\n",
 					format_html || !add_delim || (!strncmp ("-- \n", text, 4) || strstr (text, "\n-- \n")) ? "" : "-- \n",
 					text,
-					format_html ? "" : "
\n"); + format_html ? "" : "\n", + is_top_signature () ? "
" : ""); g_free (text); g_free (encoded_uid); text = html; @@ -1374,15 +1393,11 @@ set_editor_text (EMsgComposer *composer, const gchar *text, gboolean set_signature) { - gboolean reply_signature_on_top; - gchar *body = NULL, *html = NULL; - GConfClient *gconf; + gchar *body = NULL; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); g_return_if_fail (text != NULL); - gconf = gconf_client_get_default (); - /* Keeping Signatures in the beginning of composer @@ -1397,38 +1412,17 @@ set_editor_text (EMsgComposer *composer, */ - reply_signature_on_top = gconf_client_get_bool (gconf, COMPOSER_GCONF_TOP_SIGNATURE_KEY, NULL); - - g_object_unref (gconf); - - if (set_signature && reply_signature_on_top) { - gchar *tmp = NULL; - tmp = get_signature_html (composer); - if (tmp) { - /* Minimizing the damage. Make it just a part of the body instead of a signature */ - html = add_signature_delim () ? strstr (tmp, "-- \n") : NULL; - if (html) { - /* That two consecutive - symbols followed by a space */ - *(html+1) = ' '; - body = g_strdup_printf ("
%s
%s", tmp, text); - } else { - /* HTML Signature. Make it as part of body */ - body = g_strdup_printf ("
%s
%s", tmp, text); - } - g_free (tmp); - } else { - /* No signature set */ - body = g_strdup_printf ("" - "" - "
%s", text); - } + if (is_top_signature ()) { + /* put marker to the top */ + body = g_strdup_printf ("
" NO_SIGNATURE_TEXT "%s", text); } else { - body = g_strdup (text); + /* no marker => to the bottom */ + body = g_strdup_printf ("%s
", text); } gtkhtml_editor_set_text_html (GTKHTML_EDITOR (composer), body, -1); - if (set_signature && !reply_signature_on_top) + if (set_signature) e_msg_composer_show_sig_file (composer); } @@ -4504,6 +4498,7 @@ e_msg_composer_show_sig_file (EMsgComposer *composer) GtkhtmlEditor *editor; GtkHTML *html; gchar *html_text; + gboolean top_signature; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); @@ -4530,6 +4525,8 @@ e_msg_composer_show_sig_file (EMsgComposer *composer) } gtkhtml_editor_run_command (editor, "unblock-selection"); + top_signature = is_top_signature (); + html_text = get_signature_html (composer); if (html_text) { gtkhtml_editor_run_command (editor, "insert-paragraph"); @@ -4537,11 +4534,16 @@ e_msg_composer_show_sig_file (EMsgComposer *composer) gtkhtml_editor_run_command (editor, "insert-paragraph"); else gtkhtml_editor_run_command (editor, "cursor-forward"); + gtkhtml_editor_set_paragraph_data (editor, "orig", "0"); gtkhtml_editor_run_command (editor, "indent-zero"); gtkhtml_editor_run_command (editor, "style-normal"); gtkhtml_editor_insert_html (editor, html_text); g_free (html_text); + } else if (top_signature) { + /* insert paragraph after the signature ClueFlow things */ + gtkhtml_editor_run_command (editor, "cursor-forward"); + gtkhtml_editor_run_command (editor, "insert-paragraph"); } gtkhtml_editor_undo_end (editor); -- cgit v1.2.3 From 4449a34101406bffe508dd40b8b653f7c7d14c7d Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 27 Apr 2009 15:36:19 -0400 Subject: Commit the rest of the attachment UI rewrite Oops, last commit only included the -new- files. This also removes EExpander, which is no longer used. --- a11y/e-table/Makefile.am | 5 +- a11y/widgets/Makefile.am | 2 - a11y/widgets/ea-expander.c | 165 -- a11y/widgets/ea-expander.h | 51 - a11y/widgets/ea-widgets.c | 7 - a11y/widgets/ea-widgets.h | 1 - calendar/gui/Makefile.am | 2 + calendar/gui/calendar-component.c | 4 + calendar/gui/dialogs/comp-editor.c | 1229 ++------ calendar/gui/dialogs/event-editor.c | 2 - calendar/gui/e-cal-popup.c | 417 --- calendar/gui/e-cal-popup.h | 2 - composer/e-composer-actions.c | 66 +- composer/e-composer-private.c | 87 +- composer/e-composer-private.h | 12 +- composer/e-msg-composer.c | 697 ++--- composer/e-msg-composer.h | 12 +- configure.in | 6 +- e-util/e-util.c | 207 ++ e-util/e-util.h | 16 + mail/Makefile.am | 4 + mail/em-filter-i18n.h | 2 + mail/em-format-html-display.c | 615 +--- mail/em-format-html-display.h | 2 - mail/em-popup.c | 123 +- mail/em-popup.h | 35 +- mail/mail-component.c | 5 + plugins/attachment-reminder/attachment-reminder.c | 13 +- plugins/import-ics-attachments/ChangeLog | 109 - plugins/import-ics-attachments/Makefile.am | 35 - plugins/import-ics-attachments/icsimporter.c | 435 --- ...evolution-mail-attachments-import-ics.eplug.xml | 26 - plugins/save-attachments/ChangeLog | 102 - plugins/save-attachments/Makefile.am | 31 - .../org-gnome-save-attachments.eplug.xml | 26 - .../org-gnome-save-attachments.xml | 20 - plugins/save-attachments/save-attachments.c | 392 --- shell/apps_evolution_shell.schemas.in | 30 +- widgets/misc/Makefile.am | 22 +- widgets/misc/e-attachment-bar.c | 1504 ---------- widgets/misc/e-attachment-bar.h | 105 - widgets/misc/e-attachment.c | 3125 +++++++++++++++----- widgets/misc/e-attachment.h | 186 +- widgets/misc/e-expander.c | 1341 --------- widgets/misc/e-expander.h | 82 - widgets/text/Makefile.am | 2 + 46 files changed, 3482 insertions(+), 7880 deletions(-) delete mode 100644 a11y/widgets/ea-expander.c delete mode 100644 a11y/widgets/ea-expander.h delete mode 100644 plugins/import-ics-attachments/ChangeLog delete mode 100644 plugins/import-ics-attachments/Makefile.am delete mode 100644 plugins/import-ics-attachments/icsimporter.c delete mode 100644 plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml delete mode 100644 plugins/save-attachments/ChangeLog delete mode 100644 plugins/save-attachments/Makefile.am delete mode 100644 plugins/save-attachments/org-gnome-save-attachments.eplug.xml delete mode 100644 plugins/save-attachments/org-gnome-save-attachments.xml delete mode 100644 plugins/save-attachments/save-attachments.c delete mode 100644 widgets/misc/e-attachment-bar.c delete mode 100644 widgets/misc/e-attachment-bar.h delete mode 100644 widgets/misc/e-expander.c delete mode 100644 widgets/misc/e-expander.h (limited to 'composer') diff --git a/a11y/e-table/Makefile.am b/a11y/e-table/Makefile.am index 1884c3a1c5..f344d7b8c3 100644 --- a/a11y/e-table/Makefile.am +++ b/a11y/e-table/Makefile.am @@ -1,6 +1,7 @@ INCLUDES = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/widgets \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + $(E_UTIL_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) \ -DG_LOG_DOMAIN=\"e-table\" diff --git a/a11y/widgets/Makefile.am b/a11y/widgets/Makefile.am index e157f82188..6fb8c80048 100644 --- a/a11y/widgets/Makefile.am +++ b/a11y/widgets/Makefile.am @@ -22,8 +22,6 @@ libevolution_widgets_a11y_la_SOURCES = \ ea-calendar-cell.h \ ea-combo-button.c \ ea-combo-button.h \ - ea-expander.c \ - ea-expander.h \ ea-widgets.c \ ea-widgets.h diff --git a/a11y/widgets/ea-expander.c b/a11y/widgets/ea-expander.c deleted file mode 100644 index ae9da5fb61..0000000000 --- a/a11y/widgets/ea-expander.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Boby Wang - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include -#include "ea-expander.h" -#include - -static AtkObjectClass *parent_class; -static GType parent_type; - -/* Action IDs */ -enum { - ACTIVATE, - LAST_ACTION -}; - -static G_CONST_RETURN gchar* -ea_expander_get_name (AtkObject *a11y) -{ - return _("Toggle Attachment Bar"); -} - -/* Action interface */ -static G_CONST_RETURN gchar * -ea_expander_action_get_name (AtkAction *action, gint i) -{ - switch (i) - { - case ACTIVATE: - return _("activate"); - default: - return NULL; - } -} - -static gboolean -ea_expander_do_action (AtkAction *action, gint i) -{ - GtkWidget *widget; - EExpander *expander; - - widget = GTK_ACCESSIBLE (action)->widget; - if (!widget || !GTK_WIDGET_IS_SENSITIVE (widget) || !GTK_WIDGET_VISIBLE (widget)) - return FALSE; - - expander = E_EXPANDER (widget); - - switch (i) - { - case ACTIVATE: - g_signal_emit_by_name (expander, "activate"); - return TRUE; - default: - return FALSE; - } -} - -static gint -ea_expander_get_n_actions (AtkAction *action) -{ - return LAST_ACTION; -} - -static void -atk_action_interface_init (AtkActionIface *iface) -{ - g_return_if_fail (iface != NULL); - - iface->do_action = ea_expander_do_action; - iface->get_n_actions = ea_expander_get_n_actions; - iface->get_name = ea_expander_action_get_name; -} - -static void -ea_expander_class_init (EaExpanderClass *klass) -{ - AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (klass); - - parent_class = g_type_class_ref (parent_type); - - atk_object_class->get_name = ea_expander_get_name; -} - -static void -ea_expander_init (EaExpander *a11y) -{ - /* Empty */ -} - -GType -ea_expander_get_type (void) -{ - static GType type = 0; - - if (!type) { - AtkObjectFactory *factory; - GTypeQuery query; - - GTypeInfo info = { - sizeof (EaExpanderClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) ea_expander_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class data */ - sizeof (EaExpander), - 0, - (GInstanceInitFunc) ea_expander_init, - NULL /* value_tree */ - }; - - static const GInterfaceInfo atk_action_info = { - (GInterfaceInitFunc) atk_action_interface_init, - (GInterfaceFinalizeFunc) NULL, - NULL - }; - - factory = atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_BIN); - parent_type = atk_object_factory_get_accessible_type (factory); - g_type_query (parent_type, &query); - - info.class_size = query.class_size; - info.instance_size = query.instance_size; - - type = g_type_register_static (parent_type, "EaExpander", &info, 0); - g_type_add_interface_static (type, ATK_TYPE_ACTION, - &atk_action_info); - } - - return type; -} - -AtkObject * -ea_expander_new (GtkWidget *widget) -{ - EaExpander *a11y; - - a11y = g_object_new (ea_expander_get_type (), NULL); - - GTK_ACCESSIBLE (a11y)->widget = GTK_WIDGET (widget); - ATK_OBJECT (a11y)->role = ATK_ROLE_TOGGLE_BUTTON; - - return ATK_OBJECT (a11y); -} - diff --git a/a11y/widgets/ea-expander.h b/a11y/widgets/ea-expander.h deleted file mode 100644 index e670ad07be..0000000000 --- a/a11y/widgets/ea-expander.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Boby Wang - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _EA_EXPANDER_H_ -#define _EA_EXPANDER_H_ - -#include -#include - -#define EA_TYPE_EXPANDER (ea_expander_get_type ()) -#define EA_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EA_TYPE_EXPANDER, EaExpander)) -#define EA_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass,), EA_TYPE_EXPANDER, EaExpanderClass)) -#define EA_IS_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EA_TYPE_EXPANDER)) -#define EA_IS_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EA_TYPE_EXPANDER_CLASS)) - -typedef struct _EaExpander EaExpander; -typedef struct _EaExpanderClass EaExpanderClass; - -struct _EaExpander { - GtkAccessible object; -}; - -struct _EaExpanderClass { - GtkAccessibleClass parent_class; -}; - -/* Standard Glib function */ -GType ea_expander_get_type (void); -AtkObject* ea_expander_new (GtkWidget *expander); - -#endif /* ! _EA_EXPANDER_H_ */ diff --git a/a11y/widgets/ea-widgets.c b/a11y/widgets/ea-widgets.c index 66c1668baf..5befb44837 100644 --- a/a11y/widgets/ea-widgets.c +++ b/a11y/widgets/ea-widgets.c @@ -23,12 +23,10 @@ #include "ea-factory.h" #include "widgets/ea-calendar-item.h" #include "widgets/ea-combo-button.h" -#include "widgets/ea-expander.h" #include "ea-widgets.h" EA_FACTORY_GOBJECT (EA_TYPE_CALENDAR_ITEM, ea_calendar_item, ea_calendar_item_new) EA_FACTORY (EA_TYPE_COMBO_BUTTON, ea_combo_button, ea_combo_button_new) -EA_FACTORY (EA_TYPE_EXPANDER, ea_expander, ea_expander_new) void e_calendar_item_a11y_init (void) { @@ -39,8 +37,3 @@ void e_combo_button_a11y_init (void) { EA_SET_FACTORY (e_combo_button_get_type (), ea_combo_button); } - -void e_expander_a11y_init (void) -{ - EA_SET_FACTORY (e_expander_get_type (), ea_expander); -} diff --git a/a11y/widgets/ea-widgets.h b/a11y/widgets/ea-widgets.h index f4aff74655..20c1c9698d 100644 --- a/a11y/widgets/ea-widgets.h +++ b/a11y/widgets/ea-widgets.h @@ -29,6 +29,5 @@ void e_calendar_item_a11y_init (void); void e_combo_button_a11y_init (void); -void e_expander_a11y_init (void); #endif /* _EA_WIDGETS_H__ */ diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index e61f6a1f91..b5dab7aeac 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -69,6 +69,8 @@ etspec_DATA = \ libevolution_calendar_la_SOURCES = \ $(IDL_GENERATED) \ + e-attachment-handler-calendar.c \ + e-attachment-handler-calendar.h \ cal-search-bar.c \ cal-search-bar.h \ calendar-config.c \ diff --git a/calendar/gui/calendar-component.c b/calendar/gui/calendar-component.c index 942960bff5..4d30929272 100644 --- a/calendar/gui/calendar-component.c +++ b/calendar/gui/calendar-component.c @@ -58,6 +58,7 @@ #include "e-util/e-error.h" #include "e-cal-menu.h" #include "e-cal-popup.h" +#include "e-attachment-handler-calendar.h" /* IDs for user creatable items */ #define CREATE_EVENT_ID "event" @@ -1576,6 +1577,9 @@ calendar_component_class_init (CalendarComponentClass *class) object_class->dispose = impl_dispose; object_class->finalize = impl_finalize; + + /* Register attachment handler types. */ + e_attachment_handler_calendar_get_type (); } static void diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index f3034359c6..6456a5ce04 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -63,9 +63,9 @@ #include "../e-cal-popup.h" #include "../calendar-config-keys.h" #include "cal-attachment-select-file.h" +#include "widgets/misc/e-attachment-view.h" +#include "widgets/misc/e-attachment-paned.h" -#include "e-attachment-bar.h" -#include "misc/e-expander.h" #include "e-util/e-error.h" #define COMP_EDITOR_GET_PRIVATE(obj) \ @@ -95,12 +95,7 @@ struct _CompEditorPrivate { GtkNotebook *notebook; /* Attachment handling */ - GtkWidget *attachment_bar; - GtkWidget *attachment_scrolled_window; - GtkWidget *attachment_expander; - GtkWidget *attachment_expander_label; - GtkWidget *attachment_expander_icon; - GtkWidget *attachment_expander_num; + GtkWidget *attachment_view; /* Manages menus and toolbars */ GtkUIManager *manager; @@ -151,7 +146,7 @@ static const gchar *ui = " " " " " " -" " +" " " " " " " " @@ -163,13 +158,10 @@ static const gchar *ui = " " " " " " -" " -" " " " ""; static void comp_editor_show_help (CompEditor *editor); -static void setup_widgets (CompEditor *editor); static void real_edit_comp (CompEditor *editor, ECalComponent *comp); static gboolean real_send_comp (CompEditor *editor, ECalComponentItipMethod method, gboolean strip_alarms); @@ -180,43 +172,9 @@ static void page_dates_changed_cb (CompEditor *editor, CompEditorPageDates *date static void obj_modified_cb (ECal *client, GList *objs, gpointer data); static void obj_removed_cb (ECal *client, GList *uids, gpointer data); -static gboolean open_attachment (EAttachmentBar *bar, CompEditor *editor); G_DEFINE_TYPE (CompEditor, comp_editor, GTK_TYPE_WINDOW) -enum { - DND_TYPE_MESSAGE_RFC822, - DND_TYPE_X_UID_LIST, - DND_TYPE_TEXT_URI_LIST, - DND_TYPE_NETSCAPE_URL, - DND_TYPE_TEXT_VCARD, - DND_TYPE_TEXT_CALENDAR, -}; - -static GtkTargetEntry drop_types[] = { - { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 }, - { "x-uid-list", 0, DND_TYPE_X_UID_LIST }, - { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST }, - { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL }, - { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD }, - { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR }, -}; - -#define num_drop_types (sizeof (drop_types) / sizeof (drop_types[0])) - -static struct { - char *target; - GdkAtom atom; - guint32 actions; -} drag_info[] = { - { "message/rfc822", NULL, GDK_ACTION_COPY }, - { "x-uid-list", NULL, GDK_ACTION_ASK|GDK_ACTION_MOVE|GDK_ACTION_COPY }, - { "text/uri-list", NULL, GDK_ACTION_COPY }, - { "_NETSCAPE_URL", NULL, GDK_ACTION_COPY }, - { "text/x-vcard", NULL, GDK_ACTION_COPY }, - { "text/calendar", NULL, GDK_ACTION_COPY }, -}; - enum { OBJECT_CREATED, LAST_SIGNAL @@ -224,397 +182,53 @@ enum { static guint comp_editor_signals[LAST_SIGNAL] = { 0 }; -static void -attach_message(CompEditor *editor, CamelMimeMessage *msg) -{ - CamelMimePart *mime_part; - const char *subject; - guint i; - char *filename = NULL; - - mime_part = camel_mime_part_new(); - camel_mime_part_set_disposition(mime_part, "inline"); - subject = camel_mime_message_get_subject(msg); - if (subject) { - char *desc = g_strdup_printf(_("Attached message - %s"), subject); - - camel_mime_part_set_description(mime_part, desc); - g_free(desc); - } else - camel_mime_part_set_description(mime_part, _("Attached message")); - - i = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar)); - i++; - filename = g_strdup_printf ("email%d",i); - camel_mime_part_set_filename (mime_part, filename); - - camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg); - camel_mime_part_set_content_type(mime_part, "message/rfc822"); - e_attachment_bar_attach_mime_part(E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part); - camel_object_unref(mime_part); - g_free (filename); -} - -struct _drop_data { - CompEditor *editor; - - GdkDragContext *context; - /* Only selection->data and selection->length are valid */ - GtkSelectionData *selection; - - guint32 action; - guint info; - guint time; - - unsigned int move:1; - unsigned int moved:1; - unsigned int aborted:1; -}; - -static void -drop_action(CompEditor *editor, GdkDragContext *context, guint32 action, GtkSelectionData *selection, guint info, guint time) -{ - char *tmp, *str, **urls; - CamelMimePart *mime_part; - CamelStream *stream; - CamelURL *url; - CamelMimeMessage *msg; - char *content_type; - int i, success=FALSE, delete=FALSE; - - switch (info) { - case DND_TYPE_MESSAGE_RFC822: - d(printf ("dropping a message/rfc822\n")); - /* write the message(s) out to a CamelStream so we can use it */ - stream = camel_stream_mem_new (); - camel_stream_write (stream, (char *)selection->data, selection->length); - camel_stream_reset (stream); - - msg = camel_mime_message_new (); - if (camel_data_wrapper_construct_from_stream((CamelDataWrapper *)msg, stream) != -1) { - attach_message(editor, msg); - success = TRUE; - delete = action == GDK_ACTION_MOVE; - } - - camel_object_unref(msg); - camel_object_unref(stream); - break; - case DND_TYPE_TEXT_URI_LIST: - case DND_TYPE_NETSCAPE_URL: - d(printf ("dropping a text/uri-list\n")); - tmp = g_strndup ((char *)selection->data, selection->length); - urls = g_strsplit (tmp, "\n", 0); - g_free (tmp); - - for (i = 0; urls[i] != NULL; i++) { - str = g_strstrip (urls[i]); - if (urls[i][0] == '#') - continue; - - if (!g_ascii_strncasecmp (str, "mailto:", 7)) { - /* TODO does not handle mailto now */ - } else { - url = camel_url_new (str, NULL); - - if (url == NULL) - continue; - - if (!g_ascii_strcasecmp (url->protocol, "file")) - e_attachment_bar_attach - (E_ATTACHMENT_BAR (editor->priv->attachment_bar), - url->path, - "attachment"); - else - e_attachment_bar_attach_remote_file - (E_ATTACHMENT_BAR (editor->priv->attachment_bar), - str, "attachment"); - - camel_url_free (url); - } - } - - g_strfreev (urls); - success = TRUE; - break; - case DND_TYPE_TEXT_VCARD: - case DND_TYPE_TEXT_CALENDAR: - content_type = gdk_atom_name (selection->type); - d(printf ("dropping a %s\n", content_type)); - - mime_part = camel_mime_part_new (); - camel_mime_part_set_content (mime_part, (char *)selection->data, selection->length, content_type); - camel_mime_part_set_disposition (mime_part, "inline"); - - e_attachment_bar_attach_mime_part - (E_ATTACHMENT_BAR (editor->priv->attachment_bar), - mime_part); - - camel_object_unref (mime_part); - g_free (content_type); - - success = TRUE; - break; - case DND_TYPE_X_UID_LIST: { - GPtrArray *uids; - char *inptr, *inend; - CamelFolder *folder; - CamelException ex = CAMEL_EXCEPTION_INITIALISER; - - /* NB: This all runs synchronously, could be very slow/hang/block the ui */ - - uids = g_ptr_array_new(); - - inptr = (char *)selection->data; - inend = (char *)(selection->data + selection->length); - while (inptr < inend) { - char *start = inptr; - - while (inptr < inend && *inptr) - inptr++; - - if (start > (char *)selection->data) - g_ptr_array_add(uids, g_strndup(start, inptr-start)); - - inptr++; - } - - if (uids->len > 0) { - folder = mail_tool_uri_to_folder((char *)selection->data, 0, &ex); - if (folder) { - if (uids->len == 1) { - msg = camel_folder_get_message(folder, uids->pdata[0], &ex); - if (msg == NULL) - goto fail; - attach_message(editor, msg); - } else { - CamelMultipart *mp = camel_multipart_new(); - char *desc; - char *filename = NULL; - guint num; - - camel_data_wrapper_set_mime_type((CamelDataWrapper *)mp, "multipart/digest"); - camel_multipart_set_boundary(mp, NULL); - for (i=0;ilen;i++) { - - msg = camel_folder_get_message(folder, uids->pdata[i], &ex); - if (msg) { - mime_part = camel_mime_part_new(); - camel_mime_part_set_disposition(mime_part, "inline"); - camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)msg); - camel_mime_part_set_content_type(mime_part, "message/rfc822"); - camel_multipart_add_part(mp, mime_part); - camel_object_unref(mime_part); - camel_object_unref(msg); - } else { - camel_object_unref(mp); - goto fail; - } - } - mime_part = camel_mime_part_new(); - camel_medium_set_content_object((CamelMedium *)mime_part, (CamelDataWrapper *)mp); - /* translators, this count will always be >1 */ - desc = g_strdup_printf(ngettext("Attached message", "%d attached messages", uids->len), uids->len); - camel_mime_part_set_description(mime_part, desc); - g_free(desc); - - num = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar)); - num++; - filename = g_strdup_printf ("email%d", num); - camel_mime_part_set_filename (mime_part, filename); - - e_attachment_bar_attach_mime_part - (E_ATTACHMENT_BAR(editor->priv->attachment_bar), mime_part); - camel_object_unref(mime_part); - camel_object_unref(mp); - g_free (filename); - } - success = TRUE; - delete = action == GDK_ACTION_MOVE; - fail: - if (camel_exception_is_set(&ex)) { - char *name; - - camel_object_get(folder, NULL, CAMEL_FOLDER_NAME, &name, NULL); - e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages", - name?name:(char *)selection->data, camel_exception_get_description(&ex), NULL); - camel_object_free(folder, CAMEL_FOLDER_NAME, name); - } - camel_object_unref(folder); - } else { - e_error_run((GtkWindow *)editor, "mail-editor:attach-nomessages", - (char *)selection->data, camel_exception_get_description(&ex), NULL); - } - - camel_exception_clear(&ex); - } - - g_ptr_array_free(uids, TRUE); - - break; } - default: - d(printf ("dropping an unknown\n")); - break; - } - - printf("Drag finished, success %d delete %d\n", success, delete); - - gtk_drag_finish(context, success, delete, time); -} - -static void -drop_popup_copy (EPopup *ep, EPopupItem *item, void *data) -{ - struct _drop_data *m = data; - drop_action(m->editor, m->context, GDK_ACTION_COPY, m->selection, m->info, m->time); -} - -static void -drop_popup_move (EPopup *ep, EPopupItem *item, void *data) -{ - struct _drop_data *m = data; - drop_action(m->editor, m->context, GDK_ACTION_MOVE, m->selection, m->info, m->time); -} - -static void -drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data) -{ - struct _drop_data *m = data; - gtk_drag_finish(m->context, FALSE, FALSE, m->time); -} - -static EPopupItem drop_popup_menu[] = { - { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 }, - { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 }, - { E_POPUP_BAR, "10.emc" }, - { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 }, -}; - -static void -drop_popup_free(EPopup *ep, GSList *items, void *data) -{ - struct _drop_data *m = data; - - g_slist_free(items); - - g_object_unref(m->context); - g_object_unref(m->editor); - g_free(m->selection->data); - g_free(m->selection); - g_free(m); -} - -static void -drag_data_received (CompEditor *editor, GdkDragContext *context, - int x, int y, GtkSelectionData *selection, - guint info, guint time) -{ - if (selection->data == NULL || selection->length == -1) - return; - - if (context->action == GDK_ACTION_ASK) { - ECalPopup *ecp; - GSList *menus = NULL; - GtkMenu *menu; - int i; - struct _drop_data *m; - - m = g_malloc0(sizeof(*m)); - m->context = context; - g_object_ref(context); - m->editor = editor; - g_object_ref(editor); - m->action = context->action; - m->info = info; - m->time = time; - m->selection = g_malloc0(sizeof(*m->selection)); - m->selection->data = g_malloc(selection->length); - memcpy(m->selection->data, selection->data, selection->length); - m->selection->length = selection->length; - - ecp = e_cal_popup_new("org.gnome.evolution.calendar.editor.popup.drop"); - for (i=0;iaction, selection, info, time); - } -} - -static gboolean -drag_motion(GObject *o, GdkDragContext *context, gint x, gint y, guint time, CompEditor *editor) -{ - GList *targets; - GdkDragAction action, actions = 0; - - for (targets = context->targets; targets; targets = targets->next) { - int i; - - for (i=0;idata == (void *)drag_info[i].atom) - actions |= drag_info[i].actions; - } - - actions &= context->actions; - action = context->suggested_action; - /* we default to copy */ - if (action == GDK_ACTION_ASK && (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != (GDK_ACTION_MOVE|GDK_ACTION_COPY)) - action = GDK_ACTION_COPY; - - gdk_drag_status(context, action, time); - - return action != 0; -} - -static void -add_to_bar (CompEditor *editor, GPtrArray *file_list, int is_inline) -{ - CompEditorPrivate *priv = editor->priv; - int i; - - for (i = 0; i < file_list->len; i++) { - CamelURL *url; - - if (!(url = camel_url_new (file_list->pdata[i], NULL))) - continue; - - if (!g_ascii_strcasecmp (url->protocol, "file")) { - e_attachment_bar_attach((EAttachmentBar *)priv->attachment_bar, url->path, is_inline ? "inline" : "attachment"); - } else { - e_attachment_bar_attach_remote_file ((EAttachmentBar *)priv->attachment_bar, file_list->pdata[i], is_inline ? "inline" : "attachment"); - } - - camel_url_free (url); - } -} - static GSList * get_attachment_list (CompEditor *editor) { - GSList *parts = NULL, *list = NULL, *p = NULL; + EAttachmentStore *store; + EAttachmentView *view; + GtkTreeModel *model; + GtkTreeIter iter; + GSList *parts = NULL, *list = NULL; const char *comp_uid = NULL; const char *local_store = e_cal_get_local_attachment_store (editor->priv->client); + gboolean valid; int ticker=0; + e_cal_component_get_uid (editor->priv->comp, &comp_uid); - parts = e_attachment_bar_get_parts((EAttachmentBar *)editor->priv->attachment_bar); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + store = e_attachment_view_get_store (view); - for (p = parts; p!=NULL ; p = p->next) { + model = GTK_TREE_MODEL (store); + valid = gtk_tree_model_get_iter_first (model, &iter); + + while (valid) { + EAttachment *attachment; CamelDataWrapper *wrapper; + CamelMimePart *mime_part; CamelStream *stream; char *attach_file_url; char *safe_fname, *utf8_safe_fname; char *filename; + gint column_id; + + column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT; + gtk_tree_model_get (model, &iter, column_id, &attachment, -1); + mime_part = e_attachment_get_mime_part (attachment); + g_object_unref (attachment); + + valid = gtk_tree_model_iter_next (model, &iter); - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (p->data)); + if (mime_part == NULL) + continue; + + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); /* Extract the content from the stream and write it down * as a mime part file into the directory denoting the * calendar source */ - utf8_safe_fname = camel_file_util_safe_filename (camel_mime_part_get_filename ((CamelMimePart *) p->data)); + utf8_safe_fname = camel_file_util_safe_filename (camel_mime_part_get_filename (mime_part)); /* It is absolutely fine to get a NULL from the filename of * mime part. We assume that it is named "Attachment" @@ -993,20 +607,21 @@ static void action_attach_cb (GtkAction *action, CompEditor *editor) { - GPtrArray *file_list; - gboolean is_inline = FALSE; - int i; - - file_list = comp_editor_select_file_attachments (editor, &is_inline); + EAttachmentStore *store; + EAttachmentView *view; - if (file_list) { - add_to_bar (editor, file_list, is_inline); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + store = e_attachment_view_get_store (view); - for (i = 0; i < file_list->len; i++) - g_free (file_list->pdata[i]); + e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor)); +} - g_ptr_array_free (file_list, TRUE); - } +static void +action_classification_cb (GtkRadioAction *action, + GtkRadioAction *current, + CompEditor *editor) +{ + comp_editor_set_changed (editor, TRUE); } static void @@ -1132,12 +747,17 @@ action_save_cb (GtkAction *action, CompEditor *editor) { CompEditorPrivate *priv = editor->priv; + EAttachmentStore *store; + EAttachmentView *view; ECalComponentText text; gboolean delegated = FALSE; gboolean read_only, correct = FALSE; ECalComponent *comp; - if (e_attachment_bar_get_download_count (E_ATTACHMENT_BAR (editor->priv->attachment_bar)) ){ + view = E_ATTACHMENT_VIEW (priv->attachment_view); + store = e_attachment_view_get_store (view); + + if (e_attachment_store_get_num_loading (store) > 0) { gboolean response = 1; /*FIXME: Cannot use mail functions from calendar!!!! */ #if 0 @@ -1519,6 +1139,40 @@ static GtkToggleActionEntry coordinated_toggle_entries[] = { FALSE } }; +static void +comp_editor_setup_recent_menu (CompEditor *editor) +{ + EAttachmentView *view; + GtkUIManager *ui_manager; + GtkAction *action; + GtkActionGroup *action_group; + const gchar *action_name; + const gchar *path; + guint merge_id; + + ui_manager = editor->priv->manager; + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + action_group = comp_editor_get_action_group (editor, "individual"); + merge_id = gtk_ui_manager_new_merge_id (ui_manager); + path = "/main-menu/insert-menu/recent-placeholder"; + action_name = "recent-menu"; + + action = e_attachment_view_recent_action_new ( + view, action_name, _("Recent _Documents")); + + if (action != NULL) { + gtk_action_group_add_action (action_group, action); + g_object_unref (action); + + gtk_ui_manager_add_ui ( + ui_manager, merge_id, path, + action_name, action_name, + GTK_UI_MANAGER_AUTO, FALSE); + } + + gtk_ui_manager_ensure_update (ui_manager); +} + static void comp_editor_set_property (GObject *object, guint property_id, @@ -1695,15 +1349,89 @@ comp_editor_map (GtkWidget *widget) GTK_WIDGET_CLASS (comp_editor_parent_class)->map (widget); } +static gboolean +comp_editor_delete_event (GtkWidget *widget, + GdkEventAny *event) +{ + CompEditor *editor; + + editor = COMP_EDITOR (widget); + + commit_all_fields (editor); + + if (prompt_and_save_changes (editor, TRUE)) + close_dialog (editor); + + return TRUE; +} + +static gboolean +comp_editor_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + CompEditor *editor; + + editor = COMP_EDITOR (widget); + + if (event->keyval == GDK_Escape) { + commit_all_fields (editor); + + if (prompt_and_save_changes (editor, TRUE)) + close_dialog (editor); + + return TRUE; + } + + /* Chain up to parent's key_press_event() method. */ + return GTK_WIDGET_CLASS (comp_editor_parent_class)-> + key_press_event (widget, event); +} + +static gboolean +comp_editor_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + CompEditorPrivate *priv; + EAttachmentView *view; + + priv = COMP_EDITOR_GET_PRIVATE (widget); + view = E_ATTACHMENT_VIEW (priv->attachment_view); + + return e_attachment_view_drag_motion (view, context, x, y, time); +} + +static void +comp_editor_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection, + guint info, + guint time) +{ + CompEditorPrivate *priv; + EAttachmentView *view; + + priv = COMP_EDITOR_GET_PRIVATE (widget); + view = E_ATTACHMENT_VIEW (priv->attachment_view); + + /* Forward the data to the attachment view. Note that calling + * e_attachment_view_drag_data_received() will not work because + * that function only handles the case where all the other drag + * handlers have failed. */ + e_attachment_paned_drag_data_received ( + E_ATTACHMENT_PANED (view), + context, x, y, selection, info, time); +} + static void comp_editor_class_init (CompEditorClass *class) { GObjectClass *object_class; GtkWidgetClass *widget_class; - int i; - - for (i = 0; i < G_N_ELEMENTS (drag_info); i++) - drag_info[i].atom = gdk_atom_intern(drag_info[i].target, FALSE); g_type_class_add_private (class, sizeof (CompEditorPrivate)); @@ -1715,6 +1443,10 @@ comp_editor_class_init (CompEditorClass *class) widget_class = GTK_WIDGET_CLASS (class); widget_class->map = comp_editor_map; + widget_class->delete_event = comp_editor_delete_event; + widget_class->key_press_event = comp_editor_key_press_event; + widget_class->drag_motion = comp_editor_drag_motion; + widget_class->drag_data_received = comp_editor_drag_data_received; class->help_section = "usage-calendar"; class->edit_comp = real_edit_comp; @@ -1776,20 +1508,19 @@ comp_editor_class_init (CompEditorClass *class) G_TYPE_NONE, 0); } -static void -classification_changed_cb (GtkRadioAction *action, GtkRadioAction *current, CompEditor *editor) -{ - g_return_if_fail (IS_COMP_EDITOR (editor)); - - comp_editor_set_changed (editor, TRUE); -} - static void comp_editor_init (CompEditor *editor) { CompEditorPrivate *priv; + EAttachmentView *view; + GdkDragAction drag_actions; + GtkTargetList *target_list; + GtkTargetEntry *targets; GtkActionGroup *action_group; GtkAction *action; + GtkWidget *container; + GtkWidget *widget; + gint n_targets; GError *error = NULL; editor->priv = priv = COMP_EDITOR_GET_PRIVATE (editor); @@ -1798,17 +1529,18 @@ comp_editor_init (CompEditor *editor) priv->changed = FALSE; priv->needs_send = FALSE; priv->mod = CALOBJ_MOD_ALL; - priv->existing_org = FALSE; - priv->user_org = FALSE; - priv->warned = FALSE; + priv->existing_org = FALSE; + priv->user_org = FALSE; + priv->warned = FALSE; priv->is_group_item = FALSE; - priv->attachment_bar = e_attachment_bar_new (NULL); priv->manager = gtk_ui_manager_new (); - gtk_window_add_accel_group ( - GTK_WINDOW (editor), - gtk_ui_manager_get_accel_group (priv->manager)); + gtk_window_add_accel_group ( + GTK_WINDOW (editor), + gtk_ui_manager_get_accel_group (priv->manager)); + + /* Setup Action Groups */ action_group = gtk_action_group_new ("core"); gtk_action_group_set_translation_domain ( @@ -1833,11 +1565,7 @@ comp_editor_init (CompEditor *editor) action_group, classification_radio_entries, G_N_ELEMENTS (classification_radio_entries), E_CAL_COMPONENT_CLASS_PUBLIC, - G_CALLBACK (classification_changed_cb), editor); - action = e_attachment_bar_recent_action_new ( - E_ATTACHMENT_BAR (priv->attachment_bar), - "attach-recent", _("Recent _Documents")); - gtk_action_group_add_action (action_group, action); + G_CALLBACK (action_classification_cb), editor); gtk_ui_manager_insert_action_group ( priv->manager, action_group, 0); g_object_unref (action_group); @@ -1867,14 +1595,57 @@ comp_editor_init (CompEditor *editor) g_error_free (error); } - setup_widgets (editor); + /* Setup Widgets */ + + container = GTK_WIDGET (editor); + + widget = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = comp_editor_get_managed_widget (editor, "/main-menu"); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = comp_editor_get_managed_widget (editor, "/main-toolbar"); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + widget = e_attachment_paned_new (); + gtk_container_set_border_width (GTK_CONTAINER (widget), 6); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + priv->attachment_view = g_object_ref (widget); + gtk_widget_show (widget); + + container = e_attachment_paned_get_content_area ( + E_ATTACHMENT_PANED (priv->attachment_view)); + + widget = gtk_notebook_new (); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + priv->notebook = GTK_NOTEBOOK (widget); + gtk_widget_show (widget); + + comp_editor_setup_recent_menu (editor); - /* DND support */ - gtk_drag_dest_set (GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL, drop_types, num_drop_types, GDK_ACTION_COPY|GDK_ACTION_ASK|GDK_ACTION_MOVE); - g_signal_connect(editor, "drag_data_received", G_CALLBACK (drag_data_received), NULL); - g_signal_connect(editor, "drag-motion", G_CALLBACK(drag_motion), editor); + /* Drag-and-Drop Support */ - gtk_window_set_type_hint (GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL); + view = E_ATTACHMENT_VIEW (priv->attachment_view); + target_list = e_attachment_view_get_target_list (view); + drag_actions = e_attachment_view_get_drag_actions (view); + + targets = gtk_target_table_new_from_list (target_list, &n_targets); + + gtk_drag_dest_set ( + GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL, + targets, n_targets, drag_actions); + + gtk_target_table_free (targets, n_targets); + + gtk_window_set_type_hint ( + GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL); } static gboolean @@ -1927,401 +1698,16 @@ prompt_and_save_changes (CompEditor *editor, gboolean send) } } -static int -delete_event_cb (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - CompEditor *editor = COMP_EDITOR (data); - - commit_all_fields (editor); - - if (prompt_and_save_changes (editor, TRUE)) - close_dialog (editor); - - return TRUE; -} - static void -attachment_bar_changed_cb (EAttachmentBar *bar, - void *data) +attachment_store_changed_cb (CompEditor *editor) { - CompEditor *editor = COMP_EDITOR (data); - - guint attachment_num = e_attachment_bar_get_num_attachments ( - E_ATTACHMENT_BAR (editor->priv->attachment_bar)); - if (attachment_num) { - gchar *num_text = g_strdup_printf ( - ngettext ("%d Attachment", "%d Attachments", attachment_num), - attachment_num); - gtk_label_set_markup (GTK_LABEL (editor->priv->attachment_expander_num), - num_text); - g_free (num_text); - - gtk_widget_show (editor->priv->attachment_expander_icon); - e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),TRUE); - - } else { - gtk_label_set_text (GTK_LABEL (editor->priv->attachment_expander_num), ""); - gtk_widget_hide (editor->priv->attachment_expander_icon); - e_expander_set_expanded(E_EXPANDER(editor->priv->attachment_expander),FALSE); - } - - /* Mark the editor as changed so it prompts about unsaved changes on close */ comp_editor_set_changed (editor, TRUE); - -} - -static void -attachment_expander_activate_cb (EExpander *expander, - void *data) -{ - CompEditor *editor = COMP_EDITOR (data); - gboolean show = e_expander_get_expanded (expander); - - /* Update the expander label */ - if (show) - gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label), - _("Hide Attachment _Bar")); - else - gtk_label_set_text_with_mnemonic (GTK_LABEL (editor->priv->attachment_expander_label), - _("Show Attachment _Bar")); -} - -static gboolean -open_attachment (EAttachmentBar *bar, CompEditor *editor) -{ - GnomeIconList *icon_list; - GList *p; - int num; - char *attach_file_url; - - if (E_IS_ATTACHMENT_BAR (bar)) { - icon_list = GNOME_ICON_LIST (bar); - p = gnome_icon_list_get_selection (icon_list); - if (p) { - EAttachment *attachment; - GSList *list; - const char *comp_uid = NULL; - char *filename = NULL; - const char *local_store = e_cal_get_local_attachment_store (editor->priv->client); - - e_cal_component_get_uid (editor->priv->comp, &comp_uid); - num = GPOINTER_TO_INT (p->data); - list = e_attachment_bar_get_attachment (bar, num); - attachment = list->data; - g_slist_free (list); - - filename = g_strdup_printf ("%s-%s", - comp_uid, - camel_mime_part_get_filename(attachment->body)); - - attach_file_url = g_build_path ("/", local_store, filename, NULL); - - /* launch the url now */ - e_show_uri (GTK_WINDOW (editor), attach_file_url); - - g_free (filename); - g_free (attach_file_url); } - return TRUE; - } else - return FALSE; -} - -static gboolean -attachment_bar_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, CompEditor *editor) -{ - if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) - if (open_attachment (bar, editor)) - return TRUE; - return FALSE; -} - -/* Callbacks. */ - -static void -cab_open(EPopup *ep, EPopupItem *item, void *data) -{ - EAttachmentBar *bar = data; - CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar))); - - if (!open_attachment (bar, editor)) - g_message ("\n Open failed"); -} - -static void -cab_add(EPopup *ep, EPopupItem *item, void *data) -{ - EAttachmentBar *bar = data; - CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar))); - GPtrArray *file_list; - gboolean is_inline = FALSE; - int i; - - file_list = comp_editor_select_file_attachments (editor, &is_inline); - /*TODO add a good implementation here */ - if (!file_list) - return; - for (i = 0; i < file_list->len; i++) { - CamelURL *url; - - url = camel_url_new (file_list->pdata[i], NULL); - if (url == NULL) - continue; - - if (!g_ascii_strcasecmp (url->protocol, "file")) - e_attachment_bar_attach (bar, url->path, is_inline ? "inline" : "attachment"); - else - e_attachment_bar_attach_remote_file (bar, file_list->pdata[i], is_inline ? "inline" : "attachment"); - g_free (file_list->pdata[i]); - camel_url_free (url); - } - - g_ptr_array_free (file_list, TRUE); -} - -static void -cab_properties(EPopup *ep, EPopupItem *item, void *data) -{ - EAttachmentBar *bar = data; - - e_attachment_bar_edit_selected(bar); -} - -static void -cab_remove(EPopup *ep, EPopupItem *item, void *data) -{ - EAttachmentBar *bar = data; - - e_attachment_bar_remove_selected(bar); -} - -/* Popup menu handling. */ -static EPopupItem cab_popups[] = { - { E_POPUP_ITEM, "10.attach", N_("_Open"), cab_open, NULL, GTK_STOCK_OPEN, E_CAL_POPUP_ATTACHMENTS_ONE}, - { E_POPUP_ITEM, "20.attach", N_("_Remove"), cab_remove, NULL, GTK_STOCK_REMOVE, E_CAL_POPUP_ATTACHMENTS_MANY | E_CAL_POPUP_ATTACHMENTS_MODIFY }, - { E_POPUP_ITEM, "30.attach", N_("_Properties"), cab_properties, NULL, GTK_STOCK_PROPERTIES, E_CAL_POPUP_ATTACHMENTS_ONE }, - { E_POPUP_BAR, "40.attach.00", NULL, NULL, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_MANY|E_CAL_POPUP_ATTACHMENTS_ONE }, - { E_POPUP_ITEM, "40.attach.01", N_("_Add attachment..."), cab_add, NULL, GTK_STOCK_ADD, E_CAL_POPUP_ATTACHMENTS_MODIFY}, -}; - -static void -cab_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data) -{ - EAttachmentBar *bar = user_data; - GnomeIconList *icon_list = user_data; - GList *selection; - GnomeCanvasPixbuf *image; - - gdk_window_get_origin (((GtkWidget*) bar)->window, x, y); - - selection = gnome_icon_list_get_selection (icon_list); - if (selection == NULL) - return; - - image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data)); - if (image == NULL) - return; - - /* Put menu to the center of icon. */ - *x += (int)(image->item.x1 + image->item.x2) / 2; - *y += (int)(image->item.y1 + image->item.y2) / 2; -} - -static void -cab_popups_free(EPopup *ep, GSList *l, void *data) -{ - g_slist_free(l); -} - -/* if id != -1, then use it as an index for target of the popup */ -static void -cab_popup(EAttachmentBar *bar, GdkEventButton *event, int id) -{ - GSList *attachments = NULL, *menus = NULL; - int i; - ECalPopup *ecp; - ECalPopupTargetAttachments *t; - GtkMenu *menu; - CompEditor *editor = COMP_EDITOR (gtk_widget_get_toplevel (GTK_WIDGET (bar))); - - attachments = e_attachment_bar_get_attachment(bar, id); - - for (i=0;itarget.widget = (GtkWidget *)bar; - menu = e_popup_create_menu_once((EPopup *)ecp, (EPopupTarget *)t, 0); - - if (event == NULL) - gtk_menu_popup(menu, NULL, NULL, cab_popup_position, bar, 0, gtk_get_current_event_time()); - else - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); -} - -/* GtkWidget methods. */ - -static gboolean -popup_menu_event (EAttachmentBar *bar) -{ - cab_popup (bar, NULL, -1); - - return TRUE; -} - - -static int -button_press_event (EAttachmentBar *bar, - GdkEventButton *event) -{ - GnomeIconList *icon_list = GNOME_ICON_LIST (bar); - int icon_number = -1; - - if (event->button != 3) - return FALSE; - - if (!gnome_icon_list_get_selection (icon_list)) { - icon_number = gnome_icon_list_get_icon_at (icon_list, event->x, event->y); - if (icon_number >= 0) { - gnome_icon_list_unselect_all(icon_list); - gnome_icon_list_select_icon (icon_list, icon_number); - } - } - - cab_popup(bar, event, icon_number); - - return TRUE; -} - -static gint -key_press_event (EAttachmentBar *bar, - GdkEventKey *event) -{ - if (event->keyval == GDK_Delete) { - e_attachment_bar_remove_selected (bar); - return TRUE; - } - - return FALSE; -} - -static gint -editor_key_press_event (CompEditor *editor, - GdkEventKey *event) -{ - if (event->keyval == GDK_Escape) { - commit_all_fields (editor); - - if (prompt_and_save_changes (editor, TRUE)) - close_dialog (editor); - - return TRUE; - } - - return FALSE; } /* Menu callbacks */ -static void -setup_widgets (CompEditor *editor) -{ - CompEditorPrivate *priv; - GtkWidget *expander_hbox; - GtkWidget *widget; - GtkWidget *vbox; - - priv = editor->priv; - - /* Useful vbox */ - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (editor), vbox); - gtk_widget_show (vbox); - - /* Main Menu */ - widget = comp_editor_get_managed_widget (editor, "/main-menu"); - gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - /* Main Toolbar */ - widget = comp_editor_get_managed_widget (editor, "/main-toolbar"); - gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0); - gtk_widget_show (widget); - - /* Notebook */ - widget = gtk_notebook_new (); - gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); - gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0); - gtk_widget_show (widget); - priv->notebook = GTK_NOTEBOOK (widget); - - g_signal_connect (editor, "delete_event", G_CALLBACK (delete_event_cb), editor); - g_signal_connect (editor, "key_press_event", G_CALLBACK (editor_key_press_event), editor); - - /*Attachments */ - priv->attachment_scrolled_window = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->attachment_scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - - g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK (button_press_event), NULL); - g_signal_connect (priv->attachment_bar, "key_press_event", G_CALLBACK (key_press_event), NULL); - g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK (popup_menu_event), NULL); - - GTK_WIDGET_SET_FLAGS (priv->attachment_bar, GTK_CAN_FOCUS); - gtk_container_add (GTK_CONTAINER (priv->attachment_scrolled_window), - priv->attachment_bar); - gtk_widget_show (priv->attachment_bar); - g_signal_connect (priv->attachment_bar, "changed", - G_CALLBACK (attachment_bar_changed_cb), editor); - g_signal_connect (GNOME_ICON_LIST (priv->attachment_bar), "event", - G_CALLBACK (attachment_bar_icon_clicked_cb), editor); - priv->attachment_expander_label = - gtk_label_new_with_mnemonic (_("Show Attachment _Bar")); - priv->attachment_expander_num = gtk_label_new (""); - gtk_label_set_use_markup (GTK_LABEL (priv->attachment_expander_num), TRUE); - gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_label), 0.0, 0.5); - gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_num), 1.0, 0.5); - expander_hbox = gtk_hbox_new (FALSE, 0); - - priv->attachment_expander_icon = gtk_image_new_from_icon_name ("mail-attachment", GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment (GTK_MISC (priv->attachment_expander_icon), 1, 0.5); - gtk_widget_set_size_request (priv->attachment_expander_icon, 100, -1); - - gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_label, - TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_icon, - TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (expander_hbox), priv->attachment_expander_num, - TRUE, TRUE, 0); - gtk_widget_show_all (expander_hbox); - gtk_widget_hide (priv->attachment_expander_icon); - - priv->attachment_expander = e_expander_new (""); - e_expander_set_label_widget (E_EXPANDER (priv->attachment_expander), expander_hbox); - atk_object_set_name (gtk_widget_get_accessible (priv->attachment_expander), _("Show Attachments")); - atk_object_set_description (gtk_widget_get_accessible (priv->attachment_expander), _("Press space key to toggle attachment bar")); - gtk_container_add (GTK_CONTAINER (priv->attachment_expander), priv->attachment_scrolled_window); - - gtk_box_pack_start (GTK_BOX (vbox), priv->attachment_expander, FALSE, FALSE, 4); - gtk_widget_show (priv->attachment_expander); - e_expander_set_expanded (E_EXPANDER (priv->attachment_expander), FALSE); - g_signal_connect_after (priv->attachment_expander, "activate", - G_CALLBACK (attachment_expander_activate_cb), editor); -} - - static void comp_editor_show_help (CompEditor *editor) { @@ -2861,12 +2247,14 @@ comp_editor_get_client (CompEditor *editor) static void set_attachment_list (CompEditor *editor, GSList *attach_list) { - GSList *p = NULL; - const char *comp_uid= NULL; + EAttachmentStore *store; + EAttachmentView *view; + GSList *iter = NULL; - e_cal_component_get_uid (editor->priv->comp, &comp_uid); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + store = e_attachment_view_get_store (view); - if (e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR (editor->priv->attachment_bar))) { + if (e_attachment_store_get_num_attachments (store) > 0) { /* To prevent repopulating the * bar due to redraw functions in fill_widget. * Assumes it can be set only once. @@ -2874,112 +2262,55 @@ set_attachment_list (CompEditor *editor, GSList *attach_list) return; } - for (p = attach_list; p != NULL; p = p->next) { - char *attach_filename; - CamelMimePart *part; - CamelDataWrapper *wrapper; - CamelStream *stream; - struct stat statbuf; - char *mime_type, *file_name; - char *ptr; - - attach_filename = (char *) p->data; - /* should we assert if g_str_has_prefix (attach_filename, "file://")) - * here - */ - /* get url sans protocol and add it to the bar. - * how to set the filename properly */ - file_name = g_filename_from_uri (attach_filename, NULL, NULL); - if (!file_name) - continue; - - if (g_stat (file_name, &statbuf) < 0) { - g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno)); - g_free (file_name); - continue; - } - - /* return if it's not a regular file */ - if (!S_ISREG (statbuf.st_mode)) { - g_warning ("Cannot attach file %s: not a regular file", file_name); - g_free (file_name); - return; - } - - stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0); - if (!stream) { - g_warning ("Cannot attach file %s: %s", file_name, g_strerror (errno)); - g_free (file_name); - return; - } - - mime_type = e_util_guess_mime_type (file_name, TRUE); - 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); + for (iter = attach_list; iter != NULL; iter = iter->next) { + EAttachment *attachment; + const gchar *uri = iter->data; - camel_mime_part_set_disposition (part, "attachment"); - - ptr = strstr (file_name, comp_uid); - if (ptr) { - ptr += strlen(comp_uid); - if (*ptr++ == '-') - camel_mime_part_set_filename (part, ptr); - } - g_free (file_name); - - e_attachment_bar_attach_mime_part ((EAttachmentBar *) editor->priv->attachment_bar, part); - e_expander_set_expanded (E_EXPANDER (editor->priv->attachment_expander), TRUE); - - camel_object_unref (part); + attachment = e_attachment_new_for_uri (uri); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, editor); + g_object_unref (attachment); } } static void fill_widgets (CompEditor *editor) { + EAttachmentStore *store; + EAttachmentView *view; CompEditorPrivate *priv; GList *l; GtkAction *action; + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + store = e_attachment_view_get_store (view); + priv = editor->priv; /*Check if attachments are available here and set them*/ if (e_cal_component_has_attachments (priv->comp)) { GSList *attachment_list = NULL; e_cal_component_get_attachment_list (priv->comp, &attachment_list); - g_signal_handlers_block_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor); + g_signal_handlers_block_by_func ( + store, G_CALLBACK (attachment_store_changed_cb), + editor); set_attachment_list (editor, attachment_list); - g_signal_handlers_unblock_by_func(priv->attachment_bar, G_CALLBACK (attachment_bar_changed_cb), editor); + g_signal_handlers_unblock_by_func ( + store, G_CALLBACK (attachment_store_changed_cb), + editor); g_slist_foreach (attachment_list, (GFunc)g_free, NULL); g_slist_free (attachment_list); } action = comp_editor_get_action (editor, "classify-public"); - g_signal_handlers_block_by_func (action, G_CALLBACK (classification_changed_cb), editor); + g_signal_handlers_block_by_func (action, G_CALLBACK (action_classification_cb), editor); for (l = priv->pages; l != NULL; l = l->next) comp_editor_page_fill_widgets (l->data, priv->comp); - g_signal_handlers_unblock_by_func (action, G_CALLBACK (classification_changed_cb), editor); + g_signal_handlers_unblock_by_func (action, G_CALLBACK (action_classification_cb), editor); } static void @@ -3303,20 +2634,41 @@ comp_editor_close (CompEditor *editor) GSList * comp_editor_get_mime_attach_list (CompEditor *editor) { + EAttachmentStore *store; + EAttachmentView *view; + GtkTreeModel *model; + GtkTreeIter iter; struct CalMimeAttach *cal_mime_attach; - GSList *attach_list = NULL, *l, *parts; + GSList *attach_list = NULL; + gboolean valid; + + view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); + store = e_attachment_view_get_store (view); - /* TODO assert sanity of bar */ - parts = e_attachment_bar_get_parts (E_ATTACHMENT_BAR (editor->priv->attachment_bar)); - for (l = parts; l ; l = l->next) { + model = GTK_TREE_MODEL (store); + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid) { + EAttachment *attachment; CamelDataWrapper *wrapper; + CamelMimePart *mime_part; CamelStreamMem *mstream; unsigned char *buffer = NULL; const char *desc, *disp; + gint column_id; + + column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT; + gtk_tree_model_get (model, &iter, column_id, &attachment, -1); + mime_part = e_attachment_get_mime_part (attachment); + g_object_unref (attachment); + + valid = gtk_tree_model_iter_next (model, &iter); + + if (mime_part == NULL) + continue; cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach)); - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (l->data)); + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); mstream = (CamelStreamMem *) camel_stream_mem_new (); camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream); @@ -3324,15 +2676,14 @@ comp_editor_get_mime_attach_list (CompEditor *editor) cal_mime_attach->encoded_data = (char *)buffer; cal_mime_attach->length = mstream->buffer->len; - cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename - ((CamelMimePart *) l->data)); - desc = camel_mime_part_get_description ((CamelMimePart *) l->data); + cal_mime_attach->filename = g_strdup (camel_mime_part_get_filename (mime_part)); + desc = camel_mime_part_get_description (mime_part); if (!desc || *desc == '\0') desc = _("attachment"); cal_mime_attach->description = g_strdup (desc); cal_mime_attach->content_type = g_strdup (camel_data_wrapper_get_mime_type (wrapper)); - disp = camel_mime_part_get_disposition ((CamelMimePart *)l->data); + disp = camel_mime_part_get_disposition (mime_part); if (disp && !g_ascii_strcasecmp(disp, "inline")) cal_mime_attach->disposition = TRUE; @@ -3342,8 +2693,6 @@ comp_editor_get_mime_attach_list (CompEditor *editor) } - g_slist_free (parts); - return attach_list; } diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c index a579d77348..f32f24501d 100644 --- a/calendar/gui/dialogs/event-editor.c +++ b/calendar/gui/dialogs/event-editor.c @@ -512,8 +512,6 @@ event_editor_init (EventEditor *ee) g_signal_connect_swapped ( ee->priv->model, "row_deleted", G_CALLBACK (event_editor_model_changed_cb), ee); - - gtk_window_set_default_size (GTK_WINDOW (ee), 300, 225); } static void diff --git a/calendar/gui/e-cal-popup.c b/calendar/gui/e-cal-popup.c index b9f0d5f8d5..0292f16c71 100644 --- a/calendar/gui/e-cal-popup.c +++ b/calendar/gui/e-cal-popup.c @@ -86,378 +86,11 @@ ecalp_target_free(EPopup *ep, EPopupTarget *t) /* Standard menu code */ -static char * -temp_save_part(CamelMimePart *part, char *path, gboolean file) -{ - const char *filename; - char *tmpdir, *utf8_mfilename = NULL, *mfilename = NULL, *usepath; - CamelStream *stream; - CamelDataWrapper *wrapper; - - if (!path) { - tmpdir = e_mkdtemp("evolution-tmp-XXXXXX"); - if (tmpdir == NULL) { - return NULL; - } - - filename = camel_mime_part_get_filename (part); - if (filename == NULL) { - /* This is the default filename used for temporary file creation */ - filename = _("Unknown"); - } else { - utf8_mfilename = g_strdup (filename); - e_filename_make_safe (utf8_mfilename); - mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL); - g_free (utf8_mfilename); - filename = (const char *) mfilename; - } - - path = g_build_filename(tmpdir, filename, NULL); - g_free(tmpdir); - g_free(mfilename); - } else if (!file) { - tmpdir = path; - filename = camel_mime_part_get_filename (part); - if (filename == NULL) { - /* This is the default filename used for temporary file creation */ - filename = _("Unknown"); - } else { - utf8_mfilename = g_strdup (filename); - e_filename_make_safe (utf8_mfilename); - mfilename = g_filename_from_utf8 ((const char *)utf8_mfilename, -1, NULL, NULL, NULL); - g_free (utf8_mfilename); - filename = (const char *) mfilename; - } - - path = g_build_filename(tmpdir, filename, NULL); - g_free(mfilename); - } - - if (strstr (path, "://")) - usepath = path; - else - usepath = g_strjoin (NULL, "file://", path, NULL); - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - stream = camel_stream_vfs_new_with_uri (usepath, CAMEL_STREAM_VFS_CREATE); - - if (usepath != path) - g_free (usepath); - - if (!stream) { - /* TODO handle error conditions */ - g_message ("DEBUG: could not open the file to write\n"); - return NULL; - } - - if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) { - camel_stream_close (stream); - camel_object_unref (stream); - g_message ("DEBUG: could not write to file\n"); - return NULL; - } - - camel_stream_close(stream); - camel_object_unref(stream); - - return path; -} - -static void -ecalp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - CamelMimePart *part = NULL; - char *file, *mfilename = NULL; - const char *filename; - - part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body; - filename = camel_mime_part_get_filename (part); - if (filename == NULL) { - /* This is the default filename used for temporary file creation */ - filename = _("Unknown"); - } else { - mfilename = g_strdup(filename); - e_filename_make_safe(mfilename); - filename = mfilename; - } - file = e_file_dialog_save (_("Save As..."), filename); - - if (file) - temp_save_part (part, file, TRUE); - - g_free (file); - g_free (mfilename); -} - -static void -ecalp_part_popup_save_selected(EPopup *ep, EPopupItem *item, void *data) -{ - GSList *parts; - EPopupTarget *t = ep->target; - char *dir, *path; - - dir = e_file_dialog_save_folder (_("Select folder to save selected attachments...")); - parts = ((ECalPopupTargetAttachments *) t)->attachments; - - for (;parts; parts=parts->next) { - path = temp_save_part (((EAttachment *)parts->data)->body, dir, FALSE); - /* Probably we 'll do some reporting in next release, like listing the saved files and locations */ - g_free (path); - } -} - -static void -ecalp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupTarget *t = ep->target; - GConfClient *gconf; - char *str, *filename, *path, *extension; - unsigned int i=1; - CamelMimePart *part = NULL; - - part = ((EAttachment *) ((ECalPopupTargetAttachments *) t)->attachments->data)->body; - - if (!part) - return; - - filename = g_strdup(camel_mime_part_get_filename(part)); - - /* if filename is blank, create a default filename based on MIME type */ - if (!filename || !filename[0]) { - CamelContentType *ct; - - ct = camel_mime_part_get_content_type(part); - g_free (filename); - filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype); - } - - e_filename_make_safe(filename); - - path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", filename, NULL); - - extension = strrchr(filename, '.'); - if (extension) - *extension++ = 0; - - /* if file exists, stick a (number) on the end */ - while (g_file_test(path, G_FILE_TEST_EXISTS)) { - char *name; - name = g_strdup_printf(extension?"%s (%d).%s":"%s (%d)", filename, i++, extension); - g_free(path); - path = g_build_filename(g_get_home_dir(), ".gnome2", "wallpapers", name, NULL); - g_free(name); - } - - g_free(filename); - - if (temp_save_part(part, path, TRUE)) { - gconf = gconf_client_get_default(); - - /* if the filename hasn't changed, blank the filename before - * setting it so that gconf detects a change and updates it */ - if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_filename", NULL)) != NULL - && strcmp (str, path) == 0) { - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", "", NULL); - } - - g_free (str); - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_filename", path, NULL); - - /* if GNOME currently doesn't display a picture, set to "wallpaper" - * display mode, otherwise leave it alone */ - if ((str = gconf_client_get_string(gconf, "/desktop/gnome/background/picture_options", NULL)) == NULL - || strcmp(str, "none") == 0) { - gconf_client_set_string(gconf, "/desktop/gnome/background/picture_options", "wallpaper", NULL); - } - - gconf_client_suggest_sync(gconf, NULL); - - g_free(str); - g_object_unref(gconf); - } - - g_free(path); -} - -static const EPopupItem ecalp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" }; - -static ECalPopupItem ecalp_attachment_object_popups[] = { - { E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), ecalp_part_popup_saveas, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_ONE }, - { E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), ecalp_part_popup_set_background, NULL, NULL, E_CAL_POPUP_ATTACHMENTS_IMAGE }, - { E_POPUP_ITEM, "00.attach.20", N_("_Save Selected"), ecalp_part_popup_save_selected, NULL, "document-save-as", E_CAL_POPUP_ATTACHMENTS_MULTIPLE }, - { E_POPUP_BAR, "05.attach", }, -}; - -static void -ecalp_apps_open_in(EPopup *ep, EPopupItem *item, void *data) -{ - char *path; - EPopupTarget *target = ep->target; - CamelMimePart *part; - - part = ((EAttachment *) ((ECalPopupTargetAttachments *) target)->attachments->data)->body; - - path = temp_save_part(part, NULL, FALSE); - if (path) { - GAppInfo *app = item->user_data; - GList *uris = NULL; - GError *error = NULL; - - if (g_app_info_supports_files (app)) { - GFile *file = g_file_new_for_path (path); - - uris = g_list_append (uris, file); - g_app_info_launch (app, uris, NULL, &error); - g_object_unref (file); - } else { - char *uri; - - uri = e_util_filename_to_uri (path); - uris = g_list_append (uris, uri); - - g_app_info_launch_uris (app, uris, NULL, &error); - g_free (uri); - } - - if (error) { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_list_free (uris); - g_free (path); - } -} - -static void -ecalp_apps_popup_free(EPopup *ep, GSList *free_list, void *data) -{ - while (free_list) { - GSList *n = free_list->next; - EPopupItem *item = free_list->data; - - if (item->user_data && item->activate == ecalp_apps_open_in) - g_object_unref (item->user_data); - - g_free(item->path); - g_free(item->label); - g_free(item); - g_slist_free_1(free_list); - - free_list = n; - } -} - -static void -ecalp_standard_items_free(EPopup *ep, GSList *items, void *data) -{ - g_slist_free(items); -} - -static void -ecalp_standard_menu_factory (EPopup *ecalp, void *data) -{ - int i, len; - EPopupItem *items; - GSList *menus = NULL; - GList *apps = NULL; - char *mime_type = NULL; - const char *filename = NULL; - - switch (ecalp->target->type) { - case E_CAL_POPUP_TARGET_ATTACHMENTS: { - ECalPopupTargetAttachments *t = (ECalPopupTargetAttachments *)ecalp->target; - GSList *list = t->attachments; - EAttachment *attachment; - - items = ecalp_attachment_object_popups; - len = G_N_ELEMENTS(ecalp_attachment_object_popups); - - if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) { - break; - } - - /* Only one attachment selected */ - attachment = list->data; - mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body); - filename = camel_mime_part_get_filename(attachment->body); - - - break; } - default: - items = NULL; - len = 0; - } - - if (mime_type) { - gchar *cp; - - /* does gvfs expect lowercase MIME types? */ - for (cp = mime_type; *cp != '\0'; cp++) - *cp = g_ascii_tolower (*cp); - - cp = g_content_type_from_mime_type (mime_type); - apps = g_app_info_get_all_for_type (cp ? cp : mime_type); - g_free (cp); - - if (apps == NULL || strcmp(mime_type, "application/octet-stream") == 0) { - if (filename) { - gchar *name_type; - - name_type = e_util_guess_mime_type (filename, FALSE); - cp = g_content_type_from_mime_type (name_type); - /* show alternative apps first */ - apps = g_list_concat (g_app_info_get_all_for_type (cp ? cp : name_type), apps); - g_free (cp); - g_free (name_type); - } - } - g_free (mime_type); - - if (apps) { - GSList *open_menus = NULL; - GList *l; - - menus = g_slist_prepend(menus, (void *)&ecalp_standard_part_apps_bar); - - for (l = apps, i = 0; l; l = l->next, i++) { - GAppInfo *app = l->data; - EPopupItem *item; - - item = g_malloc0(sizeof(*item)); - item->type = E_POPUP_ITEM; - item->path = g_strdup_printf("99.object.%02d", i); - item->label = g_strdup_printf(_("Open in %s..."), g_app_info_get_name (app)); - item->activate = ecalp_apps_open_in; - item->user_data = app; - - open_menus = g_slist_prepend(open_menus, item); - } - - if (open_menus) - e_popup_add_items(ecalp, open_menus, NULL, ecalp_apps_popup_free, NULL); - - g_list_free (apps); - } - } - - for (i=0;itarget->mask) == 0) - menus = g_slist_prepend(menus, &items[i]); - } - - if (menus) - e_popup_add_items(ecalp, menus, NULL, ecalp_standard_items_free, NULL); -} - static void ecalp_class_init(GObjectClass *klass) { klass->finalize = ecalp_finalise; ((EPopupClass *)klass)->target_free = ecalp_target_free; - - e_popup_class_add_factory((EPopupClass *)klass, NULL, ecalp_standard_menu_factory, NULL); } GType @@ -750,56 +383,6 @@ e_cal_popup_target_new_source(ECalPopup *eabp, ESourceSelector *selector) return t; } -/** - * e_cal_popup_target_new_attachments: - * @ecp: - * @attachments: A list of CalAttachment objects, reffed for - * the list. Will be unreff'd once finished with. - * - * Owns the list @attachments and their items after they're passed in. - * - * Return value: - **/ -ECalPopupTargetAttachments * -e_cal_popup_target_new_attachments(ECalPopup *ecp, CompEditor *editor, GSList *attachments) -{ - ECalPopupTargetAttachments *t = e_popup_target_new(&ecp->popup, E_CAL_POPUP_TARGET_ATTACHMENTS, sizeof(*t)); - guint32 mask = ~0; - int len = g_slist_length(attachments); - ECal *client = comp_editor_get_client (editor); - CompEditorFlags flags = comp_editor_get_flags (editor); - gboolean read_only = FALSE; - GError *error = NULL; - - if (!e_cal_is_read_only (client, &read_only, &error)) { - if (error->code != E_CALENDAR_STATUS_BUSY) - read_only = TRUE; - g_error_free (error); - } - - if (!read_only && (!(flags & COMP_EDITOR_MEETING) || - (flags & COMP_EDITOR_NEW_ITEM) || - (flags & COMP_EDITOR_USER_ORG))) - mask &= ~ E_CAL_POPUP_ATTACHMENTS_MODIFY; - - t->attachments = attachments; - if (len > 0) - mask &= ~ E_CAL_POPUP_ATTACHMENTS_MANY; - - if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) { - if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*")) - mask &= ~ E_CAL_POPUP_ATTACHMENTS_IMAGE; - mask &= ~ E_CAL_POPUP_ATTACHMENTS_ONE; - } - - if (len > 1) - mask &= ~ E_CAL_POPUP_ATTACHMENTS_MULTIPLE; - - t->target.mask = mask; - - return t; -} - /* ********************************************************************** */ /* Popup menu plugin handler */ diff --git a/calendar/gui/e-cal-popup.h b/calendar/gui/e-cal-popup.h index fb899c3961..34874efdba 100644 --- a/calendar/gui/e-cal-popup.h +++ b/calendar/gui/e-cal-popup.h @@ -195,8 +195,6 @@ ECalPopup *e_cal_popup_new(const char *menuid); ECalPopupTargetSelect *e_cal_popup_target_new_select(ECalPopup *eabp, struct _ECalModel *model, GPtrArray *events); ECalPopupTargetSource *e_cal_popup_target_new_source(ECalPopup *eabp, struct _ESourceSelector *selector); -ECalPopupTargetAttachments * e_cal_popup_target_new_attachments (ECalPopup *ecp, - CompEditor *editor, GSList *attachments); /* ********************************************************************** */ diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c index 61ad1e9a90..e46aba4192 100644 --- a/composer/e-composer-actions.c +++ b/composer/e-composer-actions.c @@ -31,69 +31,13 @@ static void action_attach_cb (GtkAction *action, EMsgComposer *composer) { - EAttachmentBar *bar; - GtkWidget *dialog; - GtkWidget *option; - GSList *uris, *iter; - const gchar *disposition; - gboolean active; - gint response; - - bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar); - - dialog = gtk_file_chooser_dialog_new ( - _("Insert Attachment"), - GTK_WINDOW (composer), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - _("A_ttach"), GTK_RESPONSE_OK, - NULL); - - gtk_dialog_set_default_response ( - GTK_DIALOG (dialog), GTK_RESPONSE_OK); - gtk_file_chooser_set_local_only ( - GTK_FILE_CHOOSER (dialog), FALSE); - gtk_file_chooser_set_select_multiple ( - GTK_FILE_CHOOSER (dialog), TRUE); - gtk_window_set_icon_name ( - GTK_WINDOW (dialog), "mail-message-new"); + EAttachmentView *view; + EAttachmentStore *store; - option = gtk_check_button_new_with_mnemonic ( - _("_Suggest automatic display of attachment")); - gtk_widget_show (option); - gtk_file_chooser_set_extra_widget ( - GTK_FILE_CHOOSER (dialog), option); + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); - response = gtkhtml_editor_file_chooser_dialog_run ( - GTKHTML_EDITOR (composer), dialog); - - if (response != GTK_RESPONSE_OK) - goto exit; - - uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (dialog)); - active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (option)); - disposition = active ? "inline" : "attachment"; - - for (iter = uris; iter != NULL; iter = iter->next) { - CamelURL *url; - - url = camel_url_new (iter->data, NULL); - if (url == NULL) - continue; - - if (!g_ascii_strcasecmp (url->protocol, "file")) - e_attachment_bar_attach (bar, url->path, disposition); - else - e_attachment_bar_attach_remote_file (bar, iter->data, disposition); - - camel_url_free (url); - } - - g_slist_foreach (uris, (GFunc) g_free, NULL); - g_slist_free (uris); - -exit: - gtk_widget_destroy (dialog); + e_attachment_store_run_load_dialog (store, GTK_WINDOW (composer)); } static void diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c index d47a372cd5..ab1e092513 100644 --- a/composer/e-composer-private.c +++ b/composer/e-composer-private.c @@ -49,27 +49,29 @@ composer_setup_charset_menu (EMsgComposer *composer) static void composer_setup_recent_menu (EMsgComposer *composer) { + EAttachmentView *view; GtkUIManager *manager; - GtkAction *action = NULL; - const gchar *path, *action_name; + GtkAction *action; + const gchar *action_name; + const gchar *path; guint merge_id; + view = e_msg_composer_get_attachment_view (composer); manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); - action_name = "recent-menu"; path = "/main-menu/insert-menu/insert-menu-top/recent-placeholder"; merge_id = gtk_ui_manager_new_merge_id (manager); + action_name = "recent-menu"; - action = e_attachment_bar_recent_action_new ( - e_msg_composer_get_attachment_bar (composer), - action_name, _("Recent _Documents")); + action = e_attachment_view_recent_action_new ( + view, action_name, _("Recent _Documents")); if (action != NULL) { - gtk_action_group_add_action (composer->priv->composer_actions, action); + gtk_action_group_add_action ( + composer->priv->composer_actions, action); - gtk_ui_manager_add_ui ( + gtk_ui_manager_add_ui ( manager, merge_id, path, - action_name, - action_name, + action_name, action_name, GTK_UI_MANAGER_AUTO, FALSE); } @@ -84,7 +86,6 @@ e_composer_private_init (EMsgComposer *composer) GtkhtmlEditor *editor; GtkUIManager *manager; GtkWidget *widget; - GtkWidget *expander; GtkWidget *container; GtkWidget *send_widget; const gchar *path; @@ -136,6 +137,8 @@ e_composer_private_init (EMsgComposer *composer) /* Construct the header table. */ + container = editor->vbox; + widget = e_composer_header_table_new (); gtk_container_set_border_width (GTK_CONTAINER (widget), 6); gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0); @@ -143,59 +146,23 @@ e_composer_private_init (EMsgComposer *composer) priv->header_table = g_object_ref (widget); gtk_widget_show (widget); - /* Construct attachment widgets. - * XXX Move this stuff into a new custom widget. */ - - widget = gtk_expander_new (NULL); - gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE); - gtk_container_set_border_width (GTK_CONTAINER (widget), 6); - gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0); - priv->attachment_expander = g_object_ref (widget); - gtk_widget_show (widget); - expander = widget; - - widget = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy ( - GTK_SCROLLED_WINDOW (widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type ( - GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (expander), widget); - priv->attachment_scrolled_window = g_object_ref (widget); - gtk_widget_show (widget); - container = widget; - - widget = e_attachment_bar_new (NULL); - GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); - gtk_container_add (GTK_CONTAINER (container), widget); - priv->attachment_bar = g_object_ref (widget); - gtk_widget_show (widget); + /* Construct the attachment paned. */ - widget = gtk_hbox_new (FALSE, 0); - gtk_expander_set_label_widget (GTK_EXPANDER (expander), widget); + widget = e_attachment_paned_new (); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + priv->attachment_paned = g_object_ref (widget); gtk_widget_show (widget); - container = widget; - widget = gtk_label_new_with_mnemonic (_("Show _Attachment Bar")); - gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 6); - priv->attachment_expander_label = g_object_ref (widget); - gtk_widget_show (widget); + /* Reparent the scrolled window containing the GtkHTML widget + * into the content area of the top attachment pane. */ - widget = gtk_image_new_from_icon_name ( - "mail-attachment", GTK_ICON_SIZE_MENU); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_widget_set_size_request (widget, 100, -1); - gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - priv->attachment_expander_icon = g_object_ref (widget); - gtk_widget_hide (widget); - - widget = gtk_label_new (NULL); - gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); - gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); - gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6); - priv->attachment_expander_num = g_object_ref (widget); - gtk_widget_show (widget); + widget = GTK_WIDGET (gtkhtml_editor_get_html (editor)); + widget = gtk_widget_get_parent (widget); + container = e_attachment_paned_get_content_area ( + E_ATTACHMENT_PANED (priv->attachment_paned)); + gtk_widget_reparent (widget, container); + gtk_box_set_child_packing ( + GTK_BOX (container), widget, TRUE, TRUE, 0, GTK_PACK_START); composer_setup_recent_menu (composer); } diff --git a/composer/e-composer-private.h b/composer/e-composer-private.h index ec6626e004..669af31235 100644 --- a/composer/e-composer-private.h +++ b/composer/e-composer-private.h @@ -25,11 +25,12 @@ #include -#include "e-attachment-bar.h" #include "e-composer-actions.h" #include "e-composer-autosave.h" #include "e-composer-header-table.h" #include "e-util/gconf-bridge.h" +#include "widgets/misc/e-attachment-paned.h" +#include "widgets/misc/e-attachment-store.h" #define E_MSG_COMPOSER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ @@ -94,6 +95,8 @@ struct _EMsgComposerPrivate { GtkWidget *html_editor; GtkWidget *header_table; + GtkWidget *attachment_paned; + GtkActionGroup *charset_actions; GtkActionGroup *composer_actions; @@ -102,13 +105,6 @@ struct _EMsgComposerPrivate { GtkWidget *focused_entry; - GtkWidget *attachment_bar; - GtkWidget *attachment_scrolled_window; - GtkWidget *attachment_expander; - GtkWidget *attachment_expander_label; - GtkWidget *attachment_expander_icon; - GtkWidget *attachment_expander_num; - GtkWidget *address_dialog; GHashTable *inline_images; diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index d39a212e88..a2777294c6 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -60,7 +60,6 @@ #include "e-util/e-dialog-utils.h" #include "misc/e-charset-picker.h" -#include "misc/e-expander.h" #include "e-util/e-error.h" #include "e-util/e-plugin-ui.h" #include "e-util/e-util-private.h" @@ -98,7 +97,6 @@ #include "e-msg-composer.h" #include "e-attachment.h" -#include "e-attachment-bar.h" #include "e-composer-autosave.h" #include "e-composer-private.h" #include "e-composer-header-table.h" @@ -152,39 +150,6 @@ enum { LAST_SIGNAL }; -enum { - DND_TYPE_MESSAGE_RFC822, - DND_TYPE_X_UID_LIST, - DND_TYPE_TEXT_URI_LIST, - DND_TYPE_NETSCAPE_URL, - DND_TYPE_TEXT_VCARD, - DND_TYPE_TEXT_CALENDAR -}; - -static GtkTargetEntry drop_types[] = { - { "message/rfc822", 0, DND_TYPE_MESSAGE_RFC822 }, - { "x-uid-list", 0, DND_TYPE_X_UID_LIST }, - { "text/uri-list", 0, DND_TYPE_TEXT_URI_LIST }, - { "_NETSCAPE_URL", 0, DND_TYPE_NETSCAPE_URL }, - { "text/x-vcard", 0, DND_TYPE_TEXT_VCARD }, - { "text/calendar", 0, DND_TYPE_TEXT_CALENDAR } -}; - -static struct { - gchar *target; - GdkAtom atom; - guint32 actions; -} drag_info[] = { - { "message/rfc822", NULL, GDK_ACTION_COPY }, - { "x-uid-list", NULL, GDK_ACTION_ASK | - GDK_ACTION_MOVE | - GDK_ACTION_COPY }, - { "text/uri-list", NULL, GDK_ACTION_COPY }, - { "_NETSCAPE_URL", NULL, GDK_ACTION_COPY }, - { "text/x-vcard", NULL, GDK_ACTION_COPY }, - { "text/calendar", NULL, GDK_ACTION_COPY } -}; - static gpointer parent_class; static guint signals[LAST_SIGNAL]; @@ -195,7 +160,6 @@ static GSList *all_composers = NULL; static GList *add_recipients (GList *list, const gchar *recips); static void handle_mailto (EMsgComposer *composer, const gchar *mailto); -static void handle_uri (EMsgComposer *composer, const gchar *uri, gboolean html_dnd); /* used by e_msg_composer_add_message_attachments () */ static void add_attachments_from_multipart (EMsgComposer *composer, CamelMultipart *multipart, @@ -527,7 +491,8 @@ build_message (EMsgComposer *composer, GtkhtmlEditor *editor; EMsgComposerPrivate *p = composer->priv; - EAttachmentBar *attachment_bar; + EAttachmentView *view; + EAttachmentStore *store; EComposerHeaderTable *table; GtkToggleAction *action; CamelDataWrapper *plain, *html, *current; @@ -554,7 +519,8 @@ build_message (EMsgComposer *composer, editor = GTKHTML_EDITOR (composer); table = e_msg_composer_get_header_table (composer); account = e_composer_header_table_get_account (table); - attachment_bar = E_ATTACHMENT_BAR (p->attachment_bar); + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); /* evil kludgy hack for Redirect */ if (p->redirect) { @@ -714,7 +680,7 @@ build_message (EMsgComposer *composer, } else current = plain; - if (e_attachment_bar_get_num_attachments (attachment_bar)) { + if (e_attachment_store_get_num_attachments (store) > 0) { CamelMultipart *multipart = camel_multipart_new (); if (p->is_alternative) { @@ -733,7 +699,8 @@ build_message (EMsgComposer *composer, camel_multipart_add_part (multipart, part); camel_object_unref (part); - e_attachment_bar_to_multipart (attachment_bar, multipart, p->charset); + e_attachment_store_add_to_multipart ( + store, multipart, p->charset); if (p->is_alternative) { for (i = camel_multipart_get_number (multipart); i > 1; i--) { @@ -976,107 +943,6 @@ skip_content: return NULL; } -/* Attachment Bar */ - -static void -emcab_add (EPopup *ep, EPopupItem *item, gpointer data) -{ - GtkWidget *widget = data; - GtkWidget *composer; - - composer = gtk_widget_get_toplevel (widget); - gtk_action_activate (ACTION (ATTACH)); -} - -static void -emcab_properties (EPopup *ep, EPopupItem *item, gpointer data) -{ - EAttachmentBar *attachment_bar = data; - - e_attachment_bar_edit_selected (attachment_bar); -} - -static void -emcab_remove (EPopup *ep, EPopupItem *item, gpointer data) -{ - EAttachmentBar *attachment_bar = data; - - e_attachment_bar_remove_selected (attachment_bar); -} - -static void -emcab_popup_position (GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data) -{ - GtkWidget *widget = user_data; - GnomeIconList *icon_list = user_data; - GList *selection; - GnomeCanvasPixbuf *image; - - gdk_window_get_origin (widget->window, x, y); - - selection = gnome_icon_list_get_selection (icon_list); - if (selection == NULL) - return; - - image = gnome_icon_list_get_icon_pixbuf_item ( - icon_list, GPOINTER_TO_INT(selection->data)); - if (image == NULL) - return; - - /* Put menu to the center of icon. */ - *x += (int)(image->item.x1 + image->item.x2) / 2; - *y += (int)(image->item.y1 + image->item.y2) / 2; -} - -static void -emcab_popups_free (EPopup *ep, GSList *list, gpointer data) -{ - g_slist_free (list); -} - -/* Popup menu handling. */ -static EPopupItem emcab_popups[] = { - { E_POPUP_ITEM, "10.attach", N_("_Remove"), emcab_remove, NULL, GTK_STOCK_REMOVE, EM_POPUP_ATTACHMENTS_MANY }, - { E_POPUP_ITEM, "20.attach", N_("_Properties"), emcab_properties, NULL, GTK_STOCK_PROPERTIES, EM_POPUP_ATTACHMENTS_ONE }, - { E_POPUP_BAR, "30.attach.00", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MANY|EM_POPUP_ATTACHMENTS_ONE }, - { E_POPUP_ITEM, "30.attach.01", N_("_Add attachment..."), emcab_add, NULL, GTK_STOCK_ADD, 0 }, -}; - -/* if id != -1, then use it as an index for target of the popup */ - -static void -emcab_popup (EAttachmentBar *bar, GdkEventButton *event, int id) -{ - GSList *attachments = NULL, *menus = NULL; - int i; - EMPopup *emp; - EMPopupTargetAttachments *t; - GtkMenu *menu; - - attachments = e_attachment_bar_get_attachment (bar, id); - - for (i=0;itarget.widget = (GtkWidget *)bar; - menu = e_popup_create_menu_once ((EPopup *)emp, (EPopupTarget *)t, 0); - - if (event == NULL) - gtk_menu_popup (menu, NULL, NULL, emcab_popup_position, bar, 0, gtk_get_current_event_time ()); - else - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, event->button, event->time); -} - /* Signatures */ static gchar * @@ -1467,108 +1333,17 @@ autosave_load_draft (const gchar *filename) /* Miscellaneous callbacks. */ -static gint -attachment_bar_button_press_event_cb (EAttachmentBar *attachment_bar, - GdkEventButton *event) -{ - GnomeIconList *icon_list; - gint icon_number; - - if (event->button != 3) - return FALSE; - - icon_list = GNOME_ICON_LIST (attachment_bar); - icon_number = gnome_icon_list_get_icon_at ( - icon_list, event->x, event->y); - if (icon_number >= 0) { - gnome_icon_list_unselect_all (icon_list); - gnome_icon_list_select_icon (icon_list, icon_number); - } - - emcab_popup (attachment_bar, event, icon_number); - - return TRUE; -} - static void -attachment_bar_changed_cb (EAttachmentBar *attachment_bar, - EMsgComposer *composer) +attachment_store_changed_cb (EMsgComposer *composer) { GtkhtmlEditor *editor; - GtkWidget *widget; - guint attachment_num; - - editor = GTKHTML_EDITOR (composer); - attachment_num = e_attachment_bar_get_num_attachments (attachment_bar); - - if (attachment_num > 0) { - gchar *markup; - - markup = g_strdup_printf ( - "%d %s", attachment_num, ngettext ( - "Attachment", "Attachments", attachment_num)); - widget = composer->priv->attachment_expander_num; - gtk_label_set_markup (GTK_LABEL (widget), markup); - g_free (markup); - - gtk_widget_show (composer->priv->attachment_expander_icon); - - widget = composer->priv->attachment_expander; - gtk_expander_set_expanded (GTK_EXPANDER (widget), TRUE); - } else { - widget = composer->priv->attachment_expander_num; - gtk_label_set_text (GTK_LABEL (widget), ""); - - gtk_widget_hide (composer->priv->attachment_expander_icon); - - widget = composer->priv->attachment_expander; - gtk_expander_set_expanded (GTK_EXPANDER (widget), FALSE); - } /* Mark the editor as changed so it prompts about unsaved - changes on close. */ + * changes on close. */ + editor = GTKHTML_EDITOR (composer); gtkhtml_editor_set_changed (editor, TRUE); } -static gint -attachment_bar_key_press_event_cb (EAttachmentBar *attachment_bar, - GdkEventKey *event) -{ - if (event->keyval == GDK_Delete) { - e_attachment_bar_remove_selected (attachment_bar); - return TRUE; - } - - return FALSE; -} - -static gboolean -attachment_bar_popup_menu_cb (EAttachmentBar *attachment_bar) -{ - emcab_popup (attachment_bar, NULL, -1); - - return TRUE; -} - -static void -attachment_expander_notify_cb (GtkExpander *expander, - GParamSpec *pspec, - EMsgComposer *composer) -{ - GtkLabel *label; - const gchar *text; - - label = GTK_LABEL (composer->priv->attachment_expander_label); - - /* Update the expander label */ - if (gtk_expander_get_expanded (expander)) - text = _("Hide _Attachment Bar"); - else - text = _("Show _Attachment Bar"); - - gtk_label_set_text_with_mnemonic (label, text); -} - static void msg_composer_subject_changed_cb (EMsgComposer *composer) { @@ -1764,35 +1539,6 @@ msg_composer_account_list_changed_cb (EMsgComposer *composer) g_object_unref (iterator); } -static void -msg_composer_attach_message (EMsgComposer *composer, - CamelMimeMessage *msg) -{ - CamelMimePart *mime_part; - GString *description; - const gchar *subject; - EMsgComposerPrivate *p = composer->priv; - - mime_part = camel_mime_part_new (); - camel_mime_part_set_disposition (mime_part, "inline"); - subject = camel_mime_message_get_subject (msg); - - description = g_string_new (_("Attached message")); - if (subject != NULL) - g_string_append_printf (description, " - %s", subject); - camel_mime_part_set_description (mime_part, description->str); - g_string_free (description, TRUE); - - camel_medium_set_content_object ( - (CamelMedium *) mime_part, (CamelDataWrapper *) msg); - camel_mime_part_set_content_type (mime_part, "message/rfc822"); - - e_attachment_bar_attach_mime_part ( - E_ATTACHMENT_BAR (p->attachment_bar), mime_part); - - camel_object_unref (mime_part); -} - static void msg_composer_update_preferences (GConfClient *client, guint cnxn_id, @@ -1849,17 +1595,7 @@ struct _drop_data { unsigned int aborted:1; }; -int -e_msg_composer_get_remote_download_count (EMsgComposer *composer) -{ - EAttachmentBar *attachment_bar; - - g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), 0); - - attachment_bar = E_ATTACHMENT_BAR (composer->priv->attachment_bar); - return e_attachment_bar_get_download_count (attachment_bar); -} - +#if 0 /* FIXME */ static void drop_action (EMsgComposer *composer, GdkDragContext *context, @@ -2033,55 +1769,7 @@ drop_action (EMsgComposer *composer, gtk_drag_finish (context, success, delete, time); } - -static void -drop_popup_copy (EPopup *ep, EPopupItem *item, gpointer data) -{ - struct _drop_data *m = data; - - drop_action ( - m->composer, m->context, GDK_ACTION_COPY, - m->selection, m->info, m->time, FALSE); -} - -static void -drop_popup_move (EPopup *ep, EPopupItem *item, gpointer data) -{ - struct _drop_data *m = data; - - drop_action ( - m->composer, m->context, GDK_ACTION_MOVE, - m->selection, m->info, m->time, FALSE); -} - -static void -drop_popup_cancel (EPopup *ep, EPopupItem *item, gpointer data) -{ - struct _drop_data *m = data; - - gtk_drag_finish (m->context, FALSE, FALSE, m->time); -} - -static EPopupItem drop_popup_menu[] = { - { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), drop_popup_copy, NULL, "mail-copy", 0 }, - { E_POPUP_ITEM, "00.emc.03", N_("_Move"), drop_popup_move, NULL, "mail-move", 0 }, - { E_POPUP_BAR, "10.emc" }, - { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), drop_popup_cancel, NULL, NULL, 0 }, -}; - -static void -drop_popup_free (EPopup *ep, GSList *items, gpointer data) -{ - struct _drop_data *m = data; - - g_slist_free (items); - - g_object_unref (m->context); - g_object_unref (m->composer); - g_free (m->selection->data); - g_free (m->selection); - g_free (m); -} +#endif static void msg_composer_notify_header_cb (EMsgComposer *composer) @@ -2341,33 +2029,14 @@ msg_composer_drag_motion (GtkWidget *widget, gint y, guint time) { - GList *targets; - GdkDragAction actions = 0; - GdkDragAction chosen_action; - - targets = context->targets; - while (targets != NULL) { - gint ii; - - for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) - if (targets->data == (gpointer) drag_info[ii].atom) - actions |= drag_info[ii].actions; - - targets = g_list_next (targets); - } - - actions &= context->actions; - chosen_action = context->suggested_action; - - /* we default to copy */ - if (chosen_action == GDK_ACTION_ASK && - (actions & (GDK_ACTION_MOVE|GDK_ACTION_COPY)) != - (GDK_ACTION_MOVE|GDK_ACTION_COPY)) - chosen_action = GDK_ACTION_COPY; + EMsgComposer *composer; + EAttachmentView *view; - gdk_drag_status (context, chosen_action, time); + /* Widget may be EMsgComposer or GtkHTML. */ + composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget)); + view = e_msg_composer_get_attachment_view (composer); - return (chosen_action != 0); + return e_attachment_view_drag_motion (view, context, x, y, time); } static void @@ -2380,46 +2049,19 @@ msg_composer_drag_data_received (GtkWidget *widget, guint time) { EMsgComposer *composer; + EAttachmentView *view; /* Widget may be EMsgComposer or GtkHTML. */ composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (widget)); - - if (selection->data == NULL) - return; - - if (selection->length == -1) - return; - - if (context->action == GDK_ACTION_ASK) { - EMPopup *emp; - GSList *menus = NULL; - GtkMenu *menu; - gint ii; - struct _drop_data *m; - - m = g_malloc0(sizeof (*m)); - m->context = g_object_ref (context); - m->composer = g_object_ref (composer); - m->action = context->action; - m->info = info; - m->time = time; - m->selection = g_malloc0(sizeof (*m->selection)); - m->selection->data = g_malloc (selection->length); - memcpy (m->selection->data, selection->data, selection->length); - m->selection->length = selection->length; - - emp = em_popup_new ("org.gnome.evolution.mail.composer.popup.drop"); - for (ii = 0; ii < G_N_ELEMENTS (drop_popup_menu); ii++) - menus = g_slist_append (menus, &drop_popup_menu[ii]); - - e_popup_add_items ((EPopup *)emp, menus, NULL, drop_popup_free, m); - menu = e_popup_create_menu_once ((EPopup *)emp, NULL, 0); - gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, time); - } else { - drop_action ( - composer, context, context->action, selection, - info, time, !GTK_WIDGET_TOPLEVEL (widget)); - } + view = e_msg_composer_get_attachment_view (composer); + + /* Forward the data to the attachment view. Note that calling + * e_attachment_view_drag_data_received() will not work because + * that function only handles the case where all the other drag + * handlers have failed. */ + e_attachment_paned_drag_data_received ( + E_ATTACHMENT_PANED (view), + context, x, y, selection, info, time); } static void @@ -2466,11 +2108,20 @@ static void msg_composer_paste_clipboard (GtkhtmlEditor *editor) { EMsgComposer *composer; + EAttachmentView *view; + EAttachmentStore *store; + GtkClipboard *clipboard; + GdkPixbuf *pixbuf; GtkWidget *parent; GtkWidget *widget; - GtkClipboard *clipboard; + gchar *filename; + gchar *uri; + GError *error = NULL; composer = E_MSG_COMPOSER (editor); + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); + widget = gtk_window_get_focus (GTK_WINDOW (editor)); parent = gtk_widget_get_parent (widget); @@ -2480,36 +2131,63 @@ msg_composer_paste_clipboard (GtkhtmlEditor *editor) } clipboard = gtk_widget_get_clipboard (widget, GDK_SELECTION_CLIPBOARD); - if (clipboard && gtk_clipboard_wait_is_image_available (clipboard)) { - GdkPixbuf *pixbuf; - - pixbuf = gtk_clipboard_wait_for_image (clipboard); - if (pixbuf) { - char *tmpl = g_strconcat (_("Image"), "-XXXXXX", NULL); - char *filename = e_mktemp (tmpl); - - g_free (tmpl); - - if (filename && gdk_pixbuf_save (pixbuf, filename, "png", NULL, NULL)) { - if (gtkhtml_editor_get_html_mode (editor)) { - char *uri = g_strconcat ("file://", filename, NULL); - /* this loads image async, thus cannot remove file from this */ - gtkhtml_editor_insert_image (editor, uri); - g_free (uri); - } else { - /* this loads image immediately, remove file from cache to free up disk space */ - e_attachment_bar_attach (E_ATTACHMENT_BAR (composer->priv->attachment_bar), filename, "image/png"); - g_remove (filename); - } - } - g_free (filename); - g_object_unref (pixbuf); - } - } else { - /* Chain up to parent's paste_clipboard() method. */ - GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor); + /* Assume the clipboard has an image. The return + * value will be NULL we we assumed wrong. */ + pixbuf = gtk_clipboard_wait_for_image (clipboard); + if (!GDK_IS_PIXBUF (pixbuf)) + goto chainup; + + /* Reserve a temporary file. */ + filename = e_mktemp (NULL); + if (filename == NULL) { + g_warning ("%s", g_strerror (errno)); + g_object_unref (pixbuf); + g_error_free (error); + return; + } + + /* Save the pixbuf as a temporary file in image/png format. */ + if (!gdk_pixbuf_save (pixbuf, filename, "png", &error, NULL)) { + g_warning ("%s", error->message); + g_object_unref (pixbuf); + g_error_free (error); + g_free (filename); + return; + } + + /* Convert the filename to a URI. */ + uri = g_filename_to_uri (filename, NULL, &error); + if (error != NULL) { + g_warning ("%s", error->message); + g_object_unref (pixbuf); + g_error_free (error); + g_free (filename); + return; } + + if (gtkhtml_editor_get_html_mode (editor)) + gtkhtml_editor_insert_image (editor, uri); + else { + EAttachment *attachment; + + attachment = e_attachment_new_for_uri (uri); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, composer); + g_object_unref (attachment); + } + + g_object_unref (pixbuf); + g_free (filename); + g_free (uri); + + return; + +chainup: + /* Chain up to parent's paste_clipboard() method. */ + GTKHTML_EDITOR_CLASS (parent_class)->paste_clipboard (editor); } static void @@ -2733,11 +2411,6 @@ msg_composer_class_init (EMsgComposerClass *class) GtkObjectClass *gtk_object_class; GtkWidgetClass *widget_class; GtkhtmlEditorClass *editor_class; - gint ii; - - for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) - drag_info[ii].atom = - gdk_atom_intern (drag_info[ii].target, FALSE); parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EMsgComposerPrivate)); @@ -2789,10 +2462,16 @@ msg_composer_class_init (EMsgComposerClass *class) static void msg_composer_init (EMsgComposer *composer) { + EAttachmentView *view; + EAttachmentStore *store; EComposerHeaderTable *table; + GdkDragAction drag_actions; + GtkTargetList *target_list; + GtkTargetEntry *targets; GtkUIManager *manager; GtkhtmlEditor *editor; GtkHTML *html; + gint n_targets; composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer); @@ -2801,6 +2480,7 @@ msg_composer_init (EMsgComposer *composer) editor = GTKHTML_EDITOR (composer); html = gtkhtml_editor_get_html (editor); manager = gtkhtml_editor_get_ui_manager (editor); + view = e_msg_composer_get_attachment_view (composer); all_composers = g_slist_prepend (all_composers, composer); table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table); @@ -2809,36 +2489,21 @@ msg_composer_init (EMsgComposer *composer) /* Drag-and-Drop Support */ - gtk_drag_dest_set ( - GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL, - drop_types, G_N_ELEMENTS (drop_types), - GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE); + target_list = e_attachment_view_get_target_list (view); + drag_actions = e_attachment_view_get_drag_actions (view); - /* XXX I'm not sure why we have to explicitly configure the - * attachment bar as a drag destination when CompEditor - * doesn't and previous Evolution releases (2.22 and - * prior) don't, but this is the only way I could figure - * out how to get drag-and-drop to the attachment bar - * working again. I'm probably overlooking something - * simple... */ + targets = gtk_target_table_new_from_list (target_list, &n_targets); gtk_drag_dest_set ( - composer->priv->attachment_bar, GTK_DEST_DEFAULT_ALL, - drop_types, G_N_ELEMENTS (drop_types), - GDK_ACTION_COPY | GDK_ACTION_ASK | GDK_ACTION_MOVE); - - g_signal_connect ( - composer->priv->attachment_bar, "drag-motion", - G_CALLBACK (msg_composer_drag_motion), NULL); - - g_signal_connect ( - composer->priv->attachment_bar, "drag-data-received", - G_CALLBACK (msg_composer_drag_data_received), NULL); + GTK_WIDGET (composer), GTK_DEST_DEFAULT_ALL, + targets, n_targets, drag_actions); g_signal_connect ( html, "drag-data-received", G_CALLBACK (msg_composer_drag_data_received), NULL); + gtk_target_table_free (targets, n_targets); + /* Configure Headers */ e_composer_header_table_set_account_list ( @@ -2877,23 +2542,17 @@ msg_composer_init (EMsgComposer *composer) msg_composer_account_changed_cb (composer); msg_composer_account_list_changed_cb (composer); - /* Attachment Bar */ + /* Attachments */ - g_signal_connect ( - composer->priv->attachment_bar, "button_press_event", - G_CALLBACK (attachment_bar_button_press_event_cb), NULL); - g_signal_connect ( - composer->priv->attachment_bar, "key_press_event", - G_CALLBACK (attachment_bar_key_press_event_cb), NULL); - g_signal_connect ( - composer->priv->attachment_bar, "popup-menu", - G_CALLBACK (attachment_bar_popup_menu_cb), NULL); - g_signal_connect ( - composer->priv->attachment_bar, "changed", - G_CALLBACK (attachment_bar_changed_cb), composer); - g_signal_connect_after ( - composer->priv->attachment_expander, "notify::expanded", - G_CALLBACK (attachment_expander_notify_cb), composer); + store = e_attachment_view_get_store (view); + + g_signal_connect_swapped ( + store, "row-deleted", + G_CALLBACK (attachment_store_changed_cb), composer); + + g_signal_connect_swapped ( + store, "row-inserted", + G_CALLBACK (attachment_store_changed_cb), composer); e_composer_autosave_register (composer); @@ -3738,7 +3397,7 @@ disable_editor (EMsgComposer *composer) action = GTKHTML_EDITOR_ACTION_INSERT_MENU (composer); gtk_action_set_sensitive (action, FALSE); - gtk_widget_set_sensitive (composer->priv->attachment_bar, FALSE); + gtk_widget_set_sensitive (composer->priv->attachment_paned, FALSE); } /** @@ -3837,7 +3496,8 @@ add_recipients (GList *list, const gchar *recips) static void handle_mailto (EMsgComposer *composer, const gchar *mailto) { - EMsgComposerPrivate *priv = composer->priv; + EAttachmentView *view; + EAttachmentStore *store; EComposerHeaderTable *table; GList *to = NULL, *cc = NULL, *bcc = NULL; EDestination **tov, **ccv, **bccv; @@ -3846,9 +3506,10 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto) gsize nread, nwritten; const gchar *p; gint len, clen; - CamelURL *url; table = e_msg_composer_get_header_table (composer); + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); buf = g_strdup (mailto); @@ -3920,20 +3581,18 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto) } } else if (!g_ascii_strcasecmp (header, "attach") || !g_ascii_strcasecmp (header, "attachment")) { - /* Change file url to absolute path */ - if (!g_ascii_strncasecmp (content, "file:", 5)) { - url = camel_url_new (content, NULL); - e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar), - url->path, - "attachment"); - camel_url_free (url); - } else { - e_attachment_bar_attach (E_ATTACHMENT_BAR (priv->attachment_bar), - content, - "attachment"); - } - gtk_widget_show (priv->attachment_expander); - gtk_widget_show (priv->attachment_scrolled_window); + EAttachment *attachment; + + camel_url_decode (content); + if (g_ascii_strncasecmp (content, "file:", 5) == 0) + attachment = e_attachment_new_for_uri (content); + else + attachment = e_attachment_new_for_path (content); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, composer); + g_object_unref (attachment); } else if (!g_ascii_strcasecmp (header, "from")) { /* Ignore */ } else if (!g_ascii_strcasecmp (header, "reply-to")) { @@ -3985,45 +3644,6 @@ handle_mailto (EMsgComposer *composer, const gchar *mailto) } } -static void -handle_uri (EMsgComposer *composer, - const gchar *uri, - gboolean html_dnd) -{ - EMsgComposerPrivate *p = composer->priv; - GtkhtmlEditor *editor; - gboolean html_content; - - editor = GTKHTML_EDITOR (composer); - html_content = gtkhtml_editor_get_html_mode (editor); - - if (!g_ascii_strncasecmp (uri, "mailto:", 7)) { - handle_mailto (composer, uri); - } else { - CamelURL *url = camel_url_new (uri, NULL); - gchar *type; - - if (!url) - return; - - if (!g_ascii_strcasecmp (url->protocol, "file")) { - type = e_util_guess_mime_type (uri + strlen ("file://"), TRUE); - if (!type) - return; - - if (strncmp (type, "image", 5) || !html_dnd || (!html_content && !strncmp (type, "image", 5))) { - e_attachment_bar_attach (E_ATTACHMENT_BAR (p->attachment_bar), - url->path, "attachment"); - } - g_free (type); - } else { - e_attachment_bar_attach_remote_file (E_ATTACHMENT_BAR (p->attachment_bar), - uri, "attachment"); - } - camel_url_free (url); - } -} - /** * e_msg_composer_new_from_url: * @url: a mailto URL @@ -4187,21 +3807,31 @@ e_msg_composer_remove_header (EMsgComposer *composer, /** * e_msg_composer_attach: * @composer: a composer object - * @attachment: the CamelMimePart to attach + * @mime_part: the #CamelMimePart to attach * * Attaches @attachment to the message being composed in the composer. **/ void -e_msg_composer_attach (EMsgComposer *composer, CamelMimePart *attachment) +e_msg_composer_attach (EMsgComposer *composer, + CamelMimePart *mime_part) { - EAttachmentBar *bar; - EMsgComposerPrivate *p = composer->priv; + EAttachmentView *view; + EAttachmentStore *store; + EAttachment *attachment; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - g_return_if_fail (CAMEL_IS_MIME_PART (attachment)); - - bar = E_ATTACHMENT_BAR (p->attachment_bar); - e_attachment_bar_attach_mime_part (bar, attachment); + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); + + attachment = e_attachment_new (); + e_attachment_set_mime_part (attachment, mime_part); + e_attachment_store_add_attachment (store, attachment); + e_attachment_load_async ( + attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, composer); + g_object_unref (attachment); } /** @@ -4315,12 +3945,17 @@ CamelMimeMessage * e_msg_composer_get_message (EMsgComposer *composer, gboolean save_html_object_data) { + EAttachmentView *view; + EAttachmentStore *store; GtkhtmlEditor *editor; gboolean html_content; g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); - if (e_msg_composer_get_remote_download_count (composer) != 0) { + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); + + if (e_attachment_store_get_num_loading (store) > 0) { if (!em_utils_prompt_user (GTK_WINDOW (composer), NULL, "mail-composer:ask-send-message-pending-download", NULL)) { return NULL; @@ -4623,14 +4258,6 @@ e_msg_composer_get_raw_message_text (EMsgComposer *composer) return array; } -EAttachmentBar * -e_msg_composer_get_attachment_bar (EMsgComposer *composer) -{ - g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); - - return E_ATTACHMENT_BAR (composer->priv->attachment_bar); -} - void e_msg_composer_set_enable_autosave (EMsgComposer *composer, gboolean enabled) @@ -4794,6 +4421,14 @@ e_msg_composer_get_header_table (EMsgComposer *composer) return E_COMPOSER_HEADER_TABLE (composer->priv->header_table); } +EAttachmentView * +e_msg_composer_get_attachment_view (EMsgComposer *composer) +{ + g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); + + return E_ATTACHMENT_VIEW (composer->priv->attachment_paned); +} + void e_msg_composer_set_send_options (EMsgComposer *composer, gboolean send_enable) diff --git a/composer/e-msg-composer.h b/composer/e-msg-composer.h index f6b2ca7cc0..54520ec941 100644 --- a/composer/e-msg-composer.h +++ b/composer/e-msg-composer.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "e-composer-header-table.h" @@ -100,7 +101,7 @@ void e_msg_composer_modify_header (EMsgComposer *composer, void e_msg_composer_remove_header (EMsgComposer *composer, const gchar *name); void e_msg_composer_attach (EMsgComposer *composer, - CamelMimePart *attachment); + CamelMimePart *mime_part); CamelMimePart * e_msg_composer_add_inline_image_from_file (EMsgComposer *composer, const gchar *filename); @@ -139,22 +140,19 @@ void e_msg_composer_add_message_attachments gboolean e_msg_composer_request_close_all(void); EMsgComposer * e_msg_composer_load_from_file (const gchar *filename); void e_msg_composer_check_autosave (GtkWindow *parent); -gint e_msg_composer_get_remote_download_count - (EMsgComposer *composer); void e_msg_composer_reply_indent (EMsgComposer *composer); EComposerHeaderTable * e_msg_composer_get_header_table (EMsgComposer *composer); +EAttachmentView * + e_msg_composer_get_attachment_view + (EMsgComposer *composer); void e_msg_composer_set_send_options (EMsgComposer *composer, gboolean send_enable); GByteArray * e_msg_composer_get_raw_message_text (EMsgComposer *composer); -struct _EAttachmentBar * - e_msg_composer_get_attachment_bar - (EMsgComposer *composer); - gboolean e_msg_composer_is_exiting (EMsgComposer *composer); GList * e_load_spell_languages (void); diff --git a/configure.in b/configure.in index 462a4e70aa..25956061dd 100644 --- a/configure.in +++ b/configure.in @@ -1775,12 +1775,12 @@ plugins_base_always="calendar-file calendar-http $CALENDAR_WEATHER itip-formatte plugins_base="$plugins_base_always $SA_JUNK_PLUGIN $BF_JUNK_PLUGIN $EXCHANGE_PLUGIN $MONO_PLUGIN " all_plugins_base="$plugins_base_always sa-junk-plugin bogo-junk-plugin exchange-operations mono" -plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task audio-inline mailing-list-actions default-mailer import-ics-attachments prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates pst-import" +plugins_standard_always="bbdb subject-thread save-calendar select-one-source copy-tool mail-to-task audio-inline mailing-list-actions default-mailer prefer-plain mail-notification attachment-reminder face backup-restore email-custom-header templates pst-import" plugins_standard="$plugins_standard_always" all_plugins_standard="$plugins_standard" -plugins_experimental_always="folder-unsubscribe save-attachments external-editor hula-account-setup" +plugins_experimental_always="folder-unsubscribe external-editor hula-account-setup" plugins_experimental="$plugins_experimental_always $IPOD_SYNC $TNEF_ATTACHMENTS $PYTHON_PLUGIN" all_plugins_experimental="$plugins_experimental_always ipod-sync tnef-attachments" @@ -2080,7 +2080,6 @@ plugins/mail-notification/Makefile plugins/mail-to-task/Makefile plugins/mono/Makefile plugins/subject-thread/Makefile -plugins/save-attachments/Makefile plugins/save-calendar/Makefile plugins/select-one-source/Makefile plugins/prefer-plain/Makefile @@ -2105,7 +2104,6 @@ plugins/sa-junk-plugin/Makefile plugins/bogo-junk-plugin/Makefile plugins/ipod-sync/Makefile plugins/publish-calendar/Makefile -plugins/import-ics-attachments/Makefile plugins/imap-features/Makefile plugins/tnef-attachments/Makefile plugins/templates/Makefile diff --git a/e-util/e-util.c b/e-util/e-util.c index 0b28404c82..c012b267d5 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -185,6 +185,183 @@ exit: g_string_free (uri, TRUE); } +/** + * e_lookup_action: + * @ui_manager: a #GtkUIManager + * @action_name: the name of an action + * + * Returns the first #GtkAction named @action_name by traversing the + * list of action groups in @ui_manager. If no such action exists, the + * function emits a critical warning before returning %NULL, since this + * probably indicates a programming error and most code is not prepared + * to deal with lookup failures. + * + * Returns: the first #GtkAction named @action_name + **/ +GtkAction * +e_lookup_action (GtkUIManager *ui_manager, + const gchar *action_name) +{ + GtkAction *action = NULL; + GList *iter; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + iter = gtk_ui_manager_get_action_groups (ui_manager); + + while (iter != NULL) { + GtkActionGroup *action_group = iter->data; + + action = gtk_action_group_get_action ( + action_group, action_name); + if (action != NULL) + return action; + + iter = g_list_next (iter); + } + + g_critical ("%s: action `%s' not found", G_STRFUNC, action_name); + + return NULL; +} + +/** + * e_lookup_action_group: + * @ui_manager: a #GtkUIManager + * @group_name: the name of an action group + * + * Returns the #GtkActionGroup in @ui_manager named @group_name. If no + * such action group exists, the function emits a critical warnings before + * returning %NULL, since this probably indicates a programming error and + * most code is not prepared to deal with lookup failures. + * + * Returns: the #GtkActionGroup named @group_name + **/ +GtkActionGroup * +e_lookup_action_group (GtkUIManager *ui_manager, + const gchar *group_name) +{ + GList *iter; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + g_return_val_if_fail (group_name != NULL, NULL); + + iter = gtk_ui_manager_get_action_groups (ui_manager); + + while (iter != NULL) { + GtkActionGroup *action_group = iter->data; + const gchar *name; + + name = gtk_action_group_get_name (action_group); + if (strcmp (name, group_name) == 0) + return action_group; + + iter = g_list_next (iter); + } + + g_critical ("%s: action group `%s' not found", G_STRFUNC, group_name); + + return NULL; +} + +/** + * e_load_ui_definition: + * @ui_manager: a #GtkUIManager + * @basename: basename of the UI definition file + * + * Loads a UI definition into @ui_manager from Evolution's UI directory. + * Failure here is fatal, since the application can't function without + * its UI definitions. + * + * Returns: The merge ID for the merged UI. The merge ID can be used to + * unmerge the UI with gtk_ui_manager_remove_ui(). + **/ +guint +e_load_ui_definition (GtkUIManager *ui_manager, + const gchar *basename) +{ + gchar *filename; + guint merge_id; + GError *error = NULL; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0); + g_return_val_if_fail (basename != NULL, 0); + + filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); + merge_id = gtk_ui_manager_add_ui_from_file ( + ui_manager, filename, &error); + g_free (filename); + + if (error != NULL) { + g_error ("%s: %s", basename, error->message); + g_assert_not_reached (); + } + + return merge_id; +} + +/** + * e_action_compare_by_label: + * @action1: a #GtkAction + * @action2: a #GtkAction + * + * Compares the labels for @action1 and @action2 using g_utf8_collate(). + * + * Returns: < 0 if @action1 compares before @action2, 0 if they + * compare equal, > 0 if @action1 compares after @action2 + **/ +gint +e_action_compare_by_label (GtkAction *action1, + GtkAction *action2) +{ + gchar *label1; + gchar *label2; + gint result; + + /* XXX This is horribly inefficient but will generally only be + * used on short lists of actions during UI construction. */ + + if (action1 == action2) + return 0; + + g_object_get (action1, "label", &label1, NULL); + g_object_get (action2, "label", &label2, NULL); + + result = g_utf8_collate (label1, label2); + + g_free (label1); + g_free (label2); + + return result; +} + +/** + * e_action_group_remove_all_actions: + * @action_group: a #GtkActionGroup + * + * Removes all actions from the action group. + **/ +void +e_action_group_remove_all_actions (GtkActionGroup *action_group) +{ + GList *list, *iter; + + /* XXX I've proposed this function for inclusion in GTK+. + * GtkActionGroup stores actions in an internal hash + * table and can do this more efficiently by calling + * g_hash_table_remove_all(). + * + * http://bugzilla.gnome.org/show_bug.cgi?id=550485 */ + + g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); + + list = gtk_action_group_list_actions (action_group); + for (iter = list; iter != NULL; iter = iter->next) + gtk_action_group_remove_action (action_group, iter->data); + g_list_free (list); +} + /** * e_str_without_underscores: * @s: the string to strip underscores from. @@ -1321,3 +1498,33 @@ e_util_get_category_filter_options (void) return g_slist_reverse (res); } + +static gpointer +e_camel_object_copy (gpointer camel_object) +{ + if (CAMEL_IS_OBJECT (camel_object)) + camel_object_ref (camel_object); + + return camel_object; +} + +static void +e_camel_object_free (gpointer camel_object) +{ + if (CAMEL_IS_OBJECT (camel_object)) + camel_object_unref (camel_object); +} + +GType +e_camel_object_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) + type = g_boxed_type_register_static ( + "ECamelObject", + (GBoxedCopyFunc) e_camel_object_copy, + (GBoxedFreeFunc) e_camel_object_free); + + return type; +} diff --git a/e-util/e-util.h b/e-util/e-util.h index 021e3286c7..480da24eac 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,16 @@ void e_show_uri (GtkWindow *parent, const gchar *uri); void e_display_help (GtkWindow *parent, const gchar *link_id); +GtkAction * e_lookup_action (GtkUIManager *ui_manager, + const gchar *action_name); +GtkActionGroup *e_lookup_action_group (GtkUIManager *ui_manager, + const gchar *group_name); +guint e_load_ui_definition (GtkUIManager *ui_manager, + const gchar *basename); +gint e_action_compare_by_label (GtkAction *action1, + GtkAction *action2); +void e_action_group_remove_all_actions + (GtkActionGroup *action_group); char * e_str_without_underscores (const char *s); gint e_str_compare (gconstpointer x, @@ -130,6 +141,11 @@ gboolean e_util_read_file (const gchar *filename, GSList *e_util_get_category_filter_options (void); +/* Camel uses its own object system, so we have to box + * CamelObjects to safely use them as GObject properties. */ +#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ()) +GType e_camel_object_get_type (void); + G_END_DECLS #endif /* _E_UTIL_H_ */ diff --git a/mail/Makefile.am b/mail/Makefile.am index 23778d569c..2a567ec042 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -54,6 +54,7 @@ idl_DATA = $(MAIL_IDL) # plugin mail api mailinclude_HEADERS = \ $(MAIL_IDL_GENERATED_H) \ + e-mail-attachment-bar.h \ em-composer-utils.h \ em-config.h \ em-event.h \ @@ -93,6 +94,9 @@ mailinclude_HEADERS = \ libevolution_mail_la_SOURCES = \ $(MAIL_IDL_GENERATED) \ $(mailinclude_HEADERS) \ + e-attachment-handler-mail.c \ + e-attachment-handler-mail.h \ + e-mail-attachment-bar.c \ e-searching-tokenizer.c \ e-searching-tokenizer.h \ em-account-editor.c \ diff --git a/mail/em-filter-i18n.h b/mail/em-filter-i18n.h index 8b8d0c3323..c0b2925cc2 100644 --- a/mail/em-filter-i18n.h +++ b/mail/em-filter-i18n.h @@ -26,6 +26,7 @@ char *s = N_("Exist"); char *s = N_("exists"); char *s = N_("Expression"); char *s = N_("Follow Up"); +char *s = N_("Forward to"); char *s = N_("Important"); char *s = N_("is"); char *s = N_("is after"); @@ -46,6 +47,7 @@ char *s = N_("Message Body"); char *s = N_("Message Header"); char *s = N_("Message is Junk"); char *s = N_("Message is not Junk"); +char *s = N_("Message Location"); char *s = N_("Move to Folder"); char *s = N_("Pipe to Program"); char *s = N_("Play Sound"); diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index ad72ee8bdd..789705879d 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -80,14 +80,15 @@ #include "mail-config.h" +#include "e-mail-attachment-bar.h" #include "em-format-html-display.h" #include "e-searching-tokenizer.h" #include "em-icon-stream.h" #include "em-utils.h" #include "em-popup.h" -#include "e-attachment.h" -#include "e-attachment-bar.h" #include "e-icon-entry.h" +#include "widgets/misc/e-attachment-button.h" +#include "widgets/misc/e-attachment-view.h" #ifdef G_OS_WIN32 /* Undefine the similar macro from ,it doesn't check if @@ -113,18 +114,7 @@ struct _EMFormatHTMLDisplayPrivate { int search_wrap; /* are we doing a wrap search */ gboolean search_active; /* if the search is active */ - /* for Attachment bar */ - GtkWidget *attachment_bar; - GtkWidget *attachment_box; - GtkWidget *label; - GtkWidget *save_txt; - GtkWidget *arrow; - GtkWidget *forward; - GtkWidget *down; - GtkWidget *attachment_area; - gboolean show_bar; - GHashTable *files; - gboolean updated; + GtkWidget *attachment_view; /* weak reference */ }; static int efhd_html_button_press_event (GtkWidget *widget, GdkEventButton *event, EMFormatHTMLDisplay *efh); @@ -134,8 +124,6 @@ static void efhd_html_on_url (GtkHTML *html, const char *url, EMFormatHTMLDispla static void efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri); static gboolean efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); static void efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); -static void efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info); -static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd); struct _attach_puri { EMFormatPURI puri; @@ -186,7 +174,6 @@ static void efhd_format_attachment(EMFormat *, CamelStream *, CamelMimePart *, c static void efhd_format_optional(EMFormat *, CamelStream *, CamelMimePart *, CamelStream *); static void efhd_format_secure(EMFormat *emf, CamelStream *stream, CamelMimePart *part, CamelCipherValidity *valid); static void efhd_complete(EMFormat *); -gboolean efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd); static gboolean efhd_bonobo_object(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); static gboolean efhd_use_component(const char *mime_type); @@ -279,9 +266,6 @@ efhd_init(GObject *o) #undef efh efhd->nobar = getenv("EVOLUTION_NO_BAR") != NULL; - - efhd->priv->show_bar = FALSE; - efhd->priv->files = NULL; } static void @@ -291,9 +275,6 @@ efhd_finalise(GObject *o) /* check pending stuff */ - if (efhd->priv->files) - g_hash_table_destroy(efhd->priv->files); - g_free(efhd->priv->search_text); g_free(efhd->priv); @@ -431,12 +412,6 @@ void em_format_html_display_set_caret_mode(EMFormatHTMLDisplay *efhd, gboolean s gtk_html_set_caret_mode(((EMFormatHTML *)efhd)->html, state); } -EAttachmentBar * -em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd) -{ - return E_ATTACHMENT_BAR (efhd->priv->attachment_bar); -} - void em_format_html_display_set_search(EMFormatHTMLDisplay *efhd, int type, GSList *strings) { @@ -933,11 +908,6 @@ efhd_complete(EMFormat *emf) if (efhd->priv->search_dialog && efhd->priv->search_active) efhd_update_matches(efhd); - - if (efhd->priv->files) { - g_hash_table_destroy (efhd->priv->files); - efhd->priv->files = NULL; - } } /* ********************************************************************** */ @@ -1293,9 +1263,7 @@ static EMFormatHandler type_builtin_table[] = { { "image/pjpeg", (EMFormatFunc)efhd_image }, { "x-evolution/message/prefix", (EMFormatFunc)efhd_message_prefix }, - { "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar }, - { "x-evolution/message/post-header-closure", (EMFormatFunc)efhd_message_update_bar }, - + { "x-evolution/message/post-header", (EMFormatFunc)efhd_message_add_bar } }; static void @@ -1343,15 +1311,8 @@ static const EMFormatHandler *efhd_find_handler(EMFormat *emf, const char *mime_ static void efhd_format_clone(EMFormat *emf, CamelFolder *folder, const char *uid, CamelMimeMessage *msg, EMFormat *src) { - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; - - if (emf != src) { - if (src) - efhd->priv->show_bar = ((EMFormatHTMLDisplay *)src)->priv->show_bar; - else - efhd->priv->show_bar = FALSE; + if (emf != src) ((EMFormatHTML *) emf)->header_wrap_flags = 0; - } ((EMFormatClass *)efhd_parent)->format_clone(emf, folder, uid, msg, src); } @@ -1467,12 +1428,14 @@ efhd_attachment_show(EPopup *ep, EPopupItem *item, void *data) } static void -efhd_attachment_button_show(GtkWidget *w, void *data) +efhd_attachment_button_expanded (GtkWidget *widget, + GParamSpec *pspec, + struct _attach_puri *info) { - if (!efhd_can_process_attachment (w)) + if (!efhd_can_process_attachment (widget)) return; - efhd_attachment_show(NULL, NULL, data); + efhd_attachment_show (NULL, NULL, info); } static void @@ -1811,16 +1774,12 @@ static gboolean efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) { EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; - EAttachment *new; struct _attach_puri *info; - GtkWidget *hbox, *w, *button, *mainbox; - char *simple_type, *tmp, *new_file = NULL; - const char *file; - GtkTargetEntry drag_types[] = { - { NULL, 0, 0 }, - { "text/uri-list", 0, 1 }, - }; - AtkObject *a11y; + EAttachmentView *view; + EAttachmentStore *store; + EAttachment *attachment; + GtkWidget *widget; + gpointer parent; /* FIXME: handle default shown case */ d(printf("adding attachment button/content\n")); @@ -1832,139 +1791,36 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje return TRUE; } - if (efhd->priv->attachment_bar) { - file = camel_mime_part_get_filename(info->puri.part); - - new = info->attachment; - - if (!file) { - file = "attachment.dat"; - new->file_name = g_strdup(file); - } - - tmp = g_hash_table_lookup (efhd->priv->files, file); - if (tmp) { - guint count = GPOINTER_TO_UINT(tmp); - char *ext; - char *tmp_file = g_strdup (file); - - if ((ext = strrchr(tmp_file, '.'))) { - ext[0] = 0; - new_file = g_strdup_printf("%s(%d).%s", tmp_file, count++, ext+1); - } else { - new_file = g_strdup_printf("%s(%d)", tmp_file, count++); - } - - g_free (tmp_file); - g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(count)); - g_free (new->file_name); - new->file_name = new_file; - } else { - g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1)); - } - - /* Store the status of encryption / signature on the attachment for emblem display - * FIXME: May not work well always - */ - new->sign = info->sign; - new->encrypt = info->encrypt; - - /* Add the attachment to the bar.*/ - e_attachment_bar_add_attachment_silent (E_ATTACHMENT_BAR(efhd->priv->attachment_bar), new); - efhd_attachment_bar_refresh(efhd); - } - - mainbox = gtk_hbox_new(FALSE, 0); - - button = gtk_button_new(); - - if (info->handle) { - g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_button_show), info); - g_object_set_data (G_OBJECT (button), "efh", efh); - } else { - gtk_widget_set_sensitive(button, FALSE); - GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); - } - - hbox = gtk_hbox_new(FALSE, 2); - info->forward = gtk_image_new_from_stock(GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start((GtkBox *)hbox, info->forward, TRUE, TRUE, 0); - if (info->handle) { - info->down = gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON); - gtk_box_pack_start((GtkBox *)hbox, info->down, TRUE, TRUE, 0); - } - - w = gtk_image_new(); - gtk_widget_set_size_request(w, 24, 24); - gtk_box_pack_start((GtkBox *)hbox, w, TRUE, TRUE, 0); - gtk_container_add((GtkContainer *)button, hbox); - gtk_box_pack_start((GtkBox *)mainbox, button, TRUE, TRUE, 0); - - /* Check for snooped type to get the right icon/processing */ - if (info->snoop_mime_type) - simple_type = g_strdup(info->snoop_mime_type); - else - simple_type = camel_content_type_simple (((CamelDataWrapper *)pobject->part)->mime_type); - camel_strdown(simple_type); - - /* FIXME: offline parts, just get icon */ - if (camel_content_type_is(((CamelDataWrapper *)pobject->part)->mime_type, "image", "*")) { - EMFormatHTMLJob *job; - GdkPixbuf *mini; - char *key; - - key = pobject->classid; - mini = em_icon_stream_get_image(key, 24, 24); - if (mini) { - d(printf("got image from cache '%s'\n", key)); - gtk_image_set_from_pixbuf((GtkImage *)w, mini); - g_object_unref(mini); - } else { - d(printf("need to create icon image '%s'\n", key)); - job = em_format_html_job_new(efh, efhd_write_icon_job, pobject); - job->stream = (CamelStream *)em_icon_stream_new((GtkImage *)w, key, 24, 24, FALSE); - em_format_html_job_queue(efh, job); - } - } else { - GdkPixbuf *pixbuf, *mini; - - if ((pixbuf = e_icon_for_mime_type (simple_type, 24))) { - if ((mini = e_icon_factory_pixbuf_scale (pixbuf, 24, 24))) { - gtk_image_set_from_pixbuf ((GtkImage *) w, mini); - g_object_unref (mini); - } - g_object_unref (pixbuf); - } - } - - drag_types[0].target = simple_type; - gtk_drag_source_set(button, GDK_BUTTON1_MASK, drag_types, sizeof(drag_types)/sizeof(drag_types[0]), GDK_ACTION_COPY); - g_signal_connect(button, "drag-data-get", G_CALLBACK(efhd_drag_data_get), pobject); - g_signal_connect (button, "drag-data-delete", G_CALLBACK(efhd_drag_data_delete), pobject); - g_free(simple_type); + attachment = info->attachment; + e_attachment_set_shown (attachment, info->shown); + e_attachment_set_signed (attachment, info->sign); + e_attachment_set_encrypted (attachment, info->encrypt); + e_attachment_set_can_show (attachment, info->handle != NULL); - button = gtk_button_new(); - /*GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS);*/ - gtk_container_add((GtkContainer *)button, gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)); + parent = gtk_widget_get_toplevel (GTK_WIDGET (efh->html)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - a11y = gtk_widget_get_accessible (button); - atk_object_set_name (a11y, _("Attachment")); + view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view); + gtk_widget_show (efhd->priv->attachment_view); - g_signal_connect(button, "button_press_event", G_CALLBACK(efhd_attachment_popup), info); - g_signal_connect(button, "popup_menu", G_CALLBACK(efhd_attachment_popup_menu), info); - g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_popup_menu), info); - gtk_box_pack_start((GtkBox *)mainbox, button, TRUE, TRUE, 0); + store = e_attachment_view_get_store (view); + e_attachment_store_add_attachment (store, info->attachment); - g_object_set_data (G_OBJECT (button), "efh", efh); + e_attachment_load_async ( + info->attachment, (GAsyncReadyCallback) + e_attachment_load_handle_error, parent); - gtk_widget_show_all(mainbox); + widget = e_attachment_button_new (view); + e_attachment_button_set_attachment ( + E_ATTACHMENT_BUTTON (widget), attachment); + gtk_container_add (GTK_CONTAINER (eb), widget); + gtk_widget_show (widget); - if (info->shown) - gtk_widget_hide(info->forward); - else if (info->down) - gtk_widget_hide(info->down); + g_object_set_data (G_OBJECT (widget), "efh", efh); - gtk_container_add((GtkContainer *)eb, mainbox); + g_signal_connect ( + widget, "notify::expanded", + G_CALLBACK (efhd_attachment_button_expanded), info); return TRUE; } @@ -2138,330 +1994,57 @@ type_ok: } static void -attachment_bar_arrow_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd) +efhd_bar_resize (EMFormatHTML *efh, + GtkAllocation *event) { + EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh; + GtkWidget *widget; + gint width; - efhd->priv->show_bar = !efhd->priv->show_bar; + widget = GTK_WIDGET (efh->html); + width = widget->allocation.width - 12; - if (efhd->priv->show_bar) { - gtk_widget_show(efhd->priv->attachment_box); - gtk_widget_show(efhd->priv->down); - gtk_widget_hide(efhd->priv->forward); - } else { - gtk_widget_hide(efhd->priv->attachment_box); - gtk_widget_show(efhd->priv->forward); - gtk_widget_hide(efhd->priv->down); + if (width > 0) { + widget = efhd->priv->attachment_view; + gtk_widget_set_size_request (widget, width, -1); } } -static void -attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd) -{ - GSList *attachment_parts; - guint n_attachment_parts; - - attachment_parts = e_attachment_bar_get_parts ( - E_ATTACHMENT_BAR (efhd->priv->attachment_bar)); - n_attachment_parts = g_slist_length (attachment_parts); - g_return_if_fail (n_attachment_parts > 0); - - if (n_attachment_parts == 1) - em_utils_save_part ( - widget, _("Save attachment as"), - attachment_parts->data); - else - em_utils_save_parts ( - widget, _("Select folder to save all attachments"), - attachment_parts); - - g_slist_free (attachment_parts); -} - -static void -efhd_bar_popup_position(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data) -{ - EAttachmentBar *bar = user_data; - GnomeIconList *icon_list = user_data; - GList *selection; - GnomeCanvasPixbuf *image; - - gdk_window_get_origin (((GtkWidget*) bar)->window, x, y); - - selection = gnome_icon_list_get_selection (icon_list); - if (selection == NULL) - return; - - image = gnome_icon_list_get_icon_pixbuf_item (icon_list, GPOINTER_TO_INT(selection->data)); - if (image == NULL) - return; - - /* Put menu to the center of icon. */ - *x += (int)(image->item.x1 + image->item.x2) / 2; - *y += (int)(image->item.y1 + image->item.y2) / 2; -} - -static void -efhd_bar_save_selected(EPopup *ep, EPopupItem *item, void *data) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)data; - GSList *attachment_parts, *tmp; - GSList *parts = NULL; - - attachment_parts = e_attachment_bar_get_selected(E_ATTACHMENT_BAR(efhd->priv->attachment_bar)); - - for (tmp = attachment_parts; tmp; tmp=tmp->next) - parts = g_slist_prepend(parts, ((EAttachment *)tmp->data)->body); - - parts = g_slist_reverse(parts); - em_utils_save_parts(efhd->priv->attachment_bar, _("Select folder to save selected attachments..."), parts); - g_slist_free (parts); - - g_slist_foreach(attachment_parts, (GFunc)g_object_unref, NULL); - g_slist_free (attachment_parts); -} - -static EPopupItem efhd_bar_menu_items[] = { - { E_POPUP_BAR, "05.display", }, - { E_POPUP_ITEM, "05.display.01", N_("_Save Selected..."), efhd_bar_save_selected, NULL, NULL, EM_POPUP_ATTACHMENTS_MULTIPLE}, -}; - -static gboolean -efhd_bar_button_press_event(EAttachmentBar *bar, GdkEventButton *event, EMFormat *emf) -{ - GtkMenu *menu; - GSList *list=NULL; - EPopupTarget *target; - EMPopup *emp; - GSList *menus = NULL; - int i; - - if (event && event->button != 3) - return FALSE; - - /** @HookPoint-EMPopup: Attachment Bar Context Menu - * @Id: org.gnome.evolution.mail.attachments.popup - * @Class: org.gnome.evolution.mail.popup:1.0 - * @Target: EMPopupTargetPart - * - * This is the drop-down menu shown when a user clicks on the attachment bar - * when attachments are selected. - */ - emp = em_popup_new("org.gnome.evolution.mail.attachments.popup"); - - /* Add something like save-selected, foward selected attachments in a mail etc....*/ - list = e_attachment_bar_get_selected(bar); - - /* Lets not propagate any more the r-click which is intended to us*/ - if ( g_slist_length (list) == 0) - return TRUE; - - target = (EPopupTarget *)em_popup_target_new_attachments(emp, list); - for (i=0; i<2; i++) - menus = g_slist_prepend(menus, &efhd_bar_menu_items[i]); - e_popup_add_items((EPopup *)emp, menus, NULL, efhd_menu_items_free, emf); - - ((EMPopupTargetPart *)target)->target.widget = (GtkWidget *)bar; - menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, 0); - if (event) - gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); - else - gtk_menu_popup(menu, NULL, NULL, (GtkMenuPositionFunc)efhd_bar_popup_position, bar, 0, gtk_get_current_event_time()); - - return TRUE; -} - static gboolean -efhd_bar_popup_menu_event (EAttachmentBar *bar, EMFormat *emf) -{ - return efhd_bar_button_press_event(bar, NULL, emf); -} - -static void -efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd) -{ - int nattachments; - - if (!efhd->priv->attachment_bar) - return; - - nattachments = e_attachment_bar_get_num_attachments (E_ATTACHMENT_BAR(efhd->priv->attachment_bar)); - if (nattachments) { - char *txt; - - /* Cant i put in the number of attachments here ?*/ - txt = g_strdup_printf(ngettext("%d at_tachment", "%d at_tachments", nattachments), nattachments); - gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->label, txt); - g_free (txt); - - /* Show the bar even when the first attachment is added */ - if (nattachments == 1) { - gtk_widget_show_all (efhd->priv->attachment_area); - gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->save_txt, _("S_ave")); - - if (efhd->priv->show_bar) { - gtk_widget_show(efhd->priv->down); - gtk_widget_hide(efhd->priv->forward); - } else { - gtk_widget_show(efhd->priv->forward); - gtk_widget_hide(efhd->priv->down); - gtk_widget_hide(efhd->priv->attachment_box); - } - } else if (nattachments > 1) { - gtk_label_set_text_with_mnemonic ((GtkLabel *)efhd->priv->save_txt, _("S_ave All")); - } - } -} - -static void -efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh) +efhd_add_bar (EMFormatHTML *efh, + GtkHTMLEmbedded *eb, + EMFormatHTMLPObject *pobject) { - int width; - GtkRequisition req; EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh; + GtkWidget *widget; - gtk_widget_size_request (efhd->priv->attachment_bar, &req); - width = ((GtkWidget *) efh->html)->allocation.width - 16; - - /* Update the width of the bar when the width is greater than 1*/ - if (width > 0) - e_attachment_bar_set_width(E_ATTACHMENT_BAR(efhd->priv->attachment_bar), width); -} - -static gboolean -efhd_bar_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd) -{ - gboolean ret; - - /* Emulate the scroll over the attachment bar, as if it is scrolled in the window. - * It doesnt go automatically since the GnomeIconList is a layout by itself - */ - g_signal_emit_by_name (gtk_widget_get_parent((GtkWidget *)efhd->formathtml.html), "scroll_event", event, &ret); - - return TRUE; -} - -gboolean -efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd) -{ - attachment_bar_arrow_clicked (NULL, (EMFormatHTMLDisplay *)efhd); - - return TRUE; -} - -static gboolean -efhd_update_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; - struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv; - - if (priv->attachment_bar) - e_attachment_bar_refresh (E_ATTACHMENT_BAR (priv->attachment_bar)); - - return TRUE; -} - -static gboolean -efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; - struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv; - GtkWidget *hbox1, *hbox2, *hbox3, *vbox, *txt, *image, *save, *scroll; - int width, height, bar_width; - - priv->attachment_bar = e_attachment_bar_new(NULL); - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - ((EAttachmentBar *)priv->attachment_bar)->expand = TRUE; - - priv->forward = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - priv->down = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE); - hbox3 = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start ((GtkBox *)hbox3, priv->forward, FALSE, FALSE, 0); - gtk_box_pack_start ((GtkBox *)hbox3, priv->down, FALSE, FALSE, 0); - priv->arrow = (GtkWidget *)gtk_tool_button_new(hbox3, NULL); - g_signal_connect (priv->arrow, "mnemonic_activate", G_CALLBACK (efhd_mnemonic_show_bar), efh); - atk_object_set_name (gtk_widget_get_accessible (priv->arrow), _("Show Attachments")); - - priv->label = gtk_label_new(_("No Attachment")); - gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label), priv->arrow); - save = gtk_button_new(); - image = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_BUTTON); - txt = gtk_label_new_with_mnemonic(_("S_ave")); - priv->save_txt = txt; - hbox1 = gtk_hbox_new(FALSE, 0); - gtk_box_pack_start((GtkBox *)hbox1, image, FALSE, FALSE, 2); - gtk_box_pack_start((GtkBox *)hbox1, txt, FALSE, FALSE, 0); - - gtk_container_add((GtkContainer *)save, hbox1); - - hbox2 = gtk_hbox_new (FALSE, 0); - gtk_box_pack_start ((GtkBox *)hbox2, priv->arrow, FALSE, FALSE, 0); - gtk_box_pack_start ((GtkBox *)hbox2, priv->label, FALSE, FALSE, 2); - gtk_box_pack_start ((GtkBox *)hbox2, save, FALSE, FALSE, 2); - - priv->attachment_box = scroll; - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN); - gtk_container_add ((GtkContainer *)priv->attachment_box, priv->attachment_bar); - - gtk_widget_get_size_request(priv->attachment_bar, &width, &height); - - /* FIXME: What if the text is more?. Should we reduce the text with appending ...? - * or resize the bar? How to figure out that, it needs more space? */ - bar_width = ((GtkWidget *)efh->html)->parent->allocation.width - /* FIXME */16; - gtk_widget_set_size_request (priv->attachment_bar, - bar_width > 0 ? bar_width : 0, - 84 /* FIXME: Default show only one row, Dont hardcode size*/); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_box_pack_start ((GtkBox *)vbox, hbox2, FALSE, FALSE, 2); - gtk_box_pack_start ((GtkBox *)vbox, priv->attachment_box, TRUE, TRUE, 2); - - gtk_container_add ((GtkContainer *)eb, vbox); - gtk_widget_show ((GtkWidget *)eb); - - /* Lets hide it by default and show only when there are attachments */ - priv->attachment_area = vbox; - gtk_widget_hide_all (priv->attachment_area); + widget = e_mail_attachment_bar_new (); + gtk_container_add (GTK_CONTAINER (eb), widget); + efhd->priv->attachment_view = widget; + gtk_widget_hide (widget); - g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh); - g_signal_connect (priv->attachment_bar, "button_press_event", G_CALLBACK(efhd_bar_button_press_event), efhd); - g_signal_connect (priv->attachment_bar, "popup-menu", G_CALLBACK(efhd_bar_popup_menu_event), efhd); - g_signal_connect (save, "clicked", G_CALLBACK(attachments_save_all_clicked), efh); - g_signal_connect (eb, "size_allocate", G_CALLBACK (efhd_bar_resize), efh); - g_signal_connect (priv->attachment_bar, "scroll_event", G_CALLBACK(efhd_bar_scroll_event), efhd); + g_signal_connect_swapped ( + eb, "size-allocate", + G_CALLBACK (efhd_bar_resize), efh); return TRUE; } -static void -efhd_message_update_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) -{ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; - const char *classid = "attachment-bar-refresh"; - - if (efhd->nobar || efhd->priv->updated) - return; - - efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - efhd->priv->updated = TRUE; - em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_update_bar); - camel_stream_printf(stream, "", classid); - -} static void -efhd_message_add_bar(EMFormat *emf, CamelStream *stream, CamelMimePart *part, const EMFormatHandler *info) +efhd_message_add_bar (EMFormat *emf, + CamelStream *stream, + CamelMimePart *part, + const EMFormatHandler *info) { - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) emf; const char *classid = "attachment-bar"; - if (efhd->nobar || efhd->priv->files) - return; + em_format_html_add_pobject ( + (EMFormatHTML *) emf, + sizeof (EMFormatHTMLPObject), + classid, part, efhd_add_bar); - efhd->priv->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - efhd->priv->updated = FALSE; - - em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_add_bar); - camel_stream_printf(stream, "", classid); + camel_stream_printf ( + stream, "", classid); } static void @@ -2470,43 +2053,50 @@ efhd_format_attachment(EMFormat *emf, CamelStream *stream, CamelMimePart *part, char *classid, *text, *html; struct _attach_puri *info; - classid = g_strdup_printf("attachment%s", emf->part_id->str); - info = (struct _attach_puri *)em_format_add_puri(emf, sizeof(*info), classid, part, efhd_attachment_frame); - em_format_html_add_pobject((EMFormatHTML *)emf, sizeof(EMFormatHTMLPObject), classid, part, efhd_attachment_button); + classid = g_strdup_printf ("attachment%s", emf->part_id->str); + info = (struct _attach_puri *)em_format_add_puri ( + emf, sizeof (*info), classid, part, efhd_attachment_frame); + em_format_html_add_pobject ( + (EMFormatHTML *) emf, sizeof (EMFormatHTMLPObject), + classid, part, efhd_attachment_button); info->handle = handle; - info->shown = em_format_is_inline(emf, info->puri.part_id, info->puri.part, handle); + info->shown = em_format_is_inline ( + emf, info->puri.part_id, info->puri.part, handle); info->snoop_mime_type = emf->snoop_mime_type; - info->attachment = e_attachment_new_from_mime_part (info->puri.part); - e_attachment_bar_create_attachment_cache (info->attachment); + info->attachment = e_attachment_new (); + e_attachment_set_mime_part (info->attachment, info->puri.part); if (emf->valid) { info->sign = emf->valid->sign.status; info->encrypt = emf->valid->encrypt.status; } - camel_stream_write_string(stream, - EM_FORMAT_HTML_VPAD - ""); + camel_stream_write_string ( + stream, EM_FORMAT_HTML_VPAD + "
" - "" - "
"); - camel_stream_printf(stream, "", classid); + camel_stream_printf ( + stream, "", classid); - camel_stream_write_string(stream, - "
" + "" + "
" - "
"); + camel_stream_write_string ( + stream, "" + "
"); /* output some info about it */ /* FIXME: should we look up mime_type from object again? */ - text = em_format_describe_part(part, mime_type); - html = camel_text_to_html(text, ((EMFormatHTML *)emf)->text_html_flags & CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); - camel_stream_write_string(stream, html); - g_free(html); - g_free(text); - - camel_stream_write_string(stream, - "
\n" - EM_FORMAT_HTML_VPAD); + text = em_format_describe_part (part, mime_type); + html = camel_text_to_html ( + text, ((EMFormatHTML *)emf)->text_html_flags & + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS, 0); + camel_stream_write_string (stream, html); + g_free (html); + g_free (text); + + camel_stream_write_string ( + stream, "\n" + EM_FORMAT_HTML_VPAD); if (handle) { if (info->shown) @@ -2653,7 +2243,8 @@ efhd_format_optional(EMFormat *emf, CamelStream *fstream, CamelMimePart *part, C info->handle = em_format_find_handler(emf, "text/plain"); info->shown = FALSE; info->snoop_mime_type = "text/plain"; - info->attachment = e_attachment_new_from_mime_part (info->puri.part); + info->attachment = e_attachment_new (); + e_attachment_set_mime_part (info->attachment, info->puri.part); info->mstream = (CamelStreamMem *)mstream; if (emf->valid) { info->sign = emf->valid->sign.status; diff --git a/mail/em-format-html-display.h b/mail/em-format-html-display.h index 651b981364..4e2e7c1f83 100644 --- a/mail/em-format-html-display.h +++ b/mail/em-format-html-display.h @@ -26,7 +26,6 @@ #define _EM_FORMAT_HTML_DISPLAY_H #include "mail/em-format-html.h" -#include "widgets/misc/e-attachment-bar.h" typedef struct _EMFormatHTMLDisplay EMFormatHTMLDisplay; typedef struct _EMFormatHTMLDisplayClass EMFormatHTMLDisplayClass; @@ -82,7 +81,6 @@ void em_format_html_display_paste (EMFormatHTMLDisplay *efhd); void em_format_html_display_zoom_in (EMFormatHTMLDisplay *efhd); void em_format_html_display_zoom_out (EMFormatHTMLDisplay *efhd); void em_format_html_display_zoom_reset (EMFormatHTMLDisplay *efhd); -EAttachmentBar *em_format_html_display_get_bar (EMFormatHTMLDisplay *efhd); gboolean em_format_html_display_popup_menu (EMFormatHTMLDisplay *efhd); diff --git a/mail/em-popup.c b/mail/em-popup.c index 91e6ed6280..debad8cb56 100644 --- a/mail/em-popup.c +++ b/mail/em-popup.c @@ -100,12 +100,6 @@ emp_target_free(EPopup *ep, EPopupTarget *t) g_free(s->uri); break; } - case EM_POPUP_TARGET_ATTACHMENTS: { - EMPopupTargetAttachments *s = (EMPopupTargetAttachments *)t; - - g_slist_foreach(s->attachments, (GFunc)g_object_unref, NULL); - g_slist_free(s->attachments); - break; } } ((EPopupClass *)emp_parent)->target_free(ep, t); @@ -361,42 +355,6 @@ done: return t; } -/** - * em_popup_target_new_attachments: - * @emp: - * @attachments: A list of EMsgComposerAttachment objects, reffed for - * the list. Will be unreff'd once finished with. - * - * Owns the list @attachments and their items after they're passed in. - * - * Return value: - **/ -EMPopupTargetAttachments * -em_popup_target_new_attachments(EMPopup *emp, GSList *attachments) -{ - EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t)); - guint32 mask = ~0; - int len = g_slist_length(attachments); - - t->attachments = attachments; - if (len > 0) - mask &= ~ EM_POPUP_ATTACHMENTS_MANY; - if (len == 1 && ((EAttachment *)attachments->data)->is_available_local) { - - if (camel_content_type_is(((CamelDataWrapper *) ((EAttachment *) attachments->data)->body)->mime_type, "image", "*")) - mask &= ~ EM_POPUP_ATTACHMENTS_IMAGE; - if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *) ((EAttachment *) attachments->data)->body))) - mask &= ~EM_POPUP_ATTACHMENTS_MESSAGE; - - mask &= ~ EM_POPUP_ATTACHMENTS_ONE; - } - if (len > 1) - mask &= ~ EM_POPUP_ATTACHMENTS_MULTIPLE; - t->target.mask = mask; - - return t; -} - /* ********************************************************************** */ static void @@ -405,11 +363,7 @@ emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data) EPopupTarget *t = ep->target; CamelMimePart *part = NULL; - /* If it is of type EM_POPUP_TARGET_ATTACHMENTS, we can assume the length is one. */ - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; em_utils_save_part(ep->target->widget, _("Save As..."), part); } @@ -423,10 +377,7 @@ emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) unsigned int i=1; CamelMimePart *part = NULL; - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; if (!part) return; @@ -497,10 +448,7 @@ emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data) CamelMimeMessage *message; CamelMimePart *part; - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL); @@ -513,10 +461,7 @@ emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data) CamelMimeMessage *message; CamelMimePart *part; - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL); @@ -529,10 +474,7 @@ emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data) CamelMimeMessage *message; CamelMimePart *part; - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)part); em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL); @@ -545,10 +487,7 @@ emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data) CamelMimeMessage *message; CamelMimePart *part; - if (t->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) t)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) t)->part; + part = ((EMPopupTargetPart *) t)->part; /* TODO: have a emfv specific override so we can get the parent folder uri */ message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) part); @@ -566,17 +505,6 @@ static EMPopupItem emp_standard_object_popups[] = { { E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_PART_MESSAGE }, }; -static EMPopupItem emp_attachment_object_popups[] = { - { E_POPUP_ITEM, "00.attach.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "document-save-as", 0 }, - { E_POPUP_ITEM, "00.attach.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_ATTACHMENTS_IMAGE }, - { E_POPUP_BAR, "05.attach", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "mail-reply-sender" , EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE}, - { E_POPUP_ITEM, "05.attach.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "mail-reply-all", EM_POPUP_ATTACHMENTS_MESSAGE}, - { E_POPUP_BAR, "05.attach.10", NULL, NULL, NULL, NULL, EM_POPUP_ATTACHMENTS_MESSAGE }, - { E_POPUP_ITEM, "05.attach.15", N_("_Forward"), emp_part_popup_forward, NULL, "mail-forward", EM_POPUP_ATTACHMENTS_MESSAGE }, -}; - static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" }; /* ********************************************************************** */ @@ -634,10 +562,7 @@ emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data) EPopupTarget *target = ep->target; CamelMimePart *part; - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) target)->part; + part = ((EMPopupTargetPart *) target)->part; path = em_utils_temp_save_part(target->widget, part, TRUE); if (path) { @@ -705,10 +630,7 @@ emp_add_vcard (EPopup *ep, EPopupItem *item, void *data) CamelStreamMem *mem; - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) target)->part; + part = ((EMPopupTargetPart *) target)->part; if (!part) return; @@ -762,25 +684,6 @@ emp_standard_menu_factory(EPopup *emp, void *data) items = emp_standard_object_popups; len = LEN(emp_standard_object_popups); break; } - case EM_POPUP_TARGET_ATTACHMENTS: { - EMPopupTargetAttachments *t = (EMPopupTargetAttachments *)emp->target; - GSList *list = t->attachments; - EAttachment *attachment; - - if (g_slist_length(list) != 1 || !((EAttachment *)list->data)->is_available_local) { - items = NULL; - len = 0; - break; - } - - /* Only one attachment selected */ - attachment = list->data; - mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)attachment->body); - filename = camel_mime_part_get_filename(attachment->body); - - items = emp_attachment_object_popups; - len = LEN(emp_attachment_object_popups); - break; } default: items = NULL; len = 0; @@ -942,21 +845,11 @@ static const EPopupHookTargetMask emph_folder_masks[] = { { NULL } }; -static const EPopupHookTargetMask emph_attachments_masks[] = { - { "one", EM_POPUP_ATTACHMENTS_ONE }, - { "many", EM_POPUP_ATTACHMENTS_MANY }, - { "multiple", EM_POPUP_ATTACHMENTS_MULTIPLE }, - { "image", EM_POPUP_ATTACHMENTS_IMAGE }, - { "message", EM_POPUP_ATTACHMENTS_MESSAGE }, - { NULL } -}; - static const EPopupHookTargetMap emph_targets[] = { { "select", EM_POPUP_TARGET_SELECT, emph_select_masks }, { "uri", EM_POPUP_TARGET_URI, emph_uri_masks }, { "part", EM_POPUP_TARGET_PART, emph_part_masks }, { "folder", EM_POPUP_TARGET_FOLDER, emph_folder_masks }, - { "attachments", EM_POPUP_TARGET_ATTACHMENTS, emph_attachments_masks }, { NULL } }; diff --git a/mail/em-popup.h b/mail/em-popup.h index fbe41a310a..77f80e5599 100644 --- a/mail/em-popup.h +++ b/mail/em-popup.h @@ -43,7 +43,6 @@ typedef struct _EMPopupClass EMPopupClass; * @EM_POPUP_TARGET_URI: A URI. * @EM_POPUP_TARGET_PART: A CamelMimePart message part. * @EM_POPUP_TARGET_FOLDER: A folder URI. - * @EM_POPUP_TARGET_ATTACHMENTS: A list of attachments. * * Defines the value of the targetid for all EMPopup target types. **/ @@ -51,8 +50,7 @@ enum _em_popup_target_t { EM_POPUP_TARGET_SELECT, EM_POPUP_TARGET_URI, EM_POPUP_TARGET_PART, - EM_POPUP_TARGET_FOLDER, - EM_POPUP_TARGET_ATTACHMENTS, + EM_POPUP_TARGET_FOLDER }; /** @@ -158,26 +156,10 @@ enum _em_popup_target_folder_t { EM_POPUP_FOLDER_NONSTATIC = 1<<6, /* Except static folders like Outbox.*/ }; -/** - * enum _em_popup_target_attachments_t - EMPopupTargetAttachments qualifiers. - * - * @EM_POPUP_ATTACHMENTS_ONE: There is one and only one attachment selected. - * @EM_POPUP_ATTACHMENTS_MANY: There is one or more attachments selected. - * - **/ -enum _em_popup_target_attachments_t { - EM_POPUP_ATTACHMENTS_ONE = 1<<0, /* only 1 selected */ - EM_POPUP_ATTACHMENTS_MANY = 1<<1, /* one or more selected */ - EM_POPUP_ATTACHMENTS_MULTIPLE = 1<<2, /* More than 1 selected */ - EM_POPUP_ATTACHMENTS_IMAGE = 1<<3, /* Image selected */ - EM_POPUP_ATTACHMENTS_MESSAGE = 1<<4 /* Message selected */ -}; - typedef struct _EMPopupTargetSelect EMPopupTargetSelect; typedef struct _EMPopupTargetURI EMPopupTargetURI; typedef struct _EMPopupTargetPart EMPopupTargetPart; typedef struct _EMPopupTargetFolder EMPopupTargetFolder; -typedef struct _EMPopupTargetAttachments EMPopupTargetAttachments; /** * struct _EMPopupTargetURI - An inline URI. @@ -241,20 +223,6 @@ struct _EMPopupTargetFolder { char *uri; }; -/** - * struct _EMPopupTargetAttachments - A list of composer attachments. - * - * @target: Superclass. - * @attachments: A GSList list of EMsgComposer attachments. - * - * This target is used to represent a selected list of attachments in - * the message composer attachment area. - **/ -struct _EMPopupTargetAttachments { - EPopupTarget target; - GSList *attachments; -}; - typedef struct _EPopupItem EMPopupItem; /* The object */ @@ -276,7 +244,6 @@ EMPopupTargetURI *em_popup_target_new_uri(EMPopup *emp, const char *uri); EMPopupTargetSelect *em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids); EMPopupTargetPart *em_popup_target_new_part(EMPopup *emp, struct _CamelMimePart *part, const char *mime_type); EMPopupTargetFolder *em_popup_target_new_folder(EMPopup *emp, const char *uri, guint32 info_flags, guint32 popup_flags); -EMPopupTargetAttachments *em_popup_target_new_attachments(EMPopup *emp, GSList *attachments); /* ********************************************************************** */ diff --git a/mail/mail-component.c b/mail/mail-component.c index 3b67c43ad4..556715d662 100644 --- a/mail/mail-component.c +++ b/mail/mail-component.c @@ -92,6 +92,8 @@ #include "e-util/e-non-intrusive-error-dialog.h" +#include "e-attachment-handler-mail.h" + #define MAILER_ERROR_LEVEL_KEY "/apps/evolution/mail/display/error_level" #define MAILER_ERROR_TIME_OUT_KEY "/apps/evolution/mail/display/error_timeout" @@ -1259,6 +1261,9 @@ mail_component_class_init (MailComponentClass *class) epv->setLineStatus = impl_setLineStatus; mepv->test = impl_mail_test; + + /* Register attachment handler types. */ + e_attachment_handler_mail_get_type (); } static void diff --git a/plugins/attachment-reminder/attachment-reminder.c b/plugins/attachment-reminder/attachment-reminder.c index 15bac58080..8634ce4000 100644 --- a/plugins/attachment-reminder/attachment-reminder.c +++ b/plugins/attachment-reminder/attachment-reminder.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -43,9 +44,10 @@ #include -#include "widgets/misc/e-attachment-bar.h" #include "composer/e-msg-composer.h" #include "composer/e-composer-actions.h" +#include "widgets/misc/e-attachment-view.h" +#include "widgets/misc/e-attachment-store.h" #define GCONF_KEY_ATTACH_REMINDER_CLUES "/apps/evolution/mail/attachment_reminder_clues" #define SIGNATURE "-- " @@ -182,12 +184,13 @@ check_for_attachment_clues (gchar *msg) static gboolean check_for_attachment (EMsgComposer *composer) { - EAttachmentBar* bar = (EAttachmentBar*)e_msg_composer_get_attachment_bar (composer); + EAttachmentView *view; + EAttachmentStore *store; - if (e_attachment_bar_get_num_attachments (bar)) - return TRUE; + view = e_msg_composer_get_attachment_view (composer); + store = e_attachment_view_get_store (view); - return FALSE; + return (e_attachment_store_get_num_attachments (store) > 0); } static gchar* diff --git a/plugins/import-ics-attachments/ChangeLog b/plugins/import-ics-attachments/ChangeLog deleted file mode 100644 index 21a9408c9c..0000000000 --- a/plugins/import-ics-attachments/ChangeLog +++ /dev/null @@ -1,109 +0,0 @@ -2009-01-21 Milan Crha - - * Makefile.am: Use also EVOLUTION_CALENDAR_CFLAGS. - -2008-09-02 Sankar P - -License Changes - - * icsimporter.c: - -2008-08-12 Bharath Acharya - - * Makefile.am: Added necessary libraries to link to. Build break while - compiling on Windows. - -2008-08-11 Matthew Barnes - - ** Fixes part of bug #546892 - - * icsimporter.c: - Prefer gtk_image_new_from_icon_name() over e_icon_factory_get_image(). - -2008-04-17 Milan Crha - - ** Part of fix for bug #526739 - - * icsimporter.c: Do not include gnome-vfs. - -2007-02-20 Paul Bolle - - ** Fix for bug #517082 - - * icsimporter.c: (init_widgets): Fix small leak. - -2008-02-06 Milan Crha - - ** Fix for bug #514622 - - * icsimporter.c: (dialog_close_cb): Drop this function. - * icsimporter.c: (init_widgets), (dialog_response_cb), - (ical_import_done): Do not call "close" on already closed dialog. - -2007-10-01 Milan Crha - - * icsimporter.c: (prepare_events), (prepare_tasks): - Really go through every component when removing one. - -2007-06-03 Srinivasa Ragavan - - ** Fix for version removal from Installed files from Gilles Dartiguelongue - - * Makefile.am: - -2007-05-12 Matthew Barnes - - ** Fixes part of bug #337616 - - * Makefile.am: Add "eplug" file to CLEANFILES. - -2007-03-27 Matthew Barnes - - * icsimporter.c: Don't mix declarations and code (#405495). - -2007-03-20 Matthew Barnes - - ** Fixes part of bug #419524 - - * Include instead of . - -2006-11-28 Parthasarathi Susarla - - ** Fix bug #348679 - - * icsimporter.c: (org_gnome_evolution_import_ics_attachment): - Do not access structure elements directly. Use the methods of the - class in the CamelDataWrapper Class - -2006-08-28 Kjartan Maraas - - * org-gnome-evolution-mail-attachments-import-ics.eplug.xml: Mark - name and description for translation. - -2006-08-23 Srinivasa Ragavan - - ** Fix for bug #347248 - - * icsimporter.c: (get_menu_type), (import_ics): Update the - em_utils_temp_save_part to use readwrite mode. - -2006-02-21 Chenthill Palanisamy - - reviewed by Veerapuram Varadhan - - Fixes a crash - * icsimporter.c: (org_gnome_evolution_import_ics_attachments): - If the number of attachments selected is not equal to one, just return; - - -2006-01-22 Harish Krishnaswamy - - * icsimporter.c (get_menu_type), (dialog_response_cb), - (dialog_close_cb), (get_icalcomponent_from_file): - Fix twenty odd compiler warnings and style oddness. - -2006-01-17 Harish Krishnaswamy - - * import-ics-attachments : Initial commits. Plugin written and submitted by - Johnny Jacob - diff --git a/plugins/import-ics-attachments/Makefile.am b/plugins/import-ics-attachments/Makefile.am deleted file mode 100644 index baded42123..0000000000 --- a/plugins/import-ics-attachments/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -INCLUDES = \ - -I$(top_srcdir)\ - -I$(top_srcdir)/camel \ - -I$(top_srcdir)/widgets/misc \ - $(EVOLUTION_MAIL_CFLAGS) \ - $(EVOLUTION_CALENDAR_CFLAGS) \ - -DEVOLUTION_DATADIR=\""$(datadir)"\" \ - -DEVOLUTION_PRIVDATADIR=\""$(privdatadir)"\" \ - -DEVOLUTION_ICONSDIR=\""$(imagesdir)"\" \ - -DEVOLUTION_IMAGES=\""$(imagesdir)"\" \ - -DEVOLUTION_BUTTONSDIR=\""$(buttonsdir)"\" \ - -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \ - -DEVOLUTION_UIDIR=\""$(evolutionuidir)"\" \ - -DCAMEL_PROVIDERDIR=\""$(camel_providerdir)"\" \ - -DPLUGINDIR=\""$(plugindir)"\" \ - -DPREFIX=\""$(prefix)"\" - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-evolution-mail-attachments-import-ics.eplug -plugin_LTLIBRARIES = liborg-gnome-evolution-mail-attachments-import-ics.la - -liborg_gnome_evolution_mail_attachments_import_ics_la_SOURCES = icsimporter.c -liborg_gnome_evolution_mail_attachments_import_ics_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED) -liborg_gnome_evolution_mail_attachments_import_ics_la_LIBADD = \ - $(top_builddir)/e-util/libeutil.la \ - $(top_builddir)/mail/libevolution-mail.la \ - $(top_builddir)/calendar/common/libevolution-calendarprivate.la \ - $(EVOLUTION_CALENDAR_LIBS) \ - $(EVOLUTION_MAIL_LIBS) - -EXTRA_DIST = org-gnome-evolution-mail-attachments-import-ics.eplug.xml - -BUILT_SOURCES = $(plugin_DATA) -CLEANFILES = $(BUILT_SOURCES) diff --git a/plugins/import-ics-attachments/icsimporter.c b/plugins/import-ics-attachments/icsimporter.c deleted file mode 100644 index fbd5e46518..0000000000 --- a/plugins/import-ics-attachments/icsimporter.c +++ /dev/null @@ -1,435 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Johnny Jacob - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "e-attachment-bar.h" -#include -#include "e-util/e-error.h" -#include -#include -#include -#include - -typedef struct { - ECal *client; - int source_type; - icalcomponent *icalcomp; - GtkWidget *window; - GtkWidget *selector; -} ICalImporterData; - - -static void import_ics (EPlugin *ep, EPopupTarget *t, void *data); -static icalcomponent* get_icalcomponent_from_file(char *filename); -static void prepare_events (icalcomponent *icalcomp, GList **vtodos); -static void prepare_tasks (icalcomponent *icalcomp, GList *vtodos); -static void import_items(ICalImporterData *icidata); -static gboolean update_objects (ECal *client, icalcomponent *icalcomp); -static void dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata); -static void ical_import_done(ICalImporterData *icidata); -static void init_widgets (char *path); -static icalcomponent_kind get_menu_type (void *data); - -void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t); -void org_gnome_evolution_import_ics_part (EPlugin *ep, EMPopupTargetPart *t); - -static void -popup_free (EPopup *ep, GSList *items, void *data) -{ - g_slist_free (items); -} - -static EPopupItem popup_calendar_items[] = { - { E_POPUP_BAR, "25.display.00"}, - { E_POPUP_ITEM, "25.display.01", N_("_Import to Calendar"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"} -}; - -static EPopupItem popup_tasks_items[] = { - { E_POPUP_BAR, "25.display.00"}, - { E_POPUP_ITEM, "25.display.01", N_("_Import to Tasks"), (EPopupActivateFunc)import_ics, NULL, "stock_mail-import"} -}; - - -void org_gnome_evolution_import_ics_attachments (EPlugin *ep, EMPopupTargetAttachments *t) -{ - GSList *menus = NULL; - icalcomponent_kind kind; - int len = 0; - int i = 0; - CamelContentType *type; - - len = g_slist_length(t->attachments); - - if (len != 1) - return; - - type = camel_data_wrapper_get_mime_type_field (((CamelDataWrapper *) ((EAttachment *) t->attachments->data)->body)); - if (type && camel_content_type_is(type, "text", "calendar")) { - - kind = get_menu_type (t); - - if (kind == ICAL_VTODO_COMPONENT ) { - for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++) - menus = g_slist_prepend (menus, &popup_tasks_items[i]); - } else if ( kind == ICAL_VEVENT_COMPONENT) { - for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++) - menus = g_slist_prepend (menus, &popup_calendar_items[i]); - } - - e_popup_add_items (t->target.popup, menus, NULL, popup_free, t); - } -} - -void org_gnome_evolution_import_ics_part (EPlugin*ep, EMPopupTargetPart *t) -{ - GSList *menus = NULL; - icalcomponent_kind kind; - int i = 0; - - if (!camel_content_type_is(((CamelDataWrapper *) t->part)->mime_type, "text", "calendar")) - return; - - kind = get_menu_type (t); - - if (kind == ICAL_VTODO_COMPONENT ) { - for (i = 0; i < sizeof (popup_tasks_items) / sizeof (popup_tasks_items[0]); i++) - menus = g_slist_prepend (menus, &popup_tasks_items[i]); - } else if ( kind == ICAL_VEVENT_COMPONENT) { - for (i = 0; i < sizeof (popup_calendar_items) / sizeof (popup_calendar_items[0]); i++) - menus = g_slist_prepend (menus, &popup_calendar_items[i]); - } - - e_popup_add_items (t->target.popup, menus, NULL, popup_free, t); -} - -static icalcomponent_kind -get_menu_type (void *data) -{ - CamelMimePart *part; - char *path; - icalcomponent *icalcomp, *subcomp; - icalcomponent_kind kind; - EPopupTarget *target = (EPopupTarget *) data; - - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) target)->part; - - path = em_utils_temp_save_part (NULL, part, FALSE); - - icalcomp = get_icalcomponent_from_file (path); - - subcomp = icalcomponent_get_inner(icalcomp); - kind = icalcomponent_isa (subcomp); - - if (kind == ICAL_VTODO_COMPONENT ) { - return ICAL_VTODO_COMPONENT; - } else if ( kind == ICAL_VEVENT_COMPONENT) { - return ICAL_VEVENT_COMPONENT; - } - return ICAL_NO_COMPONENT; -} - -static void -import_ics (EPlugin *ep, EPopupTarget *t, void *data) -{ - CamelMimePart *part; - char *path; - EPopupTarget *target = (EPopupTarget *) data; - - if (target->type == EM_POPUP_TARGET_ATTACHMENTS) - part = ((EAttachment *) ((EMPopupTargetAttachments *) target)->attachments->data)->body; - else - part = ((EMPopupTargetPart *) target)->part; - - path = em_utils_temp_save_part (NULL, part, FALSE); - init_widgets(path); -} - -static void -init_widgets(char *path) -{ - - GtkWidget *vbox, *hbox, *dialog; - icalcomponent_kind kind; - icalcomponent *subcomp; - GtkWidget *selector, *label; - ESourceList *source_list; - ESource *primary; - GtkWidget *scrolled; - ICalImporterData *icidata = g_malloc0(sizeof(*icidata)); - GtkWidget *icon, *button; - char *label_str = NULL; - char *markup; - - g_return_if_fail ( path != NULL); - dialog = gtk_dialog_new_with_buttons (_("Import ICS"), - NULL, GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NULL); - icidata->window = dialog; - g_signal_connect (dialog, - "response", - G_CALLBACK (dialog_response_cb), - icidata); - - vbox = GTK_DIALOG(dialog)->vbox; - hbox = gtk_hbox_new (FALSE, FALSE); - label = gtk_label_new(NULL); - - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6); - - icidata->icalcomp = get_icalcomponent_from_file (path); - - subcomp = icalcomponent_get_inner(icidata->icalcomp); - kind = icalcomponent_isa (subcomp); - - if (kind == ICAL_VTODO_COMPONENT ) { - e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_TODO, NULL); - label_str = _("Select Task List"); - icidata->source_type = E_CAL_SOURCE_TYPE_TODO; - } else if ( kind == ICAL_VEVENT_COMPONENT) { - e_cal_get_sources (&source_list, E_CAL_SOURCE_TYPE_EVENT, NULL); - label_str = _("Select Calendar"); - icidata->source_type = E_CAL_SOURCE_TYPE_EVENT; - } - - markup = g_markup_printf_escaped ("%s", label_str); - gtk_label_set_markup (GTK_LABEL (label), markup); - g_free (markup); - hbox = gtk_hbox_new (FALSE, FALSE); - gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 6); - gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 6); - - selector = e_source_selector_new (source_list); - e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE); - scrolled = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add((GtkContainer *)scrolled, selector); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN); - hbox = gtk_hbox_new (FALSE, FALSE); - gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 6); - gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 6); - icidata->selector = selector; - - - /* FIXME What if no sources? */ - primary = e_source_list_peek_source_any (source_list); - e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (selector), primary); - - g_object_unref (source_list); - hbox = gtk_hbox_new (FALSE, FALSE); - icon = gtk_image_new_from_icon_name ( - "stock_mail-import", GTK_ICON_SIZE_MENU); - gtk_box_pack_start (GTK_BOX(hbox), icon, FALSE, FALSE, 6); - label = gtk_label_new_with_mnemonic (_("_Import")); - gtk_box_pack_start (GTK_BOX(hbox), label, FALSE, FALSE, 6); - gtk_widget_show(label); - button = gtk_button_new (); - gtk_container_add (GTK_CONTAINER (button), hbox); - gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_OK); - gtk_widget_grab_focus (button); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 210,340); - gtk_widget_show_all (dialog); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); -} - -static void -dialog_response_cb (GtkDialog *dialog, gint response_id, ICalImporterData *icidata) -{ - switch (response_id) { - case GTK_RESPONSE_OK : - import_items(icidata); - break; - - case GTK_RESPONSE_CANCEL : - case GTK_RESPONSE_DELETE_EVENT : - break; - } -} - -/* This removes all components except VEVENTs and VTIMEZONEs from the toplevel */ -static void -prepare_events (icalcomponent *icalcomp, GList **vtodos) -{ - icalcomponent *subcomp; - icalcompiter iter; - - if (vtodos) - *vtodos = NULL; - - iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT); - while ((subcomp = icalcompiter_deref (&iter)) != NULL) { - icalcomponent_kind child_kind = icalcomponent_isa (subcomp); - if (child_kind != ICAL_VEVENT_COMPONENT - && child_kind != ICAL_VTIMEZONE_COMPONENT) { - - icalcompiter_next (&iter); - - icalcomponent_remove_component (icalcomp, subcomp); - if (child_kind == ICAL_VTODO_COMPONENT && vtodos) - *vtodos = g_list_prepend (*vtodos, subcomp); - else - icalcomponent_free (subcomp); - } else { - icalcompiter_next (&iter); - } - } -} - -/* This removes all components except VTODOs and VTIMEZONEs from the toplevel - icalcomponent, and adds the given list of VTODO components. The list is - freed afterwards. */ -static void -prepare_tasks (icalcomponent *icalcomp, GList *vtodos) -{ - icalcomponent *subcomp; - GList *elem; - icalcompiter iter; - - iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT); - while ((subcomp = icalcompiter_deref (&iter)) != NULL) { - icalcomponent_kind child_kind = icalcomponent_isa (subcomp); - if (child_kind != ICAL_VTODO_COMPONENT - && child_kind != ICAL_VTIMEZONE_COMPONENT) { - icalcompiter_next (&iter); - icalcomponent_remove_component (icalcomp, subcomp); - icalcomponent_free (subcomp); - } else { - icalcompiter_next (&iter); - } - } - - for (elem = vtodos; elem; elem = elem->next) { - icalcomponent_add_component (icalcomp, elem->data); - } - g_list_free (vtodos); -} - -static void -import_items(ICalImporterData *icidata) -{ - ESource *source; - g_return_if_fail (icidata != NULL); - - source = e_source_selector_peek_primary_selection ((ESourceSelector *)icidata->selector); - g_return_if_fail ( source != NULL); - - icidata->client = auth_new_cal_from_source (source, icidata->source_type); - e_cal_open (icidata->client, FALSE, NULL); - - switch (icidata->source_type) { - case E_CAL_SOURCE_TYPE_EVENT: - prepare_events (icidata->icalcomp, NULL); - if (!update_objects (icidata->client, icidata->icalcomp)) - /* FIXME: e_error ... */; - break; - case E_CAL_SOURCE_TYPE_TODO: - prepare_tasks (icidata->icalcomp, NULL); - if (!update_objects (icidata->client, icidata->icalcomp)) - /* FIXME: e_error ... */; - break; - default: - g_assert_not_reached (); - } - ical_import_done (icidata); -} - -static gboolean -update_objects (ECal *client, icalcomponent *icalcomp) -{ - icalcomponent_kind kind; - icalcomponent *vcal; - gboolean success = TRUE; - - kind = icalcomponent_isa (icalcomp); - - if (kind == ICAL_VTODO_COMPONENT || kind == ICAL_VEVENT_COMPONENT) { - vcal = e_cal_util_new_top_level (); - if (icalcomponent_get_method (icalcomp) == ICAL_METHOD_CANCEL) - icalcomponent_set_method (vcal, ICAL_METHOD_CANCEL); - else - icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH); - icalcomponent_add_component (vcal, icalcomponent_new_clone (icalcomp)); - } else if (kind == ICAL_VCALENDAR_COMPONENT) { - vcal = icalcomponent_new_clone (icalcomp); - if (!icalcomponent_get_first_property (vcal, ICAL_METHOD_PROPERTY)) - icalcomponent_set_method (vcal, ICAL_METHOD_PUBLISH); - } else - return FALSE; - - if (!e_cal_receive_objects (client, vcal, NULL)) - success = FALSE; - - icalcomponent_free (vcal); - - return success; -} - -static void -ical_import_done(ICalImporterData *icidata) -{ - g_object_unref (icidata->client); - icalcomponent_free (icidata->icalcomp); - g_free (icidata); -} - -static icalcomponent * -get_icalcomponent_from_file(char *filename) -{ - char *contents; - icalcomponent *icalcomp; - - g_return_val_if_fail (filename != NULL, NULL); - - if (!g_file_get_contents (filename, &contents, NULL, NULL)) { - g_free (filename); - return NULL; - } - g_free (filename); - - icalcomp = e_cal_util_parse_ics_string (contents); - g_free (contents); - - if (icalcomp) { - return icalcomp; - } - return NULL; -} diff --git a/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml b/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml deleted file mode 100644 index 745d0fb724..0000000000 --- a/plugins/import-ics-attachments/org-gnome-evolution-mail-attachments-import-ics.eplug.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - <_description>Imports ICS attachments to calendar. - - - - - - - - - - - - - - - diff --git a/plugins/save-attachments/ChangeLog b/plugins/save-attachments/ChangeLog deleted file mode 100644 index 9980fdf13d..0000000000 --- a/plugins/save-attachments/ChangeLog +++ /dev/null @@ -1,102 +0,0 @@ -2009-01-28 Tor Lillqvist - - * Makefile.am: Use -no-undefined and link with more libs on - Windows. - -2008-09-19 Sankar P - -License Changes - - * save-attachments.c: - -2007-12-20 Matthew Barnes - - ** Fixes part of bug #362638 - - * save-attachments.c: - Use the new MailMsg API for messages. - -2007-04-02 Sankar P - - * Committed on behalf of Gilles Dartiguelongue - - * org-gnome-save-attachments.eplug.xml: - Cleanup. - Fixes part of #301149 - -2007-03-29 Matthew Barnes - - * save-attachments.c: - Evolution requires GLib 2.10 now; remove dead backward-compatibility - code for GLib < 2.8 (#418971). - -2007-01-27 Nickolay V. Shmyrev - - * save-attachments.c: (save_got_message): - mark strings as translatable. See bug #399381 for details. - -2006-07-07 Hiroyuki Ikezoe - - ** Fixes bug #341369 - * save-attachments.c: fixing a memory leak. - -2006-02-28 Shi Pu - - ** Fixes #323853 - - * save-attachments.c: (save_response), (entry_changed), - (save_got_message): - replace GnomeFileEntry by GtkFileChooserButton. - -2005-12-17 Tor Lillqvist - - * save-attachments.c (entry_changed): Use GLib API to manipulate - pathname. - -2005-05-16 Not Zed - - * save-attachments.c: moved e-error to e-util - -2005-05-13 Rodney Dawes - - * org-gnome-save-attachments.xml: Update for new menu layout - -2005-05-12 Not Zed - - * Makefile.am: setup built_sources/cleanfiles. - -2005-05-06 Not Zed - - * Makefile.am: - * org-gnome-save-attachments.eplug.xml: s/.in/.xml/ & i18n. - -2005-02-24 Björn Torkelsson - - * org-gnome-save-attachments.eplug.in: Removed plugin from the - name. - Fixed description and added author - -2005-02-07 Not Zed - - * save-attachments.c (save_part): fix the access() call test. - -2005-01-04 Philip Van Hoof - - * save-attachments.c: Use standard error messages - -2004-12-27 Philip Van Hoof - - * save-attachments.c: Warning when overwriting file - -2004-11-01 JP Rosevear - - * Makefile.am: dist xml menu file - -2004-11-01 JP Rosevear - - * Makefile.am: dist .eplug.in file - -2004-10-20 Not Zed - - * Imported save-attachments example plugin. - diff --git a/plugins/save-attachments/Makefile.am b/plugins/save-attachments/Makefile.am deleted file mode 100644 index 05c724a4e4..0000000000 --- a/plugins/save-attachments/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -if OS_WIN32 -NO_UNDEFINED_REQUIRED_LIBS = \ - $(top_builddir)/mail/libevolution-mail.la \ - $(EVOLUTION_MAIL_LIBS) \ - $(GNOME_PLATFORM_LIBS) \ - $(top_builddir)/e-util/libeutil.la -endif - -INCLUDES = \ - -I$(top_srcdir) \ - $(EVOLUTION_MAIL_CFLAGS) - -@EVO_PLUGIN_RULE@ - -plugin_DATA = org-gnome-save-attachments.eplug org-gnome-save-attachments.xml -plugin_LTLIBRARIES = liborg-gnome-save-attachments.la - -liborg_gnome_save_attachments_la_SOURCES = save-attachments.c -liborg_gnome_save_attachments_la_LDFLAGS = -module \ - -avoid-version $(NO_UNDEFINED) - -liborg_gnome_save_attachments_la_LIBADD = \ - $(NO_UNDEFINED_REQUIRED_LIBS) - - -EXTRA_DIST = \ - org-gnome-save-attachments.eplug.xml \ - org-gnome-save-attachments.xml - -BUILT_SOURCES = org-gnome-save-attachments.eplug -CLEANFILES = $(BUILT_SOURCES) diff --git a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml b/plugins/save-attachments/org-gnome-save-attachments.eplug.xml deleted file mode 100644 index d51b341db4..0000000000 --- a/plugins/save-attachments/org-gnome-save-attachments.eplug.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - <_description>A plugin for saving all attachments or parts of a message at once. - - - - - - - - - - diff --git a/plugins/save-attachments/org-gnome-save-attachments.xml b/plugins/save-attachments/org-gnome-save-attachments.xml deleted file mode 100644 index 75f4aef7fb..0000000000 --- a/plugins/save-attachments/org-gnome-save-attachments.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - diff --git a/plugins/save-attachments/save-attachments.c b/plugins/save-attachments/save-attachments.c deleted file mode 100644 index c48711c55a..0000000000 --- a/plugins/save-attachments/save-attachments.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Michael Zucchi - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -/* This is prototype code only, this may, or may not, use undocumented - * unstable or private internal function calls. */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "e-util/e-error.h" - -#include "mail/em-menu.h" -#include "mail/em-utils.h" - -/* these are sort of mail-internal */ -#include "mail/mail-mt.h" -#include "mail/mail-ops.h" - -void org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target); - -struct _save_data { - CamelFolder *folder; - char *uid; - CamelMimeMessage *msg; - - char *path; - char *base; - - GtkWidget *entry; - GtkWidget *tree; - GtkTreeStore *model; -}; - -static void -free_data(struct _save_data *data) -{ - if (data->msg) - camel_object_unref(data->msg); - g_free(data->base); - g_free(data->path); - g_free(data->uid); - camel_object_unref(data->folder); - if (data->model) - g_object_unref(data->model); - g_free(data); -} - -static char * -clean_name(const char *s) -{ - GString *out = g_string_new(""); - int c; - char *r; - - while ( (c = camel_utf8_getc((const unsigned char **)&s)) ) { - if (!g_unichar_isprint(c) || ( c < 0x7f && strchr(" /'\"`&();|<>$%{}!", c ))) - c = '_'; - g_string_append_u(out, c); - } - - r = g_strdup(out->str); - g_string_free(out, TRUE); - - return r; -} - -static void -fill_model_rec(CamelMimeMessage *msg, CamelMimePart *part, GtkTreeStore *model, GtkTreeIter *parent, GString *name) -{ - CamelDataWrapper *containee; - int parts, i; - char *type; - GtkTreeIter iter; - int len = name->len; - CamelContentType *mime; - - containee = camel_medium_get_content_object((CamelMedium *)part); - if (containee == NULL) - return; - - mime = ((CamelDataWrapper *)containee)->mime_type; - type = camel_content_type_simple(mime); - - if (CAMEL_IS_MULTIPART(containee)) { - gtk_tree_store_append(model, &iter, parent); - g_string_append_printf(name, ".multipart"); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1); - - parts = camel_multipart_get_number((CamelMultipart *)containee); - for (i = 0; i < parts; i++) { - CamelMimePart *mpart = camel_multipart_get_part((CamelMultipart *)containee, i); - - g_string_truncate(name, len); - g_string_append_printf(name, ".%d", i); - fill_model_rec(msg, mpart, model, &iter, name); - } - } else if (CAMEL_IS_MIME_MESSAGE(containee)) { - gtk_tree_store_append(model, &iter, parent); - g_string_append_printf(name, ".msg"); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, type, 2, name->str, 3, name->str, 4, part, -1); - fill_model_rec(msg, (CamelMimePart *)containee, model, &iter, name); - } else { - char *filename = NULL; - const char *ext = NULL, *tmp; - int save = FALSE; - - gtk_tree_store_append(model, &iter, parent); - tmp = camel_mime_part_get_filename(part); - if (tmp) { - filename = clean_name(tmp); - ext = strrchr(filename, '.'); - } - tmp = camel_mime_part_get_disposition(part); - if (tmp && !strcmp(tmp, "attachment")) - save = TRUE; - - if (camel_content_type_is(mime, "text", "*")) { - if (ext == NULL) { - if ((ext = mime->subtype) == NULL || !strcmp(ext, "plain")) - ext = "text"; - } - } else if (camel_content_type_is(mime, "image", "*")) { - if (ext == NULL) { - if ((ext = mime->subtype) == NULL) - ext = "image"; - } - save = TRUE; - } - - g_string_append_printf(name, ".%s", ext); - gtk_tree_store_set(model, &iter, 0, save, 1, type, 2, filename?filename:name->str, 3, filename?NULL:name->str, 4, part, -1); - g_free(filename); - } - g_free(type); - - g_string_truncate(name, len); -} - -static void -fill_model(CamelMimeMessage *msg, GtkTreeStore *model) -{ - GString *name = g_string_new(""); - GtkTreeIter iter; - - gtk_tree_store_append(model, &iter, NULL); - gtk_tree_store_set(model, &iter, 0, FALSE, 1, "message/rfc822", 2, ".msg", 3, ".msg", 4, msg, -1); - fill_model_rec(msg, (CamelMimePart *)msg, model, &iter, name); - g_string_free(name, TRUE); -} - -static gboolean -save_part(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d) -{ - struct _save_data *data = d; - char *filename, *ext, *save; - CamelMimePart *part; - gboolean doit; - - /* TODO: check for existing file */ - - gtk_tree_model_get(model, iter, 0, &doit, -1); - if (!doit) - return FALSE; - - gtk_tree_model_get(model, iter, 2, &filename, 3, &ext, 4, &part, -1); - if (ext == NULL) - save = g_build_filename(data->path, filename, NULL); - else - save = g_strdup_printf("%s%s", data->base, ext); - - /* FIXME: if part == data->msg then we need to save this - * differently, not using the envelope MimePart */ - - /* - * The underlying em_utils_save_part_to_file ain't using gnome-vfs. Therefor - * the POSIX access-call should suffice for checking the file existence. - */ - - if (g_access(save, F_OK) == 0) - doit = e_error_run(NULL, E_ERROR_ASK_FILE_EXISTS_OVERWRITE, save, NULL) == GTK_RESPONSE_OK; - - if (doit) - em_utils_save_part_to_file(NULL, save, part); - - g_free(ext); - g_free(filename); - - return FALSE; -} - -static void -save_response(GtkWidget *d, int id, struct _save_data *data) -{ - if (id == GTK_RESPONSE_OK) { - char *tmp; - - data->base = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry)); - data->path = g_strdup(data->base); - tmp = strrchr(data->path, '/'); - if (tmp) - *tmp = 0; - gtk_tree_model_foreach((GtkTreeModel *)data->model, save_part, data); - } - - gtk_widget_destroy(d); - free_data(data); -} - -static gboolean -entry_changed_update(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, void *d) -{ - const char *name = d; - char *filename, *ext; - - gtk_tree_model_get(model, iter, 3, &ext, -1); - if (ext) { - filename = g_strdup_printf("%s%s", name, ext); - gtk_tree_store_set((GtkTreeStore *)model, iter, 2, filename, -1); - g_free(filename); - g_free(ext); - } - - return FALSE; -} - -static void -entry_changed(GtkWidget *entry, struct _save_data *data) -{ - char *path; - char *basename = NULL; - const char *file; - - path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (data->entry)); - if (path == NULL - || G_IS_DIR_SEPARATOR (path[strlen(path)-1]) - || (basename = g_path_get_basename(path)) == NULL - || (basename[0] == '.' && basename[1] == '\0') - || (g_file_test(path, G_FILE_TEST_IS_DIR))) - file = "attachment"; - else - file = basename; - - gtk_tree_model_foreach((GtkTreeModel *)data->model, entry_changed_update, (void *)file); - g_free(path); - g_free(basename); -} - -static void -toggle_changed(GtkWidget *entry, const char *spath, struct _save_data *data) -{ - GtkTreePath *path; - GtkTreeIter iter; - - path = gtk_tree_path_new_from_string(spath); - if (gtk_tree_model_get_iter((GtkTreeModel *)data->model, &iter, path)) { - gboolean on; - - gtk_tree_model_get((GtkTreeModel *)data->model, &iter, 0, &on, -1); - gtk_tree_store_set(data->model, &iter, 0, !on, -1); - } - - gtk_tree_path_free (path); -} - -static void -save_got_message(CamelFolder *folder, const char *uid, CamelMimeMessage *msg, void *d) -{ - struct _save_data *data = d; - GtkDialog *dialog; - GtkWidget *w, *tree; - GtkTreeStore *model; - GtkCellRenderer *renderer; - - /* not found, the mailer will show an error box for this */ - if (msg == NULL) { - free_data(data); - return; - } - - data->msg = msg; - camel_object_ref(msg); - - dialog = (GtkDialog *)gtk_dialog_new_with_buttons(_("Save attachments"), - NULL, /* target->parent? */ - 0, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); - w = gtk_file_chooser_button_new (_("Select save base name"), GTK_FILE_CHOOSER_ACTION_OPEN); - data->entry = w; - g_object_set(w, "filechooser_action", GTK_FILE_CHOOSER_ACTION_SAVE, NULL); - gtk_widget_show(w); - gtk_box_pack_start((GtkBox *)dialog->vbox, w, FALSE, TRUE, 6); - - g_signal_connect(GTK_FILE_CHOOSER_BUTTON (w), "selection-changed", G_CALLBACK(entry_changed), data); - - model = gtk_tree_store_new(5, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); - data->model = model; - fill_model(msg, model); - - tree = gtk_tree_view_new_with_model((GtkTreeModel *)model); - data->tree = tree; - gtk_widget_show(tree); - gtk_tree_view_expand_all((GtkTreeView *)tree); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("MIME Type"), renderer, "text", 1, NULL); - gtk_tree_view_set_expander_column((GtkTreeView *)tree, gtk_tree_view_get_column((GtkTreeView *)tree, 0)); - - renderer = gtk_cell_renderer_toggle_new(); - g_object_set(renderer, "activatable", TRUE, NULL); - g_signal_connect(renderer, "toggled", G_CALLBACK(toggle_changed), data); - - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("Save"), renderer, "active", 0, NULL); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes((GtkTreeView *)tree, -1, - _("Name"), renderer, "text", 2, NULL); - - w = g_object_new(gtk_frame_get_type(), - "shadow_type", GTK_SHADOW_NONE, - "label_widget", g_object_new(gtk_label_get_type(), - "label", "Attachments", - "use_markup", TRUE, - "xalign", 0.0, NULL), - "child", g_object_new(gtk_alignment_get_type(), - "left_padding", 12, - "top_padding", 6, - "child", g_object_new(gtk_scrolled_window_get_type(), - "hscrollbar_policy", GTK_POLICY_AUTOMATIC, - "vscrollbar_policy", GTK_POLICY_AUTOMATIC, - "shadow_type", GTK_SHADOW_IN, - "child", tree, - NULL), - NULL), - NULL); - gtk_widget_show_all(w); - - gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 0); - g_signal_connect(dialog, "response", G_CALLBACK(save_response), data); - gtk_window_set_default_size((GtkWindow *)dialog, 500, 500); - gtk_widget_show((GtkWidget *)dialog); -} - -void -org_gnome_save_attachments_save(EPlugin *ep, EMMenuTargetSelect *target) -{ - struct _save_data *data; - - if (target->uids->len != 1) - return; - - data = g_malloc0(sizeof(*data)); - data->folder = target->folder; - camel_object_ref(data->folder); - data->uid = g_strdup(target->uids->pdata[0]); - - mail_get_message(data->folder, data->uid, save_got_message, data, mail_msg_unordered_push); -} diff --git a/shell/apps_evolution_shell.schemas.in b/shell/apps_evolution_shell.schemas.in index 24172f25ba..c5c6276c25 100644 --- a/shell/apps_evolution_shell.schemas.in +++ b/shell/apps_evolution_shell.schemas.in @@ -41,7 +41,35 @@ - + + + + /schemas/apps/evolution/shell/attachment_view + /apps/evolution/shell/attachment_view + evolution + int + 0 + + Initial attachment view + Initial view for attachment bar widgets. + "0" is Icon View, "1" is List View. + + + + + + + /schemas/apps/evolution/shell/current_folder + /apps/evolution/shell/current-folder + evolution + string + + Initial file chooser folder + Initial folder for GtkFileChooser dialogs. + + + + /schemas/apps/evolution/shell/start_offline diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 95acd8b929..3befe12e9d 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -37,7 +37,15 @@ widgetsinclude_HEADERS = \ e-account-combo-box.h \ e-activity-handler.h \ e-attachment.h \ - e-attachment-bar.h \ + e-attachment-button.h \ + e-attachment-dialog.h \ + e-attachment-handler.h \ + e-attachment-handler-image.h \ + e-attachment-icon-view.h \ + e-attachment-paned.h \ + e-attachment-store.h \ + e-attachment-tree-view.h \ + e-attachment-view.h \ e-spinner.c \ e-spinner.h \ e-calendar.h \ @@ -51,7 +59,6 @@ widgetsinclude_HEADERS = \ e-combo-button.h \ e-dateedit.h \ e-dropdown-button.h \ - e-expander.h \ e-icon-entry.h \ e-image-chooser.h \ e-info-label.h \ @@ -88,7 +95,15 @@ libemiscwidgets_la_SOURCES = \ e-activity-handler.c \ e-calendar.c \ e-attachment.c \ - e-attachment-bar.c \ + e-attachment-button.c \ + e-attachment-dialog.c \ + e-attachment-handler.c \ + e-attachment-handler-image.c \ + e-attachment-icon-view.c \ + e-attachment-paned.c \ + e-attachment-store.c \ + e-attachment-tree-view.c \ + e-attachment-view.c \ e-calendar-item.c \ e-cell-date-edit.c \ e-cell-percent.c \ @@ -99,7 +114,6 @@ libemiscwidgets_la_SOURCES = \ e-combo-button.c \ e-dateedit.c \ e-dropdown-button.c \ - e-expander.c \ e-icon-entry.c \ e-image-chooser.c \ e-info-label.c \ diff --git a/widgets/misc/e-attachment-bar.c b/widgets/misc/e-attachment-bar.c deleted file mode 100644 index 0210d21b46..0000000000 --- a/widgets/misc/e-attachment-bar.c +++ /dev/null @@ -1,1504 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Ettore Perazzoli - * Jeffrey Stedfast - * Srinivasa Ragavan - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H -#include -#endif - -#include "e-attachment.h" -#include "e-attachment-bar.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "e-util/e-util.h" -#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" - -#define ICON_WIDTH 64 -#define ICON_SEPARATORS " /-_" -#define ICON_SPACING 2 -#define ICON_ROW_SPACING ICON_SPACING -#define ICON_COL_SPACING ICON_SPACING -#define ICON_BORDER 2 -#define ICON_TEXT_SPACING 2 - - -static GnomeIconListClass *parent_class = NULL; - -struct _EAttachmentBarPrivate { - GtkWidget *attach; /* attachment file dialogue, if active */ - - /* Recent documents. Use this widget directly when bonoboui is obsoleted */ - GtkWidget *recent; - - gboolean batch_unref; - GPtrArray *attachments; - char *path; -}; - - -enum { - CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - - -static void update (EAttachmentBar *bar); - -/* Attachment handling functions. */ - -static void -attachment_destroy (EAttachmentBar *bar, EAttachment *attachment) -{ - if (bar->priv->batch_unref) - return; - - if (g_ptr_array_remove (bar->priv->attachments, attachment)) { - update (bar); - g_signal_emit (bar, signals[CHANGED], 0); - } -} - -static void -attachment_changed_cb (EAttachment *attachment, - gpointer data) -{ - update (E_ATTACHMENT_BAR (data)); -} - -static void -add_common (EAttachmentBar *bar, EAttachment *attachment) -{ - g_return_if_fail (attachment != NULL); - - g_ptr_array_add (bar->priv->attachments, attachment); - g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar); - g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar); - - update (bar); - - g_signal_emit (bar, signals[CHANGED], 0); -} - -static void -add_from_mime_part (EAttachmentBar *bar, CamelMimePart *part) -{ - add_common (bar, e_attachment_new_from_mime_part (part)); -} - -static void -add_from_file (EAttachmentBar *bar, const char *file_name, const char *disposition) -{ - EAttachment *attachment; - CamelException ex; - - camel_exception_init (&ex); - - if ((attachment = e_attachment_new (file_name, disposition, &ex))) { - add_common (bar, attachment); - } else { - /* FIXME: Avoid using error from mailer */ - e_error_run ((GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar), "mail-composer:no-attach", - file_name, camel_exception_get_description (&ex), NULL); - camel_exception_clear (&ex); - } -} - -/* get_system_thumbnail: - * If filled store_uri, then creating thumbnail for it, otherwise, if is_available_local, - * and attachment is not an application, then save to temp and create a thumbnail for the body. - * Otherwise returns NULL (or if something goes wrong/library not available). - */ -static GdkPixbuf * -get_system_thumbnail (EAttachment *attachment, CamelContentType *content_type) -{ - GdkPixbuf *pixbuf = NULL; -#ifdef HAVE_LIBGNOMEUI_GNOME_THUMBNAIL_H - struct stat file_stat; - char *file_uri = NULL; - gboolean is_tmp = FALSE; - - if (!attachment || !attachment->is_available_local) - return NULL; - - if (attachment->store_uri && g_str_has_prefix (attachment->store_uri, "file://")) - file_uri = attachment->store_uri; - else if (attachment->body) { - /* save part to the temp directory */ - char *tmp_file; - - is_tmp = TRUE; - - tmp_file = e_mktemp ("tmp-XXXXXX"); - if (tmp_file) { - CamelStream *stream; - char *mfilename = NULL; - const char * filename; - - filename = camel_mime_part_get_filename (attachment->body); - if (filename == NULL) - filename = "unknown"; - else { - char *utf8_mfilename; - - utf8_mfilename = g_strdup (filename); - e_filename_make_safe (utf8_mfilename); - mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL); - g_free (utf8_mfilename); - - filename = (const char *) mfilename; - } - - file_uri = g_strjoin (NULL, "file://", tmp_file, "-", filename, NULL); - - stream = camel_stream_fs_new_with_name (file_uri + 7, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (stream) { - CamelDataWrapper *content; - - content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body)); - - if (camel_data_wrapper_decode_to_stream (content, stream) == -1 - || camel_stream_flush (stream) == -1) { - g_free (file_uri); - file_uri = NULL; - } - - camel_object_unref (stream); - } else { - g_free (file_uri); - file_uri = NULL; - } - - g_free (mfilename); - g_free (tmp_file); - } - } - - if (!file_uri || !g_str_has_prefix (file_uri, "file://")) { - if (is_tmp) - g_free (file_uri); - - return NULL; - } - - if (stat (file_uri + 7, &file_stat) != -1 && S_ISREG (file_stat.st_mode)) { - GnomeThumbnailFactory *th_factory; - char *th_file; - - th_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL); - th_file = gnome_thumbnail_factory_lookup (th_factory, file_uri, file_stat.st_mtime); - - if (th_file) { - pixbuf = gdk_pixbuf_new_from_file (th_file, NULL); - g_free (th_file); - } else if (content_type) { - char *mime = camel_content_type_simple (content_type); - - if (gnome_thumbnail_factory_can_thumbnail (th_factory, file_uri, mime, file_stat.st_mtime)) { - pixbuf = gnome_thumbnail_factory_generate_thumbnail (th_factory, file_uri, mime); - - if (pixbuf && !is_tmp) - gnome_thumbnail_factory_save_thumbnail (th_factory, pixbuf, file_uri, file_stat.st_mtime); - } - - g_free (mime); - } - - g_object_unref (th_factory); - } - - if (is_tmp) { - /* clear the temp */ - g_remove (file_uri + 7); - g_free (file_uri); - } -#endif - - return pixbuf; -} - -static GdkPixbuf * -scale_pixbuf (GdkPixbuf *pixbuf) -{ - int ratio, width, height; - - if (!pixbuf) - return NULL; - - width = gdk_pixbuf_get_width (pixbuf); - height = gdk_pixbuf_get_height (pixbuf); - if (width >= height) { - if (width > 48) { - ratio = width / 48; - width = 48; - height = height / ratio; - if (height == 0) - height = 1; - } - } else { - if (height > 48) { - ratio = height / 48; - height = 48; - width = width / ratio; - if (width == 0) - width = 1; - } - } - - return e_icon_factory_pixbuf_scale (pixbuf, width, height); -} - -/* Icon list contents handling. */ - -static void -calculate_height_width(EAttachmentBar *bar, int *new_width, int *new_height) -{ - int width, height, icon_width; - PangoFontMetrics *metrics; - PangoContext *context; - - context = gtk_widget_get_pango_context ((GtkWidget *) bar); - metrics = pango_context_get_metrics (context, ((GtkWidget *) bar)->style->font_desc, pango_context_get_language (context)); - width = PANGO_PIXELS (pango_font_metrics_get_approximate_char_width (metrics)) * 15; - /* This should be *2, but the icon list creates too much space above ... */ - height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + pango_font_metrics_get_descent (metrics)) * 3; - pango_font_metrics_unref (metrics); - icon_width = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING; - - if (new_width) - *new_width = MAX (icon_width, width); - - if (new_height) - *new_height = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING + height; - - return; -} - -void -e_attachment_bar_create_attachment_cache (EAttachment *attachment) -{ - - CamelContentType *content_type; - - if (!attachment->body) - return; - - content_type = camel_mime_part_get_content_type (attachment->body); - - if (camel_content_type_is(content_type, "image", "*")) { - CamelDataWrapper *wrapper; - CamelStreamMem *mstream; - GdkPixbufLoader *loader; - gboolean error = TRUE; - GdkPixbuf *pixbuf; - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body)); - mstream = (CamelStreamMem *) camel_stream_mem_new (); - - camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream); - - /* Stream image into pixbuf loader */ - loader = gdk_pixbuf_loader_new (); - error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL); - gdk_pixbuf_loader_close (loader, NULL); - - if (!error) { - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - attachment->pixbuf_cache = scale_pixbuf (pixbuf); - pixbuf = attachment->pixbuf_cache; - g_object_ref(pixbuf); - } else { - attachment->pixbuf_cache = NULL; - g_warning ("GdkPixbufLoader Error"); - } - - /* Destroy everything */ - g_object_unref (loader); - camel_object_unref (mstream); - } -} - -static void -update (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - GnomeIconList *icon_list; - int bar_width, bar_height; - int i; - - priv = bar->priv; - icon_list = GNOME_ICON_LIST (bar); - - gnome_icon_list_freeze (icon_list); - - gnome_icon_list_clear (icon_list); - - /* FIXME could be faster, but we don't care. */ - for (i = 0; i < priv->attachments->len; i++) { - EAttachment *attachment; - CamelContentType *content_type; - char *size_string, *label; - GdkPixbuf *pixbuf = NULL; - char *desc; - - attachment = priv->attachments->pdata[i]; - - if (!attachment->is_available_local || !attachment->body) { - if ((pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG))) { - 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 */ - if ((pixbuf = attachment->pixbuf_cache)) { - g_object_ref(pixbuf); - } else if (camel_content_type_is(content_type, "image", "*")) { - CamelDataWrapper *wrapper; - CamelStreamMem *mstream; - GdkPixbufLoader *loader; - gboolean error = TRUE; - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body)); - mstream = (CamelStreamMem *) camel_stream_mem_new (); - - camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) mstream); - - /* Stream image into pixbuf loader */ - loader = gdk_pixbuf_loader_new (); - error = !gdk_pixbuf_loader_write (loader, mstream->buffer->data, mstream->buffer->len, NULL); - gdk_pixbuf_loader_close (loader, NULL); - - if (!error) { - pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); - attachment->pixbuf_cache = scale_pixbuf (pixbuf); - pixbuf = attachment->pixbuf_cache; - g_object_ref (pixbuf); - } else { - pixbuf = NULL; - g_warning ("GdkPixbufLoader Error"); - } - - /* Destroy everything */ - g_object_unref (loader); - camel_object_unref (mstream); - } else if (!bar->expand && (pixbuf = get_system_thumbnail (attachment, content_type))) { - attachment->pixbuf_cache = scale_pixbuf (pixbuf); - pixbuf = attachment->pixbuf_cache; - g_object_ref (pixbuf); - } - - desc = camel_mime_part_get_description (attachment->body); - - if (!desc || *desc == '\0') { - if (attachment->file_name) { - desc = g_filename_to_utf8 (attachment->file_name, -1, NULL, NULL, NULL); - } else { - desc = camel_mime_part_get_filename (attachment->body); - if (desc) - desc = g_strdup (desc); - } - } else { - desc = g_strdup (desc); - } - - if (!desc) - desc = g_strdup (_("attachment")); - - if (attachment->size && (size_string = g_format_size_for_display (attachment->size))) { - label = g_strdup_printf ("%s (%s)", desc, size_string); - g_free (desc); - g_free (size_string); - } else { - label = g_strdup (desc); - g_free (desc); - } - - if (pixbuf == NULL) { - char *mime_type; - - mime_type = camel_content_type_simple (content_type); - pixbuf = e_icon_for_mime_type (mime_type, 48); - if (pixbuf == NULL) { - g_warning("cannot find icon for mime type %s (installation problem?)", mime_type); - pixbuf = e_icon_factory_get_icon("mail-attachment", E_ICON_SIZE_DIALOG); - } - g_free (mime_type); - - /* remember this picture and use it later again */ - if (pixbuf) - attachment->pixbuf_cache = g_object_ref (pixbuf); - } - - if (pixbuf) { - GdkPixbuf *pixbuf_orig = pixbuf; - pixbuf = gdk_pixbuf_add_alpha (pixbuf_orig, TRUE, 255, 255, 255); - - /* gdk_pixbuf_add_alpha returns a newly allocated pixbuf, - free the original one. - */ - g_object_unref (pixbuf_orig); - - /* In case of a attachment bar, in a signed/encrypted part, display the status as a emblem*/ - if (attachment->sign) { - /* Show the signature status at the right-bottom.*/ - GdkPixbuf *sign = NULL; - int x, y; - - if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_BAD) - sign = e_icon_factory_get_icon ("stock_signature-bad", E_ICON_SIZE_MENU); - else if (attachment->sign == CAMEL_CIPHER_VALIDITY_SIGN_GOOD) - sign = e_icon_factory_get_icon ("stock_signature-ok", E_ICON_SIZE_MENU); - else - sign = e_icon_factory_get_icon ("stock_signature", E_ICON_SIZE_MENU); - - x = gdk_pixbuf_get_width (pixbuf) - 17; - y = gdk_pixbuf_get_height (pixbuf) - 17; - - gdk_pixbuf_copy_area (sign, 0, 0, 16, 16, pixbuf, x, y); - g_object_unref (sign); - } - - if (attachment->encrypt) { - /* Show the encryption status at the top left.*/ - GdkPixbuf *encrypt = e_icon_factory_get_icon ("stock_lock-ok", E_ICON_SIZE_MENU); - - gdk_pixbuf_copy_area (encrypt, 0, 0, 16, 16, pixbuf, 1, 1); - g_object_unref (encrypt); - } - - gnome_icon_list_append_pixbuf (icon_list, pixbuf, NULL, label); - g_object_unref (pixbuf); - } - - g_free (label); - } - - gnome_icon_list_thaw (icon_list); - - /* Resize */ - if (bar->expand) { - gtk_widget_get_size_request ((GtkWidget *) bar, &bar_width, &bar_height); - - if (bar->priv->attachments->len) { - int per_col, rows, height, width; - - calculate_height_width(bar, &width, &height); - per_col = bar_width / width; - per_col = (per_col ? per_col : 1); - rows = (bar->priv->attachments->len + per_col -1) / per_col; - gtk_widget_set_size_request ((GtkWidget *) bar, bar_width, rows * height); - } - } -} - -static void -update_remote_file (EAttachment *attachment, EAttachmentBar *bar) -{ - GnomeIconList *icon_list; - GnomeIconTextItem *item; - char *msg, *base; - - if (attachment->percentage == -1) { - update (bar); - return; - } - - base = g_path_get_basename(attachment->file_name); - msg = g_strdup_printf("%s (%d%%)", base, attachment->percentage); - g_free(base); - - 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); -} - -void -e_attachment_bar_remove_selected (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - int id, left, nrem = 0; - GList *items; - GPtrArray *temp_arr; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - priv = bar->priv; - - if (!(items = gnome_icon_list_get_selection ((GnomeIconList *) bar))) - return; - - temp_arr = g_ptr_array_new (); - while (items != NULL) { - if ((id = GPOINTER_TO_INT (items->data) - nrem) < priv->attachments->len) { - attachment = E_ATTACHMENT(g_ptr_array_index (priv->attachments, id)); - g_ptr_array_add (temp_arr, (gpointer)attachment); - g_ptr_array_remove_index (priv->attachments, id); - nrem++; - } - - items = items->next; - } - - g_ptr_array_foreach (temp_arr, (GFunc)g_object_unref, NULL); - g_ptr_array_free (temp_arr, TRUE); - - update (bar); - - g_signal_emit (bar, signals[CHANGED], 0); - - id++; - - if ((left = gnome_icon_list_get_num_icons ((GnomeIconList *) bar)) > 0) - gnome_icon_list_focus_icon ((GnomeIconList *) bar, left > id ? id : left - 1); -} - -void -e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width) -{ - int per_col, rows, height, width; - - calculate_height_width(bar, &width, &height); - per_col = bar_width / width; - per_col = (per_col ? per_col : 1); - rows = (bar->priv->attachments->len + per_col - 1) / per_col; - gtk_widget_set_size_request ((GtkWidget *)bar, bar_width, rows * height); -} - -void -e_attachment_bar_edit_selected (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - GList *items; - int id; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - priv = bar->priv; - - items = gnome_icon_list_get_selection ((GnomeIconList *) bar); - while (items != NULL) { - if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) { - attachment = priv->attachments->pdata[id]; - e_attachment_edit (attachment, GTK_WIDGET (bar)); - } - - items = items->next; - } -} - -GtkWidget ** -e_attachment_bar_get_selector(EAttachmentBar *bar) -{ - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - return &bar->priv->attach; -} - -/** - * e_attachment_bar_get_selected: - * @bar: an #EAttachmentBar object - * - * Returns a newly allocated #GSList of ref'd #EAttachment objects - * representing the selected items in the #EAttachmentBar Icon List. - **/ -GSList * -e_attachment_bar_get_selected (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - GSList *attachments = NULL; - EAttachment *attachment; - GList *items; - int id; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - priv = bar->priv; - - items = gnome_icon_list_get_selection ((GnomeIconList *) bar); - - while (items != NULL) { - if ((id = GPOINTER_TO_INT (items->data)) < priv->attachments->len) { - attachment = priv->attachments->pdata[id]; - attachments = g_slist_prepend (attachments, attachment); - g_object_ref (attachment); - } - - items = items->next; - } - - attachments = g_slist_reverse (attachments); - - return attachments; -} - -/* FIXME: Cleanup this, since there is a api to get selected attachments */ -/** - * e_attachment_bar_get_attachment: - * @bar: an #EAttachmentBar object - * @id: Index of the desired attachment or -1 to request all selected attachments - * - * Returns a newly allocated #GSList of ref'd #EAttachment objects - * representing the requested item(s) in the #EAttachmentBar Icon - * List. - **/ -GSList * -e_attachment_bar_get_attachment (EAttachmentBar *bar, int id) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - GSList *attachments; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - priv = bar->priv; - - if (id == -1 || id > priv->attachments->len) - return e_attachment_bar_get_selected (bar); - - attachment = priv->attachments->pdata[id]; - attachments = g_slist_prepend (NULL, attachment); - g_object_ref (attachment); - - return attachments; -} - - -/** - * e_attachment_bar_get_all_attachments: - * @bar: an #EAttachmentBar object - * - * Returns a newly allocated #GSList of ref'd #EAttachment objects. - **/ -GSList * -e_attachment_bar_get_all_attachments (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - GSList *attachments = NULL; - EAttachment *attachment; - int i; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - priv = bar->priv; - - for (i = priv->attachments->len - 1; i >= 0; i--) { - attachment = priv->attachments->pdata[i]; - if (attachment->is_available_local) { - attachments = g_slist_prepend (attachments, attachment); - g_object_ref (attachment); - } - } - - return attachments; -} - -/* Just the GSList has to be freed by the caller */ -GSList * -e_attachment_bar_get_parts (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - GSList *parts = NULL; - int i; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - priv = bar->priv; - - for (i = 0; i < priv->attachments->len; i++) { - attachment = priv->attachments->pdata[i]; - if (attachment->is_available_local) - parts = g_slist_prepend (parts, attachment->body); - } - - return parts; -} - -/* GtkObject methods. */ - -static void -destroy (GtkObject *object) -{ - EAttachmentBar *bar = (EAttachmentBar *) object; - struct _EAttachmentBarPrivate *priv = bar->priv; - EAttachment *attachment; - int i; - - if ((priv = bar->priv)) { - priv->batch_unref = TRUE; - for (i = 0; i < priv->attachments->len; i++) { - attachment = priv->attachments->pdata[i]; - g_object_weak_unref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar); - g_object_unref (attachment); - } - g_ptr_array_free (priv->attachments, TRUE); - - if (priv->attach) - gtk_widget_destroy (priv->attach); - - if (priv->recent) - gtk_widget_destroy (priv->recent); - - if (priv->path) - g_free (priv->path); - - g_free (priv); - bar->priv = NULL; - } - - if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - -static char * -temp_save_part (CamelMimePart *part, gboolean readonly) -{ - const char *filename; - char *tmpdir, *path, *mfilename = NULL, *utf8_mfilename = NULL; - CamelStream *stream; - CamelDataWrapper *wrapper; - - if (!(tmpdir = e_mkdtemp ("evolution-tmp-XXXXXX"))) - return NULL; - - if (!(filename = camel_mime_part_get_filename (part))) { - /* This is the default filename used for temporary file creation */ - filename = _("Unknown"); - } else { - utf8_mfilename = g_strdup (filename); - e_filename_make_safe (utf8_mfilename); - mfilename = g_filename_from_utf8 ((const char *) utf8_mfilename, -1, NULL, NULL, NULL); - g_free (utf8_mfilename); - filename = (const char *) mfilename; - } - - path = g_build_filename (tmpdir, filename, NULL); - g_free (tmpdir); - g_free (mfilename); - - wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (part)); - if (readonly) - stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0444); - else - stream = camel_stream_fs_new_with_name (path, O_RDWR|O_CREAT|O_TRUNC, 0644); - - if (!stream) { - /* TODO handle error conditions */ - g_message ("DEBUG: could not open the file to write\n"); - g_free (path); - return NULL; - } - - if (camel_data_wrapper_decode_to_stream (wrapper, (CamelStream *) stream) == -1) { - g_free (path); - camel_stream_close (stream); - camel_object_unref (stream); - g_message ("DEBUG: could not write to file\n"); - return NULL; - } - - camel_stream_close(stream); - camel_object_unref(stream); - - return path; -} - -static void -eab_drag_data_get(EAttachmentBar *bar, GdkDragContext *drag, GtkSelectionData *data, guint info, guint time) -{ - struct _EAttachmentBarPrivate *priv = bar->priv; - EAttachment *attachment; - char *path, **uris; - int len, n, i = 0; - CamelURL *url; - GList *items; - - if (info) - return; - - items = gnome_icon_list_get_selection (GNOME_ICON_LIST (bar)); - len = g_list_length (items); - - uris = g_malloc0 (sizeof (char *) * (len + 1)); - - for ( ; items != NULL; items = items->next) { - if (!((n = GPOINTER_TO_INT (items->data)) < priv->attachments->len)) - continue; - - attachment = priv->attachments->pdata[n]; - - if (!attachment->is_available_local) - continue; - - if (attachment->store_uri) { - uris[i++] = attachment->store_uri; - continue; - } - - /* If we are not able to save, ignore it */ - if (!(path = temp_save_part (attachment->body, FALSE))) - continue; - - url = camel_url_new ("file://", NULL); - camel_url_set_path (url, path); - attachment->store_uri = camel_url_to_string (url, 0); - camel_url_free (url); - g_free (path); - - uris[i++] = attachment->store_uri; - } - - uris[i] = NULL; - - gtk_selection_data_set_uris (data, uris); - - g_free (uris); - - return; -} - -static gboolean -eab_button_release_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy) -{ - GnomeIconList *icon_list = GNOME_ICON_LIST(bar); - GList *selected; - int length; - GtkTargetEntry drag_types[] = { - { "text/uri-list", 0, 0 }, - }; - - if (event && event->button == 1) { - selected = gnome_icon_list_get_selection(icon_list); - length = g_list_length (selected); - if (length) - gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY); - else - gtk_drag_source_unset((GtkWidget *)bar); - } - - return FALSE; -} - -static gboolean -eab_button_press_event(EAttachmentBar *bar, GdkEventButton *event, gpointer dummy) -{ - GnomeIconList *icon_list = GNOME_ICON_LIST(bar); - GList *selected = NULL, *tmp; - int length, icon_number; - gboolean take_selected = FALSE; - GtkTargetEntry drag_types[] = { - { "text/uri-list", 0, 0 }, - }; - - selected = gnome_icon_list_get_selection(icon_list); - length = g_list_length (selected); - - if (event) { - icon_number = gnome_icon_list_get_icon_at(icon_list, event->x, event->y); - if (icon_number < 0) { - /* When nothing is selected, deselect all */ - gnome_icon_list_unselect_all (icon_list); - length = 0; - selected = NULL; - } - - if (event->button == 1) { - /* If something is selected, then allow drag or else help to select */ - if (length) - gtk_drag_source_set((GtkWidget *)bar, GDK_BUTTON1_MASK, drag_types, G_N_ELEMENTS(drag_types), GDK_ACTION_COPY); - else - gtk_drag_source_unset((GtkWidget *)bar); - return FALSE; - } - - /* If not r-click dont progress any more.*/ - if (event->button != 3) - return FALSE; - - /* When a r-click on something, if it is in the already selected list, consider a r-click of multiple things - * or deselect all and select only this for r-click - */ - if (icon_number >= 0) { - for (tmp = selected; tmp; tmp = tmp->next) { - if (GPOINTER_TO_INT(tmp->data) == icon_number) - take_selected = TRUE; - } - - if (!take_selected) { - gnome_icon_list_unselect_all(icon_list); - gnome_icon_list_select_icon(icon_list, icon_number); - } - } - } - - return FALSE; -} - -static gboolean -eab_icon_clicked_cb (EAttachmentBar *bar, GdkEvent *event, gpointer *dummy) -{ - EAttachment *attachment; - gboolean ret = FALSE; - CamelURL *url; - char *path; - GSList *p; - - if (E_IS_ATTACHMENT_BAR (bar) && event->type == GDK_2BUTTON_PRESS) { - p = e_attachment_bar_get_selected (bar); - /* check if has body already, remote files can take longer to fetch */ - if (p && p->next == NULL && ((EAttachment *)p->data)->body) { - attachment = p->data; - - /* Check if the file is stored already */ - if (!attachment->store_uri) { - path = temp_save_part (attachment->body, TRUE); - url = camel_url_new ("file://", NULL); - camel_url_set_path (url, path); - attachment->store_uri = camel_url_to_string (url, 0); - camel_url_free (url); - g_free (path); - } - - /* FIXME Pass a parent window. */ - e_show_uri (NULL, attachment->store_uri); - - ret = TRUE; - } - - if (p) { - g_slist_foreach (p, (GFunc) g_object_unref, NULL); - g_slist_free (p); - } - } - - return ret; -} - -/* Initialization. */ - -static void -class_init (EAttachmentBarClass *klass) -{ - GtkObjectClass *object_class; - - object_class = GTK_OBJECT_CLASS (klass); - - parent_class = g_type_class_ref (gnome_icon_list_get_type ()); - - object_class->destroy = destroy; - - /* Setup signals. */ - - signals[CHANGED] = - g_signal_new ("changed", - E_TYPE_ATTACHMENT_BAR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EAttachmentBarClass, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -init (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - - priv = g_new (struct _EAttachmentBarPrivate, 1); - - priv->attach = NULL; - priv->batch_unref = FALSE; - priv->attachments = g_ptr_array_new (); - - priv->recent = gtk_recent_chooser_menu_new (); - gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (priv->recent), TRUE); - gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (priv->recent), GTK_RECENT_SORT_MRU); - gtk_recent_chooser_set_show_not_found (GTK_RECENT_CHOOSER (priv->recent), FALSE); - gtk_recent_chooser_set_show_private (GTK_RECENT_CHOOSER (priv->recent), FALSE); - gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (priv->recent), TRUE); - gtk_recent_chooser_set_show_tips (GTK_RECENT_CHOOSER (priv->recent), TRUE); - - priv->path = NULL; - - bar->priv = priv; - bar->expand = FALSE; -} - - -GType -e_attachment_bar_get_type (void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof (EAttachmentBarClass), - NULL, NULL, - (GClassInitFunc) class_init, - NULL, NULL, - sizeof (EAttachmentBar), - 0, - (GInstanceInitFunc) init, - }; - - type = g_type_register_static (GNOME_TYPE_ICON_LIST, "EAttachmentBar", &info, 0); - } - - return type; -} - -GtkWidget * -e_attachment_bar_new (GtkAdjustment *adj) -{ - EAttachmentBar *new; - GnomeIconList *icon_list; - int icon_width, window_height; - - new = g_object_new (e_attachment_bar_get_type (), NULL); - - icon_list = GNOME_ICON_LIST (new); - - calculate_height_width (new, &icon_width, &window_height); - - gnome_icon_list_construct (icon_list, icon_width, adj, 0); - - gtk_widget_set_size_request (GTK_WIDGET (new), icon_width * 4, window_height); - - GTK_WIDGET_SET_FLAGS (new, GTK_CAN_FOCUS); - - gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS); - gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING); - gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING); - gnome_icon_list_set_icon_border (icon_list, ICON_BORDER); - gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING); - gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE); - - atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (new)), - _("Attachment Bar")); - - g_signal_connect (new, "button_release_event", G_CALLBACK(eab_button_release_event), NULL); - g_signal_connect (new, "button_press_event", G_CALLBACK(eab_button_press_event), NULL); - g_signal_connect (new, "drag-data-get", G_CALLBACK(eab_drag_data_get), NULL); - g_signal_connect (icon_list, "event", G_CALLBACK (eab_icon_clicked_cb), NULL); - - return GTK_WIDGET (new); -} - -static char * -get_default_charset (void) -{ - GConfClient *gconf; - const char *locale; - char *charset; - - gconf = gconf_client_get_default (); - charset = gconf_client_get_string (gconf, "/apps/evolution/mail/composer/charset", NULL); - - if (!charset || charset[0] == '\0') { - g_free (charset); - charset = gconf_client_get_string (gconf, "/apps/evolution/mail/format/charset", NULL); - if (charset && charset[0] == '\0') { - g_free (charset); - charset = NULL; - } - } - - g_object_unref (gconf); - - if (!charset && (locale = camel_iconv_locale_charset ())) - charset = g_strdup (locale); - - return charset ? charset : g_strdup ("us-ascii"); -} - -static void -attach_to_multipart (CamelMultipart *multipart, - EAttachment *attachment, - const char *default_charset) -{ - CamelContentType *content_type; - CamelDataWrapper *content; - - if (!attachment->body) - return; - - content_type = camel_mime_part_get_content_type (attachment->body); - content = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body)); - - if (!CAMEL_IS_MULTIPART (content)) { - if (camel_content_type_is (content_type, "text", "*")) { - CamelTransferEncoding encoding; - CamelStreamFilter *filter_stream; - CamelMimeFilterBestenc *bestenc; - CamelStream *stream; - const char *charset; - char *buf = NULL; - char *type; - - charset = camel_content_type_param (content_type, "charset"); - - stream = camel_stream_null_new (); - filter_stream = camel_stream_filter_new_with_stream (stream); - bestenc = camel_mime_filter_bestenc_new (CAMEL_BESTENC_GET_ENCODING); - camel_stream_filter_add (filter_stream, CAMEL_MIME_FILTER (bestenc)); - camel_object_unref (stream); - - camel_data_wrapper_decode_to_stream (content, CAMEL_STREAM (filter_stream)); - camel_object_unref (filter_stream); - - encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT); - camel_mime_part_set_encoding (attachment->body, encoding); - - if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) { - /* the text fits within us-ascii so this is safe */ - /* FIXME: check that this isn't iso-2022-jp? */ - default_charset = "us-ascii"; - } else if (!charset) { - if (!default_charset) - default_charset = buf = get_default_charset (); - - /* FIXME: We should really check that this fits within the - default_charset and if not find one that does and/or - allow the user to specify? */ - } - - if (!charset) { - /* looks kinda nasty, but this is how ya have to do it */ - camel_content_type_set_param (content_type, "charset", default_charset); - type = camel_content_type_format (content_type); - camel_mime_part_set_content_type (attachment->body, type); - g_free (type); - g_free (buf); - } - - camel_object_unref (bestenc); - } else if (!CAMEL_IS_MIME_MESSAGE (content)) { - camel_mime_part_set_encoding (attachment->body, CAMEL_TRANSFER_ENCODING_BASE64); - } - } - - camel_multipart_add_part (multipart, attachment->body); -} - -void -e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, const char *default_charset) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - int i; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (CAMEL_IS_MULTIPART (multipart)); - - priv = bar->priv; - - for (i = 0; i < priv->attachments->len; i++) { - attachment = priv->attachments->pdata[i]; - if (attachment->is_available_local) - attach_to_multipart (multipart, attachment, default_charset); - } -} - -guint -e_attachment_bar_get_num_attachments (EAttachmentBar *bar) -{ - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0); - - return bar->priv->attachments->len; -} - -void -e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (file_name != NULL && disposition != NULL); - - add_from_file (bar, file_name, disposition); -} - -void -e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - add_common (bar, attachment); -} - -void -e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - g_return_if_fail (attachment != NULL); - - g_ptr_array_add (bar->priv->attachments, attachment); - g_object_weak_ref ((GObject *) attachment, (GWeakNotify) attachment_destroy, bar); - g_signal_connect (attachment, "changed", G_CALLBACK (attachment_changed_cb), bar); - - - g_signal_emit (bar, signals[CHANGED], 0); -} - -void -e_attachment_bar_refresh (EAttachmentBar *bar) -{ - update (bar); - -} - -int -e_attachment_bar_get_download_count (EAttachmentBar *bar) -{ - struct _EAttachmentBarPrivate *priv; - EAttachment *attachment; - int i, n = 0; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), 0); - - priv = bar->priv; - - for (i = 0; i < priv->attachments->len; i++) { - attachment = priv->attachments->pdata[i]; - if (!attachment->is_available_local) - n++; - } - - return n; -} - -void -e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition) -{ - EAttachment *attachment; - CamelException ex; - GtkWindow *parent; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - if (!bar->priv->path) - bar->priv->path = e_mkdtemp ("attach-XXXXXX"); - - parent = (GtkWindow *) gtk_widget_get_toplevel ((GtkWidget *) bar); - camel_exception_init (&ex); - if ((attachment = e_attachment_new_remote_file (parent, url, disposition, bar->priv->path, &ex))) { - add_common (bar, attachment); - g_signal_connect (attachment, "update", G_CALLBACK (update_remote_file), bar); - } else { - e_error_run (parent, "mail-composer:no-attach", - url, camel_exception_get_description (&ex), NULL); - camel_exception_clear (&ex); - } -} - -void -e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part) -{ - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - add_from_mime_part (bar, part); -} - -/* FIXME: Remove this API if nobody uses it */ -void -e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path, - EAttachmentBar *bar, - BonoboUIVerbFn verb_cb, gpointer user_data) -{ - struct _EAttachmentBarPrivate *priv; - GList *items, *l; - gint limit, i; - GString *menuitems; - char *encoded_label, *label; - - g_return_if_fail (E_IS_ATTACHMENT_BAR (bar)); - - priv = bar->priv; - limit = gtk_recent_chooser_get_limit (GTK_RECENT_CHOOSER (priv->recent)); - items = gtk_recent_chooser_get_items (GTK_RECENT_CHOOSER (priv->recent)); - - menuitems = g_string_new ("\n"); - - for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) { - GtkRecentInfo *info = ((GtkRecentInfo *)(l->data)); - const gchar *info_dn = gtk_recent_info_get_display_name (info); - char *display_name, *u; - - /* escape _'s in the display name so that it doesn't become an underline in a GtkLabel */ - if ((u = strchr (info_dn, '_'))) { - int extra = 1; - char *d; - const char *s; - - while ((u = strchr (u + 1, '_'))) - extra++; - - d = display_name = g_alloca (strlen (info_dn) + extra + 1); - s = info_dn; - while (*s != '\0') { - if (*s == '_') - *d++ = '_'; - *d++ = *s++; - } - *d = '\0'; - } else - display_name = (char *) info_dn; - - /* Add menu item */ - label = g_strdup (display_name); - encoded_label = bonobo_ui_util_encode_str (label); - g_string_append_printf (menuitems, - " \n", - i, encoded_label); - g_free (encoded_label); - g_free (label); - } - - g_string_append (menuitems, "\n"); - - bonobo_ui_component_set (uic, path, menuitems->str, NULL); - - g_string_free (menuitems, TRUE); - - /* Add uri prop */ - for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) { - GtkRecentInfo *info = ((GtkRecentInfo *)(l->data)); - const gchar *info_uri = gtk_recent_info_get_uri (info); - label = g_strdup_printf ("/commands/Recent-%d", i); - bonobo_ui_component_set_prop (uic, label, "uri", info_uri, NULL); - g_free (label); - } - - /* Add verb */ - for (l = g_list_first (items), i = 1; l && i <= limit; l = l->next, ++i) { - label = g_strdup_printf ("Recent-%d", i); - bonobo_ui_component_add_verb (uic, label, verb_cb, user_data); - g_free (label); - } - - for (l = g_list_first (items); l; l = l->next) - gtk_recent_info_unref ((GtkRecentInfo *)(l->data)); - g_list_free (items); -} - -static void -action_recent_cb (GtkAction *action, - EAttachmentBar *attachment_bar) -{ - GtkRecentChooser *chooser; - GFile *file; - gchar *uri; - - chooser = GTK_RECENT_CHOOSER (action); - - /* Wish: gtk_recent_chooser_get_current_file() */ - uri = gtk_recent_chooser_get_current_uri (chooser); - file = g_file_new_for_uri (uri); - g_free (uri); - - if (g_file_is_native (file)) - e_attachment_bar_attach ( - E_ATTACHMENT_BAR (attachment_bar), - g_file_get_path (file), "attachment"); - else - e_attachment_bar_attach_remote_file ( - E_ATTACHMENT_BAR (attachment_bar), - g_file_get_uri (file), "attachment"); - - g_object_unref (file); -} - -GtkAction * -e_attachment_bar_recent_action_new (EAttachmentBar *bar, - const gchar *action_name, - const gchar *action_label) -{ - GtkAction *action; - GtkRecentChooser *chooser; - - g_return_val_if_fail (E_IS_ATTACHMENT_BAR (bar), NULL); - - action = gtk_recent_action_new ( - action_name, action_label, NULL, NULL); - gtk_recent_action_set_show_numbers (GTK_RECENT_ACTION (action), TRUE); - - chooser = GTK_RECENT_CHOOSER (action); - gtk_recent_chooser_set_show_icons (chooser, TRUE); - gtk_recent_chooser_set_show_not_found (chooser, FALSE); - gtk_recent_chooser_set_show_private (chooser, FALSE); - gtk_recent_chooser_set_show_tips (chooser, TRUE); - gtk_recent_chooser_set_sort_type (chooser, GTK_RECENT_SORT_MRU); - - g_signal_connect ( - action, "item-activated", - G_CALLBACK (action_recent_cb), bar); - - return action; -} - diff --git a/widgets/misc/e-attachment-bar.h b/widgets/misc/e-attachment-bar.h deleted file mode 100644 index 7f8b4795d1..0000000000 --- a/widgets/misc/e-attachment-bar.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Ettore Perazzoli - * Srinivasa Ragavan - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __E_ATTACHMENT_BAR_H__ -#define __E_ATTACHMENT_BAR_H__ - -#include - -#include -#include - -#include -#include "e-attachment.h" - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#define E_TYPE_ATTACHMENT_BAR \ - (e_attachment_bar_get_type ()) -#define E_ATTACHMENT_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT_BAR, EAttachmentBar)) -#define E_ATTACHMENT_BAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT_BAR, EAttachmentBarClass)) -#define E_IS_ATTACHMENT_BAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT_BAR)) -#define E_IS_ATTACHMENT_BAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT_BAR)) - -typedef struct _EAttachmentBar EAttachmentBar; -typedef struct _EAttachmentBarClass EAttachmentBarClass; - -struct _EAttachmentBar { - GnomeIconList parent; - gboolean expand; - - struct _EAttachmentBarPrivate *priv; -}; - -struct _EAttachmentBarClass { - GnomeIconListClass parent_class; - - void (* changed) (EAttachmentBar *bar); -}; - - -GType e_attachment_bar_get_type (void); - -GtkWidget *e_attachment_bar_new (GtkAdjustment *adj); -void e_attachment_bar_to_multipart (EAttachmentBar *bar, CamelMultipart *multipart, - const char *default_charset); -guint e_attachment_bar_get_num_attachments (EAttachmentBar *bar); -void e_attachment_bar_attach (EAttachmentBar *bar, const char *file_name, const char *disposition); -void e_attachment_bar_attach_mime_part (EAttachmentBar *bar, CamelMimePart *part); -int e_attachment_bar_get_download_count (EAttachmentBar *bar); -void e_attachment_bar_attach_remote_file (EAttachmentBar *bar, const char *url, const char *disposition); -GSList *e_attachment_bar_get_attachment (EAttachmentBar *bar, int id); -void e_attachment_bar_add_attachment (EAttachmentBar *bar, EAttachment *attachment); -void e_attachment_bar_edit_selected (EAttachmentBar *bar); -void e_attachment_bar_remove_selected (EAttachmentBar *bar); -GtkWidget ** e_attachment_bar_get_selector(EAttachmentBar *bar); -GSList *e_attachment_bar_get_parts (EAttachmentBar *bar); -GSList *e_attachment_bar_get_selected (EAttachmentBar *bar); -void e_attachment_bar_set_width(EAttachmentBar *bar, int bar_width); -GSList * e_attachment_bar_get_all_attachments (EAttachmentBar *bar); -void e_attachment_bar_create_attachment_cache (EAttachment *attachment); -void -e_attachment_bar_bonobo_ui_populate_with_recent (BonoboUIComponent *uic, const char *path, - EAttachmentBar *bar, - BonoboUIVerbFn verb_cb, gpointer user_data); -GtkAction * -e_attachment_bar_recent_action_new (EAttachmentBar *bar, - const gchar *action_name, - const gchar *action_label); -void -e_attachment_bar_add_attachment_silent (EAttachmentBar *bar, EAttachment *attachment); -void -e_attachment_bar_refresh (EAttachmentBar *bar); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_ATTACHMENT_BAR_H__ */ diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c index 4f5e9ace34..f472a26ff3 100644 --- a/widgets/misc/e-attachment.c +++ b/widgets/misc/e-attachment.c @@ -1,4 +1,5 @@ /* + * e-attachment.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,870 +15,2660 @@ * License along with the program; if not, see * * - * Authors: - * Ettore Perazzoli - * Jeffrey Stedfast - * Srinivasa Ragavan - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef G_OS_WIN32 -/* Include early (as the gio stuff below will - * include it anyway, sigh) to workaround the DATADIR problem. - * (and the headers it includes) stomps all over the - * namespace like a baboon on crack, and especially the DATADIR enum - * in objidl.h causes problems. - */ -#undef DATADIR -#define DATADIR crap_DATADIR -#include -#undef DATADIR -#endif +#include "e-attachment.h" -#include -#include #include - -#include - +#include #include -#include - -#include +#include +#include +#include +#include +#include +#include +#include #include "e-util/e-util.h" -#include "e-util/e-error.h" #include "e-util/e-mktemp.h" -#include "e-util/e-util-private.h" - -#include "e-attachment.h" +#include "e-attachment-store.h" + +#define E_ATTACHMENT_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate)) + +/* Fallback Icon */ +#define DEFAULT_ICON_NAME "mail-attachment" + +/* Emblems */ +#define EMBLEM_CANCELLED "gtk-cancel" +#define EMBLEM_LOADING "emblem-downloads" +#define EMBLEM_SAVING "document-save" +#define EMBLEM_ENCRYPT_WEAK "security-low" +#define EMBLEM_ENCRYPT_STRONG "security-high" +#define EMBLEM_ENCRYPT_UNKNOWN "security-medium" +#define EMBLEM_SIGN_BAD "stock_signature_bad" +#define EMBLEM_SIGN_GOOD "stock_signature-ok" +#define EMBLEM_SIGN_UNKNOWN "stock_signature" + +/* Attributes needed for EAttachmentStore columns. */ +#define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*" + +struct _EAttachmentPrivate { + GFile *file; + GFileInfo *file_info; + GCancellable *cancellable; + CamelMimePart *mime_part; + guint emblem_timeout_id; + gchar *disposition; + gint percent; + + guint can_show : 1; + guint loading : 1; + guint saving : 1; + guint shown : 1; + + camel_cipher_validity_encrypt_t encrypted; + camel_cipher_validity_sign_t signed_; + + /* This is a reference to our row in an EAttachmentStore, + * serving as a means of broadcasting "row-changed" signals. + * If we are removed from the store, we lazily free the + * reference when it is found to be to be invalid. */ + GtkTreeRowReference *reference; +}; enum { - CHANGED, - UPDATE, - LAST_SIGNAL + PROP_0, + PROP_CAN_SHOW, + PROP_DISPOSITION, + PROP_ENCRYPTED, + PROP_FILE, + PROP_FILE_INFO, + PROP_LOADING, + PROP_MIME_PART, + PROP_PERCENT, + PROP_REFERENCE, + PROP_SAVING, + PROP_SHOWN, + PROP_SIGNED }; -static guint signals[LAST_SIGNAL] = { 0 }; +static gpointer parent_class; + +static gchar * +attachment_get_default_charset (void) +{ + GConfClient *client; + const gchar *key; + gchar *charset; + + /* XXX This doesn't really belong here. */ + + client = gconf_client_get_default (); + key = "/apps/evolution/mail/composer/charset"; + charset = gconf_client_get_string (client, key, NULL); + if (charset == NULL || *charset == '\0') { + g_free (charset); + key = "/apps/evolution/mail/format/charset"; + charset = gconf_client_get_string (client, key, NULL); + if (charset == NULL || *charset == '\0') { + g_free (charset); + charset = NULL; + } + } + g_object_unref (client); + + if (charset == NULL) + charset = g_strdup (camel_iconv_locale_charset ()); + + if (charset == NULL) + charset = g_strdup ("us-ascii"); + + return charset; +} + +static void +attachment_update_file_info_columns (EAttachment *attachment) +{ + GtkTreeRowReference *reference; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + GFileInfo *file_info; + const gchar *content_type; + const gchar *description; + const gchar *display_name; + gchar *content_desc; + gchar *display_size; + gchar *caption; + goffset size; + + reference = e_attachment_get_reference (attachment); + if (!gtk_tree_row_reference_valid (reference)) + return; + + file_info = e_attachment_get_file_info (attachment); + if (file_info == NULL) + return; + + model = gtk_tree_row_reference_get_model (reference); + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + content_type = g_file_info_get_content_type (file_info); + display_name = g_file_info_get_display_name (file_info); + size = g_file_info_get_size (file_info); + + content_desc = g_content_type_get_description (content_type); + display_size = g_format_size_for_display (size); + + description = e_attachment_get_description (attachment); + if (description == NULL || *description == '\0') + description = display_name; + + if (size > 0) + caption = g_strdup_printf ( + "%s\n(%s)", description, display_size); + else + caption = g_strdup (description); + + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, + E_ATTACHMENT_STORE_COLUMN_CAPTION, caption, + E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_desc, + E_ATTACHMENT_STORE_COLUMN_DESCRIPTION, description, + E_ATTACHMENT_STORE_COLUMN_SIZE, size, + -1); + + g_free (content_desc); + g_free (display_size); + g_free (caption); +} + +static void +attachment_update_icon_column (EAttachment *attachment) +{ + GtkTreeRowReference *reference; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + GFileInfo *file_info; + GCancellable *cancellable; + GIcon *icon = NULL; + const gchar *emblem_name = NULL; + const gchar *thumbnail_path = NULL; + + reference = e_attachment_get_reference (attachment); + if (!gtk_tree_row_reference_valid (reference)) + return; + + model = gtk_tree_row_reference_get_model (reference); + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + cancellable = attachment->priv->cancellable; + file_info = e_attachment_get_file_info (attachment); + + if (file_info != NULL) { + icon = g_file_info_get_icon (file_info); + thumbnail_path = g_file_info_get_attribute_byte_string ( + file_info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH); + } + + /* Prefer the thumbnail if we have one. */ + if (thumbnail_path != NULL && *thumbnail_path != '\0') { + GFile *file; + + file = g_file_new_for_path (thumbnail_path); + icon = g_file_icon_new (file); + g_object_unref (file); + + /* Else use the standard icon for the content type. */ + } else if (icon != NULL) + g_object_ref (icon); + + /* Last ditch fallback. (GFileInfo not yet loaded?) */ + else + icon = g_themed_icon_new (DEFAULT_ICON_NAME); + + /* Pick an emblem, limit one. Choices listed by priority. */ + + if (g_cancellable_is_cancelled (cancellable)) + emblem_name = EMBLEM_CANCELLED; + + else if (e_attachment_get_loading (attachment)) + emblem_name = EMBLEM_LOADING; + + else if (e_attachment_get_saving (attachment)) + emblem_name = EMBLEM_SAVING; + + else if (e_attachment_get_encrypted (attachment)) + switch (e_attachment_get_encrypted (attachment)) { + case CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK: + emblem_name = EMBLEM_ENCRYPT_WEAK; + break; + + case CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED: + emblem_name = EMBLEM_ENCRYPT_UNKNOWN; + break; + + case CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG: + emblem_name = EMBLEM_ENCRYPT_STRONG; + break; + + default: + g_warn_if_reached (); + break; + } + + else if (e_attachment_get_signed (attachment)) + switch (e_attachment_get_signed (attachment)) { + case CAMEL_CIPHER_VALIDITY_SIGN_GOOD: + emblem_name = EMBLEM_SIGN_GOOD; + break; + + case CAMEL_CIPHER_VALIDITY_SIGN_BAD: + emblem_name = EMBLEM_SIGN_BAD; + break; + + case CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN: + case CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY: + emblem_name = EMBLEM_SIGN_UNKNOWN; + break; + + default: + g_warn_if_reached (); + break; + } + + if (emblem_name != NULL) { + GIcon *emblemed_icon; + GEmblem *emblem; + + emblemed_icon = g_themed_icon_new (emblem_name); + emblem = g_emblem_new (emblemed_icon); + g_object_unref (emblemed_icon); + + emblemed_icon = g_emblemed_icon_new (icon, emblem); + g_object_unref (emblem); + g_object_unref (icon); + + icon = emblemed_icon; + } + + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, + E_ATTACHMENT_STORE_COLUMN_ICON, icon, + -1); + + g_object_unref (icon); +} + +static void +attachment_update_progress_columns (EAttachment *attachment) +{ + GtkTreeRowReference *reference; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + gboolean loading; + gboolean saving; + gint percent; + + reference = e_attachment_get_reference (attachment); + if (!gtk_tree_row_reference_valid (reference)) + return; + + model = gtk_tree_row_reference_get_model (reference); + path = gtk_tree_row_reference_get_path (reference); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + /* Don't show progress bars until we have progress to report. */ + percent = e_attachment_get_percent (attachment); + loading = e_attachment_get_loading (attachment) && (percent > 0); + saving = e_attachment_get_saving (attachment) && (percent > 0); + + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, + E_ATTACHMENT_STORE_COLUMN_LOADING, loading, + E_ATTACHMENT_STORE_COLUMN_PERCENT, percent, + E_ATTACHMENT_STORE_COLUMN_SAVING, saving, + -1); +} + +static void +attachment_set_file_info (EAttachment *attachment, + GFileInfo *file_info) +{ + GtkTreeRowReference *reference; + GIcon *icon; + + reference = e_attachment_get_reference (attachment); + + if (file_info != NULL) + g_object_ref (file_info); + + if (attachment->priv->file_info != NULL) + g_object_unref (attachment->priv->file_info); + + attachment->priv->file_info = file_info; + + /* If the GFileInfo contains a GThemedIcon, append a + * fallback icon name to ensure we display something. */ + icon = g_file_info_get_icon (file_info); + if (G_IS_THEMED_ICON (icon)) + g_themed_icon_append_name ( + G_THEMED_ICON (icon), DEFAULT_ICON_NAME); + + g_object_notify (G_OBJECT (attachment), "file-info"); + + /* Tell the EAttachmentStore its total size changed. */ + if (gtk_tree_row_reference_valid (reference)) { + GtkTreeModel *model; + model = gtk_tree_row_reference_get_model (reference); + g_object_notify (G_OBJECT (model), "total-size"); + } +} + +static void +attachment_set_loading (EAttachment *attachment, + gboolean loading) +{ + GtkTreeRowReference *reference; + + reference = e_attachment_get_reference (attachment); + + attachment->priv->percent = 0; + attachment->priv->loading = loading; + + g_object_freeze_notify (G_OBJECT (attachment)); + g_object_notify (G_OBJECT (attachment), "percent"); + g_object_notify (G_OBJECT (attachment), "loading"); + g_object_thaw_notify (G_OBJECT (attachment)); + + if (gtk_tree_row_reference_valid (reference)) { + GtkTreeModel *model; + model = gtk_tree_row_reference_get_model (reference); + g_object_notify (G_OBJECT (model), "num-loading"); + } +} + +static void +attachment_set_saving (EAttachment *attachment, + gboolean saving) +{ + attachment->priv->percent = 0; + attachment->priv->saving = saving; + + g_object_freeze_notify (G_OBJECT (attachment)); + g_object_notify (G_OBJECT (attachment), "percent"); + g_object_notify (G_OBJECT (attachment), "saving"); + g_object_thaw_notify (G_OBJECT (attachment)); +} + +static void +attachment_progress_cb (goffset current_num_bytes, + goffset total_num_bytes, + EAttachment *attachment) +{ + attachment->priv->percent = + (current_num_bytes * 100) / total_num_bytes; + + g_object_notify (G_OBJECT (attachment), "percent"); +} + +static gboolean +attachment_cancelled_timeout_cb (EAttachment *attachment) +{ + attachment->priv->emblem_timeout_id = 0; + g_cancellable_reset (attachment->priv->cancellable); + + attachment_update_icon_column (attachment); + + return FALSE; +} + +static void +attachment_cancelled_cb (EAttachment *attachment) +{ + /* Reset the GCancellable after one second. This causes a + * cancel emblem to be briefly shown on the attachment icon + * as visual feedback that an operation was cancelled. */ + + if (attachment->priv->emblem_timeout_id > 0) + g_source_remove (attachment->priv->emblem_timeout_id); + + attachment->priv->emblem_timeout_id = g_timeout_add_seconds ( + 1, (GSourceFunc) attachment_cancelled_timeout_cb, attachment); + + attachment_update_icon_column (attachment); +} + +static void +attachment_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CAN_SHOW: + e_attachment_set_can_show ( + E_ATTACHMENT (object), + g_value_get_boolean (value)); + return; + + case PROP_DISPOSITION: + e_attachment_set_disposition ( + E_ATTACHMENT (object), + g_value_get_string (value)); + return; + + case PROP_ENCRYPTED: + e_attachment_set_encrypted ( + E_ATTACHMENT (object), + g_value_get_int (value)); + return; + + case PROP_FILE: + e_attachment_set_file ( + E_ATTACHMENT (object), + g_value_get_object (value)); + return; + + case PROP_SHOWN: + e_attachment_set_shown ( + E_ATTACHMENT (object), + g_value_get_boolean (value)); + return; + + case PROP_MIME_PART: + e_attachment_set_mime_part ( + E_ATTACHMENT (object), + g_value_get_boxed (value)); + return; + + case PROP_REFERENCE: + e_attachment_set_reference ( + E_ATTACHMENT (object), + g_value_get_boxed (value)); + return; + + case PROP_SIGNED: + e_attachment_set_signed ( + E_ATTACHMENT (object), + g_value_get_int (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_CAN_SHOW: + g_value_set_boolean ( + value, e_attachment_get_can_show ( + E_ATTACHMENT (object))); + return; + + case PROP_DISPOSITION: + g_value_set_string ( + value, e_attachment_get_disposition ( + E_ATTACHMENT (object))); + return; + + case PROP_ENCRYPTED: + g_value_set_int ( + value, e_attachment_get_encrypted ( + E_ATTACHMENT (object))); + return; + + case PROP_FILE: + g_value_set_object ( + value, e_attachment_get_file ( + E_ATTACHMENT (object))); + return; + + case PROP_FILE_INFO: + g_value_set_object ( + value, e_attachment_get_file_info ( + E_ATTACHMENT (object))); + return; + + case PROP_SHOWN: + g_value_set_boolean ( + value, e_attachment_get_shown ( + E_ATTACHMENT (object))); + return; + + case PROP_LOADING: + g_value_set_boolean ( + value, e_attachment_get_loading ( + E_ATTACHMENT (object))); + return; + + case PROP_MIME_PART: + g_value_set_boxed ( + value, e_attachment_get_mime_part ( + E_ATTACHMENT (object))); + return; + + case PROP_PERCENT: + g_value_set_int ( + value, e_attachment_get_percent ( + E_ATTACHMENT (object))); + return; + + case PROP_REFERENCE: + g_value_set_boxed ( + value, e_attachment_get_reference ( + E_ATTACHMENT (object))); + return; + + case PROP_SAVING: + g_value_set_boolean ( + value, e_attachment_get_saving ( + E_ATTACHMENT (object))); + return; + + case PROP_SIGNED: + g_value_set_int ( + value, e_attachment_get_signed ( + E_ATTACHMENT (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_dispose (GObject *object) +{ + EAttachmentPrivate *priv; + + priv = E_ATTACHMENT_GET_PRIVATE (object); + + if (priv->file != NULL) { + g_object_unref (priv->file); + priv->file = NULL; + } + + if (priv->file_info != NULL) { + g_object_unref (priv->file_info); + priv->file_info = NULL; + } + + if (priv->cancellable != NULL) { + g_object_unref (priv->cancellable); + priv->cancellable = NULL; + } + + if (priv->mime_part != NULL) { + camel_object_unref (priv->mime_part); + priv->mime_part = NULL; + } + + if (priv->emblem_timeout_id > 0) { + g_source_remove (priv->emblem_timeout_id); + priv->emblem_timeout_id = 0; + } + + /* This accepts NULL arguments. */ + gtk_tree_row_reference_free (priv->reference); + priv->reference = NULL; + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +attachment_finalize (GObject *object) +{ + EAttachmentPrivate *priv; + + priv = E_ATTACHMENT_GET_PRIVATE (object); + + g_free (priv->disposition); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +attachment_class_init (EAttachmentClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAttachmentPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = attachment_set_property; + object_class->get_property = attachment_get_property; + object_class->dispose = attachment_dispose; + object_class->finalize = attachment_finalize; + + g_object_class_install_property ( + object_class, + PROP_CAN_SHOW, + g_param_spec_boolean ( + "can-show", + "Can Show", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_DISPOSITION, + g_param_spec_string ( + "disposition", + "Disposition", + NULL, + "attachment", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + /* FIXME Define a GEnumClass for this. */ + g_object_class_install_property ( + object_class, + PROP_ENCRYPTED, + g_param_spec_int ( + "encrypted", + "Encrypted", + NULL, + CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE, + CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG, + CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_FILE, + g_param_spec_object ( + "file", + "File", + NULL, + G_TYPE_FILE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_FILE_INFO, + g_param_spec_object ( + "file-info", + "File Info", + NULL, + G_TYPE_FILE_INFO, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_LOADING, + g_param_spec_boolean ( + "loading", + "Loading", + NULL, + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_MIME_PART, + g_param_spec_boxed ( + "mime-part", + "MIME Part", + NULL, + E_TYPE_CAMEL_OBJECT, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_PERCENT, + g_param_spec_int ( + "percent", + "Percent", + NULL, + 0, + 100, + 0, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_REFERENCE, + g_param_spec_boxed ( + "reference", + "Reference", + NULL, + GTK_TYPE_TREE_ROW_REFERENCE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SAVING, + g_param_spec_boolean ( + "saving", + "Saving", + NULL, + FALSE, + G_PARAM_READABLE)); + + g_object_class_install_property ( + object_class, + PROP_SHOWN, + g_param_spec_boolean ( + "shown", + "Shown", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + /* FIXME Define a GEnumClass for this. */ + g_object_class_install_property ( + object_class, + PROP_SIGNED, + g_param_spec_int ( + "signed", + "Signed", + NULL, + CAMEL_CIPHER_VALIDITY_SIGN_NONE, + CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY, + CAMEL_CIPHER_VALIDITY_SIGN_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +attachment_init (EAttachment *attachment) +{ + attachment->priv = E_ATTACHMENT_GET_PRIVATE (attachment); + attachment->priv->cancellable = g_cancellable_new (); + attachment->priv->encrypted = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE; + attachment->priv->signed_ = CAMEL_CIPHER_VALIDITY_SIGN_NONE; + + g_signal_connect ( + attachment, "notify::encrypted", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect ( + attachment, "notify::file-info", + G_CALLBACK (attachment_update_file_info_columns), NULL); + + g_signal_connect ( + attachment, "notify::file-info", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect ( + attachment, "notify::loading", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect ( + attachment, "notify::loading", + G_CALLBACK (attachment_update_progress_columns), NULL); + + g_signal_connect ( + attachment, "notify::percent", + G_CALLBACK (attachment_update_progress_columns), NULL); + + g_signal_connect ( + attachment, "notify::reference", + G_CALLBACK (attachment_update_file_info_columns), NULL); + + g_signal_connect ( + attachment, "notify::reference", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect ( + attachment, "notify::reference", + G_CALLBACK (attachment_update_progress_columns), NULL); + + g_signal_connect ( + attachment, "notify::saving", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect ( + attachment, "notify::saving", + G_CALLBACK (attachment_update_progress_columns), NULL); + + g_signal_connect ( + attachment, "notify::signed", + G_CALLBACK (attachment_update_icon_column), NULL); + + g_signal_connect_swapped ( + attachment->priv->cancellable, "cancelled", + G_CALLBACK (attachment_cancelled_cb), attachment); +} + +GType +e_attachment_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAttachmentClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) attachment_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAttachment), + 0, /* n_preallocs */ + (GInstanceInitFunc) attachment_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EAttachment", &type_info, 0); + } + + return type; +} + +EAttachment * +e_attachment_new (void) +{ + return g_object_new (E_TYPE_ATTACHMENT, NULL); +} + +EAttachment * +e_attachment_new_for_path (const gchar *path) +{ + EAttachment *attachment; + GFile *file; + + g_return_val_if_fail (path != NULL, NULL); + + file = g_file_new_for_path (path); + attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL); + g_object_unref (file); + + return attachment; +} + +EAttachment * +e_attachment_new_for_uri (const gchar *uri) +{ + EAttachment *attachment; + GFile *file; + + g_return_val_if_fail (uri != NULL, NULL); + + file = g_file_new_for_uri (uri); + attachment = g_object_new (E_TYPE_ATTACHMENT, "file", file, NULL); + g_object_unref (file); + + return attachment; +} + +EAttachment * +e_attachment_new_for_message (CamelMimeMessage *message) +{ + CamelDataWrapper *wrapper; + CamelMimePart *mime_part; + EAttachment *attachment; + GString *description; + const gchar *subject; + + g_return_val_if_fail (CAMEL_IS_MIME_MESSAGE (message), NULL); + + mime_part = camel_mime_part_new (); + camel_mime_part_set_disposition (mime_part, "inline"); + subject = camel_mime_message_get_subject (message); + + description = g_string_new (_("Attached message")); + if (subject != NULL) + g_string_append_printf (description, " - %s", subject); + camel_mime_part_set_description (mime_part, description->str); + g_string_free (description, TRUE); + + wrapper = CAMEL_DATA_WRAPPER (message); + camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper); + camel_mime_part_set_content_type (mime_part, "message/rfc822"); + + attachment = e_attachment_new (); + e_attachment_set_mime_part (attachment, mime_part); + camel_object_unref (mime_part); + + return attachment; +} + +void +e_attachment_add_to_multipart (EAttachment *attachment, + CamelMultipart *multipart, + const gchar *default_charset) +{ + CamelContentType *content_type; + CamelDataWrapper *wrapper; + CamelMimePart *mime_part; + + /* XXX EMsgComposer might be a better place for this function. */ + + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (CAMEL_IS_MULTIPART (multipart)); + + /* Still loading? Too bad. */ + mime_part = e_attachment_get_mime_part (attachment); + if (mime_part == NULL) + return; + + content_type = camel_mime_part_get_content_type (mime_part); + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + + if (CAMEL_IS_MULTIPART (wrapper)) + goto exit; + + /* For text content, determine the best encoding and character set. */ + if (camel_content_type_is (content_type, "text", "*")) { + CamelTransferEncoding encoding; + CamelStreamFilter *filtered_stream; + CamelMimeFilterBestenc *filter; + CamelStream *stream; + const gchar *charset; + + charset = camel_content_type_param (content_type, "charset"); + + /* Determine the best encoding by writing the MIME + * part to a NULL stream with a "bestenc" filter. */ + stream = camel_stream_null_new (); + filtered_stream = camel_stream_filter_new_with_stream (stream); + filter = camel_mime_filter_bestenc_new ( + CAMEL_BESTENC_GET_ENCODING); + camel_stream_filter_add ( + filtered_stream, CAMEL_MIME_FILTER (filter)); + camel_data_wrapper_decode_to_stream ( + wrapper, CAMEL_STREAM (filtered_stream)); + camel_object_unref (filtered_stream); + camel_object_unref (stream); + + /* Retrieve the best encoding from the filter. */ + encoding = camel_mime_filter_bestenc_get_best_encoding ( + filter, CAMEL_BESTENC_8BIT); + camel_mime_part_set_encoding (mime_part, encoding); + camel_object_unref (filter); + + if (encoding == CAMEL_TRANSFER_ENCODING_7BIT) { + /* The text fits within us-ascii, so this is safe. + * FIXME Check that this isn't iso-2022-jp? */ + default_charset = "us-ascii"; + + } else if (charset == NULL && default_charset == NULL) { + default_charset = attachment_get_default_charset (); + /* FIXME Check that this fits within the + * default_charset and if not, find one + * that does and/or allow the user to + * specify. */ + } + + if (charset == NULL) { + gchar *type; + + camel_content_type_set_param ( + content_type, "charset", default_charset); + type = camel_content_type_format (content_type); + camel_mime_part_set_content_type (mime_part, type); + g_free (type); + } + + /* Otherwise, unless it's a message/rfc822, Base64 encode it. */ + } else if (!CAMEL_IS_MIME_MESSAGE (wrapper)) + camel_mime_part_set_encoding ( + mime_part, CAMEL_TRANSFER_ENCODING_BASE64); + +exit: + camel_multipart_add_part (multipart, mime_part); +} + +void +e_attachment_cancel (EAttachment *attachment) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + g_cancellable_cancel (attachment->priv->cancellable); +} + +gboolean +e_attachment_get_can_show (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->can_show; +} + +void +e_attachment_set_can_show (EAttachment *attachment, + gboolean can_show) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->can_show = can_show; + + g_object_notify (G_OBJECT (attachment), "can-show"); +} + +const gchar * +e_attachment_get_disposition (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + return attachment->priv->disposition; +} + +void +e_attachment_set_disposition (EAttachment *attachment, + const gchar *disposition) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + g_free (attachment->priv->disposition); + attachment->priv->disposition = g_strdup (disposition); + + g_object_notify (G_OBJECT (attachment), "disposition"); +} + +GFile * +e_attachment_get_file (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + return attachment->priv->file; +} + +void +e_attachment_set_file (EAttachment *attachment, + GFile *file) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + if (file != NULL) { + g_return_if_fail (G_IS_FILE (file)); + g_object_ref (file); + } + + if (attachment->priv->file != NULL) + g_object_unref (attachment->priv->file); + + attachment->priv->file = file; + + g_object_notify (G_OBJECT (attachment), "file"); +} + +GFileInfo * +e_attachment_get_file_info (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + return attachment->priv->file_info; +} + +gboolean +e_attachment_get_loading (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->loading; +} + +CamelMimePart * +e_attachment_get_mime_part (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + return attachment->priv->mime_part; +} + +void +e_attachment_set_mime_part (EAttachment *attachment, + CamelMimePart *mime_part) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + if (mime_part != NULL) { + g_return_if_fail (CAMEL_IS_MIME_PART (mime_part)); + camel_object_ref (mime_part); + } + + if (attachment->priv->mime_part != NULL) + camel_object_unref (attachment->priv->mime_part); + + attachment->priv->mime_part = mime_part; + + g_object_notify (G_OBJECT (attachment), "mime-part"); +} + +gint +e_attachment_get_percent (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), 0); + + return attachment->priv->percent; +} + +GtkTreeRowReference * +e_attachment_get_reference (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + return attachment->priv->reference; +} + +void +e_attachment_set_reference (EAttachment *attachment, + GtkTreeRowReference *reference) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + if (reference != NULL) + reference = gtk_tree_row_reference_copy (reference); + + gtk_tree_row_reference_free (attachment->priv->reference); + attachment->priv->reference = reference; + + g_object_notify (G_OBJECT (attachment), "reference"); +} + +gboolean +e_attachment_get_saving (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->saving; +} + +gboolean +e_attachment_get_shown (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->shown; +} + +void +e_attachment_set_shown (EAttachment *attachment, + gboolean shown) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->shown = shown; + + g_object_notify (G_OBJECT (attachment), "shown"); +} + +camel_cipher_validity_encrypt_t +e_attachment_get_encrypted (EAttachment *attachment) +{ + g_return_val_if_fail ( + E_IS_ATTACHMENT (attachment), + CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE); + + return attachment->priv->encrypted; +} + +void +e_attachment_set_encrypted (EAttachment *attachment, + camel_cipher_validity_encrypt_t encrypted) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->encrypted = encrypted; + + g_object_notify (G_OBJECT (attachment), "encrypted"); +} + +camel_cipher_validity_sign_t +e_attachment_get_signed (EAttachment *attachment) +{ + g_return_val_if_fail ( + E_IS_ATTACHMENT (attachment), + CAMEL_CIPHER_VALIDITY_SIGN_NONE); + + return attachment->priv->signed_; +} + +void +e_attachment_set_signed (EAttachment *attachment, + camel_cipher_validity_sign_t signed_) +{ + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + attachment->priv->signed_ = signed_; + + g_object_notify (G_OBJECT (attachment), "signed"); +} + +const gchar * +e_attachment_get_description (EAttachment *attachment) +{ + GFileInfo *file_info; + const gchar *attribute; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; + file_info = e_attachment_get_file_info (attachment); + + if (file_info == NULL) + return NULL; + + return g_file_info_get_attribute_string (file_info, attribute); +} + +const gchar * +e_attachment_get_thumbnail_path (EAttachment *attachment) +{ + GFileInfo *file_info; + const gchar *attribute; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + attribute = G_FILE_ATTRIBUTE_THUMBNAIL_PATH; + file_info = e_attachment_get_file_info (attachment); + + if (file_info == NULL) + return NULL; + + return g_file_info_get_attribute_byte_string (file_info, attribute); +} + +gboolean +e_attachment_is_rfc822 (EAttachment *attachment) +{ + GFileInfo *file_info; + const gchar *content_type; + gchar *mime_type; + gboolean is_rfc822; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + file_info = e_attachment_get_file_info (attachment); + if (file_info == NULL) + return FALSE; + + content_type = g_file_info_get_content_type (file_info); + if (content_type == NULL) + return FALSE; + + mime_type = g_content_type_get_mime_type (content_type); + is_rfc822 = (g_ascii_strcasecmp (mime_type, "message/rfc822") == 0); + g_free (mime_type); + + return is_rfc822; +} + +GList * +e_attachment_list_apps (EAttachment *attachment) +{ + GList *app_info_list; + GFileInfo *file_info; + const gchar *content_type; + const gchar *display_name; + gchar *allocated; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + file_info = e_attachment_get_file_info (attachment); + if (file_info == NULL) + return NULL; + + content_type = g_file_info_get_content_type (file_info); + display_name = g_file_info_get_display_name (file_info); + g_return_val_if_fail (content_type != NULL, NULL); + + app_info_list = g_app_info_get_all_for_type (content_type); + + if (app_info_list != NULL || display_name == NULL) + goto exit; + + if (!g_content_type_is_unknown (content_type)) + goto exit; + + allocated = g_content_type_guess (display_name, NULL, 0, NULL); + app_info_list = g_app_info_get_all_for_type (allocated); + g_free (allocated); + +exit: + return app_info_list; +} + +/************************* e_attachment_load_async() *************************/ + +typedef struct _LoadContext LoadContext; + +struct _LoadContext { + EAttachment *attachment; + GSimpleAsyncResult *simple; + + GInputStream *input_stream; + GOutputStream *output_stream; + GFileInfo *file_info; + goffset total_num_bytes; + gssize bytes_read; + gchar buffer[4096]; +}; + +/* Forward Declaration */ +static void +attachment_load_stream_read_cb (GInputStream *input_stream, + GAsyncResult *result, + LoadContext *load_context); + +static LoadContext * +attachment_load_context_new (EAttachment *attachment, + GAsyncReadyCallback callback, + gpointer user_data) +{ + LoadContext *load_context; + GSimpleAsyncResult *simple; + + simple = g_simple_async_result_new ( + G_OBJECT (attachment), callback, + user_data, e_attachment_load_async); + + load_context = g_slice_new0 (LoadContext); + load_context->attachment = g_object_ref (attachment); + load_context->simple = simple; + + attachment_set_loading (load_context->attachment, TRUE); + + return load_context; +} + +static void +attachment_load_context_free (LoadContext *load_context) +{ + /* Do not free the GSimpleAsyncResult. */ + g_object_unref (load_context->attachment); + + if (load_context->input_stream != NULL) + g_object_unref (load_context->input_stream); + + if (load_context->output_stream != NULL) + g_object_unref (load_context->output_stream); + + if (load_context->file_info != NULL) + g_object_unref (load_context->file_info); + + g_slice_free (LoadContext, load_context); +} + +static gboolean +attachment_load_check_for_error (LoadContext *load_context, + GError *error) +{ + GSimpleAsyncResult *simple; + + if (error == NULL) + return FALSE; + + /* Steal the result. */ + simple = load_context->simple; + load_context->simple = NULL; + + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_error_free (error); + + attachment_load_context_free (load_context); + + return TRUE; +} + +static void +attachment_load_finish (LoadContext *load_context) +{ + GFileInfo *file_info; + EAttachment *attachment; + GMemoryOutputStream *output_stream; + GSimpleAsyncResult *simple; + CamelDataWrapper *wrapper; + CamelMimePart *mime_part; + CamelStream *stream; + const gchar *attribute; + const gchar *content_type; + const gchar *display_name; + const gchar *description; + const gchar *disposition; + gchar *mime_type; + gpointer data; + gsize size; + + /* Steal the result. */ + simple = load_context->simple; + load_context->simple = NULL; + + file_info = load_context->file_info; + attachment = load_context->attachment; + output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream); + + if (e_attachment_is_rfc822 (attachment)) + wrapper = (CamelDataWrapper *) camel_mime_message_new (); + else + wrapper = camel_data_wrapper_new (); + + content_type = g_file_info_get_content_type (file_info); + mime_type = g_content_type_get_mime_type (content_type); + + data = g_memory_output_stream_get_data (output_stream); + size = g_memory_output_stream_get_data_size (output_stream); + + stream = camel_stream_mem_new_with_buffer (data, size); + camel_data_wrapper_construct_from_stream (wrapper, stream); + camel_data_wrapper_set_mime_type (wrapper, mime_type); + camel_stream_close (stream); + camel_object_unref (stream); + + mime_part = camel_mime_part_new (); + camel_medium_set_content_object (CAMEL_MEDIUM (mime_part), wrapper); + + camel_object_unref (wrapper); + g_free (mime_type); + + display_name = g_file_info_get_display_name (file_info); + if (display_name != NULL) + camel_mime_part_set_filename (mime_part, display_name); + + attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; + description = g_file_info_get_attribute_string (file_info, attribute); + if (description != NULL) + camel_mime_part_set_description (mime_part, description); + + disposition = e_attachment_get_disposition (attachment); + if (disposition != NULL) + camel_mime_part_set_disposition (mime_part, disposition); + + g_simple_async_result_set_op_res_gpointer ( + simple, mime_part, (GDestroyNotify) camel_object_unref); + + g_simple_async_result_complete (simple); + + attachment_load_context_free (load_context); +} + +static void +attachment_load_write_cb (GOutputStream *output_stream, + GAsyncResult *result, + LoadContext *load_context) +{ + EAttachment *attachment; + GCancellable *cancellable; + GInputStream *input_stream; + gssize bytes_written; + GError *error = NULL; + + bytes_written = g_output_stream_write_finish ( + output_stream, result, &error); + + if (attachment_load_check_for_error (load_context, error)) + return; + + attachment = load_context->attachment; + cancellable = attachment->priv->cancellable; + input_stream = load_context->input_stream; + + attachment_progress_cb ( + g_seekable_tell (G_SEEKABLE (output_stream)), + load_context->total_num_bytes, attachment); + + if (bytes_written < load_context->bytes_read) { + g_memmove ( + load_context->buffer, + load_context->buffer + bytes_written, + load_context->bytes_read - bytes_written); + load_context->bytes_read -= bytes_written; + + g_output_stream_write_async ( + output_stream, + load_context->buffer, + load_context->bytes_read, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_load_write_cb, + load_context); + } else + g_input_stream_read_async ( + input_stream, + load_context->buffer, + sizeof (load_context->buffer), + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_load_stream_read_cb, + load_context); +} + +static void +attachment_load_stream_read_cb (GInputStream *input_stream, + GAsyncResult *result, + LoadContext *load_context) +{ + EAttachment *attachment; + GCancellable *cancellable; + GOutputStream *output_stream; + gssize bytes_read; + GError *error = NULL; + + bytes_read = g_input_stream_read_finish ( + input_stream, result, &error); + + if (attachment_load_check_for_error (load_context, error)) + return; + + if (bytes_read == 0) { + attachment_load_finish (load_context); + return; + } + + attachment = load_context->attachment; + cancellable = attachment->priv->cancellable; + output_stream = load_context->output_stream; + load_context->bytes_read = bytes_read; + + g_output_stream_write_async ( + output_stream, + load_context->buffer, + load_context->bytes_read, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_load_write_cb, + load_context); +} + +static void +attachment_load_file_read_cb (GFile *file, + GAsyncResult *result, + LoadContext *load_context) +{ + EAttachment *attachment; + GCancellable *cancellable; + GFileInputStream *input_stream; + GOutputStream *output_stream; + GError *error = NULL; + + /* Input stream might be NULL, so don't use cast macro. */ + input_stream = g_file_read_finish (file, result, &error); + load_context->input_stream = (GInputStream *) input_stream; + + if (attachment_load_check_for_error (load_context, error)) + return; + + /* Load the contents into a GMemoryOutputStream. */ + output_stream = g_memory_output_stream_new ( + NULL, 0, g_realloc, g_free); + + attachment = load_context->attachment; + cancellable = attachment->priv->cancellable; + load_context->output_stream = output_stream; + + g_input_stream_read_async ( + load_context->input_stream, + load_context->buffer, + sizeof (load_context->buffer), + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_load_stream_read_cb, + load_context); +} + +static void +attachment_load_query_info_cb (GFile *file, + GAsyncResult *result, + LoadContext *load_context) +{ + EAttachment *attachment; + GCancellable *cancellable; + GFileInfo *file_info; + GError *error = NULL; + + attachment = load_context->attachment; + cancellable = attachment->priv->cancellable; + + file_info = g_file_query_info_finish (file, result, &error); + attachment_set_file_info (attachment, file_info); + load_context->file_info = file_info; + + if (attachment_load_check_for_error (load_context, error)) + return; + + load_context->total_num_bytes = g_file_info_get_size (file_info); + + g_file_read_async ( + file, G_PRIORITY_DEFAULT, + cancellable, (GAsyncReadyCallback) + attachment_load_file_read_cb, load_context); +} + +static void +attachment_load_from_mime_part (LoadContext *load_context) +{ + GFileInfo *file_info; + EAttachment *attachment; + GSimpleAsyncResult *simple; + CamelContentType *content_type; + CamelMimePart *mime_part; + const gchar *attribute; + const gchar *string; + gchar *allocated; + goffset size; + + attachment = load_context->attachment; + mime_part = e_attachment_get_mime_part (attachment); + + file_info = g_file_info_new (); + load_context->file_info = file_info; + + content_type = camel_mime_part_get_content_type (mime_part); + allocated = camel_content_type_simple (content_type); + if (allocated != NULL) { + GIcon *icon; + gchar *cp; + + /* GIO expects lowercase MIME types. */ + for (cp = allocated; *cp != '\0'; cp++) + *cp = g_ascii_tolower (*cp); + + /* Swap the MIME type for a content type. */ + cp = g_content_type_from_mime_type (allocated); + g_free (allocated); + allocated = cp; + + /* Use the MIME part's filename if we have to. */ + if (g_content_type_is_unknown (allocated)) { + string = camel_mime_part_get_filename (mime_part); + if (string != NULL) { + g_free (allocated); + allocated = g_content_type_guess ( + string, NULL, 0, NULL); + } + } + + g_file_info_set_content_type (file_info, allocated); + + icon = g_content_type_get_icon (allocated); + if (icon != NULL) { + g_file_info_set_icon (file_info, icon); + g_object_unref (icon); + } + } + g_free (allocated); + + string = camel_mime_part_get_filename (mime_part); + if (string == NULL) + /* Translators: Default attachment filename. */ + string = _("attachment.dat"); + g_file_info_set_display_name (file_info, string); + + attribute = G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION; + string = camel_mime_part_get_description (mime_part); + if (string != NULL) + g_file_info_set_attribute_string ( + file_info, attribute, string); + + size = (goffset) camel_mime_part_get_content_size (mime_part); + g_file_info_set_size (file_info, size); + + string = camel_mime_part_get_disposition (mime_part); + e_attachment_set_disposition (attachment, string); + + attachment_set_file_info (attachment, file_info); + + /* Steal the result. */ + simple = load_context->simple; + load_context->simple = NULL; + + camel_object_ref (mime_part); + g_simple_async_result_set_op_res_gpointer ( + simple, mime_part, + (GDestroyNotify) camel_object_unref); + g_simple_async_result_complete_in_idle (simple); + + attachment_load_context_free (load_context); +} + +void +e_attachment_load_async (EAttachment *attachment, + GAsyncReadyCallback callback, + gpointer user_data) +{ + LoadContext *load_context; + GCancellable *cancellable; + CamelMimePart *mime_part; + GFile *file; + + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (callback != NULL); + + if (e_attachment_get_loading (attachment)) { + g_simple_async_report_error_in_idle ( + G_OBJECT (attachment), callback, user_data, + G_IO_ERROR, G_IO_ERROR_BUSY, + _("A load operation is already in progress")); + return; + } + + if (e_attachment_get_saving (attachment)) { + g_simple_async_report_error_in_idle ( + G_OBJECT (attachment), callback, user_data, + G_IO_ERROR, G_IO_ERROR_BUSY, + _("A save operation is already in progress")); + return; + } + + file = e_attachment_get_file (attachment); + mime_part = e_attachment_get_mime_part (attachment); + g_return_if_fail (file != NULL || mime_part != NULL); + + load_context = attachment_load_context_new ( + attachment, callback, user_data); + + cancellable = attachment->priv->cancellable; + g_cancellable_reset (cancellable); + + if (file != NULL) + g_file_query_info_async ( + file, ATTACHMENT_QUERY, + G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT, + cancellable, (GAsyncReadyCallback) + attachment_load_query_info_cb, load_context); + + else if (mime_part != NULL) + attachment_load_from_mime_part (load_context); -static GObjectClass *parent_class = NULL; +} -static void -changed (EAttachment *attachment) +gboolean +e_attachment_load_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error) { - g_signal_emit (attachment, signals[CHANGED], 0); -} + GSimpleAsyncResult *simple; + CamelMimePart *mime_part; + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); -/* GtkObject methods. */ + simple = G_SIMPLE_ASYNC_RESULT (result); + mime_part = g_simple_async_result_get_op_res_gpointer (simple); + if (mime_part != NULL) + e_attachment_set_mime_part (attachment, mime_part); + g_simple_async_result_propagate_error (simple, error); + g_object_unref (simple); -static void -finalise (GObject *object) + attachment_set_loading (attachment, FALSE); + + return (mime_part != NULL); +} + +void +e_attachment_load_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent) { - EAttachment *attachment = (EAttachment *) object; GtkWidget *dialog; + GFileInfo *file_info; + GtkTreeRowReference *reference; + const gchar *display_name; + const gchar *primary_text; + GError *error = NULL; - if (attachment->editor_gui != NULL) { - dialog = glade_xml_get_widget (attachment->editor_gui, "dialog"); - g_signal_emit_by_name (dialog, "response", GTK_RESPONSE_CLOSE); - } + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (G_IS_ASYNC_RESULT (result)); + g_return_if_fail (GTK_IS_WINDOW (parent)); - if (attachment->is_available_local) { - camel_object_unref (attachment->body); - if (attachment->pixbuf_cache != NULL) - g_object_unref (attachment->pixbuf_cache); - } else { - if (attachment->cancellable) { - /* the operation is still running, so cancel it */ - g_cancellable_cancel (attachment->cancellable); - attachment->cancellable = NULL; - } - g_free (attachment->description); + if (e_attachment_load_finish (attachment, result, &error)) + return; + + /* XXX Calling EAttachmentStore functions from here violates + * the abstraction, but for now it's not hurting anything. */ + reference = e_attachment_get_reference (attachment); + if (gtk_tree_row_reference_valid (reference)) { + GtkTreeModel *model; + + model = gtk_tree_row_reference_get_model (reference); + + e_attachment_store_remove_attachment ( + E_ATTACHMENT_STORE (model), attachment); } - g_free (attachment->file_name); - g_free (attachment->store_uri); + /* Ignore cancellations. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - G_OBJECT_CLASS (parent_class)->finalize (object); -} + file_info = e_attachment_get_file_info (attachment); + if (file_info != NULL) + display_name = g_file_info_get_display_name (file_info); + else + display_name = NULL; -/* Signals. */ + if (display_name != NULL) + primary_text = g_strdup_printf ( + _("Could not load '%s'"), display_name); + else + primary_text = g_strdup_printf ( + _("Could not load the attachment")); -static void -real_changed (EAttachment *attachment) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); -} + dialog = gtk_message_dialog_new_with_markup ( + parent, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "%s", primary_text); -static void -real_update_attachment (EAttachment *attachment, char *msg) -{ - g_return_if_fail (E_IS_ATTACHMENT (attachment)); + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + + gtk_dialog_run (GTK_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + g_error_free (error); } +/************************* e_attachment_open_async() *************************/ -static void -class_init (EAttachmentClass *klass) -{ - GObjectClass *object_class; +typedef struct _OpenContext OpenContext; - object_class = (GObjectClass*) klass; - parent_class = g_type_class_ref (G_TYPE_OBJECT); - - object_class->finalize = finalise; - klass->changed = real_changed; - klass->update = real_update_attachment; - - signals[CHANGED] = g_signal_new ("changed", - E_TYPE_ATTACHMENT, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EAttachmentClass, changed), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[UPDATE] = g_signal_new ("update", - E_TYPE_ATTACHMENT, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EAttachmentClass, update), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - -} - -static void -init (EAttachment *attachment) -{ - attachment->editor_gui = NULL; - attachment->body = NULL; - attachment->size = 0; - attachment->pixbuf_cache = NULL; - attachment->index = -1; - attachment->file_name = NULL; - attachment->percentage = -1; - attachment->description = NULL; - attachment->disposition = FALSE; - attachment->sign = CAMEL_CIPHER_VALIDITY_SIGN_NONE; - attachment->encrypt = CAMEL_CIPHER_VALIDITY_ENCRYPT_NONE; - attachment->store_uri = NULL; - attachment->cancellable = NULL; -} +struct _OpenContext { + EAttachment *attachment; + GSimpleAsyncResult *simple; -GType -e_attachment_get_type (void) + GAppInfo *app_info; +}; + +static OpenContext * +attachment_open_context_new (EAttachment *attachment, + GAsyncReadyCallback callback, + gpointer user_data) { - static GType type = 0; + OpenContext *open_context; + GSimpleAsyncResult *simple; - if (type == 0) { - static const GTypeInfo info = { - sizeof (EAttachmentClass), - NULL, - NULL, - (GClassInitFunc) class_init, - NULL, - NULL, - sizeof (EAttachment), - 0, - (GInstanceInitFunc) init, - }; + simple = g_simple_async_result_new ( + G_OBJECT (attachment), callback, + user_data, e_attachment_open_async); - type = g_type_register_static (G_TYPE_OBJECT, "EAttachment", &info, 0); - } + open_context = g_slice_new0 (OpenContext); + open_context->attachment = g_object_ref (attachment); + open_context->simple = simple; - return type; + return open_context; } -/** - * file_ext_is: - * @param file_name: path for file - * @param ext: desired extension, with a dot - * @return if file_name has extension ext or not - **/ +static void +attachment_open_context_free (OpenContext *open_context) +{ + /* Do not free the GSimpleAsyncResult. */ + g_object_unref (open_context->attachment); + + if (open_context->app_info != NULL) + g_object_unref (open_context->app_info); + + g_slice_free (OpenContext, open_context); +} static gboolean -file_ext_is (const char *file_name, const char *ext) +attachment_open_check_for_error (OpenContext *open_context, + GError *error) { - int i, dot = -1; + GSimpleAsyncResult *simple; - if (!file_name || !ext) + if (error == NULL) return FALSE; - for (i = 0; file_name[i]; i++) { - if (file_name [i] == '.') - dot = i; - } + /* Steal the result. */ + simple = open_context->simple; + open_context->simple = NULL; - if (dot > 0) { - return 0 == g_ascii_strcasecmp (file_name + dot, ext); - } + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_error_free (error); - return FALSE; + attachment_open_context_free (open_context); + + return TRUE; } -static char * -attachment_guess_mime_type (const char *file_name) +static void +attachment_open_file (GFile *file, + OpenContext *open_context) { - char *type; - gchar *content = NULL; + GdkAppLaunchContext *context; + GSimpleAsyncResult *simple; + GList *file_list; + gboolean success; + GError *error = NULL; - type = e_util_guess_mime_type (file_name, TRUE); + /* Steal the result. */ + simple = open_context->simple; + open_context->simple = NULL; - if (type && strcmp (type, "text/directory") == 0 && - file_ext_is (file_name, ".vcf") && - g_file_get_contents (file_name, &content, NULL, NULL) && - content) { - EVCard *vc = e_vcard_new_from_string (content); + /* Find a default app based on content type. */ + if (open_context->app_info == NULL) { + EAttachment *attachment; + GFileInfo *file_info; + const gchar *content_type; - if (vc) { - g_free (type); - g_object_unref (G_OBJECT (vc)); + attachment = open_context->attachment; + file_info = e_attachment_get_file_info (attachment); + if (file_info == NULL) + goto exit; - type = g_strdup ("text/x-vcard"); - } + content_type = g_file_info_get_content_type (file_info); + if (content_type == NULL) + goto exit; + open_context->app_info = g_app_info_get_default_for_type ( + content_type, FALSE); } - g_free (content); + if (open_context->app_info == NULL) + goto exit; - if (type) { - /* Check if returned mime_type is valid */ - CamelContentType *ctype = camel_content_type_decode (type); + context = gdk_app_launch_context_new (); + file_list = g_list_prepend (NULL, file); - if (!ctype) { - g_free (type); - type = NULL; - } else - camel_content_type_unref (ctype); + success = g_app_info_launch ( + open_context->app_info, file_list, + G_APP_LAUNCH_CONTEXT (context), &error); + + g_simple_async_result_set_op_res_gboolean (simple, success); + + g_list_free (file_list); + g_object_unref (context); + +exit: + if (error != NULL) { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); } - return type; + g_simple_async_result_complete (simple); + attachment_open_context_free (open_context); } - -/** - * e_attachment_new: - * @file_name: filename to attach - * @disposition: Content-Disposition of the attachment - * @ex: exception - * - * Return value: the new attachment, or %NULL on error - **/ -EAttachment * -e_attachment_new (const char *file_name, const char *disposition, CamelException *ex) +static void +attachment_open_save_finished_cb (EAttachment *attachment, + GAsyncResult *result, + OpenContext *open_context) { - EAttachment *new; - CamelMimePart *part; - CamelDataWrapper *wrapper; - CamelStream *stream; - struct stat statbuf; - char *mime_type; - char *filename; - CamelURL *url; + GFile *file; + GError *error = NULL; - g_return_val_if_fail (file_name != NULL, NULL); + file = e_attachment_save_finish (attachment, result, &error); - if (g_stat (file_name, &statbuf) < 0) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot attach file %s: %s"), - file_name, g_strerror (errno)); - return NULL; - } + if (attachment_open_check_for_error (open_context, error)) + 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 NULL; - } + attachment_open_file (file, open_context); + g_object_unref (file); +} - if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot attach file %s: %s"), - file_name, g_strerror (errno)); - return NULL; - } +static void +attachment_open_save_temporary (OpenContext *open_context) +{ + GFile *file; + gchar *template; + gchar *path; + GError *error = NULL; - if ((mime_type = attachment_guess_mime_type (file_name))) { - if (!g_ascii_strcasecmp (mime_type, "message/rfc822")) { - wrapper = (CamelDataWrapper *) camel_mime_message_new (); - } else { - wrapper = camel_data_wrapper_new (); - } + errno = 0; - 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"); - } + /* XXX This could trigger a blocking temp directory cleanup. */ + template = g_strdup_printf (PACKAGE "-%s-XXXXXX", g_get_user_name ()); + path = e_mktemp (template); + g_free (template); - camel_object_unref (stream); + /* XXX Let's hope errno got set properly. */ + if (path == NULL) + g_set_error ( + &error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s", g_strerror (errno)); - part = camel_mime_part_new (); - camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); - camel_object_unref (wrapper); + /* We already know if there's an error, but this does the cleanup. */ + if (attachment_open_check_for_error (open_context, error)) + return; - camel_mime_part_set_disposition (part, disposition); - filename = g_path_get_basename (file_name); - camel_mime_part_set_filename (part, filename); - -#if 0 - /* Note: Outlook 2002 is broken with respect to Content-Ids on - non-multipart/related parts, so as an interoperability - workaround, don't set a Content-Id on these parts. Fixes - bug #10032 */ - /* set the Content-Id */ - content_id = camel_header_msgid_generate (); - camel_mime_part_set_content_id (part, content_id); - g_free (content_id); -#endif + file = g_file_new_for_path (path); - new = g_object_new (E_TYPE_ATTACHMENT, NULL); - new->editor_gui = NULL; - new->body = part; - new->size = statbuf.st_size; - new->guessed_type = TRUE; - new->cancellable = NULL; - new->is_available_local = TRUE; - new->file_name = filename; + g_free (path); - url = camel_url_new ("file://", NULL); - camel_url_set_path (url, file_name); - new->store_uri = camel_url_to_string (url, 0); - camel_url_free (url); + e_attachment_save_async ( + open_context->attachment, file, (GAsyncReadyCallback) + attachment_open_save_finished_cb, open_context); - return new; + g_object_unref (file); } +void +e_attachment_open_async (EAttachment *attachment, + GAppInfo *app_info, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OpenContext *open_context; + CamelMimePart *mime_part; + GFile *file; -typedef struct { - EAttachment *attachment; - char *file_name; - char *uri; - GtkWindow *parent; /* for error dialog */ - - guint64 file_size; /* zero indicates unknown size */ - GInputStream *istream; /* read from here ... */ - GOutputStream *ostream; /* ...and write into this. */ - gboolean was_error; - GCancellable *cancellable; + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (callback != NULL); - void *buffer; /* read into this, not more than buffer_size bytes */ - gsize buffer_size; -} DownloadInfo; + file = e_attachment_get_file (attachment); + mime_part = e_attachment_get_mime_part (attachment); + g_return_if_fail (file != NULL || mime_part != NULL); -static void -download_info_free (DownloadInfo *download_info) -{ - /* if there was an error, then free attachment too */ - if (download_info->was_error) - g_object_unref (download_info->attachment); + open_context = attachment_open_context_new ( + attachment, callback, user_data); + + if (G_IS_APP_INFO (app_info)) + open_context->app_info = g_object_ref (app_info); + + /* If the attachment already references a GFile, we can launch + * the application directly. Otherwise we have to save the MIME + * part to a temporary file and launch the application from that. */ + if (file != NULL) { + attachment_open_file (file, open_context); + + } else if (mime_part != NULL) + attachment_open_save_temporary (open_context); +} - if (download_info->ostream) - g_object_unref (download_info->ostream); +gboolean +e_attachment_open_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + gboolean success; - if (download_info->istream) - g_object_unref (download_info->istream); + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - if (download_info->cancellable) - g_object_unref (download_info->cancellable); + simple = G_SIMPLE_ASYNC_RESULT (result); + success = g_simple_async_result_get_op_res_gboolean (simple); + g_simple_async_result_propagate_error (simple, error); + g_object_unref (simple); - g_free (download_info->file_name); - g_free (download_info->uri); - g_free (download_info->buffer); - g_free (download_info); + return success; } -static void -data_ready_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +void +e_attachment_open_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent) { - DownloadInfo *download_info = (DownloadInfo *)user_data; + GtkWidget *dialog; + GFileInfo *file_info; + const gchar *display_name; + const gchar *primary_text; GError *error = NULL; - gssize read; - g_return_if_fail (download_info != NULL); - - if (g_cancellable_is_cancelled (download_info->cancellable)) { - /* finish the operation and close both streams */ - g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, NULL); + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (G_IS_ASYNC_RESULT (result)); + g_return_if_fail (GTK_IS_WINDOW (parent)); - g_output_stream_close (download_info->ostream, NULL, NULL); - g_input_stream_close (download_info->istream, NULL, NULL); + if (e_attachment_open_finish (attachment, result, &error)) + return; - /* The only way how to get this canceled is in EAttachment's finalize method, - and because the download_info_free free's the attachment on error, - then do not consider cancellation as an error. */ - download_info_free (download_info); + /* Ignore cancellations. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - read = g_input_stream_read_finish (G_INPUT_STREAM (source_object), res, &error); + file_info = e_attachment_get_file_info (attachment); - if (!error) - g_output_stream_write_all (download_info->ostream, download_info->buffer, read, NULL, download_info->cancellable, &error); + if (file_info != NULL) + display_name = g_file_info_get_display_name (file_info); + else + display_name = NULL; - if (error) { - download_info->was_error = error->domain != G_IO_ERROR || error->code != G_IO_ERROR_CANCELLED; - if (download_info->was_error) - e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, error->message, NULL); + if (display_name != NULL) + primary_text = g_strdup_printf ( + _("Could not open '%s'"), display_name); + else + primary_text = g_strdup_printf ( + _("Could not open the attachment")); - g_error_free (error); + dialog = gtk_message_dialog_new_with_markup ( + parent, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "%s", primary_text); - download_info->attachment->cancellable = NULL; - download_info_free (download_info); - return; - } + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - if (read == 0) { - CamelException ex; + gtk_dialog_run (GTK_DIALOG (dialog)); - /* done with reading */ - g_output_stream_close (download_info->ostream, NULL, NULL); - g_input_stream_close (download_info->istream, NULL, NULL); + gtk_widget_destroy (dialog); + g_error_free (error); +} - download_info->attachment->cancellable = NULL; +/************************* e_attachment_save_async() *************************/ - camel_exception_init (&ex); - e_attachment_build_remote_file (download_info->file_name, download_info->attachment, "attachment", &ex); +typedef struct _SaveContext SaveContext; - if (camel_exception_is_set (&ex)) { - download_info->was_error = TRUE; - e_error_run (download_info->parent, "mail-composer:no-attach", download_info->uri, camel_exception_get_description (&ex), NULL); - camel_exception_clear (&ex); - } +struct _SaveContext { + EAttachment *attachment; + GSimpleAsyncResult *simple; + + GFile *directory; + GFile *destination; + GInputStream *input_stream; + GOutputStream *output_stream; + goffset total_num_bytes; + gssize bytes_read; + gchar buffer[4096]; + gint count; +}; - download_info->attachment->percentage = -1; - download_info->attachment->is_available_local = TRUE; - g_signal_emit (download_info->attachment, signals[UPDATE], 0); +/* Forward Declaration */ +static void +attachment_save_read_cb (GInputStream *input_stream, + GAsyncResult *result, + SaveContext *save_context); + +static SaveContext * +attachment_save_context_new (EAttachment *attachment, + GAsyncReadyCallback callback, + gpointer user_data) +{ + SaveContext *save_context; + GSimpleAsyncResult *simple; - download_info_free (download_info); - return; - } else if (download_info->file_size) { - download_info->attachment->percentage = read * 100 / download_info->file_size; - download_info->file_size -= MIN (download_info->file_size, read); - g_signal_emit (download_info->attachment, signals[UPDATE], 0); - } else { - download_info->attachment->percentage = 0; - g_signal_emit (download_info->attachment, signals[UPDATE], 0); - } + simple = g_simple_async_result_new ( + G_OBJECT (attachment), callback, + user_data, e_attachment_save_async); + + save_context = g_slice_new0 (SaveContext); + save_context->attachment = g_object_ref (attachment); + save_context->simple = simple; - /* read next chunk */ - g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info); + attachment_set_saving (save_context->attachment, TRUE); + + return save_context; } -static gboolean -download_to_local_path (DownloadInfo *download_info, CamelException *ex) +static void +attachment_save_context_free (SaveContext *save_context) { - GError *error = NULL; - GFile *src = g_file_new_for_uri (download_info->uri); - GFile *des = g_file_new_for_path (download_info->file_name); - gboolean res = FALSE; + /* Do not free the GSimpleAsyncResult. */ + g_object_unref (save_context->attachment); - g_return_val_if_fail (src != NULL && des != NULL, FALSE); + if (save_context->directory != NULL) + g_object_unref (save_context->directory); - download_info->ostream = G_OUTPUT_STREAM (g_file_replace (des, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error)); + if (save_context->destination != NULL) + g_object_unref (save_context->destination); - if (download_info->ostream && !error) { - GFileInfo *fi; + if (save_context->input_stream != NULL) + g_object_unref (save_context->input_stream); - fi = g_file_query_info (src, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (save_context->output_stream != NULL) + g_object_unref (save_context->output_stream); - if (fi) { - download_info->file_size = g_file_info_get_attribute_uint64 (fi, G_FILE_ATTRIBUTE_STANDARD_SIZE); - g_object_unref (fi); - } else { - download_info->file_size = 0; - } + g_slice_free (SaveContext, save_context); +} - download_info->istream = G_INPUT_STREAM (g_file_read (src, NULL, &error)); +static gboolean +attachment_save_check_for_error (SaveContext *save_context, + GError *error) +{ + GSimpleAsyncResult *simple; - if (download_info->istream && !error) { - download_info->cancellable = g_cancellable_new (); - download_info->attachment->cancellable = download_info->cancellable; - download_info->buffer_size = 10240; /* max 10KB chunk */ - download_info->buffer = g_malloc (sizeof (char) * download_info->buffer_size); + if (error == NULL) + return FALSE; - g_input_stream_read_async (download_info->istream, download_info->buffer, download_info->buffer_size, G_PRIORITY_DEFAULT, download_info->cancellable, data_ready_cb, download_info); + /* Steal the result. */ + simple = save_context->simple; + save_context->simple = NULL; - res = TRUE; - } - } + g_simple_async_result_set_from_error (simple, error); + g_simple_async_result_complete (simple); + g_error_free (error); - if (error) { - /* propagate error */ - if (ex) - camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, error->message); + attachment_save_context_free (save_context); - g_error_free (error); - download_info->was_error = TRUE; - download_info_free (download_info); + return TRUE; +} + +static GFile * +attachment_save_new_candidate (SaveContext *save_context) +{ + GFile *candidate; + GFileInfo *file_info; + EAttachment *attachment; + const gchar *display_name; + gchar *basename; + + attachment = save_context->attachment; + file_info = e_attachment_get_file_info (attachment); + + if (file_info != NULL) + display_name = g_file_info_get_display_name (file_info); + if (display_name == NULL) + /* Translators: Default attachment filename. */ + display_name = _("attachment.dat"); + + if (save_context->count == 0) + basename = g_strdup (display_name); + else { + GString *string; + const gchar *ext; + gsize length; + + string = g_string_sized_new (strlen (display_name)); + ext = g_utf8_strchr (display_name, -1, '.'); + + if (ext != NULL) + length = ext - display_name; + else + length = strlen (display_name); + + g_string_append_len (string, display_name, length); + g_string_append_printf (string, " (%d)", save_context->count); + g_string_append (string, (ext != NULL) ? ext : ""); + + basename = g_string_free (string, FALSE); } - g_object_unref (src); - g_object_unref (des); + save_context->count++; + + candidate = g_file_get_child (save_context->directory, basename); + + g_free (basename); - return res; + return candidate; } -EAttachment * -e_attachment_new_remote_file (GtkWindow *error_dlg_parent, const char *uri, const char *disposition, const char *path, CamelException *ex) +static void +attachment_save_write_cb (GOutputStream *output_stream, + GAsyncResult *result, + SaveContext *save_context) { - EAttachment *new; - DownloadInfo *download_info; - CamelURL *url; - char *base; + EAttachment *attachment; + GCancellable *cancellable; + GInputStream *input_stream; + gssize bytes_written; + GError *error = NULL; - g_return_val_if_fail (uri != NULL, NULL); + bytes_written = g_output_stream_write_finish ( + output_stream, result, &error); - url = camel_url_new (uri, NULL); - base = g_path_get_basename (url->path); - camel_url_free (url); - - new = g_object_new (E_TYPE_ATTACHMENT, NULL); - new->editor_gui = NULL; - new->body = NULL; - new->size = 0; - new->guessed_type = FALSE; - new->cancellable = NULL; - new->is_available_local = FALSE; - new->percentage = 0; - new->file_name = g_build_filename (path, base, NULL); - - g_free (base); - - download_info = g_new0 (DownloadInfo, 1); - download_info->attachment = new; - download_info->file_name = g_strdup (new->file_name); - download_info->uri = g_strdup (uri); - download_info->parent = error_dlg_parent; - download_info->was_error = FALSE; - - /* it frees all on the error, so do not free it twice */ - if (!download_to_local_path (download_info, ex)) - return NULL; + if (attachment_save_check_for_error (save_context, error)) + return; - return new; + attachment = save_context->attachment; + cancellable = attachment->priv->cancellable; + input_stream = save_context->input_stream; + + if (bytes_written < save_context->bytes_read) { + g_memmove ( + save_context->buffer, + save_context->buffer + bytes_written, + save_context->bytes_read - bytes_written); + save_context->bytes_read -= bytes_written; + + g_output_stream_write_async ( + output_stream, + save_context->buffer, + save_context->bytes_read, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_write_cb, + save_context); + } else + g_input_stream_read_async ( + input_stream, + save_context->buffer, + sizeof (save_context->buffer), + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_read_cb, + save_context); } - -void -e_attachment_build_remote_file (const char *file_name, EAttachment *attachment, const char *disposition, CamelException *ex) +static void +attachment_save_read_cb (GInputStream *input_stream, + GAsyncResult *result, + SaveContext *save_context) { - CamelMimePart *part; - CamelDataWrapper *wrapper; - CamelStream *stream; - struct stat statbuf; - char *mime_type; - char *filename; - CamelURL *url; - - g_return_if_fail (file_name != NULL); - - if (g_stat (file_name, &statbuf) == -1) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot attach file %s: %s"), - file_name, g_strerror (errno)); - g_message ("Cannot attach file %s: %s\n", file_name, g_strerror (errno)); - return; - } + EAttachment *attachment; + GCancellable *cancellable; + GOutputStream *output_stream; + gssize bytes_read; + GError *error = NULL; - /* 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); - g_message ("Cannot attach file %s: not a regular file", file_name); - return; - } + bytes_read = g_input_stream_read_finish ( + input_stream, result, &error); - if (!(stream = camel_stream_fs_new_with_name (file_name, O_RDONLY, 0))) { - camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, - _("Cannot attach file %s: %s"), - file_name, g_strerror (errno)); + if (attachment_save_check_for_error (save_context, error)) return; - } - - if ((mime_type = attachment_guess_mime_type (file_name))) { - 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); + if (bytes_read == 0) { + GSimpleAsyncResult *simple; + GFile *destination; - part = camel_mime_part_new (); - camel_medium_set_content_object (CAMEL_MEDIUM (part), wrapper); - camel_object_unref (wrapper); + /* Steal the result. */ + simple = save_context->simple; + save_context->simple = NULL; - if (attachment->disposition) - camel_mime_part_set_disposition (part, "inline"); - else - camel_mime_part_set_disposition (part, "attachment"); + /* Steal the destination. */ + destination = save_context->destination; + save_context->destination = NULL; - if (!attachment->file_name) - filename = g_path_get_basename (file_name); - else - filename = g_path_get_basename (attachment->file_name); + g_simple_async_result_set_op_res_gpointer ( + simple, destination, (GDestroyNotify) g_object_unref); + g_simple_async_result_complete (simple); - camel_mime_part_set_filename (part, filename); + attachment_save_context_free (save_context); - if (attachment->description) { - camel_mime_part_set_description (part, attachment->description); - g_free (attachment->description); - attachment->description = NULL; + return; } - attachment->editor_gui = NULL; - attachment->body = part; - attachment->size = statbuf.st_size; - attachment->guessed_type = TRUE; - g_free (attachment->file_name); - attachment->file_name = filename; + attachment = save_context->attachment; + cancellable = attachment->priv->cancellable; + output_stream = save_context->output_stream; + save_context->bytes_read = bytes_read; + + attachment_progress_cb ( + g_seekable_tell (G_SEEKABLE (input_stream)), + save_context->total_num_bytes, attachment); + + g_output_stream_write_async ( + output_stream, + save_context->buffer, + save_context->bytes_read, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_write_cb, + save_context); +} - url = camel_url_new ("file://", NULL); - camel_url_set_path (url, file_name); - attachment->store_uri = camel_url_to_string (url, 0); - camel_url_free (url); +static void +attachment_save_got_output_stream (SaveContext *save_context) +{ + GCancellable *cancellable; + GInputStream *input_stream; + CamelDataWrapper *wrapper; + CamelMimePart *mime_part; + CamelStream *stream; + EAttachment *attachment; + GByteArray *buffer; + + attachment = save_context->attachment; + cancellable = attachment->priv->cancellable; + mime_part = e_attachment_get_mime_part (attachment); + + /* Decode the MIME part to an in-memory buffer. We have to do + * this because CamelStream is synchronous-only, and using threads + * is dangerous because CamelDataWrapper is not reentrant. */ + buffer = g_byte_array_new (); + stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (stream), buffer); + wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (mime_part)); + camel_data_wrapper_decode_to_stream (wrapper, stream); + camel_object_unref (stream); + /* Load the buffer into a GMemoryInputStream. */ + input_stream = g_memory_input_stream_new_from_data ( + buffer->data, (gssize) buffer->len, + (GDestroyNotify) g_free); + save_context->input_stream = input_stream; + save_context->total_num_bytes = (goffset) buffer->len; + g_byte_array_free (buffer, FALSE); + + g_input_stream_read_async ( + input_stream, + save_context->buffer, + sizeof (save_context->buffer), + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_read_cb, + save_context); } - -/** - * e_attachment_new_from_mime_part: - * @part: a CamelMimePart - * - * Return value: a new EAttachment based on the mime part - **/ -EAttachment * -e_attachment_new_from_mime_part (CamelMimePart *part) +static void +attachment_save_create_cb (GFile *destination, + GAsyncResult *result, + SaveContext *save_context) { - EAttachment *new; + EAttachment *attachment; + GCancellable *cancellable; + GFileOutputStream *output_stream; + GError *error = NULL; - g_return_val_if_fail (CAMEL_IS_MIME_PART (part), NULL); + /* Output stream might be NULL, so don't use cast macro. */ + output_stream = g_file_create_finish (destination, result, &error); + save_context->output_stream = (GOutputStream *) output_stream; - new = g_object_new (E_TYPE_ATTACHMENT, NULL); - new->editor_gui = NULL; - camel_object_ref (part); - new->body = part; - new->guessed_type = FALSE; - new->is_available_local = TRUE; - new->size = camel_mime_part_get_content_size (part); - new->file_name = g_strdup (camel_mime_part_get_filename(part)); + attachment = save_context->attachment; + cancellable = attachment->priv->cancellable; - return new; -} + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { + destination = attachment_save_new_candidate (save_context); - -/* The attachment property dialog. */ + g_file_create_async ( + destination, G_FILE_CREATE_NONE, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_create_cb, + save_context); -typedef struct { - GtkWidget *dialog; - GtkEntry *file_name_entry; - GtkEntry *description_entry; - GtkEntry *mime_type_entry; - GtkToggleButton *disposition_checkbox; - EAttachment *attachment; -} DialogData; + g_object_unref (destination); + g_error_free (error); + return; + } -static void -destroy_dialog_data (DialogData *data) -{ - g_free (data); -} + if (attachment_save_check_for_error (save_context, error)) + return; -/* - * fixme: I am converting EVERYTHING to/from UTF-8, although mime types - * are in ASCII. This is not strictly necessary, but we want to be - * consistent and possibly check for errors somewhere. - */ + save_context->destination = g_object_ref (destination); + attachment_save_got_output_stream (save_context); +} static void -set_entry (GladeXML *xml, const char *widget_name, const char *value) +attachment_save_replace_cb (GFile *destination, + GAsyncResult *result, + SaveContext *save_context) { - GtkEntry *entry; + GFileOutputStream *output_stream; + GError *error = NULL; - entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name)); - if (entry == NULL) - g_warning ("Entry for `%s' not found.", widget_name); - else - gtk_entry_set_text (entry, value ? value : ""); -} + /* Output stream might be NULL, so don't use cast macro. */ + output_stream = g_file_replace_finish (destination, result, &error); + save_context->output_stream = (GOutputStream *) output_stream; -static void -connect_widget (GladeXML *gui, const char *name, const char *signal_name, - GCallback func, gpointer data) -{ - GtkWidget *widget; + if (attachment_save_check_for_error (save_context, error)) + return; - widget = glade_xml_get_widget (gui, name); - g_signal_connect (widget, signal_name, func, data); + save_context->destination = g_object_ref (destination); + attachment_save_got_output_stream (save_context); } static void -close_cb (GtkWidget *widget, gpointer data) +attachment_save_query_info_cb (GFile *destination, + GAsyncResult *result, + SaveContext *save_context) { EAttachment *attachment; - DialogData *dialog_data; + GCancellable *cancellable; + GFileInfo *file_info; + GFileType file_type; + GError *error = NULL; + + attachment = save_context->attachment; + cancellable = attachment->priv->cancellable; + + file_info = g_file_query_info_finish (destination, result, &error); + + /* G_IO_ERROR_NOT_FOUND just means we're creating a new file. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + g_error_free (error); + goto replace; + } - dialog_data = (DialogData *) data; - attachment = dialog_data->attachment; + if (attachment_save_check_for_error (save_context, error)) + return; + + file_type = g_file_info_get_file_type (file_info); + g_object_unref (file_info); + + if (file_type == G_FILE_TYPE_DIRECTORY) { + save_context->directory = g_object_ref (destination); + destination = attachment_save_new_candidate (save_context); + + g_file_create_async ( + destination, G_FILE_CREATE_NONE, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_create_cb, + save_context); - gtk_widget_destroy (dialog_data->dialog); - g_object_unref (attachment->editor_gui); - attachment->editor_gui = NULL; + g_object_unref (destination); - destroy_dialog_data (dialog_data); + return; + } + +replace: + g_file_replace_async ( + destination, NULL, FALSE, +#if GLIB_CHECK_VERSION(2,20,0) + G_FILE_CREATE_REPLACE_DESTINATION, +#else + G_FILE_CREATE_NONE, +#endif + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) attachment_save_replace_cb, + save_context); } -static void -ok_cb (GtkWidget *widget, gpointer data) +void +e_attachment_save_async (EAttachment *attachment, + GFile *destination, + GAsyncReadyCallback callback, + gpointer user_data) { - DialogData *dialog_data; - EAttachment *attachment; - const char *str; - - dialog_data = (DialogData *) data; - attachment = dialog_data->attachment; - - str = gtk_entry_get_text (dialog_data->file_name_entry); - if (attachment->is_available_local) - camel_mime_part_set_filename (attachment->body, str); - g_free (attachment->file_name); - attachment->file_name = g_strdup (str); - - str = gtk_entry_get_text (dialog_data->description_entry); - if (attachment->is_available_local) { - camel_mime_part_set_description (attachment->body, str); - } else { - g_free (attachment->description); - attachment->description = g_strdup (str); + SaveContext *save_context; + GCancellable *cancellable; + + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (G_IS_FILE (destination)); + g_return_if_fail (callback != NULL); + + if (e_attachment_get_loading (attachment)) { + g_simple_async_report_error_in_idle ( + G_OBJECT (attachment), callback, user_data, + G_IO_ERROR, G_IO_ERROR_BUSY, + _("A load operation is already in progress")); + return; } - str = gtk_entry_get_text (dialog_data->mime_type_entry); - 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 (e_attachment_get_saving (attachment)) { + g_simple_async_report_error_in_idle ( + G_OBJECT (attachment), callback, user_data, + G_IO_ERROR, G_IO_ERROR_BUSY, + _("A save operation is already in progress")); + return; } - 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); + if (e_attachment_get_mime_part (attachment) == NULL) { + g_simple_async_report_error_in_idle ( + G_OBJECT (attachment), callback, user_data, + G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, + _("Attachment contents not loaded")); + return; } - changed (attachment); - close_cb (widget, data); + save_context = attachment_save_context_new ( + attachment, callback, user_data); + + cancellable = attachment->priv->cancellable; + g_cancellable_reset (cancellable); + + /* First we need to know if destination is a directory. */ + g_file_query_info_async ( + destination, G_FILE_ATTRIBUTE_STANDARD_TYPE, + G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, + cancellable, (GAsyncReadyCallback) + attachment_save_query_info_cb, save_context); } -static void -response_cb (GtkWidget *widget, gint response, gpointer data) +GFile * +e_attachment_save_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error) { - if (response == GTK_RESPONSE_OK) - ok_cb (widget, data); - else - close_cb (widget, data); + GSimpleAsyncResult *simple; + GFile *destination; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); + + simple = G_SIMPLE_ASYNC_RESULT (result); + destination = g_simple_async_result_get_op_res_gpointer (simple); + if (destination != NULL) + g_object_ref (destination); + g_simple_async_result_propagate_error (simple, error); + g_object_unref (simple); + + attachment_set_saving (attachment, FALSE); + + return destination; } void -e_attachment_edit (EAttachment *attachment, GtkWidget *parent) +e_attachment_save_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent) { - CamelContentType *content_type; - const char *disposition; - DialogData *dialog_data; - GladeXML *editor_gui; - GtkWidget *window; - char *type; - char *filename; + GFile *file; + GFileInfo *file_info; + GtkWidget *dialog; + const gchar *display_name; + const gchar *primary_text; + GError *error = NULL; g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (G_IS_ASYNC_RESULT (result)); + g_return_if_fail (GTK_IS_WINDOW (parent)); + + file = e_attachment_save_finish (attachment, result, &error); - if (attachment->editor_gui != NULL) { - window = glade_xml_get_widget (attachment->editor_gui, "dialog"); - gdk_window_show (window->window); + if (file != NULL) { + g_object_unref (file); return; } - filename = g_build_filename (EVOLUTION_GLADEDIR, "e-attachment.glade", NULL); - editor_gui = glade_xml_new (filename, NULL, NULL); - g_free (filename); - - if (editor_gui == NULL) { - g_warning ("Cannot load `e-attachment.glade'"); + /* Ignore cancellations. */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - attachment->editor_gui = editor_gui; - - gtk_window_set_transient_for (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")), - GTK_WINDOW (gtk_widget_get_toplevel (parent))); - - dialog_data = g_new (DialogData, 1); - dialog_data->attachment = attachment; - dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog"); - dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "file_name_entry")); - dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget (editor_gui, "description_entry")); - dialog_data->mime_type_entry = GTK_ENTRY (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 && attachment->body) { - 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); - if ((type = attachment_guess_mime_type (attachment->file_name))) { - set_entry (editor_gui, "mime_type_entry", type); - g_free (type); - } else { - set_entry (editor_gui, "mime_type_entry", ""); - } + file_info = e_attachment_get_file_info (attachment); - gtk_toggle_button_set_active (dialog_data->disposition_checkbox, attachment->disposition); - } + if (file_info != NULL) + display_name = g_file_info_get_display_name (file_info); + else + display_name = NULL; + + if (display_name != NULL) + primary_text = g_strdup_printf ( + _("Could not save '%s'"), display_name); + else + primary_text = g_strdup_printf ( + _("Could not save the attachment")); + + dialog = gtk_message_dialog_new_with_markup ( + parent, GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + "%s", primary_text); + + gtk_message_dialog_format_secondary_text ( + GTK_MESSAGE_DIALOG (dialog), "%s", error->message); - connect_widget (editor_gui, "dialog", "response", (GCallback)response_cb, dialog_data); + gtk_dialog_run (GTK_DIALOG (dialog)); - /* make sure that when the parent gets hidden/closed that our windows also close */ - parent = gtk_widget_get_toplevel (parent); - gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_data->dialog), TRUE); + gtk_widget_destroy (dialog); + g_error_free (error); } diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h index 7b45f24ae5..934e1e04b6 100644 --- a/widgets/misc/e-attachment.h +++ b/widgets/misc/e-attachment.h @@ -1,4 +1,6 @@ /* + * e-attachment.h + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either @@ -13,91 +15,131 @@ * License along with the program; if not, see * * - * Authors: - * Ettore Perazzoli - * Srinivasa Ragavan - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifndef __E_ATTACHMENT_H__ -#define __E_ATTACHMENT_H__ +#ifndef E_ATTACHMENT_H +#define E_ATTACHMENT_H -#include #include -#include -#include -#include #include - -#ifdef __cplusplus -extern "C" { -#pragma } -#endif /* __cplusplus */ - -#define E_TYPE_ATTACHMENT (e_attachment_get_type ()) -#define E_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_ATTACHMENT, EAttachment)) -#define E_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_ATTACHMENT, EAttachmentClass)) -#define E_IS_ATTACHMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_ATTACHMENT)) -#define E_IS_ATTACHMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_ATTACHMENT)) - - -typedef struct _EAttachment EAttachment; -typedef struct _EAttachmentClass EAttachmentClass; +#include +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_ATTACHMENT \ + (e_attachment_get_type ()) +#define E_ATTACHMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_ATTACHMENT, EAttachment)) +#define E_ATTACHMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_ATTACHMENT, EAttachmentClass)) +#define E_IS_ATTACHMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_ATTACHMENT)) +#define E_IS_ATTACHMENT_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_ATTACHMENT)) +#define E_ATTACHMENT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_ATTACHMENT, EAttachmentClass)) + +G_BEGIN_DECLS + +typedef struct _EAttachment EAttachment; +typedef struct _EAttachmentClass EAttachmentClass; +typedef struct _EAttachmentPrivate EAttachmentPrivate; struct _EAttachment { GObject parent; - - GladeXML *editor_gui; - - CamelMimePart *body; - gboolean guessed_type; - gulong size; - - GdkPixbuf *pixbuf_cache; - - GCancellable *cancellable; - - gboolean is_available_local; - int percentage; - char *file_name; - char *description; - gboolean disposition; - int index; - char *store_uri; - - /* Status of signed/encrypted attachments */ - camel_cipher_validity_sign_t sign; - camel_cipher_validity_encrypt_t encrypt; + EAttachmentPrivate *priv; }; struct _EAttachmentClass { GObjectClass parent_class; - - void (*changed) (EAttachment *attachment); - void (*update) (EAttachment *attachment, char *msg); }; -GType e_attachment_get_type (void); -EAttachment *e_attachment_new (const char *file_name, - const char *disposition, - CamelException *ex); -EAttachment * e_attachment_new_remote_file (GtkWindow *error_dlg_parent, - const char *url, - const char *disposition, - const char *path, - CamelException *ex); -void e_attachment_build_remote_file (const char *filename, - EAttachment *attachment, - const char *disposition, - CamelException *ex); -EAttachment *e_attachment_new_from_mime_part (CamelMimePart *part); -void e_attachment_edit (EAttachment *attachment, - GtkWidget *parent); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __E_ATTACHMENT_H__ */ +GType e_attachment_get_type (void); +EAttachment * e_attachment_new (void); +EAttachment * e_attachment_new_for_path (const gchar *path); +EAttachment * e_attachment_new_for_uri (const gchar *uri); +EAttachment * e_attachment_new_for_message (CamelMimeMessage *message); +void e_attachment_add_to_multipart (EAttachment *attachment, + CamelMultipart *multipart, + const gchar *default_charset); +void e_attachment_cancel (EAttachment *attachment); +gboolean e_attachment_get_can_show (EAttachment *attachment); +void e_attachment_set_can_show (EAttachment *attachment, + gboolean can_show); +const gchar * e_attachment_get_disposition (EAttachment *attachment); +void e_attachment_set_disposition (EAttachment *attachment, + const gchar *disposition); +GFile * e_attachment_get_file (EAttachment *attachment); +void e_attachment_set_file (EAttachment *attachment, + GFile *file); +GFileInfo * e_attachment_get_file_info (EAttachment *attachment); +gboolean e_attachment_get_loading (EAttachment *attachment); +CamelMimePart * e_attachment_get_mime_part (EAttachment *attachment); +void e_attachment_set_mime_part (EAttachment *attachment, + CamelMimePart *mime_part); +gint e_attachment_get_percent (EAttachment *attachment); +GtkTreeRowReference * + e_attachment_get_reference (EAttachment *attachment); +void e_attachment_set_reference (EAttachment *attachment, + GtkTreeRowReference *reference); +gboolean e_attachment_get_saving (EAttachment *attachment); +gboolean e_attachment_get_shown (EAttachment *attachment); +void e_attachment_set_shown (EAttachment *attachment, + gboolean shown); +camel_cipher_validity_encrypt_t + e_attachment_get_encrypted (EAttachment *attachment); +void e_attachment_set_encrypted (EAttachment *attachment, + camel_cipher_validity_encrypt_t encrypted); +camel_cipher_validity_sign_t + e_attachment_get_signed (EAttachment *attachment); +void e_attachment_set_signed (EAttachment *attachment, + camel_cipher_validity_sign_t signed_); +const gchar * e_attachment_get_description (EAttachment *attachment); +const gchar * e_attachment_get_thumbnail_path (EAttachment *attachment); +gboolean e_attachment_is_rfc822 (EAttachment *attachment); +GList * e_attachment_list_apps (EAttachment *attachment); + +/* Asynchronous Operations */ +void e_attachment_load_async (EAttachment *attachment, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_attachment_load_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error); +void e_attachment_open_async (EAttachment *attachment, + GAppInfo *app_info, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean e_attachment_open_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error); +void e_attachment_save_async (EAttachment *attachment, + GFile *destination, + GAsyncReadyCallback callback, + gpointer user_data); +GFile * e_attachment_save_finish (EAttachment *attachment, + GAsyncResult *result, + GError **error); + +/* Handy GAsyncReadyCallback Functions */ +void e_attachment_load_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent); +void e_attachment_open_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent); +void e_attachment_save_handle_error (EAttachment *attachment, + GAsyncResult *result, + GtkWindow *parent); + +G_END_DECLS + +#endif /* E_ATTACHMENT_H */ diff --git a/widgets/misc/e-expander.c b/widgets/misc/e-expander.c deleted file mode 100644 index 771598739d..0000000000 --- a/widgets/misc/e-expander.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * GTK - The GIMP Toolkit - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Mark McLoughlin - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2003 Sun Microsystems, Inc. - * - */ - -#include - -#include "e-expander.h" -#include "ea-widgets.h" - -#include - -#define DEFAULT_EXPANDER_SIZE 10 -#define DEFAULT_EXPANDER_SPACING 2 - -/* ESTUFF */ -#ifndef _ -#define _(x) (x) -#endif -#define E_EXPANDER_GET_PRIVATE(expander) ((EExpanderPrivate *)g_object_get_data (G_OBJECT (expander), "e-expander-priv")) - -enum { - PROP_0, - PROP_EXPANDED, - PROP_LABEL, - PROP_USE_UNDERLINE, - PROP_PADDING, - PROP_LABEL_WIDGET -}; - -typedef struct { - GtkWidget *label_widget; - gint spacing; - - GtkExpanderStyle expander_style; - guint animation_timeout; - - guint expanded : 1; - guint use_underline : 1; - guint button_down : 1; -} EExpanderPrivate; - -static void e_expander_class_init (EExpanderClass *klass); -static void e_expander_init (EExpander *expander); - -static void e_expander_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void e_expander_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static void e_expander_destroy (GtkObject *object); - -static void e_expander_realize (GtkWidget *widget); -static void e_expander_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void e_expander_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void e_expander_map (GtkWidget *widget); -static gboolean e_expander_expose (GtkWidget *widget, - GdkEventExpose *event); -static gboolean e_expander_button_press (GtkWidget *widget, - GdkEventButton *event); -static gboolean e_expander_button_release (GtkWidget *widget, - GdkEventButton *event); -static gboolean e_expander_motion_notify (GtkWidget *widget, - GdkEventMotion *event); -static gboolean e_expander_enter_notify (GtkWidget *widget, - GdkEventCrossing *event); -static gboolean e_expander_leave_notify (GtkWidget *widget, - GdkEventCrossing *event); -static gboolean e_expander_focus (GtkWidget *widget, - GtkDirectionType direction); - -static void e_expander_add (GtkContainer *container, - GtkWidget *widget); -static void e_expander_remove (GtkContainer *container, - GtkWidget *widget); -static void e_expander_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); - -static void e_expander_activate (EExpander *expander); - -static GtkBinClass *parent_class = NULL; - -GType -e_expander_get_type (void) -{ - static GType expander_type = 0; - - if (!expander_type) - { - static const GTypeInfo expander_info = - { - sizeof (EExpanderClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) e_expander_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EExpander), - 0, /* n_preallocs */ - (GInstanceInitFunc) e_expander_init, - }; - - expander_type = g_type_register_static (GTK_TYPE_BIN, - "EExpander", - &expander_info, 0); - } - - return expander_type; -} - -static void -e_expander_class_init (EExpanderClass *klass) -{ - GObjectClass *gobject_class; - GtkObjectClass *gtkobject_class; - GtkWidgetClass *widget_class; - GtkContainerClass *container_class; - - parent_class = g_type_class_peek_parent (klass); - - gobject_class = (GObjectClass *) klass; - gtkobject_class = (GtkObjectClass *) klass; - widget_class = (GtkWidgetClass *) klass; - container_class = (GtkContainerClass *) klass; - - gobject_class->set_property = e_expander_set_property; - gobject_class->get_property = e_expander_get_property; - - gtkobject_class->destroy = e_expander_destroy; - - widget_class->realize = e_expander_realize; - widget_class->size_request = e_expander_size_request; - widget_class->size_allocate = e_expander_size_allocate; - widget_class->map = e_expander_map; - widget_class->expose_event = e_expander_expose; - widget_class->button_press_event = e_expander_button_press; - widget_class->button_release_event = e_expander_button_release; - widget_class->motion_notify_event = e_expander_motion_notify; - widget_class->enter_notify_event = e_expander_enter_notify; - widget_class->leave_notify_event = e_expander_leave_notify; - widget_class->focus = e_expander_focus; - - container_class->add = e_expander_add; - container_class->remove = e_expander_remove; - container_class->forall = e_expander_forall; - - klass->activate = e_expander_activate; - - /* ESTUFF g_type_class_add_private (klass, sizeof (EExpanderPrivate)); */ - - g_object_class_install_property (gobject_class, - PROP_EXPANDED, - g_param_spec_boolean ("expanded", - _("Expanded"), - _("Whether or not the expander is expanded"), - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (gobject_class, - PROP_LABEL, - g_param_spec_string ("label", - _("Label"), - _("Text of the expander's label"), - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (gobject_class, - PROP_USE_UNDERLINE, - g_param_spec_boolean ("use_underline", - _("Use underline"), - _("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"), - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - - g_object_class_install_property (gobject_class, - PROP_PADDING, - g_param_spec_int ("spacing", - _("Spacing"), - _("Space to put between the label and the child"), - 0, - G_MAXINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - PROP_LABEL_WIDGET, - g_param_spec_object ("label_widget", - _("Label widget"), - _("A widget to display in place of the usual expander label"), - GTK_TYPE_WIDGET, - G_PARAM_READWRITE)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("expander-size", - _("Expander Size"), - _("Size of the expander arrow"), - 0, - G_MAXINT, - DEFAULT_EXPANDER_SIZE, - G_PARAM_READABLE)); - - gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("expander-spacing", - _("Indicator Spacing"), - _("Spacing around expander arrow"), - 0, - G_MAXINT, - DEFAULT_EXPANDER_SPACING, - G_PARAM_READABLE)); - - widget_class->activate_signal = - g_signal_new ("activate", - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (EExpanderClass, activate), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - e_expander_a11y_init(); -} - -static void -e_expander_init (EExpander *expander) -{ - EExpanderPrivate *priv; - - /* ESTUFF */ - priv = g_new0 (EExpanderPrivate, 1); - g_object_set_data_full (G_OBJECT (expander), "e-expander-priv", priv, g_free); - - /* ESTUFF priv = E_EXPANDER_GET_PRIVATE (expander); */ - - GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS); - GTK_WIDGET_UNSET_FLAGS (expander, GTK_NO_WINDOW); - - priv->label_widget = NULL; - priv->spacing = 0; - - priv->expander_style = GTK_EXPANDER_COLLAPSED; - priv->animation_timeout = 0; - - priv->expanded = FALSE; - priv->use_underline = FALSE; - priv->button_down = FALSE; - -} - -static void -e_expander_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - EExpander *expander = E_EXPANDER (object); - - switch (prop_id) - { - case PROP_EXPANDED: - e_expander_set_expanded (expander, g_value_get_boolean (value)); - break; - case PROP_LABEL: - e_expander_set_label (expander, g_value_get_string (value)); - break; - case PROP_USE_UNDERLINE: - e_expander_set_use_underline (expander, g_value_get_boolean (value)); - break; - case PROP_PADDING: - e_expander_set_spacing (expander, g_value_get_int (value)); - break; - case PROP_LABEL_WIDGET: - e_expander_set_label_widget (expander, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -e_expander_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - EExpander *expander = E_EXPANDER (object); - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - switch (prop_id) - { - case PROP_EXPANDED: - g_value_set_boolean (value, priv->expanded); - break; - case PROP_LABEL: - g_value_set_string (value, e_expander_get_label (expander)); - break; - case PROP_USE_UNDERLINE: - g_value_set_boolean (value, priv->use_underline); - break; - case PROP_PADDING: - g_value_set_int (value, priv->spacing); - break; - case PROP_LABEL_WIDGET: - g_value_set_object (value, - priv->label_widget ? - G_OBJECT (priv->label_widget) : NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -e_expander_destroy (GtkObject *object) -{ - EExpander *expander = E_EXPANDER (object); - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (priv->animation_timeout) - g_source_remove (priv->animation_timeout); - priv->animation_timeout = 0; - - GTK_OBJECT_CLASS (parent_class)->destroy (object); -} - -static void -e_expander_realize (GtkWidget *widget) -{ - GdkWindowAttr attributes; - gint attributes_mask; - gint border_width; - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - - border_width = GTK_CONTAINER (widget)->border_width; - - attributes.x = widget->allocation.x + border_width; - attributes.y = widget->allocation.y + border_width; - attributes.width = widget->allocation.width - 2 * border_width; - attributes.height = widget->allocation.height - 2 * border_width; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = gtk_widget_get_events (widget) | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_EXPOSURE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK; - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, widget); - - widget->style = gtk_style_attach (widget->style, widget->window); - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); -} - -static void -e_expander_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - EExpander *expander; - GtkBin *bin; - EExpanderPrivate *priv; - gint border_width; - gint expander_size; - gint expander_spacing; - gboolean interior_focus; - gint focus_width; - gint focus_pad; - - expander = E_EXPANDER (widget); - bin = GTK_BIN (widget); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - border_width = GTK_CONTAINER (widget)->border_width; - - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "expander-size", &expander_size, - "expander-spacing", &expander_spacing, - NULL); - - requisition->width = expander_size + 2 * expander_spacing + - 2 * focus_width + 2 * focus_pad; - requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0; - - if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget)) - { - GtkRequisition label_requisition; - - gtk_widget_size_request (priv->label_widget, &label_requisition); - - requisition->width += label_requisition.width; - requisition->height += label_requisition.height; - } - - requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height); - - if (!interior_focus) - requisition->height += 2 * focus_width + 2 * focus_pad; - - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) - { - GtkRequisition child_requisition; - - gtk_widget_size_request (bin->child, &child_requisition); - - if (!interior_focus) - child_requisition.width += 2 * focus_width + 2 * focus_pad; - - requisition->width = MAX (requisition->width, child_requisition.width); - requisition->height += child_requisition.height + priv->spacing; - } - - requisition->width += 2 * border_width; - requisition->height += 2 * border_width + 2 * priv->spacing; -} - -static void -e_expander_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - EExpander *expander; - GtkBin *bin; - EExpanderPrivate *priv; - GtkRequisition child_requisition; - gboolean child_visible = FALSE; - gint border_width; - gint expander_size; - gint expander_spacing; - gboolean interior_focus; - gint focus_width; - gint focus_pad; - gint label_height; - - expander = E_EXPANDER (widget); - bin = GTK_BIN (widget); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - border_width = GTK_CONTAINER (widget)->border_width; - - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "expander-size", &expander_size, - "expander-spacing", &expander_spacing, - NULL); - - child_requisition.width = 0; - child_requisition.height = 0; - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) - { - child_visible = TRUE; - gtk_widget_get_child_requisition (bin->child, &child_requisition); - } - - widget->allocation = *allocation; - - if (GTK_WIDGET_REALIZED (widget)) - gdk_window_move_resize (widget->window, - allocation->x + border_width, - allocation->y + border_width, - MAX (allocation->width - 2 * border_width, 0), - MAX (allocation->height - 2 * border_width, 0)); - - if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget)) - { - GtkAllocation label_allocation; - GtkRequisition label_requisition; - gboolean ltr; - - gtk_widget_get_child_requisition (priv->label_widget, &label_requisition); - - ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL; - - label_allocation.x = focus_width + focus_pad; - if (ltr) - label_allocation.x += expander_size + 2 * expander_spacing; - label_allocation.y = priv->spacing + focus_width + focus_pad; - - label_allocation.width = MIN (label_requisition.width, - allocation->width - 2 * border_width - - expander_size - 2 * expander_spacing - - 2 * focus_width - 2 * focus_pad); - label_allocation.width = MAX (label_allocation.width, 1); - - label_allocation.height = MIN (label_requisition.height, - allocation->height - 2 * border_width - - 2 * priv->spacing - - 2 * focus_width - 2 * focus_pad - - child_requisition.height - - (child_visible ? priv->spacing : 0)); - label_allocation.height = MAX (label_allocation.height, 1); - - gtk_widget_size_allocate (priv->label_widget, &label_allocation); - - label_height = label_allocation.height; - } - else - { - label_height = 0; - } - - if (child_visible) - { - GtkAllocation child_allocation; - gint top_height; - - top_height = MAX (2 * expander_spacing + expander_size, - label_height + - (interior_focus ? 2 * focus_width + 2 * focus_pad : 0)); - - child_allocation.x = 0; - child_allocation.y = 2 * priv->spacing + top_height; - - if (!interior_focus) - { - child_allocation.x += focus_width + focus_pad; - child_allocation.y += focus_width + focus_pad; - } - - child_allocation.width = allocation->width - 2 * border_width - - (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0); - child_allocation.width = MAX (child_allocation.width, 1); - - child_allocation.height = allocation->height - top_height - - 2 * border_width - - 3 * priv->spacing - - (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0); - child_allocation.height = MAX (child_allocation.height, 1); - - gtk_widget_size_allocate (bin->child, &child_allocation); - } -} - -static void -e_expander_map (GtkWidget *widget) -{ - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (widget); - - if (priv->label_widget) - gtk_widget_map (priv->label_widget); - - GTK_WIDGET_CLASS (parent_class)->map (widget); -} - -static GdkRectangle -get_expander_bounds (EExpander *expander) -{ - GtkWidget *widget; - EExpanderPrivate *priv; - GdkRectangle bounds; - gint border_width; - gint expander_size; - gint expander_spacing; - gboolean interior_focus; - gint focus_width; - gint focus_pad; - gboolean ltr; - - widget = GTK_WIDGET (expander); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - border_width = GTK_CONTAINER (expander)->border_width; - - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "expander-size", &expander_size, - "expander-spacing", &expander_spacing, - NULL); - - ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL; - - - if (ltr) - bounds.x = expander_spacing; - else - bounds.x = widget->allocation.width - 2 * border_width - - expander_spacing - expander_size; - - if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget)) - { - GtkAllocation label_allocation; - - label_allocation = priv->label_widget->allocation; - - if (expander_size < label_allocation.height) - bounds.y = label_allocation.y + (label_allocation.height - expander_size) / 2; - else - bounds.y = priv->spacing + expander_spacing; - } - else - { - bounds.y = priv->spacing + expander_spacing; - } - - if (!interior_focus) - { - if (ltr) - bounds.x += focus_width + focus_pad; - else - bounds.x -= focus_width + focus_pad; - bounds.y += focus_width + focus_pad; - } - - bounds.width = bounds.height = expander_size; - - return bounds; -} - -static void -e_expander_paint (EExpander *expander) -{ - GtkWidget *widget; - EExpanderPrivate *priv; - gint x, y; - GtkStateType state; - GdkRectangle clip; - - widget = GTK_WIDGET (expander); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - clip = get_expander_bounds (expander); - - x = clip.x + clip.width / 2; - y = clip.y + clip.height / 2; - - state = widget->state; - if (state != GTK_STATE_PRELIGHT) - state = GTK_STATE_NORMAL; - - gtk_paint_expander (widget->style, - widget->window, - state, - &clip, - widget, - "expander", - x, - y, - priv->expander_style); -} - -static void -e_expander_paint_focus (EExpander *expander, - GdkRectangle *area) -{ - GtkWidget *widget; - EExpanderPrivate *priv; - gint x, y, width, height; - gboolean interior_focus; - gint focus_width; - gint focus_pad; - gint expander_size; - gint expander_spacing; - gboolean ltr; - - widget = GTK_WIDGET (expander); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - "focus-padding", &focus_pad, - "expander-size", &expander_size, - "expander-spacing", &expander_spacing, - NULL); - - ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL; - - if (interior_focus) - { - if (ltr) - x = expander_spacing * 2 + expander_size; - else - x = 0; - y = priv->spacing; - - width = height = 2 * focus_pad + 2 * focus_width; - - if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget)) - { - GtkAllocation label_allocation = priv->label_widget->allocation; - - width += label_allocation.width; - height += label_allocation.height; - } - } - else - { - x = y = 0; - width = widget->allocation.width - 2 * GTK_CONTAINER (widget)->border_width; - height = widget->allocation.height - 2 * GTK_CONTAINER (widget)->border_width; - } - - gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget), - area, widget, "expander", - x, y, width, height); -} - -static gboolean -e_expander_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - if (GTK_WIDGET_DRAWABLE (widget)) - { - EExpander *expander = E_EXPANDER (widget); - - e_expander_paint (expander); - - if (GTK_WIDGET_HAS_FOCUS (expander)) - e_expander_paint_focus (expander, &event->area); - - GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event); - } - - return FALSE; -} - -static gboolean -is_in_expander_panel (EExpander *expander, - GdkWindow *window, - gint x, - gint y) -{ - GtkWidget *widget; - GdkRectangle area; - - widget = GTK_WIDGET (expander); - - area = get_expander_bounds (expander); - - area.x = 0; - area.width = widget->allocation.width; - - if (widget->window == window) - { - if (x >= area.x && x <= (area.x + area.width) && - y >= area.y && y <= (area.y + area.height)) - return TRUE; - } - - return FALSE; -} - -static gboolean -e_expander_button_press (GtkWidget *widget, - GdkEventButton *event) -{ - EExpander *expander = E_EXPANDER (widget); - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (event->button == 1 && !priv->button_down) - { - if (is_in_expander_panel (expander, event->window, event->x, event->y)) - { - priv->button_down = TRUE; - return TRUE; - } - } - - return FALSE; -} - -static gboolean -e_expander_button_release (GtkWidget *widget, - GdkEventButton *event) -{ - EExpander *expander = E_EXPANDER (widget); - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (event->button == 1 && priv->button_down) - { - g_signal_emit_by_name (expander, "activate"); - - priv->button_down = FALSE; - return TRUE; - } - - return FALSE; -} - -static void -e_expander_maybe_prelight (EExpander *expander) -{ - GtkWidget *widget; - EExpanderPrivate *priv; - GtkStateType state = GTK_STATE_NORMAL; - - widget = GTK_WIDGET (expander); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (!priv->button_down) - { - gint x, y; - - gdk_window_get_pointer (widget->window, &x, &y, NULL); - - if (is_in_expander_panel (expander, widget->window, x, y)) - state = GTK_STATE_PRELIGHT; - } - - gtk_widget_set_state (widget, state); -} - -static gboolean -e_expander_motion_notify (GtkWidget *widget, - GdkEventMotion *event) -{ - e_expander_maybe_prelight (E_EXPANDER (widget)); - - return FALSE; -} - -static gboolean -e_expander_enter_notify (GtkWidget *widget, - GdkEventCrossing *event) -{ - e_expander_maybe_prelight (E_EXPANDER (widget)); - - return FALSE; -} - -static gboolean -e_expander_leave_notify (GtkWidget *widget, - GdkEventCrossing *event) -{ - gtk_widget_set_state (widget, GTK_STATE_NORMAL); - - return FALSE; -} - -static gboolean -focus_child_in (GtkWidget *widget, - GtkDirectionType direction) -{ - GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget)); - - if (!child) - return FALSE; - - return gtk_widget_child_focus (child, direction); -} - -static gboolean -e_expander_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - EExpanderPrivate *priv; - GtkWidget *old_focus_child; - gboolean widget_is_focus; - gboolean label_can_focus; - - priv = E_EXPANDER_GET_PRIVATE (widget); - - widget_is_focus = gtk_widget_is_focus (widget); - old_focus_child = GTK_CONTAINER (widget)->focus_child; - label_can_focus = priv->label_widget && GTK_WIDGET_CAN_FOCUS (priv->label_widget); - - if (old_focus_child && old_focus_child == priv->label_widget) - { - switch (direction) - { - case GTK_DIR_TAB_BACKWARD: - case GTK_DIR_LEFT: - case GTK_DIR_UP: - gtk_widget_grab_focus (widget); - return TRUE; - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_RIGHT: - return focus_child_in (widget, direction); - } - } - else if (old_focus_child) - { - if (gtk_widget_child_focus (old_focus_child, direction)) - return TRUE; - - switch (direction) - { - case GTK_DIR_TAB_BACKWARD: - case GTK_DIR_LEFT: - case GTK_DIR_UP: - if (label_can_focus) - gtk_widget_grab_focus (priv->label_widget); - else - gtk_widget_grab_focus (widget); - return TRUE; - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_RIGHT: - return FALSE; - } - } - else if (widget_is_focus) - { - switch (direction) - { - case GTK_DIR_TAB_BACKWARD: - case GTK_DIR_LEFT: - case GTK_DIR_UP: - return FALSE; - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_RIGHT: - if (label_can_focus) - { - gtk_widget_grab_focus (priv->label_widget); - return TRUE; - } - - return focus_child_in (widget, direction); - } - } - else - { - switch (direction) - { - case GTK_DIR_DOWN: - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_TAB_BACKWARD: - gtk_widget_grab_focus (widget); - return TRUE; - case GTK_DIR_UP: - case GTK_DIR_LEFT: - case GTK_DIR_RIGHT: - if (!focus_child_in (widget, direction)) - { - gtk_widget_grab_focus (widget); - } - return TRUE; - } - } - - g_return_val_if_reached(FALSE); -} - -static void -e_expander_add (GtkContainer *container, - GtkWidget *widget) -{ - GTK_CONTAINER_CLASS (parent_class)->add (container, widget); - - g_object_set (G_OBJECT (widget), - "visible", E_EXPANDER_GET_PRIVATE (container)->expanded, - NULL); -} - -static void -e_expander_remove (GtkContainer *container, - GtkWidget *widget) -{ - EExpander *expander = E_EXPANDER (container); - - if (E_EXPANDER_GET_PRIVATE (expander)->label_widget == widget) - e_expander_set_label_widget (expander, NULL); - else - GTK_CONTAINER_CLASS (parent_class)->remove (container, widget); -} - -static void -e_expander_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) -{ - GtkBin *bin = GTK_BIN (container); - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (container); - - if (bin->child) - (* callback) (bin->child, callback_data); - - if (priv->label_widget) - (* callback) (priv->label_widget, callback_data); -} - -static void -e_expander_activate (EExpander *expander) -{ - e_expander_set_expanded (expander, - !E_EXPANDER_GET_PRIVATE (expander)->expanded); -} - -GtkWidget * -e_expander_new (const gchar *label) -{ - return g_object_new (E_TYPE_EXPANDER, "label", label, NULL); -} - -GtkWidget * -e_expander_new_with_mnemonic (const gchar *label) -{ - return g_object_new (E_TYPE_EXPANDER, - "label", label, - "use_underline", TRUE, - NULL); -} - -static gboolean -e_expander_animation_timeout (EExpander *expander) -{ - EExpanderPrivate *priv; - GdkRectangle area; - gboolean finish = FALSE; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (GTK_WIDGET_REALIZED (expander)) - { - area = get_expander_bounds (expander); - gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE); - } - - if (priv->expanded) - { - if (priv->expander_style == GTK_EXPANDER_COLLAPSED) - { - priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED; - } - else - { - priv->expander_style = GTK_EXPANDER_EXPANDED; - finish = TRUE; - } - } - else - { - if (priv->expander_style == GTK_EXPANDER_EXPANDED) - { - priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED; - } - else - { - priv->expander_style = GTK_EXPANDER_COLLAPSED; - finish = TRUE; - } - } - - if (finish) - { - priv->animation_timeout = 0; - g_object_set (G_OBJECT (GTK_BIN (expander)->child), - "visible", priv->expanded, - NULL); - } - - return !finish; -} - -static void -e_expander_start_animation (EExpander *expander) -{ - EExpanderPrivate *priv; - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (priv->animation_timeout) - g_source_remove (priv->animation_timeout); - - priv->animation_timeout = - g_timeout_add (50, - (GSourceFunc) e_expander_animation_timeout, - expander); -} - -void -e_expander_set_expanded (EExpander *expander, - gboolean expanded) -{ - EExpanderPrivate *priv; - - g_return_if_fail (E_IS_EXPANDER (expander)); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - expanded = expanded != FALSE; - - if (priv->expanded != expanded) - { - priv->expanded = expanded; - - if (GTK_WIDGET_VISIBLE (expander)) - e_expander_start_animation (expander); - - else if (GTK_BIN (expander)->child) - { - priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED : - GTK_EXPANDER_COLLAPSED; - g_object_set (G_OBJECT (GTK_BIN (expander)->child), - "visible", priv->expanded, - NULL); - } - - gtk_widget_queue_resize (GTK_WIDGET (expander)); - - g_object_notify (G_OBJECT (expander), "expanded"); - } -} - -gboolean -e_expander_get_expanded (EExpander *expander) -{ - g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE); - - return E_EXPANDER_GET_PRIVATE (expander)->expanded; -} - -void -e_expander_set_spacing (EExpander *expander, - gint spacing) -{ - EExpanderPrivate *priv; - - g_return_if_fail (E_IS_EXPANDER (expander)); - g_return_if_fail (spacing >= 0); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (priv->spacing != spacing) - { - priv->spacing = spacing; - - gtk_widget_queue_resize (GTK_WIDGET (expander)); - - g_object_notify (G_OBJECT (expander), "spacing"); - } -} - -gint -e_expander_get_spacing (EExpander *expander) -{ - g_return_val_if_fail (E_IS_EXPANDER (expander), 0); - - return E_EXPANDER_GET_PRIVATE (expander)->spacing; -} - -void -e_expander_set_label (EExpander *expander, - const gchar *label) -{ - g_return_if_fail (E_IS_EXPANDER (expander)); - - if (!label) - { - e_expander_set_label_widget (expander, NULL); - } - else - { - GtkWidget *child; - - child = gtk_label_new (label); - gtk_label_set_use_underline (GTK_LABEL (child), - E_EXPANDER_GET_PRIVATE (expander)->use_underline); - gtk_widget_show (child); - - e_expander_set_label_widget (expander, child); - } - - g_object_notify (G_OBJECT (expander), "label"); -} - -/** - * e_expander_get_label: - * @expander: a #EExpander - * - * If the expander's label widget is a #GtkLabel, return the - * text in the label widget. (The frame will have a #GtkLabel - * for the label widget if a non-%NULL argument was passed - * to e_expander_new().) - * - * Return value: the text in the label, or %NULL if there - * was no label widget or the lable widget was not - * a #GtkLabel. This string is owned by GTK+ and - * must not be modified or freed. - **/ -G_CONST_RETURN char * -e_expander_get_label (EExpander *expander) -{ - EExpanderPrivate *priv; - - g_return_val_if_fail (E_IS_EXPANDER (expander), NULL); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (priv->label_widget && GTK_IS_LABEL (priv->label_widget)) - return gtk_label_get_text (GTK_LABEL (priv->label_widget)); - else - return NULL; -} - -void -e_expander_set_use_underline (EExpander *expander, - gboolean use_underline) -{ - EExpanderPrivate *priv; - - g_return_if_fail (E_IS_EXPANDER (expander)); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - use_underline = use_underline != FALSE; - - if (priv->use_underline != use_underline) - { - priv->use_underline = use_underline; - - if (priv->label_widget && GTK_IS_LABEL (priv->label_widget)) - gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline); - - g_object_notify (G_OBJECT (expander), "use_underline"); - } -} - -gboolean -e_expander_get_use_underline (EExpander *expander) -{ - g_return_val_if_fail (E_IS_EXPANDER (expander), FALSE); - - return E_EXPANDER_GET_PRIVATE (expander)->use_underline; -} - -/** - * e_expander_set_label_widget: - * @expander: a #EExpander - * @label_widget: the new label widget - * - * Set the label widget for the expander. This is the widget - * that will appear embedded alongside the expander arrow. - **/ -void -e_expander_set_label_widget (EExpander *expander, - GtkWidget *label_widget) -{ - EExpanderPrivate *priv; - gboolean need_resize = FALSE; - - g_return_if_fail (E_IS_EXPANDER (expander)); - g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget)); - g_return_if_fail (label_widget == NULL || label_widget->parent == NULL); - - priv = E_EXPANDER_GET_PRIVATE (expander); - - if (priv->label_widget == label_widget) - return; - - if (priv->label_widget) - { - need_resize = GTK_WIDGET_VISIBLE (priv->label_widget); - gtk_widget_unparent (priv->label_widget); - } - - priv->label_widget = label_widget; - - if (label_widget) - { - priv->label_widget = label_widget; - gtk_widget_set_parent (label_widget, GTK_WIDGET (expander)); - need_resize |= GTK_WIDGET_VISIBLE (label_widget); - } - - if (GTK_WIDGET_VISIBLE (expander) && need_resize) - gtk_widget_queue_resize (GTK_WIDGET (expander)); - - g_object_notify (G_OBJECT (expander), "label_widget"); -} - -/** - * e_expander_get_label_widget: - * @expander: a #EExpander - * - * Retrieves the label widget for the frame. See - * e_expander_set_label_widget(). - * - * Return value: the label widget, or %NULL if there is none. - **/ -GtkWidget * -e_expander_get_label_widget (EExpander *expander) -{ - g_return_val_if_fail (E_IS_EXPANDER (expander), NULL); - - return E_EXPANDER_GET_PRIVATE (expander)->label_widget; -} diff --git a/widgets/misc/e-expander.h b/widgets/misc/e-expander.h deleted file mode 100644 index 6ddb68087e..0000000000 --- a/widgets/misc/e-expander.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see - * - * - * Authors: - * Mark McLoughlin - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * Copyright (C) 2003 Sun Microsystems, Inc. - * - */ - -#ifndef _E_EXPANDER_H_ -#define _E_EXPANDER_H_ - -#include - -G_BEGIN_DECLS - -#define E_TYPE_EXPANDER (e_expander_get_type ()) -#define E_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_EXPANDER, EExpander)) -#define E_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_EXPANDER, EExpanderClass)) -#define E_IS_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_EXPANDER)) -#define E_IS_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_EXPANDER)) -#define E_EXPANDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_EXPANDER, EExpanderClass)) -/* ESTUFF #define E_EXPANDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_EXPANDER, EExpanderPrivate)) */ - -typedef struct _EExpander EExpander; -typedef struct _EExpanderClass EExpanderClass; - -struct _EExpander -{ - GtkBin bin; -}; - -struct _EExpanderClass -{ - GtkBinClass parent_class; - - void (* activate) (EExpander *expander); -}; - -GType e_expander_get_type (void); - -GtkWidget *e_expander_new (const gchar *label); -GtkWidget *e_expander_new_with_mnemonic (const gchar *label); - -void e_expander_set_expanded (EExpander *expander, - gboolean expanded); -gboolean e_expander_get_expanded (EExpander *expander); - -/* Spacing between the expander/label and the child */ -void e_expander_set_spacing (EExpander *expander, - gint spacing); -gint e_expander_get_spacing (EExpander *expander); - -void e_expander_set_label (EExpander *expander, - const gchar *label); -G_CONST_RETURN gchar *e_expander_get_label (EExpander *expander); - -void e_expander_set_use_underline (EExpander *expander, - gboolean use_underline); -gboolean e_expander_get_use_underline (EExpander *expander); - -void e_expander_set_label_widget (EExpander *expander, - GtkWidget *label_widget); -GtkWidget *e_expander_get_label_widget (EExpander *expander); - -G_END_DECLS - -#endif /* _E_EXPANDER_H_ */ diff --git a/widgets/text/Makefile.am b/widgets/text/Makefile.am index df2b02c781..565ec4e521 100644 --- a/widgets/text/Makefile.am +++ b/widgets/text/Makefile.am @@ -5,6 +5,7 @@ endif INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/widgets \ + $(E_UTIL_CFLAGS) \ $(GNOME_PLATFORM_CFLAGS) \ -DG_LOG_DOMAIN=\"e-text\" @@ -30,5 +31,6 @@ libetext_la_LIBADD = \ $(top_builddir)/e-util/libeutil.la \ $(top_builddir)/a11y/libevolution-a11y.la \ $(top_builddir)/widgets/table/libetable.la \ + $(E_UTIL_LIBS) \ $(GNOME_PLATFORM_LIBS) \ $(REGEX_LIBS) -- cgit v1.2.3 From de003c135ac993e323edcbd97f74aa28c43601f1 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 27 Apr 2009 20:27:02 -0400 Subject: Use consistent variable names for GtkUIManager --- calendar/gui/dialogs/comp-editor.c | 34 +++++++------- calendar/gui/dialogs/event-editor.c | 8 ++-- calendar/gui/dialogs/memo-editor.c | 8 ++-- calendar/gui/dialogs/task-editor.c | 8 ++-- composer/e-composer-actions.c | 8 ++-- composer/e-composer-private.c | 28 ++++++------ composer/e-msg-composer.c | 6 +-- e-util/e-plugin-ui.c | 56 ++++++++++++----------- e-util/e-plugin-ui.h | 6 +-- mail/mail-signature-editor.c | 10 ++-- plugins/email-custom-header/email-custom-header.c | 4 +- plugins/face/face.c | 4 +- plugins/templates/templates.c | 4 +- 13 files changed, 93 insertions(+), 91 deletions(-) (limited to 'composer') diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 6456a5ce04..5d842d673a 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -98,7 +98,7 @@ struct _CompEditorPrivate { GtkWidget *attachment_view; /* Manages menus and toolbars */ - GtkUIManager *manager; + GtkUIManager *ui_manager; gchar *summary; @@ -1150,7 +1150,7 @@ comp_editor_setup_recent_menu (CompEditor *editor) const gchar *path; guint merge_id; - ui_manager = editor->priv->manager; + ui_manager = editor->priv->ui_manager; view = E_ATTACHMENT_VIEW (editor->priv->attachment_view); action_group = comp_editor_get_action_group (editor, "individual"); merge_id = gtk_ui_manager_new_merge_id (ui_manager); @@ -1282,9 +1282,9 @@ comp_editor_dispose (GObject *object) priv->comp = NULL; } - if (priv->manager != NULL) { - g_object_unref (priv->manager); - priv->manager = NULL; + if (priv->ui_manager != NULL) { + g_object_unref (priv->ui_manager); + priv->ui_manager = NULL; } /* Chain up to parent's dispose() method. */ @@ -1534,11 +1534,11 @@ comp_editor_init (CompEditor *editor) priv->warned = FALSE; priv->is_group_item = FALSE; - priv->manager = gtk_ui_manager_new (); + priv->ui_manager = gtk_ui_manager_new (); gtk_window_add_accel_group ( GTK_WINDOW (editor), - gtk_ui_manager_get_accel_group (priv->manager)); + gtk_ui_manager_get_accel_group (priv->ui_manager)); /* Setup Action Groups */ @@ -1549,7 +1549,7 @@ comp_editor_init (CompEditor *editor) action_group, core_entries, G_N_ELEMENTS (core_entries), editor); gtk_ui_manager_insert_action_group ( - priv->manager, action_group, 0); + priv->ui_manager, action_group, 0); g_object_unref (action_group); action_group = gtk_action_group_new ("individual"); @@ -1567,7 +1567,7 @@ comp_editor_init (CompEditor *editor) E_CAL_COMPONENT_CLASS_PUBLIC, G_CALLBACK (action_classification_cb), editor); gtk_ui_manager_insert_action_group ( - priv->manager, action_group, 0); + priv->ui_manager, action_group, 0); g_object_unref (action_group); action_group = gtk_action_group_new ("coordinated"); @@ -1577,7 +1577,7 @@ comp_editor_init (CompEditor *editor) action_group, coordinated_toggle_entries, G_N_ELEMENTS (coordinated_toggle_entries), editor); gtk_ui_manager_insert_action_group ( - priv->manager, action_group, 0); + priv->ui_manager, action_group, 0); g_object_unref (action_group); /* Fine Tuning */ @@ -1589,7 +1589,7 @@ comp_editor_init (CompEditor *editor) action = comp_editor_get_action (editor, "save"); gtk_action_set_sensitive (action, FALSE); - gtk_ui_manager_add_ui_from_string (priv->manager, ui, -1, &error); + gtk_ui_manager_add_ui_from_string (priv->ui_manager, ui, -1, &error); if (error != NULL) { g_warning ("%s: %s", G_STRFUNC, error->message); g_error_free (error); @@ -1940,7 +1940,7 @@ comp_editor_get_ui_manager (CompEditor *editor) { g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL); - return editor->priv->manager; + return editor->priv->ui_manager; } GtkAction * @@ -1953,7 +1953,7 @@ comp_editor_get_action (CompEditor *editor, g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL); g_return_val_if_fail (action_name != NULL, NULL); - iter = gtk_ui_manager_get_action_groups (editor->priv->manager); + iter = gtk_ui_manager_get_action_groups (editor->priv->ui_manager); while (iter != NULL && action == NULL) { GtkActionGroup *action_group = iter->data; @@ -1975,7 +1975,7 @@ comp_editor_get_action_group (CompEditor *editor, g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL); g_return_val_if_fail (group_name != NULL, NULL); - iter = gtk_ui_manager_get_action_groups (editor->priv->manager); + iter = gtk_ui_manager_get_action_groups (editor->priv->ui_manager); while (iter != NULL) { GtkActionGroup *action_group = iter->data; const gchar *name; @@ -1993,14 +1993,14 @@ GtkWidget * comp_editor_get_managed_widget (CompEditor *editor, const gchar *widget_path) { - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkWidget *widget; g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL); g_return_val_if_fail (widget_path != NULL, NULL); - manager = comp_editor_get_ui_manager (editor); - widget = gtk_ui_manager_get_widget (manager, widget_path); + ui_manager = comp_editor_get_ui_manager (editor); + widget = gtk_ui_manager_get_widget (ui_manager, widget_path); g_return_val_if_fail (widget != NULL, NULL); return widget; diff --git a/calendar/gui/dialogs/event-editor.c b/calendar/gui/dialogs/event-editor.c index f32f24501d..7755894f6c 100644 --- a/calendar/gui/dialogs/event-editor.c +++ b/calendar/gui/dialogs/event-editor.c @@ -463,7 +463,7 @@ static void event_editor_init (EventEditor *ee) { CompEditor *editor = COMP_EDITOR (ee); - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkActionGroup *action_group; GtkAction *action; GError *error = NULL; @@ -486,9 +486,9 @@ event_editor_init (EventEditor *ee) action_group, meeting_entries, G_N_ELEMENTS (meeting_entries), ee); - manager = comp_editor_get_ui_manager (editor); - gtk_ui_manager_add_ui_from_string (manager, ui, -1, &error); - e_plugin_ui_register_manager ("event-editor", manager, ee); + ui_manager = comp_editor_get_ui_manager (editor); + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + e_plugin_ui_register_manager ("event-editor", ui_manager, ee); if (error != NULL) { g_critical ("%s: %s", G_STRFUNC, error->message); diff --git a/calendar/gui/dialogs/memo-editor.c b/calendar/gui/dialogs/memo-editor.c index 4fbf35d916..b90bd6fb3c 100644 --- a/calendar/gui/dialogs/memo-editor.c +++ b/calendar/gui/dialogs/memo-editor.c @@ -134,15 +134,15 @@ static void memo_editor_init (MemoEditor *me) { CompEditor *editor = COMP_EDITOR (me); - GtkUIManager *manager; + GtkUIManager *ui_manager; GError *error = NULL; me->priv = MEMO_EDITOR_GET_PRIVATE (me); me->priv->updating = FALSE; - manager = comp_editor_get_ui_manager (editor); - gtk_ui_manager_add_ui_from_string (manager, ui, -1, &error); - e_plugin_ui_register_manager ("memo-editor", manager, me); + ui_manager = comp_editor_get_ui_manager (editor); + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + e_plugin_ui_register_manager ("memo-editor", ui_manager, me); if (error != NULL) { g_critical ("%s: %s", G_STRFUNC, error->message); diff --git a/calendar/gui/dialogs/task-editor.c b/calendar/gui/dialogs/task-editor.c index 4b8f8698b9..eef1d64468 100644 --- a/calendar/gui/dialogs/task-editor.c +++ b/calendar/gui/dialogs/task-editor.c @@ -302,7 +302,7 @@ static void task_editor_init (TaskEditor *te) { CompEditor *editor = COMP_EDITOR (te); - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkActionGroup *action_group; GError *error = NULL; @@ -344,9 +344,9 @@ task_editor_init (TaskEditor *te) action_group, assigned_task_entries, G_N_ELEMENTS (assigned_task_entries), te); - manager = comp_editor_get_ui_manager (editor); - gtk_ui_manager_add_ui_from_string (manager, ui, -1, &error); - e_plugin_ui_register_manager ("task-editor", manager, te); + ui_manager = comp_editor_get_ui_manager (editor); + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + e_plugin_ui_register_manager ("task-editor", ui_manager, te); if (error != NULL) { g_critical ("%s: %s", G_STRFUNC, error->message); diff --git a/composer/e-composer-actions.c b/composer/e-composer-actions.c index e46aba4192..56ec7c5db1 100644 --- a/composer/e-composer-actions.c +++ b/composer/e-composer-actions.c @@ -606,12 +606,12 @@ void e_composer_actions_init (EMsgComposer *composer) { GtkActionGroup *action_group; - GtkUIManager *manager; + GtkUIManager *ui_manager; gboolean visible; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); - manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); + ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); /* Composer Actions */ action_group = composer->priv->composer_actions; @@ -623,7 +623,7 @@ e_composer_actions_init (EMsgComposer *composer) gtk_action_group_add_toggle_actions ( action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), composer); - gtk_ui_manager_insert_action_group (manager, action_group, 0); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); /* Character Set Actions */ action_group = composer->priv->charset_actions; @@ -632,7 +632,7 @@ e_composer_actions_init (EMsgComposer *composer) e_charset_add_radio_actions ( action_group, composer->priv->charset, G_CALLBACK (action_charset_cb), composer); - gtk_ui_manager_insert_action_group (manager, action_group, 0); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); /* Fine Tuning */ diff --git a/composer/e-composer-private.c b/composer/e-composer-private.c index ab1e092513..1729aae9fa 100644 --- a/composer/e-composer-private.c +++ b/composer/e-composer-private.c @@ -21,21 +21,21 @@ static void composer_setup_charset_menu (EMsgComposer *composer) { - GtkUIManager *manager; + GtkUIManager *ui_manager; const gchar *path; GList *list; guint merge_id; - manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); + ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); list = gtk_action_group_list_actions (composer->priv->charset_actions); path = "/main-menu/edit-menu/pre-spell-check/charset-menu"; - merge_id = gtk_ui_manager_new_merge_id (manager); + merge_id = gtk_ui_manager_new_merge_id (ui_manager); while (list != NULL) { GtkAction *action = list->data; gtk_ui_manager_add_ui ( - manager, merge_id, path, + ui_manager, merge_id, path, gtk_action_get_name (action), gtk_action_get_name (action), GTK_UI_MANAGER_AUTO, FALSE); @@ -43,23 +43,23 @@ composer_setup_charset_menu (EMsgComposer *composer) list = g_list_delete_link (list, list); } - gtk_ui_manager_ensure_update (manager); + gtk_ui_manager_ensure_update (ui_manager); } static void composer_setup_recent_menu (EMsgComposer *composer) { EAttachmentView *view; - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkAction *action; const gchar *action_name; const gchar *path; guint merge_id; view = e_msg_composer_get_attachment_view (composer); - manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); + ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (composer)); path = "/main-menu/insert-menu/insert-menu-top/recent-placeholder"; - merge_id = gtk_ui_manager_new_merge_id (manager); + merge_id = gtk_ui_manager_new_merge_id (ui_manager); action_name = "recent-menu"; action = e_attachment_view_recent_action_new ( @@ -70,12 +70,12 @@ composer_setup_recent_menu (EMsgComposer *composer) composer->priv->composer_actions, action); gtk_ui_manager_add_ui ( - manager, merge_id, path, + ui_manager, merge_id, path, action_name, action_name, GTK_UI_MANAGER_AUTO, FALSE); } - gtk_ui_manager_ensure_update (manager); + gtk_ui_manager_ensure_update (ui_manager); } void @@ -84,7 +84,7 @@ e_composer_private_init (EMsgComposer *composer) EMsgComposerPrivate *priv = composer->priv; GtkhtmlEditor *editor; - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkWidget *widget; GtkWidget *container; GtkWidget *send_widget; @@ -93,7 +93,7 @@ e_composer_private_init (EMsgComposer *composer) GError *error = NULL; editor = GTKHTML_EDITOR (composer); - manager = gtkhtml_editor_get_ui_manager (editor); + ui_manager = gtkhtml_editor_get_ui_manager (editor); priv->charset_actions = gtk_action_group_new ("charset"); priv->composer_actions = gtk_action_group_new ("composer"); @@ -119,12 +119,12 @@ e_composer_private_init (EMsgComposer *composer) e_composer_actions_init (composer); filename = e_composer_find_data_file ("evolution-composer.ui"); - gtk_ui_manager_add_ui_from_file (manager, filename, &error); + gtk_ui_manager_add_ui_from_file (ui_manager, filename, &error); g_free (filename); /* We set the send button as important to have a label */ path = "/main-toolbar/pre-main-toolbar/send"; - send_widget = gtk_ui_manager_get_widget (manager, path); + send_widget = gtk_ui_manager_get_widget (ui_manager, path); gtk_tool_item_set_is_important (GTK_TOOL_ITEM (send_widget), TRUE); composer_setup_charset_menu (composer); diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index a2777294c6..3195255a52 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -2468,7 +2468,7 @@ msg_composer_init (EMsgComposer *composer) GdkDragAction drag_actions; GtkTargetList *target_list; GtkTargetEntry *targets; - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkhtmlEditor *editor; GtkHTML *html; gint n_targets; @@ -2479,7 +2479,7 @@ msg_composer_init (EMsgComposer *composer) editor = GTKHTML_EDITOR (composer); html = gtkhtml_editor_get_html (editor); - manager = gtkhtml_editor_get_ui_manager (editor); + ui_manager = gtkhtml_editor_get_ui_manager (editor); view = e_msg_composer_get_attachment_view (composer); all_composers = g_slist_prepend (all_composers, composer); table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table); @@ -2560,7 +2560,7 @@ msg_composer_init (EMsgComposer *composer) gtkhtml_editor_set_changed (editor, FALSE); e_plugin_ui_register_manager ( - "org.gnome.evolution.composer", manager, composer); + "org.gnome.evolution.composer", ui_manager, composer); } GType diff --git a/e-util/e-plugin-ui.c b/e-util/e-plugin-ui.c index c192ece939..c3ee13fe60 100644 --- a/e-util/e-plugin-ui.c +++ b/e-util/e-plugin-ui.c @@ -62,7 +62,7 @@ static gpointer parent_class; static void plugin_ui_registry_remove (EPluginUIHook *hook, - GtkUIManager *manager) + GtkUIManager *ui_manager) { GHashTable *hash_table; @@ -71,14 +71,14 @@ plugin_ui_registry_remove (EPluginUIHook *hook, hash_table = g_hash_table_lookup (registry, hook); g_return_if_fail (hash_table != NULL); - g_hash_table_remove (hash_table, manager); + g_hash_table_remove (hash_table, ui_manager); if (g_hash_table_size (hash_table) == 0) g_hash_table_remove (registry, hook); } static void plugin_ui_registry_insert (EPluginUIHook *hook, - GtkUIManager *manager, + GtkUIManager *ui_manager, guint merge_id) { GHashTable *hash_table; @@ -90,15 +90,16 @@ plugin_ui_registry_insert (EPluginUIHook *hook, } g_object_weak_ref ( - G_OBJECT (manager), (GWeakNotify) + G_OBJECT (ui_manager), (GWeakNotify) plugin_ui_registry_remove, hook); - g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id)); + g_hash_table_insert ( + hash_table, ui_manager, GUINT_TO_POINTER (merge_id)); } /* Helper for plugin_ui_hook_merge_ui() */ static void -plugin_ui_hook_merge_foreach (GtkUIManager *manager, +plugin_ui_hook_merge_foreach (GtkUIManager *ui_manager, const gchar *ui_definition, GHashTable *hash_table) { @@ -107,15 +108,16 @@ plugin_ui_hook_merge_foreach (GtkUIManager *manager, /* Merge the UI definition into the manager. */ merge_id = gtk_ui_manager_add_ui_from_string ( - manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (manager); + ui_manager, ui_definition, -1, &error); + gtk_ui_manager_ensure_update (ui_manager); if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } /* Merge ID will be 0 on error, which is what we want. */ - g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id)); + g_hash_table_insert ( + hash_table, ui_manager, GUINT_TO_POINTER (merge_id)); } static void @@ -137,14 +139,14 @@ plugin_ui_hook_merge_ui (EPluginUIHook *hook) intermediate = g_hash_table_new (g_direct_hash, g_direct_equal); while (keys != NULL) { - GtkUIManager *manager = keys->data; + GtkUIManager *ui_manager = keys->data; gchar *ui_definition; ui_definition = g_hash_table_lookup ( hook->priv->ui_definitions, - e_plugin_ui_get_manager_id (manager)); + e_plugin_ui_get_manager_id (ui_manager)); - g_hash_table_insert (intermediate, manager, ui_definition); + g_hash_table_insert (intermediate, ui_manager, ui_definition); keys = g_list_delete_link (keys, keys); } @@ -162,16 +164,16 @@ plugin_ui_hook_merge_ui (EPluginUIHook *hook) /* Helper for plugin_ui_hook_unmerge_ui() */ static void -plugin_ui_hook_unmerge_foreach (GtkUIManager *manager, +plugin_ui_hook_unmerge_foreach (GtkUIManager *ui_manager, gpointer value, GHashTable *hash_table) { guint merge_id; merge_id = GPOINTER_TO_UINT (value); - gtk_ui_manager_remove_ui (manager, merge_id); + gtk_ui_manager_remove_ui (ui_manager, merge_id); - g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (0)); + g_hash_table_insert (hash_table, ui_manager, GUINT_TO_POINTER (0)); } static void @@ -195,7 +197,7 @@ plugin_ui_hook_unmerge_ui (EPluginUIHook *hook) static void plugin_ui_hook_register_manager (EPluginUIHook *hook, - GtkUIManager *manager, + GtkUIManager *ui_manager, const gchar *ui_definition, gpointer user_data) { @@ -210,7 +212,7 @@ plugin_ui_hook_register_manager (EPluginUIHook *hook, * function (if it defined one). The plugin should install whatever * GtkActions and GtkActionGroups are neccessary to implement the * action names in its UI definition. */ - if (func != NULL && !func (manager, user_data)) + if (func != NULL && !func (ui_manager, user_data)) return; if (plugin->enabled) { @@ -218,8 +220,8 @@ plugin_ui_hook_register_manager (EPluginUIHook *hook, /* Merge the UI definition into the manager. */ merge_id = gtk_ui_manager_add_ui_from_string ( - manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (manager); + ui_manager, ui_definition, -1, &error); + gtk_ui_manager_ensure_update (ui_manager); if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); @@ -227,7 +229,7 @@ plugin_ui_hook_register_manager (EPluginUIHook *hook, } /* Save merge ID's for later use. */ - plugin_ui_registry_insert (hook, manager, merge_id); + plugin_ui_registry_insert (hook, ui_manager, merge_id); } static void @@ -368,16 +370,16 @@ e_plugin_ui_hook_get_type (void) void e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *manager, + GtkUIManager *ui_manager, gpointer user_data) { const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; GSList *plugin_list; g_return_if_fail (id != NULL); - g_return_if_fail (GTK_IS_UI_MANAGER (manager)); + g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); - g_object_set_data (G_OBJECT (manager), key, (gpointer) id); + g_object_set_data (G_OBJECT (ui_manager), key, (gpointer) id); /* Loop over all installed plugins. */ plugin_list = e_plugin_list_plugins (); @@ -402,7 +404,7 @@ e_plugin_ui_register_manager (const gchar *id, /* Register the manager with the hook. */ plugin_ui_hook_register_manager ( - hook, manager, ui_definition, user_data); + hook, ui_manager, ui_definition, user_data); } plugin_list = g_slist_next (plugin_list); @@ -410,11 +412,11 @@ e_plugin_ui_register_manager (const gchar *id, } const gchar * -e_plugin_ui_get_manager_id (GtkUIManager *manager) +e_plugin_ui_get_manager_id (GtkUIManager *ui_manager) { const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; - g_return_val_if_fail (GTK_IS_UI_MANAGER (manager), NULL); + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); - return g_object_get_data (G_OBJECT (manager), key); + return g_object_get_data (G_OBJECT (ui_manager), key); } diff --git a/e-util/e-plugin-ui.h b/e-util/e-plugin-ui.h index 00e6ed5fcf..b8e795c4c4 100644 --- a/e-util/e-plugin-ui.h +++ b/e-util/e-plugin-ui.h @@ -57,15 +57,15 @@ struct _EPluginUIHookClass { /* Plugins with "org.gnome.evolution.ui" hooks should define a * function named e_plugin_ui_init() having this signature. */ -typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *manager, +typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *ui_manager, gpointer user_data); GType e_plugin_ui_hook_get_type (void); void e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *manager, + GtkUIManager *ui_manager, gpointer user_data); -const gchar * e_plugin_ui_get_manager_id (GtkUIManager *manager); +const gchar * e_plugin_ui_get_manager_id (GtkUIManager *ui_manager); G_END_DECLS diff --git a/mail/mail-signature-editor.c b/mail/mail-signature-editor.c index 912182f5ac..daee1db92c 100644 --- a/mail/mail-signature-editor.c +++ b/mail/mail-signature-editor.c @@ -327,7 +327,7 @@ static void signature_editor_init (ESignatureEditor *editor) { GtkActionGroup *action_group; - GtkUIManager *manager; + GtkUIManager *ui_manager; GtkWidget *container; GtkWidget *widget; GtkWidget *vbox; @@ -336,9 +336,9 @@ signature_editor_init (ESignatureEditor *editor) editor->priv = E_SIGNATURE_EDITOR_GET_PRIVATE (editor); vbox = GTKHTML_EDITOR (editor)->vbox; - manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor)); + ui_manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor)); - gtk_ui_manager_add_ui_from_string (manager, ui, -1, &error); + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); handle_error (&error); action_group = gtk_action_group_new ("signature"); @@ -347,10 +347,10 @@ signature_editor_init (ESignatureEditor *editor) gtk_action_group_add_actions ( action_group, entries, G_N_ELEMENTS (entries), editor); - gtk_ui_manager_insert_action_group (manager, action_group, 0); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); editor->priv->action_group = g_object_ref (action_group); - gtk_ui_manager_ensure_update (manager); + gtk_ui_manager_ensure_update (ui_manager); gtk_window_set_title (GTK_WINDOW (editor), _("Edit Signature")); diff --git a/plugins/email-custom-header/email-custom-header.c b/plugins/email-custom-header/email-custom-header.c index 994af730b6..fe1a73febb 100644 --- a/plugins/email-custom-header/email-custom-header.c +++ b/plugins/email-custom-header/email-custom-header.c @@ -83,7 +83,7 @@ static gint epech_check_existing_composer_window(gconstpointer a, gconstpointer static void commit_changes (ConfigData *cd); int e_plugin_lib_enable (EPluginLib *ep, int enable); GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); -gboolean e_plugin_ui_init(GtkUIManager *manager, EMsgComposer *composer); +gboolean e_plugin_ui_init(GtkUIManager *ui_manager, EMsgComposer *composer); GtkWidget *org_gnome_email_custom_header_config_option (struct _EPlugin *epl, struct _EConfigHookItemFactoryData *data); int @@ -589,7 +589,7 @@ static GtkActionEntry entries[] = { }; gboolean -e_plugin_ui_init (GtkUIManager *manager, +e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer) { GtkhtmlEditor *editor; diff --git a/plugins/face/face.c b/plugins/face/face.c index ba683e91aa..ca3af16ab4 100644 --- a/plugins/face/face.c +++ b/plugins/face/face.c @@ -34,7 +34,7 @@ #define d(x) -gboolean e_plugin_ui_init (GtkUIManager *manager, +gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer); static void @@ -130,7 +130,7 @@ static GtkActionEntry entries[] = { }; gboolean -e_plugin_ui_init (GtkUIManager *manager, +e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer) { GtkhtmlEditor *editor; diff --git a/plugins/templates/templates.c b/plugins/templates/templates.c index 8996c7f8c1..eae87721c4 100644 --- a/plugins/templates/templates.c +++ b/plugins/templates/templates.c @@ -88,7 +88,7 @@ void org_gnome_templates_popup (EPlugin *ep, EMPopupTargetSelect *t); GtkWidget *e_plugin_lib_get_configure_widget (EPlugin *epl); -gboolean e_plugin_ui_init (GtkUIManager *manager, EMsgComposer *composer); +gboolean e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer); /* Thanks to attachment reminder plugin for this*/ @@ -715,7 +715,7 @@ static GtkActionEntry entries[] = { }; gboolean -e_plugin_ui_init (GtkUIManager *manager, +e_plugin_ui_init (GtkUIManager *ui_manager, EMsgComposer *composer) { GtkhtmlEditor *editor; -- cgit v1.2.3