2007-11-27  Matthew Barnes  <mbarnes@redhat.com>

	** 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
This commit is contained in:
Matthew Barnes
2007-11-27 20:24:44 +00:00
committed by Matthew Barnes
parent 8aa60af54e
commit f5bed9bf7b
24 changed files with 2544 additions and 1175 deletions

View File

@ -1,3 +1,32 @@
2007-11-27 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #495123
* Makefile.am:
Add a bunch of files for managing composer headers.
* e-msg-composer.c (build_message), (from_changed_cb),
(set_editor_signature), (e_msg_composer_set_body),
(e_msg_composer_get_preferred_account):
Use e_msg_composer_hdrs_get_from_account() to obtain the EAccount.
* e-msg-composer-hdrs.c:
* e-msg-composer-hdrs.h:
Massive refactoring to use new EComposerHeader classes.
* e-composer-header.c:
* e-composer-header.h:
* e-composer-from-header.c:
* e-composer-from-header.h:
* e-composer-name-header.c:
* e-composer-name-header.h:
* e-composer-post-header.c:
* e-composer-post-header.h:
* e-composer-text-header.c:
* e-composer-text-header.h:
New GObject classes manage different types of composer headers.
See bug #495123 for a more detailed description of each class.
2007-11-01 Milan Crha <mcrha@redhat.com>
** Fix for bug #318592

View File

@ -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 \

View File

@ -0,0 +1,10 @@
#ifndef E_COMPOSER_COMMON
#define E_COMPOSER_COMMON
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gtk/gtk.h>
#endif /* E_COMPOSER_COMMON */

View File

@ -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;
}

View File

@ -0,0 +1,67 @@
#ifndef E_COMPOSER_FROM_HEADER_H
#define E_COMPOSER_FROM_HEADER_H
#include "e-composer-common.h"
#include <libedataserver/e-account.h>
#include <libedataserver/e-account-list.h>
#include <camel/camel-internet-address.h>
#include "e-account-combo-box.h"
#include "e-composer-header.h"
/* Standard GObject macros */
#define E_TYPE_COMPOSER_FROM_HEADER \
(e_composer_from_header_get_type ())
#define E_COMPOSER_FROM_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeader))
#define E_COMPOSER_FROM_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_CAST \
((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeaderClass))
#define E_IS_COMPOSER_FROM_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE \
((obj), E_TYPE_COMPOSER_FROM_HEADER))
#define E_IS_COMPOSER_FROM_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
((obj), E_TYPE_COMPOSER_FROM_HEADER))
#define E_COMPOSER_FROM_HEADER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_COMPOSER_FROM_HEADER, EComposerFromHeaderClass))
G_BEGIN_DECLS
typedef struct _EComposerFromHeader EComposerFromHeader;
typedef struct _EComposerFromHeaderClass EComposerFromHeaderClass;
typedef struct _EComposerFromHeaderPrivate EComposerFromHeaderPrivate;
struct _EComposerFromHeader {
EComposerHeader parent;
EComposerFromHeaderPrivate *priv;
};
struct _EComposerFromHeaderClass {
EComposerHeaderClass parent_class;
};
GType e_composer_from_header_get_type (void);
EComposerHeader * e_composer_from_header_new (const gchar *label);
void e_composer_from_header_set_account_list
(EComposerFromHeader *header,
EAccountList *account_list);
EAccount * e_composer_from_header_get_active
(EComposerFromHeader *header);
gboolean e_composer_from_header_set_active
(EComposerFromHeader *header,
EAccount *account);
const gchar * e_composer_from_header_get_active_name
(EComposerFromHeader *header);
gboolean e_composer_from_header_set_active_name
(EComposerFromHeader *header,
const gchar *account_name);
CamelInternetAddress * e_composer_from_header_get_active_address
(EComposerFromHeader *header);
G_END_DECLS
#endif /* E_COMPOSER_FROM_HEADER_H */

View File

@ -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);
}

View File

@ -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 */

View File

