[evolution-patches] Redesign of To, Cc and Bcc fields of Composer



Hi,

This patch proposes some UI changes to the Composer fields to make them
more flexible and easy to use.
Earlier there was no mechanism to verify or check the email addresses u
have entered except for horizontal scrolling.
Now the entered email addresses can be easily verified by pressing the
button at the end of To, Cc, Bcc fields or by pressing (Ctrl ->), this
pops down a list which shows all the email addresses entered in the
particular field. This list is easily scrollable and supports delete
operation also.
Also included in this patch is srinis patch which allows u to remove
names from contact list for a single mail.

By joining these two patches almost all the enhancement requests and
bugs related to composer fields are solved.

Related Bug Numbers are:
http://bugzilla.gnome.org/show_bug.cgi?id=220570
http://bugzilla.gnome.org/show_bug.cgi?id=231751
http://bugzilla.gnome.org/show_bug.cgi?id=207635
http://bugzilla.gnome.org/show_bug.cgi?id=272391

Please give a try to this and give your feedback regarding any bugs or
usability issues.


Thanks
Devashish Sharma

(New Design and Patch done by Srinivas Ragavan and Devashish Sharma)

Index: libedataserverui/Makefile.am
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/Makefile.am,v
retrieving revision 1.13
diff -u -p -r1.13 Makefile.am
--- libedataserverui/Makefile.am	13 Aug 2005 02:29:01 -0000	1.13
+++ libedataserverui/Makefile.am	8 Nov 2005 10:05:23 -0000
@@ -27,6 +27,7 @@ libedataserverui_1_2_la_SOURCES =	\
 	e-name-selector-dialog.c	\
 	e-name-selector-entry.c		\
 	e-name-selector-model.c		\
+	e-name-selector-list.c		\
 	e-passwords.c			\
 	e-source-selector.c		\
 	e-source-selector-dialog.c	\
@@ -35,11 +36,10 @@ libedataserverui_1_2_la_SOURCES =	\
 
 libedataserverui_1_2_la_LIBADD = 				\
 	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
-	$(top_builddir)/libedataserver/libedataserver-1.2.la	\
-	$(E_DATA_SERVER_UI_LIBS)
+	$(E_DATA_SERVER_LIBS)
 
 libedataserverui_1_2_la_LDFLAGS = 										\
-	-version-info $(LIBEDATASERVERUI_CURRENT):$(LIBEDATASERVERUI_REVISION):$(LIBEDATASERVERUI_AGE) $(NO_UNDEFINED)
+	-version-info $(LIBEDATASERVERUI_CURRENT):$(LIBEDATASERVERUI_REVISION):$(LIBEDATASERVERUI_AGE) 
 
 libedataserveruiincludedir = $(privincludedir)/libedataserverui
 
@@ -52,6 +52,7 @@ libedataserveruiinclude_HEADERS =	\
 	e-name-selector-dialog.h	\
 	e-name-selector-entry.h		\
 	e-name-selector-model.h		\
+	e-name-selector-list.h		\
 	e-passwords.h			\
 	e-source-selector.h		\
 	e-source-selector-dialog.h	\
Index: addressbook/libebook/e-destination.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/addressbook/libebook/e-destination.c,v
retrieving revision 1.13
diff -u -p -r1.13 e-destination.c
--- addressbook/libebook/e-destination.c	31 Aug 2005 04:21:51 -0000	1.13
+++ addressbook/libebook/e-destination.c	8 Nov 2005 10:02:55 -0000
@@ -63,6 +63,7 @@ struct _EDestinationPrivate {
 	char *email;
 	char *addr;
 	char *textrep;
+	gboolean ignored;
 
 	GList *list_dests;
 
@@ -154,6 +155,7 @@ e_destination_init (EDestination *dest)
 	dest->priv = g_new0 (struct _EDestinationPrivate, 1);
 
 	dest->priv->auto_recipient = FALSE;
+	dest->priv->ignored = FALSE;
 }
 
 GType
