[evolution-patches] Another crack at custom headers



Ok, I've tried to merge in as much of dobey and NotZed's feedback as 
possible. This new patch:
 * uses XML in gconf to store settings, avoiding the two gconf keys
   problem of the last patch
 * has a revamped user interface with much better feedback. The new 
   header is typed into the edit field at the top; the Add button is 
   active only if the entered header is valid and unique.
   the check box now selects whether or not the custom header is 
   displayed in the view
 * correctly refreshes the mail view when apply is pressed
 * keyboard shortcuts should be correct, and the UI should be more 
   HIG compliant
 * actually attempted to write a complete changelog

Screenshot of the configuration interface:
http://grahame.angrygoats.net/images/custom-mail-headers2.png

Screenshot of the resulting email display:
http://grahame.angrygoats.net/images/custom-mail-headers-view2.png

Patch is attached. It should be pretty clean, and I don't think 
it leaks memory or does anything hideous.

dobey was saying on IRC that he'd like this to go into the View 
menu somewhere, so that arbitrary custom views can be defined. 
I'm really not sure where to start with that, but I can give it 
a try. It'd be nice to commit this and then look for a generic 
solution - what do people think? I'm a bit scared of bonoboui :)

Cheers
Grahame

Index: mail/em-folder-view.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-folder-view.c,v
retrieving revision 1.14
diff -u -r1.14 em-folder-view.c
--- mail/em-folder-view.c	14 Nov 2003 16:20:17 -0000	1.14
+++ mail/em-folder-view.c	28 Nov 2003 18:57:32 -0000
@@ -62,6 +62,7 @@
 #include "em-format-html-print.h"
 #include "em-folder-selection.h"
 #include "em-folder-view.h"
+#include "em-mailer-prefs.h"
 #include "em-message-browser.h"
 #include "message-list.h"
 #include "em-utils.h"
@@ -1896,6 +1897,7 @@
 	EMFV_MARK_SEEN_TIMEOUT,
 	EMFV_LOAD_HTTP,
 	EMFV_XMAILER_MASK,
+	EMFV_HEADERS,
 	EMFV_SETTINGS		/* last, for loop count */
 };
 
@@ -1911,6 +1913,7 @@
 	"mark_seen_timeout",
 	"load_http_images",
 	"xmailer_mask",
+	"headers",
 };
 
 static GHashTable *emfv_setting_key;
@@ -1974,6 +1977,36 @@
 	case EMFV_XMAILER_MASK:
 		em_format_html_set_xmailer_mask((EMFormatHTML *)emfv->preview, gconf_value_get_int(gconf_entry_get_value(entry)));
 		break;
+	case EMFV_HEADERS: {
+		GSList *header_config_list, *p;
+		EMFormat *emf = (EMFormat *)emfv->preview;
+		header_config_list = gconf_client_get_list (gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, NULL);
+      		em_format_clear_headers((EMFormat *)emfv->preview);
+		em_format_default_headers((EMFormat *)emfv->preview);
+		p = header_config_list;
+		while (p) {
+			struct EMMailerCustomHeader h;
+			gchar *xml = (gchar *)p->data;
+			gint header_flags = 0;
+
+			em_mailer_custom_header_from_xml(&h, xml);
+			if (h.name) {
+				if (h.flags & EM_MAILER_PREFS_FLAGS_ENABLED) {
+					if (h.flags & EM_MAILER_PREFS_FLAGS_BOLD) {
+						header_flags |= EM_FORMAT_HEADER_BOLD;
+					}
+					em_format_add_header(emf, h.name, header_flags);
+				}
+			}
+			p = g_slist_next(p);
+		}
+		g_slist_foreach (header_config_list, (GFunc) g_free, NULL);
+		g_slist_free(header_config_list);
+		/* force a redraw */
+		if (emf->message) {
+			em_format_format_clone(emf, emf->message, emf);
+		}
+		break; }
 	}
 }
 
Index: mail/em-mailer-prefs.c
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.c,v
retrieving revision 1.1
diff -u -r1.1 em-mailer-prefs.c
--- mail/em-mailer-prefs.c	24 Oct 2003 19:31:22 -0000	1.1
+++ mail/em-mailer-prefs.c	28 Nov 2003 18:57:34 -0000
@@ -31,18 +31,26 @@
 
 #include <gal/util/e-iconv.h>
 #include <gtkhtml/gtkhtml-properties.h>