@ -0,0 +1,301 @@
#include "e-composer-name-header.h"
#include <glib/gi18n.h>
/* XXX Temporary kludge */
#include "addressbook/gui/contact-editor/e-contact-editor.h"
#include "addressbook/gui/contact-list-editor/e-contact-list-editor.h"
#define E_COMPOSER_NAME_HEADER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderPrivate))
enum {
PROP_0,
PROP_NAME_SELECTOR
};
struct _EComposerNameHeaderPrivate {
ENameSelector *name_selector;
guint destination_index;
};
static gpointer parent_class;
static void
composer_name_header_clicked_cb (EComposerNameHeader *header)
{
ENameSelectorDialog *dialog;
dialog = e_name_selector_peek_dialog (header->priv->name_selector);
e_name_selector_dialog_set_destination_index (
dialog, header->priv->destination_index);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_hide (GTK_WIDGET (dialog));
}
static void
composer_name_header_entry_changed_cb (ENameSelectorEntry *entry,
EComposerNameHeader *header)
{
g_signal_emit_by_name (header, "changed");
}
static gboolean
composer_name_header_entry_query_tooltip_cb (GtkEntry *entry,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip)
{
const gchar *text;
text = gtk_entry_get_text (entry);
if (keyboard_mode || text == NULL || *text == '\0')
return FALSE;
gtk_tooltip_set_text (tooltip, text);
return TRUE;
}
static GObject *
composer_name_header_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
EComposerNameHeaderPrivate *priv;
ENameSelectorModel *model;
ENameSelectorEntry *entry;
GObject *object;
gchar *label;
/* Chain up to parent's constructor() method. */
object = G_OBJECT_CLASS (parent_class)->constructor (
type, n_construct_properties, construct_properties);
priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
g_assert (E_IS_NAME_SELECTOR (priv->name_selector));
model = e_name_selector_peek_model (priv->name_selector);
label = e_composer_header_get_label (E_COMPOSER_HEADER (object));
g_assert (label != NULL);
/* XXX Peeking at private data. */
priv->destination_index = model->sections->len;
e_name_selector_model_add_section (model, label, label, NULL);
e_composer_header_set_title_tooltip (
E_COMPOSER_HEADER (object),
_("Click here for the address book"));
entry = E_NAME_SELECTOR_ENTRY (
e_name_selector_peek_section_list (
priv->name_selector, label));
e_name_selector_entry_set_contact_editor_func (
entry, e_contact_editor_new);
e_name_selector_entry_set_contact_list_editor_func (
entry, e_contact_list_editor_new);
g_signal_connect (
entry, "changed",
G_CALLBACK (composer_name_header_entry_changed_cb), object);
g_signal_connect (
entry, "query-tooltip",
G_CALLBACK (composer_name_header_entry_query_tooltip_cb),
NULL);
E_COMPOSER_HEADER (object)->input_widget = g_object_ref_sink (entry);
g_signal_connect (
object, "clicked",
G_CALLBACK (composer_name_header_clicked_cb), NULL);
return object;
}
static void
composer_name_header_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
EComposerNameHeaderPrivate *priv;
priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
switch (property_id) {
case PROP_NAME_SELECTOR: /* construct only */
g_assert (priv->name_selector == NULL);
priv->name_selector = g_value_dup_object (value);
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
composer_name_header_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_NAME_SELECTOR: /* construct only */
g_value_set_object (
value,
e_composer_name_header_get_name_selector (
E_COMPOSER_NAME_HEADER (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
composer_name_header_dispose (GObject *object)
{
EComposerNameHeaderPrivate *priv;
priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (object);
if (priv->name_selector != NULL) {
g_object_unref (priv->name_selector);
priv->name_selector = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
composer_name_header_class_init (EComposerNameHeaderClass *class)
{
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EComposerNameHeaderPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->constructor = composer_name_header_constructor;
object_class->set_property = composer_name_header_set_property;
object_class->get_property = composer_name_header_get_property;
object_class->dispose = composer_name_header_dispose;
g_object_class_install_property (
object_class,
PROP_NAME_SELECTOR,
g_param_spec_object (
"name-selector",
NULL,
NULL,
E_TYPE_NAME_SELECTOR,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
composer_name_header_init (EComposerNameHeader *header)
{
header->priv = E_COMPOSER_NAME_HEADER_GET_PRIVATE (header);
}
GType
e_composer_name_header_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
static const GTypeInfo type_info = {
sizeof (EComposerNameHeaderClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) composer_name_header_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
sizeof (EComposerNameHeader),
0, /* n_preallocs */
(GInstanceInitFunc) composer_name_header_init,
NULL /* value_table */
};
type = g_type_register_static (
E_TYPE_COMPOSER_HEADER, "EComposerNameHeader",
&type_info, 0);
}
return type;
}
EComposerHeader *
e_composer_name_header_new (const gchar *label,
ENameSelector *name_selector)
{
g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
return g_object_new (
E_TYPE_COMPOSER_NAME_HEADER, "label", label,
"button", TRUE, "name-selector", name_selector, NULL);
}
ENameSelector *
e_composer_name_header_get_name_selector (EComposerNameHeader *header)
{
g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
return header->priv->name_selector;
}
EDestination **
e_composer_name_header_get_destinations (EComposerNameHeader *header)
{
EDestinationStore *store;
EDestination **destinations;
GtkWidget *input_widget;
GList *list, *iter;
gint ii = 0;
g_return_val_if_fail (E_IS_COMPOSER_NAME_HEADER (header), NULL);
input_widget = E_COMPOSER_HEADER (header)->input_widget;
store = e_name_selector_entry_peek_destination_store (
E_NAME_SELECTOR_ENTRY (input_widget));
list = e_destination_store_list_destinations (store);
destinations = g_new0 (EDestination *, g_list_length (list) + 1);
for (iter = list; iter != NULL; iter = iter->next)
destinations[ii++] = g_object_ref (iter->data);
g_list_free (list);
return destinations;
}
void
e_composer_name_header_set_destinations (EComposerNameHeader *header,
EDestination **destinations)
{
EDestinationStore *store;
GtkWidget *input_widget;
GList *list, *iter;
gint ii;
g_return_if_fail (E_IS_COMPOSER_NAME_HEADER (header));
input_widget = E_COMPOSER_HEADER (header)->input_widget;
store = e_name_selector_entry_peek_destination_store (
E_NAME_SELECTOR_ENTRY (input_widget));
/* Clear the destination store. */
list = e_destination_store_list_destinations (store);
for (iter = list; iter != NULL; iter = iter->next)
e_destination_store_remove_destination (store, iter->data);
g_list_free (list);
if (destinations == NULL)
return;
for (ii = 0; destinations[ii] != NULL; ii++)
e_destination_store_append_destination (
store, destinations[ii]);
}

View File

@ -0,0 +1,58 @@
#ifndef E_COMPOSER_NAME_HEADER_H
#define E_COMPOSER_NAME_HEADER_H
#include "e-composer-common.h"
#include <libebook/e-destination.h>
#include <libedataserverui/e-name-selector.h>
#include "e-composer-header.h"
/* Standard GObject macros */
#define E_TYPE_COMPOSER_NAME_HEADER \
(e_composer_name_header_get_type ())
#define E_COMPOSER_NAME_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeader))
#define E_COMPOSER_NAME_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_CAST \
((cls), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderClass))
#define E_IS_COMPOSER_NAME_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE \
((obj), E_TYPE_COMPOSER_NAME_HEADER))
#define E_IS_COMPOSER_NAME_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
((cls), E_TYPE_COMPOSER_NAME_HEADER))
#define E_COMPOSER_NAME_HEADER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_COMPOSER_NAME_HEADER, EComposerNameHeaderClass))
G_BEGIN_DECLS
typedef struct _EComposerNameHeader EComposerNameHeader;
typedef struct _EComposerNameHeaderClass EComposerNameHeaderClass;
typedef struct _EComposerNameHeaderPrivate EComposerNameHeaderPrivate;
struct _EComposerNameHeader {
EComposerHeader parent;
EComposerNameHeaderPrivate *priv;
};
struct _EComposerNameHeaderClass {
EComposerHeaderClass parent_class;
};
GType e_composer_name_header_get_type (void);
EComposerHeader * e_composer_name_header_new (const gchar *label,
ENameSelector *name_selector);
ENameSelector * e_composer_name_header_get_name_selector
(EComposerNameHeader *header);
EDestination ** e_composer_name_header_get_destinations
(EComposerNameHeader *header);
void e_composer_name_header_set_destinations
(EComposerNameHeader *header,
EDestination **destinations);
G_END_DECLS
#endif /* E_COMPOSER_NAME_HEADER_H */

View File

@ -0,0 +1,401 @@
#include "e-composer-post-header.h"
#include <string.h>
#include <glib/gi18n.h>
#include "mail/em-folder-selector.h"
#include "mail/em-folder-tree.h"
#define E_COMPOSER_POST_HEADER_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderPrivate))
enum {
PROP_0,
PROP_ACCOUNT
};
struct _EComposerPostHeaderPrivate {
EAccount *account;
gchar *base_url; /* derived from account */
gboolean custom;
};
static gpointer parent_class;
/* Forward Declarations (to avoid pulling in Bonobo stuff) */
struct _MailComponent *mail_component_peek (void);
struct _EMFolderTreeModel *mail_component_peek_tree_model (struct _MailComponent *component);
static gchar *
composer_post_header_folder_name_to_string (EComposerPostHeader *header,
const gchar *url)
{
const gchar *base_url = header->priv->base_url;
if (base_url != NULL) {
gsize length = strlen (base_url);
if (g_ascii_strncasecmp (url, base_url, length) == 0)
return g_strdup (url + length);
}
return g_strdup (url);
}
static void
composer_post_header_set_base_url (EComposerPostHeader *header)
{
EAccount *account = header->priv->account;
CamelURL *camel_url;
gchar *url;
if (account == NULL || account->source == NULL)
return;
url = account->source->url;
if (url == NULL || *url == '\0')
return;
camel_url = camel_url_new (url, NULL);
if (camel_url == NULL)
return;
url = camel_url_to_string (camel_url, CAMEL_URL_HIDE_ALL);
camel_url_free (camel_url);
header->priv->base_url = url;
}
static GList *
composer_post_header_split_csv (const gchar *csv)
{
GList *list = NULL;
gchar **strv;
guint length, ii;
strv = g_strsplit (csv, ",", 0);
length = g_strv_length (strv);
for (ii = 0; ii < length; ii++)
if (*g_strstrip (strv[ii]) != '\0')
list = g_list_prepend (list, g_strdup (strv[ii]));
g_strfreev (strv);
return g_list_reverse (list);
}
static void
composer_post_header_changed_cb (EComposerPostHeader *header)
{
header->priv->custom = TRUE;
}
static void
composer_post_header_clicked_cb (EComposerPostHeader *header)
{
EMFolderTreeModel *model;
GtkWidget *folder_tree;
GtkWidget *dialog;
GList *list;
model = mail_component_peek_tree_model (mail_component_peek ());
folder_tree = em_folder_tree_new_with_model (model);
em_folder_tree_set_multiselect (
EM_FOLDER_TREE (folder_tree), TRUE);
em_folder_tree_set_excluded (
EM_FOLDER_TREE (folder_tree),
EMFT_EXCLUDE_NOSELECT |
EMFT_EXCLUDE_VIRTUAL |
EMFT_EXCLUDE_VTRASH);
dialog = em_folder_selector_new (
EM_FOLDER_TREE (folder_tree),
EM_FOLDER_SELECTOR_CAN_CREATE,
_("Posting destination"),
_("Choose folders to post the message to."),
NULL);
list = e_composer_post_header_get_folders (header);
em_folder_selector_set_selected_list (
EM_FOLDER_SELECTOR (dialog), list);
g_list_foreach (list, (GFunc) g_free, NULL);
g_list_free (list);
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
list = em_folder_selector_get_selected_uris (
EM_FOLDER_SELECTOR (dialog));
e_composer_post_header_set_folders (header, list);
header->priv->custom = FALSE;
g_list_foreach (list, (GFunc) g_free, NULL);
g_list_free (list);
}
gtk_widget_destroy (dialog);
}
static GObject *
composer_post_header_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
/* Chain up to parent's constructor() method. */
object = G_OBJECT_CLASS (parent_class)->constructor (
type, n_construct_properties, construct_properties);
e_composer_header_set_title_tooltip (
E_COMPOSER_HEADER (object),
_("Click here to select folders to post to"));
g_signal_connect (
object, "changed",
G_CALLBACK (composer_post_header_changed_cb), NULL);
g_signal_connect (
object, "clicked",
G_CALLBACK (composer_post_header_clicked_cb), NULL);
return object;
}
static void
composer_post_header_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_ACCOUNT:
e_composer_post_header_set_account (
E_COMPOSER_POST_HEADER (object),
g_value_get_object (value));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
composer_post_header_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
switch (property_id) {
case PROP_ACCOUNT:
g_value_set_object (
value, e_composer_post_header_get_account (
E_COMPOSER_POST_HEADER (object)));
return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static void
composer_post_header_dispose (GObject *object)
{
EComposerPostHeaderPrivate *priv;
priv = E_COMPOSER_POST_HEADER_GET_PRIVATE (object);
if (priv->account != NULL) {
g_object_unref (priv->account);
priv->account = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
composer_post_header_class_init (EComposerPostHeaderClass *class)
{
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EComposerPostHeaderPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->constructor = composer_post_header_constructor;
object_class->set_property = composer_post_header_set_property;
object_class->get_property = composer_post_header_get_property;
object_class->dispose = composer_post_header_dispose;
g_object_class_install_property (
object_class,
PROP_ACCOUNT,
g_param_spec_object (
"account",
NULL,
NULL,
E_TYPE_ACCOUNT,
G_PARAM_READWRITE));
}
static void
composer_post_header_init (EComposerPostHeader *header)
{
header->priv = E_COMPOSER_POST_HEADER_GET_PRIVATE (header);
}
GType
e_composer_post_header_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
static const GTypeInfo type_info = {
sizeof (EComposerPostHeaderClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) composer_post_header_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
sizeof (EComposerPostHeader),
0, /* n_preallocs */
(GInstanceInitFunc) composer_post_header_init,
NULL /* value_table */
};
type = g_type_register_static (
E_TYPE_COMPOSER_TEXT_HEADER,
"EComposerPostHeader", &type_info, 0);
}
return type;
}
EComposerHeader *
e_composer_post_header_new (const gchar *label)
{
return g_object_new (
E_TYPE_COMPOSER_POST_HEADER,
"label", label, "button", TRUE, NULL);
}
EAccount *
e_composer_post_header_get_account (EComposerPostHeader *header)
{
g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL);
return header->priv->account;
}
void
e_composer_post_header_set_account (EComposerPostHeader *header,
EAccount *account)
{
GList *folders = NULL;
g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header));
if (account != NULL) {
g_return_if_fail (E_IS_ACCOUNT (account));
g_object_ref (account);
}
if (!header->priv->custom)
folders = e_composer_post_header_get_folders (header);
if (header->priv->account != NULL)
g_object_unref (header->priv->account);
header->priv->account = account;
composer_post_header_set_base_url (header);
/* Make folders relative to the new account. */
if (!header->priv->custom) {
e_composer_post_header_set_folders (header, folders);
g_list_foreach (folders, (GFunc) g_free, NULL);
g_list_free (folders);
}
g_object_notify (G_OBJECT (header), "account");
}
GList *
e_composer_post_header_get_folders (EComposerPostHeader *header)
{
GList *folders, *iter;
gchar *base_url;
g_return_val_if_fail (E_IS_COMPOSER_POST_HEADER (header), NULL);
folders = composer_post_header_split_csv (
e_composer_text_header_get_text (
E_COMPOSER_TEXT_HEADER (header)));
base_url = header->priv->base_url;
if (base_url == NULL)
return folders;
for (iter = folders; iter != NULL; iter = iter->next) {
/* Convert relative folder names to absolute. */
/* XXX Should use CamelURL for this. */
if (strstr (iter->data, ":/") == NULL) {
gchar *abs_url;
abs_url = g_strconcat (base_url, iter->data, NULL);
g_free (iter->data);
iter->data = abs_url;
}
}
return folders;
}
void
e_composer_post_header_set_folders (EComposerPostHeader *header,
GList *folders)
{
GList *iter;
gint ii = 0;
gchar **strv;
gchar *text;
gboolean custom_save;
g_return_if_fail (E_IS_COMPOSER_POST_HEADER (header));
strv = g_new0 (gchar *, g_list_length (folders) + 1);
for (iter = folders; iter != NULL; iter = iter->next)
strv[ii++] = composer_post_header_folder_name_to_string (
header, iter->data);
text = g_strjoinv (", ", strv);
custom_save = header->priv->custom;
e_composer_text_header_set_text (
E_COMPOSER_TEXT_HEADER (header), text);
header->priv->custom = custom_save;
g_free (text);
g_strfreev (strv);
}
void
e_composer_post_header_set_folders_base (EComposerPostHeader *header,
const gchar *base_url,
const gchar *folders)
{
GList *list, *iter;
list = composer_post_header_split_csv (folders);
for (iter = list; iter != NULL; iter = iter->next) {
gchar *abs_url;
/* FIXME This doesn't handle all folder names properly. */
abs_url = g_strdup_printf (
"%s/%s", base_url, (gchar *) iter->data);
g_free (iter->data);
iter->data = abs_url;
}
e_composer_post_header_set_folders (header, list);
g_list_foreach (list, (GFunc) g_free, NULL);
g_list_free (list);
}