@@ -217,6 +219,7 @@ e_destination_copy (const EDestination *
         new_dest->priv->email              = g_strdup (dest->priv->email);
         new_dest->priv->addr               = g_strdup (dest->priv->addr);
         new_dest->priv->email_num          = dest->priv->email_num;
+        new_dest->priv->ignored            = dest->priv->ignored;
 
 	if (dest->priv->contact)
 		new_dest->priv->contact = g_object_ref (dest->priv->contact);
@@ -377,7 +380,7 @@ e_destination_set_contact (EDestination 
 	g_return_if_fail (dest && E_IS_DESTINATION (dest));
 	g_return_if_fail (contact && E_IS_CONTACT (contact));
 
-	if (dest->priv->contact != contact || dest->priv->email_num != email_num) {
+	if (dest->priv->contact != contact ) {
 		g_object_ref (contact);
 
 		e_destination_clear (dest);
@@ -388,6 +391,8 @@ e_destination_set_contact (EDestination 
 
 		dest->priv->email_num = email_num;
 
+		dest->priv->ignored = FALSE;
+
 		/* handle the mailing list case */
 		if (e_contact_get (dest->priv->contact, E_CONTACT_IS_LIST)) {
 			GList *email = e_contact_get_attributes (dest->priv->contact, E_CONTACT_EMAIL);
@@ -439,6 +444,7 @@ e_destination_set_contact (EDestination 
 					if (name) e_destination_set_name (list_dest, name);
 					if (email_addr) e_destination_set_email (list_dest, email_addr);
 					e_destination_set_html_mail_pref (list_dest, html_pref);
+					list_dest->priv->ignored = FALSE;
 
 					dest->priv->list_dests = g_list_append (dest->priv->list_dests, list_dest);
 				}
@@ -453,7 +459,21 @@ e_destination_set_contact (EDestination 
 		}
 
 		g_signal_emit (dest, signals [CHANGED], 0);
+	} else if (dest->priv->email_num != email_num){
+		/* Splitting here would help the contact lists not rebuiding, so that it remembers ignored values */
+		g_object_ref (contact);
+
+		e_destination_clear (dest);
+
+		dest->priv->contact = contact;
+
+		dest->priv->contact_uid = e_contact_get (dest->priv->contact, E_CONTACT_UID);
+
+		dest->priv->email_num = email_num;
+	
+		g_signal_emit (dest, signals [CHANGED], 0);		
 	}
+	
 }
 
 /**
@@ -770,6 +790,18 @@ e_destination_get_name (const EDestinati
 	return priv->name;
 }
 
+gboolean
+e_destination_is_ignored (const EDestination *dest)
+{
+	return dest->priv->ignored;
+}
+
+void
+e_destination_set_ignored (EDestination *dest, gboolean ignored)
+{
+	dest->priv->ignored = ignored;
+}
+
 /**
  * e_destination_get_email:
  * @dest: an #EDestination
@@ -850,7 +882,7 @@ e_destination_get_address (const EDestin
 			while (iter) {
 				EDestination *list_dest = E_DESTINATION (iter->data);
 				
-				if (!e_destination_empty (list_dest)) {
+				if (!e_destination_empty (list_dest) && !list_dest->priv->ignored) {
 					const char *name, *email;
 					name = e_destination_get_name (list_dest);
 					email = e_destination_get_email (list_dest);
Index: addressbook/libebook/e-destination.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/addressbook/libebook/e-destination.h,v
retrieving revision 1.6
diff -u -p -r1.6 e-destination.h
--- addressbook/libebook/e-destination.h	31 Aug 2005 04:21:51 -0000	1.6
+++ addressbook/libebook/e-destination.h	8 Nov 2005 10:02:55 -0000
@@ -93,6 +93,8 @@ const char    *e_destination_get_address
 gboolean       e_destination_is_evolution_list   (const EDestination *);
 gboolean       e_destination_list_show_addresses (const EDestination *);
 const GList   *e_destination_list_get_dests      (const EDestination *);
+gboolean       e_destination_is_ignored  	 (const EDestination *dest);
+void           e_destination_set_ignored 	 (EDestination *view, gboolean ignored);
 
 /* If true, they want HTML mail. */
 void           e_destination_set_html_mail_pref (EDestination *dest, gboolean flag);
Index: libedataserverui/e-destination-store.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-destination-store.c,v
retrieving revision 1.8
diff -u -p -r1.8 e-destination-store.c
--- libedataserverui/e-destination-store.c	31 Aug 2005 04:26:10 -0000	1.8
+++ libedataserverui/e-destination-store.c	8 Nov 2005 10:06:28 -0000
@@ -50,7 +50,7 @@ static GType        e_destination_store_
 static gboolean     e_destination_store_get_iter        (GtkTreeModel       *tree_model,
 							 GtkTreeIter        *iter,
 							 GtkTreePath        *path);
-static GtkTreePath *e_destination_store_get_path        (GtkTreeModel       *tree_model,
+GtkTreePath *e_destination_store_get_path        (GtkTreeModel       *tree_model,
 							 GtkTreeIter        *iter);
 static void         e_destination_store_get_value       (GtkTreeModel       *tree_model,
 							 GtkTreeIter        *iter,
@@ -424,6 +424,27 @@ e_destination_store_remove_destination (
 	row_deleted (destination_store, n);
 }
 
+void
+e_destination_store_remove_destination_nth (EDestinationStore *destination_store, int n)
+{
+	EDestination *destination;
+	
+	g_return_if_fail ( n >= 0);
+
+	destination = g_ptr_array_index(destination_store->destinations, n);
+	stop_destination (destination_store, destination);
+	g_object_unref (destination);
+
+	g_ptr_array_remove_index (destination_store->destinations, n);
+	row_deleted (destination_store, n);
+}
+
+guint
+e_destination_store_get_destination_count (EDestinationStore *destination_store)
+{
+	return destination_store->destinations->len;
+}
+
 /* ---------------- *
  * GtkTreeModel API *
  * ---------------- */
@@ -471,7 +492,7 @@ e_destination_store_get_iter (GtkTreeMod
 	return TRUE;
 }
 
-static GtkTreePath *
+GtkTreePath *
 e_destination_store_get_path (GtkTreeModel *tree_model,
 			      GtkTreeIter  *iter)
 {
Index: libedataserverui/e-destination-store.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-destination-store.h,v
retrieving revision 1.3
diff -u -p -r1.3 e-destination-store.h
--- libedataserverui/e-destination-store.h	31 Aug 2005 04:26:10 -0000	1.3
+++ libedataserverui/e-destination-store.h	8 Nov 2005 10:06:28 -0000
@@ -76,7 +76,10 @@ void               e_destination_store_a
 							   EDestination *destination);
 void               e_destination_store_remove_destination (EDestinationStore *destination_store,
 							   EDestination *destination);
-
+void		   e_destination_store_remove_destination_nth (EDestinationStore *destination_store, 
+							       int n);
+guint		   e_destination_store_get_destination_count (EDestinationStore *destination_store);
+GtkTreePath       *e_destination_store_get_path (GtkTreeModel *tree_model, GtkTreeIter *iter);
 G_END_DECLS
 
 #endif  /* E_DESTINATION_STORE_H */
Index: libedataserverui/e-name-selector-entry.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector-entry.c,v
retrieving revision 1.26
diff -u -p -r1.26 e-name-selector-entry.c
--- libedataserverui/e-name-selector-entry.c	30 Sep 2005 08:23:06 -0000	1.26
+++ libedataserverui/e-name-selector-entry.c	8 Nov 2005 10:07:46 -0000
@@ -24,19 +24,22 @@
 #include <config.h>
 #include <string.h>
 #include <gtk/gtkentry.h>
+#include <gtk/gtktreemodel.h>
 #include <gtk/gtkentrycompletion.h>
 #include <gtk/gtkcelllayout.h>
 #include <gtk/gtkcellrenderertext.h>
 #include <gtk/gtkmenuitem.h>
+#include <gtk/gtkradiomenuitem.h>
 #include <gtk/gtkseparatormenuitem.h>
 #include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
 
 #include <libebook/e-book.h>
 #include <libebook/e-contact.h>
 #include <libebook/e-destination.h>
 #include <libedataserverui/e-book-auth-util.h>
 #include <libedataserver/e-sexp.h>
-
+#include <libedataserverui/e-data-server-ui-marshal.h>
 #include "e-name-selector-entry.h"
 
 #define ENS_DEBUG(x)
@@ -109,13 +112,11 @@ e_name_selector_entry_class_init (ENameS
 	object_class->set_property = e_name_selector_entry_set_property;
 	object_class->dispose      = e_name_selector_entry_dispose;
 	object_class->finalize     = e_name_selector_entry_finalize;
-
 	widget_class->realize      = e_name_selector_entry_realize;
 
 	/* Install properties */
 
 	/* Install signals */
-
 }
 
 /* Remove unquoted commas from string */
@@ -412,7 +413,6 @@ escape_sexp_string (const gchar *string)
 
 	gstring = g_string_new ("");
 	e_sexp_encode_string (gstring, string);
-
 	encoded_string = gstring->str;
 	g_string_free (gstring, FALSE);
 
@@ -624,6 +624,7 @@ find_existing_completion (ENameSelectorE
 	if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (name_selector_entry->contact_store), &iter))
 		return FALSE;
 
+	
 	do {
 		EContact      *current_contact;
 		gint           current_field_rank;
@@ -732,7 +733,7 @@ type_ahead_complete (ENameSelectorEntry 
 	cursor_pos = gtk_editable_get_position (GTK_EDITABLE (name_selector_entry));
 	if (cursor_pos < 0)
 		return;
-
+	
 	text = gtk_entry_get_text (GTK_ENTRY (name_selector_entry));
 	get_range_at_position (text, cursor_pos, &range_start, &range_end);
 	range_len = range_end - range_start;
@@ -1250,6 +1251,7 @@ completion_match_selected (ENameSelector
 	/* Place cursor at end of address */
 
 	gtk_editable_set_position (GTK_EDITABLE (name_selector_entry), cursor_pos);
+	
 	return TRUE;
 }
 
@@ -1258,17 +1260,17 @@ entry_activate (ENameSelectorEntry *name
 {
 	gint         cursor_pos;
 	gint         range_start, range_end;
-	const gchar *text;
+	const gchar   *text;
+	
+	cursor_pos = gtk_editable_get_position (GTK_EDITABLE (name_selector_entry));
 
-	/* Show us what's really there */
+	text = gtk_entry_get_text (GTK_ENTRY (name_selector_entry));
+	get_range_at_position (text, cursor_pos, &range_start, &range_end);
 
-	cursor_pos = gtk_editable_get_position (GTK_EDITABLE (name_selector_entry));
+	/* Show us what's really there */
 	sync_destination_at_position (name_selector_entry, cursor_pos, &cursor_pos);
 
 	/* Place cursor at end of address */
-
-	text = gtk_entry_get_text (GTK_ENTRY (name_selector_entry));
-	get_range_at_position (text, cursor_pos, &range_start, &range_end);
 	gtk_editable_set_position (GTK_EDITABLE (name_selector_entry), range_end);
 }
 
@@ -1772,15 +1774,56 @@ popup_activate_email (ENameSelectorEntry
 }
 
 static void
+popup_activate_list (EDestination *destination, GtkWidget *item)
+{
+	gboolean status = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
+	
+	e_destination_set_ignored (destination, !status);	
+}
+
+static void
+destination_set_list (GtkWidget *item, EDestination *destination)
+{
+	EContact *contact;
+	gboolean status = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
+
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return;
+	
+	e_destination_set_ignored (destination, !status);
+}
+
+static void
+destination_set_email (GtkWidget *item, EDestination *destination)
+{
+	int email_num;
+	EContact *contact;
+
+ 	if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+		return;
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return;
+
+	email_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "order"));
+	e_destination_set_contact (destination, contact, email_num);
+}
+
+static void
 populate_popup (ENameSelectorEntry *name_selector_entry, GtkMenu *menu)
 {
 	EDestination *destination;
 	EContact     *contact;
 	GtkWidget    *menu_item;
-	GList        *email_list;
+	GList        *email_list = NULL;
 	GList        *l;
 	gint          i;
 	char 	     *edit_label;
+	int 	      email_num, len;
+	GSList 	     *group = NULL;
+	gboolean      is_list;
+	gboolean      show_menu = FALSE;
 
 	destination = name_selector_entry->popup_destination;
 	if (!destination)
@@ -1797,29 +1840,74 @@ populate_popup (ENameSelectorEntry *name
 	menu_item = gtk_separator_menu_item_new ();
 	gtk_widget_show (menu_item);
 	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	email_num = e_destination_get_email_num (destination);
 
 	/* Addresses */
+	is_list = e_contact_get (contact, E_CONTACT_IS_LIST) ? TRUE : FALSE;
+	if (is_list) {
+		const GList *dests = e_destination_list_get_dests (destination);
+		GList *iter;
+		int len = g_list_length ((GList *)dests);
+
+		for (iter = (GList *)dests; iter; iter = iter->next) {
+			EDestination *dest = (EDestination *) iter->data;
+			const char *email = e_destination_get_email (dest);
+			
+			if (!email || *email == '\0')
+				continue;	
+
+			if (len > 1) {
+				menu_item = gtk_check_menu_item_new_with_label (email);
+				g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_list), dest);				
+			} else {
+				menu_item = gtk_menu_item_new_with_label (email);
+			}
+			
+			gtk_widget_show (menu_item);
+			gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+			show_menu = TRUE;
+
+			if ( len > 1 ) {
+				gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), !e_destination_is_ignored(dest));
+				g_signal_connect_swapped (menu_item, "activate", G_CALLBACK (popup_activate_list),
+							  dest);	
+			}
+		}
+		
+	} else {
+		email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+		len = g_list_length (email_list);
 
-	email_list = e_contact_get (contact, E_CONTACT_EMAIL);
-
-	for (l = email_list, i = 0; l; l = g_list_next (l), i++) {
-		gchar *email = l->data;
+		for (l = email_list, i = 0; l; l = g_list_next (l), i++) {
+			gchar *email = l->data;
 
-		if (!email || *email == '\0')
-			continue;
-
-		menu_item = gtk_menu_item_new_with_label (email);
-		gtk_widget_show (menu_item);
-		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
-
-		g_object_set_data (G_OBJECT (menu_item), "order", GINT_TO_POINTER (i));
-		g_signal_connect_swapped (menu_item, "activate", G_CALLBACK (popup_activate_email),
-					  name_selector_entry);
+			if (!email || *email == '\0')
+				continue;
+		
+			if (len > 1) {
+				menu_item = gtk_radio_menu_item_new_with_label (group, email);
+				group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item));
+				g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_email), destination);
+			} else {
+				menu_item = gtk_menu_item_new_with_label (email);			
+			}
+			
+			gtk_widget_show (menu_item);
+			gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+			show_menu = TRUE;
+			g_object_set_data (G_OBJECT (menu_item), "order", GINT_TO_POINTER (i));			
+
+			if ( i == email_num && len > 1 ) {
+				gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
+				g_signal_connect_swapped (menu_item, "activate", G_CALLBACK (popup_activate_email),
+							  name_selector_entry);
+			}
+		}
 	}
 
 	/* Separator */
 
-	if (email_list) {
+	if (show_menu) {
 		menu_item = gtk_separator_menu_item_new ();
 		gtk_widget_show (menu_item);
 		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
Index: libedataserverui/e-name-selector-entry.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector-entry.h,v
retrieving revision 1.6
diff -u -p -r1.6 e-name-selector-entry.h
--- libedataserverui/e-name-selector-entry.h	24 Aug 2005 02:40:35 -0000	1.6
+++ libedataserverui/e-name-selector-entry.h	8 Nov 2005 10:07:46 -0000
@@ -63,6 +63,8 @@ struct ENameSelectorEntry {
 
 	EDestination        *popup_destination;
 
+	gchar		    *user_entered_text;
+
 	/* TEMPORARY */
 	gpointer             (*contact_editor_func) (EBook *, EContact *, gboolean, gboolean);
 	gpointer             (*contact_list_editor_func) (EBook *, EContact *, gboolean, gboolean);
Index: libedataserverui/e-name-selector.c
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector.c,v
retrieving revision 1.7
diff -u -p -r1.7 e-name-selector.c
--- libedataserverui/e-name-selector.c	6 Jul 2005 08:39:04 -0000	1.7
+++ libedataserverui/e-name-selector.c	8 Nov 2005 10:09:06 -0000
@@ -317,3 +317,68 @@ e_name_selector_peek_section_entry (ENam
 
 	return section->entry;
 }
+
+/**
+ * e_name_selector_peek_section_list:
+ * @name_selector: an #ENameSelector
+ * @name: the name of the section to peek
+ *
+ * Gets the #ENameSelectorList for the section specified by @name.
+ *
+ * Return value: The #ENameSelectorList for the named section, or %NULL if it
+ * doesn't exist in the #ENameSelectorModel.
+ **/
+
+ENameSelectorList *
+e_name_selector_peek_section_list (ENameSelector *name_selector, const gchar *name)
+{
+	EDestinationStore *destination_store;
+	Section *section;
+	gint     n;
+
+	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
+	g_return_val_if_fail (name != NULL, NULL);
+
+	if (!e_name_selector_model_peek_section (name_selector->model, name,
+						 NULL, &destination_store))
+		return NULL;
+
+	n = find_section_by_name (name_selector, name);
+	if (n < 0)
+		n = add_section (name_selector, name);
+
+	section = &g_array_index (name_selector->sections, Section, n);
+
+	if (!section->entry) {
+		GArray        *source_books;
+		EContactStore *contact_store;
+		gchar         *text;
+		gint           i;
+
+		section->entry = (ENameSelectorEntry *) e_name_selector_list_new ();
+		if (pango_parse_markup (name, -1, '_', NULL,
+					&text, NULL, NULL))  {
+			atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
+			g_free (text);
+	}
+		e_name_selector_entry_set_destination_store (section->entry, destination_store);
+
+		/* Create a contact store for the entry and assign our already-open books to it */
+
+		contact_store = e_contact_store_new ();
+		source_books = g_object_get_data (G_OBJECT (name_selector), PRIVATE_SOURCE_BOOKS_KEY);
+
+		for (i = 0; i < source_books->len; i++) {
+			SourceBook *source_book = &g_array_index (source_books, SourceBook, i);
+
+			if (source_book->is_completion_book)
+				e_contact_store_add_book (contact_store, source_book->book);
+		}
+
+		e_name_selector_entry_set_contact_store (section->entry, contact_store);
+		g_object_unref (contact_store);
+	}
+
+	return (ENameSelectorList *)section->entry;
+}
+
Index: libedataserverui/e-name-selector.h
===================================================================
RCS file: /cvs/gnome/evolution-data-server/libedataserverui/e-name-selector.h,v
retrieving revision 1.1
diff -u -p -r1.1 e-name-selector.h
--- libedataserverui/e-name-selector.h	22 Dec 2004 00:06:19 -0000	1.1
+++ libedataserverui/e-name-selector.h	8 Nov 2005 10:09:06 -0000
@@ -29,6 +29,7 @@
 #include <libedataserverui/e-name-selector-model.h>
 #include <libedataserverui/e-name-selector-dialog.h>
 #include <libedataserverui/e-name-selector-entry.h>
+#include <libedataserverui/e-name-selector-list.h>
 
 G_BEGIN_DECLS
 
@@ -62,7 +63,7 @@ ENameSelector       *e_name_selector_new
 ENameSelectorModel  *e_name_selector_peek_model         (ENameSelector *name_selector);
 ENameSelectorDialog *e_name_selector_peek_dialog        (ENameSelector *name_selector);
 ENameSelectorEntry  *e_name_selector_peek_section_entry (ENameSelector *name_selector, const gchar *name);
-
+ENameSelectorList   *e_name_selector_peek_section_list  (ENameSelector *name_selector, const gchar *name);
 G_END_DECLS
 
 #endif /* E_NAME_SELECTOR_H */
--- /var/null	2005-11-08 15:48:30.000000000 +0530
+++ libedataserverui/e-name-selector-list.c	2005-11-08 14:41:16.000000000 +0530
@@ -0,0 +1,576 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* e-name-selector-list.c - Single-line text entry widget for EDestinations.
+ *
+ * Copyright (C) 2005 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Srinivasa Ragavan <sragavan novell com>
+ * 	   :  Devashish Sharma  <sdevashish novell com>	
+ */
+
+#include <config.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkentrycompletion.h>
+#include <gtk/gtkcelllayout.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkradiomenuitem.h>
+#include <gtk/gtkseparatormenuitem.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtktreeselection.h>
+#include <gtk/gtktreemodel.h>
+#include <gtk/gtkvbox.h>
+#include <glib/gi18n-lib.h>
+
+#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
+#include <libebook/e-destination.h>
+#include <libedataserverui/e-book-auth-util.h>
+#include <libedataserver/e-sexp.h>
+#include <libedataserverui/e-data-server-ui-marshal.h>
+#include <libedataserverui/e-name-selector-entry.h>
+#include "e-name-selector-list.h"
+
+#define MAX_ROW	10
+
+G_DEFINE_TYPE (ENameSelectorList, e_name_selector_list, E_TYPE_NAME_SELECTOR_ENTRY);
+
+static void e_name_selector_list_class_init (ENameSelectorListClass *name_selector_list_class);
+static void e_name_selector_list_init       (ENameSelectorList *name_selector_list);
+static void e_name_selector_list_dispose    (GObject *object);
+static void e_name_selector_list_finalize   (GObject *object);
+
+/* Signals */
+
+static void
+enl_popup_size (ENameSelectorList *list)
+{
+	int height = 0, count;
+	GtkTreeViewColumn *column = NULL;
+
+	column = gtk_tree_view_get_column ( GTK_TREE_VIEW (list->tree_view), 0);
+	if (column)
+		gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, NULL, &height);
+
+	/* Show a maximum of 10 rows in the popup list view */
+	count = list->rows;
+	if (count > MAX_ROW) 
+		count = MAX_ROW;
+	if (count <= 0)
+		count = 1;
+
+	gtk_widget_set_size_request (list->tree_view, ((GtkWidget *)list)->allocation.width - 3 , height * count);
+}
+
+static void
+enl_popup_position (ENameSelectorList *list)
+{
+	int x,y;
+
+	enl_popup_size (list);
+	gdk_window_get_origin (((GtkWidget *)list)->window, &x, &y);
+	y = y +((GtkWidget *)list)->allocation.height;
+	
+	gtk_window_move (list->popup, x, y);
+}
+
+static void
+enl_popup_grab (ENameSelectorList *list)
+{
+	int len; 
+	
+	gtk_grab_add (GTK_WIDGET (list->popup));
+	
+	gdk_pointer_grab (((GtkWidget *)list->popup)->window, TRUE,
+                    	  GDK_BUTTON_PRESS_MASK |
+                    	  GDK_BUTTON_RELEASE_MASK |
+                    	  GDK_POINTER_MOTION_MASK,
+                	  NULL, NULL, GDK_CURRENT_TIME);
+
+    	gdk_keyboard_grab (((GtkWidget *)list->popup)->window, TRUE, GDK_CURRENT_TIME);
+	gtk_widget_grab_focus ((GtkWidget *)list);
+	
+	/* Build the listview from the model */
+	gtk_tree_view_set_model (GTK_TREE_VIEW (list->tree_view), GTK_TREE_MODEL(((ENameSelectorEntry *)list)->destination_store));
+
+	/* If any selection of text is present, unselect it */
+	len = strlen(gtk_entry_get_text(GTK_ENTRY(list)));
+	gtk_editable_select_region (GTK_EDITABLE(list), len, -1); 
+}
+
+static void
+enl_popup_ungrab (ENameSelectorList *list)
+{
+	if (!GTK_WIDGET_HAS_GRAB(list->popup))
+		return;
+		
+	gdk_pointer_ungrab (GDK_CURRENT_TIME);	
+	gtk_grab_remove ( GTK_WIDGET (list->popup));
+	gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+}
+
+static void
+enl_tree_select_node (ENameSelectorList *list,
+		      int n)
+{
+	GtkTreeSelection *selection;
+	GtkTreeIter iter;
+	GtkTreePath *path;
+	
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list->tree_view));
+	iter.stamp = ((ENameSelectorEntry *) list)->destination_store->stamp;
+	iter.user_data = GINT_TO_POINTER (n-1);
+
+	gtk_tree_selection_unselect_all (selection);
+	gtk_tree_selection_select_iter (selection, &iter);
+
+	path = e_destination_store_get_path (GTK_TREE_MODEL(((ENameSelectorEntry *) list)->destination_store), &iter);
+	gtk_tree_view_scroll_to_cell ( GTK_TREE_VIEW (list->tree_view), path, gtk_tree_view_get_column( GTK_TREE_VIEW (list->tree_view), 0), FALSE, 0, 0);
+	gtk_tree_view_set_cursor ( GTK_TREE_VIEW (list->tree_view), path, gtk_tree_view_get_column( GTK_TREE_VIEW (list->tree_view), 0), FALSE);
+	gtk_widget_grab_focus (list->tree_view);
+	/*Fixme: We should grab the focus to the column. How? */
+	
+	gtk_tree_path_free (path);
+}
+
+static gboolean
+enl_entry_key_press_event (ENameSelectorList *list, 
+			   GdkEventKey *event,
+			   gpointer dummy)
+{
+	if ( (event->state & GDK_CONTROL_MASK)  && (event->keyval == GDK_Right)) {
+		enl_popup_position (list);
+		printf("Ctrl+ -> clicked\n");
+		gtk_widget_show_all (GTK_WIDGET (list->popup));
+		enl_popup_grab (list);
+		list->rows = e_destination_store_get_destination_count (((ENameSelectorEntry *) list)->destination_store);
+		enl_popup_size (list);
+		enl_tree_select_node (list, 1);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static void
+delete_row (GtkTreePath *path, ENameSelectorList *list)
+{
+	GtkTreeIter   iter;
+	int n, len;
+	GtkTreeSelection *selection;
+	
+	if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (E_NAME_SELECTOR_ENTRY (list)->destination_store), &iter, path))
+      		return;
+		
+	selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (list->tree_view));
+	len = e_destination_store_get_destination_count (E_NAME_SELECTOR_ENTRY (list)->destination_store);
+	n = GPOINTER_TO_INT (iter.user_data);
+	
+	e_destination_store_remove_destination_nth (((ENameSelectorEntry *) list)->destination_store, n);
+	
+	/* If the last one is deleted select the last but one or the deleted +1 */
+	if (n == len -1)
+		n -= 1;
+	
+	/* We deleted the last entry */
+	if (len == 1) {
+		enl_popup_ungrab (list);
+		gtk_widget_hide ( GTK_WIDGET (list->popup));
+	    	return;
+	}
+
+	iter.stamp = ((ENameSelectorEntry *) list)->destination_store->stamp;
+	iter.user_data = GINT_TO_POINTER (n);
+
+	gtk_tree_selection_unselect_all (selection);	
+	gtk_tree_selection_select_iter (selection, &iter);
+	
+	gtk_tree_path_free (path);
+
+	list->rows = e_destination_store_get_destination_count (((ENameSelectorEntry *) list)->destination_store);
+	enl_popup_size (list);
+
+	
+}
+
+static void
+popup_activate_email (ENameSelectorEntry *name_selector_entry, GtkWidget *menu_item)
+{
+	EDestination *destination;
+	EContact     *contact;
+	gint          email_num;
+
+	destination = name_selector_entry->popup_destination;
+	if (!destination)
+		return;
+
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return;
+
+	email_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "order"));
+	e_destination_set_contact (destination, contact, email_num);
+}
+
+static void
+popup_activate_list (EDestination *destination, GtkWidget *item)
+{
+	gboolean status = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
+	
+	e_destination_set_ignored (destination, !status);	
+}
+
+static void
+destination_set_list (GtkWidget *item, EDestination *destination)
+{
+	EContact *contact;
+	gboolean status = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item));
+
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return;
+	
+	e_destination_set_ignored (destination, !status);
+}
+
+static void
+destination_set_email (GtkWidget *item, EDestination *destination)
+{
+	int email_num;
+	EContact *contact;
+
+ 	if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+		return;
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return;
+
+	email_num = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "order"));
+	e_destination_set_contact (destination, contact, email_num);
+}
+
+static void
+popup_delete_row(GtkWidget *w, ENameSelectorList *list)
+{
+	GtkTreeSelection *selection;
+	GList *paths;
+
+	selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (list->tree_view));
+	paths = gtk_tree_selection_get_selected_rows (selection, (GtkTreeModel **)&(E_NAME_SELECTOR_ENTRY (list)->destination_store));
+	delete_row((GtkTreePath *)paths->data, list);
+	g_list_free (paths);
+}
+
+static gboolean
+enl_tree_button_press_event (GtkWidget *widget,
+		       GdkEventButton *event,
+		       ENameSelectorList *list)
+{
+	GtkWidget *menu;
+	EDestination *destination;
+	ENameSelectorEntry *name_selector_entry;
+	EContact     *contact;
+	GtkWidget    *menu_item;
+	GList        *email_list = NULL, *l;
+	gint          i;
+	int 	      email_num, len, n;
+	char         *delete_label;
+	GSList 	     *group = NULL;
+	gboolean      is_list;
+	gboolean      show_menu = FALSE;
+	GtkTreeSelection *selection;
+	GList *paths;
+	GtkTreeIter   iter;
+	
+	
+	if (event->button != 3) 
+		return FALSE;
+
+	name_selector_entry = E_NAME_SELECTOR_ENTRY (list);
+	selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (list->tree_view));
+	paths = gtk_tree_selection_get_selected_rows (selection, (GtkTreeModel **)&(E_NAME_SELECTOR_ENTRY (list)->destination_store));
+	
+	
+	if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (E_NAME_SELECTOR_ENTRY (list)->destination_store), &iter, (GtkTreePath *) paths->data))
+      		return FALSE;
+	n = GPOINTER_TO_INT (iter.user_data);
+	printf("n:%d",n); 
+
+	g_list_free (paths);
+
+	
+
+	destination = e_destination_store_get_destination ( ((ENameSelectorEntry *)list)->destination_store, &iter);	
+
+	if (!destination)
+		return FALSE;
+
+	contact = e_destination_get_contact (destination);
+	if (!contact)
+		return FALSE;
+
+	menu = gtk_menu_new ();
+	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, gtk_get_current_event_time());
+	email_num = e_destination_get_email_num (destination);
+
+	/* Addresses */
+	is_list = e_contact_get (contact, E_CONTACT_IS_LIST) ? TRUE : FALSE;
+	if (is_list) {
+		printf("is list\n");
+		const GList *dests = e_destination_list_get_dests (destination);
+		GList *iter;
+		int len = g_list_length ((GList *)dests);
+
+		for (iter = (GList *)dests; iter; iter = iter->next) {
+			EDestination *dest = (EDestination *) iter->data;
+			const char *email = e_destination_get_email (dest);
+			printf("email:%s\n",email);
+			
+			if (!email || *email == '\0')
+				continue;	
+
+			if (len > 1) {
+				menu_item = gtk_check_menu_item_new_with_label (email);
+				g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_list), dest);				
+			} else {
+				menu_item = gtk_menu_item_new_with_label (email);
+			}
+			
+			gtk_widget_show (menu_item);
+			gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+			show_menu = TRUE;
+
+			if ( len > 1 ) {
+				gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), !e_destination_is_ignored(dest));
+				g_signal_connect_swapped (menu_item, "activate", G_CALLBACK (popup_activate_list),
+							  dest);	
+			}
+		}
+		
+	} else {
+		printf("not list\n");
+		email_list = e_contact_get (contact, E_CONTACT_EMAIL);
+		len = g_list_length (email_list);
+
+		for (l = email_list, i = 0; l; l = g_list_next (l), i++) {
+			gchar *email = l->data;
+
+			if (!email || *email == '\0')
+				continue;
+		
+			if (len > 1) {
+				menu_item = gtk_radio_menu_item_new_with_label (group, email);
+				group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menu_item));
+				g_signal_connect (menu_item, "toggled", G_CALLBACK (destination_set_email), destination);
+			} else {
+				menu_item = gtk_menu_item_new_with_label (email);			
+			}
+			
+			gtk_widget_show (menu_item);
+			gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+			show_menu = TRUE;
+			g_object_set_data (G_OBJECT (menu_item), "order", GINT_TO_POINTER (i));			
+
+			if ( i == email_num && len > 1 ) {
+				gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), TRUE);
+				g_signal_connect_swapped (menu_item, "activate", G_CALLBACK (popup_activate_email),
+							  name_selector_entry);
+			}
+		}
+		g_list_foreach (email_list, (GFunc) g_free, NULL);
+		g_list_free (email_list);
+	}
+
+	/* Separator */
+
+	if (show_menu) {
+		menu_item = gtk_separator_menu_item_new ();
+		gtk_widget_show (menu_item);
+		gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	}
+
+	delete_label = g_strdup_printf(_("_Delete %s"), (char *)e_contact_get_const (contact, E_CONTACT_FILE_AS));
+	menu_item = gtk_menu_item_new_with_mnemonic (delete_label);
+	g_free (delete_label);
+	gtk_widget_show (menu_item);
+	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+
+	g_signal_connect (menu_item, "activate", G_CALLBACK (popup_delete_row),
+				  list);
+	
+	return TRUE;
+
+
+}
+
+static gboolean
+enl_tree_key_press_event (GtkWidget *w,
+			   GdkEventKey *event,
+			   ENameSelectorList *list)
+{
+	if (event->keyval == GDK_Escape) {
+		enl_popup_ungrab (list);
+		gtk_widget_hide ( GTK_WIDGET (list->popup));
+		return TRUE;
+	} else if (event->keyval == GDK_Delete) {
+		GtkTreeSelection *selection;
+		GList *paths;
+
+		selection = gtk_tree_view_get_selection ( GTK_TREE_VIEW (list->tree_view));
+		paths = gtk_tree_selection_get_selected_rows (selection, (GtkTreeModel **)&(E_NAME_SELECTOR_ENTRY (list)->destination_store));
+		paths = g_list_reverse (paths);
+		g_list_foreach (paths, (GFunc) delete_row, list);
+		g_list_free (paths);
+	} else if (event->keyval != GDK_Up && event->keyval != GDK_Down 
+		   && event->keyval != GDK_Shift_R && event->keyval != GDK_Shift_L
+		   && event->keyval != GDK_Control_R && event->keyval != GDK_Control_L){
+		   
+		enl_popup_ungrab (list);
+		gtk_widget_hide ( GTK_WIDGET (list->popup));
+		gtk_widget_event (GTK_WIDGET (list), (GdkEvent *)event);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+void 
+e_name_selector_list_expand_clicked(ENameSelectorList *list)
+{
+
+	if (!GTK_WIDGET_VISIBLE (list->popup)) {
+		enl_popup_position (list);
+		gtk_widget_show_all (GTK_WIDGET (list->popup));
+		enl_popup_grab (list);
+		list->rows = e_destination_store_get_destination_count (((ENameSelectorEntry *) list)->destination_store);
+		enl_popup_size (list);
+		enl_tree_select_node (list, 1);
+	}
+	else {
+		enl_popup_ungrab (list);
+		gtk_widget_hide (GTK_WIDGET (list->popup));
+	}
+}
+/* Object Methods */
+static void
+e_name_selector_list_dispose (GObject *object)
+{
+	if (G_OBJECT_CLASS (e_name_selector_list_parent_class)->dispose)
+		G_OBJECT_CLASS (e_name_selector_list_parent_class)->dispose (object);
+}
+
+static void
+e_name_selector_list_finalize (GObject *object)
+{
+	if (G_OBJECT_CLASS (e_name_selector_list_parent_class)->finalize)
+		G_OBJECT_CLASS (e_name_selector_list_parent_class)->finalize (object);
+}
+
+static void
+e_name_selector_list_realize (GtkWidget *widget)
+{
+	ENameSelectorList *list = (ENameSelectorList *)widget;
+	GTK_WIDGET_CLASS (e_name_selector_list_parent_class)->realize (widget);
+	
+	gtk_tree_view_set_model ( GTK_TREE_VIEW (list->tree_view), GTK_TREE_MODEL(((ENameSelectorEntry *)list)->destination_store));
+}
+
+static void
+e_name_selector_list_class_init (ENameSelectorListClass *name_selector_list_class)
+{
+	GObjectClass   *object_class = G_OBJECT_CLASS (name_selector_list_class);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (name_selector_list_class);
+
+	object_class->dispose      = e_name_selector_list_dispose;
+	object_class->finalize     = e_name_selector_list_finalize;
+
+	widget_class->realize      = e_name_selector_list_realize;
+
+	/* Install properties */
+
+	/* Install signals */
+
+}
+
+static void
+e_name_selector_list_init (ENameSelectorList *list)
+{
+	GtkCellRenderer *renderer;
+	GtkWidget *scroll, *popup_frame, *vbox;
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *column;
+	ENameSelectorEntry *entry = E_NAME_SELECTOR_ENTRY (list);
+	GtkEntryCompletion *completion;
+
+	list->store = e_destination_store_new ();
+	
+	list->tree_view = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL(entry->destination_store)));
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list->tree_view), FALSE);
+	gtk_tree_view_set_hover_selection (GTK_TREE_VIEW (list->tree_view), FALSE);
+	
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list->tree_view));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+	gtk_tree_selection_unselect_all (selection);
+	gtk_tree_view_set_enable_search (GTK_TREE_VIEW (list->tree_view), FALSE);
+
+	completion = gtk_entry_get_completion (GTK_ENTRY(list));
+	gtk_entry_completion_set_inline_completion (completion, TRUE);
+	gtk_entry_completion_set_popup_completion (completion, TRUE);
+
+	renderer = gtk_cell_renderer_text_new ();
+	column = gtk_tree_view_column_new_with_attributes ("Name", renderer, "text", E_DESTINATION_STORE_COLUMN_ADDRESS, NULL);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (list->tree_view), column);
+	gtk_tree_view_column_set_clickable (column, TRUE);
+
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
+                                	GTK_POLICY_NEVER,
+					GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll),
+                                       	     GTK_SHADOW_NONE);	
+	gtk_widget_set_size_request (GTK_SCROLLED_WINDOW (scroll)->vscrollbar, -1, 0);
+
+	list->popup =  GTK_WINDOW (gtk_window_new (GTK_WINDOW_POPUP));
+ 	gtk_window_set_resizable (GTK_WINDOW (list->popup), FALSE);
+
+	popup_frame = gtk_frame_new (NULL);
+	gtk_frame_set_shadow_type (GTK_FRAME (popup_frame),
+			     	   GTK_SHADOW_ETCHED_IN);
+	
+	gtk_container_add (GTK_CONTAINER (list->popup), popup_frame);
+  
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (popup_frame), vbox);
+
+	gtk_container_add (GTK_CONTAINER (scroll), list->tree_view);
+	gtk_box_pack_start (GTK_BOX (vbox), scroll,
+                      	    TRUE, TRUE, 0);
+
+	g_signal_connect (GTK_WIDGET (list), "key-press-event", G_CALLBACK(enl_entry_key_press_event), NULL);
+	g_signal_connect_after (list->tree_view, "key-press-event", G_CALLBACK(enl_tree_key_press_event), list);
+	g_signal_connect (list->tree_view, "button-press-event", G_CALLBACK (enl_tree_button_press_event), list);
+	
+}
+
+ENameSelectorList *
+e_name_selector_list_new ()
+{
+	return g_object_new (e_name_selector_list_get_type (), NULL);
+}
--- /var/null	2005-11-08 15:48:30.000000000 +0530
+++ libedataserverui/e-name-selector-list.h	2005-11-08 14:39:56.000000000 +0530
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* e-name-selector-list.h - Single-line text entry widget for EDestinations.
+ *
+ * Copyright (C) 2004 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Srinivasa Ragavan <sragavan novell com>
+ */
+
+#ifndef E_NAME_SELECTOR_LIST_H
+#define E_NAME_SELECTOR_LIST_H
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkwindow.h>
+#include <libebook/e-contact.h>
+#include <libedataserverui/e-contact-store.h>
+#include <libedataserverui/e-destination-store.h>
+#include <libedataserverui/e-tree-model-generator.h>
+#include <libedataserverui/e-name-selector-entry.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_NAME_SELECTOR_LIST            (e_name_selector_list_get_type ())
+#define E_NAME_SELECTOR_LIST(obj)            (GTK_CHECK_CAST ((obj), e_name_selector_list_get_type (), ENameSelectorEntry))
+#define E_NAME_SELECTOR_LIST_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), e_name_selector_list_get_type (), ENameSelectorEntryClass))
+#define E_IS_NAME_SELECTOR_LIST(obj)         (GTK_CHECK_TYPE (obj, e_name_selector_list_get_type ()))
+#define E_IS_NAME_SELECTOR_LIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), e_name_selector_list_get_type ()))
+#define E_NAME_SELECTOR_LIST_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), E_NAME_SELECTOR_LIST_TYPE, ENameSelectorEntryClass))
+
+typedef struct ENameSelectorList      ENameSelectorList;
+typedef struct ENameSelectorListClass ENameSelectorListClass;
+
+struct ENameSelectorListClass {
+	ENameSelectorEntryClass parent_class;
+
+	/* Signals */
+};
+
+struct ENameSelectorList {
+	ENameSelectorEntry	parent;
+
+	GtkWindow *popup;
+	GtkWidget *tree_view;
+	EDestinationStore *store;
+	int rows;
+};
+
+GType               	 e_name_selector_list_get_type (void);
+ENameSelectorList 	*e_name_selector_list_new (void);
+void                    e_name_selector_list_expand_clicked (ENameSelectorList *list); 
+
+G_END_DECLS
+#endif
Index: composer/e-msg-composer-hdrs.c
===================================================================
RCS file: /cvs/gnome/evolution/composer/e-msg-composer-hdrs.c,v
retrieving revision 1.143
diff -u -p -r1.143 e-msg-composer-hdrs.c
--- composer/e-msg-composer-hdrs.c	24 Aug 2005 03:08:37 -0000	1.143
+++ composer/e-msg-composer-hdrs.c	8 Nov 2005 10:27:45 -0000
@@ -38,6 +38,8 @@
 #include <libgnome/gnome-i18n.h>
 #include <libedataserverui/e-name-selector.h>
 #include <libedataserverui/e-name-selector-entry.h>
