From f5bed9bf7b143fff9bd258ea31fdac192e00a0d9 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 27 Nov 2007 20:24:44 +0000 Subject: ** Fixes bug #495123 2007-11-27 Matthew Barnes ** Fixes bug #495123 * composer/Makefile.am: Add a bunch of files for managing composer headers. * composer/e-msg-composer.c (build_message), (from_changed_cb), (set_editor_signature), (e_msg_composer_set_body), (e_msg_composer_get_preferred_account): * plugins/exchange-operations/exchange-mail-send-options.c (append_to_header): Use e_msg_composer_hdrs_get_from_account() to obtain the EAccount. * composer/e-msg-composer-hdrs.c: * composer/e-msg-composer-hdrs.h: Massive refactoring to use new EComposerHeader classes. * composer/e-composer-header.c: * composer/e-composer-header.h: * composer/e-composer-from-header.c: * composer/e-composer-from-header.h: * composer/e-composer-name-header.c: * composer/e-composer-name-header.h: * composer/e-composer-post-header.c: * composer/e-composer-post-header.h: * composer/e-composer-text-header.c: * composer/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. * mail/mail-session.c (mail_session_init): Pass the CamelSession to the EAccountComboBox class (ugly hack). * widgets/misc/Makefile.am: Add e-account-combo-box.[ch]. * widgets/misc/e-account-combo-box.c: * widgets/misc/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. svn path=/trunk/; revision=34600 --- composer/ChangeLog | 29 + composer/Makefile.am | 11 + composer/e-composer-common.h | 10 + composer/e-composer-from-header.c | 178 +++ composer/e-composer-from-header.h | 67 + composer/e-composer-header.c | 310 +++++ composer/e-composer-header.h | 56 + composer/e-composer-name-header.c | 301 +++++ composer/e-composer-name-header.h | 58 + composer/e-composer-post-header.c | 401 ++++++ composer/e-composer-post-header.h | 63 + composer/e-composer-text-header.c | 120 ++ composer/e-composer-text-header.h | 50 + composer/e-msg-composer-hdrs.c | 1396 ++++---------------- composer/e-msg-composer-hdrs.h | 85 +- composer/e-msg-composer.c | 62 +- mail/ChangeLog | 7 + mail/mail-session.c | 1 + plugins/exchange-operations/ChangeLog | 7 + .../exchange-mail-send-options.c | 14 +- widgets/misc/ChangeLog | 12 + widgets/misc/Makefile.am | 2 + widgets/misc/e-account-combo-box.c | 413 ++++++ widgets/misc/e-account-combo-box.h | 60 + 24 files changed, 2541 insertions(+), 1172 deletions(-) create mode 100644 composer/e-composer-common.h create mode 100644 composer/e-composer-from-header.c create mode 100644 composer/e-composer-from-header.h create mode 100644 composer/e-composer-header.c create mode 100644 composer/e-composer-header.h create mode 100644 composer/e-composer-name-header.c create mode 100644 composer/e-composer-name-header.h create mode 100644 composer/e-composer-post-header.c create mode 100644 composer/e-composer-post-header.h create mode 100644 composer/e-composer-text-header.c create mode 100644 composer/e-composer-text-header.h create mode 100644 widgets/misc/e-account-combo-box.c create mode 100644 widgets/misc/e-account-combo-box.h 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 + + ** 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 ** 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 +#endif + +#include + +#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 +#include +#include + +#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 + +/* 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 +#include + +#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 +#include + +#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 + +#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 #endif -#include - #include #include -#include -#include -#include -#include #include #include -#include -#include #include "Composer.h" -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "e-util/e-error.h" -#include "e-util/e-icon-factory.h" - #include #include #include #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 +#include #include @@ -33,20 +32,28 @@ #include #include -#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 + + ** 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 ** 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 + + ** 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 ** 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 + + ** 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 ** 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 +#include + +#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 +#include +#include +#include + +/* 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 */ -- cgit v1.2.3