View File

@ -0,0 +1,63 @@
#ifndef E_COMPOSER_POST_HEADER_H
#define E_COMPOSER_POST_HEADER_H
#include "e-composer-common.h"
#include <libedataserver/e-account.h>
#include "e-composer-text-header.h"
/* Standard GObject macros */
#define E_TYPE_COMPOSER_POST_HEADER \
(e_composer_post_header_get_type ())
#define E_COMPOSER_POST_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeader))
#define E_COMPOSER_POST_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_CAST \
((cls), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderClass))
#define E_IS_COMPOSER_POST_HEADER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE \
((obj), E_TYPE_COMPOSER_POST_HEADER))
#define E_IS_COMPOSER_POST_HEADER_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
((cls), E_TYPE_COMPOSER_POST_HEADER))
#define E_COMPOSER_POST_HEADER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_COMPOSER_POST_HEADER, EComposerPostHeaderClass))
G_BEGIN_DECLS
typedef struct _EComposerPostHeader EComposerPostHeader;
typedef struct _EComposerPostHeaderClass EComposerPostHeaderClass;
typedef struct _EComposerPostHeaderPrivate EComposerPostHeaderPrivate;
struct _EComposerPostHeader {
EComposerTextHeader parent;
EComposerPostHeaderPrivate *priv;
};
struct _EComposerPostHeaderClass {
EComposerTextHeaderClass parent_class;
};
GType e_composer_post_header_get_type (void);
EComposerHeader * e_composer_post_header_new (const gchar *label);
EAccount * e_composer_post_header_get_account
(EComposerPostHeader *header);
void e_composer_post_header_set_account
(EComposerPostHeader *header,
EAccount *account);
GList * e_composer_post_header_get_folders
(EComposerPostHeader *header);
void e_composer_post_header_set_folders
(EComposerPostHeader *header,
GList *folders);
void e_composer_post_header_set_folders_base
(EComposerPostHeader *header,
const gchar *base_url,
const gchar *folders);
G_END_DECLS
#endif /* E_COMPOSER_POST_HEADER_H */

