aboutsummaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
authorEttore Perazzoli <ettore@src.gnome.org>1999-11-06 07:06:09 +0800
committerEttore Perazzoli <ettore@src.gnome.org>1999-11-06 07:06:09 +0800
commitb681ec2b9a98684ef821f9b6fbdb9a231a58d4b5 (patch)
tree6dc964528b9db296aa1dfedde9a2b2122fd0db8e /widgets
parentc8fce201dc8b14505f2e0387689947922e08f956 (diff)
downloadgsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.gz
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.zst
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.zip
Here is my initial Evolution work: message composition widget and some
installation fixes for Camel. svn path=/trunk/; revision=1369
Diffstat (limited to 'widgets')
-rw-r--r--widgets/.cvsignore6
-rw-r--r--widgets/ChangeLog23
-rw-r--r--widgets/Makefile.am36
-rw-r--r--widgets/e-msg-composer-address-entry.c142
-rw-r--r--widgets/e-msg-composer-address-entry.h61
-rw-r--r--widgets/e-msg-composer-attachment-bar.c602
-rw-r--r--widgets/e-msg-composer-attachment-bar.h74
-rw-r--r--widgets/e-msg-composer-attachment.c461
-rw-r--r--widgets/e-msg-composer-attachment.glade290
-rw-r--r--widgets/e-msg-composer-attachment.h71
-rw-r--r--widgets/e-msg-composer-hdrs.c196
-rw-r--r--widgets/e-msg-composer-hdrs.h67
-rw-r--r--widgets/e-msg-composer.c441
-rw-r--r--widgets/e-msg-composer.glade576
-rw-r--r--widgets/e-msg-composer.h85
-rw-r--r--widgets/e-table/.cvsignore6
-rw-r--r--widgets/e-table/ChangeLog23
-rw-r--r--widgets/e-table/Makefile.am36
-rw-r--r--widgets/table/.cvsignore6
19 files changed, 3188 insertions, 14 deletions
diff --git a/widgets/.cvsignore b/widgets/.cvsignore
new file mode 100644
index 0000000000..09980ae6ba
--- /dev/null
+++ b/widgets/.cvsignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
diff --git a/widgets/ChangeLog b/widgets/ChangeLog
index e8d0c8e9ed..77a6c36c61 100644
--- a/widgets/ChangeLog
+++ b/widgets/ChangeLog
@@ -1,3 +1,26 @@
+1999-11-05 Ettore Perazzoli <ettore@gnu.org>
+
+ * Makefile.am: Compile the new files in a `libevolutionwidgets'
+ library.
+ (CPPFLAGS): #define `E_GUIDIR'.
+
+ * e-msg-composer.c, e-msg-composer.h: New files implementing an
+ initial version of the Evolution message composer widget.
+
+ * e-msg-composer-address-entry.c, e-msg-composer-address-entry.h:
+ New files implementing a GtkEntry customized for entering email
+ address lists.
+
+ * e-msg-composer-attachment-bar.c, e-msg-composer-attachment-bar.h:
+ New files implementing a widget for editing mail attachments.
+
+ * e-msg-composer-attachment.c, e-msg-composer-attachment.h: New
+ files implementing file attachment objects for the message
+ composer.
+
+ * e-msg-composer-hdrs.c, e-msg-composer-hdrs.h: New files
+ implementing a widget for editing of email message headers.
+
1999-10-31 Miguel de Icaza <miguel@gnu.org>
* widgets/e-table-column.c, e-table-column.h: New file, implements the
diff --git a/widgets/Makefile.am b/widgets/Makefile.am
index d6aa94fb90..35d1bc64a4 100644
--- a/widgets/Makefile.am
+++ b/widgets/Makefile.am
@@ -1,7 +1,29 @@
-noinst_LIBRARIES = \
- e-table-simple.c \
- e-table-simple.h \
- e-table-model.c \
- e-table-model.h \
- e-table-column-model.c \
- e-table-column-model.h \
+guidir = $(datadir)/evolution/gui
+
+gui_DATA = \
+ e-msg-composer-attachment.glade \
+ e-msg-composer.glade
+
+INCLUDES = \
+ -I$(top_srcdir)/camel \
+ -I$(top_builddir)/camel \
+ $(GNOME_INCLUDEDIR)
+
+CPPFLAGS = \
+ -DE_GUIDIR=\"$(guidir)\"
+
+noinst_LTLIBRARIES = \
+ libevolutionwidgets.la
+
+libevolutionwidgets_la_SOURCES = \
+ e-msg-composer-address-entry.c \
+ e-msg-composer-address-entry.h \
+ e-msg-composer-attachment-bar.c \
+ e-msg-composer-attachment-bar.h \
+ e-msg-composer-attachment.c \
+ e-msg-composer-attachment.h \
+ e-msg-composer-hdrs.c \
+ e-msg-composer-hdrs.h \
+ e-msg-composer.c \
+ e-msg-composer.h
+
diff --git a/widgets/e-msg-composer-address-entry.c b/widgets/e-msg-composer-address-entry.c
new file mode 100644
index 0000000000..071730eef2
--- /dev/null
+++ b/widgets/e-msg-composer-address-entry.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer-address-entry.c
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+/* This is a custom GtkEntry for entering address lists. For now, it does not
+ have any fancy features, but in the future we might want to make it
+ cooler. */
+
+#include <gnome.h>
+
+#include "e-msg-composer-address-entry.h"
+
+
+static GtkEntryClass *parent_class = NULL;
+
+
+/* Initialization. */
+
+static void
+class_init (EMsgComposerAddressEntryClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_entry_get_type ());
+}
+
+static void
+init (EMsgComposerAddressEntry *msg_composer_address_entry)
+{
+}
+
+GtkType
+e_msg_composer_address_entry_get_type (void)
+{
+ static GtkType type = 0;
+
+ if (type == 0) {
+ static const GtkTypeInfo info = {
+ "EMsgComposerAddressEntry",
+ sizeof (EMsgComposerAddressEntry),
+ sizeof (EMsgComposerAddressEntryClass),
+ (GtkClassInitFunc) class_init,
+ (GtkObjectInitFunc) init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ type = gtk_type_unique (gtk_entry_get_type (), &info);
+ }
+
+ return type;
+}
+
+
+GtkWidget *
+e_msg_composer_address_entry_new (void)
+{
+ GtkWidget *new;
+
+ new = gtk_type_new (e_msg_composer_address_entry_get_type ());
+
+ return new;
+}
+
+
+/**
+ * e_msg_composer_address_entry_get_addresses:
+ * @entry: An address entry widget
+ *
+ * Retrieve the list of addresses stored in @entry.
+ *
+ * Return value: A GList of pointers to strings representing the addresses.
+ * Notice that the strings must be freed by the caller when not needed anymore.
+ **/
+GList *
+e_msg_composer_address_entry_get_addresses (EMsgComposerAddressEntry *entry)
+{
+ GList *list;
+ const gchar *s;
+ const gchar *p, *oldp;
+ gboolean in_quotes;
+
+ s = gtk_entry_get_text (GTK_ENTRY (entry));
+
+ in_quotes = FALSE;
+ list = NULL;
+
+ p = s;
+ oldp = s;
+
+ while (1) {
+ if (*p == '"') {
+ in_quotes = ! in_quotes;
+ p++;
+ } else if ((! in_quotes && *p == ',') || *p == 0) {
+ if (p != oldp) {
+ gchar *new_addr;
+
+ new_addr = g_strndup (oldp, p - oldp);
+ new_addr = g_strstrip (new_addr);
+ if (*new_addr != '\0')
+ list = g_list_prepend (list, new_addr);
+ else
+ g_free (new_addr);
+ }
+
+ while (*p == ',' || *p == ' ' || *p == '\t')
+ p++;
+
+ if (*p == 0)
+ break;
+
+ oldp = p;
+ } else {
+ p++;
+ }
+ }
+
+ return g_list_reverse (list);
+}
diff --git a/widgets/e-msg-composer-address-entry.h b/widgets/e-msg-composer-address-entry.h
new file mode 100644
index 0000000000..d4ab46797d
--- /dev/null
+++ b/widgets/e-msg-composer-address-entry.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer-address-entry.h
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#ifndef __E_MSG_COMPOSER_ADDRESS_ENTRY_H__
+#define __E_MSG_COMPOSER_ADDRESS_ENTRY_H__
+
+#include <gnome.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_MSG_COMPOSER_ADDRESS_ENTRY (e_msg_composer_address_entry_get_type ())
+#define E_MSG_COMPOSER_ADDRESS_ENTRY(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MSG_COMPOSER_ADDRESS_ENTRY, EMsgComposerAddressEntry))
+#define E_MSG_COMPOSER_ADDRESS_ENTRY_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER_ADDRESS_ENTRY, EMsgComposerAddressEntryClass))
+#define E_IS_MSG_COMPOSER_ADDRESS_ENTRY(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MSG_COMPOSER_ADDRESS_ENTRY))
+#define E_IS_MSG_COMPOSER_ADDRESS_ENTRY_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER_ADDRESS_ENTRY))
+
+
+typedef struct _EMsgComposerAddressEntry EMsgComposerAddressEntry;
+typedef struct _EMsgComposerAddressEntryClass EMsgComposerAddressEntryClass;
+
+struct _EMsgComposerAddressEntry {
+ GtkEntry parent;
+};
+
+struct _EMsgComposerAddressEntryClass {
+ GtkEntryClass parent_class;
+};
+
+
+GtkType e_msg_composer_address_entry_get_type (void);
+GtkWidget *e_msg_composer_address_entry_new (void);
+GList *e_msg_composer_address_entry_get_addresses (EMsgComposerAddressEntry *entry);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __E_MSG_COMPOSER_ADDRESS_ENTRY_H__ */
diff --git a/widgets/e-msg-composer-attachment-bar.c b/widgets/e-msg-composer-attachment-bar.c
new file mode 100644
index 0000000000..25cc2ff138
--- /dev/null
+++ b/widgets/e-msg-composer-attachment-bar.c
@@ -0,0 +1,602 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer-attachment-bar.c
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#include <gnome.h>
+#include <glade/glade.h>
+
+#include "e-msg-composer-attachment.h"
+#include "e-msg-composer-attachment-bar.h"
+
+
+#define ICON_WIDTH 64
+#define ICON_SEPARATORS " /-_."
+#define ICON_SPACING 2
+#define ICON_ROW_SPACING ICON_SPACING
+#define ICON_COL_SPACING ICON_SPACING
+#define ICON_BORDER 2
+#define ICON_TEXT_SPACING 2
+
+
+static GnomeIconListClass *parent_class = NULL;
+
+struct _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);
+
+
+/* Sorting. */
+
+static gint
+attachment_sort_func (gconstpointer a, gconstpointer b)
+{
+ const EMsgComposerAttachment *attachment_a, *attachment_b;
+
+ attachment_a = (EMsgComposerAttachment *) a;
+ attachment_b = (EMsgComposerAttachment *) b;
+
+ return strcmp (attachment_a->description, attachment_b->description);
+}
+
+static void
+sort (EMsgComposerAttachmentBar *bar)
+{
+ EMsgComposerAttachmentBarPrivate *priv;
+
+ priv = bar->priv;
+
+ priv->attachments = g_list_sort (priv->attachments,
+ attachment_sort_func);
+}
+
+
+/* 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));
+}
+
+static void
+attachment_changed_cb (EMsgComposerAttachment *attachment,
+ gpointer data)
+{
+ update (E_MSG_COMPOSER_ATTACHMENT_BAR (data));
+}
+
+static void
+add_from_file (EMsgComposerAttachmentBar *bar,
+ const gchar *file_name)
+{
+ EMsgComposerAttachment *attachment;
+
+ attachment = e_msg_composer_attachment_new (file_name);
+
+ 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++;
+
+ sort (bar);
+ update (bar);
+
+ gtk_signal_emit (GTK_OBJECT (bar), signals[CHANGED]);
+}
+
+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 void
+update (EMsgComposerAttachmentBar *bar)
+{
+ EMsgComposerAttachmentBarPrivate *priv;
+ GnomeIconList *icon_list;
+ GList *p;
+
+ priv = bar->priv;
+ icon_list = GNOME_ICON_LIST (bar);
+
+ gnome_icon_list_freeze (icon_list);
+
+ gnome_icon_list_clear (icon_list);
+
+ /* FIXME could be faster, but we don't care. */
+
+ for (p = priv->attachments; p != NULL; p = p->next) {
+ EMsgComposerAttachment *attachment;
+ const gchar *icon_name;
+
+ attachment = p->data;
+ icon_name = gnome_mime_get_value (attachment->mime_type,
+ "icon-filename");
+
+ /* FIXME we need some better default icon. */
+ if (icon_name == NULL)
+ icon_name = gnome_mime_get_value ("text/plain",
+ "icon-filename");
+
+ gnome_icon_list_append (icon_list, icon_name,
+ attachment->description);
+ }
+
+ gnome_icon_list_thaw (icon_list);
+}
+
+static void
+remove_selected (EMsgComposerAttachmentBar *bar)
+{
+ GnomeIconList *icon_list;
+ EMsgComposerAttachment *attachment;
+ gint num;
+
+ icon_list = GNOME_ICON_LIST (bar);
+ num = GPOINTER_TO_INT (icon_list->selection->data);
+
+ /* FIXME do this with icon data. */
+
+ attachment = E_MSG_COMPOSER_ATTACHMENT
+ (g_list_nth (bar->priv->attachments, num)->data);
+
+ remove_attachment (bar, attachment);
+ update (bar);
+}
+
+static void
+edit_selected (EMsgComposerAttachmentBar *bar)
+{
+ GnomeIconList *icon_list;
+ EMsgComposerAttachment *attachment;
+ gint num;
+
+ icon_list = GNOME_ICON_LIST (bar);
+
+ num = GPOINTER_TO_INT (icon_list->selection->data);
+ attachment = g_list_nth (bar->priv->attachments, num)->data;
+
+ e_msg_composer_attachment_edit (attachment, GTK_WIDGET (bar));
+}
+
+
+/* "Attach" dialog. */
+
+static void
+attach_cb (GtkWidget *widget,
+ gpointer data)
+{
+ EMsgComposerAttachmentBar *bar;
+ GtkWidget *file_selection;
+ const gchar *file_name;
+
+ file_selection = gtk_widget_get_toplevel (widget);
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (data);
+
+ file_name = gtk_file_selection_get_filename
+ (GTK_FILE_SELECTION (file_selection));
+ add_from_file (bar, file_name);
+
+ gtk_widget_hide (file_selection);
+}
+
+static void
+add_from_user (EMsgComposerAttachmentBar *bar)
+{
+ GtkWidget *file_selection;
+ GtkWidget *cancel_button;
+ GtkWidget *ok_button;
+
+ file_selection = gtk_file_selection_new (_("Add attachment"));
+ gtk_window_set_position (GTK_WINDOW (file_selection),
+ GTK_WIN_POS_MOUSE);
+
+ ok_button = GTK_FILE_SELECTION (file_selection)->ok_button;
+ gtk_signal_connect (GTK_OBJECT (ok_button),
+ "clicked", GTK_SIGNAL_FUNC (attach_cb), bar);
+
+ cancel_button = GTK_FILE_SELECTION (file_selection)->cancel_button;
+ gtk_signal_connect_object (GTK_OBJECT (cancel_button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_hide),
+ GTK_OBJECT (file_selection));
+
+ gtk_widget_show (GTK_WIDGET (file_selection));
+}
+
+
+/* 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 this item 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);
+}
+
+
+/* GtkWidget methods. */
+
+static gint
+button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ EMsgComposerAttachmentBar *bar;
+ GnomeIconList *icon_list;
+ gint icon_number;
+
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (widget);
+ icon_list = GNOME_ICON_LIST (widget);
+
+ if (event->button != 3)
+ return GTK_WIDGET_CLASS (parent_class)->button_press_event
+ (widget, event);
+
+ icon_number = gnome_icon_list_get_icon_at (icon_list,
+ event->x, event->y);
+
+ if (icon_number >= 0) {
+ gnome_icon_list_select_icon (icon_list, icon_number);
+ popup_icon_context_menu (bar, icon_number, event);
+ } else {
+ popup_context_menu (bar, event);
+ }
+
+ return TRUE;
+}
+
+
+/* GnomeIconList methods. */
+
+static gboolean
+text_changed (GnomeIconList *gil,
+ gint num,
+ const gchar *new_text)
+{
+ EMsgComposerAttachmentBar *bar;
+ EMsgComposerAttachment *attachment;
+ GList *p;
+
+ bar = E_MSG_COMPOSER_ATTACHMENT_BAR (gil);
+ p = g_list_nth (bar->priv->attachments, num);
+ attachment = p->data;
+
+ g_free (attachment->description);
+ attachment->description = g_strdup (new_text);
+
+ return TRUE;
+}
+
+
+/* Initialization. */
+
+static void
+class_init (EMsgComposerAttachmentBarClass *class)
+{
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GnomeIconListClass *icon_list_class;
+
+ object_class = GTK_OBJECT_CLASS (class);
+ widget_class = GTK_WIDGET_CLASS (class);
+ icon_list_class = GNOME_ICON_LIST_CLASS (class);
+
+ parent_class = gtk_type_class (gnome_icon_list_get_type ());
+
+ object_class->destroy = destroy;
+
+ widget_class->button_press_event = button_press_event;
+
+ icon_list_class->text_changed = text_changed;
+
+ /* 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;
+
+ 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 + 24;
+
+ gtk_widget_set_usize (GTK_WIDGET (bar), icon_size * 4, icon_size);
+}
+
+
+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 (gnome_icon_list_get_type (), &info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_msg_composer_attachment_bar_new (GtkAdjustment *adj)
+{
+ EMsgComposerAttachmentBar *new;
+ GnomeIconList *icon_list;
+
+ gtk_widget_push_visual (gdk_imlib_get_visual ());
+ gtk_widget_push_colormap (gdk_imlib_get_colormap ());
+ new = gtk_type_new (e_msg_composer_attachment_bar_get_type ());
+ gtk_widget_pop_visual ();
+ gtk_widget_pop_colormap ();
+
+ icon_list = GNOME_ICON_LIST (new);
+
+ gnome_icon_list_construct (icon_list, ICON_WIDTH, adj,
+ GNOME_ICON_LIST_IS_EDITABLE);
+
+ gnome_icon_list_set_separators (icon_list, ICON_SEPARATORS);
+ gnome_icon_list_set_row_spacing (icon_list, ICON_ROW_SPACING);
+ gnome_icon_list_set_col_spacing (icon_list, ICON_COL_SPACING);
+ gnome_icon_list_set_icon_border (icon_list, ICON_BORDER);
+ gnome_icon_list_set_text_spacing (icon_list, ICON_TEXT_SPACING);
+ gnome_icon_list_set_selection_mode (icon_list, GTK_SELECTION_SINGLE);
+
+ return GTK_WIDGET (new);
+}
+
+
+static void
+attach_to_multipart (CamelMultipart *multipart,
+ EMsgComposerAttachment *attachment)
+{
+ CamelMimeBodyPart *part;
+
+ /* FIXME encoding etc. etc. ? */
+ /* FIXME I am not sure how to add an attachment through the Camel
+ API. :-/ */
+
+ part = camel_mime_body_part_new ();
+ camel_mime_part_set_disposition (CAMEL_MIME_PART (part), "attachment");
+ camel_mime_part_set_filename (CAMEL_MIME_PART (part),
+ g_strdup (g_basename (attachment->file_name)));
+ camel_mime_part_set_description (CAMEL_MIME_PART (part),
+ g_strdup (attachment->description));
+ camel_data_wrapper_set_mime_type (CAMEL_DATA_WRAPPER (part),
+ g_strdup (attachment->mime_type));
+}
+
+void
+e_msg_composer_attachment_bar_to_multipart (EMsgComposerAttachmentBar *bar,
+ CamelMultipart *multipart)
+{
+ 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 (IS_CAMEL_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);
+ }
+}
+
+
+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 (bar != NULL);
+ 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);
+}
diff --git a/widgets/e-msg-composer-attachment-bar.h b/widgets/e-msg-composer-attachment-bar.h
new file mode 100644
index 0000000000..803b51a954
--- /dev/null
+++ b/widgets/e-msg-composer-attachment-bar.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* msg-composer-attachment-bar.h
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#ifndef __E_MSG_COMPOSER_ATTACHMENT_BAR_H__
+#define __E_MSG_COMPOSER_ATTACHMENT_BAR_H__
+
+#include <gnome.h>
+#include <camel/camel-multipart.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_MSG_COMPOSER_ATTACHMENT_BAR \
+ (e_msg_composer_attachment_bar_get_type ())
+#define E_MSG_COMPOSER_ATTACHMENT_BAR(obj) \
+ (GTK_CHECK_CAST ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT_BAR, EMsgComposerAttachmentBar))
+#define E_MSG_COMPOSER_ATTACHMENT_BAR_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER_ATTACHMENT_BAR, EMsgComposerAttachmentBarClass))
+#define E_IS_MSG_COMPOSER_ATTACHMENT_BAR(obj) \
+ (GTK_CHECK_TYPE ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT_BAR))
+#define E_IS_MSG_COMPOSER_ATTACHMENT_BAR_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT_BAR))
+
+
+typedef struct _EMsgComposerAttachmentBarPrivate EMsgComposerAttachmentBarPrivate;
+
+struct _EMsgComposerAttachmentBar {
+ GnomeIconList parent;
+
+ EMsgComposerAttachmentBarPrivate *priv;
+};
+typedef struct _EMsgComposerAttachmentBar EMsgComposerAttachmentBar;
+
+struct _EMsgComposerAttachmentBarClass {
+ GnomeIconListClass parent_class;
+
+ void (* changed) (EMsgComposerAttachmentBar *bar);
+};
+typedef struct _EMsgComposerAttachmentBarClass EMsgComposerAttachmentBarClass;
+
+
+GtkType e_msg_composer_attachment_bar_get_type (void);
+GtkWidget *e_msg_composer_attachment_bar_new (GtkAdjustment *adj);
+void e_msg_composer_attachment_bar_to_multipart (EMsgComposerAttachmentBar *bar, CamelMultipart *multipart);
+guint e_msg_composer_attachment_bar_get_num_attachments (EMsgComposerAttachmentBar *bar);
+void e_msg_composer_attachment_bar_attach (EMsgComposerAttachmentBar *bar, const gchar *file_name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __E_MSG_COMPOSER_ATTACHMENT_BAR_H__ */
diff --git a/widgets/e-msg-composer-attachment.c b/widgets/e-msg-composer-attachment.c
new file mode 100644
index 0000000000..9e0f7e218e
--- /dev/null
+++ b/widgets/e-msg-composer-attachment.c
@@ -0,0 +1,461 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer-attachment.c
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#include <gnome.h>
+#include "e-msg-composer-attachment.h"
+
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+guint signals[LAST_SIGNAL] = { 0 };
+
+static GtkObjectClass *parent_class = NULL;
+
+
+/* Utility functions. */
+
+static const gchar *
+get_mime_type (const gchar *file_name)
+{
+ const gchar *mime_type;
+
+ mime_type = gnome_mime_type_of_file (file_name);
+ if (mime_type == NULL)
+ mime_type = "application/octet-stream";
+
+ return mime_type;
+}
+
+static void
+init_mime_type (EMsgComposerAttachment *attachment)
+{
+ attachment->mime_type = g_strdup (get_mime_type (attachment->file_name));
+}
+
+static void
+set_mime_type (EMsgComposerAttachment *attachment)
+{
+ g_free (attachment->mime_type);
+ init_mime_type (attachment);
+}
+
+static void
+changed (EMsgComposerAttachment *attachment)
+{
+ gtk_signal_emit (GTK_OBJECT (attachment), signals[CHANGED]);
+}
+
+
+/* GtkObject methods. */
+
+static void
+destroy (GtkObject *object)
+{
+ EMsgComposerAttachment *attachment;
+
+ attachment = E_MSG_COMPOSER_ATTACHMENT (object);
+
+ g_free (attachment->file_name);
+ g_free (attachment->description);
+ g_free (attachment->mime_type);
+}
+
+
+/* Signals. */
+
+static void
+real_changed (EMsgComposerAttachment *msg_composer_attachment)
+{
+ g_return_if_fail (msg_composer_attachment != NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT (msg_composer_attachment));
+
+}
+
+
+static void
+class_init (EMsgComposerAttachmentClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_object_get_type ());
+
+ object_class->destroy = destroy;
+
+ signals[CHANGED] = gtk_signal_new ("changed",
+ GTK_RUN_FIRST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET
+ (EMsgComposerAttachmentClass,
+ changed),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+
+ gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+
+ klass->changed = real_changed;
+}
+
+static void
+init (EMsgComposerAttachment *msg_composer_attachment)
+{
+}
+
+GtkType
+e_msg_composer_attachment_get_type (void)
+{
+ static GtkType type = 0;
+
+ if (type == 0) {
+ static const GtkTypeInfo info = {
+ "EMsgComposerAttachment",
+ sizeof (EMsgComposerAttachment),
+ sizeof (EMsgComposerAttachmentClass),
+ (GtkClassInitFunc) class_init,
+ (GtkObjectInitFunc) init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ type = gtk_type_unique (gtk_object_get_type (), &info);
+ }
+
+ return type;
+}
+
+
+/**
+ * e_msg_composer_attachment_new:
+ * @file_name:
+ *
+ * Return value:
+ **/
+EMsgComposerAttachment *
+e_msg_composer_attachment_new (const gchar *file_name)
+{
+ EMsgComposerAttachment *new;
+
+ g_return_val_if_fail (file_name != NULL, NULL);
+
+ new = gtk_type_new (e_msg_composer_attachment_get_type ());
+
+ new->editor_gui = NULL;
+
+ new->file_name = g_strdup (file_name);
+ new->description = g_strdup (g_basename (new->file_name));
+
+ init_mime_type (new);
+
+ return new;
+}
+
+
+/* The attachment property dialog. */
+
+struct _DialogData {
+ GtkWidget *dialog;
+ GtkEntry *file_name_entry;
+ GtkEntry *description_entry;
+ GtkEntry *mime_type_entry;
+ GtkWidget *browse_widget;
+ EMsgComposerAttachment *attachment;
+};
+typedef struct _DialogData DialogData;
+
+static void
+destroy_dialog_data (DialogData *data)
+{
+ if (data->browse_widget != NULL)
+ gtk_widget_destroy (data->browse_widget);
+ g_free (data);
+}
+
+static void
+update_mime_type (DialogData *data)
+{
+ const gchar *mime_type;
+ const gchar *file_name;
+
+ file_name = gtk_entry_get_text (data->file_name_entry);
+ mime_type = get_mime_type (file_name);
+
+ gtk_entry_set_text (data->mime_type_entry, mime_type);
+}
+
+static void
+browse_ok_cb (GtkWidget *widget,
+ gpointer data)
+{
+ GtkWidget *file_selection;
+ DialogData *dialog_data;
+ const gchar *file_name;
+
+ dialog_data = (DialogData *) data;
+ file_selection = gtk_widget_get_toplevel (widget);
+
+ file_name = gtk_file_selection_get_filename
+ (GTK_FILE_SELECTION (file_selection));
+
+ gtk_entry_set_text (dialog_data->file_name_entry, file_name);
+
+ update_mime_type (dialog_data);
+
+ gtk_widget_hide (file_selection);
+}
+
+static void
+browse (DialogData *data)
+{
+ if (data->browse_widget == NULL) {
+ GtkWidget *file_selection;
+ GtkWidget *cancel_button;
+ GtkWidget *ok_button;
+
+ file_selection
+ = gtk_file_selection_new (_("Select attachment"));
+ gtk_window_set_position (GTK_WINDOW (file_selection),
+ GTK_WIN_POS_MOUSE);
+ gtk_window_set_transient_for (GTK_WINDOW (file_selection),
+ GTK_WINDOW (data->dialog));
+
+ ok_button = GTK_FILE_SELECTION (file_selection)->ok_button;
+ gtk_signal_connect (GTK_OBJECT (ok_button),
+ "clicked", GTK_SIGNAL_FUNC (browse_ok_cb),
+ data);
+
+ cancel_button
+ = GTK_FILE_SELECTION (file_selection)->cancel_button;
+ gtk_signal_connect_object (GTK_OBJECT (cancel_button),
+ "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_hide),
+ GTK_OBJECT (file_selection));
+
+ data->browse_widget = file_selection;
+ }
+
+ gtk_widget_show (GTK_WIDGET (data->browse_widget));
+}
+
+static void
+set_entry (GladeXML *xml,
+ const gchar *widget_name,
+ const gchar *value)
+{
+ GtkEntry *entry;
+
+ entry = GTK_ENTRY (glade_xml_get_widget (xml, widget_name));
+ if (entry == NULL)
+ g_warning ("Entry for `%s' not found.", widget_name);
+ gtk_entry_set_text (entry, value);
+}
+
+static void
+connect_entry_changed (GladeXML *gui,
+ const gchar *name,
+ GtkSignalFunc func,
+ gpointer data)
+{
+ GtkWidget *widget;
+
+ widget = glade_xml_get_widget (gui, name);
+ gtk_signal_connect (GTK_OBJECT (widget), "changed", func, data);
+}
+
+static void
+connect_widget (GladeXML *gui,
+ const gchar *name,
+ const gchar *signal_name,
+ GtkSignalFunc func,
+ gpointer data)
+{
+ GtkWidget *widget;
+
+ widget = glade_xml_get_widget (gui, name);
+ gtk_signal_connect (GTK_OBJECT (widget), signal_name, func, data);
+}
+
+static void
+apply (DialogData *data)
+{
+ EMsgComposerAttachment *attachment;
+
+ attachment = data->attachment;
+
+ g_free (attachment->file_name);
+ attachment->file_name = g_strdup (gtk_entry_get_text
+ (data->file_name_entry));
+
+ g_free (attachment->description);
+ attachment->description = g_strdup (gtk_entry_get_text
+ (data->description_entry));
+
+ g_free (attachment->mime_type);
+ attachment->mime_type = g_strdup (gtk_entry_get_text
+ (data->mime_type_entry));
+
+ changed (attachment);
+}
+
+static void
+entry_changed_cb (GtkWidget *widget, gpointer data)
+{
+ DialogData *dialog_data;
+ GladeXML *gui;
+ GtkWidget *apply_button;
+
+ dialog_data = (DialogData *) data;
+ gui = dialog_data->attachment->editor_gui;
+
+ apply_button = glade_xml_get_widget (gui, "apply_button");
+ gtk_widget_set_sensitive (apply_button, TRUE);
+}
+
+static void
+close_cb (GtkWidget *widget,
+ gpointer data)
+{
+ EMsgComposerAttachment *attachment;
+ DialogData *dialog_data;
+
+ dialog_data = (DialogData *) data;
+ attachment = dialog_data->attachment;
+
+ gtk_widget_destroy (glade_xml_get_widget (attachment->editor_gui,
+ "dialog"));
+ gtk_object_unref (GTK_OBJECT (attachment->editor_gui));
+ attachment->editor_gui = NULL;
+
+ destroy_dialog_data (dialog_data);
+}
+
+static void
+apply_cb (GtkWidget *widget,
+ gpointer data)
+{
+ DialogData *dialog_data;
+
+ dialog_data = (DialogData *) data;
+ apply (dialog_data);
+}
+
+static void
+ok_cb (GtkWidget *widget,
+ gpointer data)
+{
+ apply_cb (widget, data);
+ close_cb (widget, data);
+}
+
+static void
+browse_cb (GtkWidget *widget,
+ gpointer data)
+{
+ DialogData *dialog_data;
+
+ dialog_data = (DialogData *) data;
+ browse (dialog_data);
+}
+
+static void
+file_name_focus_out_cb (GtkWidget *widget,
+ GdkEventFocus *event,
+ gpointer data)
+{
+ DialogData *dialog_data;
+
+ dialog_data = (DialogData *) data;
+ update_mime_type (dialog_data);
+}
+
+
+void
+e_msg_composer_attachment_edit (EMsgComposerAttachment *attachment,
+ GtkWidget *parent)
+{
+ DialogData *dialog_data;
+ GladeXML *editor_gui;
+
+ g_return_if_fail (attachment != NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER_ATTACHMENT (attachment));
+
+ if (attachment->editor_gui != NULL) {
+ GtkWidget *window;
+
+ window = glade_xml_get_widget (attachment->editor_gui,
+ "dialog");
+ gdk_window_show (window->window);
+ return;
+ }
+
+ editor_gui = glade_xml_new (E_GUIDIR "/e-msg-composer-attachment.glade",
+ NULL);
+ if (editor_gui == NULL) {
+ g_warning ("Cannot load `e-msg-composer-attachment.glade'");
+ return;
+ }
+
+ attachment->editor_gui = editor_gui;
+
+ gtk_window_set_transient_for
+ (GTK_WINDOW (glade_xml_get_widget (editor_gui, "dialog")),
+ GTK_WINDOW (gtk_widget_get_toplevel (parent)));
+
+ dialog_data = g_new (DialogData, 1);
+ dialog_data->browse_widget = NULL;
+ dialog_data->attachment = attachment;
+ dialog_data->dialog = glade_xml_get_widget (editor_gui, "dialog");
+ dialog_data->file_name_entry = GTK_ENTRY (glade_xml_get_widget
+ (editor_gui,
+ "file_name_entry"));
+ dialog_data->description_entry = GTK_ENTRY (glade_xml_get_widget
+ (editor_gui,
+ "description_entry"));
+ dialog_data->mime_type_entry = GTK_ENTRY (glade_xml_get_widget
+ (editor_gui,
+ "mime_type_entry"));
+
+ if (attachment != NULL) {
+ set_entry (editor_gui, "file_name_entry", attachment->file_name);
+ set_entry (editor_gui, "description_entry", attachment->description);
+ set_entry (editor_gui, "mime_type_entry", attachment->mime_type);
+ }
+
+ connect_entry_changed (editor_gui, "file_name_entry",
+ entry_changed_cb, dialog_data);
+ connect_entry_changed (editor_gui, "description_entry",
+ entry_changed_cb, dialog_data);
+
+ connect_widget (editor_gui, "ok_button", "clicked", ok_cb, dialog_data);
+ connect_widget (editor_gui, "apply_button", "clicked", apply_cb, dialog_data);
+ connect_widget (editor_gui, "close_button", "clicked", close_cb, dialog_data);
+
+ connect_widget (editor_gui, "browse_button", "clicked", browse_cb, dialog_data);
+
+ connect_widget (editor_gui, "file_name_entry", "focus_out_event",
+ file_name_focus_out_cb, dialog_data);
+}
diff --git a/widgets/e-msg-composer-attachment.glade b/widgets/e-msg-composer-attachment.glade
new file mode 100644
index 0000000000..72c0132639
--- /dev/null
+++ b/widgets/e-msg-composer-attachment.glade
@@ -0,0 +1,290 @@
+<?xml version="1.0"?>
+<GTK-Interface>
+
+<project>
+ <name>e-msg-composer-attachment</name>
+ <program_name>e-msg-composer-attachment</program_name>
+ <directory></directory>
+ <source_directory>src</source_directory>
+ <pixmaps_directory>pixmaps</pixmaps_directory>
+ <language>C</language>
+ <gnome_support>True</gnome_support>
+ <gettext_support>True</gettext_support>
+ <use_widget_names>False</use_widget_names>
+ <output_main_file>True</output_main_file>
+ <output_support_files>True</output_support_files>
+ <output_build_files>True</output_build_files>
+ <backup_source_files>True</backup_source_files>
+ <main_source_file>interface.c</main_source_file>
+ <main_header_file>interface.h</main_header_file>
+ <handler_source_file>callbacks.c</handler_source_file>
+ <handler_header_file>callbacks.h</handler_header_file>
+ <support_source_file>support.c</support_source_file>
+ <support_header_file>support.h</support_header_file>
+ <translatable_strings_file></translatable_strings_file>
+</project>
+
+<widget>
+ <class>GnomeDialog</class>
+ <name>dialog</name>
+ <title>Attachment properties</title>
+ <type>GTK_WINDOW_TOPLEVEL</type>
+ <position>GTK_WIN_POS_NONE</position>
+ <modal>False</modal>
+ <allow_shrink>False</allow_shrink>
+ <allow_grow>False</allow_grow>
+ <auto_shrink>False</auto_shrink>
+ <auto_close>False</auto_close>
+ <hide_on_close>False</hide_on_close>
+
+ <widget>
+ <class>GtkVBox</class>
+ <child_name>GnomeDialog:vbox</child_name>
+ <name>dialog-vbox1</name>
+ <homogeneous>False</homogeneous>
+ <spacing>8</spacing>
+ <child>
+ <padding>4</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkTable</class>
+ <name>table1</name>
+ <rows>3</rows>
+ <columns>2</columns>
+ <homogeneous>False</homogeneous>
+ <row_spacing>10</row_spacing>
+ <column_spacing>5</column_spacing>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GtkLabel</class>
+ <name>label1</name>
+ <label>Description:</label>
+ <justify>GTK_JUSTIFY_CENTER</justify>
+ <wrap>False</wrap>
+ <xalign>0.5</xalign>
+ <yalign>0.5</yalign>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <child>
+ <left_attach>0</left_attach>
+ <right_attach>1</right_attach>
+ <top_attach>1</top_attach>
+ <bottom_attach>2</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>False</xexpand>
+ <yexpand>False</yexpand>
+ <xshrink>False</xshrink>
+ <yshrink>False</yshrink>
+ <xfill>False</xfill>
+ <yfill>False</yfill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkLabel</class>
+ <name>label3</name>
+ <label>MIME type:</label>
+ <justify>GTK_JUSTIFY_CENTER</justify>
+ <wrap>False</wrap>
+ <xalign>0.5</xalign>
+ <yalign>0.5</yalign>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <child>
+ <left_attach>0</left_attach>
+ <right_attach>1</right_attach>
+ <top_attach>2</top_attach>
+ <bottom_attach>3</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>False</xexpand>
+ <yexpand>False</yexpand>
+ <xshrink>False</xshrink>
+ <yshrink>False</yshrink>
+ <xfill>False</xfill>
+ <yfill>False</yfill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkEntry</class>
+ <name>description_entry</name>
+ <can_focus>True</can_focus>
+ <editable>True</editable>
+ <text_visible>True</text_visible>
+ <text_max_length>0</text_max_length>
+ <text></text>
+ <child>
+ <left_attach>1</left_attach>
+ <right_attach>2</right_attach>
+ <top_attach>1</top_attach>
+ <bottom_attach>2</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>True</xexpand>
+ <yexpand>False</yexpand>
+ <xshrink>False</xshrink>
+ <yshrink>False</yshrink>
+ <xfill>True</xfill>
+ <yfill>False</yfill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkLabel</class>
+ <name>label2</name>
+ <label>File name:</label>
+ <justify>GTK_JUSTIFY_CENTER</justify>
+ <wrap>False</wrap>
+ <xalign>0.5</xalign>
+ <yalign>0.5</yalign>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <child>
+ <left_attach>0</left_attach>
+ <right_attach>1</right_attach>
+ <top_attach>0</top_attach>
+ <bottom_attach>1</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>False</xexpand>
+ <yexpand>False</yexpand>
+ <xshrink>False</xshrink>
+ <yshrink>False</yshrink>
+ <xfill>False</xfill>
+ <yfill>False</yfill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkHBox</class>
+ <name>hbox3</name>
+ <homogeneous>False</homogeneous>
+ <spacing>10</spacing>
+ <child>
+ <left_attach>1</left_attach>
+ <right_attach>2</right_attach>
+ <top_attach>0</top_attach>
+ <bottom_attach>1</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>True</xexpand>
+ <yexpand>True</yexpand>
+ <xshrink>True</xshrink>
+ <yshrink>True</yshrink>
+ <xfill>True</xfill>
+ <yfill>True</yfill>
+ </child>
+
+ <widget>
+ <class>GtkEntry</class>
+ <name>file_name_entry</name>
+ <width>290</width>
+ <can_focus>True</can_focus>
+ <editable>True</editable>
+ <text_visible>True</text_visible>
+ <text_max_length>0</text_max_length>
+ <text></text>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>browse_button</name>
+ <width>80</width>
+ <can_focus>True</can_focus>
+ <label>Browse...</label>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>False</fill>
+ </child>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkEntry</class>
+ <name>mime_type_entry</name>
+ <sensitive>False</sensitive>
+ <can_focus>True</can_focus>
+ <editable>False</editable>
+ <text_visible>True</text_visible>
+ <text_max_length>0</text_max_length>
+ <text></text>
+ <child>
+ <left_attach>1</left_attach>
+ <right_attach>2</right_attach>
+ <top_attach>2</top_attach>
+ <bottom_attach>3</bottom_attach>
+ <xpad>0</xpad>
+ <ypad>0</ypad>
+ <xexpand>True</xexpand>
+ <yexpand>False</yexpand>
+ <xshrink>False</xshrink>
+ <yshrink>False</yshrink>
+ <xfill>True</xfill>
+ <yfill>False</yfill>
+ </child>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkHButtonBox</class>
+ <child_name>GnomeDialog:action_area</child_name>
+ <name>dialog-action_area1</name>
+ <layout_style>GTK_BUTTONBOX_END</layout_style>
+ <spacing>8</spacing>
+ <child_min_width>85</child_min_width>
+ <child_min_height>27</child_min_height>
+ <child_ipad_x>7</child_ipad_x>
+ <child_ipad_y>0</child_ipad_y>
+ <child>
+ <padding>0</padding>
+ <expand>False</expand>
+ <fill>True</fill>
+ <pack>GTK_PACK_END</pack>
+ </child>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>ok_button</name>
+ <can_default>True</can_default>
+ <has_default>True</has_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_OK</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>apply_button</name>
+ <sensitive>False</sensitive>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_APPLY</stock_button>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <name>close_button</name>
+ <can_default>True</can_default>
+ <can_focus>True</can_focus>
+ <stock_button>GNOME_STOCK_BUTTON_CLOSE</stock_button>
+ </widget>
+ </widget>
+ </widget>
+</widget>
+
+</GTK-Interface>
diff --git a/widgets/e-msg-composer-attachment.h b/widgets/e-msg-composer-attachment.h
new file mode 100644
index 0000000000..07dd7f247d
--- /dev/null
+++ b/widgets/e-msg-composer-attachment.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer-attachment.h
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+#ifndef __E_MSG_COMPOSER_ATTACHMENT_H__
+#define __E_MSG_COMPOSER_ATTACHMENT_H__
+
+#include <gnome.h>
+#include <glade/glade-xml.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_MSG_COMPOSER_ATTACHMENT (e_msg_composer_attachment_get_type ())
+#define E_MSG_COMPOSER_ATTACHMENT(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT, EMsgComposerAttachment))
+#define E_MSG_COMPOSER_ATTACHMENT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER_ATTACHMENT, EMsgComposerAttachmentClass))
+#define E_IS_MSG_COMPOSER_ATTACHMENT(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT))
+#define E_IS_MSG_COMPOSER_ATTACHMENT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER_ATTACHMENT))
+
+
+typedef struct _EMsgComposerAttachment EMsgComposerAttachment;
+typedef struct _EMsgComposerAttachmentClass EMsgComposerAttachmentClass;
+
+struct _EMsgComposerAttachment {
+ GtkObject parent;
+
+ GladeXML *editor_gui;
+
+ gchar *file_name;
+ gchar *description;
+ gchar *mime_type;
+};
+
+struct _EMsgComposerAttachmentClass {
+ GtkObjectClass parent_class;
+
+ /* Signals go here */
+ void (*changed) (EMsgComposerAttachment *msg_composer_attachment);
+};
+
+
+GtkType e_msg_composer_attachment_get_type (void);
+EMsgComposerAttachment *e_msg_composer_attachment_new (const gchar *file_name);
+void e_msg_composer_attachment_edit (EMsgComposerAttachment *attachment,
+ GtkWidget *parent);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __E_MSG_COMPOSER_ATTACHMENT_H__ */
diff --git a/widgets/e-msg-composer-hdrs.c b/widgets/e-msg-composer-hdrs.c
new file mode 100644
index 0000000000..7269b0da8b
--- /dev/null
+++ b/widgets/e-msg-composer-hdrs.c
@@ -0,0 +1,196 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* msg-composer-hdrs.c
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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 <gnome.h>
+#include <camel/camel.h>
+
+#include "e-msg-composer-address-entry.h"
+#include "e-msg-composer-hdrs.h"
+
+
+struct _EMsgComposerHdrsPrivate {
+ /* Total number of headers that we have. */
+ guint num_hdrs;
+
+ /* Standard headers. */
+ GtkWidget *to_entry;
+ GtkWidget *cc_entry;
+ GtkWidget *bcc_entry;
+ GtkWidget *subject_entry;
+};
+
+
+static GtkTableClass *parent_class = NULL;
+
+
+static GtkWidget *
+add_address_header (EMsgComposerHdrs *hdrs,
+ const gchar *name)
+{
+ EMsgComposerHdrsPrivate *priv;
+ GtkWidget *label;
+ GtkWidget *entry;
+
+ priv = hdrs->priv;
+
+ label = gtk_label_new (name);
+ gtk_table_attach (GTK_TABLE (hdrs), label,
+ 0, 1, priv->num_hdrs, priv->num_hdrs + 1,
+ GTK_FILL, GTK_FILL,
+ GNOME_PAD, GNOME_PAD);
+ gtk_widget_show (label);
+
+ entry = e_msg_composer_address_entry_new ();
+ gtk_table_attach (GTK_TABLE (hdrs), entry,
+ 1, 2, priv->num_hdrs, priv->num_hdrs + 1,
+ GTK_FILL | GTK_EXPAND, GTK_FILL,
+ GNOME_PAD, GNOME_PAD);
+ gtk_widget_show (entry);
+
+ priv->num_hdrs++;
+
+ return entry;
+}
+
+static void
+setup_headers (EMsgComposerHdrs *hdrs)
+{
+ EMsgComposerHdrsPrivate *priv;
+
+ priv = hdrs->priv;
+
+ priv->subject_entry = add_address_header (hdrs, _("Subject:"));
+ priv->to_entry = add_address_header (hdrs, _("To:"));
+ priv->cc_entry = add_address_header (hdrs, _("Cc:"));
+ priv->bcc_entry = add_address_header (hdrs, _("Bcc:"));
+}
+
+
+static void
+class_init (EMsgComposerHdrsClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass*) klass;
+
+ parent_class = gtk_type_class (gtk_table_get_type ());
+}
+
+static void
+init (EMsgComposerHdrs *hdrs)
+{
+ EMsgComposerHdrsPrivate *priv;
+
+ priv = g_new (EMsgComposerHdrsPrivate, 1);
+
+ priv->to_entry = NULL;
+ priv->cc_entry = NULL;
+ priv->bcc_entry = NULL;
+ priv->subject_entry = NULL;
+
+ priv->num_hdrs = 0;
+
+ hdrs->priv = priv;
+}
+
+
+GtkType
+e_msg_composer_hdrs_get_type (void)
+{
+ static GtkType type = 0;
+
+ if (type == 0) {
+ static const GtkTypeInfo info = {
+ "EMsgComposerHdrs",
+ sizeof (EMsgComposerHdrs),
+ sizeof (EMsgComposerHdrsClass),
+ (GtkClassInitFunc) class_init,
+ (GtkObjectInitFunc) init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ type = gtk_type_unique (gtk_table_get_type (), &info);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_msg_composer_hdrs_new (void)
+{
+ EMsgComposerHdrs *new;
+
+ new = gtk_type_new (e_msg_composer_hdrs_get_type ());
+
+ setup_headers (E_MSG_COMPOSER_HDRS (new));
+
+ return GTK_WIDGET (new);
+}
+
+
+static void
+set_recipients (CamelMimeMessage *msg,
+ GtkWidget *entry_widget,
+ const gchar *type)
+{
+ EMsgComposerAddressEntry *entry;
+ GList *list;
+ GList *p;
+
+ entry = E_MSG_COMPOSER_ADDRESS_ENTRY (entry_widget);
+ list = e_msg_composer_address_entry_get_addresses (entry);
+
+ /* FIXME leak? */
+
+ for (p = list; p != NULL; p = p->next) {
+ printf ("Adding `%s:' header: %s\n", type, (gchar *) p->data);
+ camel_mime_message_add_recipient (msg, type, (gchar *) p->data);
+ }
+
+ g_list_free (list);
+}
+
+void
+e_msg_composer_hdrs_to_message (EMsgComposerHdrs *hdrs,
+ CamelMimeMessage *msg)
+{
+ const gchar *s;
+
+ g_return_if_fail (hdrs != NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (IS_CAMEL_MIME_MESSAGE (msg));
+
+ s = gtk_entry_get_text (GTK_ENTRY (hdrs->priv->subject_entry));
+ camel_mime_message_set_subject (msg, g_strdup (s));
+
+ set_recipients (msg, hdrs->priv->to_entry, RECIPIENT_TYPE_TO);
+ set_recipients (msg, hdrs->priv->cc_entry, RECIPIENT_TYPE_CC);
+ set_recipients (msg, hdrs->priv->bcc_entry, RECIPIENT_TYPE_BCC);
+}
diff --git a/widgets/e-msg-composer-hdrs.h b/widgets/e-msg-composer-hdrs.h
new file mode 100644
index 0000000000..de8ac4ac13
--- /dev/null
+++ b/widgets/e-msg-composer-hdrs.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* msg-composer-hdrs.h
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#ifndef ___E_MSG_COMPOSER_HDRS_H__
+#define ___E_MSG_COMPOSER_HDRS_H__
+
+#include <gnome.h>
+#include <camel/camel-mime-message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+#define E_TYPE_MSG_COMPOSER_HDRS (e_msg_composer_hdrs_get_type ())
+#define E_MSG_COMPOSER_HDRS(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrs))
+#define E_MSG_COMPOSER_HDRS_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrsClass))
+#define E_IS_MSG_COMPOSER_HDRS(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MSG_COMPOSER_HDRS))
+#define E_IS_MSG_COMPOSER_HDRS_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER_HDRS))
+
+
+typedef struct _EMsgComposerHdrs EMsgComposerHdrs;
+typedef struct _EMsgComposerHdrsClass EMsgComposerHdrsClass;
+typedef struct _EMsgComposerHdrsPrivate EMsgComposerHdrsPrivate;
+
+struct _EMsgComposerHdrs {
+ GtkTable parent;
+
+ EMsgComposerHdrsPrivate *priv;
+};
+
+struct _EMsgComposerHdrsClass {
+ GtkTableClass parent_class;
+};
+
+
+GtkType e_msg_composer_hdrs_get_type (void);
+GtkWidget *e_msg_composer_hdrs_new (void);
+void e_msg_composer_hdrs_to_message (EMsgComposerHdrs *hdrs,
+ CamelMimeMessage *msg);
+
+#ifdef _cplusplus
+}
+#endif /* _cplusplus */
+
+
+#endif /* __E_MSG_COMPOSER_HDRS_H__ */
diff --git a/widgets/e-msg-composer.c b/widgets/e-msg-composer.c
new file mode 100644
index 0000000000..70602c0018
--- /dev/null
+++ b/widgets/e-msg-composer.c
@@ -0,0 +1,441 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer.c
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+/*
+
+ TODO
+
+ - Somehow users should be able to see if any file(s) are attached even when
+ the attachment bar is not shown.
+
+*/
+
+#ifdef _HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gnome.h>
+#include <glade/glade.h>
+#include <camel/camel.h>
+
+#include "e-msg-composer.h"
+#include "e-msg-composer-attachment-bar.h"
+#include "e-msg-composer-hdrs.h"
+
+
+#define DEFAULT_WIDTH 600
+#define DEFAULT_HEIGHT 500
+
+
+enum {
+ SEND,
+ POSTPONE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static GnomeAppClass *parent_class = NULL;
+
+
+/* This functions builds a CamelMimeMessage for the message that the user has
+ composed in `composer'. */
+static CamelMimeMessage *
+build_message (EMsgComposer *composer)
+{
+ CamelMimeMessage *new;
+ CamelMimeBodyPart *body_part;
+ CamelMultipart *multipart;
+ gchar *text;
+
+ new = camel_mime_message_new_with_session (NULL);
+
+ e_msg_composer_hdrs_to_message (E_MSG_COMPOSER_HDRS (composer->hdrs),
+ new);
+
+ multipart = camel_multipart_new ();
+ body_part = camel_mime_body_part_new ();
+
+ text = gtk_editable_get_chars (GTK_EDITABLE (composer->text), 0, -1);
+ camel_mime_part_set_text (CAMEL_MIME_PART (body_part), text);
+ camel_multipart_add_part (multipart, body_part);
+
+ e_msg_composer_attachment_bar_to_multipart
+ (E_MSG_COMPOSER_ATTACHMENT_BAR (composer->attachment_bar),
+ multipart);
+
+ camel_medium_set_content_object (CAMEL_MEDIUM (new),
+ CAMEL_DATA_WRAPPER (multipart));
+
+ /* FIXME refcounting is most certainly wrong. We want all the stuff to
+ be destroyed when we unref() the message. */
+
+ return new;
+}
+
+
+static void
+show_attachments (EMsgComposer *composer,
+ gboolean show)
+{
+ if (show) {
+ gtk_widget_show (composer->attachment_scrolled_window);
+ gtk_widget_show (composer->attachment_bar);
+ } else {
+ gtk_widget_hide (composer->attachment_scrolled_window);
+ gtk_widget_hide (composer->attachment_bar);
+ }
+
+ composer->attachment_bar_visible = show;
+
+ /* Update the GUI. */
+
+ gtk_check_menu_item_set_active
+ (GTK_CHECK_MENU_ITEM
+ (glade_xml_get_widget (composer->menubar_gui,
+ "menu_view_attachments")),
+ show);
+
+ /* XXX we should update the toggle toolbar item as well. At
+ this point, it is not a toggle because Glade is broken. */
+}
+
+
+/* Callbacks. */
+
+static void
+send_cb (GtkWidget *widget,
+ gpointer data)
+{
+ gtk_signal_emit (GTK_OBJECT (data), signals[SEND]);
+}
+
+static void
+menu_view_attachments_activate_cb (GtkWidget *widget,
+ gpointer data)
+{
+ e_msg_composer_show_attachments (E_MSG_COMPOSER (data),
+ GTK_CHECK_MENU_ITEM (widget)->active);
+}
+
+static void
+toolbar_view_attachments_clicked_cb (GtkWidget *widget,
+ gpointer data)
+{
+ EMsgComposer *composer;
+
+ composer = E_MSG_COMPOSER (data);
+
+ e_msg_composer_show_attachments (composer,
+ ! composer->attachment_bar_visible);
+}
+
+static void
+add_attachment_cb (GtkWidget *widget,
+ gpointer data)
+{
+ EMsgComposer *composer;
+
+ composer = E_MSG_COMPOSER (data);
+
+ e_msg_composer_attachment_bar_attach
+ (E_MSG_COMPOSER_ATTACHMENT_BAR (composer->attachment_bar),
+ NULL);
+}
+
+static void
+glade_connect (GladeXML *gui,
+ const gchar *widget_name,
+ const gchar *signal_name,
+ GtkSignalFunc callback,
+ gpointer callback_data)
+{
+ GtkWidget *widget;
+
+ widget = glade_xml_get_widget (gui, widget_name);
+ if (widget == NULL)
+ g_warning ("Widget `%s' was not found.", widget_name);
+ else
+ gtk_signal_connect (GTK_OBJECT (widget), signal_name,
+ GTK_SIGNAL_FUNC (callback), callback_data);
+}
+
+static void
+attachment_bar_changed (EMsgComposerAttachmentBar *bar,
+ gpointer data)
+{
+ EMsgComposer *composer;
+
+ composer = E_MSG_COMPOSER (data);
+
+ if (e_msg_composer_attachment_bar_get_num_attachments (bar) > 0)
+ e_msg_composer_show_attachments (composer, TRUE);
+ else
+ e_msg_composer_show_attachments (composer, FALSE);
+}
+
+static void
+setup_signals (EMsgComposer *composer)
+{
+ glade_connect (composer->menubar_gui, "menu_send",
+ "activate", GTK_SIGNAL_FUNC (send_cb), composer);
+ glade_connect (composer->toolbar_gui, "toolbar_send",
+ "clicked", GTK_SIGNAL_FUNC (send_cb), composer);
+
+ glade_connect (composer->menubar_gui, "menu_view_attachments",
+ "activate",
+ GTK_SIGNAL_FUNC (menu_view_attachments_activate_cb),
+ composer);
+ glade_connect (composer->toolbar_gui, "toolbar_view_attachments",
+ "clicked",
+ GTK_SIGNAL_FUNC (toolbar_view_attachments_clicked_cb),
+ composer);
+
+ glade_connect (composer->menubar_gui, "menu_add_attachment",
+ "activate",
+ GTK_SIGNAL_FUNC (add_attachment_cb), composer);
+ glade_connect (composer->toolbar_gui, "toolbar_add_attachment",
+ "clicked",
+ GTK_SIGNAL_FUNC (add_attachment_cb), composer);
+
+ gtk_signal_connect (GTK_OBJECT (composer->attachment_bar),
+ "changed",
+ GTK_SIGNAL_FUNC (attachment_bar_changed),
+ composer);
+}
+
+
+/* GtkObject methods. */
+
+static void
+destroy (GtkObject *object)
+{
+ EMsgComposer *composer;
+
+ composer = E_MSG_COMPOSER (object);
+
+ gtk_object_unref (GTK_OBJECT (composer->menubar_gui));
+ gtk_object_unref (GTK_OBJECT (composer->toolbar_gui));
+ gtk_object_unref (GTK_OBJECT (composer->appbar_gui));
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+
+static void
+class_init (EMsgComposerClass *klass)
+{
+ GtkObjectClass *object_class;
+
+ object_class = (GtkObjectClass *) klass;
+
+ object_class->destroy = destroy;
+
+ parent_class = gtk_type_class (gnome_app_get_type ());
+
+ signals[SEND] =
+ gtk_signal_new ("send",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EMsgComposerClass, send),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ signals[POSTPONE] =
+ gtk_signal_new ("postpone",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EMsgComposerClass, postpone),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ gtk_object_class_add_signals (object_class, signals, LAST_SIGNAL);
+}
+
+static void
+init (EMsgComposer *composer)
+{
+ composer->menubar_gui = NULL;
+ composer->toolbar_gui = NULL;
+ composer->appbar_gui = NULL;
+
+ composer->hdrs = NULL;
+
+ composer->text = NULL;
+ composer->text_scrolled_window = NULL;
+
+ composer->attachment_bar = NULL;
+ composer->attachment_scrolled_window = NULL;
+}
+
+
+GtkType
+e_msg_composer_get_type (void)
+{
+ static GtkType type = 0;
+
+ if (type == 0) {
+ static const GtkTypeInfo info = {
+ "EMsgComposer",
+ sizeof (EMsgComposer),
+ sizeof (EMsgComposerClass),
+ (GtkClassInitFunc) class_init,
+ (GtkObjectInitFunc) init,
+ /* reserved_1 */ NULL,
+ /* reserved_2 */ NULL,
+ (GtkClassInitFunc) NULL,
+ };
+
+ type = gtk_type_unique (gnome_app_get_type (), &info);
+ }
+
+ return type;
+}
+
+
+void
+e_msg_composer_construct (EMsgComposer *composer)
+{
+ GtkWidget *vbox;
+
+ gtk_window_set_default_size (GTK_WINDOW (composer),
+ DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ gnome_app_construct (GNOME_APP (composer), "e-msg-composer",
+ "Compose a message");
+
+ composer->menubar_gui = glade_xml_new (E_GUIDIR "/e-msg-composer.glade",
+ "menubar");
+ gnome_app_set_menus (GNOME_APP (composer),
+ GTK_MENU_BAR (glade_xml_get_widget (composer->menubar_gui,
+ "menubar")));
+
+ composer->toolbar_gui = glade_xml_new (E_GUIDIR "/e-msg-composer.glade",
+ "toolbar");
+ gnome_app_set_toolbar (GNOME_APP (composer),
+ GTK_TOOLBAR (glade_xml_get_widget (composer->toolbar_gui,
+ "toolbar")));
+
+ composer->appbar_gui = glade_xml_new (E_GUIDIR "/e-msg-composer.glade",
+ "appbar");
+ gnome_app_set_statusbar (GNOME_APP (composer),
+ glade_xml_get_widget (composer->appbar_gui,
+ "appbar"));
+
+ vbox = gtk_vbox_new (FALSE, GNOME_PAD);
+
+ composer->hdrs = e_msg_composer_hdrs_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), composer->hdrs, FALSE, TRUE, 0);
+ gtk_widget_show (composer->hdrs);
+
+ /* GtkText for message body editing, wrapped into a
+ GtkScrolledWindow. */
+
+ composer->text_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy
+ (GTK_SCROLLED_WINDOW (composer->text_scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ composer->text = gtk_text_new (NULL, NULL);
+ gtk_text_set_word_wrap (GTK_TEXT (composer->text), FALSE);
+ gtk_text_set_editable (GTK_TEXT (composer->text), TRUE);
+ gtk_container_add (GTK_CONTAINER (composer->text_scrolled_window),
+ composer->text);
+ gtk_widget_show (composer->text);
+ gtk_box_pack_start (GTK_BOX (vbox), composer->text_scrolled_window,
+ TRUE, TRUE, 0);
+ gtk_widget_show (composer->text_scrolled_window);
+
+ /* Attachment editor, wrapped into a GtkScrolledWindow. We don't
+ show it for now. */
+
+ composer->attachment_scrolled_window = gtk_scrolled_window_new (NULL,
+ NULL);
+ gtk_scrolled_window_set_policy
+ (GTK_SCROLLED_WINDOW (composer->attachment_scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ composer->attachment_bar = e_msg_composer_attachment_bar_new (NULL);
+ GTK_WIDGET_SET_FLAGS (composer->attachment_bar, GTK_CAN_FOCUS);
+ gtk_container_add (GTK_CONTAINER (composer->attachment_scrolled_window),
+ composer->attachment_bar);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ composer->attachment_scrolled_window,
+ FALSE, TRUE, 0);
+
+ gnome_app_set_contents (GNOME_APP (composer), vbox);
+ gtk_widget_show (vbox);
+
+ e_msg_composer_show_attachments (composer, FALSE);
+
+ setup_signals (composer);
+}
+
+GtkWidget *
+e_msg_composer_new (void)
+{
+ GtkWidget *new;
+
+ new = gtk_type_new (e_msg_composer_get_type ());
+ e_msg_composer_construct (E_MSG_COMPOSER (new));
+
+ return new;
+}
+
+
+/**
+ * e_msg_composer_show_attachments:
+ * @composer: A message composer widget
+ * @show: A boolean specifying whether the attachment bar should be shown or
+ * not
+ *
+ * If @show is %FALSE, hide the attachment bar. Otherwise, show it.
+ **/
+void
+e_msg_composer_show_attachments (EMsgComposer *composer,
+ gboolean show)
+{
+ g_return_if_fail (composer != NULL);
+ g_return_if_fail (E_IS_MSG_COMPOSER (composer));
+
+ show_attachments (composer, show);
+}
+
+
+/**
+ * e_msg_composer_get_message:
+ * @composer: A message composer widget
+ *
+ * Retrieve the message edited by the user as a CamelMimeMessage. The
+ * CamelMimeMessage object is created on the fly; subsequent calls to this
+ * function will always create new objects from scratch.
+ *
+ * Return value: A pointer to the new CamelMimeMessage object
+ **/
+CamelMimeMessage *
+e_msg_composer_get_message (EMsgComposer *composer)
+{
+ g_return_val_if_fail (composer != NULL, NULL);
+ g_return_val_if_fail (E_IS_MSG_COMPOSER (composer), NULL);
+
+ return build_message (composer);
+}
diff --git a/widgets/e-msg-composer.glade b/widgets/e-msg-composer.glade
new file mode 100644
index 0000000000..c2d18b8125
--- /dev/null
+++ b/widgets/e-msg-composer.glade
@@ -0,0 +1,576 @@
+<?xml version="1.0"?>
+<GTK-Interface>
+
+<project>
+ <name>Message Composer</name>
+ <program_name>e-msg-composer</program_name>
+ <directory></directory>
+ <source_directory>src</source_directory>
+ <pixmaps_directory>pixmaps</pixmaps_directory>
+ <language>C</language>
+ <gnome_support>True</gnome_support>
+ <gettext_support>True</gettext_support>
+ <use_widget_names>False</use_widget_names>
+ <output_main_file>True</output_main_file>
+ <output_support_files>True</output_support_files>
+ <output_build_files>True</output_build_files>
+ <backup_source_files>True</backup_source_files>
+ <main_source_file>interface.c</main_source_file>
+ <main_header_file>interface.h</main_header_file>
+ <handler_source_file>callbacks.c</handler_source_file>
+ <handler_header_file>callbacks.h</handler_header_file>
+ <support_source_file>support.c</support_source_file>
+ <support_header_file>support.h</support_header_file>
+ <translatable_strings_file></translatable_strings_file>
+</project>
+
+<widget>
+ <class>GnomeApp</class>
+ <name>app1</name>
+ <title>Message Composer</title>
+ <type>GTK_WINDOW_TOPLEVEL</type>
+ <position>GTK_WIN_POS_NONE</position>
+ <modal>False</modal>
+ <allow_shrink>False</allow_shrink>
+ <allow_grow>True</allow_grow>
+ <auto_shrink>False</auto_shrink>
+ <enable_layout_config>True</enable_layout_config>
+
+ <widget>
+ <class>GnomeDock</class>
+ <child_name>GnomeApp:dock</child_name>
+ <name>dock1</name>
+ <allow_floating>True</allow_floating>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+
+ <widget>
+ <class>GnomeDockItem</class>
+ <name>dockitem1</name>
+ <border_width>2</border_width>
+ <placement>GNOME_DOCK_TOP</placement>
+ <band>0</band>
+ <position>0</position>
+ <offset>0</offset>
+ <locked>False</locked>
+ <exclusive>True</exclusive>
+ <never_floating>False</never_floating>
+ <never_vertical>True</never_vertical>
+ <never_horizontal>False</never_horizontal>
+ <shadow_type>GTK_SHADOW_OUT</shadow_type>
+
+ <widget>
+ <class>GtkMenuBar</class>
+ <name>menubar</name>
+ <shadow_type>GTK_SHADOW_NONE</shadow_type>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>file</name>
+ <stock_item>GNOMEUIINFO_MENU_FILE_TREE</stock_item>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>file_menu</name>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>open</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_open_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:08 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_OPEN_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>save</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_save_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:13 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_SAVE_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>save_as</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_save_as_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:16 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_SAVE_AS_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>save_in_folder</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_save_in_folder_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:20 GMT</last_modification_time>
+ </signal>
+ <label>Save in _Folder...</label>
+ <right_justify>False</right_justify>
+ <stock_icon>GNOME_STOCK_MENU_SAVE_AS</stock_icon>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator8</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>menu_send</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_send_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:29 GMT</last_modification_time>
+ </signal>
+ <label>S_end</label>
+ <right_justify>False</right_justify>
+ <stock_icon>GNOME_STOCK_MENU_MAIL_SND</stock_icon>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>postpone</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_postpone_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:37 GMT</last_modification_time>
+ </signal>
+ <label>_Postpone</label>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator1</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>exit</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_exit_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:25:59 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_EXIT_ITEM</stock_item>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>edit</name>
+ <stock_item>GNOMEUIINFO_MENU_EDIT_TREE</stock_item>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>edit_menu</name>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>undo</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_undo_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:10 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_UNDO_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>redo</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_redo_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:15 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_REDO_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator3</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>cut</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_cut_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:21 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_CUT_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>copy</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_copy_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:26 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_COPY_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>paste</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_paste_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:31 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_PASTE_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator2</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>select_all</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_select_all_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:37 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_SELECT_ALL_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator5</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>find</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_find_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:42 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_FIND_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>find_again</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_find_again_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:47 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_FIND_AGAIN_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>replace</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_replace_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:53 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_REPLACE_ITEM</stock_item>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator6</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>properties</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_properties_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:26:58 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_PROPERTIES_ITEM</stock_item>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>view1</name>
+ <stock_item>GNOMEUIINFO_MENU_VIEW_TREE</stock_item>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>view1_menu</name>
+
+ <widget>
+ <class>GtkCheckMenuItem</class>
+ <name>menu_view_attachments</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_view_attachments_activate</handler>
+ <last_modification_time>Fri, 05 Nov 1999 18:31:16 GMT</last_modification_time>
+ </signal>
+ <label>Attachments</label>
+ <active>False</active>
+ <always_show_toggle>False</always_show_toggle>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>insert</name>
+ <label>_Insert</label>
+ <right_justify>False</right_justify>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>insert_menu</name>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>menu_add_attachment</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_attachment_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:05 GMT</last_modification_time>
+ </signal>
+ <label>Attachment...</label>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>text_from_file</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_text_from_file_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:16 GMT</last_modification_time>
+ </signal>
+ <label>Text from file...</label>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator6</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>hypertext_link</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_hypertext_link_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:21 GMT</last_modification_time>
+ </signal>
+ <label>Hypertext link...</label>
+ <right_justify>False</right_justify>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>settings</name>
+ <stock_item>GNOMEUIINFO_MENU_SETTINGS_TREE</stock_item>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>settings_menu</name>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>preferences</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_preferences_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:37 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_PREFERENCES_ITEM</stock_item>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>tools</name>
+ <label>_Tools</label>
+ <right_justify>False</right_justify>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>tools_menu</name>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>spell_check1</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_spell_check_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:44 GMT</last_modification_time>
+ </signal>
+ <label>_Spell check</label>
+ <right_justify>False</right_justify>
+ <stock_icon>GNOME_STOCK_MENU_SPELLCHECK</stock_icon>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>separator7</name>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>check_names</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_check_names_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:49 GMT</last_modification_time>
+ </signal>
+ <label>Check names</label>
+ <right_justify>False</right_justify>
+ </widget>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>address_book</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_address_book_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:27:53 GMT</last_modification_time>
+ </signal>
+ <label>Address book...</label>
+ <right_justify>False</right_justify>
+ <stock_icon>GNOME_STOCK_MENU_BOOK_RED</stock_icon>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GtkMenuItem</class>
+ <name>help</name>
+ <stock_item>GNOMEUIINFO_MENU_HELP_TREE</stock_item>
+
+ <widget>
+ <class>GtkMenu</class>
+ <name>help_menu</name>
+
+ <widget>
+ <class>GtkPixmapMenuItem</class>
+ <name>about</name>
+ <signal>
+ <name>activate</name>
+ <handler>on_about_activate</handler>
+ <last_modification_time>Wed, 27 Oct 1999 22:28:01 GMT</last_modification_time>
+ </signal>
+ <stock_item>GNOMEUIINFO_MENU_ABOUT_ITEM</stock_item>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GnomeDockItem</class>
+ <name>dockitem2</name>
+ <border_width>1</border_width>
+ <placement>GNOME_DOCK_TOP</placement>
+ <band>1</band>
+ <position>0</position>
+ <offset>0</offset>
+ <locked>False</locked>
+ <exclusive>True</exclusive>
+ <never_floating>False</never_floating>
+ <never_vertical>False</never_vertical>
+ <never_horizontal>False</never_horizontal>
+ <shadow_type>GTK_SHADOW_OUT</shadow_type>
+
+ <widget>
+ <class>GtkToolbar</class>
+ <name>toolbar</name>
+ <border_width>1</border_width>
+ <orientation>GTK_ORIENTATION_HORIZONTAL</orientation>
+ <type>GTK_TOOLBAR_BOTH</type>
+ <space_size>16</space_size>
+ <space_style>GTK_TOOLBAR_SPACE_LINE</space_style>
+ <relief>GTK_RELIEF_NONE</relief>
+ <tooltips>True</tooltips>
+
+ <widget>
+ <class>GtkButton</class>
+ <child_name>Toolbar:button</child_name>
+ <name>toolbar_send</name>
+ <tooltip>Send this message</tooltip>
+ <label>Send</label>
+ <stock_pixmap>GNOME_STOCK_PIXMAP_MAIL_SND</stock_pixmap>
+ </widget>
+
+ <widget>
+ <class>GtkToggleButton</class>
+ <child_name>Toolbar:button</child_name>
+ <name>toolbar_view_attachments</name>
+ <tooltip>Show attachments for this message</tooltip>
+ <label>Show
+attachments</label>
+ <active>False</active>
+ </widget>
+
+ <widget>
+ <class>GtkButton</class>
+ <child_name>Toolbar:button</child_name>
+ <name>toolbar_add_attachment</name>
+ <tooltip>Attach a file</tooltip>
+ <label>Attach
+file</label>
+ </widget>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>Placeholder</class>
+ <child_name>GnomeDock:contents</child_name>
+ </widget>
+ </widget>
+
+ <widget>
+ <class>GnomeAppBar</class>
+ <child_name>GnomeApp:appbar</child_name>
+ <name>appbar</name>
+ <has_progress>True</has_progress>
+ <has_status>True</has_status>
+ <child>
+ <padding>0</padding>
+ <expand>True</expand>
+ <fill>True</fill>
+ </child>
+ </widget>
+</widget>
+
+</GTK-Interface>
diff --git a/widgets/e-msg-composer.h b/widgets/e-msg-composer.h
new file mode 100644
index 0000000000..46657479a3
--- /dev/null
+++ b/widgets/e-msg-composer.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* e-msg-composer.h
+ *
+ * Copyright (C) 1999 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#ifndef ___E_MSG_COMPOSER_H__
+#define ___E_MSG_COMPOSER_H__
+
+#include <gnome.h>
+#include <glade/glade.h>
+
+#include "e-msg-composer-attachment-bar.h"
+#include "e-msg-composer-hdrs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus */
+
+
+#define E_TYPE_MSG_COMPOSER (e_msg_composer_get_type ())
+#define E_MSG_COMPOSER(obj) (GTK_CHECK_CAST ((obj), E_TYPE_MSG_COMPOSER, EMsgComposer))
+#define E_MSG_COMPOSER_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER, EMsgComposerClass))
+#define E_IS_MSG_COMPOSER(obj) (GTK_CHECK_TYPE ((obj), E_TYPE_MSG_COMPOSER))
+#define E_IS_MSG_COMPOSER_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER))
+
+
+typedef struct _EMsgComposer EMsgComposer;
+typedef struct _EMsgComposerClass EMsgComposerClass;
+
+struct _EMsgComposer {
+ GnomeApp parent;
+
+ GladeXML *menubar_gui;
+ GladeXML *toolbar_gui;
+ GladeXML *appbar_gui;
+
+ GtkWidget *hdrs;
+
+ GtkWidget *text;
+ GtkWidget *text_scrolled_window;
+
+ GtkWidget *attachment_bar;
+ GtkWidget *attachment_scrolled_window;
+
+ gboolean attachment_bar_visible : 1;
+};
+
+struct _EMsgComposerClass {
+ GnomeAppClass parent_class;
+
+ void (* send) (EMsgComposer *composer);
+ void (* postpone) (EMsgComposer *composer);
+};
+
+
+GtkType e_msg_composer_get_type (void);
+void e_msg_composer_construct (EMsgComposer *composer);
+GtkWidget *e_msg_composer_new (void);
+void e_msg_composer_show_attachments (EMsgComposer *composer, gboolean show);
+CamelMimeMessage *e_msg_composer_get_message (EMsgComposer *composer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* ___E_MSG_COMPOSER_H__ */
diff --git a/widgets/e-table/.cvsignore b/widgets/e-table/.cvsignore
new file mode 100644
index 0000000000..09980ae6ba
--- /dev/null
+++ b/widgets/e-table/.cvsignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
diff --git a/widgets/e-table/ChangeLog b/widgets/e-table/ChangeLog
index e8d0c8e9ed..77a6c36c61 100644
--- a/widgets/e-table/ChangeLog
+++ b/widgets/e-table/ChangeLog
@@ -1,3 +1,26 @@
+1999-11-05 Ettore Perazzoli <ettore@gnu.org>
+
+ * Makefile.am: Compile the new files in a `libevolutionwidgets'
+ library.
+ (CPPFLAGS): #define `E_GUIDIR'.
+
+ * e-msg-composer.c, e-msg-composer.h: New files implementing an
+ initial version of the Evolution message composer widget.
+
+ * e-msg-composer-address-entry.c, e-msg-composer-address-entry.h:
+ New files implementing a GtkEntry customized for entering email
+ address lists.
+
+ * e-msg-composer-attachment-bar.c, e-msg-composer-attachment-bar.h:
+ New files implementing a widget for editing mail attachments.
+
+ * e-msg-composer-attachment.c, e-msg-composer-attachment.h: New
+ files implementing file attachment objects for the message
+ composer.
+
+ * e-msg-composer-hdrs.c, e-msg-composer-hdrs.h: New files
+ implementing a widget for editing of email message headers.
+
1999-10-31 Miguel de Icaza <miguel@gnu.org>
* widgets/e-table-column.c, e-table-column.h: New file, implements the
diff --git a/widgets/e-table/Makefile.am b/widgets/e-table/Makefile.am
index d6aa94fb90..35d1bc64a4 100644
--- a/widgets/e-table/Makefile.am
+++ b/widgets/e-table/Makefile.am
@@ -1,7 +1,29 @@
-noinst_LIBRARIES = \
- e-table-simple.c \
- e-table-simple.h \
- e-table-model.c \
- e-table-model.h \
- e-table-column-model.c \
- e-table-column-model.h \
+guidir = $(datadir)/evolution/gui
+
+gui_DATA = \
+ e-msg-composer-attachment.glade \
+ e-msg-composer.glade
+
+INCLUDES = \
+ -I$(top_srcdir)/camel \
+ -I$(top_builddir)/camel \
+ $(GNOME_INCLUDEDIR)
+
+CPPFLAGS = \
+ -DE_GUIDIR=\"$(guidir)\"
+
+noinst_LTLIBRARIES = \
+ libevolutionwidgets.la
+
+libevolutionwidgets_la_SOURCES = \
+ e-msg-composer-address-entry.c \
+ e-msg-composer-address-entry.h \
+ e-msg-composer-attachment-bar.c \
+ e-msg-composer-attachment-bar.h \
+ e-msg-composer-attachment.c \
+ e-msg-composer-attachment.h \
+ e-msg-composer-hdrs.c \
+ e-msg-composer-hdrs.h \
+ e-msg-composer.c \
+ e-msg-composer.h
+
diff --git a/widgets/table/.cvsignore b/widgets/table/.cvsignore
new file mode 100644
index 0000000000..09980ae6ba
--- /dev/null
+++ b/widgets/table/.cvsignore
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la