aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--addressbook/ChangeLog69
-rw-r--r--addressbook/backend/ebook/e-book-util.c50
-rw-r--r--addressbook/backend/ebook/e-book-util.h5
-rw-r--r--addressbook/backend/ebook/e-card.c23
-rw-r--r--addressbook/backend/ebook/e-card.h2
-rw-r--r--addressbook/backend/ebook/e-destination.c373
-rw-r--r--addressbook/backend/ebook/e-destination.h14
-rw-r--r--addressbook/gui/component/select-names/e-select-names-bonobo.c11
-rw-r--r--addressbook/gui/component/select-names/e-select-names-manager.c45
-rw-r--r--addressbook/gui/component/select-names/e-select-names-model.c113
-rw-r--r--addressbook/gui/component/select-names/e-select-names-model.h6
-rw-r--r--addressbook/gui/component/select-names/e-select-names-text-model.c2
12 files changed, 681 insertions, 32 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog
index f2509fd5cd..3a872f2ad1 100644
--- a/addressbook/ChangeLog
+++ b/addressbook/ChangeLog
@@ -1,3 +1,72 @@
+2001-08-09 Jon Trowbridge <trow@ximian.com>
+
+ * gui/component/select-names/e-select-names-manager.c
+ (e_select_names_manager_create_entry): Hook up some magic to
+ (basically) cardify an entry on focus-out. (What we do is actually
+ more complicated than that.)
+
+ * gui/component/select-names/e-select-names-bonobo.c
+ (entry_set_property_fn): After we set an entry's text, try to
+ cardify it. We need to do this so that (for example) reply
+ e-mails get properly cardified.
+
+ * gui/component/select-names/e-select-names-model.c
+ (e_select_names_model_duplicate): Use e_select_names_model_append,
+ rather than manipulating lists directly.
+ (e_select_names_model_insert): Connect "changed" signal proxy for
+ added EDestination.
+ (e_select_names_model_append): Ditto.
+ (e_select_names_model_replace): Ditto, and disconnect signals for
+ replaced EDestination.
+ (e_select_names_model_delete): Ditto on the disconnection.
+ (e_select_names_model_delete_all): Ditto.
+ (e_select_names_model_cardify): Added. Try to cardify a specified
+ EDestination.
+ (e_select_names_model_cancel_cardify): Added. Cancel the pending
+ cardification of a single EDestination.
+ (e_select_names_model_cardify_all): Added. Cardify all of the
+ EDestinations in the model.
+ (e_select_names_model_cancel_cardify_all): Added. Cancel's any
+ and all pending cardifications.
+
+ * backend/ebook/e-destination.c (e_destination_class_init): Added
+ "changed" and "cardified" signals.
+ (e_destination_freeze): Added (static).
+ (e_destination_thaw): Added (static).
+ (e_destination_clear_card): Reset allow_cardify and
+ cannot_cardify, cancel any pending cardifications, and emit the
+ "changed" signal.
+ (e_destination_clear_strings): Emit the "changed" signal.
+ (e_destination_clear): Do freeze/thaw to prevent multiple signal
+ emissions.
+ (e_destination_set_card): Check that the card we are setting is
+ not equal to the current card, and emit the "changed" signal if we
+ are actually changing.
+ (e_destination_set_card_uri): Emit "changed" signal, if necessary.
+ (e_destination_set_name): Emit "changed" signal, if necessary.
+ (e_destination_set_email): Emit "changed" signal, if necessary.
+ (e_destination_set_html_mail_pref): Emit "changed" signal, if
+ necessary.
+ (use_card_cb): If we've just loaded/set the ECard, emit the
+ "changed" signal.
+ (e_destination_set_raw): Emit "changed" signal, if necessary.
+ (e_destination_allow_cardification): Added.
+ (e_destination_set_allow_cardification): Added.
+ (e_destination_cardify): Added. Tries to automatically convert
+ a string-based EDestination to one based on an ECard.
+ (e_destination_cardify_delayed): Added. Cardifies in a timeout.
+ (e_destination_cancel_cardify): Added. Cancels any pending
+ cardifications.
+ (e_destination_xml_decode): Added freeze/thaw.
+
+ * backend/ebook/e-book-util.c (e_book_nickname_query): Added. A
+ canned simple query for nicknames.
+
+ * backend/ebook/e-card.c (e_card_email_find_number): Added. Given
+ a card and an string containing an email address, return the index
+ number of the address inside of the card, or -1 if the address is
+ not found.
+
2001-08-09 Chris Toshok <toshok@ximian.com>
[ Fixes ximian bugs #5080, #6021, #6704, #6705 ]
diff --git a/addressbook/backend/ebook/e-book-util.c b/addressbook/backend/ebook/e-book-util.c
index d10c5612f1..c65c70dfde 100644
--- a/addressbook/backend/ebook/e-book-util.c
+++ b/addressbook/backend/ebook/e-book-util.c
@@ -508,6 +508,56 @@ e_book_name_and_email_query (EBook *book,
}
/*
+ * Simple nickname query
+ */
+
+typedef struct _NicknameQueryInfo NicknameQueryInfo;
+struct _NicknameQueryInfo {
+ gchar *nickname;
+ EBookSimpleQueryCallback cb;
+ gpointer closure;
+};
+
+static void
+nickname_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure)
+{
+ NicknameQueryInfo *info = closure;
+
+ if (info->cb)
+ info->cb (book, status, cards, info->closure);
+
+ g_free (info->nickname);
+ g_free (info);
+}
+
+guint
+e_book_nickname_query (EBook *book,
+ const char *nickname,
+ EBookSimpleQueryCallback cb,
+ gpointer closure)
+{
+ NicknameQueryInfo *info;
+ gchar *query;
+ guint retval;
+
+ g_return_val_if_fail (E_IS_BOOK (book), 0);
+ g_return_val_if_fail (nickname && *nickname, 0);
+
+ info = g_new0 (NicknameQueryInfo, 1);
+ info->nickname = g_strdup (nickname);
+ info->cb = cb;
+ info->closure = closure;
+
+ query = g_strdup_printf ("(is \"nickname\" \"%s\")", info->nickname);
+
+ retval = e_book_simple_query (book, query, nickname_cb, info);
+
+ g_free (query);
+
+ return retval;
+}
+
+/*
* Convenience routine to check for addresses in the local address book.
*/
diff --git a/addressbook/backend/ebook/e-book-util.h b/addressbook/backend/ebook/e-book-util.h
index 0988887324..69965c8363 100644
--- a/addressbook/backend/ebook/e-book-util.h
+++ b/addressbook/backend/ebook/e-book-util.h
@@ -61,6 +61,11 @@ guint e_book_name_and_email_query (EBook *book,
EBookSimpleQueryCallback cb,
gpointer closure);
+guint e_book_nickname_query (EBook *book,
+ const char *nickname,
+ EBookSimpleQueryCallback cb,
+ gpointer closure);
+
/* Returns the ECard associated to email in the callback,
or NULL if no match is found in the local address book. */
void e_book_query_address_locally (const gchar *email,
diff --git a/addressbook/backend/ebook/e-card.c b/addressbook/backend/ebook/e-card.c
index 3833211637..4b85c33868 100644
--- a/addressbook/backend/ebook/e-card.c
+++ b/addressbook/backend/ebook/e-card.c
@@ -1813,6 +1813,29 @@ e_card_email_match_string (const ECard *card, const gchar *str)
return FALSE;
}
+gint
+e_card_email_find_number (const ECard *card, const gchar *email)
+{
+ EIterator *iter;
+ gint count = 0;
+
+ g_return_val_if_fail (E_IS_CARD (card), -1);
+ g_return_val_if_fail (email != NULL, -1);
+
+ iter = e_list_get_iterator (card->email);
+ for (e_iterator_reset (iter); e_iterator_is_valid (iter); e_iterator_next (iter)) {
+ if (!strcmp (e_iterator_get (iter), email))
+ goto finished;
+ ++count;
+ }
+ count = -1;
+
+ finished:
+ gtk_object_unref (GTK_OBJECT (iter));
+
+ return count;
+}
+
/*
* ECard lifecycle management and vCard loading/saving.
*/
diff --git a/addressbook/backend/ebook/e-card.h b/addressbook/backend/ebook/e-card.h
index 3aaeddb813..83e074ff23 100644
--- a/addressbook/backend/ebook/e-card.h
+++ b/addressbook/backend/ebook/e-card.h
@@ -174,6 +174,8 @@ void e_card_arbitrary_free (ECardArbitrary
/* ECard email manipulation */
gboolean e_card_email_match_string (const ECard *card,
const gchar *str);
+gint e_card_email_find_number (const ECard *card,
+ const gchar *email);
/* Specialized functionality */
GList *e_card_load_cards_from_file (const char *filename);
diff --git a/addressbook/backend/ebook/e-destination.c b/addressbook/backend/ebook/e-destination.c
index bed6fc1b7d..4e1e27519d 100644
--- a/addressbook/backend/ebook/e-destination.c
+++ b/addressbook/backend/ebook/e-destination.c
@@ -32,6 +32,7 @@
#include <ctype.h>
#include <string.h>
#include <gtk/gtkobject.h>
+#include <gtk/gtkmain.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-i18n.h>
#include "e-book.h"
@@ -41,6 +42,14 @@
#include <gnome-xml/xmlmemory.h>
#include <camel/camel-internet-address.h>
+enum {
+ CHANGED,
+ CARDIFIED,
+ LAST_SIGNAL
+};
+
+guint e_destination_signals[LAST_SIGNAL] = { 0 };
+
struct _EDestinationPrivate {
gchar *raw;
@@ -57,6 +66,15 @@ struct _EDestinationPrivate {
gboolean wants_html_mail;
GList *list_dests;
+
+ gboolean has_been_cardified;
+ gboolean allow_cardify;
+ gboolean cannot_cardify;
+ guint pending_cardification;
+ EBook *cardify_book;
+
+ gint freeze_count;
+ gboolean pending_change;
};
static void e_destination_clear_card (EDestination *);
@@ -70,6 +88,10 @@ e_destination_destroy (GtkObject *obj)
EDestination *dest = E_DESTINATION (obj);
e_destination_clear (dest);
+
+ if (dest->priv->cardify_book)
+ gtk_object_unref (GTK_OBJECT (dest->priv->cardify_book));
+
g_free (dest->priv);
if (parent_class->destroy)
@@ -84,12 +106,34 @@ e_destination_class_init (EDestinationClass *klass)
parent_class = GTK_OBJECT_CLASS (gtk_type_class (GTK_TYPE_OBJECT));
object_class->destroy = e_destination_destroy;
+
+ e_destination_signals[CHANGED] =
+ gtk_signal_new ("changed",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EDestinationClass, changed),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ e_destination_signals[CARDIFIED] =
+ gtk_signal_new ("cardified",
+ GTK_RUN_LAST,
+ object_class->type,
+ GTK_SIGNAL_OFFSET (EDestinationClass, cardified),
+ gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
+ gtk_object_class_add_signals (object_class, e_destination_signals, LAST_SIGNAL);
}
static void
e_destination_init (EDestination *dest)
{
dest->priv = g_new0 (struct _EDestinationPrivate, 1);
+
+ dest->priv->allow_cardify = TRUE;
+ dest->priv->cannot_cardify = FALSE;
+ dest->priv->pending_cardification = 0;
}
GtkType
@@ -120,6 +164,38 @@ e_destination_new (void)
return E_DESTINATION (gtk_type_new (E_TYPE_DESTINATION));
}
+static void
+e_destination_freeze (EDestination *dest)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+ g_return_if_fail (dest->priv->freeze_count >= 0);
+ ++dest->priv->freeze_count;
+}
+
+static void
+e_destination_thaw (EDestination *dest)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+ g_return_if_fail (dest->priv->freeze_count > 0);
+ --dest->priv->freeze_count;
+ if (dest->priv->freeze_count == 0 && dest->priv->pending_change)
+ e_destination_changed (dest);
+}
+
+void
+e_destination_changed (EDestination *dest)
+{
+ if (dest->priv->freeze_count == 0) {
+ gtk_signal_emit (GTK_OBJECT (dest), e_destination_signals[CHANGED]);
+ dest->priv->pending_change = FALSE;
+
+ dest->priv->cannot_cardify = FALSE;
+
+ } else {
+ dest->priv->pending_change = TRUE;
+ }
+}
+
EDestination *
e_destination_copy (const EDestination *dest)
{
@@ -166,6 +242,13 @@ e_destination_clear_card (EDestination *dest)
g_list_foreach (dest->priv->list_dests, (GFunc) gtk_object_unref, NULL);
g_list_free (dest->priv->list_dests);
dest->priv->list_dests = NULL;
+
+ dest->priv->allow_cardify = TRUE;
+ dest->priv->cannot_cardify = FALSE;
+
+ e_destination_cancel_cardify (dest);
+
+ e_destination_changed (dest);
}
static void
@@ -182,6 +265,8 @@ e_destination_clear_strings (EDestination *dest)
g_free (dest->priv->addr);
dest->priv->addr = NULL;
+
+ e_destination_changed (dest);
}
void
@@ -189,8 +274,12 @@ e_destination_clear (EDestination *dest)
{
g_return_if_fail (dest && E_IS_DESTINATION (dest));
+ e_destination_freeze (dest);
+
e_destination_clear_card (dest);
e_destination_clear_strings (dest);
+
+ e_destination_thaw (dest);
}
gboolean
@@ -215,12 +304,17 @@ e_destination_set_card (EDestination *dest, ECard *card, gint email_num)
g_return_if_fail (dest && E_IS_DESTINATION (dest));
g_return_if_fail (card && E_IS_CARD (card));
- e_destination_clear (dest);
+ if (dest->priv->card != card || dest->priv->card_email_num != email_num) {
+
+ e_destination_clear (dest);
- dest->priv->card = card;
- gtk_object_ref (GTK_OBJECT (dest->priv->card));
+ dest->priv->card = card;
+ gtk_object_ref (GTK_OBJECT (dest->priv->card));
- dest->priv->card_email_num = email_num;
+ dest->priv->card_email_num = email_num;
+
+ e_destination_changed (dest);
+ }
}
void
@@ -228,16 +322,23 @@ e_destination_set_card_uri (EDestination *dest, const gchar *uri, gint email_num
{
g_return_if_fail (dest && E_IS_DESTINATION (dest));
g_return_if_fail (uri != NULL);
+
+ if (dest->priv->card_uri == NULL
+ || strcmp (dest->priv->card_uri, uri)
+ || dest->priv->card_email_num != email_num) {
- g_free (dest->priv->card_uri);
- dest->priv->card_uri = g_strdup (uri);
- dest->priv->card_email_num = email_num;
+ g_free (dest->priv->card_uri);
+ dest->priv->card_uri = g_strdup (uri);
+ dest->priv->card_email_num = email_num;
+
+ /* If we already have a card, remove it unless it's uri matches the one
+ we just set. */
+ if (dest->priv->card && strcmp (uri, e_card_get_uri (dest->priv->card))) {
+ gtk_object_unref (GTK_OBJECT (dest->priv->card));
+ dest->priv->card = NULL;
+ }
- /* If we already have a card, remove it unless it's uri matches the one
- we just set. */
- if (dest->priv->card && strcmp (uri, e_card_get_uri (dest->priv->card))) {
- gtk_object_unref (GTK_OBJECT (dest->priv->card));
- dest->priv->card = NULL;
+ e_destination_changed (dest);
}
}
@@ -247,12 +348,17 @@ e_destination_set_name (EDestination *dest, const gchar *name)
g_return_if_fail (dest && E_IS_DESTINATION (dest));
g_return_if_fail (name != NULL);
- g_free (dest->priv->name);
- dest->priv->name = g_strdup (name);
+ if (dest->priv->name == NULL || strcmp (dest->priv->name, name)) {
+
+ g_free (dest->priv->name);
+ dest->priv->name = g_strdup (name);
+
+ if (dest->priv->addr != NULL) {
+ g_free (dest->priv->addr);
+ dest->priv->addr = NULL;
+ }
- if (dest->priv->addr != NULL) {
- g_free (dest->priv->addr);
- dest->priv->addr = NULL;
+ e_destination_changed (dest);
}
}
@@ -262,12 +368,17 @@ e_destination_set_email (EDestination *dest, const gchar *email)
g_return_if_fail (dest && E_IS_DESTINATION (dest));
g_return_if_fail (email != NULL);
- g_free (dest->priv->email);
- dest->priv->email = g_strdup (email);
+ if (dest->priv->email == NULL || strcmp (dest->priv->email, email)) {
+
+ g_free (dest->priv->email);
+ dest->priv->email = g_strdup (email);
- if (dest->priv->addr != NULL) {
- g_free (dest->priv->addr);
- dest->priv->addr = NULL;
+ if (dest->priv->addr != NULL) {
+ g_free (dest->priv->addr);
+ dest->priv->addr = NULL;
+ }
+
+ e_destination_changed (dest);
}
}
@@ -275,9 +386,12 @@ void
e_destination_set_html_mail_pref (EDestination *dest, gboolean x)
{
g_return_if_fail (dest && E_IS_DESTINATION (dest));
-
+
dest->priv->html_mail_override = TRUE;
- dest->priv->wants_html_mail = x;
+ if (dest->priv->wants_html_mail != x) {
+ dest->priv->wants_html_mail = x;
+ e_destination_changed (dest);
+ }
}
gboolean
@@ -311,6 +425,7 @@ use_card_cb (ECard *card, gpointer closure)
uc->dest->priv->card = card;
gtk_object_ref (GTK_OBJECT (uc->dest->priv->card));
+ e_destination_changed (uc->dest);
}
@@ -520,10 +635,16 @@ e_destination_set_raw (EDestination *dest, const gchar *raw)
g_return_if_fail (E_IS_DESTINATION (dest));
g_return_if_fail (raw != NULL);
- e_destination_clear (dest);
+ if (dest->priv->raw == NULL || strcmp (dest->priv->raw, raw)) {
- dest->priv->raw = g_strdup (raw);
+ e_destination_freeze (dest);
+ e_destination_clear (dest);
+ dest->priv->raw = g_strdup (raw);
+ e_destination_changed (dest);
+
+ e_destination_thaw (dest);
+ }
}
const gchar *
@@ -582,6 +703,202 @@ e_destination_get_html_mail_pref (const EDestination *dest)
return dest->priv->card->wants_html;
}
+gboolean
+e_destination_allow_cardification (const EDestination *dest)
+{
+ g_return_val_if_fail (E_IS_DESTINATION (dest), FALSE);
+
+ return dest->priv->allow_cardify;
+}
+
+void
+e_destination_set_allow_cardification (EDestination *dest, gboolean x)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+
+ dest->priv->allow_cardify = x;
+}
+
+static void
+set_cardify_book (EDestination *dest, EBook *book)
+{
+ if (dest->priv->cardify_book && dest->priv->cardify_book != book) {
+ gtk_object_unref (GTK_OBJECT (dest->priv->cardify_book));
+ }
+
+ dest->priv->cardify_book = book;
+
+ if (book)
+ gtk_object_ref (GTK_OBJECT (book));
+}
+
+static void
+name_and_email_simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure)
+{
+ EDestination *dest = E_DESTINATION (closure);
+
+ if (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS && g_list_length ((GList *) cards) == 1) {
+ ECard *card = E_CARD (cards->data);
+ gint email_num = e_card_email_find_number (card, e_destination_get_email (dest));
+
+ if (email_num >= 0) {
+ dest->priv->has_been_cardified = TRUE;
+ e_destination_set_card (dest, E_CARD (cards->data), email_num);
+ gtk_signal_emit (GTK_OBJECT (dest), e_destination_signals[CARDIFIED]);
+ }
+ }
+
+ if (!dest->priv->has_been_cardified) {
+ dest->priv->cannot_cardify = TRUE;
+ }
+
+ gtk_object_unref (GTK_OBJECT (dest));
+}
+
+
+static void
+nickname_simple_query_cb (EBook *book, EBookSimpleQueryStatus status, const GList *cards, gpointer closure)
+{
+ EDestination *dest = E_DESTINATION (closure);
+
+ if (status == E_BOOK_SIMPLE_QUERY_STATUS_SUCCESS && g_list_length ((GList *) cards) == 1) {
+
+ dest->priv->has_been_cardified = TRUE;
+ e_destination_set_card (dest, E_CARD (cards->data), 0); /* Uses primary e-mail by default. */
+ gtk_signal_emit (GTK_OBJECT (dest), e_destination_signals[CARDIFIED]);
+ gtk_object_unref (GTK_OBJECT (dest));
+
+ } else {
+
+ e_book_name_and_email_query (book,
+ e_destination_get_name (dest),
+ e_destination_get_email (dest),
+ name_and_email_simple_query_cb,
+ dest);
+ }
+}
+
+static void
+launch_cardify_query (EDestination *dest)
+{
+ if (strchr (e_destination_get_textrep (dest), '@') == NULL) {
+
+ /* If it doesn't look like an e-mail address, see if it is a nickname. */
+ e_book_nickname_query (dest->priv->cardify_book,
+ e_destination_get_textrep (dest),
+ nickname_simple_query_cb,
+ dest);
+
+ } else {
+
+ e_book_name_and_email_query (dest->priv->cardify_book,
+ e_destination_get_name (dest),
+ e_destination_get_email (dest),
+ name_and_email_simple_query_cb,
+ dest);
+ }
+}
+
+static void
+use_local_book_cb (EBook *book, gpointer closure)
+{
+ EDestination *dest = E_DESTINATION (closure);
+ if (dest->priv->cardify_book == NULL) {
+ dest->priv->cardify_book = book;
+ gtk_object_ref (GTK_OBJECT (book));
+ }
+
+ launch_cardify_query (dest);
+}
+
+
+void
+e_destination_cardify (EDestination *dest, EBook *book)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+ g_return_if_fail (book == NULL || E_IS_BOOK (book));
+
+ if (e_destination_is_evolution_list (dest))
+ return;
+
+ if (e_destination_contains_card (dest))
+ return;
+
+ if (!dest->priv->allow_cardify)
+ return;
+
+ if (dest->priv->cannot_cardify)
+ return;
+
+ e_destination_cancel_cardify (dest);
+
+ set_cardify_book (dest, book);
+
+ /* Handle the case of an EDestination containing a card URL */
+ if (e_destination_contains_card (dest)) {
+ e_destination_use_card (dest, NULL, NULL);
+ return;
+ }
+
+ /* If we have a book ready, proceed. We hold a reference to ourselves
+ until our query is complete. */
+ gtk_object_ref (GTK_OBJECT (dest));
+ if (dest->priv->cardify_book != NULL) {
+ launch_cardify_query (dest);
+ } else {
+ e_book_use_local_address_book (use_local_book_cb, dest);
+ }
+}
+
+static gint
+do_cardify_delayed (gpointer ptr)
+{
+ EDestination *dest = E_DESTINATION (ptr);
+ e_destination_cardify (dest, dest->priv->cardify_book);
+ return FALSE;
+}
+
+void
+e_destination_cardify_delayed (EDestination *dest, EBook *book, gint delay)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+ g_return_if_fail (book == NULL || E_IS_BOOK (book));
+
+ if (delay < 0)
+ delay = 500;
+
+ e_destination_cancel_cardify (dest);
+
+ set_cardify_book (dest, book);
+
+ dest->priv->pending_cardification = gtk_timeout_add (delay, do_cardify_delayed, dest);
+}
+
+void
+e_destination_cancel_cardify (EDestination *dest)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+
+ if (dest->priv->pending_cardification) {
+ gtk_timeout_remove (dest->priv->pending_cardification);
+ dest->priv->pending_cardification = 0;
+ }
+}
+
+#if 0
+void
+e_destination_uncardify (EDestination *dest)
+{
+ g_return_if_fail (E_IS_DESTINATION (dest));
+
+ g_assert_not_reached ();
+}
+#endif
+
+/*
+ * Destination import/export
+ */
+
gchar *
e_destination_get_address_textv (EDestination **destv)
{
@@ -754,6 +1071,8 @@ e_destination_xml_decode (EDestination *dest, xmlNodePtr node)
node = node->next;
}
+
+ e_destination_freeze (dest);
e_destination_clear (dest);
@@ -765,6 +1084,8 @@ e_destination_xml_decode (EDestination *dest, xmlNodePtr node)
e_destination_set_card_uri (dest, card_uri, email_num);
if (list_dests)
dest->priv->list_dests = list_dests;
+
+ e_destination_thaw (dest);
return TRUE;
}
diff --git a/addressbook/backend/ebook/e-destination.h b/addressbook/backend/ebook/e-destination.h
index 96a3989d9a..92d4d803f2 100644
--- a/addressbook/backend/ebook/e-destination.h
+++ b/addressbook/backend/ebook/e-destination.h
@@ -54,12 +54,16 @@ struct _EDestination {
struct _EDestinationClass {
GtkObjectClass parent_class;
+
+ void (*changed) (EDestination *dest);
+ void (*cardified) (EDestination *dest);
};
GtkType e_destination_get_type (void);
EDestination *e_destination_new (void);
+void e_destination_changed (EDestination *);
EDestination *e_destination_copy (const EDestination *);
void e_destination_clear (EDestination *);
@@ -94,6 +98,16 @@ gboolean e_destination_is_evolution_list (const EDestination *);
/* If true, they want HTML mail. */
gboolean e_destination_get_html_mail_pref (const EDestination *);
+gboolean e_destination_allow_cardification (const EDestination *);
+void e_destination_set_allow_cardification (EDestination *, gboolean);
+void e_destination_cardify (EDestination *, EBook *);
+void e_destination_cardify_delayed (EDestination *, EBook *, gint delay); /* delay < 0: "default" */
+void e_destination_cancel_cardify (EDestination *);
+
+#if 0
+void e_destination_uncardify (EDestination *);
+#endif
+
gchar *e_destination_get_address_textv (EDestination **);
xmlNodePtr e_destination_xml_encode (const EDestination *dest);
diff --git a/addressbook/gui/component/select-names/e-select-names-bonobo.c b/addressbook/gui/component/select-names/e-select-names-bonobo.c
index 25adf13a65..90b3e477fb 100644
--- a/addressbook/gui/component/select-names/e-select-names-bonobo.c
+++ b/addressbook/gui/component/select-names/e-select-names-bonobo.c
@@ -132,8 +132,15 @@ entry_set_property_fn (BonoboPropertyBag *bag,
switch (arg_id) {
case ENTRY_PROPERTY_ID_TEXT:
- e_entry_set_text (E_ENTRY (w), BONOBO_ARG_GET_STRING (arg));
- break;
+ {
+ ESelectNamesModel *model;
+ model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (w), "select_names_model"));
+ g_assert (model != NULL);
+
+ e_entry_set_text (E_ENTRY (w), BONOBO_ARG_GET_STRING (arg));
+ e_select_names_model_cardify_all (model, NULL, 0);
+ break;
+ }
case ENTRY_PROPERTY_ID_DESTINATIONS:
{
diff --git a/addressbook/gui/component/select-names/e-select-names-manager.c b/addressbook/gui/component/select-names/e-select-names-manager.c
index 4481438327..0bec7da416 100644
--- a/addressbook/gui/component/select-names/e-select-names-manager.c
+++ b/addressbook/gui/component/select-names/e-select-names-manager.c
@@ -368,6 +368,38 @@ popup_cb (EEntry *entry, GdkEventButton *ev, gint pos, ESelectNamesModel *model)
e_select_names_popup (model, ev, pos);
}
+static gint
+focus_in_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data)
+{
+ EEntry *entry = E_ENTRY (user_data);
+ ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model"));
+
+ e_select_names_model_cancel_cardify_all (model);
+
+ return FALSE;
+}
+
+static gint
+focus_out_cb (GtkWidget *w, GdkEventFocus *ev, gpointer user_data)
+{
+ EEntry *entry = E_ENTRY (user_data);
+ ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model"));
+
+ if (!e_entry_completion_popup_is_visible (entry))
+ e_select_names_model_cardify_all (model, NULL, 0);
+
+ return FALSE;
+}
+
+static void
+completion_popup_cb (EEntry *entry, gint visible, gpointer user_data)
+{
+ ESelectNamesModel *model = E_SELECT_NAMES_MODEL (gtk_object_get_data (GTK_OBJECT (entry), "select_names_model"));
+
+ if (!visible && !GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (entry->canvas)))
+ e_select_names_model_cardify_all (model, NULL, 0);
+}
+
GtkWidget *
e_select_names_manager_create_entry (ESelectNamesManager *manager, const char *id)
{
@@ -389,6 +421,19 @@ e_select_names_manager_create_entry (ESelectNamesManager *manager, const char *i
GTK_SIGNAL_FUNC (popup_cb),
section->model);
+ gtk_signal_connect (GTK_OBJECT (eentry->canvas),
+ "focus_in_event",
+ GTK_SIGNAL_FUNC (focus_in_cb),
+ eentry);
+ gtk_signal_connect (GTK_OBJECT (eentry->canvas),
+ "focus_out_event",
+ GTK_SIGNAL_FUNC (focus_out_cb),
+ eentry);
+ gtk_signal_connect (GTK_OBJECT (eentry),
+ "completion_popup",
+ GTK_SIGNAL_FUNC (completion_popup_cb),
+ NULL);
+
entry = g_new (ESelectNamesManagerEntry, 1);
entry->entry = eentry;
entry->id = (char *)id;
diff --git a/addressbook/gui/component/select-names/e-select-names-model.c b/addressbook/gui/component/select-names/e-select-names-model.c
index dc383994d3..9dda927640 100644
--- a/addressbook/gui/component/select-names/e-select-names-model.c
+++ b/addressbook/gui/component/select-names/e-select-names-model.c
@@ -219,6 +219,12 @@ e_select_names_model_changed (ESelectNamesModel *model)
gtk_signal_emit (GTK_OBJECT(model), e_select_names_model_signals[E_SELECT_NAMES_MODEL_CHANGED]);
}
+static void
+destination_changed_proxy (EDestination *dest, gpointer closure)
+{
+ e_select_names_model_changed (E_SELECT_NAMES_MODEL (closure));
+}
+
/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **/
ESelectNamesModel *
@@ -240,7 +246,7 @@ e_select_names_model_duplicate (ESelectNamesModel *old)
for (iter = old->priv->data; iter != NULL; iter = g_list_next (iter)) {
EDestination *dup = e_destination_copy (E_DESTINATION (iter->data));
- model->priv->data = g_list_append (model->priv->data, dup);
+ e_select_names_model_append (model, dup);
}
model->priv->limit = old->priv->limit;
@@ -444,6 +450,21 @@ e_select_names_model_get_string (ESelectNamesModel *model, gint index)
return dest ? e_destination_get_textrep (dest) : "";
}
+static void
+connect_destination (ESelectNamesModel *model, EDestination *dest)
+{
+ gtk_signal_connect (GTK_OBJECT (dest),
+ "changed",
+ destination_changed_proxy,
+ model);
+}
+
+static void
+disconnect_destination (ESelectNamesModel *model, EDestination *dest)
+{
+ gtk_signal_disconnect_by_func (GTK_OBJECT (dest), destination_changed_proxy, model);
+}
+
void
e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination *dest)
{
@@ -458,6 +479,8 @@ e_select_names_model_insert (ESelectNamesModel *model, gint index, EDestination
return;
}
+ connect_destination (model, dest);
+
model->priv->data = g_list_insert (model->priv->data, dest, index);
gtk_object_ref (GTK_OBJECT (dest));
@@ -478,6 +501,8 @@ e_select_names_model_append (ESelectNamesModel *model, EDestination *dest)
return;
}
+ connect_destination (model, dest);
+
model->priv->data = g_list_append (model->priv->data, dest);
gtk_object_ref (GTK_OBJECT (dest));
@@ -503,6 +528,8 @@ e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination
if (model->priv->data == NULL) {
+ connect_destination (model, dest);
+
model->priv->data = g_list_append (model->priv->data, dest);
gtk_object_ref (GTK_OBJECT (dest));
gtk_object_sink (GTK_OBJECT (dest));
@@ -513,6 +540,9 @@ e_select_names_model_replace (ESelectNamesModel *model, gint index, EDestination
if (node->data != dest) {
+ disconnect_destination (model, E_DESTINATION (node->data));
+ connect_destination (model, dest);
+
old_str = e_destination_get_textrep (E_DESTINATION (node->data));
old_strlen = old_str ? strlen (old_str) : 0;
@@ -540,6 +570,7 @@ e_select_names_model_delete (ESelectNamesModel *model, gint index)
g_return_if_fail (0 <= index && index < g_list_length (model->priv->data));
node = g_list_nth (model->priv->data, index);
+ disconnect_destination (model, E_DESTINATION (node->data));
gtk_object_unref (GTK_OBJECT (node->data));
model->priv->data = g_list_remove_link (model->priv->data, node);
@@ -565,8 +596,10 @@ e_select_names_model_clean (ESelectNamesModel *model)
dest = iter->data ? E_DESTINATION (iter->data) : NULL;
if (dest == NULL || e_destination_is_empty (dest)) {
- if (dest)
+ if (dest) {
+ disconnect_destination (model, dest);
gtk_object_unref (GTK_OBJECT (dest));
+ }
model->priv->data = g_list_remove_link (model->priv->data, iter);
g_list_free_1 (iter);
changed = TRUE;
@@ -579,12 +612,19 @@ e_select_names_model_clean (ESelectNamesModel *model)
e_select_names_model_changed (model);
}
+static void
+delete_all_iter (gpointer data, gpointer closure)
+{
+ disconnect_destination (E_SELECT_NAMES_MODEL (closure), E_DESTINATION (data));
+ gtk_object_unref (GTK_OBJECT (data));
+}
+
void
e_select_names_model_delete_all (ESelectNamesModel *model)
{
g_return_if_fail (model != NULL && E_IS_SELECT_NAMES_MODEL (model));
- g_list_foreach (model->priv->data, (GFunc) gtk_object_unref, NULL);
+ g_list_foreach (model->priv->data, delete_all_iter, model);
g_list_free (model->priv->data);
model->priv->data = NULL;
@@ -692,3 +732,70 @@ e_select_names_model_text_pos (ESelectNamesModel *model, gint pos, gint *index,
if (length)
*length = len;
}
+
+void
+e_select_names_model_cardify (ESelectNamesModel *model, EBook *book, gint index, gint delay)
+{
+ EDestination *dest;
+
+ g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
+ g_return_if_fail (book == NULL || E_IS_BOOK (book));
+ g_return_if_fail (0 <= index && index < g_list_length (model->priv->data));
+
+ dest = E_DESTINATION (g_list_nth_data (model->priv->data, index));
+
+ if (!e_destination_is_empty (dest)) {
+
+ if (delay > 0)
+ e_destination_cardify_delayed (dest, book, delay);
+ else
+ e_destination_cardify (dest, book);
+ }
+}
+
+void
+e_select_names_model_cancel_cardify (ESelectNamesModel *model, gint index)
+{
+ EDestination *dest;
+
+ g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
+ g_return_if_fail (0 <= index && index < g_list_length (model->priv->data));
+
+ dest = E_DESTINATION (g_list_nth_data (model->priv->data, index));
+
+ e_destination_cancel_cardify (dest);
+}
+
+void
+e_select_names_model_cardify_all (ESelectNamesModel *model, EBook *book, gint delay)
+{
+ GList *iter;
+
+ g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
+ g_return_if_fail (book == NULL || E_IS_BOOK (book));
+
+ for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) {
+ EDestination *dest = E_DESTINATION (iter->data);
+ if (!e_destination_is_empty (dest)) {
+
+ if (delay > 0)
+ e_destination_cardify_delayed (dest, book, delay);
+ else
+ e_destination_cardify (dest, book);
+ }
+ }
+}
+
+void
+e_select_names_model_cancel_cardify_all (ESelectNamesModel *model)
+{
+ GList *iter;
+
+ g_return_if_fail (E_IS_SELECT_NAMES_MODEL (model));
+
+ for (iter = model->priv->data; iter != NULL; iter = g_list_next (iter)) {
+ EDestination *dest = E_DESTINATION (iter->data);
+ e_destination_cancel_cardify (dest);
+ }
+}
+
diff --git a/addressbook/gui/component/select-names/e-select-names-model.h b/addressbook/gui/component/select-names/e-select-names-model.h
index b11e9503ec..9f89e91093 100644
--- a/addressbook/gui/component/select-names/e-select-names-model.h
+++ b/addressbook/gui/component/select-names/e-select-names-model.h
@@ -73,4 +73,10 @@ void e_select_names_model_clean (ESelectNamesModel *model);
void e_select_names_model_name_pos (ESelectNamesModel *model, gint index, gint *pos, gint *length);
void e_select_names_model_text_pos (ESelectNamesModel *model, gint pos, gint *index, gint *start_pos, gint *length);
+void e_select_names_model_cardify (ESelectNamesModel *model, EBook *book, gint index, gint delay);
+void e_select_names_model_cancel_cardify (ESelectNamesModel *model, gint index);
+void e_select_names_model_cardify_all (ESelectNamesModel *model, EBook *book, gint delay);
+void e_select_names_model_cancel_cardify_all (ESelectNamesModel *model);
+
+
#endif /* ! __E_SELECT_NAMES_MODEL_H__ */
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 11b3b67323..2f10516dd1 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
@@ -423,7 +423,7 @@ e_select_names_text_model_insert_length (ETextModel *model, gint pos, const gcha
EDestination *dest = e_destination_new ();
e_destination_set_raw (dest, new_str);
-
+
e_select_names_model_replace (source, index, dest);
if (this_length > 0) {