View File

@ -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);
}

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,10 @@
* Author: Ettore Perazzoli
*/
#ifndef ___E_MSG_COMPOSER_HDRS_H__
#define ___E_MSG_COMPOSER_HDRS_H__
#include <gtk/gtktable.h>
#include <gtk/gtk.h>
#include <bonobo/bonobo-ui-component.h>
@ -33,20 +32,28 @@
#include <camel/camel-mime-message.h>
#include <libebook/e-destination.h>
#ifdef __cplusplus
extern "C" {
#pragma }
#endif /* __cplusplus */
#define E_TYPE_MSG_COMPOSER_HDRS \
(e_msg_composer_hdrs_get_type ())
#define E_MSG_COMPOSER_HDRS(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_MSG_COMPOSER_HDRS, EMsgComposerHdrs))
#define E_MSG_COMPOSER_HDRS_CLASS(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))
#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))
G_BEGIN_DECLS
typedef struct _EMsgComposerHdrs EMsgComposerHdrs;
typedef struct _EMsgComposerHdrsClass EMsgComposerHdrsClass;
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_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_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)
GtkType e_msg_composer_hdrs_get_type (void);
#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)
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__ */

View File

@ -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;
g_return_if_fail (E_MSG_COMPOSER_HDRS (p->hdrs)->account != NULL);
account = e_msg_composer_hdrs_get_from_account (
E_MSG_COMPOSER_HDRS (p->hdrs));
id = E_MSG_COMPOSER_HDRS (p->hdrs)->account->id;
g_return_if_fail (account != NULL);
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);
}

