
001-12-11 Jeffrey Stedfast <fejj@ximian.com> * e-msg-composer-attachment.c (e_msg_composer_attachment_edit): Attach to the parent widget's destroy signal - when that gets destroyed, we need to cancel the editor dialog too. Also connect to our parent window's "hide" signal so that when the composer gets hidden (ie, it's being sent), we also close the dialogs. * e-msg-composer.c (init): Default composer->enable_autosave to TRUE. svn path=/trunk/; revision=15016
824 lines
20 KiB
C
824 lines
20 KiB
C
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
||
/* e-msg-composer-attachment-bar.c
|
||
*
|
||
* Copyright (C) 1999 Ximian, Inc.
|
||
*
|
||
* This program is free software; you can redistribute it and/or
|
||
* modify it under the terms of version 2 of the GNU General Public
|
||
* published by the Free Software Foundation; either version 2 of the
|
||
* License as published by the Free Software Foundation.
|
||
*
|
||
* 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
|
||
* General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public
|
||
* License along with this program; if not, write to the
|
||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||
* Boston, MA 02111-1307, USA.
|
||
*
|
||
* Author: Ettore Perazzoli
|
||
*/
|
||
|
||
#ifdef HAVE_CONFIG_H
|
||
#include <config.h>
|
||
#endif
|
||
|
||
#include <gtk/gtksignal.h>
|
||
#include <libgnome/gnome-defs.h>
|
||
#include <libgnome/gnome-util.h>
|
||
#include <libgnomeui/gnome-app.h>
|
||
#include <libgnomeui/gnome-app-helper.h>
|
||
#include <libgnomeui/gnome-popup-menu.h>
|
||
#include <libgnomeui/gnome-dialog-util.h>
|
||
#include <libgnomeui/gnome-dialog.h>
|
||
#include <glade/glade.h>
|
||
#include <libgnomevfs/gnome-vfs-mime-info.h>
|
||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||
#include <gdk-pixbuf/gdk-pixbuf-loader.h>
|
||
#include <gdk-pixbuf/gnome-canvas-pixbuf.h>
|
||
|
||
#include "e-msg-composer.h"
|
||
#include "e-msg-composer-select-file.h"
|
||
#include "e-msg-composer-attachment.h"
|
||
#include "e-msg-composer-attachment-bar.h"
|
||
|
||
#include "e-icon-list.h"
|
||
|
||
#include <gal/widgets/e-unicode.h>
|
||
|
||
#include "camel/camel-data-wrapper.h"
|
||
#include "camel/camel-stream-fs.h"
|
||
#include "camel/camel-stream-null.h"
|
||
#include "camel/camel-stream-filter.h"
|
||
#include "camel/camel-mime-filter-bestenc.h"
|
||
#include "camel/camel-mime-part.h"
|
||
|
||
|
||
#define ICON_WIDTH 64
|
||
#define ICON_SEPARATORS " /-_"
|
||
#define ICON_SPACING 2
|
||
#define ICON_ROW_SPACING ICON_SPACING
|
||
#define ICON_COL_SPACING ICON_SPACING
|
||
#define ICON_BORDER 2
|
||
#define ICON_TEXT_SPACING 2
|
||
|
||
|
||
static EIconListClass *parent_class = NULL;
|
||
|
||
struct _EMsgComposerAttachmentBarPrivate {
|
||
GList *attachments;
|
||
guint num_attachments;
|
||
|
||
GtkWidget *context_menu;
|
||
GtkWidget *icon_context_menu;
|
||
};
|
||
|
||
|
||
enum {
|
||
CHANGED,
|
||
LAST_SIGNAL
|
||
};
|
||
|
||
static guint signals[LAST_SIGNAL] = { 0 };
|
||
|
||
|
||
static void update (EMsgComposerAttachmentBar *bar);
|
||
|
||
|
||
static gchar *
|
||
size_to_string (gulong size)
|
||
{
|
||
gchar *size_string;
|
||
|
||
/* FIXME: The following should probably go into a separate module, as
|
||
we might have to do the same thing in other places as well. Also,
|
||
I am not sure this will be OK for all the languages. */
|
||
|
||
if (size < 1e3L) {
|
||
if (size == 1)
|
||
size_string = g_strdup (_("1 byte"));
|
||
else
|
||
size_string = g_strdup_printf (_("%u bytes"),
|
||
(guint) size);
|
||
} else {
|
||
gdouble displayed_size;
|
||
|
||
if (size < 1e6L) {
|
||
displayed_size = (gdouble) size / 1.0e3;
|
||
size_string = g_strdup_printf (_("%.1fK"),
|
||
displayed_size);
|
||
} else if (size < 1e9L) {
|
||
displayed_size = (gdouble) size / 1.0e6;
|
||
size_string = g_strdup_printf (_("%.1fM"),
|
||
displayed_size);
|
||
} else {
|
||
displayed_size = (gdouble) size / 1.0e9;
|
||
size_string = g_strdup_printf (_("%.1fG"),
|
||
displayed_size);
|
||
}
|
||
}
|
||
|
||
return size_string;
|
||
}
|
||
|
||
/* Attachment handling functions. */
|
||
|
||
static void
|
||
free_attachment_list (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
GList *p;
|
||
|
||
priv = bar->priv;
|
||
|
||
for (p = priv->attachments; p != NULL; p = p->next)
|
||
gtk_object_unref (GTK_OBJECT (p->data));
|
||
|
||
priv->attachments = NULL;
|
||
}
|
||
|
||
static void
|
||
attachment_changed_cb (EMsgComposerAttachment *attachment,
|
||
gpointer data)
|
||
{
|
||
update (E_MSG_COMPOSER_ATTACHMENT_BAR (data));
|
||
}
|
||
|
||
static void
|
||
add_common (EMsgComposerAttachmentBar *bar,
|
||
EMsgComposerAttachment *attachment)
|
||
{
|
||
g_return_if_fail (attachment != NULL);
|
||
|
||
gtk_signal_connect (GTK_OBJECT (attachment), "changed",
|
||
GTK_SIGNAL_FUNC (attachment_changed_cb),
|
||
bar);
|
||
|
||
bar->priv->attachments = g_list_append (bar->priv->attachments,
|
||
attachment);
|
||
bar->priv->num_attachments++;
|
||
|
||
update (bar);
|
||
|
||
gtk_signal_emit (GTK_OBJECT (bar), signals[CHANGED]);
|
||
}
|
||
|
||
static void
|
||
add_from_mime_part (EMsgComposerAttachmentBar *bar,
|
||
CamelMimePart *part)
|
||
{
|
||
add_common (bar, e_msg_composer_attachment_new_from_mime_part (part));
|
||
}
|
||
|
||
static void
|
||
add_from_file (EMsgComposerAttachmentBar *bar,
|
||
const char *file_name,
|
||
const char *disposition)
|
||
{
|
||
EMsgComposerAttachment *attachment;
|
||
EMsgComposer *composer;
|
||
CamelException ex;
|
||
GtkWidget *dialog;
|
||
|
||
camel_exception_init (&ex);
|
||
attachment = e_msg_composer_attachment_new (file_name, disposition, &ex);
|
||
if (attachment) {
|
||
add_common (bar, attachment);
|
||
} else {
|
||
composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
|
||
|
||
dialog = gnome_error_dialog_parented (camel_exception_get_description (&ex),
|
||
GTK_WINDOW (composer));
|
||
|
||
gnome_dialog_run_and_close (GNOME_DIALOG (dialog));
|
||
|
||
camel_exception_clear (&ex);
|
||
}
|
||
}
|
||
|
||
static void
|
||
remove_attachment (EMsgComposerAttachmentBar *bar,
|
||
EMsgComposerAttachment *attachment)
|
||
{
|
||
bar->priv->attachments = g_list_remove (bar->priv->attachments,
|
||
attachment);
|
||
bar->priv->num_attachments--;
|
||
|
||
gtk_object_unref (GTK_OBJECT (attachment));
|
||
|
||
gtk_signal_emit (GTK_OBJECT (bar), signals[CHANGED]);
|
||
}
|
||
|
||
|
||
/* Icon list contents handling. */
|
||
|
||
static GdkPixbuf *
|
||
pixbuf_for_mime_type (const char *mime_type)
|
||
{
|
||
const char *icon_name;
|
||
char *filename = NULL;
|
||
GdkPixbuf *pixbuf;
|
||
|
||
icon_name = gnome_vfs_mime_get_value (mime_type, "icon-filename");
|
||
if (icon_name) {
|
||
if (*icon_name == '/') {
|
||
pixbuf = gdk_pixbuf_new_from_file (icon_name);
|
||
if (pixbuf)
|
||
return pixbuf;
|
||
}
|
||
|
||
filename = gnome_pixmap_file (icon_name);
|
||
if (!filename) {
|
||
char *fm_icon;
|
||
|
||
fm_icon = g_strdup_printf ("nautilus/%s", icon_name);
|
||
filename = gnome_pixmap_file (fm_icon);
|
||
if (!filename) {
|
||
fm_icon = g_strdup_printf ("mc/%s", icon_name);
|
||
filename = gnome_pixmap_file (fm_icon);
|
||
}
|
||
g_free (fm_icon);
|
||
}
|
||
}
|
||
|
||
if (!filename)
|
||
filename = gnome_pixmap_file ("gnome-unknown.png");
|
||
|
||
pixbuf = gdk_pixbuf_new_from_file (filename);
|
||
g_free (filename);
|
||
|
||
return pixbuf;
|
||
}
|
||
|
||
static void
|
||
update (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
EIconList *icon_list;
|
||
GList *p;
|
||
|
||
priv = bar->priv;
|
||
icon_list = E_ICON_LIST (bar);
|
||
|
||
e_icon_list_freeze (icon_list);
|
||
|
||
e_icon_list_clear (icon_list);
|
||
|
||
/* FIXME could be faster, but we don't care. */
|
||
for (p = priv->attachments; p != NULL; p = p->next) {
|
||
EMsgComposerAttachment *attachment;
|
||
gchar *size_string, *label;
|
||
CamelContentType *content_type;
|
||
GdkPixbuf *pixbuf;
|
||
gboolean image;
|
||
char *desc;
|
||
|
||
attachment = p->data;
|
||
content_type = camel_mime_part_get_content_type (attachment->body);
|
||
/* Get the image out of the attachment
|
||
and create a thumbnail for it */
|
||
image = header_content_type_is (content_type, "image", "*");
|
||
|
||
if (image && attachment->pixbuf_cache == NULL) {
|
||
CamelDataWrapper *wrapper;
|
||
CamelStream *mstream;
|
||
GdkPixbufLoader *loader;
|
||
gboolean error = TRUE;
|
||
char tmp[4096];
|
||
int t;
|
||
|
||
wrapper = camel_medium_get_content_object (CAMEL_MEDIUM (attachment->body));
|
||
mstream = camel_stream_mem_new ();
|
||
|
||
camel_data_wrapper_write_to_stream (wrapper, mstream);
|
||
|
||
camel_stream_reset (mstream);
|
||
|
||
/* Stream image into pixbuf loader */
|
||
loader = gdk_pixbuf_loader_new ();
|
||
do {
|
||
t = camel_stream_read (mstream, tmp, 4096);
|
||
if (t > 0) {
|
||
error = !gdk_pixbuf_loader_write (loader,
|
||
tmp, t);
|
||
if (error) {
|
||
break;
|
||
}
|
||
} else {
|
||
if (camel_stream_eos (mstream))
|
||
break;
|
||
error = TRUE;
|
||
break;
|
||
}
|
||
|
||
} while (!camel_stream_eos (mstream));
|
||
|
||
if (!error) {
|
||
int ratio, width, height;
|
||
|
||
/* Shrink pixbuf */
|
||
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
|
||
width = gdk_pixbuf_get_width (pixbuf);
|
||
height = gdk_pixbuf_get_height (pixbuf);
|
||
if (width >= height) {
|
||
if (width > 48) {
|
||
ratio = width / 48;
|
||
width = 48;
|
||
height = height / ratio;
|
||
}
|
||
} else {
|
||
if (height > 48) {
|
||
ratio = height / 48;
|
||
height = 48;
|
||
width = width / ratio;
|
||
}
|
||
}
|
||
|
||
attachment->pixbuf_cache = gdk_pixbuf_scale_simple
|
||
(pixbuf,
|
||
width,
|
||
height,
|
||
GDK_INTERP_BILINEAR);
|
||
} else {
|
||
g_warning ("GdkPixbufLoader Error");
|
||
image = FALSE;
|
||
}
|
||
|
||
/* Destroy everything */
|
||
gdk_pixbuf_loader_close (loader);
|
||
gtk_object_unref (GTK_OBJECT (loader));
|
||
camel_stream_close (mstream);
|
||
}
|
||
|
||
desc = e_utf8_to_gtk_string (GTK_WIDGET (icon_list), camel_mime_part_get_description (attachment->body));
|
||
if (!desc || *desc == '\0')
|
||
desc = e_utf8_to_gtk_string (GTK_WIDGET (icon_list),
|
||
camel_mime_part_get_filename (attachment->body));
|
||
|
||
if (!desc)
|
||
desc = g_strdup (_("attachment"));
|
||
|
||
if (attachment->size) {
|
||
size_string = size_to_string (attachment->size);
|
||
label = g_strdup_printf ("%s (%s)", desc, size_string);
|
||
g_free (size_string);
|
||
} else
|
||
label = g_strdup (desc);
|
||
|
||
if (image) {
|
||
e_icon_list_append_pixbuf (icon_list, attachment->pixbuf_cache, NULL, label);
|
||
} else {
|
||
char *mime_type;
|
||
|
||
mime_type = header_content_type_simple (content_type);
|
||
pixbuf = pixbuf_for_mime_type (mime_type);
|
||
g_free (mime_type);
|
||
e_icon_list_append_pixbuf (icon_list, pixbuf,
|
||
NULL, label);
|
||
if (pixbuf)
|
||
gdk_pixbuf_unref (pixbuf);
|
||
}
|
||
|
||
g_free (desc);
|
||
g_free (label);
|
||
}
|
||
|
||
e_icon_list_thaw (icon_list);
|
||
}
|
||
|
||
static void
|
||
remove_selected (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EIconList *icon_list;
|
||
EMsgComposerAttachment *attachment;
|
||
GList *attachment_list;
|
||
GList *p;
|
||
gint num;
|
||
|
||
icon_list = E_ICON_LIST (bar);
|
||
|
||
/* Weee! I am especially proud of this piece of cheesy code: it is
|
||
truly awful. But unless one attaches a huge number of files, it
|
||
will not be as greedy as intended. FIXME of course. */
|
||
|
||
attachment_list = NULL;
|
||
p = e_icon_list_get_selection (icon_list);
|
||
for (; p != NULL; p = p->next) {
|
||
num = GPOINTER_TO_INT (p->data);
|
||
attachment = E_MSG_COMPOSER_ATTACHMENT
|
||
(g_list_nth (bar->priv->attachments, num)->data);
|
||
attachment_list = g_list_prepend (attachment_list, attachment);
|
||
}
|
||
|
||
for (p = attachment_list; p != NULL; p = p->next)
|
||
remove_attachment (bar, E_MSG_COMPOSER_ATTACHMENT (p->data));
|
||
|
||
g_list_free (attachment_list);
|
||
|
||
update (bar);
|
||
}
|
||
|
||
static void
|
||
edit_selected (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EIconList *icon_list;
|
||
EMsgComposerAttachment *attachment;
|
||
GList *selection;
|
||
gint num;
|
||
|
||
icon_list = E_ICON_LIST (bar);
|
||
|
||
selection = e_icon_list_get_selection (icon_list);
|
||
num = GPOINTER_TO_INT (selection->data);
|
||
attachment = g_list_nth (bar->priv->attachments, num)->data;
|
||
|
||
e_msg_composer_attachment_edit (attachment, GTK_WIDGET (bar));
|
||
}
|
||
|
||
|
||
/* "Attach" dialog. */
|
||
|
||
static void
|
||
add_from_user (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposer *composer;
|
||
GPtrArray *file_list;
|
||
gboolean is_inline = FALSE;
|
||
int i;
|
||
|
||
composer = E_MSG_COMPOSER (gtk_widget_get_toplevel (GTK_WIDGET (bar)));
|
||
|
||
file_list = e_msg_composer_select_file_attachments (composer, &is_inline);
|
||
if (!file_list)
|
||
return;
|
||
|
||
for (i = 0; i < file_list->len; i++) {
|
||
add_from_file (bar, file_list->pdata[i], is_inline ? "inline" : "attachment");
|
||
g_free (file_list->pdata[i]);
|
||
}
|
||
|
||
g_ptr_array_free (file_list, TRUE);
|
||
}
|
||
|
||
|
||
/* Callbacks. */
|
||
|
||
static void
|
||
add_cb (GtkWidget *widget,
|
||
gpointer data)
|
||
{
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
|
||
|
||
add_from_user (E_MSG_COMPOSER_ATTACHMENT_BAR (data));
|
||
}
|
||
|
||
static void
|
||
properties_cb (GtkWidget *widget,
|
||
gpointer data)
|
||
{
|
||
EMsgComposerAttachmentBar *bar;
|
||
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
|
||
|
||
bar = E_MSG_COMPOSER_ATTACHMENT_BAR (data);
|
||
edit_selected (data);
|
||
}
|
||
|
||
static void
|
||
remove_cb (GtkWidget *widget,
|
||
gpointer data)
|
||
{
|
||
EMsgComposerAttachmentBar *bar;
|
||
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (data));
|
||
|
||
bar = E_MSG_COMPOSER_ATTACHMENT_BAR (data);
|
||
remove_selected (bar);
|
||
}
|
||
|
||
|
||
/* Popup menu handling. */
|
||
|
||
static GnomeUIInfo icon_context_menu_info[] = {
|
||
GNOMEUIINFO_ITEM (N_("Remove"),
|
||
N_("Remove selected items from the attachment list"),
|
||
remove_cb, NULL),
|
||
GNOMEUIINFO_MENU_PROPERTIES_ITEM (properties_cb, NULL),
|
||
GNOMEUIINFO_END
|
||
};
|
||
|
||
static GtkWidget *
|
||
get_icon_context_menu (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
|
||
priv = bar->priv;
|
||
if (priv->icon_context_menu == NULL)
|
||
priv->icon_context_menu = gnome_popup_menu_new
|
||
(icon_context_menu_info);
|
||
|
||
return priv->icon_context_menu;
|
||
}
|
||
|
||
static void
|
||
popup_icon_context_menu (EMsgComposerAttachmentBar *bar,
|
||
gint num,
|
||
GdkEventButton *event)
|
||
{
|
||
GtkWidget *menu;
|
||
|
||
menu = get_icon_context_menu (bar);
|
||
gnome_popup_menu_do_popup (menu, NULL, NULL, event, bar);
|
||
}
|
||
|
||
static GnomeUIInfo context_menu_info[] = {
|
||
GNOMEUIINFO_ITEM (N_("Add attachment..."),
|
||
N_("Attach a file to the message"),
|
||
add_cb, NULL),
|
||
GNOMEUIINFO_END
|
||
};
|
||
|
||
static GtkWidget *
|
||
get_context_menu (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
|
||
priv = bar->priv;
|
||
if (priv->context_menu == NULL)
|
||
priv->context_menu = gnome_popup_menu_new (context_menu_info);
|
||
|
||
return priv->context_menu;
|
||
}
|
||
|
||
static void
|
||
popup_context_menu (EMsgComposerAttachmentBar *bar,
|
||
GdkEventButton *event)
|
||
{
|
||
GtkWidget *menu;
|
||
|
||
menu = get_context_menu (bar);
|
||
gnome_popup_menu_do_popup (menu, NULL, NULL, event, bar);
|
||
}
|
||
|
||
|
||
/* GtkObject methods. */
|
||
|
||
static void
|
||
destroy (GtkObject *object)
|
||
{
|
||
EMsgComposerAttachmentBar *bar;
|
||
|
||
bar = E_MSG_COMPOSER_ATTACHMENT_BAR (object);
|
||
|
||
free_attachment_list (bar);
|
||
|
||
if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
|
||
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
|
||
}
|
||
|
||
|
||
/* GtkWidget methods. */
|
||
|
||
static gint
|
||
button_press_event (GtkWidget *widget,
|
||
GdkEventButton *event)
|
||
{
|
||
EMsgComposerAttachmentBar *bar;
|
||
EIconList *icon_list;
|
||
gint icon_number;
|
||
|
||
bar = E_MSG_COMPOSER_ATTACHMENT_BAR (widget);
|
||
icon_list = E_ICON_LIST (widget);
|
||
|
||
if (event->button != 3)
|
||
return GTK_WIDGET_CLASS (parent_class)->button_press_event
|
||
(widget, event);
|
||
|
||
icon_number = e_icon_list_get_icon_at (icon_list, event->x, event->y);
|
||
|
||
if (icon_number >= 0) {
|
||
e_icon_list_select_icon (icon_list, icon_number);
|
||
popup_icon_context_menu (bar, icon_number, event);
|
||
} else {
|
||
popup_context_menu (bar, event);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/* Initialization. */
|
||
|
||
static void
|
||
class_init (EMsgComposerAttachmentBarClass *class)
|
||
{
|
||
GtkObjectClass *object_class;
|
||
GtkWidgetClass *widget_class;
|
||
EIconListClass *icon_list_class;
|
||
|
||
object_class = GTK_OBJECT_CLASS (class);
|
||
widget_class = GTK_WIDGET_CLASS (class);
|
||
icon_list_class = E_ICON_LIST_CLASS (class);
|
||
|
||
parent_class = gtk_type_class (e_icon_list_get_type ());
|
||
|
||
object_class->destroy = destroy;
|
||
|
||
widget_class->button_press_event = button_press_event;
|
||
|
||
/* Setup signals. */
|
||
|
||
signals[CHANGED] =
|
||
gtk_signal_new ("changed",
|
||
GTK_RUN_LAST,
|
||
object_class->type,
|
||
GTK_SIGNAL_OFFSET (EMsgComposerAttachmentBarClass,
|
||
changed),
|
||
gtk_marshal_NONE__NONE,
|
||
GTK_TYPE_NONE, 0);
|
||
|
||
gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
|
||
}
|
||
|
||
static void
|
||
init (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
guint icon_size, icon_height;
|
||
GdkFont *font;
|
||
|
||
priv = g_new (EMsgComposerAttachmentBarPrivate, 1);
|
||
|
||
priv->attachments = NULL;
|
||
priv->context_menu = NULL;
|
||
priv->icon_context_menu = NULL;
|
||
|
||
priv->num_attachments = 0;
|
||
|
||
bar->priv = priv;
|
||
|
||
/* FIXME partly hardcoded. We should compute height from the font, and
|
||
allow at least 2 lines for every item. */
|
||
icon_size = ICON_WIDTH + ICON_SPACING + ICON_BORDER + ICON_TEXT_SPACING;
|
||
|
||
font = GTK_WIDGET (bar)->style->font;
|
||
icon_height = icon_size + ((font->ascent + font->descent) * 2);
|
||
icon_size += 24;
|
||
|
||
gtk_widget_set_usize (GTK_WIDGET (bar), icon_size * 4, icon_height);
|
||
}
|
||
|
||
|
||
GtkType
|
||
e_msg_composer_attachment_bar_get_type (void)
|
||
{
|
||
static GtkType type = 0;
|
||
|
||
if (type == 0) {
|
||
static const GtkTypeInfo info = {
|
||
"EMsgComposerAttachmentBar",
|
||
sizeof (EMsgComposerAttachmentBar),
|
||
sizeof (EMsgComposerAttachmentBarClass),
|
||
(GtkClassInitFunc) class_init,
|
||
(GtkObjectInitFunc) init,
|
||
/* reserved_1 */ NULL,
|
||
/* reserved_2 */ NULL,
|
||
(GtkClassInitFunc) NULL,
|
||
};
|
||
|
||
type = gtk_type_unique (e_icon_list_get_type (), &info);
|
||
}
|
||
|
||
return type;
|
||
}
|
||
|
||
GtkWidget *
|
||
e_msg_composer_attachment_bar_new (GtkAdjustment *adj)
|
||
{
|
||
EMsgComposerAttachmentBar *new;
|
||
EIconList *icon_list;
|
||
|
||
gdk_rgb_init ();
|
||
gtk_widget_push_visual (gdk_rgb_get_visual ());
|
||
gtk_widget_push_colormap (gdk_rgb_get_cmap ());
|
||
new = gtk_type_new (e_msg_composer_attachment_bar_get_type ());
|
||
gtk_widget_pop_visual ();
|
||
gtk_widget_pop_colormap ();
|
||
|
||
icon_list = E_ICON_LIST (new);
|
||
|
||
e_icon_list_construct (icon_list, ICON_WIDTH, 0);
|
||
|
||
e_icon_list_set_separators (icon_list, ICON_SEPARATORS);
|
||
e_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
|
||
e_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
|
||
e_icon_list_set_icon_border (icon_list, ICON_BORDER);
|
||
e_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
|
||
e_icon_list_set_selection_mode (icon_list, GTK_SELECTION_MULTIPLE);
|
||
|
||
return GTK_WIDGET (new);
|
||
}
|
||
|
||
static void
|
||
attach_to_multipart (CamelMultipart *multipart,
|
||
EMsgComposerAttachment *attachment,
|
||
const char *default_charset)
|
||
{
|
||
CamelContentType *content_type;
|
||
|
||
content_type = camel_mime_part_get_content_type (attachment->body);
|
||
|
||
if (!header_content_type_is (content_type, "multipart", "*")) {
|
||
if (header_content_type_is (content_type, "text", "*")) {
|
||
CamelMimePartEncodingType encoding;
|
||
CamelStreamFilter *filtered_stream;
|
||
CamelMimeFilterBestenc *bestenc;
|
||
CamelStream *stream;
|
||
char *type;
|
||
|
||
stream = camel_stream_null_new ();
|
||
filtered_stream = camel_stream_filter_new_with_stream (stream);
|
||
bestenc = camel_mime_filter_bestenc_new (CAMEL_BESTENC_GET_ENCODING);
|
||
camel_stream_filter_add (filtered_stream, CAMEL_MIME_FILTER (bestenc));
|
||
camel_object_unref (CAMEL_OBJECT (stream));
|
||
|
||
camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (attachment->body),
|
||
CAMEL_STREAM (filtered_stream));
|
||
|
||
encoding = camel_mime_filter_bestenc_get_best_encoding (bestenc, CAMEL_BESTENC_8BIT);
|
||
camel_mime_part_set_encoding (attachment->body, encoding);
|
||
|
||
/* looks kinda nasty, but this is how ya have to do it */
|
||
header_content_type_set_param (content_type, "charset", default_charset);
|
||
type = header_content_type_format (content_type);
|
||
camel_mime_part_set_content_type (attachment->body, type);
|
||
g_free (type);
|
||
|
||
camel_object_unref (CAMEL_OBJECT (bestenc));
|
||
camel_object_unref (CAMEL_OBJECT (filtered_stream));
|
||
} else if (!header_content_type_is (content_type, "message", "*")) {
|
||
camel_mime_part_set_encoding (attachment->body,
|
||
CAMEL_MIME_PART_ENCODING_BASE64);
|
||
}
|
||
}
|
||
|
||
camel_multipart_add_part (multipart, attachment->body);
|
||
}
|
||
|
||
void
|
||
e_msg_composer_attachment_bar_to_multipart (EMsgComposerAttachmentBar *bar,
|
||
CamelMultipart *multipart,
|
||
const char *default_charset)
|
||
{
|
||
EMsgComposerAttachmentBarPrivate *priv;
|
||
GList *p;
|
||
|
||
g_return_if_fail (bar != NULL);
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar));
|
||
g_return_if_fail (multipart != NULL);
|
||
g_return_if_fail (CAMEL_IS_MULTIPART (multipart));
|
||
|
||
priv = bar->priv;
|
||
|
||
for (p = priv->attachments; p != NULL; p = p->next) {
|
||
EMsgComposerAttachment *attachment;
|
||
|
||
attachment = E_MSG_COMPOSER_ATTACHMENT (p->data);
|
||
attach_to_multipart (multipart, attachment, default_charset);
|
||
}
|
||
}
|
||
|
||
|
||
guint
|
||
e_msg_composer_attachment_bar_get_num_attachments (EMsgComposerAttachmentBar *bar)
|
||
{
|
||
g_return_val_if_fail (bar != NULL, 0);
|
||
g_return_val_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar), 0);
|
||
|
||
return bar->priv->num_attachments;
|
||
}
|
||
|
||
|
||
void
|
||
e_msg_composer_attachment_bar_attach (EMsgComposerAttachmentBar *bar,
|
||
const gchar *file_name)
|
||
{
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar));
|
||
|
||
if (file_name == NULL)
|
||
add_from_user (bar);
|
||
else
|
||
add_from_file (bar, file_name, "attachment");
|
||
}
|
||
|
||
void
|
||
e_msg_composer_attachment_bar_attach_mime_part (EMsgComposerAttachmentBar *bar,
|
||
CamelMimePart *part)
|
||
{
|
||
g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT_BAR (bar));
|
||
|
||
add_from_mime_part (bar, part);
|
||
}
|