diff options
Diffstat (limited to 'composer/e-composer-header-table.c')
-rw-r--r-- | composer/e-composer-header-table.c | 1501 |
1 files changed, 1501 insertions, 0 deletions
diff --git a/composer/e-composer-header-table.c b/composer/e-composer-header-table.c new file mode 100644 index 0000000000..8c21af1e24 --- /dev/null +++ b/composer/e-composer-header-table.c @@ -0,0 +1,1501 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-composer-header-table.h" + +#include <glib/gi18n-lib.h> + +#include "e-msg-composer.h" +#include "e-composer-private.h" +#include "e-composer-from-header.h" +#include "e-composer-name-header.h" +#include "e-composer-post-header.h" +#include "e-composer-spell-header.h" +#include "e-composer-text-header.h" + +#define E_COMPOSER_HEADER_TABLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_COMPOSER_HEADER_TABLE, EComposerHeaderTablePrivate)) + +#define HEADER_TOOLTIP_TO \ + _("Enter the recipients of the message") +#define HEADER_TOOLTIP_CC \ + _("Enter the addresses that will receive a " \ + "carbon copy of the message") +#define HEADER_TOOLTIP_BCC \ + _("Enter the addresses that will receive a " \ + "carbon copy of the message without appearing " \ + "in the recipient list of the message") + +struct _EComposerHeaderTablePrivate { + EComposerHeader *headers[E_COMPOSER_NUM_HEADERS]; + GtkWidget *signature_label; + GtkWidget *signature_combo_box; + ENameSelector *name_selector; + EClientCache *client_cache; +}; + +enum { + PROP_0, + PROP_CLIENT_CACHE, + PROP_DESTINATIONS_BCC, + PROP_DESTINATIONS_CC, + PROP_DESTINATIONS_TO, + PROP_IDENTITY_UID, + PROP_POST_TO, + PROP_REPLY_TO, + PROP_SIGNATURE_COMBO_BOX, + PROP_SIGNATURE_UID, + PROP_SUBJECT +}; + +G_DEFINE_TYPE ( + EComposerHeaderTable, + e_composer_header_table, + GTK_TYPE_TABLE) + +static void +g_value_set_destinations (GValue *value, + EDestination **destinations) +{ + GPtrArray *array; + gint ii; + + /* Preallocate some reasonable number. */ + array = g_ptr_array_new_full (64, g_object_unref); + + for (ii = 0; destinations[ii] != NULL; ii++) { + g_ptr_array_add (array, e_destination_copy (destinations[ii])); + } + + g_value_take_boxed (value, array); +} + +static EDestination ** +g_value_dup_destinations (const GValue *value) +{ + EDestination **destinations; + const EDestination *dest; + GPtrArray *array; + guint ii; + + array = g_value_get_boxed (value); + destinations = g_new0 (EDestination *, array->len + 1); + + for (ii = 0; ii < array->len; ii++) { + dest = g_ptr_array_index (array, ii); + destinations[ii] = e_destination_copy (dest); + } + + return destinations; +} + +static void +g_value_set_string_list (GValue *value, + GList *list) +{ + GPtrArray *array; + + array = g_ptr_array_new_full (g_list_length (list), g_free); + + while (list != NULL) { + g_ptr_array_add (array, g_strdup (list->data)); + list = list->next; + } + + g_value_take_boxed (value, array); +} + +static GList * +g_value_dup_string_list (const GValue *value) +{ + GPtrArray *array; + GList *list = NULL; + gint ii; + + array = g_value_get_boxed (value); + + for (ii = 0; ii < array->len; ii++) { + const gchar *element = g_ptr_array_index (array, ii); + list = g_list_prepend (list, g_strdup (element)); + } + + return g_list_reverse (list); +} + +static void +composer_header_table_notify_header (EComposerHeader *header, + const gchar *property_name) +{ + GtkWidget *parent; + + parent = gtk_widget_get_parent (header->input_widget); + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (parent)); + g_object_notify (G_OBJECT (parent), property_name); +} + +static void +composer_header_table_notify_widget (GtkWidget *widget, + const gchar *property_name) +{ + GtkWidget *parent; + + parent = gtk_widget_get_parent (widget); + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (parent)); + g_object_notify (G_OBJECT (parent), property_name); +} + +static void +composer_header_table_bind_header (const gchar *property_name, + const gchar *signal_name, + EComposerHeader *header) +{ + /* Propagate the signal as "notify::property_name". */ + + g_signal_connect ( + header, signal_name, + G_CALLBACK (composer_header_table_notify_header), + (gpointer) property_name); +} + +static void +composer_header_table_bind_widget (const gchar *property_name, + const gchar *signal_name, + GtkWidget *widget) +{ + /* Propagate the signal as "notify::property_name". */ + + g_signal_connect ( + widget, signal_name, + G_CALLBACK (composer_header_table_notify_widget), + (gpointer) property_name); +} + +static EDestination ** +composer_header_table_update_destinations (EDestination **old_destinations, + const gchar * const *auto_addresses) +{ + CamelAddress *address; + CamelInternetAddress *inet_address; + EDestination **new_destinations; + EDestination *destination; + GQueue queue = G_QUEUE_INIT; + guint length; + gint ii; + + /* Include automatic recipients for the selected account. */ + + if (auto_addresses == NULL) + goto skip_auto; + + inet_address = camel_internet_address_new (); + address = CAMEL_ADDRESS (inet_address); + + /* XXX Calling camel_address_decode() multiple times on the same + * CamelInternetAddress has a cumulative effect, which isn't + * well documented. */ + for (ii = 0; auto_addresses[ii] != NULL; ii++) + camel_address_decode (address, auto_addresses[ii]); + + for (ii = 0; ii < camel_address_length (address); ii++) { + const gchar *name, *email; + + if (!camel_internet_address_get ( + inet_address, ii, &name, &email)) + continue; + + destination = e_destination_new (); + e_destination_set_auto_recipient (destination, TRUE); + + if (name != NULL) + e_destination_set_name (destination, name); + + if (email != NULL) + e_destination_set_email (destination, email); + + g_queue_push_tail (&queue, destination); + } + + g_object_unref (inet_address); + +skip_auto: + + /* Include custom recipients for this message. */ + + if (old_destinations == NULL) + goto skip_custom; + + for (ii = 0; old_destinations[ii] != NULL; ii++) { + if (e_destination_is_auto_recipient (old_destinations[ii])) + continue; + + destination = e_destination_copy (old_destinations[ii]); + g_queue_push_tail (&queue, destination); + } + +skip_custom: + + length = g_queue_get_length (&queue); + new_destinations = g_new0 (EDestination *, length + 1); + + for (ii = 0; ii < length; ii++) + new_destinations[ii] = g_queue_pop_head (&queue); + + /* Sanity check. */ + g_warn_if_fail (g_queue_is_empty (&queue)); + + return new_destinations; +} + +static void +composer_header_table_setup_mail_headers (EComposerHeaderTable *table) +{ + GSettings *settings; + gint ii; + + settings = g_settings_new ("org.gnome.evolution.mail"); + + for (ii = 0; ii < E_COMPOSER_NUM_HEADERS; ii++) { + EComposerHeader *header; + const gchar *key; + gboolean sensitive; + gboolean visible; + + header = e_composer_header_table_get_header (table, ii); + + switch (ii) { + case E_COMPOSER_HEADER_BCC: + key = "composer-show-bcc"; + break; + + case E_COMPOSER_HEADER_CC: + key = "composer-show-cc"; + break; + + case E_COMPOSER_HEADER_REPLY_TO: + key = "composer-show-reply-to"; + break; + + default: + key = NULL; + break; + } + + if (key != NULL) + g_settings_unbind (header, "visible"); + + switch (ii) { + case E_COMPOSER_HEADER_FROM: + sensitive = TRUE; + visible = TRUE; + break; + + case E_COMPOSER_HEADER_BCC: + case E_COMPOSER_HEADER_CC: + case E_COMPOSER_HEADER_REPLY_TO: + case E_COMPOSER_HEADER_SUBJECT: + case E_COMPOSER_HEADER_TO: + sensitive = TRUE; + visible = TRUE; + break; + + default: + sensitive = FALSE; + visible = FALSE; + break; + } + + e_composer_header_set_sensitive (header, sensitive); + e_composer_header_set_visible (header, visible); + + if (key != NULL) + g_settings_bind ( + settings, key, + header, "visible", + G_SETTINGS_BIND_DEFAULT); + } + + g_object_unref (settings); +} + +static void +composer_header_table_setup_post_headers (EComposerHeaderTable *table) +{ + GSettings *settings; + gint ii; + + settings = g_settings_new ("org.gnome.evolution.mail"); + + for (ii = 0; ii < E_COMPOSER_NUM_HEADERS; ii++) { + EComposerHeader *header; + const gchar *key; + + header = e_composer_header_table_get_header (table, ii); + + switch (ii) { + case E_COMPOSER_HEADER_FROM: + key = "composer-show-post-from"; + break; + + case E_COMPOSER_HEADER_REPLY_TO: + key = "composer-show-post-reply-to"; + break; + + default: + key = NULL; + break; + } + + if (key != NULL) + g_settings_unbind (header, "visible"); + + switch (ii) { + case E_COMPOSER_HEADER_FROM: + case E_COMPOSER_HEADER_POST_TO: + case E_COMPOSER_HEADER_REPLY_TO: + case E_COMPOSER_HEADER_SUBJECT: + e_composer_header_set_sensitive (header, TRUE); + e_composer_header_set_visible (header, TRUE); + break; + + default: /* this includes TO, CC and BCC */ + e_composer_header_set_sensitive (header, FALSE); + e_composer_header_set_visible (header, FALSE); + break; + } + + if (key != NULL) + g_settings_bind ( + settings, key, + header, "visible", + G_SETTINGS_BIND_DEFAULT); + } + + g_object_unref (settings); +} + +static gboolean +composer_header_table_show_post_headers (EComposerHeaderTable *table) +{ + EClientCache *client_cache; + ESourceRegistry *registry; + GList *list, *link; + const gchar *extension_name; + const gchar *target_uid; + gboolean show_post_headers = FALSE; + + client_cache = e_composer_header_table_ref_client_cache (table); + registry = e_client_cache_ref_registry (client_cache); + + target_uid = e_composer_header_table_get_identity_uid (table); + + extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT; + list = e_source_registry_list_sources (registry, extension_name); + + /* Look for a mail account referencing this mail identity. + * If the mail account's backend name is "nntp", show the + * post headers. Otherwise show the mail headers. + * + * XXX What if multiple accounts use this identity but only + * one is "nntp"? Maybe it should be indicated by the + * transport somehow? + */ + for (link = list; link != NULL; link = link->next) { + ESource *source = E_SOURCE (link->data); + ESourceExtension *extension; + const gchar *backend_name; + const gchar *identity_uid; + + extension = e_source_get_extension (source, extension_name); + + backend_name = e_source_backend_get_backend_name ( + E_SOURCE_BACKEND (extension)); + identity_uid = e_source_mail_account_get_identity_uid ( + E_SOURCE_MAIL_ACCOUNT (extension)); + + if (g_strcmp0 (identity_uid, target_uid) != 0) + continue; + + if (g_strcmp0 (backend_name, "nntp") != 0) + continue; + + show_post_headers = TRUE; + break; + } + + g_list_free_full (list, (GDestroyNotify) g_object_unref); + + g_object_unref (client_cache); + g_object_unref (registry); + + return show_post_headers; +} + +static void +composer_header_table_from_changed_cb (EComposerHeaderTable *table) +{ + ESource *source = NULL; + ESource *mail_account = NULL; + EComposerHeader *header; + EComposerHeaderType type; + EComposerPostHeader *post_header; + EComposerTextHeader *text_header; + EDestination **old_destinations; + EDestination **new_destinations; + const gchar *reply_to = NULL; + const gchar * const *bcc = NULL; + const gchar * const *cc = NULL; + const gchar *uid; + + /* Keep "Post-To" and "Reply-To" synchronized with "From" */ + + uid = e_composer_header_table_get_identity_uid (table); + if (uid != NULL) + source = e_composer_header_table_ref_source (table, uid); + + /* Make sure this is really a mail identity source. */ + if (source != NULL) { + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + if (!e_source_has_extension (source, extension_name)) { + g_object_unref (source); + source = NULL; + } + } + + if (source != NULL) { + ESourceMailIdentity *mi; + ESourceMailComposition *mc; + const gchar *extension_name; + + extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY; + mi = e_source_get_extension (source, extension_name); + + extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION; + mc = e_source_get_extension (source, extension_name); + + reply_to = e_source_mail_identity_get_reply_to (mi); + bcc = e_source_mail_composition_get_bcc (mc); + cc = e_source_mail_composition_get_cc (mc); + + g_object_unref (source); + } + + type = E_COMPOSER_HEADER_POST_TO; + header = e_composer_header_table_get_header (table, type); + post_header = E_COMPOSER_POST_HEADER (header); + e_composer_post_header_set_mail_account (post_header, mail_account); + + type = E_COMPOSER_HEADER_REPLY_TO; + header = e_composer_header_table_get_header (table, type); + text_header = E_COMPOSER_TEXT_HEADER (header); + e_composer_text_header_set_text (text_header, reply_to); + + /* Update automatic CC destinations. */ + old_destinations = + e_composer_header_table_get_destinations_cc (table); + new_destinations = + composer_header_table_update_destinations ( + old_destinations, cc); + e_composer_header_table_set_destinations_cc (table, new_destinations); + e_destination_freev (old_destinations); + e_destination_freev (new_destinations); + + /* Update automatic BCC destinations. */ + old_destinations = + e_composer_header_table_get_destinations_bcc (table); + new_destinations = + composer_header_table_update_destinations ( + old_destinations, bcc); + e_composer_header_table_set_destinations_bcc (table, new_destinations); + e_destination_freev (old_destinations); + e_destination_freev (new_destinations); + + if (composer_header_table_show_post_headers (table)) + composer_header_table_setup_post_headers (table); + else + composer_header_table_setup_mail_headers (table); +} + +static void +composer_header_table_set_client_cache (EComposerHeaderTable *table, + EClientCache *client_cache) +{ + g_return_if_fail (E_IS_CLIENT_CACHE (client_cache)); + g_return_if_fail (table->priv->client_cache == NULL); + + table->priv->client_cache = g_object_ref (client_cache); +} + +static void +composer_header_table_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EDestination **destinations; + GList *list; + + switch (property_id) { + case PROP_CLIENT_CACHE: + composer_header_table_set_client_cache ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_object (value)); + return; + + case PROP_DESTINATIONS_BCC: + destinations = g_value_dup_destinations (value); + e_composer_header_table_set_destinations_bcc ( + E_COMPOSER_HEADER_TABLE (object), + destinations); + e_destination_freev (destinations); + return; + + case PROP_DESTINATIONS_CC: + destinations = g_value_dup_destinations (value); + e_composer_header_table_set_destinations_cc ( + E_COMPOSER_HEADER_TABLE (object), + destinations); + e_destination_freev (destinations); + return; + + case PROP_DESTINATIONS_TO: + destinations = g_value_dup_destinations (value); + e_composer_header_table_set_destinations_to ( + E_COMPOSER_HEADER_TABLE (object), + destinations); + e_destination_freev (destinations); + return; + + case PROP_IDENTITY_UID: + e_composer_header_table_set_identity_uid ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_string (value)); + return; + + case PROP_POST_TO: + list = g_value_dup_string_list (value); + e_composer_header_table_set_post_to_list ( + E_COMPOSER_HEADER_TABLE (object), list); + g_list_foreach (list, (GFunc) g_free, NULL); + g_list_free (list); + return; + + case PROP_REPLY_TO: + e_composer_header_table_set_reply_to ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_string (value)); + return; + + case PROP_SIGNATURE_UID: + e_composer_header_table_set_signature_uid ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_string (value)); + return; + + case PROP_SUBJECT: + e_composer_header_table_set_subject ( + E_COMPOSER_HEADER_TABLE (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +composer_header_table_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EDestination **destinations; + GList *list; + + switch (property_id) { + case PROP_CLIENT_CACHE: + g_value_take_object ( + value, + e_composer_header_table_ref_client_cache ( + E_COMPOSER_HEADER_TABLE (object))); + return; + + case PROP_DESTINATIONS_BCC: + destinations = + e_composer_header_table_get_destinations_bcc ( + E_COMPOSER_HEADER_TABLE (object)); + g_value_set_destinations (value, destinations); + e_destination_freev (destinations); + return; + + case PROP_DESTINATIONS_CC: + destinations = + e_composer_header_table_get_destinations_cc ( + E_COMPOSER_HEADER_TABLE (object)); + g_value_set_destinations (value, destinations); + e_destination_freev (destinations); + return; + + case PROP_DESTINATIONS_TO: + destinations = + e_composer_header_table_get_destinations_to ( + E_COMPOSER_HEADER_TABLE (object)); + g_value_set_destinations (value, destinations); + e_destination_freev (destinations); + return; + + case PROP_IDENTITY_UID: + g_value_set_string ( + value, + e_composer_header_table_get_identity_uid ( + E_COMPOSER_HEADER_TABLE (object))); + return; + + case PROP_POST_TO: + list = e_composer_header_table_get_post_to ( + E_COMPOSER_HEADER_TABLE (object)); + g_value_set_string_list (value, list); + g_list_foreach (list, (GFunc) g_free, NULL); + g_list_free (list); + return; + + case PROP_REPLY_TO: + g_value_set_string ( + value, + e_composer_header_table_get_reply_to ( + E_COMPOSER_HEADER_TABLE (object))); + return; + + case PROP_SIGNATURE_COMBO_BOX: + g_value_set_object ( + value, + e_composer_header_table_get_signature_combo_box ( + E_COMPOSER_HEADER_TABLE (object))); + return; + + case PROP_SIGNATURE_UID: + g_value_set_string ( + value, + e_composer_header_table_get_signature_uid ( + E_COMPOSER_HEADER_TABLE (object))); + return; + + case PROP_SUBJECT: + g_value_set_string ( + value, + e_composer_header_table_get_subject ( + E_COMPOSER_HEADER_TABLE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +composer_header_table_dispose (GObject *object) +{ + EComposerHeaderTablePrivate *priv; + gint ii; + + priv = E_COMPOSER_HEADER_TABLE_GET_PRIVATE (object); + + 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; + } + } + + if (priv->signature_combo_box != NULL) { + g_object_unref (priv->signature_combo_box); + priv->signature_combo_box = NULL; + } + + if (priv->name_selector != NULL) { + e_name_selector_cancel_loading (priv->name_selector); + g_object_unref (priv->name_selector); + priv->name_selector = NULL; + } + + if (priv->client_cache != NULL) { + g_object_unref (priv->client_cache); + priv->client_cache = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_composer_header_table_parent_class)->dispose (object); +} + +static void +composer_header_table_constructed (GObject *object) +{ + EComposerHeaderTable *table; + ENameSelector *name_selector; + EClientCache *client_cache; + ESourceRegistry *registry; + EComposerHeader *header; + GtkWidget *widget; + guint ii; + gint row_padding; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_composer_header_table_parent_class)-> + constructed (object); + + table = E_COMPOSER_HEADER_TABLE (object); + + client_cache = e_composer_header_table_ref_client_cache (table); + registry = e_client_cache_ref_registry (client_cache); + + name_selector = e_name_selector_new (client_cache); + table->priv->name_selector = name_selector; + + header = e_composer_from_header_new (registry, _("Fr_om:")); + composer_header_table_bind_header ("identity-uid", "changed", header); + g_signal_connect_swapped ( + header, "changed", G_CALLBACK ( + composer_header_table_from_changed_cb), table); + table->priv->headers[E_COMPOSER_HEADER_FROM] = header; + + header = e_composer_text_header_new_label (registry, _("_Reply-To:")); + composer_header_table_bind_header ("reply-to", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_REPLY_TO] = header; + + header = e_composer_name_header_new ( + registry, _("_To:"), name_selector); + e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_TO); + composer_header_table_bind_header ("destinations-to", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_TO] = header; + + header = e_composer_name_header_new ( + registry, _("_Cc:"), name_selector); + e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_CC); + composer_header_table_bind_header ("destinations-cc", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_CC] = header; + + header = e_composer_name_header_new ( + registry, _("_Bcc:"), name_selector); + e_composer_header_set_input_tooltip (header, HEADER_TOOLTIP_BCC); + composer_header_table_bind_header ("destinations-bcc", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_BCC] = header; + + header = e_composer_post_header_new (registry, _("_Post To:")); + composer_header_table_bind_header ("post-to", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_POST_TO] = header; + + header = e_composer_spell_header_new_label (registry, _("S_ubject:")); + composer_header_table_bind_header ("subject", "changed", header); + table->priv->headers[E_COMPOSER_HEADER_SUBJECT] = header; + + widget = e_mail_signature_combo_box_new (registry); + composer_header_table_bind_widget ("signature-uid", "changed", widget); + table->priv->signature_combo_box = g_object_ref_sink (widget); + + widget = gtk_label_new_with_mnemonic (_("Si_gnature:")); + gtk_label_set_mnemonic_widget ( + GTK_LABEL (widget), table->priv->signature_combo_box); + table->priv->signature_label = g_object_ref_sink (widget); + + /* Use "ypadding" instead of "row-spacing" because some rows may + * be invisible and we don't want spacing around them. */ + + row_padding = 3; + + for (ii = 0; ii < G_N_ELEMENTS (table->priv->headers); ii++) { + gtk_table_attach ( + GTK_TABLE (object), + table->priv->headers[ii]->title_widget, 0, 1, + ii, ii + 1, GTK_FILL, GTK_FILL, 0, row_padding); + gtk_table_attach ( + GTK_TABLE (object), + table->priv->headers[ii]->input_widget, 1, 4, + ii, ii + 1, GTK_FILL | GTK_EXPAND, 0, 0, row_padding); + } + + ii = E_COMPOSER_HEADER_FROM; + + /* Leave room in the "From" row for signature stuff. */ + gtk_container_child_set ( + GTK_CONTAINER (object), + table->priv->headers[ii]->input_widget, + "right-attach", 2, NULL); + + g_object_bind_property ( + table->priv->headers[ii]->input_widget, "visible", + table->priv->signature_label, "visible", + G_BINDING_SYNC_CREATE); + + g_object_bind_property ( + table->priv->headers[ii]->input_widget, "visible", + table->priv->signature_combo_box, "visible", + G_BINDING_SYNC_CREATE); + + /* Now add the signature stuff. */ + gtk_table_attach ( + GTK_TABLE (object), + table->priv->signature_label, + 2, 3, ii, ii + 1, 0, 0, 0, row_padding); + gtk_table_attach ( + GTK_TABLE (object), + table->priv->signature_combo_box, + 3, 4, ii, ii + 1, 0, 0, 0, row_padding); + + /* Initialize the headers. */ + composer_header_table_from_changed_cb (table); + + g_object_unref (client_cache); + g_object_unref (registry); +} + +static void +e_composer_header_table_class_init (EComposerHeaderTableClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EComposerHeaderTablePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = composer_header_table_set_property; + object_class->get_property = composer_header_table_get_property; + object_class->dispose = composer_header_table_dispose; + object_class->constructed = composer_header_table_constructed; + + /** + * EComposerHeaderTable:client-cache: + * + * Cache of shared #EClient instances. + **/ + g_object_class_install_property ( + object_class, + PROP_CLIENT_CACHE, + g_param_spec_object ( + "client-cache", + "Client Cache", + "Cache of shared EClient instances", + E_TYPE_CLIENT_CACHE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_DESTINATIONS_BCC, + g_param_spec_boxed ( + "destinations-bcc", + NULL, + NULL, + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_DESTINATIONS_CC, + g_param_spec_boxed ( + "destinations-cc", + NULL, + NULL, + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_DESTINATIONS_TO, + g_param_spec_boxed ( + "destinations-to", + NULL, + NULL, + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_IDENTITY_UID, + g_param_spec_string ( + "identity-uid", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_POST_TO, + g_param_spec_boxed ( + "post-to", + NULL, + NULL, + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_REPLY_TO, + g_param_spec_string ( + "reply-to", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE_COMBO_BOX, + g_param_spec_string ( + "signature-combo-box", + NULL, + NULL, + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE_UID, + g_param_spec_string ( + "signature-uid", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_SUBJECT, + g_param_spec_string ( + "subject", + NULL, + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void +composer_header_table_realize_cb (EComposerHeaderTable *table) +{ + g_return_if_fail (table != NULL); + g_return_if_fail (table->priv != NULL); + + g_signal_handlers_disconnect_by_func ( + table, composer_header_table_realize_cb, NULL); + + e_name_selector_load_books (table->priv->name_selector); +} + +static void +e_composer_header_table_init (EComposerHeaderTable *table) +{ + gint rows; + + table->priv = E_COMPOSER_HEADER_TABLE_GET_PRIVATE (table); + + rows = G_N_ELEMENTS (table->priv->headers); + gtk_table_resize (GTK_TABLE (table), rows, 4); + gtk_table_set_row_spacings (GTK_TABLE (table), 0); + gtk_table_set_col_spacings (GTK_TABLE (table), 6); + + /* postpone name_selector loading, do that only when really needed */ + g_signal_connect ( + table, "realize", + G_CALLBACK (composer_header_table_realize_cb), NULL); +} + +GtkWidget * +e_composer_header_table_new (EClientCache *client_cache) +{ + g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL); + + return g_object_new ( + E_TYPE_COMPOSER_HEADER_TABLE, + "client-cache", client_cache, NULL); +} + +EClientCache * +e_composer_header_table_ref_client_cache (EComposerHeaderTable *table) +{ + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + return g_object_ref (table->priv->client_cache); +} + +EComposerHeader * +e_composer_header_table_get_header (EComposerHeaderTable *table, + EComposerHeaderType type) +{ + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + g_return_val_if_fail (type < E_COMPOSER_NUM_HEADERS, NULL); + + return table->priv->headers[type]; +} + +EMailSignatureComboBox * +e_composer_header_table_get_signature_combo_box (EComposerHeaderTable *table) +{ + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + return E_MAIL_SIGNATURE_COMBO_BOX (table->priv->signature_combo_box); +} + +EDestination ** +e_composer_header_table_get_destinations (EComposerHeaderTable *table) +{ + EDestination **destinations; + EDestination **to, **cc, **bcc; + gint total, n_to, n_cc, n_bcc; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + to = e_composer_header_table_get_destinations_to (table); + for (n_to = 0; to != NULL && to[n_to] != NULL; n_to++); + + cc = e_composer_header_table_get_destinations_cc (table); + for (n_cc = 0; cc != NULL && cc[n_cc] != NULL; n_cc++); + + bcc = e_composer_header_table_get_destinations_bcc (table); + for (n_bcc = 0; bcc != NULL && bcc[n_bcc] != NULL; n_bcc++); + + total = n_to + n_cc + n_bcc; + destinations = g_new0 (EDestination *, total + 1); + + while (n_bcc > 0 && total > 0) + destinations[--total] = g_object_ref (bcc[--n_bcc]); + + while (n_cc > 0 && total > 0) + destinations[--total] = g_object_ref (cc[--n_cc]); + + while (n_to > 0 && total > 0) + destinations[--total] = g_object_ref (to[--n_to]); + + /* Counters should all be zero now. */ + g_assert (total == 0 && n_to == 0 && n_cc == 0 && n_bcc == 0); + + e_destination_freev (to); + e_destination_freev (cc); + e_destination_freev (bcc); + + return destinations; +} + +EDestination ** +e_composer_header_table_get_destinations_bcc (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_BCC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + return e_composer_name_header_get_destinations (name_header); +} + +void +e_composer_header_table_add_destinations_bcc (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_BCC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_add_destinations (name_header, destinations); + + if (destinations != NULL && *destinations != NULL) + e_composer_header_set_visible (header, TRUE); +} + +void +e_composer_header_table_set_destinations_bcc (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_BCC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_set_destinations (name_header, destinations); + + if (destinations != NULL && *destinations != NULL) + e_composer_header_set_visible (header, TRUE); +} + +EDestination ** +e_composer_header_table_get_destinations_cc (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_CC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + return e_composer_name_header_get_destinations (name_header); +} + +void +e_composer_header_table_add_destinations_cc (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_CC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_add_destinations (name_header, destinations); + + if (destinations != NULL && *destinations != NULL) + e_composer_header_set_visible (header, TRUE); +} + +void +e_composer_header_table_set_destinations_cc (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_CC; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_set_destinations (name_header, destinations); + + if (destinations != NULL && *destinations != NULL) + e_composer_header_set_visible (header, TRUE); +} + +EDestination ** +e_composer_header_table_get_destinations_to (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_TO; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + return e_composer_name_header_get_destinations (name_header); +} + +void +e_composer_header_table_add_destinations_to (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_TO; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_add_destinations (name_header, destinations); +} + +void +e_composer_header_table_set_destinations_to (EComposerHeaderTable *table, + EDestination **destinations) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerNameHeader *name_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_TO; + header = e_composer_header_table_get_header (table, type); + name_header = E_COMPOSER_NAME_HEADER (header); + + e_composer_name_header_set_destinations (name_header, destinations); +} + +const gchar * +e_composer_header_table_get_identity_uid (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerFromHeader *from_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_FROM; + header = e_composer_header_table_get_header (table, type); + from_header = E_COMPOSER_FROM_HEADER (header); + + return e_composer_from_header_get_active_id (from_header); +} + +void +e_composer_header_table_set_identity_uid (EComposerHeaderTable *table, + const gchar *identity_uid) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerFromHeader *from_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_FROM; + header = e_composer_header_table_get_header (table, type); + from_header = E_COMPOSER_FROM_HEADER (header); + + e_composer_from_header_set_active_id (from_header, identity_uid); +} + +GList * +e_composer_header_table_get_post_to (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerPostHeader *post_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_POST_TO; + header = e_composer_header_table_get_header (table, type); + post_header = E_COMPOSER_POST_HEADER (header); + + return e_composer_post_header_get_folders (post_header); +} + +void +e_composer_header_table_set_post_to_base (EComposerHeaderTable *table, + const gchar *base_url, + const gchar *folders) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerPostHeader *post_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_POST_TO; + header = e_composer_header_table_get_header (table, type); + post_header = E_COMPOSER_POST_HEADER (header); + + e_composer_post_header_set_folders_base (post_header, base_url, folders); +} + +void +e_composer_header_table_set_post_to_list (EComposerHeaderTable *table, + GList *folders) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerPostHeader *post_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_POST_TO; + header = e_composer_header_table_get_header (table, type); + post_header = E_COMPOSER_POST_HEADER (header); + + e_composer_post_header_set_folders (post_header, folders); +} + +const gchar * +e_composer_header_table_get_reply_to (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerTextHeader *text_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_REPLY_TO; + header = e_composer_header_table_get_header (table, type); + text_header = E_COMPOSER_TEXT_HEADER (header); + + return e_composer_text_header_get_text (text_header); +} + +void +e_composer_header_table_set_reply_to (EComposerHeaderTable *table, + const gchar *reply_to) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerTextHeader *text_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_REPLY_TO; + header = e_composer_header_table_get_header (table, type); + text_header = E_COMPOSER_TEXT_HEADER (header); + + e_composer_text_header_set_text (text_header, reply_to); + + if (reply_to != NULL && *reply_to != '\0') + e_composer_header_set_visible (header, TRUE); +} + +const gchar * +e_composer_header_table_get_signature_uid (EComposerHeaderTable *table) +{ + EMailSignatureComboBox *combo_box; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + combo_box = e_composer_header_table_get_signature_combo_box (table); + + return gtk_combo_box_get_active_id (GTK_COMBO_BOX (combo_box)); +} + +void +e_composer_header_table_set_signature_uid (EComposerHeaderTable *table, + const gchar *signature_uid) +{ + EMailSignatureComboBox *combo_box; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + combo_box = e_composer_header_table_get_signature_combo_box (table); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (combo_box), signature_uid); +} + +const gchar * +e_composer_header_table_get_subject (EComposerHeaderTable *table) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerTextHeader *text_header; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + + type = E_COMPOSER_HEADER_SUBJECT; + header = e_composer_header_table_get_header (table, type); + text_header = E_COMPOSER_TEXT_HEADER (header); + + return e_composer_text_header_get_text (text_header); +} + +void +e_composer_header_table_set_subject (EComposerHeaderTable *table, + const gchar *subject) +{ + EComposerHeader *header; + EComposerHeaderType type; + EComposerTextHeader *text_header; + + g_return_if_fail (E_IS_COMPOSER_HEADER_TABLE (table)); + + type = E_COMPOSER_HEADER_SUBJECT; + header = e_composer_header_table_get_header (table, type); + text_header = E_COMPOSER_TEXT_HEADER (header); + + e_composer_text_header_set_text (text_header, subject); +} + +void +e_composer_header_table_set_header_visible (EComposerHeaderTable *table, + EComposerHeaderType type, + gboolean visible) +{ + EComposerHeader *header; + + header = e_composer_header_table_get_header (table, type); + e_composer_header_set_visible (header, visible); + + /* Signature widgets track the "From" header. */ + if (type == E_COMPOSER_HEADER_FROM) { + if (visible) { + gtk_widget_show (table->priv->signature_label); + gtk_widget_show (table->priv->signature_combo_box); + } else { + gtk_widget_hide (table->priv->signature_label); + gtk_widget_hide (table->priv->signature_combo_box); + } + } +} + +/** + * e_composer_header_table_ref_source: + * @table: an #EComposerHeaderTable + * @uid: a unique identifier string + * + * Convenience function that works just like e_source_registry_ref_source(), + * but spares the caller from digging out the #ESourceRegistry from @table. + * + * The returned #ESource is referenced for thread-safety and must be + * unreferenced with g_object_unref() when finished with it. + * + * Returns: an #ESource, or %NULL if no match was found + **/ +ESource * +e_composer_header_table_ref_source (EComposerHeaderTable *table, + const gchar *uid) +{ + EClientCache *client_cache; + ESourceRegistry *registry; + ESource *source; + + g_return_val_if_fail (E_IS_COMPOSER_HEADER_TABLE (table), NULL); + g_return_val_if_fail (uid != NULL, NULL); + + client_cache = e_composer_header_table_ref_client_cache (table); + registry = e_client_cache_ref_registry (client_cache); + + source = e_source_registry_ref_source (registry, uid); + + g_object_unref (client_cache); + g_object_unref (registry); + + return source; +} + |