View File

@ -1,3 +1,10 @@
2007-11-27 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #495123
* mail-session.c (mail_session_init):
Pass the CamelSession to the EAccountComboBox class (ugly hack).
2007-11-26 Nicholas Miell <nmiell@gmail.com>
** Fix for bug #216485

View File

@ -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);

View File

@ -1,3 +1,10 @@
2007-11-27 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #495123
* exchange-mail-send-options.c (append_to_header):
Use e_msg_composer_hdrs_get_from_account() to obtain the EAccount.
2007-11-23 Milan Crha <mcrha@redhat.com>
** Fix for bug #479081

View File

@ -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);
}

View File

@ -1,3 +1,15 @@
2007-11-27 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #495123
* Makefile.am:
Add e-account-combo-box.[ch].
* e-account-combo-box.c:
* e-account-combo-box.h:
New widget renders an EAccountList as a combo box. Also listens
for changes to the EAccountList and updates itself accordingly.
2007-11-05 Milan Crha <mcrha@redhat.com>
** Fix for bug #231166

View File

@ -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 \

View File

@ -0,0 +1,413 @@
#include "e-account-combo-box.h"
#include <string.h>
#include <camel/camel-store.h>
#define E_ACCOUNT_COMBO_BOX_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxPrivate))
enum {
COLUMN_STRING,
COLUMN_ACCOUNT
};
struct _EAccountComboBoxPrivate {
EAccountList *account_list;
};
static gpointer parent_class;
static CamelSession *camel_session;
static gboolean
account_combo_box_has_dupes (GList *list,
const gchar *address)
{
GList *iter;
guint count = 0;
/* Look for duplicates of the given email address. */
for (iter = list; iter != NULL; iter = iter->next) {
EAccount *account = iter->data;
if (strcmp (account->id->address, address) == 0)
count++;
}
return (count > 1);
}
static gboolean
account_combo_box_test_account (EAccount *account)
{
CamelStore *store;
CamelException ex;
const gchar *url;
gboolean writable = FALSE;
/* Account must be enabled. */
if (!account->enabled)
return FALSE;
/* Account must have a non-empty email address. */
if (account->id->address == NULL || *account->id->address == '\0')
return FALSE;
/* XXX Not sure I understand this part. */
if (account->parent_uid == NULL)
return TRUE;
/* Account must be writable. */
camel_exception_init (&ex);
url = e_account_get_string (account, E_ACCOUNT_SOURCE_URL);
store = CAMEL_STORE (camel_session_get_service (
camel_session, url, CAMEL_PROVIDER_STORE, &ex));
if (store != NULL) {
writable = (store->mode & CAMEL_STORE_WRITE);
camel_object_unref (store);
}
camel_exception_clear (&ex);
return writable;
}
static void
account_combo_box_refresh_cb (EAccountList *account_list,
EAccount *unused,
EAccountComboBox *combo_box)
{
GtkListStore *store;
GtkTreeModel *model;
EIterator *account_iter;
EAccount *account;
GHashTable *index;
GList *list = NULL;
GList *iter;
store = gtk_list_store_new (2, G_TYPE_STRING, E_TYPE_ACCOUNT);
model = GTK_TREE_MODEL (store);
/* Embed a reverse-lookup index into the list store. */
index = g_hash_table_new_full (
g_direct_hash, g_direct_equal,
(GDestroyNotify) g_object_unref,
(GDestroyNotify) gtk_tree_row_reference_free);
g_object_set_data_full (
G_OBJECT (combo_box), "index", index,
(GDestroyNotify) g_hash_table_destroy);
if (account_list == NULL)
goto skip;
/* Build a list of EAccounts to display. */
account_iter = e_list_get_iterator (E_LIST (account_list));
while (e_iterator_is_valid (account_iter)) {
EAccount *account;
/* XXX EIterator misuses const. */
account = (EAccount *) e_iterator_get (account_iter);
if (account_combo_box_test_account (account))
list = g_list_prepend (list, account);
e_iterator_next (account_iter);
}
g_object_unref (account_iter);
list = g_list_reverse (list);
/* Populate the list store and index. */
for (iter = list; iter != NULL; iter = iter->next) {
GtkTreeRowReference *reference;
GtkTreeIter tree_iter;
GtkTreePath *path;
gchar *string;
account = iter->data;
/* Show the account name for duplicate email addresses. */
if (account_combo_box_has_dupes (list, account->id->address))
string = g_strdup_printf (
"%s <%s> (%s)",
account->id->name,
account->id->address,
account->name);
else
string = g_strdup_printf (
"%s <%s>",
account->id->name,
account->id->address);
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (
store, &tree_iter,
COLUMN_STRING, string,
COLUMN_ACCOUNT, account, -1);
path = gtk_tree_model_get_path (model, &tree_iter);
reference = gtk_tree_row_reference_new (model, path);
g_hash_table_insert (index, account, reference);
gtk_tree_path_free (path);
g_free (string);
}
g_list_free (list);
skip:
/* Restore the previously selected account. */
account = e_account_combo_box_get_active (combo_box);
gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), model);
e_account_combo_box_set_active (combo_box, account);
}
static GObject *
account_combo_box_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *object;
GtkCellRenderer *renderer;
/* Chain up to parent's constructor() method. */
object = G_OBJECT_CLASS (parent_class)->constructor (
type, n_construct_properties, construct_properties);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (
GTK_CELL_LAYOUT (object), renderer, TRUE);
gtk_cell_layout_add_attribute (
GTK_CELL_LAYOUT (object), renderer, "text", COLUMN_STRING);
return object;
}
static void
account_combo_box_dispose (GObject *object)
{
EAccountComboBoxPrivate *priv;
priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (object);
if (priv->account_list != NULL) {
g_signal_handlers_disconnect_by_func (
priv->account_list,
account_combo_box_refresh_cb, object);
g_object_unref (priv->account_list);
priv->account_list = NULL;
}
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
account_combo_box_class_init (EAccountComboBoxClass *class)
{
GObjectClass *object_class;
parent_class = g_type_class_peek_parent (class);
g_type_class_add_private (class, sizeof (EAccountComboBoxPrivate));
object_class = G_OBJECT_CLASS (class);
object_class->constructor = account_combo_box_constructor;
object_class->dispose = account_combo_box_dispose;
}
static void
account_combo_box_init (EAccountComboBox *combo_box)
{
combo_box->priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
}
GType
e_account_combo_box_get_type (void)
{
static GType type = 0;
if (G_UNLIKELY (type == 0)) {
static const GTypeInfo type_info = {
sizeof (EAccountComboBoxClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) account_combo_box_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
sizeof (EAccountComboBox),
0, /* n_preallocs */
(GInstanceInitFunc) account_combo_box_init,
NULL /* value_table */
};
type = g_type_register_static (
GTK_TYPE_COMBO_BOX, "EAccountComboBox", &type_info, 0);
}
return type;
}
GtkWidget *
e_account_combo_box_new (void)
{
return g_object_new (E_TYPE_ACCOUNT_COMBO_BOX, NULL);
}
void
e_account_combo_box_set_session (CamelSession *session)
{
/* XXX Really gross hack.
*
* We need a CamelSession to test whether a given EAccount is
* writable. The global CamelSession object is defined in the
* mailer, but we're too far down the stack to access it. So
* we have to rely on someone passing us a reference to it.
*
* A much cleaner solution would be to store the writeability
* of an account directly into the EAccount, but this would likely
* require breaking ABI and all the fun that goes along with that.
*/
camel_session = session;
}
void
e_account_combo_box_set_account_list (EAccountComboBox *combo_box,
EAccountList *account_list)
{
EAccountComboBoxPrivate *priv;
g_return_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box));
if (account_list != NULL)
g_return_if_fail (E_IS_ACCOUNT_LIST (account_list));
priv = E_ACCOUNT_COMBO_BOX_GET_PRIVATE (combo_box);
if (priv->account_list != NULL) {
g_signal_handlers_disconnect_by_func (
priv->account_list,
account_combo_box_refresh_cb, combo_box);
g_object_unref (priv->account_list);
priv->account_list = NULL;
}
if (account_list != NULL) {
priv->account_list = g_object_ref (account_list);
/* Listen for changes to the account list. */
g_signal_connect (
priv->account_list, "account-added",
G_CALLBACK (account_combo_box_refresh_cb), combo_box);
g_signal_connect (
priv->account_list, "account-changed",
G_CALLBACK (account_combo_box_refresh_cb), combo_box);
g_signal_connect (
priv->account_list, "account-removed",
G_CALLBACK (account_combo_box_refresh_cb), combo_box);
}
account_combo_box_refresh_cb (account_list, NULL, combo_box);
}
EAccount *
e_account_combo_box_get_active (EAccountComboBox *combo_box)
{
EAccount *account;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean iter_set;
g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
iter_set = gtk_combo_box_get_active_iter (
GTK_COMBO_BOX (combo_box), &iter);
if (!iter_set)
return NULL;
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
gtk_tree_model_get (model, &iter, COLUMN_ACCOUNT, &account, -1);
return account;
}
gboolean
e_account_combo_box_set_active (EAccountComboBox *combo_box,
EAccount *account)
{
GHashTable *index;
EAccountList *account_list;
GtkTreeRowReference *reference;
GtkTreeModel *model;
GtkTreePath *path;
GtkTreeIter iter;
gboolean iter_set;
g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
if (account != NULL)
g_return_val_if_fail (E_IS_ACCOUNT (account), FALSE);
account_list = combo_box->priv->account_list;
g_return_val_if_fail (account_list != NULL, FALSE);
/* Failure here indicates a programming error. */
index = g_object_get_data (G_OBJECT (combo_box), "index");
g_assert (index != NULL);
/* NULL means select the default account. */
/* XXX EAccountList misuses const. */
if (account == NULL)
account = (EAccount *)
e_account_list_get_default (account_list);
/* Lookup the tree row reference for the account. */
reference = g_hash_table_lookup (index, account);
if (reference == NULL)
return FALSE;
/* Convert the reference to a tree iterator. */
path = gtk_tree_row_reference_get_path (reference);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
iter_set = gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_path_free (path);
if (!iter_set)
return FALSE;
/* Activate the corresponding combo box item. */
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
return TRUE;
}
const gchar *
e_account_combo_box_get_active_name (EAccountComboBox *combo_box)
{
EAccount *account;
g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), NULL);
account = e_account_combo_box_get_active (combo_box);
return (account != NULL) ? account->name : NULL;
}
gboolean
e_account_combo_box_set_active_name (EAccountComboBox *combo_box,
const gchar *account_name)
{
EAccountList *account_list;
EAccount *account;
g_return_val_if_fail (E_IS_ACCOUNT_COMBO_BOX (combo_box), FALSE);
account_list = combo_box->priv->account_list;
g_return_val_if_fail (account_list != NULL, FALSE);
/* XXX EAccountList misuses const. */
account = (EAccount *) e_account_list_find (
account_list, E_ACCOUNT_FIND_NAME, account_name);
if (account == NULL)
return FALSE;
return e_account_combo_box_set_active (combo_box, account);
}