+#include <libxml/tree.h>
 #include "widgets/misc/e-charset-picker.h"
 #include <bonobo/bonobo-generic-factory.h>
 
 #include "mail-config.h"
 
 
-static void em_mailer_prefs_class_init (EMMailerPrefsClass *class);
-static void em_mailer_prefs_init       (EMMailerPrefs *dialog);
-static void em_mailer_prefs_finalise   (GObject *obj);
+static void em_mailer_prefs_class_init       (EMMailerPrefsClass *class);
+static void em_mailer_prefs_init             (EMMailerPrefs *dialog);
+static void em_mailer_prefs_finalise         (GObject *obj);
+static gchar *em_mailer_custom_header_to_xml (struct EMMailerCustomHeader *h);
 
 static GtkVBoxClass *parent_class = NULL;
 
+enum {
+	HEADER_LIST_NAME_COLUMN, 
+	HEADER_LIST_ENABLED_COLUMN,
+	HEADER_LIST_N_COLUMNS
+};
+
 
 GtkType
 em_mailer_prefs_get_type (void)
@@ -203,6 +211,122 @@
 }
 
 static void
+header_list_enabled_toggled (GtkCellRendererToggle *cell, const char *path_string, gpointer user_data)
+{
+	EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+	GtkTreeModel *model = GTK_TREE_MODEL(prefs->header_list_store);
+	GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+	GtkTreeIter iter;
+	gint enabled;
+
+	gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_model_get (model, &iter, HEADER_LIST_ENABLED_COLUMN, &enabled, -1);
+	enabled = !enabled;
+	gtk_list_store_set(GTK_LIST_STORE(model), &iter, HEADER_LIST_ENABLED_COLUMN,
+			   enabled, -1);
+	gtk_tree_path_free(path);
+
+	if (prefs->control)
+		evolution_config_control_changed (prefs->control);
+}
+
+static void
+add_header (GtkWidget *widget, gpointer user_data)
+{
+	EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+	GtkTreeModel *model = GTK_TREE_MODEL(prefs->header_list_store);
+	GtkTreeIter iter;
+
+	gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+	gtk_list_store_set(GTK_LIST_STORE(model), &iter, 
+			   HEADER_LIST_NAME_COLUMN, g_strdup(gtk_entry_get_text(prefs->entry_header)), 
+			   HEADER_LIST_ENABLED_COLUMN, TRUE, 
+			   -1);
+	if (!GTK_WIDGET_SENSITIVE(GTK_WIDGET(prefs->remove_header))) {
+		GtkTreeSelection *selection = gtk_tree_view_get_selection (prefs->header_list);
+		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter);
+		gtk_widget_set_sensitive(GTK_WIDGET(prefs->remove_header), TRUE);
+		gtk_tree_selection_select_iter(selection, &iter);
+	}
+	/* now clear out the text entry, and make the add button insensitive */
+	gtk_entry_set_text(prefs->entry_header, "");
+	gtk_widget_set_sensitive(GTK_WIDGET(prefs->add_header), FALSE);
+	if (prefs->control)
+		evolution_config_control_changed (prefs->control);
+}
+
+static void
+remove_header (GtkWidget *button, gpointer user_data)
+{
+	EMMailerPrefs *prefs = (EMMailerPrefs *) user_data;
+	GtkTreeView *treeview = prefs->header_list;
+	GtkTreeModel *model = GTK_TREE_MODEL(prefs->header_list_store);
+	GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
+	GtkTreeIter iter;
+	
+	if (gtk_tree_selection_get_selected (selection, NULL, &iter)) {
+		gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+		if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) {
+			/* list is empty - disable the remove button*/
+			gtk_widget_set_sensitive(GTK_WIDGET(prefs->remove_header), FALSE);
+		} else {
+			/* select the first entry */
+			gtk_tree_selection_select_iter(selection, &iter);
+		}
+		if (prefs->control)
+			evolution_config_control_changed (prefs->control);
+	}
+}
+
+static gboolean
+is_valid_header(const gchar *header)
+{
+	const gchar *p = header;
+
+	if (strlen(header) == 0) {
+		return FALSE;
+	}
+	while (*p) {
+		if ((*p == ':') || (*p == ' ')) {
+			return FALSE;
+		}
+		p++;
+	}
+	return TRUE;
+}
+
+static void
+entry_header_changed (GtkWidget *entry, gpointer user_data)
+{
+	EMMailerPrefs *prefs = (EMMailerPrefs *)user_data;
+	const gchar *entry_contents;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	entry_contents = gtk_entry_get_text(GTK_ENTRY(entry));
+	if (!is_valid_header (entry_contents)) {
+		gtk_widget_set_sensitive(GTK_WIDGET(prefs->add_header), FALSE);
+		return;
+	}
+	/* check if this is a duplicate */
+	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs->header_list_store), &iter);
+	while (valid) {
+		gchar *header_name;
+		gtk_tree_model_get (GTK_TREE_MODEL(prefs->header_list_store), &iter, 
+				    HEADER_LIST_NAME_COLUMN, &header_name, 
+				    -1);
+		if (!strcasecmp(header_name, entry_contents)) {
+			/* duplicate, not valid */
+			gtk_widget_set_sensitive (GTK_WIDGET(prefs->add_header), FALSE);
+			return;
+		}
+		valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(prefs->header_list_store), &iter);
+	}
+	/* if we got here, we are valid and unique */
+	gtk_widget_set_sensitive (GTK_WIDGET(prefs->add_header), TRUE);
+}
+
+static void
 em_mailer_prefs_construct (EMMailerPrefs *prefs)
 {
 	GtkWidget *toplevel, *menu;
@@ -212,7 +336,9 @@
 	char *font;
 	int i, val;
 	char *buf;
-	
+	GSList *header_config_list, *p;
+	GtkTreeIter iter;
+
 	gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "preferences_tab", NULL);
 	prefs->gui = gui;
 	
