From 6e163b39c75dbba470d073b4f79a897aa6fb0e54 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 24 Mar 2009 02:05:26 +0000 Subject: Saving progress again on the attachment rewrite. svn path=/branches/kill-bonobo/; revision=37470 --- calendar/gui/dialogs/comp-editor.c | 39 +- composer/e-msg-composer.c | 8 +- mail/Makefile.am | 2 + mail/e-mail-attachment-bar.c | 656 ++++++++++++++++++++++++++++++++++ mail/e-mail-attachment-bar.h | 77 ++++ mail/em-format-html-display.c | 235 ++---------- mail/em-format-html.c | 4 - widgets/misc/e-activity.c | 36 +- widgets/misc/e-attachment-dialog.c | 25 +- widgets/misc/e-attachment-icon-view.c | 70 +++- widgets/misc/e-attachment-paned.c | 176 ++++++++- widgets/misc/e-attachment-paned.h | 3 - widgets/misc/e-attachment-store.c | 170 +++------ widgets/misc/e-attachment-store.h | 9 +- widgets/misc/e-attachment-tree-view.c | 50 ++- widgets/misc/e-attachment-view.c | 148 +++++++- widgets/misc/e-attachment-view.h | 5 + widgets/misc/e-attachment.c | 479 ++++++++++++++++++++++--- widgets/misc/e-attachment.h | 18 + 19 files changed, 1769 insertions(+), 441 deletions(-) create mode 100644 mail/e-mail-attachment-bar.c create mode 100644 mail/e-mail-attachment-bar.h diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index e3b1bac053..7e51411002 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -63,6 +63,7 @@ #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-util/e-error.h" @@ -233,11 +234,9 @@ drag_data_received (CompEditor *editor, guint info, guint time) { - EAttachmentPaned *paned; EAttachmentView *view; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); e_attachment_view_drag_data_received ( view, context, x, y, selection, info, time); @@ -250,11 +249,9 @@ drag_motion (CompEditor *editor, gint y, guint time) { - EAttachmentPaned *paned; EAttachmentView *view; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); return e_attachment_view_drag_motion (view, context, x, y, time); } @@ -262,7 +259,6 @@ drag_motion (CompEditor *editor, static GSList * get_attachment_list (CompEditor *editor) { - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; GtkTreeModel *model; @@ -275,8 +271,7 @@ get_attachment_list (CompEditor *editor) e_cal_component_get_uid (editor->priv->comp, &comp_uid); - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); store = e_attachment_view_get_store (view); model = GTK_TREE_MODEL (store); @@ -681,12 +676,10 @@ static void action_attach_cb (GtkAction *action, CompEditor *editor) { - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); store = e_attachment_view_get_store (view); e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor)); @@ -815,7 +808,6 @@ action_save_cb (GtkAction *action, CompEditor *editor) { CompEditorPrivate *priv = editor->priv; - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; ECalComponentText text; @@ -823,11 +815,10 @@ action_save_cb (GtkAction *action, gboolean read_only, correct = FALSE; ECalComponent *comp; - paned = E_ATTACHMENT_PANED (priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (priv->attachment_paned); store = e_attachment_view_get_store (view); - if (e_attachment_store_get_num_downloading (store) > 0) { + if (e_attachment_store_get_num_loading (store) > 0) { gboolean response = 1; /*FIXME: Cannot use mail functions from calendar!!!! */ #if 0 @@ -1504,7 +1495,6 @@ static void comp_editor_init (CompEditor *editor) { CompEditorPrivate *priv; - EAttachmentPaned *paned; EAttachmentView *view; GtkActionGroup *action_group; GtkAction *action; @@ -1626,8 +1616,7 @@ comp_editor_init (CompEditor *editor) /* Add a GtkRecentAction to the "individual" action group. */ action_group = comp_editor_get_action_group (editor, "individual"); - paned = E_ATTACHMENT_PANED (priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (priv->attachment_paned); action = e_attachment_view_recent_action_new ( view, "attach-recent", _("Recent _Documents")); gtk_action_group_add_action (action_group, action); @@ -2251,13 +2240,11 @@ comp_editor_get_client (CompEditor *editor) static void set_attachment_list (CompEditor *editor, GSList *attach_list) { - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; GSList *iter = NULL; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); store = e_attachment_view_get_store (view); if (e_attachment_store_get_num_attachments (store) > 0) { @@ -2281,14 +2268,12 @@ set_attachment_list (CompEditor *editor, GSList *attach_list) static void fill_widgets (CompEditor *editor) { - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; CompEditorPrivate *priv; GList *l; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); store = e_attachment_view_get_store (view); priv = editor->priv; @@ -2628,7 +2613,6 @@ comp_editor_close (CompEditor *editor) GSList * comp_editor_get_mime_attach_list (CompEditor *editor) { - EAttachmentPaned *paned; EAttachmentStore *store; EAttachmentView *view; GtkTreeModel *model; @@ -2637,8 +2621,7 @@ comp_editor_get_mime_attach_list (CompEditor *editor) GSList *attach_list = NULL; gboolean valid; - paned = E_ATTACHMENT_PANED (editor->priv->attachment_paned); - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (editor->priv->attachment_paned); store = e_attachment_view_get_store (view); model = GTK_TREE_MODEL (store); diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 138da07389..f77addfa58 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -3803,7 +3803,7 @@ e_msg_composer_get_message (EMsgComposer *composer, view = e_msg_composer_get_attachment_view (composer); store = e_attachment_view_get_store (view); - if (e_attachment_store_get_num_downloading (store) > 0) { + 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; @@ -4255,13 +4255,9 @@ e_msg_composer_get_header_table (EMsgComposer *composer) EAttachmentView * e_msg_composer_get_attachment_view (EMsgComposer *composer) { - EAttachmentPaned *paned; - g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL); - paned = E_ATTACHMENT_PANED (composer->priv->attachment_paned); - - return e_attachment_paned_get_view (paned); + return E_ATTACHMENT_VIEW (composer->priv->attachment_paned); } void diff --git a/mail/Makefile.am b/mail/Makefile.am index ef5b769ce4..f2b3119308 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -35,6 +35,8 @@ module_LTLIBRARIES = \ libevolution-module-mail.la libevolution_module_mail_la_SOURCES = \ + e-mail-attachment-bar.c \ + e-mail-attachment-bar.h \ e-mail-browser.c \ e-mail-browser.h \ e-mail-display.c \ diff --git a/mail/e-mail-attachment-bar.c b/mail/e-mail-attachment-bar.c new file mode 100644 index 0000000000..4424a84684 --- /dev/null +++ b/mail/e-mail-attachment-bar.c @@ -0,0 +1,656 @@ +/* + * e-mail-attachment-bar.c + * + * 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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-mail-attachment-bar.h" + +#include +#include "e-util/e-binding.h" +#include "e-attachment-store.h" +#include "e-attachment-icon-view.h" +#include "e-attachment-tree-view.h" + +#define E_MAIL_ATTACHMENT_BAR_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarPrivate)) + +#define NUM_VIEWS 2 + +struct _EMailAttachmentBarPrivate { + GtkTreeModel *model; + GtkWidget *vbox; + GtkWidget *expander; + GtkWidget *combo_box; + GtkWidget *icon_view; + GtkWidget *tree_view; + GtkWidget *icon_frame; + GtkWidget *tree_frame; + GtkWidget *status_icon; + GtkWidget *status_label; + + gint active_view; + guint expanded : 1; +}; + +enum { + PROP_0, + PROP_ACTIVE_VIEW, + PROP_EDITABLE, + PROP_EXPANDED +}; + +static gpointer parent_class; + +static void +mail_attachment_bar_sync_icon_view (EMailAttachmentBar *bar) +{ + EAttachmentView *source; + EAttachmentView *target; + + source = E_ATTACHMENT_VIEW (bar->priv->tree_view); + target = E_ATTACHMENT_VIEW (bar->priv->icon_view); + + /* Only sync if the tree view is active. This prevents the + * two views from endlessly trying to sync with each other. */ + if (e_mail_attachment_bar_get_active_view (bar) == 1) + e_attachment_view_sync_selection (source, target); +} + +static void +mail_attachment_bar_sync_tree_view (EMailAttachmentBar *bar) +{ + EAttachmentView *source; + EAttachmentView *target; + + source = E_ATTACHMENT_VIEW (bar->priv->icon_view); + target = E_ATTACHMENT_VIEW (bar->priv->tree_view); + + /* Only sync if the icon view is active. This prevents the + * two views from endlessly trying to sync with each other. */ + if (e_mail_attachment_bar_get_active_view (bar) == 0) + e_attachment_view_sync_selection (source, target); +} + +static void +mail_attachment_bar_update_status (EMailAttachmentBar *bar) +{ + EAttachmentView *view; + EAttachmentStore *store; + GtkExpander *expander; + GtkLabel *label; + gint num_attachments; + guint64 total_size; + gchar *display_size; + gchar *markup; + + view = E_ATTACHMENT_VIEW (bar); + store = e_attachment_view_get_store (view); + expander = GTK_EXPANDER (bar->priv->expander); + label = GTK_LABEL (bar->priv->status_label); + + num_attachments = e_attachment_store_get_num_attachments (store); + total_size = e_attachment_store_get_total_size (store); + display_size = g_format_size_for_display (total_size); + + markup = g_strdup_printf ( + "%d %s (%s)", num_attachments, ngettext ( + "Attachment", "Attachments", num_attachments), + display_size); + gtk_label_set_markup (label, markup); + g_free (markup); + + g_free (display_size); +} + +static void +mail_attachment_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVE_VIEW: + e_mail_attachment_bar_set_active_view ( + E_MAIL_ATTACHMENT_BAR (object), + g_value_get_int (value)); + return; + + case PROP_EDITABLE: + e_attachment_view_set_editable ( + E_ATTACHMENT_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_EXPANDED: + e_mail_attachment_bar_set_expanded ( + E_MAIL_ATTACHMENT_BAR (object), + g_value_get_boolean (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_attachment_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ACTIVE_VIEW: + g_value_set_int ( + value, + e_mail_attachment_bar_get_active_view ( + E_MAIL_ATTACHMENT_BAR (object))); + return; + + case PROP_EDITABLE: + g_value_set_boolean ( + value, + e_attachment_view_get_editable ( + E_ATTACHMENT_VIEW (object))); + return; + + case PROP_EXPANDED: + g_value_set_boolean ( + value, + e_mail_attachment_bar_get_expanded ( + E_MAIL_ATTACHMENT_BAR (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_attachment_bar_dispose (GObject *object) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object); + + if (priv->model != NULL) { + g_object_unref (priv->model); + priv->model = NULL; + } + + if (priv->vbox != NULL) { + g_object_unref (priv->vbox); + priv->vbox = NULL; + } + + if (priv->expander != NULL) { + g_object_unref (priv->expander); + priv->expander = NULL; + } + + if (priv->combo_box != NULL) { + g_object_unref (priv->combo_box); + priv->combo_box = NULL; + } + + if (priv->icon_view != NULL) { + g_object_unref (priv->icon_view); + priv->icon_view = NULL; + } + + if (priv->tree_view != NULL) { + g_object_unref (priv->tree_view); + priv->tree_view = NULL; + } + + if (priv->icon_frame != NULL) { + g_object_unref (priv->icon_frame); + priv->icon_frame = NULL; + } + + if (priv->tree_frame != NULL) { + g_object_unref (priv->tree_frame); + priv->tree_frame = NULL; + } + + if (priv->status_icon != NULL) { + g_object_unref (priv->status_icon); + priv->status_icon = NULL; + } + + if (priv->status_label != NULL) { + g_object_unref (priv->status_label); + priv->status_label = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +mail_attachment_bar_constructed (GObject *object) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (object); + + e_mutual_binding_new ( + G_OBJECT (object), "active-view", + G_OBJECT (priv->combo_box), "active"); + + e_mutual_binding_new ( + G_OBJECT (object), "editable", + G_OBJECT (priv->icon_view), "editable"); + + e_mutual_binding_new ( + G_OBJECT (object), "editable", + G_OBJECT (priv->tree_view), "editable"); + + e_mutual_binding_new ( + G_OBJECT (object), "expanded", + G_OBJECT (priv->expander), "expanded"); + + e_mutual_binding_new ( + G_OBJECT (object), "expanded", + G_OBJECT (priv->combo_box), "visible"); + + e_mutual_binding_new ( + G_OBJECT (object), "expanded", + G_OBJECT (priv->vbox), "visible"); +} + +static EAttachmentViewPrivate * +mail_attachment_bar_get_private (EAttachmentView *view) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_private (view); +} + +static EAttachmentStore * +mail_attachment_bar_get_store (EAttachmentView *view) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_store (view); +} + +static GtkTreePath * +mail_attachment_bar_get_path_at_pos (EAttachmentView *view, + gint x, + gint y) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_path_at_pos (view, x, y); +} + +static GList * +mail_attachment_bar_get_selected_paths (EAttachmentView *view) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_selected_paths (view); +} + +static gboolean +mail_attachment_bar_path_is_selected (EAttachmentView *view, + GtkTreePath *path) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_path_is_selected (view, path); +} + +static void +mail_attachment_bar_select_path (EAttachmentView *view, + GtkTreePath *path) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_select_path (view, path); +} + +static void +mail_attachment_bar_unselect_path (EAttachmentView *view, + GtkTreePath *path) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_unselect_path (view, path); +} + +static void +mail_attachment_bar_select_all (EAttachmentView *view) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_select_all (view); +} + +static void +mail_attachment_bar_unselect_all (EAttachmentView *view) +{ + EMailAttachmentBarPrivate *priv; + + priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_unselect_all (view); +} + +static void +mail_attachment_bar_class_init (EMailAttachmentBarClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EMailAttachmentBarPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_attachment_bar_set_property; + object_class->get_property = mail_attachment_bar_get_property; + object_class->dispose = mail_attachment_bar_dispose; + object_class->constructed = mail_attachment_bar_constructed; + + g_object_class_install_property ( + object_class, + PROP_ACTIVE_VIEW, + g_param_spec_int ( + "active-view", + "Active View", + NULL, + 0, + NUM_VIEWS, + 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_EXPANDED, + g_param_spec_boolean ( + "expanded", + "Expanded", + NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_override_property ( + object_class, PROP_EDITABLE, "editable"); +} + +static void +mail_attachment_bar_iface_init (EAttachmentViewIface *iface) +{ + iface->get_private = mail_attachment_bar_get_private; + iface->get_store = mail_attachment_bar_get_store; + iface->get_path_at_pos = mail_attachment_bar_get_path_at_pos; + iface->get_selected_paths = mail_attachment_bar_get_selected_paths; + iface->path_is_selected = mail_attachment_bar_path_is_selected; + iface->select_path = mail_attachment_bar_select_path; + iface->unselect_path = mail_attachment_bar_unselect_path; + iface->select_all = mail_attachment_bar_select_all; + iface->unselect_all = mail_attachment_bar_unselect_all; +} + +static void +mail_attachment_bar_init (EMailAttachmentBar *bar) +{ + GtkTreeSelection *selection; + GtkSizeGroup *size_group; + GtkWidget *container; + GtkWidget *widget; + + bar->priv = E_MAIL_ATTACHMENT_BAR_GET_PRIVATE (bar); + bar->priv->model = e_attachment_store_new (); + + gtk_box_set_spacing (GTK_BOX (bar), 6); + + /* Keep the expander label and save button the same height. */ + size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL); + + /* Construct the Controls */ + + container = GTK_WIDGET (bar); + + widget = gtk_hbox_new (FALSE, 6); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_expander_new (NULL); + gtk_expander_set_spacing (GTK_EXPANDER (widget), 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + bar->priv->expander = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_alignment_new (1.0, 0.5, 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_combo_box_new_text (); + gtk_size_group_add_widget (size_group, widget); + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("Icon View")); + gtk_combo_box_append_text (GTK_COMBO_BOX (widget), _("List View")); + gtk_container_add (GTK_CONTAINER (container), widget); + bar->priv->combo_box = g_object_ref (widget); + gtk_widget_show (widget); + + container = bar->priv->expander; + + widget = gtk_hbox_new (FALSE, 0); + gtk_size_group_add_widget (size_group, widget); + gtk_expander_set_label_widget (GTK_EXPANDER (container), widget); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_image_new_from_icon_name ( + "mail-attachment", GTK_ICON_SIZE_MENU); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + bar->priv->status_icon = g_object_ref (widget); + gtk_widget_show (widget); + + widget = gtk_label_new (NULL); + gtk_label_set_use_markup (GTK_LABEL (widget), TRUE); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + bar->priv->status_label = g_object_ref (widget); + gtk_widget_show (widget); + + /* Construct the Attachment Views */ + + container = GTK_WIDGET (bar); + + widget = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); + bar->priv->vbox = g_object_ref (widget); + gtk_widget_show (widget); + + container = bar->priv->vbox; + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + bar->priv->icon_frame = g_object_ref (widget); + gtk_widget_show (widget); + + container = widget; + + widget = e_attachment_icon_view_new (); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + gtk_icon_view_set_model (GTK_ICON_VIEW (widget), bar->priv->model); + gtk_container_add (GTK_CONTAINER (container), widget); + bar->priv->icon_view = g_object_ref (widget); + gtk_widget_show (widget); + + container = bar->priv->vbox; + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + bar->priv->tree_frame = g_object_ref (widget); + gtk_widget_show (widget); + + container = widget; + + widget = e_attachment_tree_view_new (); + GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); + gtk_tree_view_set_model (GTK_TREE_VIEW (widget), bar->priv->model); + gtk_container_add (GTK_CONTAINER (container), widget); + bar->priv->tree_view = g_object_ref (widget); + gtk_widget_show (widget); + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (bar->priv->tree_view)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (mail_attachment_bar_sync_icon_view), bar); + + g_signal_connect_swapped ( + bar->priv->icon_view, "selection-changed", + G_CALLBACK (mail_attachment_bar_sync_tree_view), bar); + + g_signal_connect_swapped ( + bar->priv->model, "notify::num-attachments", + G_CALLBACK (mail_attachment_bar_update_status), bar); + + g_signal_connect_swapped ( + bar->priv->model, "notify::total-size", + G_CALLBACK (mail_attachment_bar_update_status), bar); + + g_object_unref (size_group); +} + +GType +e_mail_attachment_bar_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EMailAttachmentBarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) mail_attachment_bar_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EMailAttachmentBar), + 0, /* n_preallocs */ + (GInstanceInitFunc) mail_attachment_bar_init, + NULL /* value_table */ + }; + + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) mail_attachment_bar_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL /* interface_data */ + }; + + type = g_type_register_static ( + GTK_TYPE_VBOX, "EMailAttachmentBar", &type_info, 0); + + g_type_add_interface_static ( + type, E_TYPE_ATTACHMENT_VIEW, &iface_info); + } + + return type; +} + +GtkWidget * +e_mail_attachment_bar_new (void) +{ + return g_object_new ( + E_TYPE_MAIL_ATTACHMENT_BAR, + "editable", FALSE, NULL); +} + +gint +e_mail_attachment_bar_get_active_view (EMailAttachmentBar *bar) +{ + g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), 0); + + return bar->priv->active_view; +} + +void +e_mail_attachment_bar_set_active_view (EMailAttachmentBar *bar, + gint active_view) +{ + g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar)); + g_return_if_fail (active_view >= 0 && active_view < NUM_VIEWS); + + bar->priv->active_view = active_view; + + if (active_view == 0) { + gtk_widget_show (bar->priv->icon_frame); + gtk_widget_hide (bar->priv->tree_frame); + } else { + gtk_widget_hide (bar->priv->icon_frame); + gtk_widget_show (bar->priv->tree_frame); + } + + g_object_notify (G_OBJECT (bar), "active-view"); +} + +gboolean +e_mail_attachment_bar_get_expanded (EMailAttachmentBar *bar) +{ + g_return_val_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar), FALSE); + + return bar->priv->expanded; +} + +void +e_mail_attachment_bar_set_expanded (EMailAttachmentBar *bar, + gboolean expanded) +{ + g_return_if_fail (E_IS_MAIL_ATTACHMENT_BAR (bar)); + + bar->priv->expanded = expanded; + + g_object_notify (G_OBJECT (bar), "expanded"); +} diff --git a/mail/e-mail-attachment-bar.h b/mail/e-mail-attachment-bar.h new file mode 100644 index 0000000000..e32f6e2ede --- /dev/null +++ b/mail/e-mail-attachment-bar.h @@ -0,0 +1,77 @@ +/* + * e-mail-attachment-bar.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 + * 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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_MAIL_ATTACHMENT_BAR_H +#define E_MAIL_ATTACHMENT_BAR_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_MAIL_ATTACHMENT_BAR \ + (e_mail_attachment_bar_get_type ()) +#define E_MAIL_ATTACHMENT_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBar)) +#define E_MAIL_ATTACHMENT_BAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarClass)) +#define E_IS_MAIL_ATTACHMENT_BAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_ATTACHMENT_BAR)) +#define E_IS_MAIL_ATTACHMENT_BAR_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_ATTACHMENT_BAR)) +#define E_MAIL_ATTACHMENT_BAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_ATTACHMENT_BAR, EMailAttachmentBarClass)) + +G_BEGIN_DECLS + +typedef struct _EMailAttachmentBar EMailAttachmentBar; +typedef struct _EMailAttachmentBarClass EMailAttachmentBarClass; +typedef struct _EMailAttachmentBarPrivate EMailAttachmentBarPrivate; + +struct _EMailAttachmentBar { + GtkVBox parent; + EMailAttachmentBarPrivate *priv; +}; + +struct _EMailAttachmentBarClass { + GtkVBoxClass parent_class; +}; + +GType e_mail_attachment_bar_get_type (void); +GtkWidget * e_mail_attachment_bar_new (void); +gint e_mail_attachment_bar_get_active_view + (EMailAttachmentBar *bar); +void e_mail_attachment_bar_set_active_view + (EMailAttachmentBar *bar, + gint active_view); +gboolean e_mail_attachment_bar_get_expanded + (EMailAttachmentBar *bar); +void e_mail_attachment_bar_set_expanded + (EMailAttachmentBar *bar, + gboolean expanded); + +G_END_DECLS + +#endif /* E_MAIL_ATTACHMENT_BAR_H */ diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index 242dcdceb8..7ccdc07e63 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -75,12 +75,12 @@ #include "mail-config.h" #include "e-mail-display.h" +#include "e-mail-attachment-bar.h" #include "em-format-html-display.h" #include "em-icon-stream.h" #include "em-utils.h" #include "em-popup.h" #include "widgets/misc/e-attachment-view.h" -#include "widgets/misc/e-attachment-icon-view.h" #ifdef G_OS_WIN32 /* Undefine the similar macro from ,it doesn't check if @@ -100,8 +100,7 @@ struct _EMFormatHTMLDisplayPrivate { /* for Attachment bar */ - GtkWidget *attachment_view; - GtkWidget *attachment_box; + GtkWidget *attachment_bar; GtkWidget *label; GtkWidget *save_txt; GtkWidget *arrow; @@ -150,11 +149,9 @@ static const char *smime_sign_colour[5] = { 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_button_show (GtkWidget *w, void *data); static gboolean efhd_attachment_button (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); static gboolean efhd_attachment_optional (EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *object); -static void efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd); struct _attach_puri { EMFormatPURI puri; @@ -194,7 +191,6 @@ struct _attach_puri { static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info); static void efhd_complete(EMFormat *); -gboolean efhd_mnemonic_show_bar (GtkWidget *widget, gboolean focus, GtkWidget *efhd); static void efhd_builtin_init(EMFormatHTMLDisplayClass *efhc); @@ -481,6 +477,9 @@ efhd_format_attachment (EMFormat *emf, const gchar *mime_type, const EMFormatHandler *handle) { + EMFormatHTMLDisplay *efhd; + EAttachmentView *view; + EAttachmentStore *store; char *classid, *text, *html; struct _attach_puri *info; @@ -840,8 +839,6 @@ static EMFormatHandler type_builtin_table[] = { { "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 }, - }; static void @@ -1297,7 +1294,6 @@ efhd_attachment_image(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObjec static gboolean efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) { -#if 0 /* KILL-BONOBO !! FIXME !! */ EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; EAttachment *new; struct _attach_puri *info; @@ -1320,10 +1316,15 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje return TRUE; } - if (efhd->priv->attachment_view) { + if (efhd->priv->attachment_bar) { EAttachmentView *view; EAttachmentStore *store; + view = E_ATTACHMENT_VIEW (efhd->priv->attachment_bar); + store = e_attachment_view_get_store (view); + e_attachment_store_add_attachment (store, info->attachment); + +#if 0 /* KILL-BONOBO */ file = camel_mime_part_get_filename(info->puri.part); new = info->attachment; @@ -1353,16 +1354,10 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje } else { g_hash_table_insert (efhd->priv->files, g_strdup(file), GUINT_TO_POINTER(1)); } +#endif - /* 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); + e_attachment_set_encrypted (info->attachment, info->encrypt); + e_attachment_set_signed (info->attachment, info->sign); } mainbox = gtk_hbox_new(FALSE, 0); @@ -1456,7 +1451,6 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje gtk_widget_hide(info->down); gtk_container_add((GtkContainer *)eb, mainbox); -#endif return TRUE; } @@ -1480,23 +1474,6 @@ efhd_attachment_frame(EMFormat *emf, CamelStream *stream, EMFormatPURI *puri) } } -static void -attachment_bar_arrow_clicked(GtkWidget *w, EMFormatHTMLDisplay *efhd) -{ - - efhd->priv->show_bar = !efhd->priv->show_bar; - - 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); - } -} - static void attachments_save_all_clicked (GtkWidget *widget, EMFormatHTMLDisplay *efhd) { @@ -1565,184 +1542,44 @@ static EPopupItem efhd_bar_menu_items[] = { #endif static void -efhd_attachment_bar_refresh (EMFormatHTMLDisplay *efhd) +efhd_bar_resize (EMFormatHTML *efh, + GtkAllocation *event) { - EAttachmentStore *store; - EAttachmentView *view; - guint nattachments; - - if (!efhd->priv->attachment_view) - return; - - view = E_ATTACHMENT_VIEW (efhd->priv->attachment_view); - store = e_attachment_view_get_store (view); - - nattachments = e_attachment_store_get_num_attachments (store); - - if (nattachments > 0) { - char *txt; + EMFormatHTMLDisplay *efhd; + GtkWidget *widget; + gint width; - /* 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); + efhd = EM_FORMAT_HTML_DISPLAY (efh); - /* 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")); + widget = GTK_WIDGET (efh->html); + width = widget->allocation.width - 12; - 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")); - } + if (width > 0) { + widget = efhd->priv->attachment_bar; + gtk_widget_set_size_request (widget, width, -1); } } -static void -efhd_bar_resize(GtkWidget *w, GtkAllocation *event, EMFormatHTML *efh) -{ -#if 0 /* KILL-BONOBO -- Does EAttachmentIconView need a resize method? */ - int width; - GtkRequisition req; - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *) efh; - - 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); -#endif -} - static gboolean -efhd_bar_scroll_event(GtkWidget *w, GdkEventScroll *event, EMFormatHTMLDisplay *efhd) -{ -#if 0 /* KILL-BONOBO -- Do we still need this for a GtkIconView? */ - 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->parent.html), "scroll_event", event, &ret); -#endif - - 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) -{ -#if 0 /* KILL-BONOBO -- Does EAttachmentIconView need a refresh method? */ - EMFormatHTMLDisplay *efhd = (EMFormatHTMLDisplay *)efh; - struct _EMFormatHTMLDisplayPrivate *priv = efhd->priv; - - if (priv->attachment_bar) - e_attachment_bar_refresh (E_ATTACHMENT_BAR (priv->attachment_bar)); -#endif - - return TRUE; -} - -static gboolean -efhd_add_bar(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject) +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_view = e_attachment_icon_view_new (); - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - - 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_view); - - gtk_widget_get_size_request(priv->attachment_view, &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_view, - 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); + GtkWidget *widget; - /* 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); + priv->attachment_bar = g_object_ref (widget); + gtk_widget_show (widget); - g_signal_connect (priv->arrow, "clicked", G_CALLBACK(attachment_bar_arrow_clicked), efh); - 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_swapped ( + widget, "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->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) diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 6308947a26..fae1566876 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -200,10 +200,6 @@ efh_format_exec (struct _format_msg *m) handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/rfc822"); if (handle) handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); - handle = em_format_find_handler((EMFormat *)m->format, "x-evolution/message/post-header-closure"); - if (handle && !((EMFormat *)m->format)->print) - handle->handler((EMFormat *)m->format, (CamelStream *)m->estream, (CamelMimePart *)m->message, handle); - } camel_stream_flush((CamelStream *)m->estream); diff --git a/widgets/misc/e-activity.c b/widgets/misc/e-activity.c index c65c3aaa0a..d40d5aacbe 100644 --- a/widgets/misc/e-activity.c +++ b/widgets/misc/e-activity.c @@ -69,6 +69,7 @@ activity_idle_cancel_cb (EActivity *activity) { activity->priv->idle_id = 0; e_activity_cancel (activity); + g_object_unref (activity); return FALSE; } @@ -78,6 +79,7 @@ activity_idle_complete_cb (EActivity *activity) { activity->priv->idle_id = 0; e_activity_complete (activity); + g_object_unref (activity); return FALSE; } @@ -474,13 +476,24 @@ e_activity_cancel (EActivity *activity) void e_activity_cancel_in_idle (EActivity *activity) { + guint old_idle_id; + g_return_if_fail (E_IS_ACTIVITY (activity)); - if (activity->priv->idle_id > 0) - g_source_remove (activity->priv->idle_id); + /* Be careful not to finalize the activity. Decrement the + * reference count only after incrementing it, in case this + * is the last reference. */ + + old_idle_id = activity->priv->idle_id; activity->priv->idle_id = g_idle_add ( - (GSourceFunc) activity_idle_cancel_cb, activity); + (GSourceFunc) activity_idle_cancel_cb, + g_object_ref (activity)); + + if (old_idle_id > 0) { + g_source_remove (old_idle_id); + g_object_unref (activity); + } } void @@ -500,13 +513,24 @@ e_activity_complete (EActivity *activity) void e_activity_complete_in_idle (EActivity *activity) { + guint old_idle_id; + g_return_if_fail (E_IS_ACTIVITY (activity)); - if (activity->priv->idle_id > 0) - g_source_remove (activity->priv->idle_id); + /* Be careful not to finalize the activity. Decrement the + * reference count only after incrementing it, in case this + * is the last reference. */ + + old_idle_id = activity->priv->idle_id; activity->priv->idle_id = g_idle_add ( - (GSourceFunc) activity_idle_complete_cb, activity); + (GSourceFunc) activity_idle_complete_cb, + g_object_ref (activity)); + + if (old_idle_id > 0) { + g_source_remove (old_idle_id); + g_object_unref (activity); + } } void diff --git a/widgets/misc/e-attachment-dialog.c b/widgets/misc/e-attachment-dialog.c index f697df1fe9..da3c3a855c 100644 --- a/widgets/misc/e-attachment-dialog.c +++ b/widgets/misc/e-attachment-dialog.c @@ -52,6 +52,7 @@ attachment_dialog_update (EAttachmentDialog *dialog) const gchar *display_name; const gchar *description; const gchar *disposition; + gchar *type_description = NULL; gboolean sensitive; gboolean active; @@ -71,32 +72,42 @@ attachment_dialog_update (EAttachmentDialog *dialog) disposition = NULL; } + if (content_type != NULL) { + gchar *comment; + gchar *mime_type; + + comment = g_content_type_get_description (content_type); + mime_type = g_content_type_get_mime_type (content_type); + + type_description = + g_strdup_printf ("%s (%s)", comment, mime_type); + + g_free (comment); + g_free (mime_type); + } + sensitive = G_IS_FILE_INFO (file_info); gtk_dialog_set_response_sensitive ( GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive); - if (display_name == NULL) - display_name = ""; widget = dialog->priv->display_name_entry; gtk_widget_set_sensitive (widget, sensitive); gtk_entry_set_text (GTK_ENTRY (widget), display_name); - if (description == NULL) - description = ""; widget = dialog->priv->description_entry; gtk_widget_set_sensitive (widget, sensitive); gtk_entry_set_text (GTK_ENTRY (widget), description); - if (content_type == NULL) - content_type = ""; widget = dialog->priv->content_type_label; - gtk_label_set_text (GTK_LABEL (widget), content_type); + gtk_label_set_text (GTK_LABEL (widget), type_description); active = (g_strcmp0 (disposition, "inline") == 0); widget = dialog->priv->disposition_checkbox; gtk_widget_set_sensitive (widget, sensitive); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active); + + g_free (type_description); } static void diff --git a/widgets/misc/e-attachment-icon-view.c b/widgets/misc/e-attachment-icon-view.c index 8d39a76d75..6d27429743 100644 --- a/widgets/misc/e-attachment-icon-view.c +++ b/widgets/misc/e-attachment-icon-view.c @@ -35,8 +35,47 @@ struct _EAttachmentIconViewPrivate { EAttachmentViewPrivate view_priv; }; +enum { + PROP_0, + PROP_EDITABLE +}; + static gpointer parent_class; +static void +attachment_icon_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EDITABLE: + e_attachment_view_set_editable ( + E_ATTACHMENT_VIEW (object), + g_value_get_boolean (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_icon_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_attachment_view_get_editable ( + E_ATTACHMENT_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + static void attachment_icon_view_dispose (GObject *object) { @@ -231,6 +270,8 @@ attachment_icon_view_class_init (EAttachmentIconViewClass *class) g_type_class_add_private (class, sizeof (EAttachmentViewPrivate)); object_class = G_OBJECT_CLASS (class); + object_class->set_property = attachment_icon_view_set_property; + object_class->get_property = attachment_icon_view_get_property; object_class->dispose = attachment_icon_view_dispose; object_class->finalize = attachment_icon_view_finalize; @@ -240,6 +281,9 @@ attachment_icon_view_class_init (EAttachmentIconViewClass *class) widget_class->drag_motion = attachment_icon_view_drag_motion; widget_class->drag_data_received = attachment_icon_view_drag_data_received; widget_class->popup_menu = attachment_icon_view_popup_menu; + + g_object_class_override_property ( + object_class, PROP_EDITABLE, "editable"); } static void @@ -260,6 +304,10 @@ attachment_icon_view_iface_init (EAttachmentViewIface *iface) static void attachment_icon_view_init (EAttachmentIconView *icon_view) { + GtkCellLayout *cell_layout; + GtkCellRenderer *renderer; + + cell_layout = GTK_CELL_LAYOUT (icon_view); icon_view->priv = E_ATTACHMENT_ICON_VIEW_GET_PRIVATE (icon_view); e_attachment_view_init (E_ATTACHMENT_VIEW (icon_view)); @@ -267,13 +315,23 @@ attachment_icon_view_init (EAttachmentIconView *icon_view) gtk_icon_view_set_selection_mode ( GTK_ICON_VIEW (icon_view), GTK_SELECTION_MULTIPLE); - gtk_icon_view_set_pixbuf_column ( - GTK_ICON_VIEW (icon_view), - E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF); + renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_DIALOG, NULL); + gtk_cell_layout_pack_start (cell_layout, renderer, FALSE); + + gtk_cell_layout_add_attribute ( + cell_layout, renderer, "gicon", + E_ATTACHMENT_STORE_COLUMN_ICON); + + renderer = gtk_cell_renderer_text_new (); + g_object_set ( + renderer, "alignment", PANGO_ALIGN_CENTER, + "xalign", 0.5, NULL); + gtk_cell_layout_pack_start (cell_layout, renderer, FALSE); - gtk_icon_view_set_text_column ( - GTK_ICON_VIEW (icon_view), - E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION); + gtk_cell_layout_add_attribute ( + cell_layout, renderer, "text", + E_ATTACHMENT_STORE_COLUMN_CAPTION); } GType diff --git a/widgets/misc/e-attachment-paned.c b/widgets/misc/e-attachment-paned.c index bb919e9789..5134282526 100644 --- a/widgets/misc/e-attachment-paned.c +++ b/widgets/misc/e-attachment-paned.c @@ -23,6 +23,7 @@ #include #include "e-util/e-binding.h" +#include "e-attachment-view.h" #include "e-attachment-store.h" #include "e-attachment-icon-view.h" #include "e-attachment-tree-view.h" @@ -52,6 +53,7 @@ struct _EAttachmentPanedPrivate { enum { PROP_0, PROP_ACTIVE_VIEW, + PROP_EDITABLE, PROP_EXPANDED }; @@ -118,7 +120,7 @@ attachment_paned_update_status (EAttachmentPaned *paned) gchar *display_size; gchar *markup; - view = e_attachment_paned_get_view (paned); + view = E_ATTACHMENT_VIEW (paned); store = e_attachment_view_get_store (view); expander = GTK_EXPANDER (paned->priv->expander); label = GTK_LABEL (paned->priv->status_label); @@ -149,9 +151,9 @@ attachment_paned_update_status (EAttachmentPaned *paned) static void attachment_paned_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) + guint property_id, + const GValue *value, + GParamSpec *pspec) { switch (property_id) { case PROP_ACTIVE_VIEW: @@ -160,6 +162,12 @@ attachment_paned_set_property (GObject *object, g_value_get_int (value)); return; + case PROP_EDITABLE: + e_attachment_view_set_editable ( + E_ATTACHMENT_VIEW (object), + g_value_get_boolean (value)); + return; + case PROP_EXPANDED: e_attachment_paned_set_expanded ( E_ATTACHMENT_PANED (object), @@ -172,9 +180,9 @@ attachment_paned_set_property (GObject *object, static void attachment_paned_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) + guint property_id, + GValue *value, + GParamSpec *pspec) { switch (property_id) { case PROP_ACTIVE_VIEW: @@ -183,6 +191,12 @@ attachment_paned_get_property (GObject *object, E_ATTACHMENT_PANED (object))); return; + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_attachment_view_get_editable ( + E_ATTACHMENT_VIEW (object))); + return; + case PROP_EXPANDED: g_value_set_boolean ( value, e_attachment_paned_get_expanded ( @@ -269,6 +283,14 @@ attachment_paned_constructed (GObject *object) G_OBJECT (object), "active-view", G_OBJECT (priv->notebook), "page"); + e_mutual_binding_new ( + G_OBJECT (object), "editable", + G_OBJECT (priv->icon_view), "editable"); + + e_mutual_binding_new ( + G_OBJECT (object), "editable", + G_OBJECT (priv->tree_view), "editable"); + e_mutual_binding_new ( G_OBJECT (object), "expanded", G_OBJECT (priv->expander), "expanded"); @@ -282,6 +304,110 @@ attachment_paned_constructed (GObject *object) G_OBJECT (priv->notebook), "visible"); } +static EAttachmentViewPrivate * +attachment_paned_get_private (EAttachmentView *view) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_private (view); +} + +static EAttachmentStore * +attachment_paned_get_store (EAttachmentView *view) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_store (view); +} + +static GtkTreePath * +attachment_paned_get_path_at_pos (EAttachmentView *view, + gint x, + gint y) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_path_at_pos (view, x, y); +} + +static GList * +attachment_paned_get_selected_paths (EAttachmentView *view) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_get_selected_paths (view); +} + +static gboolean +attachment_paned_path_is_selected (EAttachmentView *view, + GtkTreePath *path) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + return e_attachment_view_path_is_selected (view, path); +} + +static void +attachment_paned_select_path (EAttachmentView *view, + GtkTreePath *path) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_select_path (view, path); +} + +static void +attachment_paned_unselect_path (EAttachmentView *view, + GtkTreePath *path) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_unselect_path (view, path); +} + +static void +attachment_paned_select_all (EAttachmentView *view) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_select_all (view); +} + +static void +attachment_paned_unselect_all (EAttachmentView *view) +{ + EAttachmentPanedPrivate *priv; + + priv = E_ATTACHMENT_PANED_GET_PRIVATE (view); + view = E_ATTACHMENT_VIEW (priv->icon_view); + + e_attachment_view_unselect_all (view); +} + static void attachment_paned_class_init (EAttachmentPanedClass *class) { @@ -319,6 +445,23 @@ attachment_paned_class_init (EAttachmentPanedClass *class) FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + g_object_class_override_property ( + object_class, PROP_EDITABLE, "editable"); +} + +static void +attachment_paned_iface_init (EAttachmentViewIface *iface) +{ + iface->get_private = attachment_paned_get_private; + iface->get_store = attachment_paned_get_store; + iface->get_path_at_pos = attachment_paned_get_path_at_pos; + iface->get_selected_paths = attachment_paned_get_selected_paths; + iface->path_is_selected = attachment_paned_path_is_selected; + iface->select_path = attachment_paned_select_path; + iface->unselect_path = attachment_paned_unselect_path; + iface->select_all = attachment_paned_select_all; + iface->unselect_all = attachment_paned_unselect_all; } static void @@ -394,7 +537,7 @@ attachment_paned_init (EAttachmentPaned *paned) gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 6); paned->priv->status_label = g_object_ref (widget); - gtk_widget_show (widget); + gtk_widget_hide (widget); /* Construct the Attachment Views */ @@ -493,9 +636,18 @@ e_attachment_paned_get_type (void) NULL /* value_table */ }; + static const GInterfaceInfo iface_info = { + (GInterfaceInitFunc) attachment_paned_iface_init, + (GInterfaceFinalizeFunc) NULL, + NULL /* interface_data */ + }; + type = g_type_register_static ( GTK_TYPE_VPANED, "EAttachmentPaned", &type_info, 0); + + g_type_add_interface_static ( + type, E_TYPE_ATTACHMENT_VIEW, &iface_info); } return type; @@ -507,14 +659,6 @@ e_attachment_paned_new (void) return g_object_new (E_TYPE_ATTACHMENT_PANED, NULL); } -EAttachmentView * -e_attachment_paned_get_view (EAttachmentPaned *paned) -{ - g_return_val_if_fail (E_IS_ATTACHMENT_PANED (paned), NULL); - - return E_ATTACHMENT_VIEW (paned->priv->icon_view); -} - GtkWidget * e_attachment_paned_get_content_area (EAttachmentPaned *paned) { diff --git a/widgets/misc/e-attachment-paned.h b/widgets/misc/e-attachment-paned.h index c6cad5226f..c15d642771 100644 --- a/widgets/misc/e-attachment-paned.h +++ b/widgets/misc/e-attachment-paned.h @@ -23,7 +23,6 @@ #define E_ATTACHMENT_PANED_H #include -#include /* Standard GObject macros */ #define E_TYPE_ATTACHMENT_PANED \ @@ -61,8 +60,6 @@ struct _EAttachmentPanedClass { GType e_attachment_paned_get_type (void); GtkWidget * e_attachment_paned_new (void); -EAttachmentView * - e_attachment_paned_get_view (EAttachmentPaned *paned); GtkWidget * e_attachment_paned_get_content_area (EAttachmentPaned *paned); gint e_attachment_paned_get_active_view diff --git a/widgets/misc/e-attachment-store.c b/widgets/misc/e-attachment-store.c index 2658dd06c9..bd6cb18481 100644 --- a/widgets/misc/e-attachment-store.c +++ b/widgets/misc/e-attachment-store.c @@ -34,12 +34,6 @@ #define DEFAULT_ICON_NAME "mail-attachment" -/* XXX Unfortunate that we have to define this here. Would - * prefer the attachment view classes pick their own size, - * but GtkIconView requires a dedicated pixbuf column. */ -#define LARGE_ICON_SIZE GTK_ICON_SIZE_DIALOG -#define SMALL_ICON_SIZE GTK_ICON_SIZE_MENU - struct _EAttachmentStorePrivate { GHashTable *activity_index; GHashTable *attachment_index; @@ -56,7 +50,7 @@ enum { PROP_BACKGROUND_OPTIONS, PROP_CURRENT_FOLDER, PROP_NUM_ATTACHMENTS, - PROP_NUM_DOWNLOADING, + PROP_NUM_LOADING, PROP_TOTAL_SIZE }; @@ -133,7 +127,7 @@ attachment_store_remove_activity (EAttachmentStore *store, g_hash_table_remove (hash_table, activity); - g_object_notify (G_OBJECT (store), "num-downloading"); + g_object_notify (G_OBJECT (store), "num-loading"); } static void @@ -178,10 +172,6 @@ attachment_store_copy_ready (GFile *source, e_activity_complete (activity); - path = gtk_tree_model_get_path (model, &iter); - gtk_tree_model_row_changed (model, path, &iter); - gtk_tree_path_free (path); - g_object_unref (attachment); g_object_unref (activity); @@ -247,6 +237,7 @@ attachment_store_copy_async (EAttachmentStore *store, reference = gtk_tree_row_reference_copy (reference); + hash_table = store->priv->activity_index; g_hash_table_insert (hash_table, g_object_ref (activity), reference); g_signal_connect_swapped ( @@ -271,7 +262,7 @@ attachment_store_copy_async (EAttachmentStore *store, e_file_activity_set_file (E_FILE_ACTIVITY (activity), destination); g_signal_emit (store, signals[NEW_ACTIVITY], 0, activity); - g_object_notify (G_OBJECT (store), "num-downloading"); + g_object_notify (G_OBJECT (store), "num-loading"); g_object_unref (activity); g_object_unref (destination); @@ -350,10 +341,10 @@ attachment_store_get_property (GObject *object, E_ATTACHMENT_STORE (object))); return; - case PROP_NUM_DOWNLOADING: + case PROP_NUM_LOADING: g_value_set_uint ( value, - e_attachment_store_get_num_downloading ( + e_attachment_store_get_num_loading ( E_ATTACHMENT_STORE (object))); return; @@ -427,31 +418,25 @@ attachment_store_row_changed (GtkTreeModel *model, { EAttachmentStorePrivate *priv; EAttachment *attachment; - GtkIconTheme *icon_theme; - GdkPixbuf *large_pixbuf; - GdkPixbuf *small_pixbuf; + GFile *file; GIcon *icon; + GList *list; const gchar *content_type; const gchar *display_name; const gchar *thumbnail_path; gchar *content_description; gchar *display_size; - gchar *icon_caption; - gint large_icon_size; - gint small_icon_size; + gchar *caption; + gboolean loading; + gboolean saving; guint64 size; gint column_id; - GError *error = NULL; priv = E_ATTACHMENT_STORE_GET_PRIVATE (model); if (priv->ignore_row_changed) return; - icon_theme = gtk_icon_theme_get_default (); - gtk_icon_size_lookup (LARGE_ICON_SIZE, &large_icon_size, NULL); - gtk_icon_size_lookup (SMALL_ICON_SIZE, &small_icon_size, NULL); - column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT; gtk_tree_model_get (model, iter, column_id, &attachment, -1); g_return_if_fail (E_IS_ATTACHMENT (attachment)); @@ -459,6 +444,8 @@ attachment_store_row_changed (GtkTreeModel *model, content_type = e_attachment_get_content_type (attachment); display_name = e_attachment_get_display_name (attachment); thumbnail_path = e_attachment_get_thumbnail_path (attachment); + loading = e_attachment_get_loading (attachment); + saving = e_attachment_get_saving (attachment); icon = e_attachment_get_icon (attachment); size = e_attachment_get_size (attachment); @@ -467,82 +454,46 @@ attachment_store_row_changed (GtkTreeModel *model, display_size = g_format_size_for_display ((goffset) size); if (size > 0) - icon_caption = g_strdup_printf ( + caption = g_strdup_printf ( "%s\n(%s)", display_name, display_size); else - icon_caption = g_strdup (display_name); + caption = g_strdup (display_name); /* Prefer the thumbnail if we have one. */ - if (thumbnail_path != NULL) { - gint width = -1; - gint height = -1; - - gdk_pixbuf_get_file_info (thumbnail_path, &width, &height); + if (thumbnail_path != NULL && *thumbnail_path != '\0') { + file = g_file_new_for_path (thumbnail_path); + icon = g_file_icon_new (file); + g_object_unref (file); - large_pixbuf = gdk_pixbuf_new_from_file_at_scale ( - thumbnail_path, - (width > height) ? large_icon_size : -1, - (width > height) ? -1 : large_icon_size, - TRUE, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); - } + /* Else use the standard icon for the content type. */ + } else if (icon != NULL) + g_object_ref (icon); - small_pixbuf = gdk_pixbuf_new_from_file_at_scale ( - thumbnail_path, - (width > height) ? small_icon_size : -1, - (width > height) ? -1 : small_icon_size, - TRUE, &error); - - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); - } - - /* Otherwise fall back to the icon theme. */ - } else { - GtkIconInfo *icon_info = NULL; - const gchar *filename; - - if (G_IS_ICON (icon)) - icon_info = gtk_icon_theme_lookup_by_gicon ( - icon_theme, icon, large_icon_size, 0); - if (icon_info == NULL) - icon_info = gtk_icon_theme_lookup_icon ( - icon_theme, DEFAULT_ICON_NAME, - large_icon_size, 0); - g_return_if_fail (icon_info != NULL); - - filename = gtk_icon_info_get_filename (icon_info); - large_pixbuf = gdk_pixbuf_new_from_file (filename, &error); - gtk_icon_info_free (icon_info); - - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); + /* Last ditch fallback. (GFileInfo not yet loaded?) */ + else + icon = g_themed_icon_new (DEFAULT_ICON_NAME); + + /* Apply emblems. */ + list = e_attachment_list_emblems (attachment); + if (list != NULL) { + GIcon *emblemed_icon; + GEmblem *emblem; + + emblem = G_EMBLEM (list->data); + emblemed_icon = g_emblemed_icon_new (icon, emblem); + list = g_list_delete_link (list, list); + g_object_unref (emblem); + + while (list != NULL) { + emblem = G_EMBLEM (list->data); + g_emblemed_icon_add_emblem ( + G_EMBLEMED_ICON (emblemed_icon), emblem); + list = g_list_delete_link (list, list); + g_object_unref (emblem); } - icon_info = NULL; - - if (G_IS_ICON (icon)) - icon_info = gtk_icon_theme_lookup_by_gicon ( - icon_theme, icon, small_icon_size, 0); - if (icon_info == NULL) - icon_info = gtk_icon_theme_lookup_icon ( - icon_theme, DEFAULT_ICON_NAME, - small_icon_size, 0); - g_return_if_fail (icon_info != NULL); - - filename = gtk_icon_info_get_filename (icon_info); - small_pixbuf = gdk_pixbuf_new_from_file (filename, &error); - gtk_icon_info_free (icon_info); - - if (error != NULL) { - g_warning ("%s", error->message); - g_clear_error (&error); - } + g_object_unref (icon); + icon = emblemed_icon; } /* We're about to trigger another "row-changed" @@ -553,20 +504,16 @@ attachment_store_row_changed (GtkTreeModel *model, GTK_LIST_STORE (model), iter, E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, content_description, E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME, display_name, - E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION, icon_caption, - E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF, large_pixbuf, - E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF, small_pixbuf, + E_ATTACHMENT_STORE_COLUMN_CAPTION, caption, + E_ATTACHMENT_STORE_COLUMN_ICON, icon, + E_ATTACHMENT_STORE_COLUMN_LOADING, loading, + E_ATTACHMENT_STORE_COLUMN_SAVING, saving, E_ATTACHMENT_STORE_COLUMN_SIZE, size, -1); priv->ignore_row_changed = FALSE; - if (large_pixbuf != NULL) - g_object_unref (large_pixbuf); - - if (small_pixbuf != NULL) - g_object_unref (small_pixbuf); - + g_object_unref (icon); g_free (content_description); g_free (display_size); } @@ -633,10 +580,10 @@ attachment_store_class_init (EAttachmentStoreClass *class) g_object_class_install_property ( object_class, - PROP_NUM_DOWNLOADING, + PROP_NUM_LOADING, g_param_spec_uint ( - "num-downloading", - "Num Downloading", + "num-loading", + "Num Loading", NULL, 0, G_MAXUINT, @@ -686,11 +633,12 @@ attachment_store_init (EAttachmentStore *store) types[column++] = E_TYPE_ACTIVITY; /* COLUMN_ACTIVITY */ types[column++] = E_TYPE_ATTACHMENT; /* COLUMN_ATTACHMENT */ + types[column++] = G_TYPE_STRING; /* COLUMN_CAPTION */ types[column++] = G_TYPE_STRING; /* COLUMN_CONTENT_TYPE */ types[column++] = G_TYPE_STRING; /* COLUMN_DISPLAY_NAME */ - types[column++] = G_TYPE_STRING; /* COLUMN_ICON_CAPTION */ - types[column++] = GDK_TYPE_PIXBUF; /* COLUMN_LARGE_PIXBUF */ - types[column++] = GDK_TYPE_PIXBUF; /* COLUMN_SMALL_PIXBUF */ + types[column++] = G_TYPE_ICON; /* COLUMN_ICON */ + types[column++] = G_TYPE_BOOLEAN; /* COLUMN_LOADING */ + types[column++] = G_TYPE_BOOLEAN; /* COLUMN_SAVING */ types[column++] = G_TYPE_UINT64; /* COLUMN_SIZE */ g_assert (column == E_ATTACHMENT_STORE_NUM_COLUMNS); @@ -774,7 +722,7 @@ e_attachment_store_add_attachment (EAttachmentStore *store, /* This lets the attachment tell us when to update. */ _e_attachment_set_reference (attachment, reference); - if (!g_file_is_native (file)) + if (file != NULL && !g_file_is_native (file)) attachment_store_copy_async (store, attachment); g_object_freeze_notify (G_OBJECT (store)); @@ -897,7 +845,7 @@ e_attachment_store_get_num_attachments (EAttachmentStore *store) } guint -e_attachment_store_get_num_downloading (EAttachmentStore *store) +e_attachment_store_get_num_loading (EAttachmentStore *store) { g_return_val_if_fail (E_IS_ATTACHMENT_STORE (store), 0); diff --git a/widgets/misc/e-attachment-store.h b/widgets/misc/e-attachment-store.h index 906aee6638..971868258f 100644 --- a/widgets/misc/e-attachment-store.h +++ b/widgets/misc/e-attachment-store.h @@ -62,11 +62,12 @@ struct _EAttachmentStoreClass { enum { E_ATTACHMENT_STORE_COLUMN_ACTIVITY, /* E_TYPE_ACTIVITY */ E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, /* E_TYPE_ATTACHMENT */ + E_ATTACHMENT_STORE_COLUMN_CAPTION, /* G_TYPE_STRING */ E_ATTACHMENT_STORE_COLUMN_CONTENT_TYPE, /* G_TYPE_STRING */ E_ATTACHMENT_STORE_COLUMN_DISPLAY_NAME, /* G_TYPE_STRING */ - E_ATTACHMENT_STORE_COLUMN_ICON_CAPTION, /* G_TYPE_STRING */ - E_ATTACHMENT_STORE_COLUMN_LARGE_PIXBUF, /* GDK_TYPE_PIXBUF */ - E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF, /* GDK_TYPE_PIXBUF */ + E_ATTACHMENT_STORE_COLUMN_ICON, /* G_TYPE_ICON */ + E_ATTACHMENT_STORE_COLUMN_LOADING, /* G_TYPE_BOOLEAN */ + E_ATTACHMENT_STORE_COLUMN_SAVING, /* G_TYPE_BOOLEAN */ E_ATTACHMENT_STORE_COLUMN_SIZE, /* G_TYPE_UINT64 */ E_ATTACHMENT_STORE_NUM_COLUMNS }; @@ -90,7 +91,7 @@ void e_attachment_store_set_current_folder const gchar *current_folder); guint e_attachment_store_get_num_attachments (EAttachmentStore *store); -guint e_attachment_store_get_num_downloading +guint e_attachment_store_get_num_loading (EAttachmentStore *store); guint64 e_attachment_store_get_total_size (EAttachmentStore *store); diff --git a/widgets/misc/e-attachment-tree-view.c b/widgets/misc/e-attachment-tree-view.c index 817a6c7dab..df01e07040 100644 --- a/widgets/misc/e-attachment-tree-view.c +++ b/widgets/misc/e-attachment-tree-view.c @@ -36,8 +36,47 @@ struct _EAttachmentTreeViewPrivate { EAttachmentViewPrivate view_priv; }; +enum { + PROP_0, + PROP_EDITABLE +}; + static gpointer parent_class; +static void +attachment_tree_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EDITABLE: + e_attachment_view_set_editable ( + E_ATTACHMENT_VIEW (object), + g_value_get_boolean (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +attachment_tree_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_attachment_view_get_editable ( + E_ATTACHMENT_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + static void attachment_tree_view_dispose (GObject *object) { @@ -267,6 +306,8 @@ attachment_tree_view_class_init (EAttachmentTreeViewClass *class) g_type_class_add_private (class, sizeof (EAttachmentViewPrivate)); object_class = G_OBJECT_CLASS (class); + object_class->set_property = attachment_tree_view_set_property; + object_class->get_property = attachment_tree_view_get_property; object_class->dispose = attachment_tree_view_dispose; object_class->finalize = attachment_tree_view_finalize; @@ -276,6 +317,9 @@ attachment_tree_view_class_init (EAttachmentTreeViewClass *class) widget_class->drag_motion = attachment_tree_view_drag_motion; widget_class->drag_data_received = attachment_tree_view_drag_data_received; widget_class->popup_menu = attachment_tree_view_popup_menu; + + g_object_class_override_property ( + object_class, PROP_EDITABLE, "editable"); } static void @@ -318,9 +362,11 @@ attachment_tree_view_init (EAttachmentTreeView *tree_view) renderer = gtk_cell_renderer_pixbuf_new (); gtk_tree_view_column_pack_start (column, renderer, FALSE); + g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_add_attribute ( - column, renderer, "pixbuf", - E_ATTACHMENT_STORE_COLUMN_SMALL_PIXBUF); + column, renderer, "gicon", + E_ATTACHMENT_STORE_COLUMN_ICON); renderer = gtk_cell_renderer_text_new (); g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c index 198ce75d31..bdb0a0067e 100644 --- a/widgets/misc/e-attachment-view.c +++ b/widgets/misc/e-attachment-view.c @@ -25,6 +25,7 @@ #include #include +#include "e-util/e-binding.h" #include "e-util/e-plugin-ui.h" #include "e-util/e-util.h" #include "e-attachment-dialog.h" @@ -122,6 +123,30 @@ action_drag_move_cb (GtkAction *action, e_attachment_view_drag_action (view, GDK_ACTION_MOVE); } +static void +action_open_in_cb (GtkAction *action, + EAttachmentView *view) +{ + GAppInfo *app_info; + EActivity *activity; + EAttachment *attachment; + + app_info = g_object_get_data (G_OBJECT (action), "app-info"); + g_return_if_fail (G_IS_APP_INFO (app_info)); + + attachment = g_object_get_data (G_OBJECT (action), "attachment"); + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + + activity = e_file_activity_newv ( + _("Opening attachment in %s"), + g_app_info_get_name (app_info)); + + e_attachment_launch_async ( + attachment, E_FILE_ACTIVITY (activity), app_info); + + g_object_unref (activity); +} + static void action_properties_cb (GtkAction *action, EAttachmentView *view) @@ -407,6 +432,16 @@ attachment_view_class_init (EAttachmentViewIface *iface) { gint ii; + g_object_interface_install_property ( + iface, + g_param_spec_boolean ( + "editable", + "Editable", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + for (ii = 0; ii < G_N_ELEMENTS (drag_info); ii++) { const gchar *target = drag_info[ii].target; drag_info[ii].atom = gdk_atom_intern (target, FALSE); @@ -489,6 +524,10 @@ e_attachment_view_init (EAttachmentView *view) if (error != NULL) g_error ("%s", error->message); + e_mutual_binding_new ( + G_OBJECT (view), "editable", + G_OBJECT (priv->editable_actions), "visible"); + e_plugin_ui_register_manager (ui_manager, "attachment-view", view); } @@ -562,6 +601,32 @@ e_attachment_view_get_store (EAttachmentView *view) return iface->get_store (view); } +gboolean +e_attachment_view_get_editable (EAttachmentView *view) +{ + EAttachmentViewPrivate *priv; + + g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); + + priv = e_attachment_view_get_private (view); + + return priv->editable; +} + +void +e_attachment_view_set_editable (EAttachmentView *view, + gboolean editable) +{ + EAttachmentViewPrivate *priv; + + g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); + + priv = e_attachment_view_get_private (view); + priv->editable = editable; + + g_object_notify (G_OBJECT (view), "editable"); +} + GList * e_attachment_view_get_selected_attachments (EAttachmentView *view) { @@ -1006,27 +1071,29 @@ void e_attachment_view_update_actions (EAttachmentView *view) { EAttachmentViewPrivate *priv; - GFileInfo *file_info; + EAttachment *attachment; GtkAction *action; - GList *selected; + GList *list, *iter; guint n_selected; gboolean is_image; g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); priv = e_attachment_view_get_private (view); - selected = e_attachment_view_get_selected_attachments (view); - n_selected = g_list_length (selected); - - is_image = FALSE; - file_info = NULL; + list = e_attachment_view_get_selected_attachments (view); + n_selected = g_list_length (list); if (n_selected == 1) { - EAttachment *attachment = selected->data; - file_info = e_attachment_get_file_info (attachment); + attachment = g_object_ref (list->data); is_image = e_attachment_is_image (attachment); + } else { + attachment = NULL; + is_image = FALSE; } + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); + action = e_attachment_view_get_action (view, "properties"); gtk_action_set_visible (action, n_selected == 1); @@ -1038,4 +1105,67 @@ e_attachment_view_update_actions (EAttachmentView *view) action = e_attachment_view_get_action (view, "set-background"); gtk_action_set_visible (action, is_image); + + /* Clear out the "openwith" action group. */ + gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id); + e_action_group_remove_all_actions (priv->openwith_actions); + + if (attachment == NULL) + return; + + list = e_attachment_list_apps (attachment); + + for (iter = list; iter != NULL; iter = iter->next) { + GAppInfo *app_info = iter->data; + GtkAction *action; + const gchar *app_executable; + const gchar *app_name; + gchar *action_tooltip; + gchar *action_label; + gchar *action_name; + + if (!g_app_info_should_show (app_info)) + continue; + + app_executable = g_app_info_get_executable (app_info); + app_name = g_app_info_get_name (app_info); + + action_name = g_strdup_printf ("open-in-%s", app_executable); + action_label = g_strdup_printf (_("Open in %s..."), app_name); + + action_tooltip = g_strdup_printf ( + _("Open this attachment in %s"), app_name); + + action = gtk_action_new ( + action_name, action_label, action_tooltip, NULL); + + g_object_set_data_full ( + G_OBJECT (action), + "app-info", g_object_ref (app_info), + (GDestroyNotify) g_object_unref); + + g_object_set_data_full ( + G_OBJECT (action), + "attachment", g_object_ref (attachment), + (GDestroyNotify) g_object_unref); + + g_signal_connect ( + action, "activate", + G_CALLBACK (action_open_in_cb), view); + + gtk_action_group_add_action (priv->openwith_actions, action); + + gtk_ui_manager_add_ui ( + priv->ui_manager, priv->merge_id, + "/context/open-actions", action_name, + action_name, GTK_UI_MANAGER_AUTO, FALSE); + + g_free (action_name); + g_free (action_label); + g_free (action_tooltip); + } + + g_object_unref (attachment); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); } diff --git a/widgets/misc/e-attachment-view.h b/widgets/misc/e-attachment-view.h index a00308d2d5..e6e04a82a3 100644 --- a/widgets/misc/e-attachment-view.h +++ b/widgets/misc/e-attachment-view.h @@ -88,6 +88,8 @@ struct _EAttachmentViewPrivate { GtkSelectionData *selection_data; guint info; guint time; + + guint editable : 1; }; GType e_attachment_view_get_type (void); @@ -100,6 +102,9 @@ EAttachmentViewPrivate * e_attachment_view_get_private (EAttachmentView *view); EAttachmentStore * e_attachment_view_get_store (EAttachmentView *view); +gboolean e_attachment_view_get_editable (EAttachmentView *view); +void e_attachment_view_set_editable (EAttachmentView *view, + gboolean editable); GList * e_attachment_view_get_selected_attachments (EAttachmentView *view); void e_attachment_view_remove_selected diff --git a/widgets/misc/e-attachment.c b/widgets/misc/e-attachment.c index 6f9e80f02b..015a706dc4 100644 --- a/widgets/misc/e-attachment.c +++ b/widgets/misc/e-attachment.c @@ -36,6 +36,16 @@ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_ATTACHMENT, EAttachmentPrivate)) +/* Emblems */ +#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 by EAttachmentStore, et al. */ #define ATTACHMENT_QUERY "standard::*,preview::*,thumbnail::*" @@ -45,6 +55,11 @@ struct _EAttachmentPrivate { GCancellable *cancellable; CamelMimePart *mime_part; gchar *disposition; + guint loading : 1; + guint saving : 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. @@ -56,9 +71,12 @@ struct _EAttachmentPrivate { enum { PROP_0, PROP_DISPOSITION, + PROP_ENCRYPTED, PROP_FILE, PROP_FILE_INFO, - PROP_MIME_PART + PROP_LOADING, + PROP_MIME_PART, + PROP_SIGNED }; static gpointer parent_class; @@ -89,6 +107,8 @@ attachment_notify_model (EAttachment *attachment) gtk_tree_model_get_iter (model, &iter, path); gtk_tree_model_row_changed (model, path, &iter); + + /* XXX This doesn't really belong here. */ g_object_notify (G_OBJECT (model), "total-size"); gtk_tree_path_free (path); @@ -101,7 +121,7 @@ attachment_get_default_charset (void) const gchar *key; gchar *charset; - /* XXX This function doesn't really belong here. */ + /* XXX This doesn't really belong here. */ client = gconf_client_get_default (); key = "/apps/evolution/mail/composer/charset"; @@ -149,7 +169,26 @@ attachment_set_file_info (EAttachment *attachment, attachment->priv->file_info = file_info; g_object_notify (G_OBJECT (attachment), "file-info"); + attachment_notify_model (attachment); +} +static void +attachment_set_loading (EAttachment *attachment, + gboolean loading) +{ + attachment->priv->loading = loading; + + g_object_notify (G_OBJECT (attachment), "loading"); + attachment_notify_model (attachment); +} + +static void +attachment_set_saving (EAttachment *attachment, + gboolean saving) +{ + attachment->priv->saving = saving; + + g_object_notify (G_OBJECT (attachment), "saving"); attachment_notify_model (attachment); } @@ -162,7 +201,7 @@ attachment_reset (EAttachment *attachment) g_object_freeze_notify (G_OBJECT (attachment)); - /* Cancel any query operations in progress. */ + /* Cancel any I/O operations in progress. */ if (!g_cancellable_is_cancelled (cancellable)) { g_cancellable_cancel (cancellable); g_cancellable_reset (cancellable); @@ -220,7 +259,8 @@ attachment_file_info_to_mime_part (EAttachment *attachment, if (file_info == NULL || mime_part == NULL) return; - /* XXX Note that we skip "standard::size" here. */ + /* XXX Note that we skip "standard::size" here. + * The CamelMimePart already knows the size. */ attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE; string = g_file_info_get_attribute_string (file_info, attribute); @@ -241,28 +281,55 @@ attachment_file_info_to_mime_part (EAttachment *attachment, } static void -attachment_mime_part_to_file_info (EAttachment *attachment) +attachment_populate_file_info (EAttachment *attachment, + GFileInfo *file_info) { CamelContentType *content_type; CamelMimePart *mime_part; - GFileInfo *file_info; const gchar *attribute; const gchar *string; gchar *allocated; guint64 v_uint64; - file_info = e_attachment_get_file_info (attachment); mime_part = e_attachment_get_mime_part (attachment); - if (file_info == NULL || mime_part == NULL) - return; - attribute = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE; content_type = camel_mime_part_get_content_type (mime_part); allocated = camel_content_type_simple (content_type); - if (allocated != NULL) + 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_attribute_string ( file_info, attribute, allocated); + + attribute = G_FILE_ATTRIBUTE_STANDARD_ICON; + icon = g_content_type_get_icon (allocated); + if (icon != NULL) { + g_file_info_set_attribute_object ( + file_info, attribute, G_OBJECT (icon)); + g_object_unref (icon); + } + } g_free (allocated); attribute = G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME; @@ -298,6 +365,12 @@ attachment_set_property (GObject *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), @@ -309,6 +382,12 @@ attachment_set_property (GObject *object, 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); @@ -327,6 +406,12 @@ attachment_get_property (GObject *object, 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 ( @@ -339,11 +424,23 @@ attachment_get_property (GObject *object, 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_SIGNED: + g_value_set_int ( + value, e_attachment_get_signed ( + E_ATTACHMENT (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -423,6 +520,20 @@ attachment_class_init (EAttachmentClass *class) 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, @@ -444,6 +555,16 @@ attachment_class_init (EAttachmentClass *class) 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, @@ -453,6 +574,20 @@ attachment_class_init (EAttachmentClass *class) NULL, E_TYPE_CAMEL_OBJECT, G_PARAM_READWRITE)); + + /* 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 @@ -460,6 +595,8 @@ 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; } GType @@ -724,8 +861,6 @@ void e_attachment_set_mime_part (EAttachment *attachment, CamelMimePart *mime_part) { - GFileInfo *file_info; - g_return_if_fail (E_IS_ATTACHMENT (attachment)); g_object_freeze_notify (G_OBJECT (attachment)); @@ -738,16 +873,64 @@ e_attachment_set_mime_part (EAttachment *attachment, attachment_reset (attachment); attachment->priv->mime_part = mime_part; - file_info = g_file_info_new (); - attachment_set_file_info (attachment, file_info); - attachment_mime_part_to_file_info (attachment); - g_object_unref (file_info); + if (mime_part != NULL) { + GFileInfo *file_info; + + file_info = g_file_info_new (); + attachment_populate_file_info (attachment, file_info); + attachment_set_file_info (attachment, file_info); + g_object_unref (file_info); + } g_object_notify (G_OBJECT (attachment), "mime-part"); g_object_thaw_notify (G_OBJECT (attachment)); } +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"); + attachment_notify_model (attachment); +} + +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"); + attachment_notify_model (attachment); +} + const gchar * e_attachment_get_content_type (EAttachment *attachment) { @@ -817,6 +1000,14 @@ e_attachment_get_icon (EAttachment *attachment) g_file_info_get_attribute_object (file_info, attribute); } +gboolean +e_attachment_get_loading (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->loading; +} + const gchar * e_attachment_get_thumbnail_path (EAttachment *attachment) { @@ -834,6 +1025,14 @@ e_attachment_get_thumbnail_path (EAttachment *attachment) return g_file_info_get_attribute_byte_string (file_info, attribute); } +gboolean +e_attachment_get_saving (EAttachment *attachment) +{ + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), FALSE); + + return attachment->priv->saving; +} + guint64 e_attachment_get_size (EAttachment *attachment) { @@ -881,24 +1080,225 @@ e_attachment_is_rfc822 (EAttachment *attachment) return g_content_type_equals (content_type, "message/rfc822"); } +GList * +e_attachment_list_apps (EAttachment *attachment) +{ + GList *app_info_list; + const gchar *content_type; + const gchar *display_name; + gchar *allocated; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + content_type = e_attachment_get_content_type (attachment); + display_name = e_attachment_get_display_name (attachment); + 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; +} + +GList * +e_attachment_list_emblems (EAttachment *attachment) +{ + GList *list = NULL; + GIcon *icon; + + g_return_val_if_fail (E_IS_ATTACHMENT (attachment), NULL); + + if (e_attachment_get_loading (attachment)) { + icon = g_themed_icon_new (EMBLEM_LOADING); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + } + + if (e_attachment_get_saving (attachment)) { + icon = g_themed_icon_new (EMBLEM_SAVING); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + } + + switch (e_attachment_get_encrypted (attachment)) { + case CAMEL_CIPHER_VALIDITY_ENCRYPT_WEAK: + icon = g_themed_icon_new (EMBLEM_ENCRYPT_WEAK); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + case CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED: + icon = g_themed_icon_new (EMBLEM_ENCRYPT_UNKNOWN); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + case CAMEL_CIPHER_VALIDITY_ENCRYPT_STRONG: + icon = g_themed_icon_new (EMBLEM_ENCRYPT_STRONG); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + default: + break; + } + + switch (e_attachment_get_signed (attachment)) { + case CAMEL_CIPHER_VALIDITY_SIGN_GOOD: + icon = g_themed_icon_new (EMBLEM_SIGN_GOOD); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + case CAMEL_CIPHER_VALIDITY_SIGN_BAD: + icon = g_themed_icon_new (EMBLEM_SIGN_BAD); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + case CAMEL_CIPHER_VALIDITY_SIGN_UNKNOWN: + case CAMEL_CIPHER_VALIDITY_SIGN_NEED_PUBLIC_KEY: + icon = g_themed_icon_new (EMBLEM_SIGN_UNKNOWN); + list = g_list_append (list, g_emblem_new (icon)); + g_object_unref (icon); + break; + + default: + break; + } + + return list; +} + +/************************ e_attachment_launch_async() ************************/ + +static void +attachment_launch_file (EActivity *activity, + GAppInfo *app_info, + GFile *file) +{ + GdkAppLaunchContext *launch_context; + GList *file_list; + GError *error = NULL; + + file_list = g_list_prepend (NULL, file); + launch_context = gdk_app_launch_context_new (); + + g_app_info_launch ( + app_info, file_list, + G_APP_LAUNCH_CONTEXT (launch_context), &error); + + g_list_free (file_list); + g_object_unref (launch_context); + + if (error != NULL) { + e_activity_set_error (activity, error); + g_error_free (error); + } + + e_activity_complete (activity); + g_object_unref (activity); +} + +void +e_attachment_launch_async (EAttachment *attachment, + EFileActivity *file_activity, + GAppInfo *app_info) +{ + CamelMimePart *mime_part; + GFile *file; + + g_return_if_fail (E_IS_ATTACHMENT (attachment)); + g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity)); + g_return_if_fail (G_IS_APP_INFO (app_info)); + + file = e_attachment_get_file (attachment); + mime_part = e_attachment_get_mime_part (attachment); + g_return_if_fail (file != NULL || mime_part != NULL); + + /* 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 (G_IS_FILE (file)) { + EActivity *activity = g_object_ref (file_activity); + attachment_launch_file (activity, app_info, file); + + } else if (CAMEL_IS_MIME_PART (mime_part)) { + /* XXX Not done yet. */ + } +} + +/************************* e_attachment_save_async() *************************/ + +typedef struct _AttachmentSaveContext AttachmentSaveContext; + +struct _AttachmentSaveContext { + EAttachment *attachment; + EFileActivity *file_activity; + GOutputStream *output_stream; +}; + +static AttachmentSaveContext * +attachment_save_context_new (EAttachment *attachment, + EFileActivity *file_activity) +{ + AttachmentSaveContext *save_context; + + save_context = g_slice_new (AttachmentSaveContext); + save_context->attachment = g_object_ref (attachment); + save_context->file_activity = g_object_ref (file_activity); + save_context->output_stream = NULL; + + attachment_set_saving (save_context->attachment, TRUE); + + return save_context; +} + +static void +attachment_save_context_free (AttachmentSaveContext *save_context) +{ + attachment_set_saving (save_context->attachment, FALSE); + + g_object_unref (save_context->attachment); + g_object_unref (save_context->file_activity); + + if (save_context->output_stream != NULL) + g_object_unref (save_context->output_stream); + + g_slice_free (AttachmentSaveContext, save_context); +} + static void attachment_save_file_cb (GFile *source, GAsyncResult *result, - EActivity *activity) + AttachmentSaveContext *save_context) { + EActivity *activity; GError *error = NULL; + activity = E_ACTIVITY (save_context->file_activity); + if (!g_file_copy_finish (source, result, &error)) { e_activity_set_error (activity, error); g_error_free (error); } e_activity_complete (activity); - g_object_unref (activity); + attachment_save_context_free (save_context); } static gpointer -attachment_save_part_thread (EActivity *activity) +attachment_save_part_thread (AttachmentSaveContext *save_context) { GObject *object; EAttachment *attachment; @@ -910,12 +1310,11 @@ attachment_save_part_thread (EActivity *activity) CamelStream *stream; GError *error = NULL; - object = G_OBJECT (activity); - attachment = g_object_get_data (object, "attachment"); - output_stream = g_object_get_data (object, "output-stream"); + attachment = save_context->attachment; + file_activity = save_context->file_activity; + output_stream = save_context->output_stream; /* Last chance to cancel. */ - file_activity = E_FILE_ACTIVITY (activity); cancellable = e_file_activity_get_cancellable (file_activity); if (g_cancellable_set_error_if_cancelled (cancellable, &error)) goto exit; @@ -941,12 +1340,12 @@ attachment_save_part_thread (EActivity *activity) exit: if (error != NULL) { - e_activity_set_error (activity, error); + e_activity_set_error (E_ACTIVITY (file_activity), error); g_error_free (error); } - e_activity_complete_in_idle (activity); - g_object_unref (activity); + e_activity_complete_in_idle (E_ACTIVITY (file_activity)); + attachment_save_context_free (save_context); return NULL; } @@ -954,30 +1353,28 @@ exit: static void attachment_save_part_cb (GFile *destination, GAsyncResult *result, - EActivity *activity) + AttachmentSaveContext *save_context) { GFileOutputStream *output_stream; + EActivity *activity; GError *error = NULL; + activity = E_ACTIVITY (save_context->file_activity); output_stream = g_file_replace_finish (destination, result, &error); + save_context->output_stream = G_OUTPUT_STREAM (output_stream); - if (output_stream != NULL) { - g_object_set_data_full ( - G_OBJECT (activity), - "output-stream", output_stream, - (GDestroyNotify) g_object_unref); + if (output_stream != NULL) g_thread_create ( (GThreadFunc) attachment_save_part_thread, - activity, FALSE, &error); - } + save_context, FALSE, &error); if (error != NULL) { e_activity_set_error (activity, error); e_activity_complete (activity); - g_object_unref (activity); g_error_free (error); - } + attachment_save_context_free (save_context); + } } void @@ -985,14 +1382,15 @@ e_attachment_save_async (EAttachment *attachment, EFileActivity *file_activity, GFile *destination) { + AttachmentSaveContext *save_context; GFileProgressCallback progress_callback; GCancellable *cancellable; CamelMimePart *mime_part; GFile *source; g_return_if_fail (E_IS_ATTACHMENT (attachment)); - g_return_if_fail (G_IS_FILE (destination)); g_return_if_fail (E_IS_FILE_ACTIVITY (file_activity)); + g_return_if_fail (G_IS_FILE (destination)); /* The attachment content is either a GFile (on disk) or a * CamelMimePart (in memory). Each is saved differently. */ @@ -1001,6 +1399,7 @@ e_attachment_save_async (EAttachment *attachment, mime_part = e_attachment_get_mime_part (attachment); g_return_if_fail (source != NULL || mime_part != NULL); + save_context = attachment_save_context_new (attachment, file_activity); cancellable = e_file_activity_get_cancellable (file_activity); progress_callback = e_file_activity_progress; @@ -1017,7 +1416,7 @@ e_attachment_save_async (EAttachment *attachment, G_PRIORITY_DEFAULT, cancellable, progress_callback, file_activity, (GAsyncReadyCallback) attachment_save_file_cb, - g_object_ref (file_activity)); + save_context); /* CamelMimePart can only be decoded to a file synchronously, so * we do this in two stages. Stage one asynchronously opens the @@ -1034,7 +1433,7 @@ e_attachment_save_async (EAttachment *attachment, G_FILE_CREATE_REPLACE_DESTINATION, G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback) attachment_save_part_cb, - g_object_ref (file_activity)); + save_context); } } diff --git a/widgets/misc/e-attachment.h b/widgets/misc/e-attachment.h index a7bb85dd75..d9ef68bf39 100644 --- a/widgets/misc/e-attachment.h +++ b/widgets/misc/e-attachment.h @@ -23,6 +23,7 @@ #define E_ATTACHMENT_H #include +#include #include #include #include @@ -80,14 +81,31 @@ GFileInfo * e_attachment_get_file_info (EAttachment *attachment); CamelMimePart * e_attachment_get_mime_part (EAttachment *attachment); void e_attachment_set_mime_part (EAttachment *attachment, CamelMimePart *mime_part); +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_content_type (EAttachment *attachment); const gchar * e_attachment_get_display_name (EAttachment *attachment); const gchar * e_attachment_get_description (EAttachment *attachment); GIcon * e_attachment_get_icon (EAttachment *attachment); +gboolean e_attachment_get_loading (EAttachment *attachment); const gchar * e_attachment_get_thumbnail_path (EAttachment *attachment); +gboolean e_attachment_get_saving (EAttachment *attachment); guint64 e_attachment_get_size (EAttachment *attachment); gboolean e_attachment_is_image (EAttachment *attachment); gboolean e_attachment_is_rfc822 (EAttachment *attachment); +GList * e_attachment_list_apps (EAttachment *attachment); +GList * e_attachment_list_emblems (EAttachment *attachment); + +/* Asynchronous Operations */ +void e_attachment_launch_async (EAttachment *attachment, + EFileActivity *file_activity, + GAppInfo *app_info); void e_attachment_save_async (EAttachment *attachment, EFileActivity *file_activity, GFile *destination); -- cgit