View File

@ -0,0 +1,60 @@
#ifndef E_ACCOUNT_COMBO_BOX_H
#define E_ACCOUNT_COMBO_BOX_H
#include <gtk/gtk.h>
#include <camel/camel-session.h>
#include <libedataserver/e-account.h>
#include <libedataserver/e-account-list.h>
/* Standard GObject macros */
#define E_TYPE_ACCOUNT_COMBO_BOX \
(e_account_combo_box_get_type ())
#define E_ACCOUNT_COMBO_BOX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST \
((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBox))
#define E_ACCOUNT_COMBO_BOX_CLASS(cls) \
(G_TYPE_CHECK_CLASS_CAST \
((cls), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
#define E_IS_ACCOUNT_COMBO_BOX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE \
((obj), E_TYPE_ACCOUNT_COMBO_BOX))
#define E_IS_ACCOUNT_COMBO_BOX_CLASS(cls) \
(G_TYPE_CHECK_CLASS_TYPE \
((cls), E_TYPE_ACCOUNT_COMBO_BOX))
#define E_ACCOUNT_COMBO_BOX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS \
((obj), E_TYPE_ACCOUNT_COMBO_BOX, EAccountComboBoxClass))
G_BEGIN_DECLS
typedef struct _EAccountComboBox EAccountComboBox;
typedef struct _EAccountComboBoxClass EAccountComboBoxClass;
typedef struct _EAccountComboBoxPrivate EAccountComboBoxPrivate;
struct _EAccountComboBox {
GtkComboBox parent;
EAccountComboBoxPrivate *priv;
};
struct _EAccountComboBoxClass {
GtkComboBoxClass parent_class;
};
GType e_account_combo_box_get_type (void);
GtkWidget * e_account_combo_box_new (void);
void e_account_combo_box_set_session (CamelSession *session);
void e_account_combo_box_set_account_list
(EAccountComboBox *combo_box,
EAccountList *account_list);
EAccount * e_account_combo_box_get_active (EAccountComboBox *combo_box);
gboolean e_account_combo_box_set_active (EAccountComboBox *combo_box,
EAccount *account);
const gchar * e_account_combo_box_get_active_name
(EAccountComboBox *combo_box);
gboolean e_account_combo_box_set_active_name
(EAccountComboBox *combo_box,
const gchar *account_name);
G_END_DECLS
#endif /* E_ACCOUNT_COMBO_BOX_H */