@@ -360,6 +486,58 @@
 	
 	prefs->restore_labels = GTK_BUTTON (glade_xml_get_widget (gui, "cmdRestoreLabels"));
 	g_signal_connect (prefs->restore_labels, "clicked", G_CALLBACK (restore_labels_clicked), prefs);
+
+	/* headers */
+	prefs->add_header = GTK_BUTTON (glade_xml_get_widget (gui, "cmdHeadersAdd"));
+	prefs->remove_header = GTK_BUTTON (glade_xml_get_widget (gui, "cmdHeadersRemove"));
+	prefs->entry_header = GTK_ENTRY (glade_xml_get_widget (gui, "txtHeaders"));
+	prefs->header_list = GTK_TREE_VIEW (glade_xml_get_widget (gui, "treeHeaders"));
+	g_signal_connect (prefs->entry_header, "changed", 
+			  G_CALLBACK (entry_header_changed), prefs);
+	g_signal_connect (prefs->entry_header, "activate",
+			  G_CALLBACK (add_header), prefs);
+	/* initialise the tree with appropriate headings */
+	prefs->header_list_store = gtk_list_store_new(HEADER_LIST_N_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+	g_signal_connect (prefs->add_header, "clicked",
+			  G_CALLBACK (add_header), prefs);
+	g_signal_connect (prefs->remove_header, "clicked", 
+			  G_CALLBACK (remove_header), prefs);
+	gtk_tree_view_set_model(prefs->header_list, GTK_TREE_MODEL (prefs->header_list_store));
+	prefs->header_list_enabled_renderer = gtk_cell_renderer_toggle_new();
+	g_object_set(prefs->header_list_enabled_renderer, "activatable", TRUE, NULL);
+	g_signal_connect(prefs->header_list_enabled_renderer, "toggled", 
+			 G_CALLBACK(header_list_enabled_toggled), prefs);
+        gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(prefs->header_list), -1, 
+						    "Enabled", prefs->header_list_enabled_renderer,
+						    "active", HEADER_LIST_ENABLED_COLUMN, 
+						    NULL);
+	prefs->header_list_name_renderer = gtk_cell_renderer_text_new();
+	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(prefs->header_list), -1, 
+						    "Name", prefs->header_list_name_renderer,
+						    "text", HEADER_LIST_NAME_COLUMN, 
+						    NULL);
+	/* read stored values from gconf */
+	header_config_list = gconf_client_get_list (prefs->gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, NULL);
+	p = header_config_list;
+	while (p) {
+		gchar *xml = (gchar *)p->data;
+		struct EMMailerCustomHeader h;
+		em_mailer_custom_header_from_xml(&h, xml);
+		if (h.name) {
+			gtk_list_store_append(prefs->header_list_store, &iter);
+			gtk_list_store_set(prefs->header_list_store, &iter, 
+					   HEADER_LIST_NAME_COLUMN, h.name,
+					   HEADER_LIST_ENABLED_COLUMN, (h.flags & EM_MAILER_PREFS_FLAGS_ENABLED), 
+					   -1);
+		}
+		p = g_slist_next(p);
+	}
+	g_slist_foreach (header_config_list, (GFunc) g_free, NULL);
+	g_slist_free(header_config_list);
+	if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs->header_list_store), &iter)) {
+		/* list is empty - disable the remove button */
+		gtk_widget_set_sensitive(GTK_WIDGET(prefs->remove_header), FALSE);
+	}
 }
 
 