+#include <libedataserverui/e-name-selector-list.h>
+
 
 #include "Composer.h"
 
@@ -55,6 +57,7 @@
 #include <text/e-entry.h>
 
 #include "e-util/e-error.h"
+#include "e-util/e-icon-factory.h"
 
 #include <camel/camel.h>
 #include <camel/camel-store.h>
@@ -92,6 +95,7 @@ extern struct _EMFolderTreeModel *mail_c
 typedef struct {
 	GtkWidget *label;
 	GtkWidget *entry;
+	GtkWidget *button;
 	int visible:1;
 } EMsgComposerHdrPair;
 
@@ -477,7 +481,7 @@ create_addressbook_entry (EMsgComposerHd
 	name_selector_model = e_name_selector_peek_model (priv->name_selector);
 	e_name_selector_model_add_section (name_selector_model, name, name, NULL);
 
-	name_selector_entry = e_name_selector_peek_section_entry (priv->name_selector, name);
+	name_selector_entry = (ENameSelectorEntry *)e_name_selector_peek_section_list (priv->name_selector, name);
 	g_signal_connect (name_selector_entry, "changed",
 			  G_CALLBACK (addressbook_entry_changed), hdrs);
 
@@ -573,12 +577,19 @@ post_entry_changed_cb (GtkButton *button
 	hdrs->priv->post_custom = TRUE;
 }
 
+static void
+expand_entry_clicked (GtkWidget *button, EMsgComposerHdrPair *hdr_pair)
+{
+	e_name_selector_list_expand_clicked((ENameSelectorList *)hdr_pair->entry);	
+}
+
 static EMsgComposerHdrPair 
 header_new_recipient (EMsgComposerHdrs *hdrs, const char *name, const char *tip)
 {
 	EMsgComposerHdrsPrivate *priv;
 	EMsgComposerHdrPair ret;
-	
+	GtkWidget *pixmap;
+
 	priv = hdrs->priv;
 	
 	ret.label = gtk_button_new_with_mnemonic (name);
@@ -592,6 +603,10 @@ header_new_recipient (EMsgComposerHdrs *
 	gtk_tooltips_set_tip (hdrs->priv->tooltips, ret.label,
 			      _("Click here for the address book"),
 			      NULL);
+
+	ret.button = gtk_button_new ();
+	pixmap = e_icon_factory_get_image ("stock_show-all", E_ICON_SIZE_BUTTON);
+	gtk_container_add (GTK_CONTAINER (ret.button), pixmap);
 	
 	ret.entry = create_addressbook_entry (hdrs, name);
 	
@@ -645,16 +660,19 @@ create_headers (EMsgComposerHdrs *hdrs)
 	priv->to = header_new_recipient (
 		hdrs, _("_To:"),
 		_("Enter the recipients of the message"));
+	gtk_signal_connect (GTK_OBJECT (priv->to.button), "clicked", G_CALLBACK (expand_entry_clicked), &(priv->to));
 	
 	priv->cc = header_new_recipient (
 		hdrs, _("_Cc:"),
 		_("Enter the addresses that will receive a carbon copy of the message"));
+	gtk_signal_connect (GTK_OBJECT (priv->cc.button), "clicked", G_CALLBACK (expand_entry_clicked), &(priv->cc)); 
 	
 	priv->bcc = header_new_recipient (
 		hdrs, _("_Bcc:"),
 		 _("Enter the addresses that will receive a carbon copy of "
 		   "the message without appearing in the recipient list of "
 		   "the message."));
+	gtk_signal_connect (GTK_OBJECT (priv->bcc.button), "clicked", G_CALLBACK (expand_entry_clicked), &(priv->bcc)); 
 
 	/*
 	 * Post-To
@@ -684,10 +702,22 @@ attach_couple (EMsgComposerHdrs *hdrs, E
 			  line, line + 1,
 			  GTK_FILL, GTK_FILL, 3, 3);
 	
-	gtk_table_attach (GTK_TABLE (hdrs),
-			  pair->entry, 1, 2,
-			  line, line + 1,
-			  GTK_FILL | GTK_EXPAND, 0, 3, 3);
+	if (line == LINE_TO || line == LINE_CC || line == LINE_BCC) {
+		gtk_table_attach (GTK_TABLE (hdrs),
+				  pair->button, 2 , 3 ,
+				  line, line+1,
+ 				  GTK_FILL , GTK_FILL, 0, 0); 
+		gtk_table_attach (GTK_TABLE (hdrs),
+				  pair->entry, 1, 2,
+				  line, line + 1,
+				  GTK_FILL | GTK_EXPAND, 0, 3, 3);
+	}
+	else {
+		gtk_table_attach (GTK_TABLE (hdrs),
+				  pair->entry, 1, 2,
+				  line, line + 1,
+				  GTK_FILL | GTK_EXPAND, 0, 3, 3);
+	}
 }
 
 static void
@@ -710,9 +740,13 @@ set_pair_visibility (EMsgComposerHdrs *h
 	if (visible /*& h->visible_mask*/) {
 		gtk_widget_show (pair->label);
 		gtk_widget_show (pair->entry);
+		if (pair->button)
+		gtk_widget_show_all (pair->button);
 	} else {
 		gtk_widget_hide (pair->label);
 		gtk_widget_hide (pair->entry);
+		if(pair->button)
+		gtk_widget_hide (pair->button);
 	}
 
 	pair->visible = TRUE;


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