aboutsummaryrefslogtreecommitdiffstats
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
parentc8fce201dc8b14505f2e0387689947922e08f956 (diff)
downloadgsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.gz
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.bz2
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.lz
gsoc2013-evolution-b681ec2b9a98684ef821f9b6fbdb9a231a58d4b5.tar.xz
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
-rw-r--r--ChangeLog38
-rw-r--r--camel/Makefile.am3
-rw-r--r--camel/camel-data-wrapper.h2
-rw-r--r--camel/camel-folder.c4
-rw-r--r--camel/camel-medium.c6
-rw-r--r--camel/camel-mime-part.c11
-rw-r--r--camel/camel-multipart.c13
-rw-r--r--camel/camel-provider.c5
-rw-r--r--camel/camel.c3
-rw-r--r--camel/camel.h1
-rw-r--r--camel/data-wrapper-repository.h1
-rw-r--r--camel/gmime-content-field.c2
-rw-r--r--camel/gmime-rfc2047.c5
-rw-r--r--configure.in1
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/ui-tests/.cvsignore1
-rw-r--r--tests/ui-tests/Makefile.am26
-rw-r--r--tests/ui-tests/msg-composer-test.c52
-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
37 files changed, 3325 insertions, 53 deletions
diff --git a/ChangeLog b/ChangeLog
index ba39571d16..7c89092878 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+1999-11-05 Ettore Perazzoli <ettore@gnu.org>
+
+ * tests/ui-tests/msg-composer-test.c: New file for testing the
+ `EMsgComposer' widget.
+ * tests/ui-tests/Makefile.am (noinst_PROGRAMS): Compile it. Do
+ not compile `store_listing' for now because it's currently broken.
+ (INCLUDES): Added the `widgets' source directory to the include
+ path list.
+ (LDADD): Removed the MH dependency; link with
+ `libevolutionwidgets.la' from the `widgets' directory.
+
+ * configure.in: Create `widgets/Makefile'.
+
+ * camel/gmime-rfc2047.c (rfc2047_clean): Removed C++-like comment.
+ * camel/camel-folder.c (camel_folder_get_message_uid_by_number):
+ Likewise.
+ * camel/gmime-content-field.c (gmime_content_field_get_parameter):
+ Likewise.
+ * camel/camel.c (camel_init): Likewise.
+ * camel/camel-provider.c (camel_provider_register): Likewise.
+ * camel/camel-multipart.c (_construct_from_stream): Likewise.
+ * camel/camel-mime-part.c (_write_content_to_stream): Likewise.
+ * camel/camel-medium.c (camel_medium_class_init): Likewise.
+
+ * camel/camel-data-wrapper.h (camel_data_wrapper_get_type): Make
+ prototype non-static.
+
+ * camel/Makefile.am (libcamelinclude_HEADERS): Move
+ `camel-exception-list.def' from `EXTRA_DIST' to
+ `libcamelinclude_HEADERS'.
+
+ * camel/camel.h: Do not #include <config.h>.
+ * camel/data-wrapper-repository.h: Likewise.
+
+1999-11-05 Ettore Perazzoli <ettore@gnu.org>
+
+ * tests/Makefile.am (INCLUDES): Add `-I$(top_srcdir)'.
+
1999-10-13 bertrand <Bertrand.Guiheneuf@aful.org>
* camel/camel-folder.c (camel_folder_close): the
diff --git a/camel/Makefile.am b/camel/Makefile.am
index b9316d1fca..0f5a4227b2 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -98,6 +98,7 @@ libcamelinclude_HEADERS = \
md5-utils.h \
string-utils.h \
url-util.h \
+ camel-exception-list.def \
$(pthread_HDR)
libcamel_extra_sources = \
@@ -106,4 +107,4 @@ libcamel_extra_sources = \
libcamel_la_LDFLAGS = -version-info 0:0:0 -rpath $(libdir)
-EXTRA_DIST = README camel-exception-list.def
+EXTRA_DIST = README
diff --git a/camel/camel-data-wrapper.h b/camel/camel-data-wrapper.h
index bc98f85c7e..2f56ed2000 100644
--- a/camel/camel-data-wrapper.h
+++ b/camel/camel-data-wrapper.h
@@ -79,7 +79,7 @@ GtkType camel_data_wrapper_get_type (void);
void camel_data_wrapper_write_to_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
void camel_data_wrapper_construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream);
void camel_data_wrapper_set_mime_type (CamelDataWrapper *data_wrapper, gchar *mime_type);
-static gchar *camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper);
+gchar *camel_data_wrapper_get_mime_type (CamelDataWrapper *data_wrapper);
GMimeContentField *camel_data_wrapper_get_mime_type_field (CamelDataWrapper *data_wrapper);
void camel_data_wrapper_set_mime_type_field (CamelDataWrapper *data_wrapper, GMimeContentField *mime_type);
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index d890ffd69d..cacfa318e0 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -1128,8 +1128,8 @@ _get_message_uid_by_number (CamelFolder *folder, gint message_number, CamelExcep
const gchar *
camel_folder_get_message_uid_by_number (CamelFolder *folder, gint message_number, CamelException *ex)
{
- //if (!folder->has_uid_capability) return NULL;
- //return CF_CLASS (folder)->get_message_uid_by_number (folder, message_number, ex);
+ /* if (!folder->has_uid_capability) return NULL; */
+ /* return CF_CLASS (folder)->get_message_uid_by_number (folder, message_number, ex); */
}
diff --git a/camel/camel-medium.c b/camel/camel-medium.c
index d26b64a246..01aa440f84 100644
--- a/camel/camel-medium.c
+++ b/camel/camel-medium.c
@@ -67,11 +67,9 @@ camel_medium_class_init (CamelMediumClass *camel_medium_class)
camel_medium_class->set_content_object = _set_content_object;
camel_medium_class->get_content_object = _get_content_object;
-
-
/* virtual method overload */
- // camel_data_wrapper_class->write_to_stream = _write_to_stream;
- //camel_data_wrapper_class->construct_from_stream = _construct_from_stream;
+ /* camel_data_wrapper_class->write_to_stream = _write_to_stream; */
+ /* camel_data_wrapper_class->construct_from_stream = _construct_from_stream; */
gtk_object_class->finalize = _finalize;
}
diff --git a/camel/camel-mime-part.c b/camel/camel-mime-part.c
index 71a4c80643..180a843c02 100644
--- a/camel/camel-mime-part.c
+++ b/camel/camel-mime-part.c
@@ -628,10 +628,13 @@ _write_content_to_stream (CamelMimePart *mime_part, CamelStream *stream)
CAMEL_LOG_FULL_DEBUG ( "Entering CamelMimePart::_write_content_to_stream\n");
CAMEL_LOG_FULL_DEBUG ( "CamelMimePart::_write_content_to_stream, content=%p\n", content);
if (!content) return;
- // buffer_size = camel_data_wrapper_size (content);
- //buffer = g_malloc (buffer_size);
+
+ /* buffer_size = camel_data_wrapper_size (content); */
+ /* buffer = g_malloc (buffer_size); */
+
camel_data_wrapper_write_to_stream (content, stream);
-
+
+#if 0
//if (mime_part->encoding) {
// encoded_buffer_size = gmime_encoded_size(buffer, buffer_size, encoding);
// encoded_buffer = g_malloc (encoded_buffer_size);
@@ -642,6 +645,8 @@ _write_content_to_stream (CamelMimePart *mime_part, CamelStream *stream)
//fwrite (buffer, buffer_size, 1, file);
//camel_stream_write (stream, buffer, buffer_size);
//g_free (buffer);
+#endif
+
CAMEL_LOG_FULL_DEBUG ( "Leaving CamelMimePart::_write_content_to_stream\n");
}
diff --git a/camel/camel-multipart.c b/camel/camel-multipart.c
index 7df44b6cb2..f3128be9e7 100644
--- a/camel/camel-multipart.c
+++ b/camel/camel-multipart.c
@@ -474,7 +474,8 @@ _construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
CAMEL_LOG_FULL_DEBUG ("CamelMultipart::construct_from_stream freeing new_part_stream:%p\n", new_part_stream);
gtk_object_unref (GTK_OBJECT (new_part_stream));
if (multipart->preface) g_free (multipart->preface);
- //if ( (new_part->str)[0] != '\0') multipart->preface = g_strdup (new_part->str);
+
+ /* if ( (new_part->str)[0] != '\0') multipart->preface = g_strdup (new_part->str); */
/* read all the real parts */
while (!end_of_multipart) {
@@ -490,12 +491,14 @@ _construct_from_stream (CamelDataWrapper *data_wrapper, CamelStream *stream)
}
- //g_string_assign (new_part, "");
- //_read_part (new_part, stream, real_boundary_line, end_boundary_line);
+ /* g_string_assign (new_part, ""); */
+ /* _read_part (new_part, stream, real_boundary_line, end_boundary_line); */
+
if (multipart->postface) g_free (multipart->postface);
- //if ( (new_part->str)[0] != '\0') multipart->postface = g_strdup (new_part->str);
+ /* if ( (new_part->str)[0] != '\0') multipart->postface = g_strdup (new_part->str); */
+
+ /* g_string_free (new_part, TRUE); */
- //g_string_free (new_part, TRUE);
g_free (real_boundary_line);
g_free (end_boundary_line);
CAMEL_LOG_FULL_DEBUG ("Leaving CamelMultipart::_construct_from_stream\n");
diff --git a/camel/camel-provider.c b/camel/camel-provider.c
index 362ad087bc..7664838975 100644
--- a/camel/camel-provider.c
+++ b/camel/camel-provider.c
@@ -72,15 +72,14 @@ camel_provider_register (CamelProvider *provider)
old_provider_node = g_list_find_custom (_provider_list, provider, _provider_name_cmp);
if (old_provider_node != NULL) {
- // camel_provider_unref (CAMEL_PROVIDER (old_provider_node->data));
+ /* camel_provider_unref (CAMEL_PROVIDER (old_provider_node->data)); */
old_provider_node->data = provider;
} else {
/* be careful, we use prepend here, so that last registered
providers come first */
_provider_list = g_list_prepend (_provider_list, provider);
}
- // camel_provider_ref (provider);
-
+ /* camel_provider_ref (provider); */
}
diff --git a/camel/camel.c b/camel/camel.c
index 51bf4ca8ee..68d0a54407 100644
--- a/camel/camel.c
+++ b/camel/camel.c
@@ -35,6 +35,5 @@ camel_init()
printf ("Threads are not supported by glib\n");
#endif /* G_THREADS_ENABLED */
- //return data_wrapper_repository_init ();
-
+ /* return data_wrapper_repository_init (); */
}
diff --git a/camel/camel.h b/camel/camel.h
index 9a3898e055..b21ccf5e78 100644
--- a/camel/camel.h
+++ b/camel/camel.h
@@ -34,7 +34,6 @@ extern "C" {
#endif /* __cplusplus }*/
#include <gtk/gtk.h>
-#include <config.h>
#include <camel/data-wrapper-repository.h>
#include <camel/data-wrapper-repository.h>
#include <camel/camel-log.h>
diff --git a/camel/data-wrapper-repository.h b/camel/data-wrapper-repository.h
index 8999467175..27f782878a 100644
--- a/camel/data-wrapper-repository.h
+++ b/camel/data-wrapper-repository.h
@@ -34,7 +34,6 @@ extern "C" {
#endif /* __cplusplus }*/
#include <glib.h>
-#include <config.h>
#include "camel-data-wrapper.h"
diff --git a/camel/gmime-content-field.c b/camel/gmime-content-field.c
index 79d4d1bdca..43691f0d62 100644
--- a/camel/gmime-content-field.c
+++ b/camel/gmime-content-field.c
@@ -261,7 +261,7 @@ gmime_content_field_get_parameter (GMimeContentField *content_field, const gchar
g_assert (content_field->parameters);
g_assert (name);
CAMEL_LOG_FULL_DEBUG ("GMimeContentField::get_parameter looking for parameter \"%s\"\n", name);
- //parameter = (const gchar *)g_hash_table_lookup (content_field->parameters, name);
+ /* parameter = (const gchar *)g_hash_table_lookup (content_field->parameters, name); */
parameter_exists = g_hash_table_lookup_extended (content_field->parameters,
name,
(gpointer *) &old_name,
diff --git a/camel/gmime-rfc2047.c b/camel/gmime-rfc2047.c
index 587c654d9f..7da12450b6 100644
--- a/camel/gmime-rfc2047.c
+++ b/camel/gmime-rfc2047.c
@@ -240,8 +240,9 @@ gmime_rfc2047_decode (const gchar *data, const gchar *into_what)
#define isnt_ascii(a) ((a) <= 0x1f || (a) >= 0x7f)
static int
-rfc2047_clean (const gchar *string, const gchar *max) {
- // if (strstr (string, "?=")) return 1;
+rfc2047_clean (const gchar *string, const gchar *max)
+{
+ /* if (strstr (string, "?=")) return 1; */
while (string < max) {
if (isnt_ascii ((unsigned char)*string))
return 0;
diff --git a/configure.in b/configure.in
index cb7fbe60b2..e59611e040 100644
--- a/configure.in
+++ b/configure.in
@@ -106,4 +106,5 @@ devel-docs/Makefile
devel-docs/camel/Makefile
tests/Makefile
tests/ui-tests/Makefile
+widgets/Makefile
])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index be6523dfbd..85ee40b3a1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,6 +1,6 @@
# process this file with automake to create Makefile.in
-INCLUDES = -I$(top_srcdir)/intl -I$(top_srcdir)/camel \
+INCLUDES = -I$(top_srcdir)/intl -I$(top_srcdir) -I$(top_srcdir)/camel \
-I$(includedir) -I$(top_srcdir)/camel/providers/MH
LDADD = \
$(top_builddir)/camel/libcamel.la \
diff --git a/tests/ui-tests/.cvsignore b/tests/ui-tests/.cvsignore
index be569b9c4c..10c9ca5909 100644
--- a/tests/ui-tests/.cvsignore
+++ b/tests/ui-tests/.cvsignore
@@ -3,3 +3,4 @@ Makefile
.deps
.libs
store_listing
+msg-composer-test
diff --git a/tests/ui-tests/Makefile.am b/tests/ui-tests/Makefile.am
index c4849e7c3c..24d62047db 100644
--- a/tests/ui-tests/Makefile.am
+++ b/tests/ui-tests/Makefile.am
@@ -1,17 +1,19 @@
# process this file with automake to create Makefile.in
-INCLUDES = -I$(top_srcdir)/intl -I$(top_srcdir)/camel \
- -I$(includedir) -I$(top_srcdir)/camel/providers/MH \
+INCLUDES = \
+ -I$(top_srcdir)/intl \
+ -I$(top_srcdir)/camel \
+ -I$(includedir) \
+ -I$(top_srcdir)/camel/providers/MH \
+ -I$(top_srcdir)/widgets \
$(EXTRA_GNOME_CFLAGS)
-LDADD = \
- $(top_builddir)/camel/libcamel.la \
- $(top_builddir)/camel/providers/MH/libcamelmh.la \
- $(INTLLIBS) $(EXTRA_GNOME_LIBS) $(PTHREAD_LIB)
+LDADD = \
+ $(top_builddir)/widgets/libevolutionwidgets.la \
+ $(top_builddir)/camel/libcamel.la \
+ $(INTLLIBS) \
+ $(EXTRA_GNOME_LIBS) \
+ $(PTHREAD_LIB)
-
-
-
-
-noinst_PROGRAMS = \
- store_listing \ No newline at end of file
+noinst_PROGRAMS = \
+ msg-composer-test \ No newline at end of file
diff --git a/tests/ui-tests/msg-composer-test.c b/tests/ui-tests/msg-composer-test.c
new file mode 100644
index 0000000000..8fbf01b5e8
--- /dev/null
+++ b/tests/ui-tests/msg-composer-test.c
@@ -0,0 +1,52 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+#include <gnome.h>
+
+#include <camel/camel-data-wrapper.h>
+#include <camel/camel-stream-fs.h>
+#include <camel/camel-stream.h>
+
+#include "e-msg-composer.h"
+
+static void
+send_cb (EMsgComposer *composer,
+ gpointer data)
+{
+ CamelMimeMessage *message;
+ CamelStream *stream;
+ gint stdout_dup;
+
+ message = e_msg_composer_get_message (composer);
+
+ stdout_dup = dup (1);
+ stream = camel_stream_fs_new_with_fd (stdout_dup);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message),
+ stream);
+ camel_stream_close (stream);
+
+ gtk_object_unref (GTK_OBJECT (message));
+
+#if 0
+ gtk_widget_destroy (GTK_WIDGET (composer));
+ gtk_main_quit ();
+#endif
+}
+
+int
+main (int argc, char **argv)
+{
+ GtkWidget *composer;
+
+ gnome_init ("test", "0.0", argc, argv);
+ glade_gnome_init ();
+
+ composer = e_msg_composer_new ();
+ gtk_widget_show (composer);
+
+ gtk_signal_connect (GTK_OBJECT (composer), "send",
+ GTK_SIGNAL_FUNC (send_cb), NULL);
+
+ gtk_main ();
+
+ return 0;
+}
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