@@ -384,6 +562,9 @@
 	GSList *list, *l, *n;
 	guint32 rgb;
 	int i, val;
+	GtkTreeIter iter;
+	gboolean valid;
+	GSList *header_list;
 	
 	/* General tab */
 	
@@ -444,7 +625,7 @@
 	gconf_client_set_string (prefs->gconf, "/apps/evolution/mail/display/fonts/monospace",
 				 gnome_font_picker_get_font_name (prefs->font_fixed), NULL);
 	gconf_client_set_bool (prefs->gconf, "/apps/evolution/mail/display/fonts/use_custom",
-			       !gtk_toggle_button_get_active (prefs->font_share), NULL);
+ 			       !gtk_toggle_button_get_active (prefs->font_share), NULL);
 	gconf_client_set_bool (prefs->gconf, "/apps/evolution/mail/display/animate_images",
 			       gtk_toggle_button_get_active (prefs->show_animated), NULL);
 	
@@ -469,6 +650,105 @@
 		g_slist_free_1 (l);
 		l = n;
 	}
-	
+
+	/* Headers */
+	header_list = NULL;
+	valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs->header_list_store), &iter);
+	while (valid) {
+		struct EMMailerCustomHeader h;
+		gboolean header_enabled;
+		gchar *xml;
+		/* bold should be on by default */
+		h.flags = EM_MAILER_PREFS_FLAGS_BOLD;
+		gtk_tree_model_get (GTK_TREE_MODEL(prefs->header_list_store), &iter, 
+				    HEADER_LIST_NAME_COLUMN, &h.name, 
+				    HEADER_LIST_ENABLED_COLUMN, &header_enabled, 
+				    -1);
+		if (header_enabled) {
+			h.flags |= EM_MAILER_PREFS_FLAGS_ENABLED;
+		}
+		xml = em_mailer_custom_header_to_xml(&h);
+		if (xml != NULL) {
+			header_list = g_slist_append(header_list, xml);
+		}
+		valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs->header_list_store), &iter);
+	}
+	gconf_client_set_list (prefs->gconf, "/apps/evolution/mail/display/headers", GCONF_VALUE_STRING, header_list, NULL);
+	g_slist_free (header_list);
 	gconf_client_suggest_sync (prefs->gconf, NULL);
+}
+
+static void
+em_mailer_custom_header_from_xmldoc(struct EMMailerCustomHeader *header, xmlDocPtr doc)
+{
+	xmlNodePtr root;
+	xmlChar *name, *flags;
+
+	if (doc == NULL) {
+		header->name = NULL;
+		return;
+	}
+	root = doc->children;
+	if (strcmp (root->name, "header") != 0) {
+		return;
+	}
+	name = xmlGetProp (root, "name");
+	flags = xmlGetProp (root, "flags");
+	if ((name == NULL) || (flags == NULL)) {
+		return;
+	}
+	header->name = g_strdup(name);
+	header->flags = atoi(flags);
+	xmlFree(name);
+	xmlFree(flags);
+	return;
+}
+
+void
+em_mailer_custom_header_from_xml(struct EMMailerCustomHeader *header, const gchar *xml)
+{
+	xmlDocPtr doc;
+	
+	header->name = NULL;
+	doc = xmlParseDoc((char *)xml);
+	if (doc == NULL) {
+		return;
+	}
+	em_mailer_custom_header_from_xmldoc(header, doc);
+	xmlFreeDoc(doc);
+	return;
+}
+
+static gchar *
+em_mailer_custom_header_to_xml(struct EMMailerCustomHeader *header)
+{
+	xmlDocPtr doc;
+	xmlNodePtr root;
+	gchar *flags;
+	xmlChar *xml_buffer;
+	char *returned_buffer;
+	int xml_buffer_size;
+
+	g_return_val_if_fail (header != NULL, NULL);
+	g_return_val_if_fail (header->name != NULL, NULL);
+
+	doc = xmlNewDoc ("1.0");
+
+	root = xmlNewDocNode (doc, NULL, "header", NULL);
+	flags = g_strdup_printf ("%d", header->flags);
+	xmlSetProp (root, "name", header->name);
+	xmlSetProp (root, "flags", flags);
+
+	xmlDocSetRootElement (doc, root);
+
+	xmlDocDumpMemory (doc, &xml_buffer, &xml_buffer_size);
+	xmlFreeDoc (doc);
+
+	returned_buffer = g_malloc (xml_buffer_size + 1);
+	memcpy (returned_buffer, xml_buffer, xml_buffer_size);
+	returned_buffer [xml_buffer_size] = '\0';
+	xmlFree (xml_buffer);
+	g_free (flags);
+
+	return returned_buffer;
 }
