aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--composer/ChangeLog29
-rw-r--r--composer/Makefile.am11
-rw-r--r--composer/e-composer-common.h10
-rw-r--r--composer/e-composer-from-header.c178
-rw-r--r--composer/e-composer-from-header.h67
-rw-r--r--composer/e-composer-header.c310
-rw-r--r--composer/e-composer-header.h56
-rw-r--r--composer/e-composer-name-header.c301
-rw-r--r--composer/e-composer-name-header.h58
-rw-r--r--composer/e-composer-post-header.c401
-rw-r--r--composer/e-composer-post-header.h63
-rw-r--r--composer/e-composer-text-header.c120
-rw-r--r--composer/e-composer-text-header.h50
-rw-r--r--composer/e-msg-composer-hdrs.c1396
-rw-r--r--composer/e-msg-composer-hdrs.h85
-rw-r--r--composer/e-msg-composer.c62
-rw-r--r--mail/ChangeLog7
-rw-r--r--mail/mail-session.c1
-rw-r--r--plugins/exchange-operations/ChangeLog7
-rw-r--r--plugins/exchange-operations/exchange-mail-send-options.c14
-rw-r--r--widgets/misc/ChangeLog12
-rw-r--r--widgets/misc/Makefile.am2
-rw-r--r--widgets/misc/e-account-combo-box.c413
-rw-r--r--widgets/misc/e-account-combo-box.h60
24 files changed, 2541 insertions, 1172 deletions
diff --git a/composer/ChangeLog b/composer/ChangeLog
index 5aaa7f86b0..71a1279662 100644
--- a/composer/ChangeLog
+++ b/composer/ChangeLog
@@ -1,3 +1,32 @@
+2007-11-27 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #495123
+
+ * Makefile.am:
+ Add a bunch of files for managing composer headers.
+
+ * e-msg-composer.c (build_message), (from_changed_cb),
+ (set_editor_signature), (e_msg_composer_set_body),
+ (e_msg_composer_get_preferred_account):
+ Use e_msg_composer_hdrs_get_from_account() to obtain the EAccount.
+
+ * e-msg-composer-hdrs.c:
+ * e-msg-composer-hdrs.h:
+ Massive refactoring to use new EComposerHeader classes.
+
+ * e-composer-header.c:
+ * e-composer-header.h:
+ * e-composer-from-header.c:
+ * e-composer-from-header.h:
+ * e-composer-name-header.c:
+ * e-composer-name-header.h:
+ * e-composer-post-header.c:
+ * e-composer-post-header.h:
+ * e-composer-text-header.c:
+ * e-composer-text-header.h:
+ New GObject classes manage different types of composer headers.
+ See bug #495123 for a more detailed description of each class.
+
2007-11-01 Milan Crha <mcrha@redhat.com>
** Fix for bug #318592
diff --git a/composer/Makefile.am b/composer/Makefile.am
index 64ea51d3d2..9f3899bcbf 100644
--- a/composer/Makefile.am
+++ b/composer/Makefile.am
@@ -58,6 +58,17 @@ INCLUDES = \
libcomposer_la_SOURCES = \
$(IDL_GENERATED) \
$(HTML_EDITOR_GENERATED) \
+ e-composer-common.h \
+ e-composer-header.c \
+ e-composer-header.h \
+ e-composer-from-header.c \
+ e-composer-from_header.h \
+ e-composer-name-header.c \
+ e-composer-name-header.h \
+ e-composer-post-header.c \
+ e-composer-post-header.h \
+ e-composer-text-header.c \
+ e-composer-text-header.h \
e-msg-composer-hdrs.c \
e-msg-composer-hdrs.h \
e-msg-composer-select-file.c \
diff --git a/composer/e-composer-common.h b/composer/e-composer-common.h
new file mode 100644
index 0000000000..f03b7ca344
--- /dev/null
+++ b/composer/e-composer-common.h
@@ -0,0 +1,10 @@
+#ifndef E_COMPOSER_COMMON
+#define E_COMPOSER_COMMON
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#endif /* E_COMPOSER_COMMON */
diff --git a/composer/e-composer-from-header.c b/composer/e-composer-from-header.c
new file mode 100644
index 0000000000..de4f8ac8e0
--- /dev/null
+++ b/composer/e-composer-from-header.c
@@ -0,0 +1,178 @@
+#include "e-composer-from-header.h"
+
+#define E_COMPOSER_FROM_HEADER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeaderPrivate))
+
+struct _EComposerFromHeaderPrivate {
+ GtkWidget *combo_box;
+};
+
+static gpointer parent_class;
+
+static void
+composer_from_header_changed_cb (EAccountComboBox *combo_box,
+ EComposerFromHeader *header)
+{
+ g_signal_emit_by_name (header, "changed");
+}
+
+static void
+composer_from_header_dispose (GObject *object)
+{
+ EComposerFromHeaderPrivate *priv;
+
+ priv = E_COMPOSER_FROM_HEADER_GET_PRIVATE (object);
+
+ if (priv->combo_box != NULL) {
+ g_object_unref (priv->combo_box);
+ priv->combo_box = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+composer_from_header_class_init (EComposerFromHeaderClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EComposerFromHeaderPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = composer_from_header_dispose;
+}
+
+static void
+composer_from_header_init (EComposerFromHeader *header)
+{
+ GtkWidget *hbox;
+ GtkWidget *widget;
+
+ header->priv = E_COMPOSER_FROM_HEADER_GET_PRIVATE (header);
+
+ hbox = g_object_ref_sink (gtk_hbox_new (FALSE, 6));
+ E_COMPOSER_HEADER (header)->input_widget = hbox;
+
+ widget = e_account_combo_box_new ();
+ g_signal_connect (
+ widget, "changed",
+ G_CALLBACK (composer_from_header_changed_cb), header);
+ gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
+ header->priv->combo_box = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+}
+
+GType
+e_composer_from_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EComposerFromHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_from_header_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EComposerFromHeader),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) composer_from_header_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_COMPOSER_HEADER, "EComposerFromHeader",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EComposerHeader *
+e_composer_from_header_new (const gchar *label)
+{
+ return g_object_new (
+ E_TYPE_COMPOSER_FROM_HEADER, "label", label,
+ "button", FALSE, NULL);
+}
+
+void
+e_composer_from_header_set_account_list (EComposerFromHeader *header,
+ EAccountList *account_list)
+{
+ EAccountComboBox *combo_box;
+
+ g_return_if_fail (E_IS_COMPOSER_FROM_HEADER (header));
+
+ combo_box = E_ACCOUNT_COMBO_BOX (header->priv->combo_box);
+ e_account_combo_box_set_account_list (combo_box, account_list);
+}
+
+EAccount *
+e_composer_from_header_get_active (EComposerFromHeader *header)
+{
+ EAccountComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL);
+
+ combo_box = E_ACCOUNT_COMBO_BOX (header->priv->combo_box);
+ return e_account_combo_box_get_active (combo_box);
+}
+
+gboolean
+e_composer_from_header_set_active (EComposerFromHeader *header,
+ EAccount *account)
+{
+ EAccountComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), FALSE);
+
+ combo_box = E_ACCOUNT_COMBO_BOX (header->priv->combo_box);
+ return e_account_combo_box_set_active (combo_box, account);
+}
+
+const gchar *
+e_composer_from_header_get_active_name (EComposerFromHeader *header)
+{
+ EAccountComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL);
+
+ combo_box = E_ACCOUNT_COMBO_BOX (header->priv->combo_box);
+ return e_account_combo_box_get_active_name (combo_box);
+}
+
+gboolean
+e_composer_from_header_set_active_name (EComposerFromHeader *header,
+ const gchar *account_name)
+{
+ EAccountComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), FALSE);
+
+ combo_box = E_ACCOUNT_COMBO_BOX (header->priv->combo_box);
+ return e_account_combo_box_set_active_name (combo_box, account_name);
+}
+
+CamelInternetAddress *
+e_composer_from_header_get_active_address (EComposerFromHeader *header)
+{
+ CamelInternetAddress *address;
+ EAccount *account;
+
+ g_return_val_if_fail (E_IS_COMPOSER_FROM_HEADER (header), NULL);
+
+ account = e_composer_from_header_get_active (header);
+ if (account == NULL)
+ return NULL;
+
+ address = camel_internet_address_new ();
+ camel_internet_address_add (
+ address, account->id->name, account->id->address);
+
+ return address;
+}
diff --git a/composer/e-composer-from-header.h b/composer/e-composer-from-header.h
new file mode 100644
index 0000000000..39fb09ca6b
--- /dev/null
+++ b/composer/e-composer-from-header.h
@@ -0,0 +1,67 @@
+#ifndef E_COMPOSER_FROM_HEADER_H
+#define E_COMPOSER_FROM_HEADER_H
+
+#include "e-composer-common.h"
+
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+#include <camel/camel-internet-address.h>
+
+#include "e-account-combo-box.h"
+#include "e-composer-header.h"
+
+/* Standard GObject macros */
+#define E_TYPE_COMPOSER_FROM_HEADER \
+ (e_composer_from_header_get_type ())
+#define E_COMPOSER_FROM_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeader))
+#define E_COMPOSER_FROM_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeaderClass))
+#define E_IS_COMPOSER_FROM_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER))
+#define E_IS_COMPOSER_FROM_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER))
+#define E_COMPOSER_FROM_HEADER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeaderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EComposerFromHeader EComposerFromHeader;
+typedef struct _EComposerFromHeaderClass EComposerFromHeaderClass;
+typedef struct _EComposerFromHeaderPrivate EComposerFromHeaderPrivate;
+
+struct _EComposerFromHeader {
+ EComposerHeader parent;
+ EComposerFromHeaderPrivate *priv;
+};
+
+struct _EComposerFromHeaderClass {
+ EComposerHeaderClass parent_class;
+};
+
+GType e_composer_from_header_get_type (void);
+EComposerHeader * e_composer_from_header_new (const gchar *label);
+void e_composer_from_header_set_account_list
+ (EComposerFromHeader *header,
+ EAccountList *account_list);
+EAccount * e_composer_from_header_get_active
+ (EComposerFromHeader *header);
+gboolean e_composer_from_header_set_active
+ (EComposerFromHeader *header,
+ EAccount *account);
+const gchar * e_composer_from_header_get_active_name
+ (EComposerFromHeader *header);
+gboolean e_composer_from_header_set_active_name
+ (EComposerFromHeader *header,
+ const gchar *account_name);
+CamelInternetAddress * e_composer_from_header_get_active_address
+ (EComposerFromHeader *header);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_FROM_HEADER_H */
diff --git a/composer/e-composer-header.c b/composer/e-composer-header.c
new file mode 100644
index 0000000000..a7c10997cc
--- /dev/null
+++ b/composer/e-composer-header.c
@@ -0,0 +1,310 @@
+#include "e-composer-header.h"
+
+#define E_COMPOSER_HEADER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_COMPOSER_HEADER, EComposerHeaderPrivate))
+
+enum {
+ PROP_0,
+ PROP_BUTTON,
+ PROP_LABEL,
+ PROP_VISIBLE
+};
+
+enum {
+ CHANGED,
+ CLICKED,
+ LAST_SIGNAL
+};
+
+struct _EComposerHeaderPrivate {
+ gchar *label;
+ gboolean button;
+};
+
+static gpointer parent_class;
+static guint signal_ids[LAST_SIGNAL];
+
+static void
+composer_header_button_clicked_cb (GtkButton *button,
+ EComposerHeader *header)
+{
+ gtk_widget_grab_focus (header->input_widget);
+ g_signal_emit (header, signal_ids[CLICKED], 0);
+}
+
+static GObject *
+composer_header_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GtkWidget *widget;
+ EComposerHeader *header;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ header = E_COMPOSER_HEADER (object);
+
+ if (header->priv->button) {
+ widget = gtk_button_new_with_mnemonic (header->priv->label);
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
+ g_signal_connect (
+ widget, "clicked",
+ G_CALLBACK (composer_header_button_clicked_cb),
+ header);
+ } else {
+ widget = gtk_label_new_with_mnemonic (header->priv->label);
+
+ /* The subclass may not have initialized 'input_widget' yet,
+ * in which case the subclass will have to do this. */
+ if (header->input_widget != NULL)
+ gtk_label_set_mnemonic_widget (
+ GTK_LABEL (widget), header->input_widget);
+ }
+ header->title_widget = g_object_ref_sink (widget);
+
+ g_free (header->priv->label);
+ header->priv->label = NULL;
+
+ return object;
+}
+
+static void
+composer_header_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EComposerHeaderPrivate *priv;
+
+ priv = E_COMPOSER_HEADER_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_BUTTON: /* construct only */
+ priv->button = g_value_get_boolean (value);
+ return;
+
+ case PROP_LABEL: /* construct only */
+ priv->label = g_value_dup_string (value);
+ return;
+
+ case PROP_VISIBLE:
+ e_composer_header_set_visible (
+ E_COMPOSER_HEADER (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_header_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EComposerHeaderPrivate *priv;
+
+ priv = E_COMPOSER_HEADER_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_BUTTON: /* construct only */
+ g_value_set_boolean (value, priv->button);
+ return;
+
+ case PROP_LABEL: /* construct only */
+ g_value_take_string (
+ value, e_composer_header_get_label (
+ E_COMPOSER_HEADER (object)));
+ return;
+
+ case PROP_VISIBLE:
+ g_value_set_boolean (
+ value, e_composer_header_get_visible (
+ E_COMPOSER_HEADER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_header_dispose (GObject *object)
+{
+ EComposerHeader *header = E_COMPOSER_HEADER (object);
+
+ if (header->title_widget != NULL) {
+ g_object_unref (header->title_widget);
+ header->title_widget = NULL;
+ }
+
+ if (header->input_widget != NULL) {
+ g_object_unref (header->input_widget);
+ header->input_widget = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+composer_header_class_init (EComposerHeaderClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EComposerHeaderPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = composer_header_constructor;
+ object_class->set_property = composer_header_set_property;
+ object_class->get_property = composer_header_get_property;
+ object_class->dispose = composer_header_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_BUTTON,
+ g_param_spec_boolean (
+ "button",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_LABEL,
+ g_param_spec_string (
+ "label",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_VISIBLE,
+ g_param_spec_boolean (
+ "visible",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ signal_ids[CHANGED] = g_signal_new (
+ "changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signal_ids[CLICKED] = g_signal_new (
+ "clicked",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+composer_header_init (EComposerHeader *header)
+{
+ header->priv = E_COMPOSER_HEADER_GET_PRIVATE (header);
+}
+
+GType
+e_composer_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EComposerHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_header_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EComposerHeader),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) composer_header_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ G_TYPE_OBJECT, "EComposerHeader",
+ &type_info, G_TYPE_FLAG_ABSTRACT);
+ }
+
+ return type;
+}
+
+gchar *
+e_composer_header_get_label (EComposerHeader *header)
+{
+ gchar *label;
+
+ g_return_val_if_fail (E_IS_COMPOSER_HEADER (header), NULL);
+
+ /* GtkButton and GtkLabel both have a "label" property. */
+ g_object_get (header->title_widget, "label", &label, NULL);
+
+ return label;
+}
+
+gboolean
+e_composer_header_get_visible (EComposerHeader *header)
+{
+ gboolean visible;
+
+ g_return_val_if_fail (E_IS_COMPOSER_HEADER (header), FALSE);
+
+ visible = GTK_WIDGET_VISIBLE (header->title_widget);
+ if (GTK_WIDGET_VISIBLE (header->input_widget) != visible)
+ g_warning ("%s: Visibility is out of sync", G_STRFUNC);
+
+ return visible;
+}
+
+void
+e_composer_header_set_visible (EComposerHeader *header,
+ gboolean visible)
+{
+ g_return_if_fail (E_IS_COMPOSER_HEADER (header));
+
+ if (visible) {
+ gtk_widget_show (header->title_widget);
+ gtk_widget_show (header->input_widget);
+ } else {
+ gtk_widget_hide (header->title_widget);
+ gtk_widget_hide (header->input_widget);
+ }
+
+ g_object_notify (G_OBJECT (header), "visible");
+}
+
+void
+e_composer_header_set_title_tooltip (EComposerHeader *header,
+ const gchar *tooltip)
+{
+ g_return_if_fail (E_IS_COMPOSER_HEADER (header));
+
+ gtk_widget_set_tooltip_text (header->title_widget, tooltip);
+}
+
+void
+e_composer_header_set_input_tooltip (EComposerHeader *header,
+ const gchar *tooltip)
+{
+ g_return_if_fail (E_IS_COMPOSER_HEADER (header));
+
+ gtk_widget_set_tooltip_text (header->input_widget, tooltip);
+}
diff --git a/composer/e-composer-header.h b/composer/e-composer-header.h
new file mode 100644
index 0000000000..c98b3419e4
--- /dev/null
+++ b/composer/e-composer-header.h
@@ -0,0 +1,56 @@
+#ifndef E_COMPOSER_HEADER_H
+#define E_COMPOSER_HEADER_H
+
+#include "e-composer-common.h"
+
+/* Standard GObject macros */
+#define E_TYPE_COMPOSER_HEADER \
+ (e_composer_header_get_type ())
+#define E_COMPOSER_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_COMPOSER_HEADER, EComposerHeader))
+#define E_COMPOSER_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((obj), E_TYPE_COMPOSER_HEADER, EComposerHeaderClass))
+#define E_IS_COMPOSER_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_COMPOSER_HEADER))
+#define E_IS_COMPOSER_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_COMPOSER_HEADER))
+#define E_COMPOSER_HEADER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_COMPOSER_HEADER, EComposerHeaderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EComposerHeader EComposerHeader;
+typedef struct _EComposerHeaderClass EComposerHeaderClass;
+typedef struct _EComposerHeaderPrivate EComposerHeaderPrivate;
+
+struct _EComposerHeader {
+ GObject parent;
+ GtkWidget *title_widget;
+ GtkWidget *input_widget;
+ EComposerHeaderPrivate *priv;
+};
+
+struct _EComposerHeaderClass {
+ GObjectClass parent_class;
+};
+
+GType e_composer_header_get_type (void);
+gchar * e_composer_header_get_label (EComposerHeader *header);
+gboolean e_composer_header_get_visible (EComposerHeader *header);
+void e_composer_header_set_visible (EComposerHeader *header,
+ gboolean visible);
+void e_composer_header_set_title_tooltip
+ (EComposerHeader *header,
+ const gchar *tooltip);
+void e_composer_header_set_input_tooltip
+ (EComposerHeader *header,
+ const gchar *tooltip);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_HEADER_H */
diff --git a/composer/e-composer-name-header.c b/composer/e-composer-name-header.c
new file mode 100644
index 0000000000..f54b50d87e
--- /dev/null
+++ b/composer/e-composer-name-header.c
@@ -0,0 +1,301 @@
+#include "e-composer-name-header.h"
+
+#include <glib/gi18n.h>
+
+/* XXX Temporary kludge */
+#include "addressbook/gui/contact-editor/e-contact-editor.h"
+#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
+
+#define E_COMPOSER_NAME_HEADER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderPrivate))
+
+enum {
+ PROP_0,
+ PROP_NAME_SELECTOR
+};
+
+struct _EComposerNameHeaderPrivate {
+ ENameSelector *name_selector;
+ guint destination_index;
+};
+
+static gpointer parent_class;
+
+static void
+composer_name_header_clicked_cb (EComposerNameHeader *header)
+{
+ ENameSelectorDialog *dialog;
+
+ dialog = e_name_selector_peek_dialog (header->priv->name_selector);
+ e_name_selector_dialog_set_destination_index (
+ dialog, header->priv->destination_index);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_hide (GTK_WIDGET (dialog));
+}
+
+static void
+composer_name_header_entry_changed_cb (ENameSelectorEntry *entry,
+ EComposerNameHeader *header)
+{
+ g_signal_emit_by_name (header, "changed");
+}
+
+static gboolean
+composer_name_header_entry_query_tooltip_cb (GtkEntry *entry,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip)
+{
+ const gchar *text;
+
+ text = gtk_entry_get_text (entry);
+
+ if (keyboard_mode || text == NULL || *text == '\0')
+ return FALSE;
+
+ gtk_tooltip_set_text (tooltip, text);
+
+ return TRUE;
+}
+
+static GObject *
+composer_name_header_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ EComposerNameHeaderPrivate *priv;
+ ENameSelectorModel *model;
+ ENameSelectorEntry *entry;
+ GObject *object;
+ gchar *label;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
+ g_assert (E_IS_NAME_SELECTOR (priv->name_selector));
+
+ model = e_name_selector_peek_model (priv->name_selector);
+ label = e_composer_header_get_label (E_COMPOSER_HEADER (object));
+ g_assert (label != NULL);
+
+ /* XXX Peeking at private data. */
+ priv->destination_index = model->sections->len;
+ e_name_selector_model_add_section (model, label, label, NULL);
+
+ e_composer_header_set_title_tooltip (
+ E_COMPOSER_HEADER (object),
+ _("Click here for the address book"));
+
+ entry = E_NAME_SELECTOR_ENTRY (
+ e_name_selector_peek_section_list (
+ priv->name_selector, label));
+ e_name_selector_entry_set_contact_editor_func (
+ entry, e_contact_editor_new);
+ e_name_selector_entry_set_contact_list_editor_func (
+ entry, e_contact_list_editor_new);
+ g_signal_connect (
+ entry, "changed",
+ G_CALLBACK (composer_name_header_entry_changed_cb), object);
+ g_signal_connect (
+ entry, "query-tooltip",
+ G_CALLBACK (composer_name_header_entry_query_tooltip_cb),
+ NULL);
+ E_COMPOSER_HEADER (object)->input_widget = g_object_ref_sink (entry);
+
+ g_signal_connect (
+ object, "clicked",
+ G_CALLBACK (composer_name_header_clicked_cb), NULL);
+
+ return object;
+}
+
+static void
+composer_name_header_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EComposerNameHeaderPrivate *priv;
+
+ priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
+
+ switch (property_id) {
+ case PROP_NAME_SELECTOR: /* construct only */
+ g_assert (priv->name_selector == NULL);
+ priv->name_selector = g_value_dup_object (value);
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_name_header_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_NAME_SELECTOR: /* construct only */
+ g_value_set_object (
+ value,
+ e_composer_name_header_get_name_selector (
+ E_COMPOSER_NAME_HEADER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_name_header_dispose (GObject *object)
+{
+ EComposerNameHeaderPrivate *priv;
+
+ priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
+
+ if (priv->name_selector != NULL) {
+ g_object_unref (priv->name_selector);
+ priv->name_selector = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+composer_name_header_class_init (EComposerNameHeaderClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EComposerNameHeaderPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = composer_name_header_constructor;
+ object_class->set_property = composer_name_header_set_property;
+ object_class->get_property = composer_name_header_get_property;
+ object_class->dispose = composer_name_header_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_NAME_SELECTOR,
+ g_param_spec_object (
+ "name-selector",
+ NULL,
+ NULL,
+ E_TYPE_NAME_SELECTOR,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+composer_name_header_init (EComposerNameHeader *header)
+{
+ header->priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (header);
+}
+
+GType
+e_composer_name_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EComposerNameHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_name_header_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EComposerNameHeader),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) composer_name_header_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_COMPOSER_HEADER, "EComposerNameHeader",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EComposerHeader *
+e_composer_name_header_new (const gchar *label,
+ ENameSelector *name_selector)
+{
+ g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
+
+ return g_object_new (
+ E_TYPE_COMPOSER_NAME_HEADER, "label", label,
+ "button", TRUE, "name-selector", name_selector, NULL);
+}
+
+ENameSelector *
+e_composer_name_header_get_name_selector (EComposerNameHeader *header)
+{
+ g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
+
+ return header->priv->name_selector;
+}
+
+EDestination **
+e_composer_name_header_get_destinations (EComposerNameHeader *header)
+{
+ EDestinationStore *store;
+ EDestination **destinations;
+ GtkWidget *input_widget;
+ GList *list, *iter;
+ gint ii = 0;
+
+ g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
+
+ input_widget = E_COMPOSER_HEADER (header)->input_widget;
+ store = e_name_selector_entry_peek_destination_store (
+ E_NAME_SELECTOR_ENTRY (input_widget));
+
+ list = e_destination_store_list_destinations (store);
+ destinations = g_new0 (EDestination *, g_list_length (list) + 1);
+
+ for (iter = list; iter != NULL; iter = iter->next)
+ destinations[ii++] = g_object_ref (iter->data);
+
+ g_list_free (list);
+
+ return destinations;
+}
+
+void
+e_composer_name_header_set_destinations (EComposerNameHeader *header,
+ EDestination **destinations)
+{
+ EDestinationStore *store;
+ GtkWidget *input_widget;
+ GList *list, *iter;
+ gint ii;
+
+ g_return_if_fail (E_IS_COMPOSER_NAME_HEADER (header));
+
+ input_widget = E_COMPOSER_HEADER (header)->input_widget;
+ store = e_name_selector_entry_peek_destination_store (
+ E_NAME_SELECTOR_ENTRY (input_widget));
+
+ /* Clear the destination store. */
+ list = e_destination_store_list_destinations (store);
+ for (iter = list; iter != NULL; iter = iter->next)
+ e_destination_store_remove_destination (store, iter->data);
+ g_list_free (list);
+
+ if (destinations == NULL)
+ return;
+
+ for (ii = 0; destinations[ii] != NULL; ii++)
+ e_destination_store_append_destination (
+ store, destinations[ii]);
+}
diff --git a/composer/e-composer-name-header.h b/composer/e-composer-name-header.h
new file mode 100644
index 0000000000..1027c14d3c
--- /dev/null
+++ b/composer/e-composer-name-header.h
@@ -0,0 +1,58 @@
+#ifndef E_COMPOSER_NAME_HEADER_H
+#define E_COMPOSER_NAME_HEADER_H
+
+#include "e-composer-common.h"
+
+#include <libebook/e-destination.h>
+#include <libedataserverui/e-name-selector.h>
+
+#include "e-composer-header.h"
+
+/* Standard GObject macros */
+#define E_TYPE_COMPOSER_NAME_HEADER \
+ (e_composer_name_header_get_type ())
+#define E_COMPOSER_NAME_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeader))
+#define E_COMPOSER_NAME_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderClass))
+#define E_IS_COMPOSER_NAME_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_COMPOSER_NAME_HEADER))
+#define E_IS_COMPOSER_NAME_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_COMPOSER_NAME_HEADER))
+#define E_COMPOSER_NAME_HEADER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EComposerNameHeader EComposerNameHeader;
+typedef struct _EComposerNameHeaderClass EComposerNameHeaderClass;
+typedef struct _EComposerNameHeaderPrivate EComposerNameHeaderPrivate;
+
+struct _EComposerNameHeader {
+ EComposerHeader parent;
+ EComposerNameHeaderPrivate *priv;
+};
+
+struct _EComposerNameHeaderClass {
+ EComposerHeaderClass parent_class;
+};
+
+GType e_composer_name_header_get_type (void);
+EComposerHeader * e_composer_name_header_new (const gchar *label,
+ ENameSelector *name_selector);
+ENameSelector * e_composer_name_header_get_name_selector
+ (EComposerNameHeader *header);
+EDestination ** e_composer_name_header_get_destinations
+ (EComposerNameHeader *header);
+void e_composer_name_header_set_destinations
+ (EComposerNameHeader *header,
+ EDestination **destinations);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_NAME_HEADER_H */
diff --git a/composer/e-composer-post-header.c b/composer/e-composer-post-header.c
new file mode 100644
index 0000000000..ea16eeb684
--- /dev/null
+++ b/composer/e-composer-post-header.c
@@ -0,0 +1,401 @@
+#include "e-composer-post-header.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "mail/em-folder-selector.h"
+#include "mail/em-folder-tree.h"
+
+#define E_COMPOSER_POST_HEADER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderPrivate))
+
+enum {
+ PROP_0,
+ PROP_ACCOUNT
+};
+
+struct _EComposerPostHeaderPrivate {
+ EAccount *account;
+ gchar *base_url; /* derived from account */
+ gboolean custom;
+};
+
+static gpointer parent_class;
+
+/* Forward Declarations (to avoid pulling in Bonobo stuff) */
+struct _MailComponent *mail_component_peek (void);
+struct _EMFolderTreeModel *mail_component_peek_tree_model (struct _MailComponent *component);
+
+static gchar *
+composer_post_header_folder_name_to_string (EComposerPostHeader *header,
+ const gchar *url)
+{
+ const gchar *base_url = header->priv->base_url;
+
+ if (base_url != NULL) {
+ gsize length = strlen (base_url);
+
+ if (g_ascii_strncasecmp (url, base_url, length) == 0)
+ return g_strdup (url + length);
+ }
+
+ return g_strdup (url);
+}
+
+static void
+composer_post_header_set_base_url (EComposerPostHeader *header)
+{
+ EAccount *account = header->priv->account;
+ CamelURL *camel_url;
+ gchar *url;
+
+ if (account == NULL || account->source == NULL)
+ return;
+
+ url = account->source->url;
+ if (url == NULL || *url == '\0')
+ return;
+
+ camel_url = camel_url_new (url, NULL);
+ if (camel_url == NULL)
+ return;
+
+ url = camel_url_to_string (camel_url, CAMEL_URL_HIDE_ALL);
+ camel_url_free (camel_url);
+
+ header->priv->base_url = url;
+}
+
+static GList *
+composer_post_header_split_csv (const gchar *csv)
+{
+ GList *list = NULL;
+ gchar **strv;
+ guint length, ii;
+
+ strv = g_strsplit (csv, ",", 0);
+ length = g_strv_length (strv);
+
+ for (ii = 0; ii < length; ii++)
+ if (*g_strstrip (strv[ii]) != '\0')
+ list = g_list_prepend (list, g_strdup (strv[ii]));
+
+ g_strfreev (strv);
+
+ return g_list_reverse (list);
+}
+
+static void
+composer_post_header_changed_cb (EComposerPostHeader *header)
+{
+ header->priv->custom = TRUE;
+}
+
+static void
+composer_post_header_clicked_cb (EComposerPostHeader *header)
+{
+ EMFolderTreeModel *model;
+ GtkWidget *folder_tree;
+ GtkWidget *dialog;
+ GList *list;
+
+ model = mail_component_peek_tree_model (mail_component_peek ());
+ folder_tree = em_folder_tree_new_with_model (model);
+
+ em_folder_tree_set_multiselect (
+ EM_FOLDER_TREE (folder_tree), TRUE);
+ em_folder_tree_set_excluded (
+ EM_FOLDER_TREE (folder_tree),
+ EMFT_EXCLUDE_NOSELECT |
+ EMFT_EXCLUDE_VIRTUAL |
+ EMFT_EXCLUDE_VTRASH);
+
+ dialog = em_folder_selector_new (
+ EM_FOLDER_TREE (folder_tree),
+ EM_FOLDER_SELECTOR_CAN_CREATE,
+ _("Posting destination"),
+ _("Choose folders to post the message to."),
+ NULL);
+
+ list = e_composer_post_header_get_folders (header);
+ em_folder_selector_set_selected_list (
+ EM_FOLDER_SELECTOR (dialog), list);
+ g_list_foreach (list, (GFunc) g_free, NULL);
+ g_list_free (list);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ list = em_folder_selector_get_selected_uris (
+ EM_FOLDER_SELECTOR (dialog));
+ e_composer_post_header_set_folders (header, list);
+ header->priv->custom = FALSE;
+ g_list_foreach (list, (GFunc) g_free, NULL);
+ g_list_free (list);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static GObject *
+composer_post_header_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ e_composer_header_set_title_tooltip (
+ E_COMPOSER_HEADER (object),
+ _("Click here to select folders to post to"));
+
+ g_signal_connect (
+ object, "changed",
+ G_CALLBACK (composer_post_header_changed_cb), NULL);
+
+ g_signal_connect (
+ object, "clicked",
+ G_CALLBACK (composer_post_header_clicked_cb), NULL);
+
+ return object;
+}
+
+static void
+composer_post_header_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT:
+ e_composer_post_header_set_account (
+ E_COMPOSER_POST_HEADER (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_post_header_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_ACCOUNT:
+ g_value_set_object (
+ value, e_composer_post_header_get_account (
+ E_COMPOSER_POST_HEADER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+composer_post_header_dispose (GObject *object)
+{
+ EComposerPostHeaderPrivate *priv;
+
+ priv = E_COMPOSER_POST_HEADER_GET_PRIVATE (object);
+
+ if (priv->account != NULL) {
+ g_object_unref (priv->account);
+ priv->account = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+composer_post_header_class_init (EComposerPostHeaderClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EComposerPostHeaderPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = composer_post_header_constructor;
+ object_class->set_property = composer_post_header_set_property;
+ object_class->get_property = composer_post_header_get_property;
+ object_class->dispose = composer_post_header_dispose;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_ACCOUNT,
+ g_param_spec_object (
+ "account",
+ NULL,
+ NULL,
+ E_TYPE_ACCOUNT,
+ G_PARAM_READWRITE));
+}
+
+static void
+composer_post_header_init (EComposerPostHeader *header)
+{
+ header->priv = E_COMPOSER_POST_HEADER_GET_PRIVATE (header);
+}
+
+GType
+e_composer_post_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EComposerPostHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_post_header_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EComposerPostHeader),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) composer_post_header_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_COMPOSER_TEXT_HEADER,
+ "EComposerPostHeader", &type_info, 0);
+ }
+
+ return type;
+}
+
+EComposerHeader *
+e_composer_post_header_new (const gchar *label)
+{
+ return g_object_new (
+ E_TYPE_COMPOSER_POST_HEADER,
+ "label", label, "button", TRUE, NULL);
+}
+
+EAccount *
+e_composer_post_header_get_account (EComposerPostHeader *header)
+{
+ g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL);
+
+ return header->priv->account;
+}
+
+void
+e_composer_post_header_set_account (EComposerPostHeader *header,
+ EAccount *account)
+{
+ GList *folders = NULL;
+
+ g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header));
+
+ if (account != NULL) {
+ g_return_if_fail (E_IS_ACCOUNT (account));
+ g_object_ref (account);
+ }
+
+ if (!header->priv->custom)
+ folders = e_composer_post_header_get_folders (header);
+
+ if (header->priv->account != NULL)
+ g_object_unref (header->priv->account);
+
+ header->priv->account = account;
+ composer_post_header_set_base_url (header);
+
+ /* Make folders relative to the new account. */
+ if (!header->priv->custom) {
+ e_composer_post_header_set_folders (header, folders);
+ g_list_foreach (folders, (GFunc) g_free, NULL);
+ g_list_free (folders);
+ }
+
+ g_object_notify (G_OBJECT (header), "account");
+}
+
+GList *
+e_composer_post_header_get_folders (EComposerPostHeader *header)
+{
+ GList *folders, *iter;
+ gchar *base_url;
+
+ g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL);
+
+ folders = composer_post_header_split_csv (
+ e_composer_text_header_get_text (
+ E_COMPOSER_TEXT_HEADER (header)));
+
+ base_url = header->priv->base_url;
+ if (base_url == NULL)
+ return folders;
+
+ for (iter = folders; iter != NULL; iter = iter->next) {
+ /* Convert relative folder names to absolute. */
+ /* XXX Should use CamelURL for this. */
+ if (strstr (iter->data, ":/") == NULL) {
+ gchar *abs_url;
+
+ abs_url = g_strconcat (base_url, iter->data, NULL);
+ g_free (iter->data);
+ iter->data = abs_url;
+ }
+ }
+
+ return folders;
+}
+
+void
+e_composer_post_header_set_folders (EComposerPostHeader *header,
+ GList *folders)
+{
+ GList *iter;
+ gint ii = 0;
+ gchar **strv;
+ gchar *text;
+ gboolean custom_save;
+
+ g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header));
+
+ strv = g_new0 (gchar *, g_list_length (folders) + 1);
+
+ for (iter = folders; iter != NULL; iter = iter->next)
+ strv[ii++] = composer_post_header_folder_name_to_string (
+ header, iter->data);
+
+ text = g_strjoinv (", ", strv);
+ custom_save = header->priv->custom;
+ e_composer_text_header_set_text (
+ E_COMPOSER_TEXT_HEADER (header), text);
+ header->priv->custom = custom_save;
+ g_free (text);
+
+ g_strfreev (strv);
+}
+
+void
+e_composer_post_header_set_folders_base (EComposerPostHeader *header,
+ const gchar *base_url,
+ const gchar *folders)
+{
+ GList *list, *iter;
+
+ list = composer_post_header_split_csv (folders);
+ for (iter = list; iter != NULL; iter = iter->next) {
+ gchar *abs_url;
+
+ /* FIXME This doesn't handle all folder names properly. */
+ abs_url = g_strdup_printf (
+ "%s/%s", base_url, (gchar *) iter->data);
+ g_free (iter->data);
+ iter->data = abs_url;
+ }
+
+ e_composer_post_header_set_folders (header, list);
+ g_list_foreach (list, (GFunc) g_free, NULL);
+ g_list_free (list);
+}
diff --git a/composer/e-composer-post-header.h b/composer/e-composer-post-header.h
new file mode 100644
index 0000000000..2825b6c5dd
--- /dev/null
+++ b/composer/e-composer-post-header.h
@@ -0,0 +1,63 @@
+#ifndef E_COMPOSER_POST_HEADER_H
+#define E_COMPOSER_POST_HEADER_H
+
+#include "e-composer-common.h"
+
+#include <libedataserver/e-account.h>
+
+#include "e-composer-text-header.h"
+
+/* Standard GObject macros */
+#define E_TYPE_COMPOSER_POST_HEADER \
+ (e_composer_post_header_get_type ())
+#define E_COMPOSER_POST_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeader))
+#define E_COMPOSER_POST_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderClass))
+#define E_IS_COMPOSER_POST_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_COMPOSER_POST_HEADER))
+#define E_IS_COMPOSER_POST_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_COMPOSER_POST_HEADER))
+#define E_COMPOSER_POST_HEADER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EComposerPostHeader EComposerPostHeader;
+typedef struct _EComposerPostHeaderClass EComposerPostHeaderClass;
+typedef struct _EComposerPostHeaderPrivate EComposerPostHeaderPrivate;
+
+struct _EComposerPostHeader {
+ EComposerTextHeader parent;
+ EComposerPostHeaderPrivate *priv;
+};
+
+struct _EComposerPostHeaderClass {
+ EComposerTextHeaderClass parent_class;
+};
+
+GType e_composer_post_header_get_type (void);
+EComposerHeader * e_composer_post_header_new (const gchar *label);
+EAccount * e_composer_post_header_get_account
+ (EComposerPostHeader *header);
+void e_composer_post_header_set_account
+ (EComposerPostHeader *header,
+ EAccount *account);
+GList * e_composer_post_header_get_folders
+ (EComposerPostHeader *header);
+void e_composer_post_header_set_folders
+ (EComposerPostHeader *header,
+ GList *folders);
+void e_composer_post_header_set_folders_base
+ (EComposerPostHeader *header,
+ const gchar *base_url,
+ const gchar *folders);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_POST_HEADER_H */
diff --git a/composer/e-composer-text-header.c b/composer/e-composer-text-header.c
new file mode 100644
index 0000000000..4ef761e450
--- /dev/null
+++ b/composer/e-composer-text-header.c
@@ -0,0 +1,120 @@
+#include "e-composer-text-header.h"
+
+static gpointer parent_class;
+
+static void
+composer_text_header_changed_cb (GtkEntry *entry,
+ EComposerTextHeader *header)
+{
+ g_signal_emit_by_name (header, "changed");
+}
+
+static gboolean
+composer_text_header_query_tooltip_cb (GtkEntry *entry,
+ gint x,
+ gint y,
+ gboolean keyboard_mode,
+ GtkTooltip *tooltip)
+{
+ const gchar *text;
+
+ text = gtk_entry_get_text (entry);
+
+ if (keyboard_mode || text == NULL || *text == '\0')
+ return FALSE;
+
+ gtk_tooltip_set_text (tooltip, text);
+
+ return TRUE;
+}
+
+static void
+composer_text_header_class_init (EComposerTextHeaderClass *class)
+{
+ parent_class = g_type_class_peek_parent (class);
+}
+
+static void
+composer_text_header_init (EComposerTextHeader *header)
+{
+ GtkWidget *widget;
+
+ widget = g_object_ref_sink (gtk_entry_new ());
+ g_signal_connect (
+ widget, "changed",
+ G_CALLBACK (composer_text_header_changed_cb), header);
+ g_signal_connect (
+ widget, "query-tooltip",
+ G_CALLBACK (composer_text_header_query_tooltip_cb), NULL);
+ gtk_widget_set_has_tooltip (widget, TRUE);
+ E_COMPOSER_HEADER (header)->input_widget = widget;
+}
+
+GType
+e_composer_text_header_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EComposerTextHeaderClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) composer_text_header_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EComposerTextHeader),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) composer_text_header_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_COMPOSER_HEADER, "EComposerTextHeader",
+ &type_info, 0);
+ }
+
+ return type;
+}
+
+EComposerHeader *
+e_composer_text_header_new_label (const gchar *label)
+{
+ return g_object_new (
+ E_TYPE_COMPOSER_TEXT_HEADER, "label", label,
+ "button", FALSE, NULL);
+}
+
+EComposerHeader *
+e_composer_text_header_new_button (const gchar *label)
+{
+ return g_object_new (
+ E_TYPE_COMPOSER_TEXT_HEADER, "label", label,
+ "button", TRUE, NULL);
+}
+
+const gchar *
+e_composer_text_header_get_text (EComposerTextHeader *header)
+{
+ GtkWidget *input_widget;
+
+ g_return_val_if_fail (E_IS_COMPOSER_TEXT_HEADER (header), NULL);
+
+ input_widget = E_COMPOSER_HEADER (header)->input_widget;
+ return gtk_entry_get_text (GTK_ENTRY (input_widget));
+}
+
+void
+e_composer_text_header_set_text (EComposerTextHeader *header,
+ const gchar *text)
+{
+ GtkWidget *input_widget;
+
+ g_return_if_fail (E_IS_COMPOSER_TEXT_HEADER (header));
+
+ if (text == NULL)
+ text = "";
+
+ input_widget = E_COMPOSER_HEADER (header)->input_widget;
+ gtk_entry_set_text (GTK_ENTRY (input_widget), text);
+}
diff --git a/composer/e-composer-text-header.h b/composer/e-composer-text-header.h
new file mode 100644
index 0000000000..9d4bb2fa3e
--- /dev/null
+++ b/composer/e-composer-text-header.h
@@ -0,0 +1,50 @@
+#ifndef E_COMPOSER_TEXT_HEADER_H
+#define E_COMPOSER_TEXT_HEADER_H
+
+#include "e-composer-common.h"
+#include "e-composer-header.h"
+
+/* Standard GObject macros */
+#define E_TYPE_COMPOSER_TEXT_HEADER \
+ (e_composer_text_header_get_type ())
+#define E_COMPOSER_TEXT_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_COMPOSER_TEXT_HEADER, EComposerTextHeader))
+#define E_COMPOSER_TEXT_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_COMPOSER_TEXT_HEADER, EComposerTextHeaderClass))
+#define E_IS_COMPOSER_TEXT_HEADER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_COMPOSER_TEXT_HEADER))
+#define E_IS_COMPOSER_TEXT_HEADER_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_COMPOSER_TEXT_HEADER))
+#define E_COMPOSER_TEXT_HEADER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_COMPOSER_TEXT_HEADER, EComposerTextHeaderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EComposerTextHeader EComposerTextHeader;
+typedef struct _EComposerTextHeaderClass EComposerTextHeaderClass;
+
+struct _EComposerTextHeader {
+ EComposerHeader parent;
+};
+
+struct _EComposerTextHeaderClass {
+ EComposerHeaderClass parent_class;
+};
+
+GType e_composer_text_header_get_type (void);
+EComposerHeader * e_composer_text_header_new_label
+ (const gchar *label);
+EComposerHeader * e_composer_text_header_new_button
+ (const gchar *label);
+const gchar * e_composer_text_header_get_text (EComposerTextHeader *header);
+void e_composer_text_header_set_text (EComposerTextHeader *header,
+ const gchar *text);
+
+G_END_DECLS
+
+#endif /* E_COMPOSER_TEXT_HEADER_H */
diff --git a/composer/e-msg-composer-hdrs.c b/composer/e-msg-composer-hdrs.c
index 523c66f695..02208c14fa 100644
--- a/composer/e-msg-composer-hdrs.c
+++ b/composer/e-msg-composer-hdrs.c
@@ -26,753 +26,82 @@
#include <config.h>
#endif
-#include <string.h>
-
#include <bonobo/bonobo-control.h>
#include <bonobo/bonobo-widget.h>
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtktooltips.h>
-#include <libgnomeui/gnome-uidefs.h>
#include <glib/gi18n.h>
#include <libedataserverui/e-name-selector.h>
-#include <libedataserverui/e-name-selector-entry.h>
-#include <libedataserverui/e-name-selector-list.h>
#include "Composer.h"
-#include <gtk/gtkmenuitem.h>
-#include <gtk/gtkoptionmenu.h>
-#include <gtk/gtktooltips.h>
-#include <gtk/gtkentry.h>
-#include <gtk/gtklabel.h>
-#include <gtk/gtkhbox.h>
-#include <gtk/gtkmessagedialog.h>
-
-#include <gconf/gconf.h>
-#include <gconf/gconf-client.h>
-
-#include "e-util/e-error.h"
-#include "e-util/e-icon-factory.h"
-
#include <camel/camel.h>
#include <camel/camel-store.h>
#include <camel/camel-session.h>
#include "e-msg-composer-hdrs.h"
#include "mail/mail-config.h"
#include "mail/mail-session.h"
-/*#include "mail/em-folder-selection-button.h"*/
-#include "mail/em-folder-selector.h"
-
-/* another 'temporary' kludge, so we dont need to build idl's for the MailComponent */
-/*#include "mail/mail-component.h"*/
-struct _MailComponent *mail_component_peek(void);
-extern struct _EMFolderTreeModel *mail_component_peek_tree_model(struct _MailComponent *);
-
-#include "mail/em-folder-tree.h"
+#include "e-account-combo-box.h"
-/* TEMPORARY KLUDGE */
-#include "addressbook/gui/contact-editor/e-contact-editor.h"
-#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
+#include "e-composer-header.h"
+#include "e-composer-from-header.h"
+#include "e-composer-name-header.h"
+#include "e-composer-post-header.h"
+#include "e-composer-text-header.h"
-
-
-/* Indexes in the GtkTable assigned to various items */
-
-#define LINE_FROM 0
-#define LINE_REPLYTO 1
-#define LINE_TO 2
-#define LINE_CC 3
-#define LINE_BCC 4
-#define LINE_POSTTO 5
-#define LINE_SUBJECT 6
+#define E_MSG_COMPOSER_HDRS_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrsPrivate))
-
-typedef struct {
- GtkWidget *label;
- GtkWidget *entry;
- guint visible:1;
-} EMsgComposerHdrPair;
-
-struct _EMsgComposerHdrsPrivate {
- ENameSelector *name_selector;
-
- /* ui component */
- BonoboUIComponent *uic;
-
- /* The tooltips. */
- GtkTooltips *tooltips;
-
- EAccountList *accounts;
- GSList *from_options;
-
- gboolean post_custom;
-
- /* Standard headers. */
- EMsgComposerHdrPair from, reply_to, to, cc, bcc, post_to, subject;
+/* Headers, listed in the order that they should appear in the table. */
+enum {
+ HEADER_FROM,
+ HEADER_REPLY_TO,
+ HEADER_TO,
+ HEADER_CC,
+ HEADER_BCC,
+ HEADER_POST_TO,
+ HEADER_SUBJECT,
+ NUM_HEADERS
};
-
-static GtkTableClass *parent_class = NULL;
-
enum {
- SHOW_ADDRESS_DIALOG,
SUBJECT_CHANGED,
HDRS_CHANGED,
FROM_CHANGED,
LAST_SIGNAL
};
-static int signals[LAST_SIGNAL];
-
-
-static void
-addressbook_dialog_response (ENameSelectorDialog *name_selector_dialog, gint response, gpointer user_data)
-{
- gtk_widget_hide (GTK_WIDGET (name_selector_dialog));
-}
-
-static void
-setup_name_selector (EMsgComposerHdrs *hdrs)
-{
- EMsgComposerHdrsPrivate *priv;
- ENameSelectorDialog *name_selector_dialog;
-
- priv = hdrs->priv;
-
- g_return_if_fail (priv->name_selector == NULL);
-
- priv->name_selector = e_name_selector_new ();
- name_selector_dialog = e_name_selector_peek_dialog (priv->name_selector);
- g_signal_connect (name_selector_dialog, "response",
- G_CALLBACK (addressbook_dialog_response), hdrs);
-}
-
-typedef struct {
- EMsgComposerHdrs *hdrs;
- char *string;
-} EMsgComposerHdrsAndString;
-
-static void
-e_msg_composer_hdrs_and_string_free (EMsgComposerHdrsAndString *emchas)
-{
- if (emchas->hdrs)
- g_object_unref (emchas->hdrs);
- g_free (emchas->string);
- g_free (emchas);
-}
-
-static EMsgComposerHdrsAndString *
-e_msg_composer_hdrs_and_string_create (EMsgComposerHdrs *hdrs, const char *string)
-{
- EMsgComposerHdrsAndString *emchas;
-
- emchas = g_new (EMsgComposerHdrsAndString, 1);
- emchas->hdrs = hdrs;
- emchas->string = g_strdup (string);
- if (emchas->hdrs)
- g_object_ref (emchas->hdrs);
-
- return emchas;
-}
-
-static void
-address_button_clicked_cb (GtkButton *button, gpointer data)
-{
- EMsgComposerHdrsAndString *emchas;
- EMsgComposerHdrs *hdrs;
- EMsgComposerHdrsPrivate *priv;
- ENameSelectorDialog *name_selector_dialog;
- guint index = 0;
+struct _EMsgComposerHdrsPrivate {
+ ENameSelector *name_selector;
- emchas = data;
- hdrs = emchas->hdrs;
- priv = hdrs->priv;
+ /* ui component */
+ BonoboUIComponent *uic;
- if (button == (GtkButton *) hdrs->priv->to.label) {
- gtk_widget_grab_focus (hdrs->priv->to.entry);
- index = 0;
- printf("index:%d\n", index);
- }
- else if (button == (GtkButton *) priv->cc.label) {
- gtk_widget_grab_focus (hdrs->priv->cc.entry);
- index = 1;
- printf("index:%d\n", index);
- }
- else if (button == (GtkButton *) priv->bcc.label) {
- gtk_widget_grab_focus (hdrs->priv->bcc.entry);
- index = 2;
- printf("index:%d\n", index);
- }
+ EComposerHeader *headers[NUM_HEADERS];
+};
- name_selector_dialog = e_name_selector_peek_dialog (priv->name_selector);
- e_name_selector_dialog_set_destination_index (name_selector_dialog, index);
- gtk_widget_show (GTK_WIDGET (name_selector_dialog));
-}
+static gpointer parent_class;
+static guint signal_ids[LAST_SIGNAL];
static void
-from_changed (GtkWidget *item, gpointer data)
+from_changed (EComposerFromHeader *from_header, EMsgComposerHdrs *hdrs)
{
- EMsgComposerHdrs *hdrs = E_MSG_COMPOSER_HDRS (data);
- const char *reply_to;
- GList *post_items = NULL;
+ EComposerHeader *header;
+ EAccount *account;
- /* this will retrieve items relative to the previous account */
- if (!hdrs->priv->post_custom)
- post_items = e_msg_composer_hdrs_get_post_to(hdrs);
+ account = e_composer_from_header_get_active (from_header);
- hdrs->account = g_object_get_data ((GObject *) item, "account");
+ header = hdrs->priv->headers[HEADER_POST_TO];
+ e_composer_post_header_set_account (
+ E_COMPOSER_POST_HEADER (header), account);
/* we do this rather than calling e_msg_composer_hdrs_set_reply_to()
because we don't want to change the visibility of the header */
- reply_to = hdrs->account->id->reply_to;
- gtk_entry_set_text (GTK_ENTRY (hdrs->priv->reply_to.entry), reply_to ? reply_to : "");
-
- /* folders should be made relative to the new from */
- if (!hdrs->priv->post_custom) {
- e_msg_composer_hdrs_set_post_to_list (hdrs, post_items);
- g_list_foreach (post_items, (GFunc)g_free, NULL);
- g_list_free(post_items);
- }
-
- g_signal_emit (hdrs, signals [FROM_CHANGED], 0);
-}
-
-static gboolean
-account_can_send (EAccount *account)
-{
- static CamelStore *store;
- CamelException ex;
- gboolean result = FALSE;
-
- if (!account->parent_uid)
- return TRUE;
-
- if (!(store = (CamelStore *) camel_session_get_service (session, e_account_get_string(account, E_ACCOUNT_SOURCE_URL), CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return result;
- } else if (store->mode & CAMEL_STORE_WRITE)
- result = TRUE;
-
- camel_object_unref (store);
- return result;
-}
-
-static void
-account_added_cb (EAccountList *accounts, EAccount *account, EMsgComposerHdrs *hdrs)
-{
- GtkWidget *item, *menu, *omenu, *toplevel;
- char *label;
-
- omenu = e_msg_composer_hdrs_get_from_omenu (hdrs);
- menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (omenu));
-
- if (account_can_send (account)) {
- label = g_strdup_printf ("%s <%s>", account->id->name, account->id->address);
- item = gtk_menu_item_new_with_label (label);
- gtk_widget_show (item);
- g_free (label);
-
- g_object_ref (account);
- g_object_set_data ((GObject *) item, "account", account);
- g_signal_connect (item, "activate", G_CALLBACK (from_changed), hdrs);
-
- /* this is so we can later set which one we want */
- hdrs->priv->from_options = g_slist_append (hdrs->priv->from_options, item);
-
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
-
- toplevel = gtk_widget_get_toplevel ((GtkWidget *) hdrs);
- gtk_widget_set_sensitive (toplevel, TRUE);
- }
-}
-
-static void
-account_changed_cb (EAccountList *accounts, EAccount *account, EMsgComposerHdrs *hdrs)
-{
- GtkWidget *item, *label;
- EAccount *acnt;
- GSList *node;
- char *text;
-
- node = hdrs->priv->from_options;
- while (node != NULL) {
- item = node->data;
- acnt = g_object_get_data ((GObject *) item, "account");
- if (acnt == account) {
- text = g_strdup_printf ("%s <%s>", account->id->name, account->id->address);
- label = gtk_bin_get_child ((GtkBin *) item);
- gtk_label_set_text ((GtkLabel *) label, text);
- g_free (text);
- break;
- }
-
- node = node->next;
- }
-}
-
-static void
-account_removed_cb (EAccountList *accounts, EAccount *account, EMsgComposerHdrs *hdrs)
-{
- struct _EMsgComposerHdrsPrivate *priv = hdrs->priv;
- GtkWidget *item, *omenu, *toplevel;
- EAccount *acnt;
- GSList *node;
-
- node = priv->from_options;
- while (node != NULL) {
- item = node->data;
- acnt = g_object_get_data ((GObject *) item, "account");
- if (acnt == account) {
- if (hdrs->account == account)
- hdrs->account = NULL;
-
- priv->from_options = g_slist_delete_link (priv->from_options, node);
- g_object_unref (account);
- gtk_widget_destroy (item);
- break;
- }
-
- node = node->next;
- }
-
- if (hdrs->account == NULL) {
- if (priv->from_options) {
- /* the previously selected account was removed,
- default the new selection to the first account in
- the menu list */
- omenu = e_msg_composer_hdrs_get_from_omenu (hdrs);
-
- item = priv->from_options->data;
- gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), 0);
- g_signal_emit_by_name (item, "activate", hdrs);
- } else {
- toplevel = gtk_widget_get_toplevel ((GtkWidget *) hdrs);
- gtk_widget_set_sensitive (toplevel, FALSE);
-
- /* FIXME: this should offer a 'configure account' button, can we do that? */
- e_error_run((GtkWindow *)toplevel, "mail-composer:all-accounts-deleted", NULL);
- }
- }
-}
-
-static GtkWidget *
-create_from_optionmenu (EMsgComposerHdrs *hdrs)
-{
- struct _EMsgComposerHdrsPrivate *priv = hdrs->priv;
- GtkWidget *hbox, *omenu, *menu, *item, *first = NULL;
- int i = 0, history = 0, m, matches;
- GPtrArray *addresses;
- GConfClient *gconf;
- EAccount *account;
- EIterator *iter;
- char *uid;
-
- omenu = gtk_option_menu_new ();
- menu = gtk_menu_new ();
-
- gconf = gconf_client_get_default ();
- uid = gconf_client_get_string (gconf, "/apps/evolution/mail/default_account", NULL);
- g_object_unref (gconf);
-
- /* Make list of account email addresses */
- addresses = g_ptr_array_new ();
- iter = e_list_get_iterator ((EList *) priv->accounts);
- while (e_iterator_is_valid (iter)) {
- account = (EAccount *) e_iterator_get (iter);
-
- if (account->id->address && account_can_send (account) && account->enabled)
- g_ptr_array_add (addresses, account->id->address);
-
- e_iterator_next (iter);
- }
-
- e_iterator_reset (iter);
-
- while (e_iterator_is_valid (iter)) {
- char *label;
-
- account = (EAccount *) e_iterator_get (iter);
-
- /* this should never ever fail */
- if (!account || !account->name || !account->id) {
- g_warning ("account details are bad\n");
- continue;
- }
-
- if (account->id->address && *account->id->address && account_can_send (account) && account->enabled) {
- /* If the account has a unique email address, just
- * show that. Otherwise include the account name.
- */
- for (m = matches = 0; m < addresses->len; m++) {
- if (!strcmp (account->id->address, addresses->pdata[m]))
- matches++;
- }
-
- if (matches > 1)
- label = g_strdup_printf ("%s <%s> (%s)", account->id->name,
- account->id->address, account->name);
- else
- label = g_strdup_printf ("%s <%s>", account->id->name, account->id->address);
-
- item = gtk_menu_item_new_with_label (label);
- g_free (label);
-
- g_object_ref (account);
- g_object_set_data ((GObject *) item, "account", account);
- g_signal_connect (item, "activate", G_CALLBACK (from_changed), hdrs);
-
- if (uid && !strcmp (account->uid, uid)) {
- first = item;
- history = i;
- }
-
- /* this is so we can later set which one we want */
- hdrs->priv->from_options = g_slist_append (hdrs->priv->from_options, item);
-
- gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
- gtk_widget_show (item);
- i++;
- }
-
- e_iterator_next (iter);
- }
-
- g_free (uid);
- g_object_unref (iter);
-
- g_ptr_array_free (addresses, TRUE);
-
- gtk_option_menu_set_menu (GTK_OPTION_MENU (omenu), menu);
-
- if (first) {
- gtk_option_menu_set_history (GTK_OPTION_MENU (omenu), history);
- g_signal_emit_by_name (first, "activate", hdrs);
- }
-
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start_defaults (GTK_BOX (hbox), omenu);
- gtk_widget_show (omenu);
- gtk_widget_show (hbox);
-
- g_object_set_data ((GObject *) hbox, "from_menu", omenu);
-
- /* listen for changes to the account list so we can auto-update the from menu */
- g_signal_connect (priv->accounts, "account-added", G_CALLBACK (account_added_cb), hdrs);
- g_signal_connect (priv->accounts, "account-changed", G_CALLBACK (account_changed_cb), hdrs);
- g_signal_connect (priv->accounts, "account-removed", G_CALLBACK (account_removed_cb), hdrs);
-
- return hbox;
-}
-
-static void
-addressbook_entry_changed (GtkWidget *entry,
- gpointer user_data)
-{
- EMsgComposerHdrs *hdrs = E_MSG_COMPOSER_HDRS (user_data);
-
- g_signal_emit (hdrs, signals[HDRS_CHANGED], 0);
-}
+ header = hdrs->priv->headers[HEADER_REPLY_TO];
+ e_composer_text_header_set_text (
+ E_COMPOSER_TEXT_HEADER (header), account->id->reply_to);
-static gboolean
-entry_query_tooltip (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
-{
- const char *text;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_ENTRY (widget), FALSE);
- g_return_val_if_fail (tooltip != NULL, FALSE);
-
- if (keyboard_mode)
- return FALSE;
-
- text = gtk_entry_get_text (GTK_ENTRY (widget));
-
- if (!text || !*text)
- return FALSE;
-
- gtk_tooltip_set_text (tooltip, text);
-
- return TRUE;
-}
-
-/**
- * connect_entry_for_tooltip
- * This connects "tooltip" callback to entry.
- * If entry has tooltip depends on the length of the text inside it.
- * @param entry GtkEntry widget, to connect to.
- **/
-static void
-connect_entry_for_tooltip (GtkWidget *entry)
-{
- g_return_if_fail (entry != NULL);
- g_return_if_fail (GTK_IS_ENTRY (entry));
-
- g_signal_connect (G_OBJECT (entry), "query-tooltip", G_CALLBACK (entry_query_tooltip), NULL);
- gtk_widget_set_has_tooltip (entry, TRUE);
-}
-
-static GtkWidget *
-create_addressbook_entry (EMsgComposerHdrs *hdrs, const char *name)
-{
- EMsgComposerHdrsPrivate *priv;
- ENameSelectorModel *name_selector_model;
- ENameSelectorEntry *name_selector_entry;
-
- priv = hdrs->priv;
-
- name_selector_model = e_name_selector_peek_model (priv->name_selector);
- e_name_selector_model_add_section (name_selector_model, name, name, NULL);
-
- name_selector_entry = (ENameSelectorEntry *)e_name_selector_peek_section_list (priv->name_selector, name);
- g_signal_connect (name_selector_entry, "changed", G_CALLBACK (addressbook_entry_changed), hdrs);
- connect_entry_for_tooltip (GTK_WIDGET (name_selector_entry));
-
- e_name_selector_entry_set_contact_editor_func (name_selector_entry, e_contact_editor_new);
- e_name_selector_entry_set_contact_list_editor_func (name_selector_entry, e_contact_list_editor_new);
-
- return GTK_WIDGET (name_selector_entry);
-
-#if 0
-
- CORBA_exception_init (&ev);
-
- GNOME_Evolution_Addressbook_SelectNames_addSection (
- corba_select_names, name, name, &ev);
- if (ev._major != CORBA_NO_EXCEPTION) {
- CORBA_exception_free (&ev);
- return NULL;
- }
-
- corba_control =
- GNOME_Evolution_Addressbook_SelectNames_getEntryBySection (
- corba_select_names, name, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- CORBA_exception_free (&ev);
- return NULL;
- }
-
- CORBA_exception_free (&ev);
-
- control_widget = bonobo_widget_new_control_from_objref (
- corba_control, bonobo_ui_component_get_container (priv->uic));
-
- cf = bonobo_widget_get_control_frame (BONOBO_WIDGET (control_widget));
- pb = bonobo_control_frame_get_control_property_bag (cf, NULL);
-
- bonobo_control_frame_set_autoactivate (cf, TRUE);
-
- bonobo_event_source_client_add_listener (
- pb, addressbook_entry_changed,
- "Bonobo/Property:change:entry_changed",
- NULL, hdrs);
-
- return control_widget;
-#endif
-}
-
-static void
-post_browser_response (EMFolderSelector *emfs, int response, EMsgComposerHdrs *hdrs)
-{
- if (response == GTK_RESPONSE_OK) {
- GList *uris = em_folder_selector_get_selected_uris (emfs);
-
- e_msg_composer_hdrs_set_post_to_list (hdrs, uris);
- hdrs->priv->post_custom = FALSE;
- g_list_foreach (uris, (GFunc) g_free, NULL);
- g_list_free (uris);
- }
-
- gtk_widget_destroy ((GtkWidget *) emfs);
-}
-
-static void
-post_browser_clicked_cb (GtkButton *button, EMsgComposerHdrs *hdrs)
-{
- EMFolderTreeModel *model;
- EMFolderTree *emft;
- GtkWidget *dialog;
- GList *post_items;
-
- gtk_widget_grab_focus(hdrs->priv->post_to.entry);
- model = mail_component_peek_tree_model (mail_component_peek ());
- emft = (EMFolderTree *) em_folder_tree_new_with_model (model);
- em_folder_tree_set_multiselect (emft, TRUE);
- em_folder_tree_set_excluded(emft, EMFT_EXCLUDE_NOSELECT|EMFT_EXCLUDE_VIRTUAL|EMFT_EXCLUDE_VTRASH);
-
- dialog = em_folder_selector_new (emft, EM_FOLDER_SELECTOR_CAN_CREATE,
- _("Posting destination"),
- _("Choose folders to post the message to."), NULL);
-
- post_items = e_msg_composer_hdrs_get_post_to (hdrs);
- em_folder_selector_set_selected_list ((EMFolderSelector *) dialog, post_items);
- g_list_foreach (post_items, (GFunc) g_free, NULL);
- g_list_free (post_items);
-
- g_signal_connect (dialog, "response", G_CALLBACK (post_browser_response), hdrs);
- gtk_widget_show (dialog);
-}
-
-static void
-post_entry_changed_cb (GtkButton *button, EMsgComposerHdrs *hdrs)
-{
- hdrs->priv->post_custom = TRUE;
-}
-
-static EMsgComposerHdrPair
-header_new_recipient (EMsgComposerHdrs *hdrs, const char *name, const char *tip)
-{
- EMsgComposerHdrPair ret;
-
- ret.label = gtk_button_new_with_mnemonic (name);
- GTK_OBJECT_UNSET_FLAGS (ret.label, GTK_CAN_FOCUS);
- g_signal_connect_data (ret.label, "clicked",
- G_CALLBACK (address_button_clicked_cb),
- e_msg_composer_hdrs_and_string_create (hdrs, name),
- (GClosureNotify) e_msg_composer_hdrs_and_string_free,
- 0);
-
- gtk_tooltips_set_tip (hdrs->priv->tooltips, ret.label,
- _("Click here for the address book"),
- NULL);
-
- ret.entry = create_addressbook_entry (hdrs, name);
- ret.visible = FALSE;
-
- return ret;
-}
-
-static void
-entry_changed (GtkWidget *entry, EMsgComposerHdrs *hdrs)
-{
- const char *subject;
-
- subject = e_msg_composer_hdrs_get_subject (hdrs);
- g_signal_emit (hdrs, signals[SUBJECT_CHANGED], 0, subject);
- g_signal_emit (hdrs, signals[HDRS_CHANGED], 0);
-}
-
-static void
-create_headers (EMsgComposerHdrs *hdrs)
-{
- EMsgComposerHdrsPrivate *priv = hdrs->priv;
- AtkObject *a11y;
-
- /*
- * Reply-To:
- *
- * Create this before we call create_from_optionmenu,
- * because that causes from_changed to be called, which
- * expects the reply_to fields to be initialized.
- */
- priv->reply_to.label = gtk_label_new_with_mnemonic (_("_Reply-To:"));
- priv->reply_to.entry = gtk_entry_new ();
- gtk_label_set_mnemonic_widget((GtkLabel *)priv->reply_to.label, priv->reply_to.entry);
-
- /*
- * From
- */
- priv->from.label = gtk_label_new_with_mnemonic (_("Fr_om:"));
- priv->from.entry = create_from_optionmenu (hdrs);
- gtk_label_set_mnemonic_widget((GtkLabel *)priv->from.label, e_msg_composer_hdrs_get_from_omenu (hdrs));
-
- /*
- * Subject
- */
- priv->subject.label = gtk_label_new_with_mnemonic (_("S_ubject:"));
- priv->subject.entry = gtk_entry_new ();
- gtk_label_set_mnemonic_widget((GtkLabel *)priv->subject.label, priv->subject.entry);
- g_signal_connect(priv->subject.entry, "changed", G_CALLBACK(entry_changed), hdrs);
- connect_entry_for_tooltip (priv->subject.entry);
-
- /*
- * To, CC, and Bcc
- */
- priv->to = header_new_recipient (
- hdrs, _("_To:"),
- _("Enter the recipients of the message"));
-
- priv->cc = header_new_recipient (
- hdrs, _("_Cc:"),
- _("Enter the addresses that will receive a carbon copy of the message"));
-
- priv->bcc = header_new_recipient (
- hdrs, _("_Bcc:"),
- _("Enter the addresses that will receive a carbon copy of "
- "the message without appearing in the recipient list of "
- "the message."));
-
- /*
- * Post-To
- */
- priv->post_to.label = gtk_button_new_with_mnemonic (_("_Post To:"));
- GTK_OBJECT_UNSET_FLAGS (priv->post_to.label, GTK_CAN_FOCUS);
- g_signal_connect (priv->post_to.label, "clicked",
- G_CALLBACK (post_browser_clicked_cb), hdrs);
- gtk_tooltips_set_tip (hdrs->priv->tooltips, priv->post_to.label,
- _("Click here to select folders to post to"),
- NULL);
-
- priv->post_to.entry = gtk_entry_new ();
- if ((a11y = gtk_widget_get_accessible (priv->post_to.entry)))
- atk_object_set_name (a11y, _("Post To:"));
-
- g_signal_connect(priv->post_to.entry, "changed",
- G_CALLBACK (post_entry_changed_cb), hdrs);
-
- connect_entry_for_tooltip (priv->post_to.entry);
-}
-
-static void
-attach_couple (EMsgComposerHdrs *hdrs, EMsgComposerHdrPair *pair, int line)
-{
- gtk_table_attach (GTK_TABLE (hdrs),
- pair->label, 0, 1,
- line, line + 1,
- GTK_FILL, GTK_FILL, 3, 3);
-
- if (line == LINE_TO || line == LINE_CC || line == LINE_BCC) {
- gtk_table_attach (GTK_TABLE (hdrs),
- pair->entry, 1, 2,
- line, line + 1,
- GTK_FILL | GTK_EXPAND, 0, 3, 3);
- }
- else {
- gtk_table_attach (GTK_TABLE (hdrs),
- pair->entry, 1, 2,
- line, line + 1,
- GTK_FILL | GTK_EXPAND, 0, 3, 3);
- }
-}
-
-static void
-attach_headers (EMsgComposerHdrs *hdrs)
-{
- EMsgComposerHdrsPrivate *p = hdrs->priv;
-
- attach_couple (hdrs, &p->from, LINE_FROM);
- attach_couple (hdrs, &p->reply_to, LINE_REPLYTO);
- attach_couple (hdrs, &p->to, LINE_TO);
- attach_couple (hdrs, &p->cc, LINE_CC);
- attach_couple (hdrs, &p->bcc, LINE_BCC);
- attach_couple (hdrs, &p->post_to, LINE_POSTTO);
- attach_couple (hdrs, &p->subject, LINE_SUBJECT);
-}
-
-static void
-set_pair_visibility (EMsgComposerHdrs *h, EMsgComposerHdrPair *pair, int visible)
-{
- if (visible /*& h->visible_mask*/) {
- gtk_widget_show (pair->label);
- gtk_widget_show (pair->entry);
- } else {
- gtk_widget_hide (pair->label);
- gtk_widget_hide (pair->entry);
- }
-
- pair->visible = TRUE;
+ g_signal_emit (hdrs, signal_ids[FROM_CHANGED], 0);
}
static void
@@ -786,13 +115,27 @@ headers_set_visibility (EMsgComposerHdrs *h, int visible_flags)
else
visible_flags |= E_MSG_COMPOSER_VISIBLE_POSTTO;
- set_pair_visibility (h, &p->from, visible_flags & E_MSG_COMPOSER_VISIBLE_FROM);
- set_pair_visibility (h, &p->reply_to, visible_flags & E_MSG_COMPOSER_VISIBLE_REPLYTO);
- set_pair_visibility (h, &p->to, visible_flags & E_MSG_COMPOSER_VISIBLE_TO);
- set_pair_visibility (h, &p->cc, visible_flags & E_MSG_COMPOSER_VISIBLE_CC);
- set_pair_visibility (h, &p->bcc, visible_flags & E_MSG_COMPOSER_VISIBLE_BCC);
- set_pair_visibility (h, &p->post_to, visible_flags & E_MSG_COMPOSER_VISIBLE_POSTTO);
- set_pair_visibility (h, &p->subject, visible_flags & E_MSG_COMPOSER_VISIBLE_SUBJECT);
+ e_composer_header_set_visible (
+ p->headers[HEADER_FROM],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_FROM);
+ e_composer_header_set_visible (
+ p->headers[HEADER_REPLY_TO],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_REPLYTO);
+ e_composer_header_set_visible (
+ p->headers[HEADER_TO],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_TO);
+ e_composer_header_set_visible (
+ p->headers[HEADER_CC],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_CC);
+ e_composer_header_set_visible (
+ p->headers[HEADER_BCC],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_BCC);
+ e_composer_header_set_visible (
+ p->headers[HEADER_POST_TO],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_POSTTO);
+ e_composer_header_set_visible (
+ p->headers[HEADER_SUBJECT],
+ visible_flags & E_MSG_COMPOSER_VISIBLE_SUBJECT);
}
static void
@@ -826,91 +169,78 @@ e_msg_composer_hdrs_set_visible (EMsgComposerHdrs *hdrs, int visible_flags)
gtk_widget_queue_resize (GTK_WIDGET (hdrs));
}
-static void
-setup_headers (EMsgComposerHdrs *hdrs, int visible_flags)
+static GObject *
+msg_composer_hdrs_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
{
- create_headers (hdrs);
- attach_headers (hdrs);
+ GObject *object;
+ EMsgComposerHdrsPrivate *priv;
+ guint rows, ii;
- headers_set_sensitivity (hdrs);
- headers_set_visibility (hdrs, visible_flags);
-}
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
-
-/* GtkObject methods. */
+ priv = E_MSG_COMPOSER_HDRS_GET_PRIVATE (object);
-static void
-destroy (GtkObject *object)
-{
- EMsgComposerHdrs *hdrs;
- EMsgComposerHdrsPrivate *priv;
- GSList *l, *n;
+ rows = G_N_ELEMENTS (priv->headers);
+ gtk_table_resize (GTK_TABLE (object), rows, 2);
+ gtk_table_set_row_spacings (GTK_TABLE (object), 0);
+ gtk_table_set_col_spacings (GTK_TABLE (object), 6);
- hdrs = E_MSG_COMPOSER_HDRS (object);
- priv = hdrs->priv;
+ /* Use "ypadding" instead of "row-spacing" because some rows may
+ * be invisible and we don't want spacing around them. */
- if (priv) {
- if (priv->name_selector != NULL) {
- g_object_unref (priv->name_selector);
- priv->name_selector = NULL;
- }
+ for (ii = 0; ii < rows; ii++) {
+ gtk_table_attach (
+ GTK_TABLE (object), priv->headers[ii]->title_widget,
+ 0, 1, ii, ii + 1, GTK_FILL, GTK_FILL, 0, 3);
+ gtk_table_attach (
+ GTK_TABLE (object), priv->headers[ii]->input_widget,
+ 1, 2, ii, ii + 1, GTK_FILL | GTK_EXPAND, 0, 0, 3);
+ }
- if (priv->tooltips) {
- gtk_object_destroy (GTK_OBJECT (priv->tooltips));
- g_object_unref (priv->tooltips);
- priv->tooltips = NULL;
- }
+ return object;
+}
- if (priv->accounts) {
- g_signal_handlers_disconnect_matched(priv->accounts, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, hdrs);
- g_object_unref (priv->accounts);
- priv->accounts = NULL;
- }
+static void
+msg_composer_hdrs_dispose (GObject *object)
+{
+ EMsgComposerHdrsPrivate *priv;
+ gint ii;
- l = priv->from_options;
- while (l) {
- EAccount *account;
- GtkWidget *item = l->data;
+ priv = E_MSG_COMPOSER_HDRS_GET_PRIVATE (object);
- account = g_object_get_data ((GObject *) item, "account");
- g_object_unref (account);
+ if (priv->name_selector != NULL) {
+ g_object_unref (priv->name_selector);
+ priv->name_selector = NULL;
+ }
- n = l->next;
- g_slist_free_1 (l);
- l = n;
+ for (ii = 0; ii < G_N_ELEMENTS (priv->headers); ii++) {
+ if (priv->headers[ii] != NULL) {
+ g_object_unref (priv->headers[ii]);
+ priv->headers[ii] = NULL;
}
-
- priv->from_options = NULL;
-
- g_free (priv);
- hdrs->priv = NULL;
}
- if (GTK_OBJECT_CLASS (parent_class)->destroy != NULL)
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
-
static void
-class_init (EMsgComposerHdrsClass *class)
+msg_composer_hdrs_class_init (EMsgComposerHdrsClass *class)
{
- GtkObjectClass *object_class;
+ GObjectClass *object_class;
- object_class = GTK_OBJECT_CLASS (class);
- object_class->destroy = destroy;
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EMsgComposerHdrsPrivate));
- parent_class = g_type_class_ref (gtk_table_get_type ());
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = msg_composer_hdrs_constructor;
+ object_class->dispose = msg_composer_hdrs_dispose;
- signals[SHOW_ADDRESS_DIALOG] =
- g_signal_new ("show_address_dialog",
- E_TYPE_MSG_COMPOSER_HDRS,
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(EMsgComposerHdrsClass, show_address_dialog),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- signals[SUBJECT_CHANGED] =
+ signal_ids[SUBJECT_CHANGED] =
g_signal_new ("subject_changed",
E_TYPE_MSG_COMPOSER_HDRS,
G_SIGNAL_RUN_LAST,
@@ -920,7 +250,7 @@ class_init (EMsgComposerHdrsClass *class)
G_TYPE_NONE,
1, G_TYPE_STRING);
- signals[HDRS_CHANGED] =
+ signal_ids[HDRS_CHANGED] =
g_signal_new ("hdrs_changed",
E_TYPE_MSG_COMPOSER_HDRS,
G_SIGNAL_RUN_LAST,
@@ -929,7 +259,7 @@ class_init (EMsgComposerHdrsClass *class)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- signals[FROM_CHANGED] =
+ signal_ids[FROM_CHANGED] =
g_signal_new ("from_changed",
E_TYPE_MSG_COMPOSER_HDRS,
G_SIGNAL_RUN_LAST,
@@ -940,43 +270,77 @@ class_init (EMsgComposerHdrsClass *class)
}
static void
-init (EMsgComposerHdrs *hdrs)
+msg_composer_hdrs_init (EMsgComposerHdrs *hdrs)
{
- EMsgComposerHdrsPrivate *priv;
+ EComposerHeader *header;
+ ENameSelector *name_selector;
+
+ hdrs->priv = E_MSG_COMPOSER_HDRS_GET_PRIVATE (hdrs);
+
+ name_selector = e_name_selector_new ();
+
+ hdrs->priv->name_selector = name_selector;
+
+ header = e_composer_from_header_new (_("Fr_om:"));
+ g_signal_connect (
+ header, "changed",
+ G_CALLBACK (from_changed), hdrs);
+ hdrs->priv->headers[HEADER_FROM] = header;
+
+ header = e_composer_text_header_new_label (_("_Reply-To:"));
+ hdrs->priv->headers[HEADER_REPLY_TO] = header;
- priv = g_new0 (EMsgComposerHdrsPrivate, 1);
+ header = e_composer_name_header_new (_("_To:"), name_selector);
+ e_composer_header_set_input_tooltip (
+ header, _("Enter the recipients of the message"));
+ hdrs->priv->headers[HEADER_TO] = header;
- priv->tooltips = gtk_tooltips_new ();
- g_object_ref_sink (priv->tooltips);
+ header = e_composer_name_header_new (_("_Cc:"), name_selector);
+ e_composer_header_set_input_tooltip (
+ header, _("Enter the addresses that will receive a "
+ "carbon copy of the message"));
+ hdrs->priv->headers[HEADER_CC] = header;
- priv->accounts = mail_config_get_accounts ();
- g_object_ref (priv->accounts);
+ header = e_composer_name_header_new (_("_Bcc:"), name_selector);
+ e_composer_header_set_input_tooltip (
+ header, _("Enter the addresses that will receive a "
+ "carbon copy of the message without appearing in the "
+ "recipient list of the message"));
+ hdrs->priv->headers[HEADER_BCC] = header;
- priv->post_custom = FALSE;
+ header = e_composer_post_header_new (_("_Post To:"));
+ hdrs->priv->headers[HEADER_POST_TO] = header;
- hdrs->priv = priv;
+ header = e_composer_text_header_new_label (_("S_ubject:"));
+ hdrs->priv->headers[HEADER_SUBJECT] = header;
+
+ /* Do this after all the headers are initialized. */
+ e_composer_from_header_set_account_list (
+ E_COMPOSER_FROM_HEADER (hdrs->priv->headers[HEADER_FROM]),
+ mail_config_get_accounts ());
}
-
GType
e_msg_composer_hdrs_get_type (void)
{
static GType type = 0;
- if (type == 0) {
- static const GTypeInfo info = {
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
sizeof (EMsgComposerHdrsClass),
- NULL,
- NULL,
- (GClassInitFunc) class_init,
- NULL,
- NULL,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) msg_composer_hdrs_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
sizeof (EMsgComposerHdrs),
- 0,
- (GInstanceInitFunc) init,
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) msg_composer_hdrs_init,
+ NULL /* value_table */
};
- type = g_type_register_static (gtk_table_get_type (), "EMsgComposerHdrs", &info, 0);
+ type = g_type_register_static (
+ GTK_TYPE_TABLE, "EMsgComposerHdrs", &type_info, 0);
}
return type;
@@ -988,17 +352,16 @@ e_msg_composer_hdrs_new (BonoboUIComponent *uic, int visible_mask, int visible_f
EMsgComposerHdrs *new;
EMsgComposerHdrsPrivate *priv;
- new = g_object_new (e_msg_composer_hdrs_get_type (), NULL);
+ new = g_object_new (E_TYPE_MSG_COMPOSER_HDRS, NULL);
priv = new->priv;
priv->uic = uic;
g_object_ref_sink (new);
- setup_name_selector (new);
-
new->visible_mask = visible_mask;
- setup_headers (new, visible_flags);
+ headers_set_sensitivity (new);
+ headers_set_visibility (new, visible_flags);
return GTK_WIDGET (new);
}
@@ -1094,6 +457,7 @@ e_msg_composer_hdrs_to_message_internal (EMsgComposerHdrs *hdrs,
EDestination **to_destv, **cc_destv, **bcc_destv;
CamelInternetAddress *addr;
const char *subject;
+ gboolean visible;
char *header;
g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
@@ -1118,7 +482,15 @@ e_msg_composer_hdrs_to_message_internal (EMsgComposerHdrs *hdrs,
camel_object_unref (addr);
}
- if (hdrs->priv->to.visible || hdrs->priv->cc.visible || hdrs->priv->bcc.visible) {
+ visible =
+ e_composer_header_get_visible (
+ hdrs->priv->headers[HEADER_TO]) ||
+ e_composer_header_get_visible (
+ hdrs->priv->headers[HEADER_CC]) ||
+ e_composer_header_get_visible (
+ hdrs->priv->headers[HEADER_BCC]);
+
+ if (visible) {
to_destv = e_msg_composer_hdrs_get_to (hdrs);
cc_destv = e_msg_composer_hdrs_get_cc (hdrs);
bcc_destv = e_msg_composer_hdrs_get_bcc (hdrs);
@@ -1132,7 +504,10 @@ e_msg_composer_hdrs_to_message_internal (EMsgComposerHdrs *hdrs,
e_destination_freev (bcc_destv);
}
- if (hdrs->priv->post_to.visible) {
+ visible = e_composer_header_get_visible (
+ hdrs->priv->headers[HEADER_POST_TO]);
+
+ if (visible) {
GList *post, *l;
camel_medium_remove_header((CamelMedium *)msg, "X-Evolution-PostTo");
@@ -1161,133 +536,93 @@ e_msg_composer_hdrs_to_redirect (EMsgComposerHdrs *hdrs,
e_msg_composer_hdrs_to_message_internal (hdrs, msg, TRUE);
}
-
-/* FIXME: yea, this could be better... but it's doubtful it'll be used much */
-void
-e_msg_composer_hdrs_set_from_account (EMsgComposerHdrs *hdrs,
- const char *account_name)
+EAccount *
+e_msg_composer_hdrs_get_from_account (EMsgComposerHdrs *hdrs)
{
- GtkOptionMenu *omenu;
- GConfClient *gconf;
- GtkWidget *item;
- char *uid = NULL;
- GSList *l;
- int i = 0;
+ EComposerFromHeader *header;
- g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
+ g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- omenu = GTK_OPTION_MENU (e_msg_composer_hdrs_get_from_omenu (hdrs));
+ header = E_COMPOSER_FROM_HEADER (hdrs->priv->headers[HEADER_FROM]);
+ return e_composer_from_header_get_active (header);
+}
- if (!account_name) {
- gconf = gconf_client_get_default ();
- uid = gconf_client_get_string (gconf, "/apps/evolution/mail/default_account", NULL);
- g_object_unref (gconf);
- }
+gboolean
+e_msg_composer_hdrs_set_from_account (EMsgComposerHdrs *hdrs,
+ const gchar *account_name)
+{
+ EComposerFromHeader *header;
- /* find the item that represents the account and activate it */
- l = hdrs->priv->from_options;
- while (l) {
- EAccount *account;
- item = l->data;
-
- account = g_object_get_data ((GObject *) item, "account");
- if (account_can_send (account)) {
- if (account_name) {
- if (account->name && !strcmp (account_name, account->name)) {
- /* set the correct optionlist item */
- gtk_option_menu_set_history (omenu, i);
- g_signal_emit_by_name (item, "activate", hdrs);
- g_free (uid);
-
- return;
- }
- } else if (uid && !strcmp (account->uid, uid)) {
- /* set the default optionlist item */
- gtk_option_menu_set_history (omenu, i);
- g_signal_emit_by_name (item, "activate", hdrs);
- g_free (uid);
+ g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), FALSE);
- return;
- }
- }
- l = l->next;
- i++;
- }
-
- g_free (uid);
+ header = E_COMPOSER_FROM_HEADER (hdrs->priv->headers[HEADER_FROM]);
+ return e_composer_from_header_set_active_name (header, account_name);
}
void
e_msg_composer_hdrs_set_reply_to (EMsgComposerHdrs *hdrs,
- const char *reply_to)
+ const gchar *text)
{
- g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
-
- gtk_entry_set_text (GTK_ENTRY (hdrs->priv->reply_to.entry), reply_to ? reply_to : "");
-
- if (reply_to && *reply_to)
- set_pair_visibility (hdrs, &hdrs->priv->cc, TRUE);
-}
+ EComposerHeader *header;
-static void
-destinations_to_name_selector_entry (ENameSelectorEntry *name_selector_entry, EDestination **destv)
-{
- EDestinationStore *destination_store;
- GList *destinations;
- GList *l;
- gint i;
-
- /* First clear the store */
- destination_store = e_name_selector_entry_peek_destination_store (name_selector_entry);
- destinations = e_destination_store_list_destinations (destination_store);
-
- for (l = destinations; l; l = g_list_next (l)) {
- EDestination *destination = l->data;
- e_destination_store_remove_destination (destination_store, destination);
- }
+ g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
- g_list_free (destinations);
+ header = hdrs->priv->headers[HEADER_REPLY_TO];
- if (!destv)
- return;
+ e_composer_text_header_set_text (
+ E_COMPOSER_TEXT_HEADER (header), text);
- for (i = 0; destv [i]; i++)
- e_destination_store_append_destination (destination_store, destv [i]);
+ if (*text != '\0')
+ e_composer_header_set_visible (header, TRUE);
}
void
e_msg_composer_hdrs_set_to (EMsgComposerHdrs *hdrs,
EDestination **to_destv)
{
+ EComposerHeader *header;
+
g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
- destinations_to_name_selector_entry (E_NAME_SELECTOR_ENTRY (hdrs->priv->to.entry), to_destv);
+ header = hdrs->priv->headers[HEADER_TO];
+
+ e_composer_name_header_set_destinations (
+ E_COMPOSER_NAME_HEADER (header), to_destv);
}
void
e_msg_composer_hdrs_set_cc (EMsgComposerHdrs *hdrs,
EDestination **cc_destv)
{
+ EComposerHeader *header;
+
g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
- destinations_to_name_selector_entry (E_NAME_SELECTOR_ENTRY (hdrs->priv->cc.entry), cc_destv);
+ header = hdrs->priv->headers[HEADER_CC];
+
+ e_composer_name_header_set_destinations (
+ E_COMPOSER_NAME_HEADER (header), cc_destv);
- if (cc_destv && *cc_destv)
- set_pair_visibility (hdrs, &hdrs->priv->cc, TRUE);
+ if (cc_destv != NULL && *cc_destv != NULL)
+ e_composer_header_set_visible (header, TRUE);
}
void
e_msg_composer_hdrs_set_bcc (EMsgComposerHdrs *hdrs,
EDestination **bcc_destv)
{
+ EComposerHeader *header;
+
g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
- destinations_to_name_selector_entry (E_NAME_SELECTOR_ENTRY (hdrs->priv->bcc.entry), bcc_destv);
+ header = hdrs->priv->headers[HEADER_BCC];
- if (bcc_destv && *bcc_destv)
- set_pair_visibility (hdrs, &hdrs->priv->bcc, TRUE);
-}
+ e_composer_name_header_set_destinations (
+ E_COMPOSER_NAME_HEADER (header), bcc_destv);
+ if (bcc_destv != NULL && *bcc_destv != NULL)
+ e_composer_header_set_visible (header, TRUE);
+}
void
e_msg_composer_hdrs_set_post_to (EMsgComposerHdrs *hdrs,
@@ -1306,175 +641,82 @@ e_msg_composer_hdrs_set_post_to (EMsgComposerHdrs *hdrs,
g_list_free (list);
}
-static GList *
-newsgroups_list_split (const char *list)
-{
- GList *lst = NULL;
- char *tmp;
- char **items, **cur_ptr;
-
- cur_ptr = items = g_strsplit (list, ",", 0);
-
- while ((tmp = *cur_ptr) != NULL) {
- g_strstrip (tmp);
-
- if (tmp[0])
- lst = g_list_append (lst, g_strdup (tmp));
-
- cur_ptr++;
- }
-
- g_strfreev (items);
-
- return lst;
-}
-
-static char *
-get_account_store_url (EMsgComposerHdrs *hdrs)
-{
- CamelURL *url;
- char *ret = NULL;
-
- if (hdrs->account->source
- && hdrs->account->source->url
- && hdrs->account->source->url[0]
- && (url = camel_url_new (hdrs->account->source->url, NULL))) {
- ret = camel_url_to_string (url, CAMEL_URL_HIDE_ALL);
- camel_url_free (url);
- }
-
- return ret;
-}
-
-static char *
-folder_name_to_string (EMsgComposerHdrs *hdrs, const char *uri)
-{
- char *storeurl = get_account_store_url (hdrs);
- int len;
-
- if (storeurl) {
- len = strlen (storeurl);
-
- if (g_ascii_strncasecmp (uri, storeurl, len) == 0) {
- g_free (storeurl);
- return g_strdup (uri + len);
- }
-
- g_free (storeurl);
- }
-
- return g_strdup (uri);
-}
-
void
e_msg_composer_hdrs_set_post_to_list (EMsgComposerHdrs *hdrs, GList *urls)
{
- GString *caption;
- char *tmp;
- gboolean post_custom;
-
- if (hdrs->priv->post_to.entry == NULL)
- return;
-
- caption = g_string_new("");
- while (urls) {
- tmp = folder_name_to_string(hdrs, (char *)urls->data);
- if (tmp) {
- if (caption->len)
- g_string_append(caption, ", ");
- g_string_append(caption, tmp);
- }
+ EComposerHeader *header;
- urls = g_list_next (urls);
- }
+ g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
- post_custom = hdrs->priv->post_custom;
- gtk_entry_set_text(GTK_ENTRY(hdrs->priv->post_to.entry), caption->str);
- hdrs->priv->post_custom = post_custom;
+ header = hdrs->priv->headers[HEADER_POST_TO];
- g_string_free(caption, TRUE);
+ e_composer_post_header_set_folders (
+ E_COMPOSER_POST_HEADER (header), urls);
}
void
-e_msg_composer_hdrs_set_post_to_base (EMsgComposerHdrs *hdrs, const char *base, const char *post_to)
+e_msg_composer_hdrs_set_post_to_base (EMsgComposerHdrs *hdrs,
+ const gchar *base,
+ const gchar *post_to)
{
- GList *lst, *curlist;
- char *tmp, *tmp2;
- gboolean post_custom;
- GString *caption;
-
- /* split to newsgroup names */
- lst = newsgroups_list_split(post_to);
- curlist = lst;
-
- caption = g_string_new("");
- while (curlist) {
- /* FIXME: this doens't handle all folder names properly */
- tmp2 = g_strdup_printf ("%s/%s", base, (char *)curlist->data);
- tmp = folder_name_to_string (hdrs, tmp2);
- g_free (tmp2);
- if (tmp) {
- if (caption->len)
- g_string_append(caption, ", ");
- g_string_append(caption, tmp);
- }
- curlist = g_list_next(curlist);
- }
+ EComposerHeader *header;
- post_custom = hdrs->priv->post_custom;
- gtk_entry_set_text(GTK_ENTRY(hdrs->priv->post_to.entry), caption->str);
- hdrs->priv->post_custom = post_custom;
+ g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
+
+ header = hdrs->priv->headers[HEADER_POST_TO];
- g_string_free(caption, TRUE);
- g_list_foreach(lst, (GFunc)g_free, NULL);
- g_list_free(lst);
+ e_composer_post_header_set_folders_base (
+ E_COMPOSER_POST_HEADER (header), base, post_to);
}
void
e_msg_composer_hdrs_set_subject (EMsgComposerHdrs *hdrs,
- const char *subject)
+ const gchar *subject)
{
+ EComposerHeader *header;
+
g_return_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs));
g_return_if_fail (subject != NULL);
- gtk_entry_set_text ((GtkEntry *) hdrs->priv->subject.entry, subject);
+ header = hdrs->priv->headers[HEADER_SUBJECT];
+
+ e_composer_text_header_set_text (
+ E_COMPOSER_TEXT_HEADER (header), subject);
}
CamelInternetAddress *
e_msg_composer_hdrs_get_from (EMsgComposerHdrs *hdrs)
{
- CamelInternetAddress *addr;
- EAccount *account;
+ EComposerHeader *header;
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- if (!(account = hdrs->account)) {
- /* FIXME: perhaps we should try the default account? */
- return NULL;
- }
-
- addr = camel_internet_address_new ();
- camel_internet_address_add (addr, account->id->name, account->id->address);
+ header = hdrs->priv->headers[HEADER_FROM];
- return addr;
+ return e_composer_from_header_get_active_address (
+ E_COMPOSER_FROM_HEADER (header));
}
CamelInternetAddress *
e_msg_composer_hdrs_get_reply_to (EMsgComposerHdrs *hdrs)
{
CamelInternetAddress *addr;
- const char *reply_to;
+ EComposerHeader *header;
+ const gchar *text;
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- reply_to = gtk_entry_get_text (GTK_ENTRY (hdrs->priv->reply_to.entry));
+ header = hdrs->priv->headers[HEADER_REPLY_TO];
+
+ text = e_composer_text_header_get_text (
+ E_COMPOSER_TEXT_HEADER (header));
- if (!reply_to || *reply_to == '\0')
+ if (text == NULL || *text == '\0')
return NULL;
addr = camel_internet_address_new ();
- if (camel_address_unformat (CAMEL_ADDRESS (addr), reply_to) == -1) {
+ if (camel_address_unformat (CAMEL_ADDRESS (addr), text) == -1) {
camel_object_unref (CAMEL_OBJECT (addr));
return NULL;
}
@@ -1482,66 +724,37 @@ e_msg_composer_hdrs_get_reply_to (EMsgComposerHdrs *hdrs)
return addr;
}
-static EDestination **
-destination_list_to_destv (GList *destinations)
-{
- EDestination **destv;
- GList *l;
- gint n, i;
-
- n = g_list_length (destinations);
-
- destv = g_new0 (EDestination *, n + 1);
-
- for (i = 0, l = destinations; l; i++, l = g_list_next (l)) {
- EDestination *destination = l->data;
-
- /* Need to ref, as users expect to own it */
- g_object_ref (destination);
- destv [i] = l->data;
- }
-
- return destv;
-}
-
-static EDestination **
-e_msg_composer_hdrs_get_internal (EMsgComposerHdrs *hdrs, ENameSelectorEntry *entry)
-{
- EDestinationStore *destination_store;
- GList *destinations;
- EDestination **destv = NULL;
-
- destination_store = e_name_selector_entry_peek_destination_store (entry);
- destinations = e_destination_store_list_destinations (destination_store);
-
- destv = destination_list_to_destv (destinations);
-
- g_list_free (destinations);
- return destv;
-}
-
EDestination **
e_msg_composer_hdrs_get_to (EMsgComposerHdrs *hdrs)
{
+ EComposerNameHeader *header;
+
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return e_msg_composer_hdrs_get_internal (hdrs, E_NAME_SELECTOR_ENTRY (hdrs->priv->to.entry));
+ header = E_COMPOSER_NAME_HEADER (hdrs->priv->headers[HEADER_TO]);
+ return e_composer_name_header_get_destinations (header);
}
EDestination **
e_msg_composer_hdrs_get_cc (EMsgComposerHdrs *hdrs)
{
+ EComposerNameHeader *header;
+
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return e_msg_composer_hdrs_get_internal (hdrs, E_NAME_SELECTOR_ENTRY (hdrs->priv->cc.entry));
+ header = E_COMPOSER_NAME_HEADER (hdrs->priv->headers[HEADER_CC]);
+ return e_composer_name_header_get_destinations (header);
}
EDestination **
e_msg_composer_hdrs_get_bcc (EMsgComposerHdrs *hdrs)
{
+ EComposerNameHeader *header;
+
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return e_msg_composer_hdrs_get_internal (hdrs, E_NAME_SELECTOR_ENTRY (hdrs->priv->bcc.entry));
+ header = E_COMPOSER_NAME_HEADER (hdrs->priv->headers[HEADER_BCC]);
+ return e_composer_name_header_get_destinations (header);
}
EDestination **
@@ -1595,47 +808,27 @@ e_msg_composer_hdrs_get_recipients (EMsgComposerHdrs *hdrs)
GList *
e_msg_composer_hdrs_get_post_to (EMsgComposerHdrs *hdrs)
{
- GList *uris, *cur;
- char *storeurl = NULL, *tmp;
+ EComposerHeader *header;
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- if (hdrs->priv->post_to.entry == NULL)
- return NULL;
-
- tmp = g_strdup (gtk_entry_get_text (GTK_ENTRY (hdrs->priv->post_to.entry)));
- uris = newsgroups_list_split (tmp);
- g_free (tmp);
-
- cur = uris;
- while (cur) {
- /* FIXME: this is a bit of a hack, should use camelurl's etc */
- if (strstr ((char *) cur->data, ":/") == NULL) {
- /* relative folder name: convert to absolute */
- if (!storeurl)
- storeurl = get_account_store_url (hdrs);
- if (!storeurl)
- break;
- tmp = g_strconcat (storeurl, cur->data, NULL);
- g_free (cur->data);
- cur->data = tmp;
- }
-
- cur = cur->next;
- }
-
- g_free (storeurl);
+ header = hdrs->priv->headers[HEADER_POST_TO];
- return uris;
+ return e_composer_post_header_get_folders (
+ E_COMPOSER_POST_HEADER (header));
}
-const char *
+const gchar *
e_msg_composer_hdrs_get_subject (EMsgComposerHdrs *hdrs)
{
+ GtkWidget *widget;
+
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return gtk_entry_get_text ((GtkEntry *) hdrs->priv->subject.entry);
+ widget = e_msg_composer_hdrs_get_subject_entry (hdrs);
+
+ return gtk_entry_get_text (GTK_ENTRY (widget));
}
@@ -1644,7 +837,7 @@ e_msg_composer_hdrs_get_reply_to_entry (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->reply_to.entry;
+ return hdrs->priv->headers[HEADER_REPLY_TO]->input_widget;
}
GtkWidget *
@@ -1652,7 +845,7 @@ e_msg_composer_hdrs_get_to_entry (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->to.entry;
+ return hdrs->priv->headers[HEADER_TO]->input_widget;
}
GtkWidget *
@@ -1660,7 +853,7 @@ e_msg_composer_hdrs_get_cc_entry (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->cc.entry;
+ return hdrs->priv->headers[HEADER_CC]->input_widget;
}
GtkWidget *
@@ -1668,7 +861,7 @@ e_msg_composer_hdrs_get_bcc_entry (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->bcc.entry;
+ return hdrs->priv->headers[HEADER_BCC]->input_widget;
}
GtkWidget *
@@ -1676,7 +869,7 @@ e_msg_composer_hdrs_get_post_to_label (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->post_to.entry;
+ return hdrs->priv->headers[HEADER_POST_TO]->input_widget;
}
GtkWidget *
@@ -1684,7 +877,7 @@ e_msg_composer_hdrs_get_subject_entry (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->subject.entry;
+ return hdrs->priv->headers[HEADER_SUBJECT]->input_widget;
}
GtkWidget *
@@ -1692,14 +885,5 @@ e_msg_composer_hdrs_get_from_hbox (EMsgComposerHdrs *hdrs)
{
g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
- return hdrs->priv->from.entry;
+ return hdrs->priv->headers[HEADER_FROM]->input_widget;
}
-
-GtkWidget *
-e_msg_composer_hdrs_get_from_omenu (EMsgComposerHdrs *hdrs)
-{
- g_return_val_if_fail (E_IS_MSG_COMPOSER_HDRS (hdrs), NULL);
-
- return GTK_WIDGET (g_object_get_data ((GObject *) hdrs->priv->from.entry, "from_menu"));
-}
-
diff --git a/composer/e-msg-composer-hdrs.h b/composer/e-msg-composer-hdrs.h
index 919400167d..1e983272a5 100644
--- a/composer/e-msg-composer-hdrs.h
+++ b/composer/e-msg-composer-hdrs.h
@@ -21,11 +21,10 @@
* Author: Ettore Perazzoli
*/
-
#ifndef ___E_MSG_COMPOSER_HDRS_H__
#define ___E_MSG_COMPOSER_HDRS_H__
-#include <gtk/gtktable.h>
+#include <gtk/gtk.h>
#include <bonobo/bonobo-ui-component.h>
@@ -33,20 +32,28 @@
#include <camel/camel-mime-message.h>
#include <libebook/e-destination.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) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrs))
-#define E_MSG_COMPOSER_HDRS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrsClass))
-#define E_IS_MSG_COMPOSER_HDRS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_MSG_COMPOSER_HDRS))
-#define E_IS_MSG_COMPOSER_HDRS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), E_TYPE_MSG_COMPOSER_HDRS))
-
-
-typedef struct _EMsgComposerHdrs EMsgComposerHdrs;
-typedef struct _EMsgComposerHdrsClass EMsgComposerHdrsClass;
+#define E_TYPE_MSG_COMPOSER_HDRS \
+ (e_msg_composer_hdrs_get_type ())
+#define E_MSG_COMPOSER_HDRS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrs))
+#define E_MSG_COMPOSER_HDRS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrsClass))
+#define E_IS_MSG_COMPOSER_HDRS(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_MSG_COMPOSER_HDRS))
+#define E_IS_MSG_COMPOSER_HDRS_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_MSG_COMPOSER_HDRS))
+#define E_MSG_COMPOSER_HDRS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrsClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMsgComposerHdrs EMsgComposerHdrs;
+typedef struct _EMsgComposerHdrsClass EMsgComposerHdrsClass;
typedef struct _EMsgComposerHdrsPrivate EMsgComposerHdrsPrivate;
struct _EMsgComposerHdrs {
@@ -54,18 +61,12 @@ struct _EMsgComposerHdrs {
EMsgComposerHdrsPrivate *priv;
- EAccount *account;
-
guint32 visible_mask;
-
- gboolean has_changed;
};
struct _EMsgComposerHdrsClass {
GtkTableClass parent_class;
- void (* show_address_dialog) (EMsgComposerHdrs *hdrs);
-
void (* subject_changed) (EMsgComposerHdrs *hdrs, gchar *subject);
void (* hdrs_changed) (EMsgComposerHdrs *hdrs);
@@ -79,19 +80,32 @@ typedef enum {
E_MSG_COMPOSER_VISIBLE_TO = (1 << 2),
E_MSG_COMPOSER_VISIBLE_CC = (1 << 3),
E_MSG_COMPOSER_VISIBLE_BCC = (1 << 4),
- E_MSG_COMPOSER_VISIBLE_POSTTO = (1 << 5), /* for posting to folders */
+ E_MSG_COMPOSER_VISIBLE_POSTTO = (1 << 5),
E_MSG_COMPOSER_VISIBLE_SUBJECT = (1 << 7)
} EMsgComposerHeaderVisibleFlags;
-#define E_MSG_COMPOSER_VISIBLE_MASK_SENDER (E_MSG_COMPOSER_VISIBLE_FROM | E_MSG_COMPOSER_VISIBLE_REPLYTO)
-#define E_MSG_COMPOSER_VISIBLE_MASK_BASIC (E_MSG_COMPOSER_VISIBLE_MASK_SENDER | E_MSG_COMPOSER_VISIBLE_SUBJECT)
-#define E_MSG_COMPOSER_VISIBLE_MASK_RECIPIENTS (E_MSG_COMPOSER_VISIBLE_TO | E_MSG_COMPOSER_VISIBLE_CC | E_MSG_COMPOSER_VISIBLE_BCC)
+#define E_MSG_COMPOSER_VISIBLE_MASK_SENDER \
+ (E_MSG_COMPOSER_VISIBLE_FROM | \
+ E_MSG_COMPOSER_VISIBLE_REPLYTO)
+
+#define E_MSG_COMPOSER_VISIBLE_MASK_BASIC \
+ (E_MSG_COMPOSER_VISIBLE_MASK_SENDER | \
+ E_MSG_COMPOSER_VISIBLE_SUBJECT)
+
+#define E_MSG_COMPOSER_VISIBLE_MASK_RECIPIENTS \
+ (E_MSG_COMPOSER_VISIBLE_TO | \
+ E_MSG_COMPOSER_VISIBLE_CC | \
+ E_MSG_COMPOSER_VISIBLE_BCC)
-#define E_MSG_COMPOSER_VISIBLE_MASK_MAIL (E_MSG_COMPOSER_VISIBLE_MASK_BASIC | E_MSG_COMPOSER_VISIBLE_MASK_RECIPIENTS)
-#define E_MSG_COMPOSER_VISIBLE_MASK_POST (E_MSG_COMPOSER_VISIBLE_MASK_BASIC | E_MSG_COMPOSER_VISIBLE_POSTTO)
+#define E_MSG_COMPOSER_VISIBLE_MASK_MAIL \
+ (E_MSG_COMPOSER_VISIBLE_MASK_BASIC | \
+ E_MSG_COMPOSER_VISIBLE_MASK_RECIPIENTS)
+#define E_MSG_COMPOSER_VISIBLE_MASK_POST \
+ (E_MSG_COMPOSER_VISIBLE_MASK_BASIC | \
+ E_MSG_COMPOSER_VISIBLE_POSTTO)
-GtkType e_msg_composer_hdrs_get_type (void);
+GType e_msg_composer_hdrs_get_type (void);
GtkWidget *e_msg_composer_hdrs_new (BonoboUIComponent *uic, int visible_mask, int visible_flags);
void e_msg_composer_hdrs_to_message (EMsgComposerHdrs *hdrs,
@@ -101,7 +115,8 @@ void e_msg_composer_hdrs_to_redirect (EMsgComposerHdrs *hdrs,
CamelMimeMessage *msg);
-void e_msg_composer_hdrs_set_from_account (EMsgComposerHdrs *hdrs,
+EAccount * e_msg_composer_hdrs_get_from_account (EMsgComposerHdrs *hdrs);
+gboolean e_msg_composer_hdrs_set_from_account (EMsgComposerHdrs *hdrs,
const char *account_name);
void e_msg_composer_hdrs_set_reply_to (EMsgComposerHdrs *hdrs,
const char *reply_to);
@@ -116,8 +131,8 @@ void e_msg_composer_hdrs_set_post_to (EMsgComposerHdrs *hdrs,
void e_msg_composer_hdrs_set_post_to_list (EMsgComposerHdrs *hdrs,
GList *urls);
void e_msg_composer_hdrs_set_post_to_base (EMsgComposerHdrs *hdrs,
- const char *base,
- const char *post_to);
+ const gchar *base,
+ const gchar *post_to);
void e_msg_composer_hdrs_set_subject (EMsgComposerHdrs *hdrs,
const char *subject);
@@ -134,7 +149,6 @@ const char *e_msg_composer_hdrs_get_subject (EMsgComposerHdrs *hdrs);
GList *e_msg_composer_hdrs_get_post_to (EMsgComposerHdrs *hdrs);
GtkWidget *e_msg_composer_hdrs_get_from_hbox (EMsgComposerHdrs *hdrs);
-GtkWidget *e_msg_composer_hdrs_get_from_omenu (EMsgComposerHdrs *hdrs);
GtkWidget *e_msg_composer_hdrs_get_reply_to_entry (EMsgComposerHdrs *hdrs);
GtkWidget *e_msg_composer_hdrs_get_to_entry (EMsgComposerHdrs *hdrs);
GtkWidget *e_msg_composer_hdrs_get_cc_entry (EMsgComposerHdrs *hdrs);
@@ -147,9 +161,6 @@ void e_msg_composer_hdrs_set_visible_mask (EMsgComposerHdrs *hdrs,
void e_msg_composer_hdrs_set_visible (EMsgComposerHdrs *hdrs,
int visible_flags);
-#ifdef _cplusplus
-}
-#endif /* _cplusplus */
-
+G_END_DECLS
#endif /* __E_MSG_COMPOSER_HDRS_H__ */
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index eb4cac1e8b..be3f47e9c9 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -520,9 +520,12 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
CamelMimePart *part;
CamelException ex;
GByteArray *data;
+ EAccount *account;
char *charset;
int i;
+ account = e_msg_composer_hdrs_get_from_account (hdrs);
+
if (p->persist_stream_interface == CORBA_OBJECT_NIL)
return NULL;
@@ -543,9 +546,9 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
/* Message Disposition Notification */
if (p->request_receipt) {
- char *mdn_address = hdrs->account->id->reply_to;
+ char *mdn_address = account->id->reply_to;
if (!mdn_address || !*mdn_address)
- mdn_address = hdrs->account->id->address;
+ mdn_address = account->id->address;
camel_medium_add_header (CAMEL_MEDIUM (new), "Disposition-Notification-To", mdn_address);
}
@@ -747,8 +750,8 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
camel_mime_part_set_encoding (part, plain_encoding);
camel_object_unref (current);
- if (hdrs->account && hdrs->account->pgp_key && *hdrs->account->pgp_key) {
- pgp_userid = hdrs->account->pgp_key;
+ if (account && account->pgp_key && *account->pgp_key) {
+ pgp_userid = account->pgp_key;
} else {
from = e_msg_composer_hdrs_get_from(hdrs);
camel_internet_address_get(from, 0, NULL, &pgp_userid);
@@ -757,7 +760,7 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
if (p->pgp_sign) {
CamelMimePart *npart = camel_mime_part_new();
- cipher = mail_crypto_get_pgp_cipher_context(hdrs->account);
+ cipher = mail_crypto_get_pgp_cipher_context(account);
camel_cipher_sign(cipher, pgp_userid, CAMEL_CIPHER_HASH_SHA1, part, npart, &ex);
camel_object_unref(cipher);
@@ -774,14 +777,14 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
CamelMimePart *npart = camel_mime_part_new();
/* check to see if we should encrypt to self, NB gets removed immediately after use */
- if (hdrs->account && hdrs->account->pgp_encrypt_to_self && pgp_userid)
+ if (account && account->pgp_encrypt_to_self && pgp_userid)
g_ptr_array_add (recipients, g_strdup (pgp_userid));
- cipher = mail_crypto_get_pgp_cipher_context (hdrs->account);
+ cipher = mail_crypto_get_pgp_cipher_context (account);
camel_cipher_encrypt(cipher, pgp_userid, recipients, part, npart, &ex);
camel_object_unref (cipher);
- if (hdrs->account && hdrs->account->pgp_encrypt_to_self && pgp_userid)
+ if (account && account->pgp_encrypt_to_self && pgp_userid)
g_ptr_array_set_size(recipients, recipients->len - 1);
if (camel_exception_is_set (&ex)) {
@@ -813,14 +816,14 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
camel_object_unref(current);
if (p->smime_sign
- && (hdrs->account == NULL || hdrs->account->smime_sign_key == NULL || hdrs->account->smime_sign_key[0] == 0)) {
+ && (account == NULL || account->smime_sign_key == NULL || account->smime_sign_key[0] == 0)) {
camel_exception_set (&ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot sign outgoing message: No signing certificate set for this account"));
goto exception;
}
if (p->smime_encrypt
- && (hdrs->account == NULL || hdrs->account->smime_sign_key == NULL || hdrs->account->smime_sign_key[0] == 0)) {
+ && (account == NULL || account->smime_sign_key == NULL || account->smime_sign_key[0] == 0)) {
camel_exception_set (&ex, CAMEL_EXCEPTION_SYSTEM,
_("Cannot encrypt outgoing message: No encryption certificate set for this account"));
goto exception;
@@ -834,12 +837,12 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
/* if we're also encrypting, envelope-sign rather than clear-sign */
if (p->smime_encrypt) {
camel_smime_context_set_sign_mode((CamelSMIMEContext *)cipher, CAMEL_SMIME_SIGN_ENVELOPED);
- camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, hdrs->account->smime_encrypt_key);
- } else if (hdrs->account && hdrs->account->smime_encrypt_key && *hdrs->account->smime_encrypt_key) {
- camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, hdrs->account->smime_encrypt_key);
+ camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, account->smime_encrypt_key);
+ } else if (account && account->smime_encrypt_key && *account->smime_encrypt_key) {
+ camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, account->smime_encrypt_key);
}
- camel_cipher_sign(cipher, hdrs->account->smime_sign_key, CAMEL_CIPHER_HASH_SHA1, part, npart, &ex);
+ camel_cipher_sign(cipher, account->smime_sign_key, CAMEL_CIPHER_HASH_SHA1, part, npart, &ex);
camel_object_unref(cipher);
if (camel_exception_is_set(&ex)) {
@@ -853,11 +856,11 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
if (p->smime_encrypt) {
/* check to see if we should encrypt to self, NB removed after use */
- if (hdrs->account->smime_encrypt_to_self)
- g_ptr_array_add(recipients, g_strdup (hdrs->account->smime_encrypt_key));
+ if (account->smime_encrypt_to_self)
+ g_ptr_array_add(recipients, g_strdup (account->smime_encrypt_key));
cipher = camel_smime_context_new(session);
- camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, hdrs->account->smime_encrypt_key);
+ camel_smime_context_set_encrypt_key((CamelSMIMEContext *)cipher, TRUE, account->smime_encrypt_key);
camel_cipher_encrypt(cipher, NULL, recipients, part, (CamelMimePart *)new, &ex);
camel_object_unref(cipher);
@@ -865,7 +868,7 @@ build_message (EMsgComposer *composer, gboolean save_html_object_data)
if (camel_exception_is_set(&ex))
goto exception;
- if (hdrs->account->smime_encrypt_to_self)
+ if (account->smime_encrypt_to_self)
g_ptr_array_set_size(recipients, recipients->len - 1);
}
@@ -1186,7 +1189,8 @@ get_signature_html (EMsgComposer *composer)
char *address;
char *name;
- id = E_MSG_COMPOSER_HDRS (p->hdrs)->account->id;
+ id = e_msg_composer_hdrs_get_from_account (
+ E_MSG_COMPOSER_HDRS (p->hdrs))->id;
address = id->address ? camel_text_to_html (id->address, CONVERT_SPACES, 0) : NULL;
name = id->name ? camel_text_to_html (id->name, CONVERT_SPACES, 0) : NULL;
organization = id->organization ? camel_text_to_html (id->organization, CONVERT_SPACES, 0) : NULL;
@@ -2737,10 +2741,11 @@ from_changed_cb (EMsgComposerHdrs *hdrs, void *data)
{
EMsgComposer *composer = E_MSG_COMPOSER (data);
EMsgComposerPrivate *p = composer->priv;
+ EAccount *account;
- if (hdrs->account) {
- EAccount *account = hdrs->account;
+ account = e_msg_composer_hdrs_get_from_account (hdrs);
+ if (account) {
e_msg_composer_set_pgp_sign (composer,
account->pgp_always_sign &&
(!account->pgp_no_imip_sign || !p->mime_type ||
@@ -4058,10 +4063,14 @@ set_editor_signature (EMsgComposer *composer)
{
EAccountIdentity *id;
EMsgComposerPrivate *p = composer->priv;
+ EAccount *account;
+
+ account = e_msg_composer_hdrs_get_from_account (
+ E_MSG_COMPOSER_HDRS (p->hdrs));
- g_return_if_fail (E_MSG_COMPOSER_HDRS (p->hdrs)->account != NULL);
+ g_return_if_fail (account != NULL);
- id = E_MSG_COMPOSER_HDRS (p->hdrs)->account->id;
+ id = account->id;
if (id->sig_uid)
p->signature = mail_config_get_signature_by_uid (id->sig_uid);
else
@@ -5133,7 +5142,10 @@ e_msg_composer_set_body (EMsgComposer *composer, const char *body,
if (g_ascii_strncasecmp (p->mime_type, "text/calendar", 13) == 0) {
EMsgComposerHdrs *hdrs = E_MSG_COMPOSER_HDRS (p->hdrs);
- if (hdrs->account && hdrs->account->pgp_no_imip_sign)
+ EAccount *account;
+
+ account = e_msg_composer_hdrs_get_from_account (hdrs);
+ if (account && account->pgp_no_imip_sign)
e_msg_composer_set_pgp_sign (composer, FALSE);
}
}
@@ -5608,7 +5620,7 @@ e_msg_composer_get_preferred_account (EMsgComposer *composer)
hdrs = E_MSG_COMPOSER_HDRS (p->hdrs);
- return hdrs->account;
+ return e_msg_composer_hdrs_get_from_account (hdrs);
}
diff --git a/mail/ChangeLog b/mail/ChangeLog
index b3ca18a6a1..46e36edb06 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,10 @@
+2007-11-27 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #495123
+
+ * mail-session.c (mail_session_init):
+ Pass the CamelSession to the EAccountComboBox class (ugly hack).
+
2007-11-26 Nicholas Miell <nmiell@gmail.com>
** Fix for bug #216485
diff --git a/mail/mail-session.c b/mail/mail-session.c
index 2f4d5c8021..6f4922355f 100644
--- a/mail/mail-session.c
+++ b/mail/mail-session.c
@@ -656,6 +656,7 @@ mail_session_init (const char *base_directory)
camel_provider_init();
session = CAMEL_SESSION (camel_object_new (MAIL_SESSION_TYPE));
+ e_account_combo_box_set_session (session); /* XXX Don't ask... */
camel_dir = g_strdup_printf ("%s/mail", base_directory);
camel_session_construct (session, camel_dir);
diff --git a/plugins/exchange-operations/ChangeLog b/plugins/exchange-operations/ChangeLog
index e69873d123..9c7cec7959 100644
--- a/plugins/exchange-operations/ChangeLog
+++ b/plugins/exchange-operations/ChangeLog
@@ -1,3 +1,10 @@
+2007-11-27 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #495123
+
+ * exchange-mail-send-options.c (append_to_header):
+ Use e_msg_composer_hdrs_get_from_account() to obtain the EAccount.
+
2007-11-23 Milan Crha <mcrha@redhat.com>
** Fix for bug #479081
diff --git a/plugins/exchange-operations/exchange-mail-send-options.c b/plugins/exchange-operations/exchange-mail-send-options.c
index 8852e993a0..716ea7a01d 100644
--- a/plugins/exchange-operations/exchange-mail-send-options.c
+++ b/plugins/exchange-operations/exchange-mail-send-options.c
@@ -123,10 +123,13 @@ append_to_header (ExchangeSendOptionsDialog *dialog, gint state, gpointer data)
if (dialog->options->delivery_enabled) {
EMsgComposerHdrs *hdrs = e_msg_composer_get_hdrs(composer);
+ EAccount *account;
+ char *mdn_address;
- char *mdn_address = hdrs->account->id->reply_to;
+ account = e_msg_composer_hdrs_get_from_account (hdrs);
+ mdn_address = account->id->reply_to;
if (!mdn_address || !*mdn_address)
- mdn_address = hdrs->account->id->address;
+ mdn_address = account->id->address;
e_msg_composer_modify_header (composer, "Return-Receipt-To", mdn_address);
}
else
@@ -134,10 +137,13 @@ append_to_header (ExchangeSendOptionsDialog *dialog, gint state, gpointer data)
if (dialog->options->read_enabled) {
EMsgComposerHdrs *hdrs = e_msg_composer_get_hdrs(composer);
+ EAccount *account;
+ char *mdn_address;
- char *mdn_address = hdrs->account->id->reply_to;
+ account = e_msg_composer_hdrs_get_from_account (hdrs);
+ mdn_address = account->id->reply_to;
if (!mdn_address || !*mdn_address)
- mdn_address = hdrs->account->id->address;
+ mdn_address = account->id->address;
e_msg_composer_modify_header (composer, "Disposition-Notification-To", mdn_address);
}
diff --git a/widgets/misc/ChangeLog b/widgets/misc/ChangeLog
index bff2d54362..559bf58055 100644
--- a/widgets/misc/ChangeLog
+++ b/widgets/misc/ChangeLog
@@ -1,3 +1,15 @@
+2007-11-27 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #495123
+
+ * Makefile.am:
+ Add e-account-combo-box.[ch].
+
+ * e-account-combo-box.c:
+ * e-account-combo-box.h:
+ New widget renders an EAccountList as a combo box. Also listens
+ for changes to the EAccountList and updates itself accordingly.
+
2007-11-05 Milan Crha <mcrha@redhat.com>
** Fix for bug #231166
diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am
index fb8997f4a5..c35d7a9f2c 100644
--- a/widgets/misc/Makefile.am
+++ b/widgets/misc/Makefile.am
@@ -34,6 +34,7 @@ glade_DATA = e-send-options.glade \
widgetsinclude_HEADERS = \
$(pilot_headers) \
+ e-account-combo-box.h \
e-activity-handler.h \
e-attachment.h \
e-attachment-bar.h \
@@ -81,6 +82,7 @@ widgetsinclude_HEADERS = \
libemiscwidgets_la_SOURCES = \
$(widgetsinclude_HEADERS) \
$(pilot_sources) \
+ e-account-combo-box.c \
e-activity-handler.c \
e-calendar.c \
e-attachment.c \
diff --git a/widgets/misc/e-account-combo-box.c b/widgets/misc/e-account-combo-box.c
new file mode 100644
index 0000000000..064ed2bd10
--- /dev/null
+++ b/widgets/misc/e-account-combo-box.c
@@ -0,0 +1,413 @@
+#include "e-account-combo-box.h"
+
+#include <string.h>
+#include <camel/camel-store.h>
+
+#define E_ACCOUNT_COMBO_BOX_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxPrivate))
+
+enum {
+ COLUMN_STRING,
+ COLUMN_ACCOUNT
+};
+
+struct _EAccountComboBoxPrivate {
+ EAccountList *account_list;
+};
+
+static gpointer parent_class;
+static CamelSession *camel_session;
+
+static gboolean
+account_combo_box_has_dupes (GList *list,
+ const gchar *address)
+{
+ GList *iter;
+ guint count = 0;
+
+ /* Look for duplicates of the given email address. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ EAccount *account = iter->data;
+
+ if (strcmp (account->id->address, address) == 0)
+ count++;
+ }
+
+ return (count > 1);
+}
+
+static gboolean
+account_combo_box_test_account (EAccount *account)
+{
+ CamelStore *store;
+ CamelException ex;
+ const gchar *url;
+ gboolean writable = FALSE;
+
+ /* Account must be enabled. */
+ if (!account->enabled)
+ return FALSE;
+
+ /* Account must have a non-empty email address. */
+ if (account->id->address == NULL || *account->id->address == '\0')
+ return FALSE;
+
+ /* XXX Not sure I understand this part. */
+ if (account->parent_uid == NULL)
+ return TRUE;
+
+ /* Account must be writable. */
+ camel_exception_init (&ex);
+ url = e_account_get_string (account, E_ACCOUNT_SOURCE_URL);
+ store = CAMEL_STORE (camel_session_get_service (
+ camel_session, url, CAMEL_PROVIDER_STORE, &ex));
+ if (store != NULL) {
+ writable = (store->mode & CAMEL_STORE_WRITE);
+ camel_object_unref (store);
+ }
+ camel_exception_clear (&ex);
+
+ return writable;
+}
+
+static void
+account_combo_box_refresh_cb (EAccountList *account_list,
+ EAccount *unused,
+ EAccountComboBox *combo_box)
+{
+ GtkListStore *store;
+ GtkTreeModel *model;
+ EIterator *account_iter;
+ EAccount *account;
+ GHashTable *index;
+ GList *list = NULL;
+ GList *iter;
+
+ store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_ACCOUNT);
+ model = GTK_TREE_MODEL (store);
+
+ /* Embed a reverse-lookup index into the list store. */
+ index = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) g_object_unref,
+ (GDestroyNotify) gtk_tree_row_reference_free);
+ g_object_set_data_full (
+ G_OBJECT (combo_box), "index", index,
+ (GDestroyNotify) g_hash_table_destroy);
+
+ if (account_list == NULL)
+ goto skip;
+
+ /* Build a list of EAccounts to display. */
+ account_iter = e_list_get_iterator (E_LIST (account_list));
+ while (e_iterator_is_valid (account_iter)) {
+ EAccount *account;
+
+ /* XXX EIterator misuses const. */
+ account = (EAccount *) e_iterator_get (account_iter);
+ if (account_combo_box_test_account (account))
+ list = g_list_prepend (list, account);
+ e_iterator_next (account_iter);
+ }
+ g_object_unref (account_iter);
+
+ list = g_list_reverse (list);
+
+ /* Populate the list store and index. */
+ for (iter = list; iter != NULL; iter = iter->next) {
+ GtkTreeRowReference *reference;
+ GtkTreeIter tree_iter;
+ GtkTreePath *path;
+ gchar *string;
+
+ account = iter->data;
+
+ /* Show the account name for duplicate email addresses. */
+ if (account_combo_box_has_dupes (list, account->id->address))
+ string = g_strdup_printf (
+ "%s <%s> (%s)",
+ account->id->name,
+ account->id->address,
+ account->name);
+ else
+ string = g_strdup_printf (
+ "%s <%s>",
+ account->id->name,
+ account->id->address);
+
+ gtk_list_store_append (store, &tree_iter);
+ gtk_list_store_set (
+ store, &tree_iter,
+ COLUMN_STRING, string,
+ COLUMN_ACCOUNT, account, -1);
+
+ path = gtk_tree_model_get_path (model, &tree_iter);
+ reference = gtk_tree_row_reference_new (model, path);
+ g_hash_table_insert (index, account, reference);
+ gtk_tree_path_free (path);
+
+ g_free (string);
+ }
+
+ g_list_free (list);
+
+skip:
+ /* Restore the previously selected account. */
+ account = e_account_combo_box_get_active (combo_box);
+ gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), model);
+ e_account_combo_box_set_active (combo_box, account);
+}
+
+static GObject *
+account_combo_box_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GtkCellRenderer *renderer;
+
+ /* Chain up to parent's constructor() method. */
+ object = G_OBJECT_CLASS (parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+
+ renderer = gtk_cell_renderer_text_new ();
+
+ gtk_cell_layout_pack_start (
+ GTK_CELL_LAYOUT (object), renderer, TRUE);
+ gtk_cell_layout_add_attribute (
+ GTK_CELL_LAYOUT (object), renderer, "text", COLUMN_STRING);
+
+ return object;
+}
+
+static void
+account_combo_box_dispose (GObject *object)
+{
+ EAccountComboBoxPrivate *priv;
+
+ priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (object);
+
+ if (priv->account_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->account_list,
+ account_combo_box_refresh_cb, object);
+ g_object_unref (priv->account_list);
+ priv->account_list = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+account_combo_box_class_init (EAccountComboBoxClass *class)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EAccountComboBoxPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->constructor = account_combo_box_constructor;
+ object_class->dispose = account_combo_box_dispose;
+}
+
+static void
+account_combo_box_init (EAccountComboBox *combo_box)
+{
+ combo_box->priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
+}
+
+GType
+e_account_combo_box_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EAccountComboBoxClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) account_combo_box_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EAccountComboBox),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) account_combo_box_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_COMBO_BOX, "EAccountComboBox", &type_info, 0);
+ }
+
+ return type;
+}
+
+GtkWidget *
+e_account_combo_box_new (void)
+{
+ return g_object_new (E_TYPE_ACCOUNT_COMBO_BOX, NULL);
+}
+
+void
+e_account_combo_box_set_session (CamelSession *session)
+{
+ /* XXX Really gross hack.
+ *
+ * We need a CamelSession to test whether a given EAccount is
+ * writable. The global CamelSession object is defined in the
+ * mailer, but we're too far down the stack to access it. So
+ * we have to rely on someone passing us a reference to it.
+ *
+ * A much cleaner solution would be to store the writeability
+ * of an account directly into the EAccount, but this would likely
+ * require breaking ABI and all the fun that goes along with that.
+ */
+
+ camel_session = session;
+}
+
+void
+e_account_combo_box_set_account_list (EAccountComboBox *combo_box,
+ EAccountList *account_list)
+{
+ EAccountComboBoxPrivate *priv;
+
+ g_return_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box));
+
+ if (account_list != NULL)
+ g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
+
+ priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
+
+ if (priv->account_list != NULL) {
+ g_signal_handlers_disconnect_by_func (
+ priv->account_list,
+ account_combo_box_refresh_cb, combo_box);
+ g_object_unref (priv->account_list);
+ priv->account_list = NULL;
+ }
+
+ if (account_list != NULL) {
+ priv->account_list = g_object_ref (account_list);
+
+ /* Listen for changes to the account list. */
+ g_signal_connect (
+ priv->account_list, "account-added",
+ G_CALLBACK (account_combo_box_refresh_cb), combo_box);
+ g_signal_connect (
+ priv->account_list, "account-changed",
+ G_CALLBACK (account_combo_box_refresh_cb), combo_box);
+ g_signal_connect (
+ priv->account_list, "account-removed",
+ G_CALLBACK (account_combo_box_refresh_cb), combo_box);
+ }
+
+ account_combo_box_refresh_cb (account_list, NULL, combo_box);
+}
+
+EAccount *
+e_account_combo_box_get_active (EAccountComboBox *combo_box)
+{
+ EAccount *account;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean iter_set;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
+
+ iter_set = gtk_combo_box_get_active_iter (
+ GTK_COMBO_BOX (combo_box), &iter);
+ if (!iter_set)
+ return NULL;
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
+ gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
+
+ return account;
+}
+
+gboolean
+e_account_combo_box_set_active (EAccountComboBox *combo_box,
+ EAccount *account)
+{
+ GHashTable *index;
+ EAccountList *account_list;
+ GtkTreeRowReference *reference;
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean iter_set;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
+
+ if (account != NULL)
+ g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE);
+
+ account_list = combo_box->priv->account_list;
+ g_return_val_if_fail (account_list != NULL, FALSE);
+
+ /* Failure here indicates a programming error. */
+ index = g_object_get_data (G_OBJECT (combo_box), "index");
+ g_assert (index != NULL);
+
+ /* NULL means select the default account. */
+ /* XXX EAccountList misuses const. */
+ if (account == NULL)
+ account = (EAccount *)
+ e_account_list_get_default (account_list);
+
+ /* Lookup the tree row reference for the account. */
+ reference = g_hash_table_lookup (index, account);
+ if (reference == NULL)
+ return FALSE;
+
+ /* Convert the reference to a tree iterator. */
+ path = gtk_tree_row_reference_get_path (reference);
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
+ iter_set = gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ if (!iter_set)
+ return FALSE;
+
+ /* Activate the corresponding combo box item. */
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
+
+ return TRUE;
+}
+
+const gchar *
+e_account_combo_box_get_active_name (EAccountComboBox *combo_box)
+{
+ EAccount *account;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
+
+ account = e_account_combo_box_get_active (combo_box);
+ return (account != NULL) ? account->name : NULL;
+}
+
+gboolean
+e_account_combo_box_set_active_name (EAccountComboBox *combo_box,
+ const gchar *account_name)
+{
+ EAccountList *account_list;
+ EAccount *account;
+
+ g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
+
+ account_list = combo_box->priv->account_list;
+ g_return_val_if_fail (account_list != NULL, FALSE);
+
+ /* XXX EAccountList misuses const. */
+ account = (EAccount *) e_account_list_find (
+ account_list, E_ACCOUNT_FIND_NAME, account_name);
+
+ if (account == NULL)
+ return FALSE;
+
+ return e_account_combo_box_set_active (combo_box, account);
+}
diff --git a/widgets/misc/e-account-combo-box.h b/widgets/misc/e-account-combo-box.h
new file mode 100644
index 0000000000..a4363cf2e2
--- /dev/null
+++ b/widgets/misc/e-account-combo-box.h
@@ -0,0 +1,60 @@
+#ifndef E_ACCOUNT_COMBO_BOX_H
+#define E_ACCOUNT_COMBO_BOX_H
+
+#include <gtk/gtk.h>
+#include <camel/camel-session.h>
+#include <libedataserver/e-account.h>
+#include <libedataserver/e-account-list.h>
+
+/* Standard GObject macros */
+#define E_TYPE_ACCOUNT_COMBO_BOX \
+ (e_account_combo_box_get_type ())
+#define E_ACCOUNT_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBox))
+#define E_ACCOUNT_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
+#define E_IS_ACCOUNT_COMBO_BOX(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_ACCOUNT_COMBO_BOX))
+#define E_IS_ACCOUNT_COMBO_BOX_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_ACCOUNT_COMBO_BOX))
+#define E_ACCOUNT_COMBO_BOX_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EAccountComboBox EAccountComboBox;
+typedef struct _EAccountComboBoxClass EAccountComboBoxClass;
+typedef struct _EAccountComboBoxPrivate EAccountComboBoxPrivate;
+
+struct _EAccountComboBox {
+ GtkComboBox parent;
+ EAccountComboBoxPrivate *priv;
+};
+
+struct _EAccountComboBoxClass {
+ GtkComboBoxClass parent_class;
+};
+
+GType e_account_combo_box_get_type (void);
+GtkWidget * e_account_combo_box_new (void);
+void e_account_combo_box_set_session (CamelSession *session);
+void e_account_combo_box_set_account_list
+ (EAccountComboBox *combo_box,
+ EAccountList *account_list);
+EAccount * e_account_combo_box_get_active (EAccountComboBox *combo_box);
+gboolean e_account_combo_box_set_active (EAccountComboBox *combo_box,
+ EAccount *account);
+const gchar * e_account_combo_box_get_active_name
+ (EAccountComboBox *combo_box);
+gboolean e_account_combo_box_set_active_name
+ (EAccountComboBox *combo_box,
+ const gchar *account_name);
+
+G_END_DECLS
+
+#endif /* E_ACCOUNT_COMBO_BOX_H */