diff options
18 files changed, 1102 insertions, 178 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index e5c41ac07a..82f54b0458 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,50 @@ +2001-03-08 Jon Trowbridge <trow@ximian.com> + + * gui/component/select-names/e-select-names-popup.c + (quick_add_cb): Switched to use e_contact_quick_add_free_form. + Removed debugging code, hopefully without introducing any bugs + in the process. + + * gui/component/select-names/e-select-names-text-model.c + (e_select_names_text_model_insert_length): Fix bug with commas + inside of name/address combos. As long as the comma is inside of + quotes, it will be treated as part of the name rather than as a + break between addresses. + + * gui/component/select-names/e-select-names-completion.c + (match_nickname): Use e_card_name_to_string for nickname match + strings. + (match_email): Use e_card_name_to_string for email match strings. + (e_select_names_completion_begin): Strip quotes out of query text, + so we don't produce malformed sexps. + Added William Blake quote easter egg. + + * contact-editor/e-contact-quick-add.c: Further attempts to fix... + mostly unsuccessful. + (e_contact_quick_add_free_form): Added. Takes a single string + and tries to parse out (using some simple, loose rules) the + name and e-mail -- then calls e_contact_quick_add. An attempt to + get the computer to automatically Do The Right Thing. + + * backend/ebook/e-book.c: Fixed some broken indentation. Yes, I'm + anal. + + * gui/component/GNOME_Evolution_Addressbook.oafinfo: Added oaf_server + info for EAddressWidget. + + * gui/component/GNOME_Evolution_Addressbook.oaf.in: Added oaf_server + info for EAddressWidget. + + * gui/component/addressbook-factory.c (main): Add call to + e_address_widget_factory_init. + + * gui/component/e-address-widget.h: + * gui/component/e-address-widget.c: Added. A little widget (and a + Bonobo control, BTW) for displaying addresses, with a left-click + menu. Used to display addresses in the mail viewer (as embedded + GtkHTML objects, replacing the text previously used). Still quite + incomplete. + 2001-03-08 Ettore Perazzoli <ettore@ximian.com> * gui/component/addressbook-component.c (factory_fn): Specify a diff --git a/addressbook/backend/ebook/e-book.c b/addressbook/backend/ebook/e-book.c index a4dd4e196f..1401498d2d 100644 --- a/addressbook/backend/ebook/e-book.c +++ b/addressbook/backend/ebook/e-book.c @@ -1008,10 +1008,11 @@ e_book_check_connection (EBook *book) return TRUE; } -gboolean e_book_get_cursor (EBook *book, - gchar *query, - EBookCursorCallback cb, - gpointer closure) +gboolean +e_book_get_cursor (EBook *book, + gchar *query, + EBookCursorCallback cb, + gpointer closure) { CORBA_Environment ev; @@ -1041,10 +1042,11 @@ gboolean e_book_get_cursor (EBook *book, return TRUE; } -gboolean e_book_get_book_view (EBook *book, - gchar *query, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_get_book_view (EBook *book, + gchar *query, + EBookBookViewCallback cb, + gpointer closure) { CORBA_Environment ev; EBookViewListener *listener; @@ -1077,10 +1079,11 @@ gboolean e_book_get_book_view (EBook *book, return TRUE; } -gboolean e_book_get_changes (EBook *book, - gchar *changeid, - EBookBookViewCallback cb, - gpointer closure) +gboolean +e_book_get_changes (EBook *book, + gchar *changeid, + EBookBookViewCallback cb, + gpointer closure) { CORBA_Environment ev; EBookViewListener *listener; diff --git a/addressbook/contact-editor/e-contact-quick-add.c b/addressbook/contact-editor/e-contact-quick-add.c index 8445542975..2592f797a5 100644 --- a/addressbook/contact-editor/e-contact-quick-add.c +++ b/addressbook/contact-editor/e-contact-quick-add.c @@ -26,79 +26,78 @@ */ #include <config.h> +#include <ctype.h> #include <gnome.h> #include <addressbook/backend/ebook/e-book.h> #include <addressbook/backend/ebook/e-card.h> #include "e-contact-editor.h" #include "e-contact-quick-add.h" -static FILE *out = NULL; - static void e_card_quick_set_name (ECard *card, const gchar *str) { + ECardSimple *simple; + g_return_if_fail (card && E_IS_CARD (card)); if (str == NULL) return; - if (out) - fprintf (out, "quick-set name to \"%s\"\n", str); - - if (card->name) - e_card_name_free (card->name); - card->name = e_card_name_from_string (str); + simple = e_card_simple_new (card); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_FULL_NAME, str); + e_card_simple_sync_card (simple); + gtk_object_unref (GTK_OBJECT (simple)); } static void e_card_quick_set_email (ECard *card, const gchar *str) { + ECardSimple *simple; + g_return_if_fail (card && E_IS_CARD (card)); if (str == NULL) return; - if (out) - fprintf (out, "quick-set email to \"%s\"\n", str); - - if (card->email == NULL) { - card->email = e_list_new ((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - e_list_append (card->email, str); - } else { - EIterator *iter = e_list_get_iterator (card->email); - e_iterator_reset (iter); - if (e_iterator_is_valid (iter)) { - e_iterator_set (iter, str); - } - } + simple = e_card_simple_new (card); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_EMAIL, str); + e_card_simple_sync_card (simple); + gtk_object_unref (GTK_OBJECT (simple)); } static void book_ready_cb (EBook *book, EBookStatus status, gpointer user_data) { - if (status == E_BOOK_STATUS_SUCCESS) - e_book_add_card (book, E_CARD (user_data), NULL, NULL); - gtk_object_unref (GTK_OBJECT (book)); + ECard *card = E_CARD (user_data); + + EContactQuickAddCallback cb = gtk_object_get_data (GTK_OBJECT (card), "e-contact-quick-add-cb"); + gpointer cb_user_data = gtk_object_get_data (GTK_OBJECT (card), "e-contact-quick-add-user-data"); + + if (status == E_BOOK_STATUS_SUCCESS) { + e_book_add_card (book, card, NULL, NULL); + if (cb) + cb (card, cb_user_data); + } else { + /* Something went wrong... */ + if (cb) + cb (NULL, cb_user_data); + + gtk_object_unref (GTK_OBJECT (book)); + } } static void add_card (ECard *card) { EBook *book = e_book_new (); - gchar *filename, *uri; - - filename = gnome_util_prepend_user_home ("evolution/local/Contacts/addressbook.db"); - uri = g_strdup_printf ("file://%s", filename); - - e_book_load_uri (book, uri, book_ready_cb, card); - - g_free (filename); - g_free (uri); + e_book_load_local_address_book (book, book_ready_cb, card); } +/* + * Raise a contact editor with all fields editable, and hook up all signals accordingly. + */ + static void add_card_cb (EContactEditor *ce, ECard *card, gpointer user_data) { @@ -108,12 +107,55 @@ add_card_cb (EContactEditor *ce, ECard *card, gpointer user_data) static void editor_closed_cb (GtkWidget *w, gpointer user_data) { + /* w is the contact editor, user_data is an ECard. */ if (user_data) gtk_object_unref (user_data); gtk_object_unref (GTK_OBJECT (w)); } static void +ce_book_found_fields (EBook *book, EBookStatus status, EList *fields, gpointer user_data) +{ + ECard *card = E_CARD (user_data); + EContactEditor *contact_editor; + + if (status != E_BOOK_STATUS_SUCCESS) { + g_warning ("Couldn't find supported fields for local address book."); + return; + } + + contact_editor = e_contact_editor_new (card, TRUE, fields); + + gtk_signal_connect (GTK_OBJECT (contact_editor), + "add_card", + GTK_SIGNAL_FUNC (add_card_cb), + NULL); + gtk_signal_connect (GTK_OBJECT (contact_editor), + "editor_closed", + GTK_SIGNAL_FUNC (editor_closed_cb), + user_data); + + e_contact_editor_raise (contact_editor); +} + +static void +ce_book_ready (EBook *book, EBookStatus status, gpointer user_data) +{ + if (status != E_BOOK_STATUS_SUCCESS) { + g_warning ("Couldn't open local address book."); + return; + } + + e_book_get_supported_fields (book, ce_book_found_fields, user_data); +} + +static void +edit_card (ECard *card) +{ + e_book_load_local_address_book (e_book_new (), ce_book_ready, card); +} + +static void clicked_cb (GtkWidget *w, gint button, gpointer user_data) { ECard *card = E_CARD (user_data); @@ -149,19 +191,7 @@ clicked_cb (GtkWidget *w, gint button, gpointer user_data) } else if (button == 1) { /* EDIT FULL */ - EContactEditor *contact_editor; - contact_editor = e_contact_editor_new (card, TRUE, NULL); - - gtk_signal_connect (GTK_OBJECT (contact_editor), - "add_card", - GTK_SIGNAL_FUNC (add_card_cb), - NULL); - gtk_signal_connect (GTK_OBJECT (contact_editor), - "editor_closed", - GTK_SIGNAL_FUNC (editor_closed_cb), - user_data); - - e_contact_editor_raise (contact_editor); + edit_card (card); } else { /* CANCEL */ @@ -249,16 +279,6 @@ e_contact_quick_add (const gchar *name, const gchar *email, ECard *new_card; GtkWidget *dialog; - if (out == NULL) { - out = fopen ("/tmp/barnass", "w"); - if (out) - setvbuf (out, NULL, _IONBF, 0); - } - - if (out) - fprintf (out, "\n name: %s\nemail: %s\n", name, email); - - /* We need to have *something* to work with. */ if (name == NULL && email == NULL) { if (cb) @@ -280,3 +300,85 @@ e_contact_quick_add (const gchar *name, const gchar *email, gtk_widget_show_all (dialog); } + +void +e_contact_quick_add_free_form (const gchar *text, EContactQuickAddCallback cb, gpointer user_data) +{ + gchar *name=NULL, *email=NULL; + const gchar *last_at, *s; + gboolean in_quote; + + if (text == NULL) { + e_contact_quick_add (NULL, NULL, cb, user_data); + return; + } + + /* Look for things that look like e-mail addresses embedded in text */ + in_quote = FALSE; + last_at = NULL; + for (s = text; *s; ++s) { + if (*s == '@' && !in_quote) + last_at = s; + else if (*s == '"') + in_quote = !in_quote; + } + + + if (last_at == NULL) { + /* No at sign, so we treat it all as the name */ + name = g_strdup (text); + } else { + gboolean bad_char = FALSE; + + /* walk backwards to whitespace or a < or a quote... */ + while (last_at >= text && !bad_char + && !(isspace ((gint) *last_at) || *last_at == '<' || *last_at == '"')) { + /* Check for some stuff that can't appear in a legal e-mail address. */ + if (*last_at == '[' + || *last_at == ']' + || *last_at == '(' + || *last_at == ')') + bad_char = TRUE; + --last_at; + } + if (last_at < text) + last_at = text; + + /* ...and then split the text there */ + if (!bad_char) { + if (text < last_at) + name = g_strndup (text, last_at-text); + email = g_strdup (last_at); + } + } + + /* If all else has failed, make it the name. */ + if (name == NULL && email == NULL) + name = g_strdup (text); + + + /* Clean up name */ + if (name && *name) + g_strstrip (name); + + /* Clean up email, remove bracketing <>s */ + if (email && *email) { + gboolean changed = FALSE; + g_strstrip (email); + if (*email == '<') { + *email = ' '; + changed = TRUE; + } + if (email[strlen (email)-1] == '>') { + email[strlen (email)-1] = ' '; + changed = TRUE; + } + if (changed) + g_strstrip (email); + } + + + e_contact_quick_add (name, email, cb, user_data); + g_free (name); + g_free (email); +} diff --git a/addressbook/contact-editor/e-contact-quick-add.h b/addressbook/contact-editor/e-contact-quick-add.h index 630dfd2ad0..9d928e43f4 100644 --- a/addressbook/contact-editor/e-contact-quick-add.h +++ b/addressbook/contact-editor/e-contact-quick-add.h @@ -36,5 +36,7 @@ typedef void (*EContactQuickAddCallback) (ECard *new_card, gpointer user_data); void e_contact_quick_add (const gchar *name, const gchar *email, EContactQuickAddCallback cb, gpointer user_data); +void e_contact_quick_add_free_form (const gchar *text, EContactQuickAddCallback cb, gpointer user_data); + #endif /* __E_CONTACT_QUICK_ADD_H__ */ diff --git a/addressbook/gui/component/GNOME_Evolution_Addressbook.oaf.in b/addressbook/gui/component/GNOME_Evolution_Addressbook.oaf.in index 2a523c9dc1..2e604862af 100644 --- a/addressbook/gui/component/GNOME_Evolution_Addressbook.oaf.in +++ b/addressbook/gui/component/GNOME_Evolution_Addressbook.oaf.in @@ -87,6 +87,34 @@ <oaf_attribute name="evolution:shell-component-icon" type="string" value="evolution-contacts.png"/> + +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressWidgetFactory" + type="exe" + location="evolution-addressbook"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + + <oaf_attribute name="description" type="string" + _value="Factory for the Addressbook's address displayer"/> + +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressWidget" + type="factory" + location="OAFIID:GNOME_Evolution_Addressbook_AddressWidgetFactory"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:BonoboControl/address-widget:1.0"/> + <item value="IDL:GNOME/Control:1.0"/> + </oaf_attribute> + + <oaf_attribute name="description" type="string" + _value="A Bonobo control for displaying an address."/> + </oaf_server> </oaf_info> diff --git a/addressbook/gui/component/GNOME_Evolution_Addressbook.oafinfo b/addressbook/gui/component/GNOME_Evolution_Addressbook.oafinfo index 01474ce90a..03c2e66d19 100644 --- a/addressbook/gui/component/GNOME_Evolution_Addressbook.oafinfo +++ b/addressbook/gui/component/GNOME_Evolution_Addressbook.oafinfo @@ -89,4 +89,31 @@ value="evolution-contacts.png"/> </oaf_server> +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressWidgetFactory" + type="exe" + location="evolution-addressbook"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + + <oaf_attribute name="description" type="string" + value="Factory for the Addressbook's address displayer"/> + +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_AddressWidget" + type="factory" + location="OAFIID:GNOME_Evolution_Addressbook_AddressWidgetFactory"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:BonoboControl/address-widget:1.0"/> + <item value="IDL:GNOME/Control:1.0"/> + </oaf_attribute> + + <oaf_attribute name="description" type="string" + value="A Bonobo control for displaying an address."/> + +</oaf_server> + </oaf_info> diff --git a/addressbook/gui/component/Makefile.am b/addressbook/gui/component/Makefile.am index eaefdbab96..59b1d4c394 100644 --- a/addressbook/gui/component/Makefile.am +++ b/addressbook/gui/component/Makefile.am @@ -36,7 +36,9 @@ evolution_addressbook_SOURCES = \ addressbook.c \ addressbook.h \ e-cardlist-model.c \ - e-cardlist-model.h + e-cardlist-model.h \ + e-address-widget.h \ + e-address-widget.c evolution_addressbook_LDADD = \ select-names/libeselectnames.la \ diff --git a/addressbook/gui/component/addressbook-factory.c b/addressbook/gui/component/addressbook-factory.c index ebfd0d9cfd..3887090a91 100644 --- a/addressbook/gui/component/addressbook-factory.c +++ b/addressbook/gui/component/addressbook-factory.c @@ -18,6 +18,7 @@ #include "addressbook.h" #include "addressbook-component.h" +#include "e-address-widget.h" #include "addressbook/gui/widgets/e-minicard-control.h" #include "select-names/e-select-names-factory.h" @@ -63,6 +64,8 @@ main (int argc, char **argv) e_minicard_control_factory_init (); + e_address_widget_factory_init (); + e_cursors_init(); unicode_init(); diff --git a/addressbook/gui/component/e-address-widget.c b/addressbook/gui/component/e-address-widget.c new file mode 100644 index 0000000000..2af83e67aa --- /dev/null +++ b/addressbook/gui/component/e-address-widget.c @@ -0,0 +1,414 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * e-address-widget.c + * + * Copyright (C) 2001 Ximian, Inc. + * + * Developed by Jon Trowbridge <trow@ximian.com> + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#include <config.h> +#include <bonobo/bonobo-control.h> +#include <bonobo/bonobo-property-bag.h> +#include <bonobo/bonobo-generic-factory.h> +#include <addressbook/contact-editor/e-contact-quick-add.h> +#include "e-address-widget.h" + +static void e_address_widget_class_init (EAddressWidgetClass *klass); +static void e_address_widget_init (EAddressWidget *obj); +static void e_address_widget_destroy (GtkObject *obj); + +static gint e_address_widget_button_press_handler (GtkWidget *w, GdkEventButton *ev); +static void e_address_widget_popup (EAddressWidget *, GdkEventButton *ev); + +static GtkObjectClass *parent_class; + +static void +e_address_widget_class_init (EAddressWidgetClass *klass) +{ + GtkObjectClass *object_class = (GtkObjectClass *) klass; + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + parent_class = GTK_OBJECT_CLASS (gtk_type_class (gtk_event_box_get_type ())); + + object_class->destroy = e_address_widget_destroy; + + widget_class->button_press_event = e_address_widget_button_press_handler; +} + +static void +e_address_widget_init (EAddressWidget *addr) +{ + +} + +static void +e_address_widget_destroy (GtkObject *obj) +{ + EAddressWidget *addr = E_ADDRESS_WIDGET (obj); + + g_free (addr->name); + g_free (addr->email); + if (addr->card) + gtk_object_unref (GTK_OBJECT (addr->card)); +} + +static gint +e_address_widget_button_press_handler (GtkWidget *w, GdkEventButton *ev) +{ + EAddressWidget *addr = E_ADDRESS_WIDGET (w); + if (ev->button == 3 && ev->state == 0) { + e_address_widget_popup (addr, ev); + return TRUE; + } + + return FALSE; +} + +GtkType +e_address_widget_get_type (void) +{ + static GtkType aw_type = 0; + + if (!aw_type) { + GtkTypeInfo aw_info = { + "EAddressWidget", + sizeof (EAddressWidget), + sizeof (EAddressWidgetClass), + (GtkClassInitFunc) e_address_widget_class_init, + (GtkObjectInitFunc) e_address_widget_init, + NULL, NULL, /* reserved... but for what sinister purpose? */ + (GtkClassInitFunc) NULL + }; + + aw_type = gtk_type_unique (gtk_event_box_get_type (), &aw_info); + } + + return aw_type; +} + +static void +gtk_widget_visible (GtkWidget *w, gboolean x) +{ + if (x) + gtk_widget_show (w); + else + gtk_widget_hide (w); +} + +static void +e_address_widget_refresh (EAddressWidget *addr) +{ + gchar *str; + gboolean have_name, have_email; + + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + have_name = addr->name && *addr->name; + have_email = addr->email && *addr->email; + + gtk_label_set_text (GTK_LABEL (addr->name_widget), have_name ? addr->name : ""); + gtk_widget_visible (addr->name_widget, have_name); + + if (have_email) { + str = g_strdup_printf (have_name ? "<%s>" : "%s", addr->email); + gtk_label_set_text (GTK_LABEL (addr->email_widget), str); + g_free (str); + } else { + gtk_label_set_text (GTK_LABEL (addr->email_widget), ""); + } + gtk_widget_visible (addr->email_widget, have_email); + + gtk_widget_visible (addr->spacer, have_name && have_email); + + /* Launch a query to find the appropriate card, if necessary. */ + addr->querying = TRUE; +} + +void +e_address_widget_set_name (EAddressWidget *addr, const gchar *name) +{ + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + g_free (addr->name); + addr->name = g_strdup (name); + + e_address_widget_refresh (addr); +} + +void +e_address_widget_set_email (EAddressWidget *addr, const gchar *email) +{ + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + g_free (addr->email); + addr->email = g_strdup (email); + + e_address_widget_refresh (addr); +} + + +void +e_address_widget_set_text (EAddressWidget *addr, const gchar *text) +{ + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + e_address_widget_set_email (addr, text); /* CRAP */ +} + +void +e_address_widget_construct (EAddressWidget *addr) +{ + GtkWidget *box; + + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + box = gtk_hbox_new (FALSE, 2); + + addr->name_widget = gtk_label_new (""); + addr->spacer = gtk_label_new (" "); + addr->email_widget = gtk_label_new (""); + + gtk_box_pack_start (GTK_BOX (box), addr->name_widget, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), addr->spacer, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (box), addr->email_widget, FALSE, FALSE, 0); + + + gtk_container_add (GTK_CONTAINER (addr), box); + + gtk_widget_show (box); + gtk_widget_show (addr->name_widget); + gtk_widget_show (addr->email_widget); +} + +GtkWidget * +e_address_widget_new (void) +{ + EAddressWidget *addr = gtk_type_new (e_address_widget_get_type ()); + e_address_widget_construct (addr); + return GTK_WIDGET (addr); +} + +/* + * + * Popup Menu + * + */ + +#define ARBITRARY_UIINFO_LIMIT 64 +static GtkWidget * +popup_menu_card (EAddressWidget *addr) +{ + ECard *card = E_CARD (addr->card); + g_return_val_if_fail (card != NULL, NULL); + + return NULL; +} + +static void +add_contacts_cb (GtkWidget *w, gpointer user_data) +{ + EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); + + e_contact_quick_add (addr->name, addr->email, NULL, NULL); +} + +static GtkWidget * +popup_menu_nocard (EAddressWidget *addr) +{ + GnomeUIInfo uiinfo[ARBITRARY_UIINFO_LIMIT]; + GtkWidget *pop; + gint i=0, dead; + + memset (uiinfo, 0, sizeof (uiinfo)); + + if (addr->name) { + uiinfo[i].type = GNOME_APP_UI_ITEM; + uiinfo[i].label = addr->name; + ++i; + } + + if (addr->email) { + uiinfo[i].type = GNOME_APP_UI_ITEM; + uiinfo[i].label = addr->email; + ++i; + } + dead = i; + + uiinfo[i].type = GNOME_APP_UI_SEPARATOR; + ++i; + + uiinfo[i].type = GNOME_APP_UI_ITEM; + uiinfo[i].label = N_("Add to Contacts"); + uiinfo[i].moreinfo = add_contacts_cb; + ++i; + + uiinfo[i].type = GNOME_APP_UI_ENDOFINFO; + + + pop = gnome_popup_menu_new (uiinfo); + for (i=0; i<dead; ++i) + dead_item (GTK_ITEM (uiinfo[i].widget)); + return pop; +} + +static void +e_address_widget_popup (EAddressWidget *addr, GdkEventButton *ev) +{ + GtkWidget *pop; + + g_return_if_fail (addr && E_IS_ADDRESS_WIDGET (addr)); + + pop = addr->card ? popup_menu_card (addr) : popup_menu_nocard (addr); + + if (pop) + gnome_popup_menu_do_popup (pop, NULL, NULL, ev, addr); +} + +/* + * + * Bonobo Control Magic + * + */ + +enum { + ADDRESS_PROPERTY_NAME, + ADDRESS_PROPERTY_EMAIL, + ADDRESS_PROPERTY_TEXT, + ADDRESS_PROPERTY_BACKGROUND_RGB +}; + + +static void +get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) +{ + EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); + + switch (arg_id) { + + case ADDRESS_PROPERTY_NAME: + BONOBO_ARG_SET_STRING (arg, addr->name ? addr->name :""); + break; + + case ADDRESS_PROPERTY_EMAIL: + BONOBO_ARG_SET_STRING (arg, addr->email ? addr->email : ""); + break; + + case ADDRESS_PROPERTY_TEXT: + BONOBO_ARG_SET_STRING (arg, "?"); + break; + } +} + +static void +set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, CORBA_Environment *ev, gpointer user_data) +{ + EAddressWidget *addr = E_ADDRESS_WIDGET (user_data); + + switch (arg_id) { + case ADDRESS_PROPERTY_NAME: + e_address_widget_set_name (addr, BONOBO_ARG_GET_STRING (arg)); + break; + + case ADDRESS_PROPERTY_EMAIL: + e_address_widget_set_email (addr, BONOBO_ARG_GET_STRING (arg)); + break; + + case ADDRESS_PROPERTY_TEXT: + e_address_widget_set_text (addr, BONOBO_ARG_GET_STRING (arg)); + break; + + + case ADDRESS_PROPERTY_BACKGROUND_RGB: + { + gint bg = BONOBO_ARG_GET_INT (arg); + GdkColor color; + + color.red = (bg & 0xff0000) >> 8; + color.green = (bg & 0x00ff00); + color.blue = (bg & 0x0000ff) << 8; + + if (gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET (addr)), &color, FALSE, TRUE)) { + GtkStyle *style = gtk_style_copy (gtk_widget_get_style (GTK_WIDGET (addr))); + style->bg[0] = color; + gtk_widget_set_style (GTK_WIDGET (addr), style); + } + } + + break; + } +} + +static BonoboControl * +e_address_widget_factory_new_control (void) +{ + BonoboControl *control; + BonoboPropertyBag *bag; + GtkWidget *w; + + w = e_address_widget_new (); + gtk_widget_show (w); + + control = bonobo_control_new (w); + + bag = bonobo_property_bag_new (get_prop, set_prop, w); + bonobo_property_bag_add (bag, "name", ADDRESS_PROPERTY_NAME, + BONOBO_ARG_STRING, NULL, NULL, + BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); + + bonobo_property_bag_add (bag, "email", ADDRESS_PROPERTY_EMAIL, + BONOBO_ARG_STRING, NULL, NULL, + BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); + + bonobo_property_bag_add (bag, "text", ADDRESS_PROPERTY_TEXT, + BONOBO_ARG_STRING, NULL, NULL, + BONOBO_PROPERTY_READABLE | BONOBO_PROPERTY_WRITEABLE); + + bonobo_property_bag_add (bag, "background_rgb", ADDRESS_PROPERTY_BACKGROUND_RGB, + BONOBO_ARG_INT, NULL, NULL, + BONOBO_PROPERTY_WRITEABLE); + + bonobo_control_set_properties (control, bag); + bonobo_object_unref (BONOBO_OBJECT (bag)); + + return control; +} + +static BonoboObject * +e_address_widget_factory (BonoboGenericFactory *factory, gpointer user_data) +{ + return BONOBO_OBJECT (e_address_widget_factory_new_control ()); +} + +void +e_address_widget_factory_init (void) +{ + static BonoboGenericFactory *factory = NULL; + + if (factory != NULL) + return; + + factory = bonobo_generic_factory_new ("OAFIID:GNOME_Evolution_Addressbook_AddressWidgetFactory", + e_address_widget_factory, NULL); + + if (factory == NULL) + g_error ("I could not register an AddressWidget factory."); +} diff --git a/addressbook/gui/component/e-address-widget.h b/addressbook/gui/component/e-address-widget.h new file mode 100644 index 0000000000..7168242323 --- /dev/null +++ b/addressbook/gui/component/e-address-widget.h @@ -0,0 +1,81 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * e-address-widget.h + * + * Copyright (C) 2001 Ximian, Inc. + * + * Developed by Jon Trowbridge <trow@ximian.com> + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + */ + +#ifndef __E_ADDRESS_WIDGET_H__ +#define __E_ADDRESS_WIDGET_H__ + +#include <gtk/gtk.h> +#include <libgnome/gnome-defs.h> +#include <addressbook/backend/ebook/e-card.h> + +BEGIN_GNOME_DECLS + +#define E_ADDRESS_WIDGET_TYPE (e_address_widget_get_type ()) +#define E_ADDRESS_WIDGET(o) (GTK_CHECK_CAST ((o), E_ADDRESS_WIDGET_TYPE, EAddressWidget)) +#define E_ADDRESS_WIDGET_CLASS(k) (GTK_CHECK_CLASS_CAST ((k), E_ADDRESS_WIDGET_TYPE, EAddressWidgetClass)) +#define E_IS_ADDRESS_WIDGET(o) (GTK_CHECK_TYPE ((o), E_ADDRESS_WIDGET_TYPE)) +#define E_IS_ADDRESS_WIDGET_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_ADDRESS_WIDGET_TYPE)) + +typedef struct _EAddressWidget EAddressWidget; +typedef struct _EAddressWidgetClass EAddressWidgetClass; + +struct _EAddressWidget { + GtkEventBox parent; + + gchar *name; + gchar *email; + + GtkWidget *name_widget; + GtkWidget *email_widget; + GtkWidget *spacer; + + gboolean querying; + ECard *card; +}; + +struct _EAddressWidgetClass { + GtkHBoxClass parent_class; +}; + +GtkType e_address_widget_get_type (void); + +void e_address_widget_set_name (EAddressWidget *, const gchar *name); +void e_address_widget_set_email (EAddressWidget *, const gchar *email); +void e_address_widget_set_text (EAddressWidget *, const gchar *text); + +void e_address_widget_construct (EAddressWidget *); +GtkWidget *e_address_widget_new (void); + + +void e_address_widget_factory_init (void); + + + +END_GNOME_DECLS + +#endif /* __E_ADDRESS_WIDGET_H__ */ + diff --git a/addressbook/gui/component/select-names/e-select-names-completion.c b/addressbook/gui/component/select-names/e-select-names-completion.c index 5f87144510..aa1bf7e2e3 100644 --- a/addressbook/gui/component/select-names/e-select-names-completion.c +++ b/addressbook/gui/component/select-names/e-select-names-completion.c @@ -97,11 +97,14 @@ match_nickname (ESelectNamesCompletion *comp, EDestination *dest, double *score) if (card->nickname && !g_strncasecmp (comp->priv->query_text, card->nickname, len)) { + gchar *name = e_card_name_to_string (card->name); + gchar *str; *score = len * 10; /* nickname gives 10 points per matching character */ - return g_strdup_printf ("(%s) %s %s", card->nickname, card->name->given, card->name->family); - + str = g_strdup_printf ("(%s) %s", card->nickname, name); + g_free (name); + return str; } return NULL; @@ -125,8 +128,12 @@ match_email (ESelectNamesCompletion *comp, EDestination *dest, double *score) const gchar *email = e_destination_get_email (dest); if (email && !g_strncasecmp (comp->priv->query_text, email, len)) { + gchar *name, *str; *score = len * 2; /* 2 points for each matching character */ - return g_strdup_printf ("<%s> %s %s", email, card->name->given, card->name->family); + name = e_card_name_to_string (card->name); + str = g_strdup_printf ("<%s> %s", email, name); + g_free (name); + return str; } return NULL; @@ -693,7 +700,9 @@ struct _SearchOverride { const gchar *text[4]; }; static SearchOverride override[] = { - { "easter egg", { "This is the sample", "Easter Egg text for", "Evolution.", NULL } }, + { "why?", { "\"I must create a system, or be enslaved by another man's.\"", + " -- Wiliam Blake, \"Jerusalem\"", + NULL } }, { NULL, { NULL } } }; static gboolean @@ -711,6 +720,7 @@ e_select_names_completion_begin (ECompletion *comp, const gchar *text, gint pos, ESelectNamesCompletion *selcomp = E_SELECT_NAMES_COMPLETION (comp); const gchar *str; gint index, j; + gchar *s, *t; g_return_if_fail (comp != NULL); g_return_if_fail (E_IS_SELECT_NAMES_COMPLETION (comp)); @@ -751,6 +761,18 @@ e_select_names_completion_begin (ECompletion *comp, const gchar *text, gint pos, g_free (selcomp->priv->pending_query_text); selcomp->priv->pending_query_text = g_strdup (str); + + /* Strip problematic characters out of query text. */ + s = t = selcomp->priv->pending_query_text; + while (*s) { + if (*s != ',' && *s != '"') { + if (s != t) + *t = *s; + ++t; + } + ++s; + } + *t = '\0'; e_select_names_completion_do_query (selcomp); } diff --git a/addressbook/gui/component/select-names/e-select-names-popup.c b/addressbook/gui/component/select-names/e-select-names-popup.c index 23898a3079..85c2489b1a 100644 --- a/addressbook/gui/component/select-names/e-select-names-popup.c +++ b/addressbook/gui/component/select-names/e-select-names-popup.c @@ -31,8 +31,6 @@ #include <addressbook/contact-editor/e-contact-quick-add.h> #include "e-select-names-popup.h" -static FILE *out = NULL; - typedef struct _PopupInfo PopupInfo; struct _PopupInfo { ESelectNamesModel *model; @@ -64,9 +62,6 @@ popup_info_free (PopupInfo *info) { if (info) { - if (out) - fprintf (out, "popup_info_free\n"); - if (info->model) gtk_object_unref (GTK_OBJECT (info->model)); @@ -103,8 +98,6 @@ change_email_num_cb (GtkWidget *w, gpointer user_data) return; n = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (w), "number")); - if (out) - fprintf (out, "replacing %d\n", n); if (n != e_destination_get_email_num (info->dest)) { dest = e_destination_new (); @@ -157,9 +150,6 @@ popup_menu_card (PopupInfo *info) EIterator *iterator; gchar *name_str; - if (out) - fprintf (out, "popup_menu_card\n"); - /* * Build up our GnomeUIInfo array. */ @@ -236,9 +226,6 @@ popup_menu_card (PopupInfo *info) } } - if (out) - fprintf (out, "leaving popup_menu_card\n"); - return pop; } @@ -246,8 +233,7 @@ static void quick_add_cb (GtkWidget *w, gpointer user_data) { PopupInfo *info = (PopupInfo *) user_data; - e_contact_quick_add (NULL, e_destination_get_string (info->dest), - NULL, NULL); + e_contact_quick_add_free_form (e_destination_get_string (info->dest), NULL, NULL); } static GtkWidget * @@ -301,15 +287,6 @@ e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) g_return_if_fail (ev); g_return_if_fail (0 <= pos); - if (out == NULL) { - out = fopen ("/tmp/evo-debug-select-names-popup", "w"); - if (out) - setvbuf (out, NULL, _IONBF, 0); - } - - if (out) - fprintf (out, "\n\ne_select_names_popup\n"); - e_select_names_model_text_pos (model, pos, &index, NULL, NULL); if (index < 0 || index >= e_select_names_model_count (model)) return; @@ -328,9 +305,6 @@ e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) GTK_SIGNAL_FUNC (popup_info_cleanup), info); - if (out) - fprintf (out, "doing popup\n"); - gnome_popup_menu_do_popup (popup, NULL, NULL, ev, info); } else { @@ -338,8 +312,4 @@ e_select_names_popup (ESelectNamesModel *model, GdkEventButton *ev, gint pos) popup_info_free (info); } - - if (out) - fprintf (out, "leaving e_select_names_popup\n\n"); - } diff --git a/addressbook/gui/component/select-names/e-select-names-text-model.c b/addressbook/gui/component/select-names/e-select-names-text-model.c index d66112d2bc..0e4d5eeb32 100644 --- a/addressbook/gui/component/select-names/e-select-names-text-model.c +++ b/addressbook/gui/component/select-names/e-select-names-text-model.c @@ -125,7 +125,7 @@ dump_model (ESelectNamesTextModel *text_model) if (out == NULL) return; - + fprintf (out, "\n*** Model State: count=%d\n", e_select_names_model_count (model)); for (i=0; i<e_select_names_model_count (model); ++i) @@ -297,6 +297,7 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha for (i = 0; i < length && text[i]; ++i) { gint index, start_pos, text_len; + gboolean inside_quote = FALSE; if (out) fprintf (out, "processing [%c]\n", text[i]); @@ -306,8 +307,26 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha if (out) fprintf (out, "index=%d start_pos=%d text_len=%d\n", index, start_pos, text_len); + if (text[i] == ',' && index >= 0) { /* Is this a quoted or an unquoted comma we are dealing with? */ + const EDestination *dest = e_select_names_model_get_destination (source, index); + if (dest) { + const gchar *str = e_destination_get_string (dest); + gint j; + if (out) + fprintf (out, "str=%s pos=%d\n", str, pos); + for (j=0; j<pos-start_pos && str[j]; ++j) + if (str[j] == '"') { + inside_quote = !inside_quote; + if (out) + fprintf (out, "flip to %d at %d\n", start_pos+j, inside_quote); + } + } + if (out) + fprintf (out, inside_quote ? "inside quote\n" : "not inside quote\n"); + } + - if (text[i] == ',') { + if (text[i] == ',' && !inside_quote) { /* This is the case of hitting , first thing in an empty entry */ if (index == -1) { diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.c b/addressbook/gui/contact-editor/e-contact-quick-add.c index 8445542975..2592f797a5 100644 --- a/addressbook/gui/contact-editor/e-contact-quick-add.c +++ b/addressbook/gui/contact-editor/e-contact-quick-add.c @@ -26,79 +26,78 @@ */ #include <config.h> +#include <ctype.h> #include <gnome.h> #include <addressbook/backend/ebook/e-book.h> #include <addressbook/backend/ebook/e-card.h> #include "e-contact-editor.h" #include "e-contact-quick-add.h" -static FILE *out = NULL; - static void e_card_quick_set_name (ECard *card, const gchar *str) { + ECardSimple *simple; + g_return_if_fail (card && E_IS_CARD (card)); if (str == NULL) return; - if (out) - fprintf (out, "quick-set name to \"%s\"\n", str); - - if (card->name) - e_card_name_free (card->name); - card->name = e_card_name_from_string (str); + simple = e_card_simple_new (card); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_FULL_NAME, str); + e_card_simple_sync_card (simple); + gtk_object_unref (GTK_OBJECT (simple)); } static void e_card_quick_set_email (ECard *card, const gchar *str) { + ECardSimple *simple; + g_return_if_fail (card && E_IS_CARD (card)); if (str == NULL) return; - if (out) - fprintf (out, "quick-set email to \"%s\"\n", str); - - if (card->email == NULL) { - card->email = e_list_new ((EListCopyFunc) g_strdup, - (EListFreeFunc) g_free, - NULL); - e_list_append (card->email, str); - } else { - EIterator *iter = e_list_get_iterator (card->email); - e_iterator_reset (iter); - if (e_iterator_is_valid (iter)) { - e_iterator_set (iter, str); - } - } + simple = e_card_simple_new (card); + e_card_simple_set (simple, E_CARD_SIMPLE_FIELD_EMAIL, str); + e_card_simple_sync_card (simple); + gtk_object_unref (GTK_OBJECT (simple)); } static void book_ready_cb (EBook *book, EBookStatus status, gpointer user_data) { - if (status == E_BOOK_STATUS_SUCCESS) - e_book_add_card (book, E_CARD (user_data), NULL, NULL); - gtk_object_unref (GTK_OBJECT (book)); + ECard *card = E_CARD (user_data); + + EContactQuickAddCallback cb = gtk_object_get_data (GTK_OBJECT (card), "e-contact-quick-add-cb"); + gpointer cb_user_data = gtk_object_get_data (GTK_OBJECT (card), "e-contact-quick-add-user-data"); + + if (status == E_BOOK_STATUS_SUCCESS) { + e_book_add_card (book, card, NULL, NULL); + if (cb) + cb (card, cb_user_data); + } else { + /* Something went wrong... */ + if (cb) + cb (NULL, cb_user_data); + + gtk_object_unref (GTK_OBJECT (book)); + } } static void add_card (ECard *card) { EBook *book = e_book_new (); - gchar *filename, *uri; - - filename = gnome_util_prepend_user_home ("evolution/local/Contacts/addressbook.db"); - uri = g_strdup_printf ("file://%s", filename); - - e_book_load_uri (book, uri, book_ready_cb, card); - - g_free (filename); - g_free (uri); + e_book_load_local_address_book (book, book_ready_cb, card); } +/* + * Raise a contact editor with all fields editable, and hook up all signals accordingly. + */ + static void add_card_cb (EContactEditor *ce, ECard *card, gpointer user_data) { @@ -108,12 +107,55 @@ add_card_cb (EContactEditor *ce, ECard *card, gpointer user_data) static void editor_closed_cb (GtkWidget *w, gpointer user_data) { + /* w is the contact editor, user_data is an ECard. */ if (user_data) gtk_object_unref (user_data); gtk_object_unref (GTK_OBJECT (w)); } static void +ce_book_found_fields (EBook *book, EBookStatus status, EList *fields, gpointer user_data) +{ + ECard *card = E_CARD (user_data); + EContactEditor *contact_editor; + + if (status != E_BOOK_STATUS_SUCCESS) { + g_warning ("Couldn't find supported fields for local address book."); + return; + } + + contact_editor = e_contact_editor_new (card, TRUE, fields); + + gtk_signal_connect (GTK_OBJECT (contact_editor), + "add_card", + GTK_SIGNAL_FUNC (add_card_cb), + NULL); + gtk_signal_connect (GTK_OBJECT (contact_editor), + "editor_closed", + GTK_SIGNAL_FUNC (editor_closed_cb), + user_data); + + e_contact_editor_raise (contact_editor); +} + +static void +ce_book_ready (EBook *book, EBookStatus status, gpointer user_data) +{ + if (status != E_BOOK_STATUS_SUCCESS) { + g_warning ("Couldn't open local address book."); + return; + } + + e_book_get_supported_fields (book, ce_book_found_fields, user_data); +} + +static void +edit_card (ECard *card) +{ + e_book_load_local_address_book (e_book_new (), ce_book_ready, card); +} + +static void clicked_cb (GtkWidget *w, gint button, gpointer user_data) { ECard *card = E_CARD (user_data); @@ -149,19 +191,7 @@ clicked_cb (GtkWidget *w, gint button, gpointer user_data) } else if (button == 1) { /* EDIT FULL */ - EContactEditor *contact_editor; - contact_editor = e_contact_editor_new (card, TRUE, NULL); - - gtk_signal_connect (GTK_OBJECT (contact_editor), - "add_card", - GTK_SIGNAL_FUNC (add_card_cb), - NULL); - gtk_signal_connect (GTK_OBJECT (contact_editor), - "editor_closed", - GTK_SIGNAL_FUNC (editor_closed_cb), - user_data); - - e_contact_editor_raise (contact_editor); + edit_card (card); } else { /* CANCEL */ @@ -249,16 +279,6 @@ e_contact_quick_add (const gchar *name, const gchar *email, ECard *new_card; GtkWidget *dialog; - if (out == NULL) { - out = fopen ("/tmp/barnass", "w"); - if (out) - setvbuf (out, NULL, _IONBF, 0); - } - - if (out) - fprintf (out, "\n name: %s\nemail: %s\n", name, email); - - /* We need to have *something* to work with. */ if (name == NULL && email == NULL) { if (cb) @@ -280,3 +300,85 @@ e_contact_quick_add (const gchar *name, const gchar *email, gtk_widget_show_all (dialog); } + +void +e_contact_quick_add_free_form (const gchar *text, EContactQuickAddCallback cb, gpointer user_data) +{ + gchar *name=NULL, *email=NULL; + const gchar *last_at, *s; + gboolean in_quote; + + if (text == NULL) { + e_contact_quick_add (NULL, NULL, cb, user_data); + return; + } + + /* Look for things that look like e-mail addresses embedded in text */ + in_quote = FALSE; + last_at = NULL; + for (s = text; *s; ++s) { + if (*s == '@' && !in_quote) + last_at = s; + else if (*s == '"') + in_quote = !in_quote; + } + + + if (last_at == NULL) { + /* No at sign, so we treat it all as the name */ + name = g_strdup (text); + } else { + gboolean bad_char = FALSE; + + /* walk backwards to whitespace or a < or a quote... */ + while (last_at >= text && !bad_char + && !(isspace ((gint) *last_at) || *last_at == '<' || *last_at == '"')) { + /* Check for some stuff that can't appear in a legal e-mail address. */ + if (*last_at == '[' + || *last_at == ']' + || *last_at == '(' + || *last_at == ')') + bad_char = TRUE; + --last_at; + } + if (last_at < text) + last_at = text; + + /* ...and then split the text there */ + if (!bad_char) { + if (text < last_at) + name = g_strndup (text, last_at-text); + email = g_strdup (last_at); + } + } + + /* If all else has failed, make it the name. */ + if (name == NULL && email == NULL) + name = g_strdup (text); + + + /* Clean up name */ + if (name && *name) + g_strstrip (name); + + /* Clean up email, remove bracketing <>s */ + if (email && *email) { + gboolean changed = FALSE; + g_strstrip (email); + if (*email == '<') { + *email = ' '; + changed = TRUE; + } + if (email[strlen (email)-1] == '>') { + email[strlen (email)-1] = ' '; + changed = TRUE; + } + if (changed) + g_strstrip (email); + } + + + e_contact_quick_add (name, email, cb, user_data); + g_free (name); + g_free (email); +} diff --git a/addressbook/gui/contact-editor/e-contact-quick-add.h b/addressbook/gui/contact-editor/e-contact-quick-add.h index 630dfd2ad0..9d928e43f4 100644 --- a/addressbook/gui/contact-editor/e-contact-quick-add.h +++ b/addressbook/gui/contact-editor/e-contact-quick-add.h @@ -36,5 +36,7 @@ typedef void (*EContactQuickAddCallback) (ECard *new_card, gpointer user_data); void e_contact_quick_add (const gchar *name, const gchar *email, EContactQuickAddCallback cb, gpointer user_data); +void e_contact_quick_add_free_form (const gchar *text, EContactQuickAddCallback cb, gpointer user_data); + #endif /* __E_CONTACT_QUICK_ADD_H__ */ diff --git a/mail/ChangeLog b/mail/ChangeLog index f6a3ef6da5..48757cd6f8 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,20 @@ +2001-03-08 Jon Trowbridge <trow@ximian.com> + + * mail-format.c (write_field_row_begin): Added. Table row HTML + broken out into its own function. + (write_subject): Added. Emits the proper HTML for the subject + line. + (write_field_to_stream): #ifdef-ed out of existence. + (write_address): Take a CamelInternetAddress and spit out an + <object> tag with the appropriate <param>s. + + * mail-display.c (on_object_requested): Check for an "address" + object. If found, call... + (handle_embedded_address_object): ...this function, which creates + an AddressWidget bonobo control and passes in the necessary info. + I never really realized just quite how much GtkHTML kicks ass + until I figured out how to make this work. + 2001-03-08 Jeffrey Stedfast <fejj@ximian.com> * mail-vtrash.[c,h]: Removed from cvs diff --git a/mail/mail-display.c b/mail/mail-display.c index 9f599bc797..8304cbc595 100644 --- a/mail/mail-display.c +++ b/mail/mail-display.c @@ -603,6 +603,33 @@ get_embedded_for_component (const char *iid, MailDisplay *md) return embedded; } +static void +handle_embedded_address_object (GtkHTMLEmbedded *eb) +{ + const gchar *name, *email; + GtkWidget *w; + + w = bonobo_widget_new_control ("OAFIID:GNOME_Evolution_Addressbook_AddressWidget", + CORBA_OBJECT_NIL); + + name = gtk_html_embedded_get_parameter (eb, "name"); + email = gtk_html_embedded_get_parameter (eb, "email"); + + bonobo_widget_set_property (BONOBO_WIDGET (w), + "name", name, + "email", email, + /* Hackish: this is the bg color defined for the HTML table + in mail-format.c. If you change it there, you'd better + change it here as well. */ + "background_rgb", 0xeeeeee, + NULL); + + gtk_widget_show (w); + gtk_container_add (GTK_CONTAINER (eb), w); + + gtk_html_embedded_set_descent (eb, 0); +} + static gboolean on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) { @@ -621,6 +648,12 @@ on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) char *cid; cid = eb->classid; + + if (!strcmp (cid, "address")) { + handle_embedded_address_object (eb); + return TRUE; + } + if (!strncmp (cid, "popup:", 6)) cid += 6; if (strncmp (cid, "cid:", 4) != 0) diff --git a/mail/mail-format.c b/mail/mail-format.c index 27849d54b7..7c8fed1ff7 100644 --- a/mail/mail-format.c +++ b/mail/mail-format.c @@ -575,9 +575,42 @@ enum { }; static void +write_field_row_begin (const char *description, gint flags, GtkHTML *html, GtkHTMLStream *stream) +{ + char *encoded_desc; + int bold = (flags & WRITE_BOLD) == WRITE_BOLD; + + encoded_desc = e_utf8_from_gtk_string (GTK_WIDGET (html), description); + + mail_html_write (html, stream, "<tr><%s align=right> %s </%s>", + bold ? "th" : "td", encoded_desc, bold ? "th" : "td"); + + g_free (encoded_desc); +} + +static void +write_subject (const char *subject, int flags, GtkHTML *html, GtkHTMLStream *stream) +{ + char *encoded_subj; + + if (subject) + encoded_subj = e_text_to_html (subject, E_TEXT_TO_HTML_CONVERT_NL | E_TEXT_TO_HTML_CONVERT_URLS); + else + encoded_subj = ""; + + write_field_row_begin (_("Subject:"), flags, html, stream); + + mail_html_write (html, stream, "<td> %s </td> </tr>", encoded_subj); + + if (subject) + g_free (encoded_subj); +} + +#ifdef USE_OBSOLETE_UNUSED_STUFF_AND_GET_COMPILER_WARNINGS +static void write_field_to_stream(const char *description, const char *value, int flags, GtkHTML *html, GtkHTMLStream *stream) { - char *encoded_desc, *encoded_value; + char *encoded_desc, *encoded_value, *embedded_object; int bold = (flags&WRITE_BOLD) == WRITE_BOLD; /* The description comes from gettext... */ @@ -590,26 +623,45 @@ write_field_to_stream(const char *description, const char *value, int flags, Gtk mail_html_write(html, stream, "<tr valign=top><%s align=right>%s</%s>" - "<td>%s</td></tr>", bold ? "th" : "td", + "<td> %s </td></tr>", bold ? "th" : "td", encoded_desc, bold ? "th" : "td", encoded_value); g_free (encoded_desc); + g_free (embedded_object); if (value) g_free(encoded_value); } +#endif static void -write_address(MailDisplay *md, const CamelInternetAddress *addr, const char *name, int flags) +write_address(MailDisplay *md, const CamelInternetAddress *addr, const char *field_name, int flags) { - char *string; + const char *name, *email; + gint i; - if (addr == NULL) + if (addr == NULL || !camel_internet_address_get (addr, 0, NULL, NULL)) return; - string = camel_address_format((CamelAddress *)addr); - if (string && string[0]) { - write_field_to_stream(name, string, flags, md->html, md->stream); + write_field_row_begin (field_name, flags, md->html, md->stream); + + i = 0; + while (camel_internet_address_get (addr, i, &name, &email)) { + + if ((name && *name) || (email && *email)) { + + mail_html_write (md->html, md->stream, i ? ", " : "<td>"); + + mail_html_write (md->html, md->stream, "<object classid=\"address\">"); + if (name && *name) + mail_html_write (md->html, md->stream, "<param name=\"name\" value=\"%s\"/>", name); + if (email && *email) + mail_html_write (md->html, md->stream, "<param name=\"email\" value=\"%s\"/>", email); + mail_html_write (md->html, md->stream, "</object>"); + } + + ++i; } - g_free(string); + + mail_html_write (md->html, md->stream, "</td></tr>"); /* Finish up the table row */ } @@ -632,9 +684,7 @@ write_headers (CamelMimeMessage *message, MailDisplay *md) write_address(md, camel_mime_message_get_recipients(message, CAMEL_RECIPIENT_TYPE_CC), _("Cc:"), WRITE_BOLD); - write_field_to_stream (_("Subject:"), - camel_mime_message_get_subject (message), - TRUE, md->html, md->stream); + write_subject (camel_mime_message_get_subject (message), WRITE_BOLD, md->html, md->stream); mail_html_write (md->html, md->stream, "</table></td></tr></table></td></tr></table></font>"); |