Index: mail/em-mailer-prefs.h
===================================================================
RCS file: /cvs/gnome/evolution/mail/em-mailer-prefs.h,v
retrieving revision 1.2
diff -u -r1.2 em-mailer-prefs.h
--- mail/em-mailer-prefs.h	29 Oct 2003 17:49:55 -0000	1.2
+++ mail/em-mailer-prefs.h	28 Nov 2003 18:57:34 -0000
@@ -49,8 +49,16 @@
 typedef struct _EMMailerPrefs EMMailerPrefs;
 typedef struct _EMMailerPrefsClass EMMailerPrefsClass;
 
+#define EM_MAILER_PREFS_FLAGS_BOLD       0x01
+#define EM_MAILER_PREFS_FLAGS_ENABLED    0x02
+
+struct EMMailerCustomHeader {
+	gchar *name;
+	gint flags;
+};
+
 struct _EMMailerPrefs {
-	GtkVBox parent_object;
+        GtkVBox parent_object;
 	
 	GNOME_Evolution_Shell shell;
 	
@@ -98,6 +106,15 @@
 		GnomeColorPicker *color;
 	} labels[5];
 	GtkButton *restore_labels;
+
+	/* Headers tab */
+	GtkButton *add_header;
+	GtkButton *remove_header;
+	GtkEntry *entry_header;
+	GtkTreeView *header_list;
+	GtkListStore *header_list_store;
+	GtkCellRenderer *header_list_name_renderer;
+	GtkCellRenderer *header_list_enabled_renderer;
 };
 
 struct _EMMailerPrefsClass {
@@ -113,6 +130,11 @@
 GtkWidget *em_mailer_prefs_new (void);
 
 void em_mailer_prefs_apply (EMMailerPrefs *prefs);
+
+/* pass a pointer to an allocated struct EMMailerCustomHeader. on error, header.name will 
+   be set to NULL
+ */
+void em_mailer_custom_header_from_xml(struct EMMailerCustomHeader *header, const gchar *xml);
 
 /* needed by global config */
 #define EM_MAILER_PREFS_CONTROL_ID "OAFIID:GNOME_Evolution_Mail_MailerPrefs_ConfigControl_2"
Index: mail/mail-config.glade
===================================================================
RCS file: /cvs/gnome/evolution/mail/mail-config.glade,v
retrieving revision 1.124
diff -u -r1.124 mail-config.glade
--- mail/mail-config.glade	11 Nov 2003 02:38:01 -0000	1.124
+++ mail/mail-config.glade	28 Nov 2003 18:57:51 -0000
@@ -4475,6 +4475,177 @@
 	  <property name="type">tab</property>
 	</packing>
       </child>
+
+      <child>
+	<widget class="GtkVBox" id="vboxHeaderTab">
+	  <property name="border_width">6</property>
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">0</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="lblHeaders">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">&lt;b&gt;_Displayed Mail Headers&lt;/b&gt;</property>
+	      <property name="use_underline">True</property>
+	      <property name="use_markup">True</property>
+	      <property name="justify">GTK_JUSTIFY_LEFT</property>
+	      <property name="wrap">False</property>
+	      <property name="selectable">False</property>
+	      <property name="xalign">0</property>
+	      <property name="yalign">0.5</property>
+	      <property name="xpad">0</property>
+	      <property name="ypad">0</property>
+	      <property name="mnemonic_widget">txtHeaders</property>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
+	    </packing>
+	  </child>
+
+	  <child>
+	    <widget class="GtkHBox" id="hboxTreeButtons">
+	      <property name="border_width">6</property>
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">0</property>
+
+	      <child>
+		<widget class="GtkVBox" id="vboxEntryTree">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">6</property>
+
+		  <child>
+		    <widget class="GtkEntry" id="txtHeaders">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">True</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char" translatable="yes">*</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkScrolledWindow" id="scrolledwindow49">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		      <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+		      <property name="shadow_type">GTK_SHADOW_NONE</property>
+		      <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+		      <child>
+			<widget class="GtkTreeView" id="treeHeaders">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="headers_visible">False</property>
+			  <property name="rules_hint">False</property>
+			  <property name="reorderable">False</property>
+			  <property name="enable_search">True</property>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkVBox" id="vbox162">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkButton" id="cmdHeadersAdd">
+		      <property name="visible">True</property>
+		      <property name="sensitive">False</property>
+		      <property name="can_focus">True</property>
+		      <property name="label">gtk-add</property>
+		      <property name="use_stock">True</property>
+		      <property name="relief">GTK_RELIEF_NORMAL</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">6</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkButton" id="cmdHeadersRemove">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="label">gtk-remove</property>
+		      <property name="use_stock">True</property>
+		      <property name="relief">GTK_RELIEF_NORMAL</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">6</property>
+		  <property name="expand">False</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
+	    </packing>
+	  </child>
+	</widget>
+	<packing>
+	  <property name="tab_expand">False</property>
+	  <property name="tab_fill">True</property>
+	</packing>
+      </child>
+
+      <child>
+	<widget class="GtkLabel" id="lblHeaders">
+	  <property name="visible">True</property>
+	  <property name="label" translatable="yes">H_eaders</property>
+	  <property name="use_underline">True</property>
+	  <property name="use_markup">False</property>
+	  <property name="justify">GTK_JUSTIFY_LEFT</property>
+	  <property name="wrap">False</property>
+	  <property name="selectable">False</property>
+	  <property name="xalign">0.5</property>
+	  <property name="yalign">0.5</property>
+	  <property name="xpad">0</property>
+	  <property name="ypad">0</property>
+	</widget>
+	<packing>
+	  <property name="type">tab</property>
+	</packing>
+      </child>
     </widget>
   </child>
 </widget>
Index: mail/ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/mail/ChangeLog,v
retrieving revision 1.2896
diff -u -r1.2896 ChangeLog
--- mail/ChangeLog	23 Nov 2003 17:02:09 -0000	1.2896
+++ mail/ChangeLog	28 Nov 2003 18:57:58 -0000
@@ -1,3 +1,33 @@
+2003-11-29  Grahame Bowland  <grahame angrygoats net>
+
+	* mail-config.glade: add tab to mail configuration 
+	dialog to allow custom headers to be specified for 
+	display.
+	* em-mailer-prefs.h: modify struct _EMMailerPrefs to 
+	add widgets for custom header tab. Add defines for custom 
+	header flags. Add struct EMMailerCustomHeader to describe
+	custom headers, and add function 
+	em_mailer_custom_headers_from_xml to allow XML from gconf 
+	key to be parsed into this structure.
+	* em-folder-view.c (emfv_setting_notify): catch changes to 
+	custom header gconf key and update mail view to correspond
+	* em-mailer-prefs.c (em_mailer_prefs_apply): save custom 
+	headers to gconf
+	(header_list_enabled_toggled): toggle clicked toggle column
+	(add_header): add header to custom header list if valid
+	(remove_header): remove selected custom header
+	(is_valid_header): return true if passed header is valid, 
+	otherwise false
+	(entry_header_changed): set add button sensitive if entered
+	header is valid, otherwise set add button unsensitive
+	(em_mailer_prefs_construct): initialise header selection tab. 
+	Load gconf data for header selection dialog.
+	(em_mailer_custom_header_to_xml): 
+	load a header structure from XML document structure
+	(em_mailer_custom_header_from_xml): load a header 
+	structure from a string containing valid XML. if any failure, 
+	the header.name is set to NULL.
+	
 2003-11-22  Jeffrey Stedfast  <fejj ximian com>
 
 	* em-folder-tree-model.c (model_drag_data_received)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]